Adding documentation and a few tweaks to node.js

This commit is contained in:
Jeff Avallone 2015-04-19 16:40:53 -04:00
parent 8796c1329c
commit 1ef8bd7500
3 changed files with 54 additions and 11 deletions

View File

@ -310,7 +310,7 @@ describe('parser/javascript/node.js', function() {
it('creates a text element', function() { it('creates a text element', function() {
this.node.renderLabeledBox('example label', this.content, { padding: 5 }); this.node.renderLabeledBox('example label', this.content, { padding: 5 });
expect(this.node.container.text).toHaveBeenCalledWith(0, 0, 'example label'); expect(this.node.container.text).toHaveBeenCalledWith(0, 0, ['example label']);
}); });
it('sets the class on the text element', function() { it('sets the class on the text element', function() {

View File

@ -1,7 +1,11 @@
// Base class for all nodes in the parse tree. An instance of this class is
// created for each parsed node, and then extended with one of the node-type
// modules.
import util from '../../util.js'; import util from '../../util.js';
import _ from 'lodash'; import _ from 'lodash';
export default class Node { export default class Node {
// Arguments passed in are defined by the canopy tool.
constructor(textValue, offset, elements, properties) { constructor(textValue, offset, elements, properties) {
this.textValue = textValue; this.textValue = textValue;
this.offset = offset; this.offset = offset;
@ -9,9 +13,13 @@ export default class Node {
this.properties = properties; this.properties = properties;
// This is the current parser state (an instance
// [ParserState](./parser_state.html).)
this.state = Node.state; this.state = Node.state;
} }
// Node-type module to extend the Node instance with. Setting of this is
// done by canopy during parsing and is setup in [parser.js](./parser.html).
set module(mod) { set module(mod) {
_.extend(this, mod); _.extend(this, mod);
@ -24,6 +32,9 @@ export default class Node {
}); });
} }
// The SVG element to render this node into. A node-type class is
// automatically added to the container. The class to set is defined on the
// module set during parsing.
set container(container) { set container(container) {
this._container = container; this._container = container;
this._container.addClass(this.type); this._container.addClass(this.type);
@ -33,6 +44,10 @@ export default class Node {
return this._container; return this._container;
} }
// The anchor defined the points on the left and right of the rendered node
// that the centerline of the rendered expression connects to. For most
// nodes, this element will be defined by the normalizeBBox method in
// [Util](../../util.html).
get anchor() { get anchor() {
if (this.proxy) { if (this.proxy) {
return this.proxy.anchor; return this.proxy.anchor;
@ -41,14 +56,23 @@ export default class Node {
} }
} }
// Returns the bounding box of the container with the anchor included.
getBBox() { getBBox() {
return _.extend(util.normalizeBBox(this.container.getBBox()), this.anchor); return _.extend(util.normalizeBBox(this.container.getBBox()), this.anchor);
} }
// Transforms the container.
//
// - __matrix__ - A matrix transform to be applied. Created using Snap.svg.
transform(matrix) { transform(matrix) {
return this.container.transform(matrix); return this.container.transform(matrix);
} }
// Returns a Promise that will be resolved with the provided value. If the
// render is cancelled before the Promise is resolved, then an exception will
// be thrown to halt any rendering.
//
// - __value__ - Value to resolve the returned promise with.
deferredStep(value) { deferredStep(value) {
return util.tick().then(() => { return util.tick().then(() => {
if (this.state.cancelRender) { if (this.state.cancelRender) {
@ -59,14 +83,22 @@ export default class Node {
}); });
} }
// Render this node.
//
// - __container__ - Optional element to render this node into. A container
// must be specified, but if it has already been set, then it does not
// need to be provided to render.
render(container) { render(container) {
if (container) { if (container) {
this.container = container; this.container = container;
} }
if (this.proxy) { if (this.proxy) {
// For nodes that proxy to a child node, just render the child.
return this.proxy.render(this.container); return this.proxy.render(this.container);
} else { } else {
// Non-proxied nodes call their _render method (defined by the node-type
// module).
this.state.renderCounter++; this.state.renderCounter++;
return this._render() return this._render()
.then(() => { .then(() => {
@ -76,14 +108,19 @@ export default class Node {
} }
} }
// Renders a label centered within a rectangle which can be styled. Returns
// a Promise which will be resolved with the SVG group the rect and text are
// rendered in.
//
// - __text__ - String or array of strings to render as a label.
renderLabel(text) { renderLabel(text) {
var group = this.container.group() var group = this.container.group()
.addClass('label'), .addClass('label'),
rect = group.rect(), rect = group.rect(),
text = group.text(0, 0, _.flatten([text])); text = group.text(0, 0, _.flatten([text]));
return this.deferredStep(group) return this.deferredStep()
.then(group => { .then(() => {
var box = text.getBBox(), var box = text.getBBox(),
margin = 5; margin = 5;
@ -99,11 +136,17 @@ export default class Node {
}); });
} }
// Renders a labeled box around another SVG element. Returns a Promise.
//
// - __label__ - String or array of strings to label the box with.
// - __content__ - SVG element to wrap in the box.
// - __options.padding__ - Pixels of padding to place between the content and
// the box.
renderLabeledBox(label, content, options) { renderLabeledBox(label, content, options) {
var label = this.container.text(0, 0, label) var label = this.container.text(0, 0, _.flatten([label]))
.addClass([this.type, 'label'].join('-')), .addClass(`${this.type}-label`),
box = this.container.rect() box = this.container.rect()
.addClass([this.type, 'box'].join('-')) .addClass(`${this.type}-box`)
.attr({ .attr({
rx: 3, rx: 3,
ry: 3 ry: 3

View File

@ -44,14 +44,14 @@ circle {
fill: $tan; fill: $tan;
} }
.subexp .subexp-label, .subexp .subexp-label tspan,
.charset .charset-label, .charset .charset-label tspan,
.match-fragment .repeat-label { .match-fragment .repeat-label tspan {
font-size: 10px; font-size: 10px;
} }
.subexp .subexp-label, .subexp .subexp-label tspan,
.charset .charset-label { .charset .charset-label tspan {
dominant-baseline: text-after-edge; dominant-baseline: text-after-edge;
} }