(function() { /** * Line constructor. Lines are defined by an array of points and * a tension * @constructor * @memberof Konva * @augments Konva.Shape * @param {Object} config * @param {Array} config.points * @param {Number} [config.tension] Higher values will result in a more curvy line. A value of 0 will result in no interpolation. * The default is 0 * @param {Boolean} [config.closed] defines whether or not the line shape is closed, creating a polygon or blob * @@shapeParams * @@nodeParams * @example * var line = new Konva.Line({ * x: 100, * y: 50, * points: [73, 70, 340, 23, 450, 60, 500, 20], * stroke: 'red', * tension: 1 * }); */ Konva.Line = function(config) { this.___init(config); }; Konva.Line.prototype = { ___init: function(config) { // call super constructor Konva.Shape.call(this, config); this.className = 'Line'; this.on('pointsChange.konva tensionChange.konva closedChange.konva', function() { this._clearCache('tensionPoints'); }); this.sceneFunc(this._sceneFunc); }, _sceneFunc: function(context) { var points = this.getPoints(), length = points.length, tension = this.getTension(), closed = this.getClosed(), tp, len, n; if (!length) { return; } context.beginPath(); context.moveTo(points[0], points[1]); // tension if(tension !== 0 && length > 4) { tp = this.getTensionPoints(); len = tp.length; n = closed ? 0 : 4; if (!closed) { context.quadraticCurveTo(tp[0], tp[1], tp[2], tp[3]); } while(n < len - 2) { context.bezierCurveTo(tp[n++], tp[n++], tp[n++], tp[n++], tp[n++], tp[n++]); } if (!closed) { context.quadraticCurveTo(tp[len - 2], tp[len - 1], points[length - 2], points[length - 1]); } } // no tension else { for(n = 2; n < length; n += 2) { context.lineTo(points[n], points[n + 1]); } } // closed e.g. polygons and blobs if (closed) { context.closePath(); context.fillStrokeShape(this); } // open e.g. lines and splines else { context.strokeShape(this); } }, getTensionPoints: function() { return this._getCache('tensionPoints', this._getTensionPoints); }, _getTensionPoints: function() { if (this.getClosed()) { return this._getTensionPointsClosed(); } else { return Konva.Util._expandPoints(this.getPoints(), this.getTension()); } }, _getTensionPointsClosed: function() { var p = this.getPoints(), len = p.length, tension = this.getTension(), util = Konva.Util, firstControlPoints = util._getControlPoints( p[len - 2], p[len - 1], p[0], p[1], p[2], p[3], tension ), lastControlPoints = util._getControlPoints( p[len - 4], p[len - 3], p[len - 2], p[len - 1], p[0], p[1], tension ), middle = Konva.Util._expandPoints(p, tension), tp = [ firstControlPoints[2], firstControlPoints[3] ] .concat(middle) .concat([ lastControlPoints[0], lastControlPoints[1], p[len - 2], p[len - 1], lastControlPoints[2], lastControlPoints[3], firstControlPoints[0], firstControlPoints[1], p[0], p[1] ]); return tp; }, getWidth: function() { return this.getSelfRect().width; }, getHeight: function() { return this.getSelfRect().height; }, // overload size detection getSelfRect: function() { var points; if (this.getTension() !== 0) { points = this._getTensionPoints(); } else { points = this.getPoints(); } var minX = points[0]; var maxX = points[0]; var minY = points[0]; var maxY = points[0]; var x, y; for (var i = 0; i < points.length / 2; i++) { x = points[i * 2]; y = points[i * 2 + 1]; minX = Math.min(minX, x); maxX = Math.max(maxX, x); minY = Math.min(minY, y); maxY = Math.max(maxY, y); } return { x: Math.round(minX), y: Math.round(minY), width: Math.round(maxX - minX), height: Math.round(maxY - minY) }; } }; Konva.Util.extend(Konva.Line, Konva.Shape); // add getters setters Konva.Factory.addGetterSetter(Konva.Line, 'closed', false); /** * get/set closed flag. The default is false * @name closed * @method * @memberof Konva.Line.prototype * @param {Boolean} closed * @returns {Boolean} * @example * // get closed flag * var closed = line.closed(); * * // close the shape * line.closed(true); * * // open the shape * line.closed(false); */ Konva.Factory.addGetterSetter(Konva.Line, 'tension', 0); /** * get/set tension * @name tension * @method * @memberof Konva.Line.prototype * @param {Number} Higher values will result in a more curvy line. A value of 0 will result in no interpolation. * The default is 0 * @returns {Number} * @example * // get tension * var tension = line.tension(); * * // set tension * line.tension(3); */ Konva.Factory.addGetterSetter(Konva.Line, 'points', []); /** * get/set points array * @name points * @method * @memberof Konva.Line.prototype * @param {Array} points * @returns {Array} * @example * // get points * var points = line.points(); * * // set points * line.points([10, 20, 30, 40, 50, 60]); * * // push a new point * line.points(line.points().concat([70, 80])); */ Konva.Collection.mapMethods(Konva.Line); })();