(function() { // constants var ATTR_CHANGE_LIST = ['fontFamily', 'fontSize', 'fontStyle', 'padding', 'lineHeight', 'text'], CHANGE_KINETIC = 'Change.kinetic', NONE = 'none', UP = 'up', RIGHT = 'right', DOWN = 'down', LEFT = 'left', LABEL = 'Label', // cached variables attrChangeListLen = ATTR_CHANGE_LIST.length; /** * Label constructor. Labels are groups that contain a Text and Tag shape * @constructor * @memberof Kinetic * @param {Object} config * @@nodeParams * @example * // create label * var label = new Kinetic.Label({<br> * x: 100,<br> * y: 100, <br> * draggable: true<br> * });<br><br> * * // add a tag to the label<br> * label.add(new Kinetic.Tag({<br> * fill: '#bbb',<br> * stroke: '#333',<br> * shadowColor: 'black',<br> * shadowBlur: 10,<br> * shadowOffset: [10, 10],<br> * shadowOpacity: 0.2,<br> * lineJoin: 'round',<br> * pointerDirection: 'up',<br> * pointerWidth: 20,<br> * pointerHeight: 20,<br> * cornerRadius: 5<br> * }));<br><br> * * // add text to the label<br> * label.add(new Kinetic.Text({<br> * text: 'Hello World!',<br> * fontSize: 50,<br> * lineHeight: 1.2,<br> * padding: 10,<br> * fill: 'green'<br> * })); */ Kinetic.Label = function(config) { this.____init(config); }; Kinetic.Label.prototype = { ____init: function(config) { var that = this; this.className = LABEL; Kinetic.Group.call(this, config); this.on('add.kinetic', function(evt) { that._addListeners(evt.child); that._sync(); }); }, /** * get Text shape for the label. You need to access the Text shape in order to update * the text properties * @name getText * @method * @memberof Kinetic.Label.prototype */ getText: function() { return this.find('Text')[0]; }, /** * get Tag shape for the label. You need to access the Tag shape in order to update * the pointer properties and the corner radius * @name getTag * @method * @memberof Kinetic.Label.prototype */ getTag: function() { return this.find('Tag')[0]; }, _addListeners: function(text) { var that = this, n; var func = function(){ that._sync(); }; // update text data for certain attr changes for(n = 0; n < attrChangeListLen; n++) { text.on(ATTR_CHANGE_LIST[n] + CHANGE_KINETIC, func); } }, getWidth: function() { return this.getText().getWidth(); }, getHeight: function() { return this.getText().getHeight(); }, _sync: function() { var text = this.getText(), tag = this.getTag(), width, height, pointerDirection, pointerWidth, x, y; if (text && tag) { width = text.getWidth(), height = text.getHeight(), pointerDirection = tag.getPointerDirection(), pointerWidth = tag.getPointerWidth(), pointerHeight = tag.getPointerHeight(), x = 0, y = 0; switch(pointerDirection) { case UP: x = width / 2; y = -1 * pointerHeight; break; case RIGHT: x = width + pointerWidth; y = height / 2; break; case DOWN: x = width / 2; y = height + pointerHeight; break; case LEFT: x = -1 * pointerWidth; y = height / 2; break; } tag.setAttrs({ x: -1 * x, y: -1 * y, width: width, height: height }); text.setAttrs({ x: -1 * x, y: -1 * y }); } } }; Kinetic.Util.extend(Kinetic.Label, Kinetic.Group); Kinetic.Collection.mapMethods(Kinetic.Label); /** * Tag constructor. A Tag can be configured * to have a pointer element that points up, right, down, or left * @constructor * @memberof Kinetic * @param {Object} config * @param {String} [config.pointerDirection] can be up, right, down, left, or none; the default * is none. When a pointer is present, the positioning of the label is relative to the tip of the pointer. * @param {Number} [config.pointerWidth] * @param {Number} [config.pointerHeight] * @param {Number} [config.cornerRadius] */ Kinetic.Tag = function(config) { this.___init(config); }; Kinetic.Tag.prototype = { ___init: function(config) { Kinetic.Shape.call(this, config); this.className = 'Tag'; this.sceneFunc(this._sceneFunc); }, _sceneFunc: function(context) { var width = this.getWidth(), height = this.getHeight(), pointerDirection = this.getPointerDirection(), pointerWidth = this.getPointerWidth(), pointerHeight = this.getPointerHeight(), cornerRadius = this.getCornerRadius(); context.beginPath(); context.moveTo(0,0); if (pointerDirection === UP) { context.lineTo((width - pointerWidth)/2, 0); context.lineTo(width/2, -1 * pointerHeight); context.lineTo((width + pointerWidth)/2, 0); } context.lineTo(width, 0); if (pointerDirection === RIGHT) { context.lineTo(width, (height - pointerHeight)/2); context.lineTo(width + pointerWidth, height/2); context.lineTo(width, (height + pointerHeight)/2); } context.lineTo(width, height); if (pointerDirection === DOWN) { context.lineTo((width + pointerWidth)/2, height); context.lineTo(width/2, height + pointerHeight); context.lineTo((width - pointerWidth)/2, height); } context.lineTo(0, height); if (pointerDirection === LEFT) { context.lineTo(0, (height + pointerHeight)/2); context.lineTo(-1 * pointerWidth, height/2); context.lineTo(0, (height - pointerHeight)/2); } context.closePath(); context.fillStrokeShape(this); } }; Kinetic.Util.extend(Kinetic.Tag, Kinetic.Shape); Kinetic.Factory.addGetterSetter(Kinetic.Tag, 'pointerDirection', NONE); /** * set pointer Direction * @name setPointerDirection * @method * @memberof Kinetic.Tag.prototype * @param {String} pointerDirection can be up, right, down, left, or none. The * default is none */ /** * get pointer Direction * @name getPointerDirection * @method * @memberof Kinetic.Tag.prototype */ Kinetic.Factory.addGetterSetter(Kinetic.Tag, 'pointerWidth', 0); /** * set pointer width * @name setPointerWidth * @method * @memberof Kinetic.Tag.prototype * @param {Number} pointerWidth */ /** * get pointer width * @name getPointerWidth * @method * @memberof Kinetic.Tag.prototype */ Kinetic.Factory.addGetterSetter(Kinetic.Tag, 'pointerHeight', 0); /** * set pointer height * @name setPointerHeight * @method * @memberof Kinetic.Tag.prototype * @param {Number} pointerHeight */ /** * get pointer height * @name getPointerHeight * @method * @memberof Kinetic.Tag.prototype */ Kinetic.Factory.addGetterSetter(Kinetic.Tag, 'cornerRadius', 0); /** * set corner radius * @name setCornerRadius * @method * @memberof Kinetic.Tag.prototype * @param {Number} corner radius */ /** * get corner radius * @name getCornerRadius * @method * @memberof Kinetic.Tag.prototype */ Kinetic.Collection.mapMethods(Kinetic.Tag); })();