From a1f934d26a427e81b08b952b0ac089a97adb78aa Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Sun, 17 Mar 2013 17:20:06 -0700 Subject: [PATCH] changed label rect drawing from Polygon to Shape to support rounded corners soon. Also wrapped the text and rect inside of an inner group so that the label can be positioned based on the pointer tip --- src/plugins/Label.js | 196 ++++++++++++++++------------ tests/js/unit/plugins/labelTests.js | 21 +-- 2 files changed, 123 insertions(+), 94 deletions(-) diff --git a/src/plugins/Label.js b/src/plugins/Label.js index 21802dce..c0443756 100644 --- a/src/plugins/Label.js +++ b/src/plugins/Label.js @@ -1,24 +1,20 @@ (function() { // constants - var ATTR_CHANGE_LIST = ['fontFamily', 'fontSize', 'fontStyle', 'padding', 'lineHeight', 'text'], - CHANGE_KINETIC = 'Change.kinetic', - NONE = 'none', - TOP = 'top', + var NONE = 'none', + UP = 'up', RIGHT = 'right', - BOTTOM = 'bottom', + DOWN = 'down', LEFT = 'left'; - - // cached variables - attrChangeListLen = ATTR_CHANGE_LIST.length; - + /** * Label constructor.  Blobs are defined by an array of points and * a tension * @constructor * @param {Object} config - * @param {String} [config.arrow] can be none, top, right, bottom, or left. none is the default - * @param {Number} [config.arrowWidth] - * @param {Number} [config.arrowHeight] + * @param {String} [config.pointerDirection] can be none, up, right, down, or left. none is the default + * @param {Number} [config.pointerWidth] + * @param {Number} [config.pointerHeight] + @param {Number} [config.cornerRadius] default is 0 * @param {Object} config.text * @param {Object} config.rect * @param {String} [config.text.fontFamily] default is Calibri @@ -27,10 +23,7 @@ * @param {String} config.text.text * @param {String} [config.text.align] can be left, center, or right * @param {Number} [config.text.padding] - * @param {Number} [config.text.width] default is auto - * @param {Number} [config.text.height] default is auto - * @param {Number} [config.rect.lineHeight] default is 1 - * {{ShapeParams}} + * @param {Number} [config.text.lineHeight] default is 1 * {{NodeParams}} */ Kinetic.Plugins.Label = function(config) { @@ -39,85 +32,120 @@ Kinetic.Plugins.Label.prototype = { _initLabel: function(config) { - var that = this, - text = null; - + this.innerGroup = new Kinetic.Group(); this.createAttrs(); Kinetic.Group.call(this, config); this.setText(new Kinetic.Text(config.text)); - text = this.getText(); - this.setRect(new Kinetic.Polygon(config.rect)); - this.add(this.getRect()); - this.add(this.getText()); - - this._setPoints(); - - // update text data for certain attr changes - for(var n = 0; n < attrChangeListLen; n++) { - text.on(ATTR_CHANGE_LIST[n] + CHANGE_KINETIC, function() { - that._setPoints(); - }); - } + this.setRect(new Kinetic.Plugins.LabelRect(config.rect)); + this.getRect().text = this.getText(); + this.innerGroup.add(this.getRect()); + this.innerGroup.add(this.getText()); + this.add(this.innerGroup); + + this._setGroupOffset(); }, - _setPoints: function() { + _setGroupOffset: function() { var text = this.getText(), width = text.getWidth(), height = text.getHeight(), - points = [], - arrow = this.getArrow(), - arrowWidth = this.getArrowWidth(), - arrowHeight = this.getArrowHeight(); - - // top left corner - points.push(0); - points.push(0); - - - if (arrow === TOP) { - points.push((width - arrowWidth)/2, 0); - points.push(width/2, -1 * arrowHeight); - points.push((width + arrowWidth)/2, 0); - } - - // top right - points.push(width); - points.push(0); + rect = this.getRect(), + pointerDirection = rect.getPointerDirection(), + pointerWidth = rect.getPointerWidth(), + pointerHeight = rect.getPointerHeight(), + x = 0, + y = 0; - if (arrow === RIGHT) { - points.push(width, (height - arrowHeight)/2); - points.push(width + arrowWidth, height/2); - points.push(width, (height + arrowHeight)/2); - } - - // bottom right - points.push(width); - points.push(height); - - if (arrow === BOTTOM) { - points.push((width + arrowWidth)/2, height); - points.push(width/2, height + arrowHeight); - points.push((width - arrowWidth)/2, height); - } - - // bottom left - points.push(0); - points.push(height); - - if (arrow === LEFT) { - points.push(0, (height + arrowHeight)/2); - points.push(0 - arrowWidth, height/2); - points.push(0, (height - arrowHeight)/2); - } - - this.getRect().setPoints(points); + 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; + } + + this.setOffset({ + x: x, + y: y + }); } }; Kinetic.Global.extend(Kinetic.Plugins.Label, Kinetic.Group); - Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'text'); Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'rect'); - Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'arrow', NONE); - Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'arrowWidth', 0); - Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'arrowHeight', 0); -})(); + + Kinetic.Plugins.LabelRect = function(config) { + this._initLabelRect(config); + }; + + Kinetic.Plugins.LabelRect.prototype = { + _initLabelRect: function(config) { + this.createAttrs(); + Kinetic.Shape.call(this, config); + this.shapeType = 'LabelRect'; + this._setDrawFuncs(); + }, + drawFunc: function(canvas) { + var context = canvas.getContext(), + width = this.text.getWidth(), + height = this.text.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(); + canvas.fillStroke(this); + } + }; + + Kinetic.Global.extend(Kinetic.Plugins.LabelRect, Kinetic.Shape); + Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerDirection', NONE); + Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerWidth', 0); + Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerHeight', 0); + Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'cornerRadius', 0); +})(); \ No newline at end of file diff --git a/tests/js/unit/plugins/labelTests.js b/tests/js/unit/plugins/labelTests.js index 3e1bf0a2..af090acf 100644 --- a/tests/js/unit/plugins/labelTests.js +++ b/tests/js/unit/plugins/labelTests.js @@ -8,29 +8,30 @@ Test.Modules.LABEL = { var layer = new Kinetic.Layer(); var label = new Kinetic.Plugins.Label({ - x: 20, - y: 20, + x: 100, + y: 100, draggable: true, - arrow: 'left', - arrowWidth: 20, - arrowHeight: 20, - text: { + text: { text: 'Hello World!', fontSize: 50, fontFamily: 'Calibri', fontStyle: 'normal', lineHeight: 1.2, padding: 10, - fill: 'green', - }, + fill: 'green' + }, rect: { fill: '#bbb', stroke: '#333', shadowColor: 'black', - shadowBlur: 1, + shadowBlur: 10, shadowOffset: [10, 10], shadowOpacity: 0.2, - lineJoin: 'round' + lineJoin: 'round', + pointerDirection: 'down', + pointerWidth: 20, + pointerHeight: 20, + cornerRadius: 5 } });