diff --git a/spec/parser/javascript/node_spec.js b/spec/parser/javascript/node_spec.js index 2c2680b..6e7478a 100644 --- a/spec/parser/javascript/node_spec.js +++ b/spec/parser/javascript/node_spec.js @@ -310,7 +310,7 @@ describe('parser/javascript/node.js', function() { it('creates a text element', function() { 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() { diff --git a/src/js/parser/javascript/node.js b/src/js/parser/javascript/node.js index 58836e4..94d8fbd 100644 --- a/src/js/parser/javascript/node.js +++ b/src/js/parser/javascript/node.js @@ -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 _ from 'lodash'; export default class Node { + // Arguments passed in are defined by the canopy tool. constructor(textValue, offset, elements, properties) { this.textValue = textValue; this.offset = offset; @@ -9,9 +13,13 @@ export default class Node { this.properties = properties; + // This is the current parser state (an instance + // [ParserState](./parser_state.html).) 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) { _.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) { this._container = container; this._container.addClass(this.type); @@ -33,6 +44,10 @@ export default class Node { 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() { if (this.proxy) { return this.proxy.anchor; @@ -41,14 +56,23 @@ export default class Node { } } + // Returns the bounding box of the container with the anchor included. getBBox() { 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) { 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) { return util.tick().then(() => { 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) { if (container) { this.container = container; } if (this.proxy) { + // For nodes that proxy to a child node, just render the child. return this.proxy.render(this.container); } else { + // Non-proxied nodes call their _render method (defined by the node-type + // module). this.state.renderCounter++; return this._render() .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) { var group = this.container.group() .addClass('label'), rect = group.rect(), text = group.text(0, 0, _.flatten([text])); - return this.deferredStep(group) - .then(group => { + return this.deferredStep() + .then(() => { var box = text.getBBox(), 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) { - var label = this.container.text(0, 0, label) - .addClass([this.type, 'label'].join('-')), + var label = this.container.text(0, 0, _.flatten([label])) + .addClass(`${this.type}-label`), box = this.container.rect() - .addClass([this.type, 'box'].join('-')) + .addClass(`${this.type}-box`) .attr({ rx: 3, ry: 3 diff --git a/src/sass/svg.scss b/src/sass/svg.scss index 1492f8a..1316adc 100644 --- a/src/sass/svg.scss +++ b/src/sass/svg.scss @@ -44,14 +44,14 @@ circle { fill: $tan; } -.subexp .subexp-label, -.charset .charset-label, -.match-fragment .repeat-label { +.subexp .subexp-label tspan, +.charset .charset-label tspan, +.match-fragment .repeat-label tspan { font-size: 10px; } -.subexp .subexp-label, -.charset .charset-label { +.subexp .subexp-label tspan, +.charset .charset-label tspan { dominant-baseline: text-after-edge; }