UNPKG

@sky-foundry/two.js

Version:

A renderer agnostic two-dimensional drawing api for the web.

344 lines (259 loc) 7.94 kB
(function(Two) { var root = Two.root; var getComputedMatrix = Two.Utils.getComputedMatrix; var _ = Two.Utils; var canvas = getCanvas(); var ctx = canvas.getContext('2d'); /** * @class * @name Two.Text * @param {String} message - The String to be rendered to the scene. * @param {Number} [x=0] - The position in the x direction for the object. * @param {Number} [y=0] - The position in the y direction for the object. * @param {Object} [styles] - An object where styles are applied. Attribute must exist in Two.Text.Properties. */ var Text = Two.Text = function(message, x, y, styles) { Two.Shape.call(this); this._renderer.type = 'text'; this._renderer.flagFill = _.bind(Two.Text.FlagFill, this); this._renderer.flagStroke = _.bind(Two.Text.FlagStroke, this); this.value = message; if (_.isNumber(x)) { this.translation.x = x; } if (_.isNumber(y)) { this.translation.y = y; } this.dashes = []; if (!_.isObject(styles)) { return this; } _.each(Two.Text.Properties, function(property) { if (property in styles) { this[property] = styles[property]; } }, this); }; _.extend(Two.Text, { Ratio: 0.6, Properties: [ 'value', 'family', 'size', 'leading', 'alignment', 'linewidth', 'style', 'className', 'weight', 'decoration', 'baseline', 'opacity', 'visible', 'fill', 'stroke', ], FlagFill: function() { this._flagFill = true; }, FlagStroke: function() { this._flagStroke = true; }, MakeObservable: function(object) { Two.Shape.MakeObservable(object); _.each(Two.Text.Properties.slice(0, 13), Two.Utils.defineProperty, object); Object.defineProperty(object, 'fill', { enumerable: true, get: function() { return this._fill; }, set: function(f) { if (this._fill instanceof Two.Gradient || this._fill instanceof Two.LinearGradient || this._fill instanceof Two.RadialGradient || this._fill instanceof Two.Texture) { this._fill.unbind(Two.Events.change, this._renderer.flagFill); } this._fill = f; this._flagFill = true; if (this._fill instanceof Two.Gradient || this._fill instanceof Two.LinearGradient || this._fill instanceof Two.RadialGradient || this._fill instanceof Two.Texture) { this._fill.bind(Two.Events.change, this._renderer.flagFill); } } }); Object.defineProperty(object, 'stroke', { enumerable: true, get: function() { return this._stroke; }, set: function(f) { if (this._stroke instanceof Two.Gradient || this._stroke instanceof Two.LinearGradient || this._stroke instanceof Two.RadialGradient || this._stroke instanceof Two.Texture) { this._stroke.unbind(Two.Events.change, this._renderer.flagStroke); } this._stroke = f; this._flagStroke = true; if (this._stroke instanceof Two.Gradient || this._stroke instanceof Two.LinearGradient || this._stroke instanceof Two.RadialGradient || this._stroke instanceof Two.Texture) { this._stroke.bind(Two.Events.change, this._renderer.flagStroke); } } }); Object.defineProperty(object, 'clip', { enumerable: true, get: function() { return this._clip; }, set: function(v) { this._clip = v; this._flagClip = true; } }); } }); _.extend(Two.Text.prototype, Two.Shape.prototype, { // Flags // http://en.wikipedia.org/wiki/Flag _flagValue: true, _flagFamily: true, _flagSize: true, _flagLeading: true, _flagAlignment: true, _flagBaseline: true, _flagStyle: true, _flagWeight: true, _flagDecoration: true, _flagFill: true, _flagStroke: true, _flagLinewidth: true, _flagOpacity: true, _flagClassName: true, _flagVisible: true, _flagClip: false, // Underlying Properties _value: '', _family: 'sans-serif', _size: 13, _leading: 17, _alignment: 'center', _baseline: 'middle', _style: 'normal', _weight: 500, _decoration: 'none', _fill: '#000', _stroke: 'transparent', _linewidth: 1, _opacity: 1, _className: '', _visible: true, _clip: false, constructor: Two.Text, remove: function() { if (!this.parent) { return this; } this.parent.remove(this); return this; }, clone: function(parent) { var clone = new Two.Text(this.value); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; _.each(Two.Text.Properties, function(property) { clone[property] = this[property]; }, this); if (parent) { parent.add(clone); } return clone._update(); }, toObject: function() { var result = { translation: this.translation.toObject(), rotation: this.rotation, scale: this.scale }; _.each(Two.Text.Properties, function(property) { result[property] = this[property]; }, this); return result; }, noStroke: function() { this.stroke = 'transparent'; return this; }, noFill: function() { this.fill = 'transparent'; return this; }, // /** // * A shim to not break `getBoundingClientRect` calls. TODO: Implement a // * way to calculate proper bounding boxes of `Two.Text`. // */ getBoundingClientRect: function(shallow) { var matrix, border, l, x, y, i, v; var left, right, top, bottom; // TODO: Update this to not __always__ update. Just when it needs to. this._update(true); matrix = !!shallow ? this._matrix : getComputedMatrix(this); var height = this.leading; var width = this.value.length * this.size * Text.Ratio; switch (this.alignment) { case 'left': left = 0; right = width; break; case 'right': left = - width; right = 0; break; default: left = - width / 2; right = width / 2; } switch (this.baseline) { case 'top': top = 0; bottom = height; break; case 'bottom': top = - height; bottom = 0; break; default: top = - height / 2; bottom = height / 2; } v = matrix.multiply(left, top, 1); top = v.y; left = v.x; v = matrix.multiply(right, bottom, 1); right = v.x; bottom = v.y; return { top: top, left: left, right: right, bottom: bottom, width: right - left, height: bottom - top }; }, flagReset: function() { this._flagValue = this._flagFamily = this._flagSize = this._flagLeading = this._flagAlignment = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagClip = this._flagDecoration = this._flagClassName = this._flagBaseline = false; Two.Shape.prototype.flagReset.call(this); return this; } }); Two.Text.MakeObservable(Two.Text.prototype); function getCanvas() { if (root.document) { return root.document.createElement('canvas'); } else { console.warn('Two.js: Unable to create canvas for Two.Text measurements.'); return { getContext: _.identity } } } })((typeof global !== 'undefined' ? global : (this || window)).Two);