From f97012195992d203771643389d56463393a6cc72 Mon Sep 17 00:00:00 2001 From: Anton Lavrenov Date: Tue, 21 Apr 2020 14:11:52 -0500 Subject: [PATCH] many transformer fixes --- konva.js | 1746 +++----------------------- konva.min.js | 4 +- src/shapes/Transformer.ts | 440 +++---- test/unit/shapes/Transformer-test.js | 549 +++++--- 4 files changed, 696 insertions(+), 2043 deletions(-) diff --git a/konva.js b/konva.js index 0f797f64..9c0e0aed 100644 --- a/konva.js +++ b/konva.js @@ -5,10 +5,10 @@ }(this, (function () { 'use strict'; /* - * Konva JavaScript Framework v4.2.2 + * Konva JavaScript Framework v@@version * http://konvajs.org/ * Licensed under the MIT - * Date: Mon Apr 13 2020 + * Date: @@date * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) @@ -76,7 +76,7 @@ : {}; var Konva = { _global: glob, - version: '4.2.2', + version: '@@version', isBrowser: detectBrowser(), isUnminified: /param/.test(function (param) { }.toString()), dblClickWindow: 400, @@ -2597,26 +2597,7 @@ * @constructor * @memberof Konva * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams */ var Node = /** @class */ (function () { function Node(config) { @@ -5163,33 +5144,8 @@ * @augments Konva.Node * @abstract * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams */ var Container = /** @class */ (function (_super) { __extends(Container, _super); @@ -5830,26 +5786,7 @@ * @augments Konva.Container * @param {Object} config * @param {String|Element} config.container Container selector or DOM element - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams * @example * var stage = new Konva.Stage({ * width: 500, @@ -6691,33 +6628,8 @@ * @param {Object} config * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want * to clear the canvas before each layer draw. The default value is true. - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams */ var BaseLayer = /** @class */ (function (_super) { __extends(BaseLayer, _super); @@ -7048,78 +6960,8 @@ * @memberof Konva * @augments Konva.Node * @param {Object} config - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var customShape = new Konva.Shape({ * x: 5, @@ -8622,33 +8464,8 @@ * @param {Object} config * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want * to clear the canvas before each layer draw. The default value is true. - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams * @example * var layer = new Konva.Layer(); * stage.add(layer); @@ -8866,13 +8683,7 @@ * @param {String} [config.id] unique id * @param {String} [config.name] non-unique name * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@containerParams * @example * var layer = new Konva.FastLayer(); */ @@ -8914,33 +8725,8 @@ * @memberof Konva * @augments Konva.Container * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams * @example * var group = new Konva.Group(); */ @@ -9907,78 +9693,8 @@ * @param {Number} config.innerRadius * @param {Number} config.outerRadius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // draw a Arc that's pointing downwards * var arc = new Konva.Arc({ @@ -10096,78 +9812,8 @@ * The default is 0 * @param {Boolean} [config.closed] defines whether or not the line shape is closed, creating a polygon or blob * @param {Boolean} [config.bezier] if no tension is provided but bezier=true, we draw the line as a bezier using the passed points - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var line = new Konva.Line({ * x: 100, @@ -10390,78 +10036,8 @@ * @param {Number} config.pointerLength Arrow pointer length. Default value is 10. * @param {Number} config.pointerWidth Arrow pointer width. Default value is 10. * @param {Boolean} config.pointerAtBeginning Do we need to draw pointer on both sides?. Default false. - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var line = new Konva.Line({ * points: [73, 70, 340, 23, 450, 60, 500, 20], @@ -10607,78 +10183,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Number} config.radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // create circle * var circle = new Konva.Circle({ @@ -10744,78 +10250,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Object} config.radius defines x and y radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var ellipse = new Konva.Ellipse({ * radius : { @@ -10918,78 +10354,8 @@ * @param {Object} config * @param {Image} config.image * @param {Object} [config.crop] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var imageObj = new Image(); * imageObj.onload = function() { @@ -11202,26 +10568,7 @@ * @constructor * @memberof Konva * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams * @example * // create label * var label = new Konva.Label({ @@ -11497,78 +10844,8 @@ * @augments Konva.Shape * @param {Object} config * @param {String} config.data SVG data string - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var path = new Konva.Path({ * x: 240, @@ -12314,78 +11591,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Number} [config.cornerRadius] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var rect = new Konva.Rect({ * width: 100, @@ -12466,78 +11673,8 @@ * @param {Object} config * @param {Number} config.sides * @param {Number} config.radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var hexagon = new Konva.RegularPolygon({ * x: 100, @@ -12624,78 +11761,8 @@ * @param {Number} config.innerRadius * @param {Number} config.outerRadius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var ring = new Konva.Ring({ * innerRadius: 40, @@ -12777,78 +11844,8 @@ * @param {Integer} [config.frameIndex] animation frame index * @param {Image} config.image image object * @param {Integer} [config.frameRate] animation frame rate - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var imageObj = new Image(); * imageObj.onload = function() { @@ -13144,78 +12141,8 @@ * @param {Integer} config.numPoints * @param {Number} config.innerRadius * @param {Number} config.outerRadius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var star = new Konva.Star({ * x: 100, @@ -13371,78 +12298,8 @@ * @param {Number} [config.lineHeight] default is 1 * @param {String} [config.wrap] can be "word", "char", or "none". Default is word * @param {Boolean} [config.ellipsis] can be true or false. Default is false. if Konva.Text config is set to wrap="none" and ellipsis=true, then it will add "..." to the end - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var text = new Konva.Text({ * x: 10, @@ -14032,78 +12889,8 @@ * @param {String} config.data SVG data string * @param {Function} config.getKerning a getter for kerning values for the specified characters * @param {Function} config.kerningFunc a getter for kerning values for the specified characters - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var kerningPairs = { * 'A': { @@ -14700,16 +13487,11 @@ 'bottom-right': 135 }; var TOUCH_DEVICE = 'ontouchstart' in Konva._global; - function getCursor(anchorName, rad, isMirrored) { + function getCursor(anchorName, rad) { if (anchorName === 'rotater') { return 'crosshair'; } rad += Util._degToRad(ANGLES[anchorName] || 0); - // If we are mirrored, we need to mirror the angle (this is not the same as - // rotate). - if (isMirrored) { - rad *= -1; - } var angle = ((Util._radToDeg(rad) % 360) + 360) % 360; if (Util._inRange(angle, 315 + 22.5, 360) || Util._inRange(angle, 0, 22.5)) { // TOP @@ -14810,16 +13592,6 @@ }; } function getShapesRect(shapes) { - // if (shapes.length === 1) { - // const shape = shapes[0]; - // return { - // x: shape.x, - // y: shape.y, - // width: shape.width, - // height: shape.height, - // rotation: shape.rotation - // }; - // } var x1 = 9999999999; var y1 = 9999999999; var x2 = -999999999; @@ -14946,42 +13718,12 @@ return this; }; Transformer.prototype.setNode = function (node) { + Util.warn('tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.'); return this.setNodes([node]); - // if (this._node) { - // this.detach(); - // } - // this._node = node; - // this._resetTransformCache(); - // const additionalEvents = node._attrsAffectingSize - // .map(prop => prop + 'Change.' + EVENTS_NAME) - // .join(' '); - // const onChange = () => { - // this._resetTransformCache(); - // if (!this._transforming) { - // this.update(); - // } - // }; - // node.on(additionalEvents, onChange); - // node.on(TRANSFORM_CHANGE_STR, onChange); - // node.on(`xChange.${EVENTS_NAME} yChange.${EVENTS_NAME}`, () => - // this._resetTransformCache() - // ); - // // we may need it if we set node in initial props - // // so elements are not defined yet - // var elementsCreated = !!this.findOne('.top-left'); - // if (elementsCreated) { - // this.update(); - // } - // return this; }; Transformer.prototype.getNode = function () { return this._nodes && this._nodes[0]; }; - Transformer.prototype.drawScene = function (can, top, caching) { - return _super.prototype.drawScene.call(this, can, top, caching); - }; - // _attachTo(node) => { - // } Transformer.prototype.setNodes = function (nodes) { var _this = this; if (nodes === void 0) { nodes = []; } @@ -15011,6 +13753,7 @@ _this._resetTransformCache(); }); node.on("xChange." + EVENTS_NAME + " yChange." + EVENTS_NAME, onChange); + _this._proxyDrag(node); }); this._resetTransformCache(); // we may need it if we set node in initial props @@ -15021,6 +13764,36 @@ } return this; }; + Transformer.prototype._proxyDrag = function (node) { + var _this = this; + var lastPos; + node.on("dragstart." + EVENTS_NAME, function () { + lastPos = node.getAbsolutePosition(); + }); + node.on("dragmove." + EVENTS_NAME, function () { + if (!lastPos) { + return; + } + var abs = node.getAbsolutePosition(); + var dx = abs.x - lastPos.x; + var dy = abs.y - lastPos.y; + _this.nodes().forEach(function (otherNode) { + if (otherNode === node) { + return; + } + if (otherNode.isDragging()) { + return; + } + var otherAbs = otherNode.getAbsolutePosition(); + otherNode.setAbsolutePosition({ + x: otherAbs.x + dx, + y: otherAbs.y + dy + }); + otherNode.startDrag(); + }); + lastPos = null; + }); + }; Transformer.prototype.getNodes = function () { return this._nodes; }; @@ -15096,9 +13869,6 @@ rotation: 0 }; } - if (node.parent && this.parent && node.parent !== this.parent) { - Util.warn('Transformer and attached node have different parents. Konva does not support such case right now. Please move Transformer to the parent of attaching node.'); - } var shapes = this.nodes().map(function (node) { return _this.__getNodeShape(node); }); @@ -15107,13 +13877,6 @@ x: 0, y: 0 }); - // return { - // x: node.x() + dx * Math.cos(rotation) + dy * Math.sin(-rotation), - // y: node.y() + dy * Math.cos(rotation) + dx * Math.sin(rotation), - // width: rect.width * node.scaleX(), - // height: rect.height * node.scaleY(), - // rotation: node.rotation() - // }; }; Transformer.prototype.getX = function () { return this._getNodeRect().x; @@ -15149,22 +13912,10 @@ anchor.on('mousedown touchstart', function (e) { self._handleMouseDown(e); }); - // anchor.on('dragstart', function(e) { - // e.cancelBubble = true; - // }); - // anchor.on('dragmove', function(e) { - // e.cancelBubble = true; - // }); - // anchor.on('dragend', function(e) { - // e.cancelBubble = true; - // }); // add hover styling anchor.on('mouseenter', function () { var rad = Konva.getAngle(_this.rotation()); - // var scale = this.getNode().getAbsoluteScale(); - // If scale.y < 0 xor scale.x < 0 we need to flip (not rotate). - // var isMirrored = false; - var cursor = getCursor(name, rad, false); + var cursor = getCursor(name, rad); anchor.getStage().content.style.cursor = cursor; _this._cursorChange = true; }); @@ -15178,10 +13929,12 @@ this.add(anchor); }; Transformer.prototype._createBack = function () { + var _this = this; var back = new Shape({ name: 'back', width: 0, height: 0, + draggable: true, sceneFunc: function (ctx) { var tr = this.getParent(); var padding = tr.padding(); @@ -15193,21 +13946,18 @@ } ctx.fillStrokeShape(this); }, - listening: false - // hitFunc(ctx) { - // var tr = this.getParent(); - // var padding = tr.padding(); - // ctx.beginPath(); - // ctx.rect( - // -padding, - // -padding, - // this.width() + padding * 2, - // this.height() + padding * 2 - // ); - // ctx.fillStrokeShape(this); - // } + hitFunc: function (ctx, shape) { + if (!_this.shouldOverdrawWholeArea()) { + return; + } + var padding = _this.padding(); + ctx.beginPath(); + ctx.rect(-padding, -padding, shape.width() + padding * 2, shape.height() + padding * 2); + ctx.fillStrokeShape(shape); + } }); this.add(back); + this._proxyDrag(back); }; Transformer.prototype._handleMouseDown = function (e) { this._movingAnchorName = e.target.name().split(' ')[0]; @@ -15267,184 +14017,122 @@ this._fitNodesInto(shape, e); return; } - var padding = 0; - // var centeredScaling = this.centeredScaling() || e.altKey; - // if (centeredScaling && this._movingAnchorName.indexOf('left') >= 0) { - // var topLeft = this.findOne('.top-left'); - // var bottomRight = this.findOne('.bottom-right'); - // var topOffsetX = topLeft.x() + padding; - // var topOffsetY = topLeft.y() + padding; - // var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; - // var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; - // bottomRight.move({ - // x: -topOffsetX, - // y: -topOffsetY - // }); - // topLeft.move({ - // x: bottomOffsetX, - // y: bottomOffsetY - // }); - // } var keepProportion = this.keepRatio() || e.shiftKey; + var centeredScaling = this.centeredScaling() || e.altKey; if (this._movingAnchorName === 'top-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: -anchorNode.y() - // }); - // } if (keepProportion) { - newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-right').x() - anchorNode.x() - padding * 2, 2) + - Math.pow(this.findOne('.bottom-right').y() - anchorNode.y() - padding * 2, 2)); - var reverseX = this.findOne('.top-left').x() > this.findOne('.bottom-right').x() - ? -1 - : 1; - var reverseY = this.findOne('.top-left').y() > this.findOne('.bottom-right').y() - ? -1 - : 1; + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.bottom-right').x(), + y: this.findOne('.bottom-right').y() + }; + newHypotenuse = Math.sqrt(Math.pow(comparePoint.x - anchorNode.x(), 2) + + Math.pow(comparePoint.y - anchorNode.y(), 2)); + var reverseX = this.findOne('.top-left').x() > comparePoint.x ? -1 : 1; + var reverseY = this.findOne('.top-left').y() > comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.top-left').x(this.findOne('.bottom-right').x() - x - padding * 2); - this.findOne('.top-left').y(this.findOne('.bottom-right').y() - y - padding * 2); + this.findOne('.top-left').x(comparePoint.x - x); + this.findOne('.top-left').y(comparePoint.y - y); } } else if (this._movingAnchorName === 'top-center') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: 0, - // y: -anchorNode.y() - // }); - // } this.findOne('.top-left').y(anchorNode.y()); } else if (this._movingAnchorName === 'top-right') { - // if (centeredScaling) { - // // this.findOne('.bottom-left').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: -anchorNode.y() - // // }); - // // this.findOne('.top-left').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: anchorNode.y() - // // }); - // // this.findOne('.bottom-right').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: anchorNode.y() - // // }); - // } - // var center = getCenter({ - // x - // }) if (keepProportion) { - newHypotenuse = Math.sqrt(Math.pow(anchorNode.x() - this.findOne('.bottom-left').x() - padding * 2, 2) + - Math.pow(this.findOne('.bottom-left').y() - anchorNode.y() - padding * 2, 2)); - var reverseX = this.findOne('.top-right').x() < this.findOne('.top-left').x() - ? -1 - : 1; - var reverseY = this.findOne('.top-right').y() > this.findOne('.bottom-left').y() - ? -1 - : 1; + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.bottom-left').x(), + y: this.findOne('.bottom-left').y() + }; + newHypotenuse = Math.sqrt(Math.pow(anchorNode.x() - comparePoint.x, 2) + + Math.pow(comparePoint.y - anchorNode.y(), 2)); + var reverseX = this.findOne('.top-right').x() < comparePoint.x ? -1 : 1; + var reverseY = this.findOne('.top-right').y() > comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.top-right').x(x + padding); - this.findOne('.top-right').y(this.findOne('.bottom-left').y() - y - padding * 2); + this.findOne('.top-right').x(comparePoint.x + x); + this.findOne('.top-right').y(comparePoint.y - y); } var pos = anchorNode.position(); this.findOne('.top-left').y(pos.y); this.findOne('.bottom-right').x(pos.x); } else if (this._movingAnchorName === 'middle-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: 0 - // }); - // } this.findOne('.top-left').x(anchorNode.x()); } else if (this._movingAnchorName === 'middle-right') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: 0 - // }); - // } this.findOne('.bottom-right').x(anchorNode.x()); } else if (this._movingAnchorName === 'bottom-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: -(anchorNode.y() - this.height()) - // }); - // } if (keepProportion) { - newHypotenuse = Math.sqrt(Math.pow(this.findOne('.top-right').x() - anchorNode.x() - padding * 2, 2) + - Math.pow(anchorNode.y() - this.findOne('.top-right').y() - padding * 2, 2)); - var reverseX = this.findOne('.top-right').x() < this.findOne('.bottom-left').x() - ? -1 - : 1; - var reverseY = this.findOne('.bottom-left').y() < this.findOne('.top-right').y() - ? -1 - : 1; + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.top-right').x(), + y: this.findOne('.top-right').y() + }; + newHypotenuse = Math.sqrt(Math.pow(comparePoint.x - anchorNode.x(), 2) + + Math.pow(anchorNode.y() - comparePoint.y, 2)); + var reverseX = comparePoint.x < anchorNode.x() ? -1 : 1; + var reverseY = anchorNode.y() < comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.bottom-left').x(this.findOne('.top-right').x() - x - padding * 2); - this.findOne('.bottom-left').y(y + padding); + anchorNode.x(comparePoint.x - x); + anchorNode.y(comparePoint.y + y); } pos = anchorNode.position(); this.findOne('.top-left').x(pos.x); this.findOne('.bottom-right').y(pos.y); } else if (this._movingAnchorName === 'bottom-center') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: 0, - // y: -(anchorNode.y() - this.height()) - // }); - // } this.findOne('.bottom-right').y(anchorNode.y()); } else if (this._movingAnchorName === 'bottom-right') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: -(anchorNode.y() - this.height()) - // }); - // } if (keepProportion) { - newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-right').x() - padding, 2) + - Math.pow(this.findOne('.bottom-right').y() - padding, 2)); - var reverseX = this.findOne('.top-left').x() > this.findOne('.bottom-right').x() - ? -1 - : 1; - var reverseY = this.findOne('.top-left').y() > this.findOne('.bottom-right').y() - ? -1 - : 1; + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.top-left').x(), + y: this.findOne('.top-left').y() + }; + newHypotenuse = Math.sqrt(Math.pow(anchorNode.x() - comparePoint.x, 2) + + Math.pow(anchorNode.y() - comparePoint.y, 2)); + var reverseX = this.findOne('.bottom-right').x() < comparePoint.x ? -1 : 1; + var reverseY = this.findOne('.bottom-right').y() < comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.bottom-right').x(x + padding); - this.findOne('.bottom-right').y(y + padding); + this.findOne('.bottom-right').x(comparePoint.x + x); + this.findOne('.bottom-right').y(comparePoint.y + y); } } else { console.error(new Error('Wrong position argument of selection resizer: ' + this._movingAnchorName)); } - if (this._movingAnchorName === 'rotater') { - return; - } var centeredScaling = this.centeredScaling() || e.altKey; if (centeredScaling) { var topLeft = this.findOne('.top-left'); var bottomRight = this.findOne('.bottom-right'); - var topOffsetX = topLeft.x() + padding; - var topOffsetY = topLeft.y() + padding; - var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; - var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; - if (Math.abs(topOffsetY) > 10) { - debugger; - } + var topOffsetX = topLeft.x(); + var topOffsetY = topLeft.y(); + var bottomOffsetX = this.getWidth() - bottomRight.x(); + var bottomOffsetY = this.getHeight() - bottomRight.y(); bottomRight.move({ x: -topOffsetX, y: -topOffsetY @@ -15504,13 +14192,11 @@ this.update(); return; } - // if (newAttrs.width < 0) { - // debugger; - // } - var an = this._movingAnchorName; var t = new Transform(); t.rotate(Konva.getAngle(this.rotation())); - if (an && newAttrs.width < 0 && an.indexOf('left') >= 0) { + if (this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('left') >= 0) { var offset = t.point({ x: -this.padding() * 2, y: 0 @@ -15518,38 +14204,44 @@ newAttrs.x += offset.x; newAttrs.y += offset.y; newAttrs.width += this.padding() * 2; - this._movingAnchorName = an.replace('left', 'right'); + this._movingAnchorName = this._movingAnchorName.replace('left', 'right'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; } - else if (an && newAttrs.width < 0 && an.indexOf('right') >= 0) { + else if (this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('right') >= 0) { var offset = t.point({ x: this.padding() * 2, y: 0 }); - this._movingAnchorName = an.replace('right', 'left'); + this._movingAnchorName = this._movingAnchorName.replace('right', 'left'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.width += this.padding() * 2; } - if (an && newAttrs.height < 0 && an.indexOf('top') >= 0) { + if (this._movingAnchorName && + newAttrs.height < 0 && + this._movingAnchorName.indexOf('top') >= 0) { var offset = t.point({ x: 0, y: -this.padding() * 2 }); newAttrs.x += offset.x; newAttrs.y += offset.y; - this._movingAnchorName = an.replace('top', 'bottom'); + this._movingAnchorName = this._movingAnchorName.replace('top', 'bottom'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.height += this.padding() * 2; } - else if (an && newAttrs.height < 0 && an.indexOf('bottom') >= 0) { + else if (this._movingAnchorName && + newAttrs.height < 0 && + this._movingAnchorName.indexOf('bottom') >= 0) { var offset = t.point({ x: 0, y: this.padding() * 2 }); - this._movingAnchorName = an.replace('bottom', 'top'); + this._movingAnchorName = this._movingAnchorName.replace('bottom', 'top'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.height += this.padding() * 2; @@ -15572,7 +14264,6 @@ skipShadow: true, skipStroke: this.ignoreStroke() }); - var padding = 0; var parentTransform = node .getParent() .getAbsoluteTransform() @@ -15587,17 +14278,11 @@ var absScale = node.getParent().getAbsoluteScale(); pure.width *= absScale.x; pure.height *= absScale.y; - // pure.x -= absPos.x; - // pure.y -= absPos.y; - // newAttrs.x = (newAttrs.x - absPos.x) / absScale.x; - // newAttrs.y = (newAttrs.y - absPos.y) / absScale.y; - var scaleX = pure.width ? (newAttrs.width - padding * 2) / pure.width : 1; - var scaleY = pure.height - ? (newAttrs.height - padding * 2) / pure.height - : 1; + var scaleX = pure.width ? newAttrs.width / pure.width : 1; + var scaleY = pure.height ? newAttrs.height / pure.height : 1; var rotation = Konva.getAngle(node.rotation()); - var dx = pure.x * scaleX - padding - node.offsetX() * scaleX; - var dy = pure.y * scaleY - padding - node.offsetY() * scaleY; + var dx = pure.x * scaleX - node.offsetX() * scaleX; + var dy = pure.y * scaleY - node.offsetY() * scaleY; node.setAttrs({ scaleX: scaleX, scaleY: scaleY, @@ -15702,7 +14387,9 @@ visible: this.borderEnabled(), stroke: this.borderStroke(), strokeWidth: this.borderStrokeWidth(), - dash: this.borderDash() + dash: this.borderDash(), + x: 0, + y: 0 }); }; /** @@ -16075,6 +14762,7 @@ * }); */ Factory.addGetterSetter(Transformer, 'boundBoxFunc'); + Factory.addGetterSetter(Transformer, 'shouldOverdrawWholeArea', false); Factory.backCompat(Transformer, { lineEnabled: 'borderEnabled', rotateHandlerOffset: 'rotateAnchorOffset', @@ -16091,78 +14779,8 @@ * @param {Number} config.angle in degrees * @param {Number} config.radius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shasow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or sqare. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // draw a wedge that's pointing downwards * var wedge = new Konva.Wedge({ diff --git a/konva.min.js b/konva.min.js index a5254f0b..36fb0842 100644 --- a/konva.min.js +++ b/konva.min.js @@ -3,10 +3,10 @@ * Konva JavaScript Framework v4.2.2 * http://konvajs.org/ * Licensed under the MIT - * Date: Mon Apr 13 2020 + * Date: Tue Apr 21 2020 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * * @license - */var e=Math.PI/180;function t(t){var e=t.toLowerCase(),i=/(chrome)[ /]([\w.]+)/.exec(e)||/(webkit)[ /]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ /]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[],n=!!t.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i),r=!!t.match(/IEMobile/i);return{browser:i[1]||"",version:i[2]||"0",isIE:function(t){var e=t.indexOf("msie ");if(0>16&255,g:e>>8&255,b:255&e}},getRandomColor:function(){for(var t=(16777215*Math.random()<<0).toString(16);t.length<6;)t="0"+t;return"#"+t},get:function(t,e){return void 0===t?e:t},getRGB:function(t){var e;return t in p?{r:(e=p[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=u.exec(t.replace(/ /g,"")),{r:parseInt(e[1],10),g:parseInt(e[2],10),b:parseInt(e[3],10)}):{r:0,g:0,b:0}},colorToRGBA:function(t){return t=t||"black",M._namedColorToRBA(t)||M._hex3ColorToRGBA(t)||M._hex6ColorToRGBA(t)||M._rgbColorToRGBA(t)||M._rgbaColorToRGBA(t)||M._hslColorToRGBA(t)},_namedColorToRBA:function(t){var e=p[t.toLowerCase()];return e?{r:e[0],g:e[1],b:e[2],a:1}:null},_rgbColorToRGBA:function(t){if(0===t.indexOf("rgb(")){var e=(t=t.match(/rgb\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:1}}},_rgbaColorToRGBA:function(t){if(0===t.indexOf("rgba(")){var e=(t=t.match(/rgba\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:e[3]}}},_hex6ColorToRGBA:function(t){if("#"===t[0]&&7===t.length)return{r:parseInt(t.slice(1,3),16),g:parseInt(t.slice(3,5),16),b:parseInt(t.slice(5,7),16),a:1}},_hex3ColorToRGBA:function(t){if("#"===t[0]&&4===t.length)return{r:parseInt(t[1]+t[1],16),g:parseInt(t[2]+t[2],16),b:parseInt(t[3]+t[3],16),a:1}},_hslColorToRGBA:function(t){if(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)){var e=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t),i=(e[0],e.slice(1)),n=Number(i[0])/360,r=Number(i[1])/100,o=Number(i[2])/100,a=void 0,s=void 0,h=void 0;if(0==r)return h=255*o,{r:Math.round(h),g:Math.round(h),b:Math.round(h),a:1};for(var d=2*o-(a=o<.5?o*(1+r):o+r-o*r),l=[0,0,0],c=0;c<3;c++)(s=n+1/3*-(c-1))<0&&s++,1t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var a=e;e=t,t=a}for(n=0;n=this.parent.children.length)&&M.warn("Unexpected value "+t+" for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to "+(this.parent.children.length-1)+".");var e=this.index;return this.parent.children.splice(e,1),this.parent.children.splice(t,0,this),this.parent._setChildrenIndices(),this},pt.prototype.getAbsoluteOpacity=function(){return this._getCache(Z,this._getAbsoluteOpacity)},pt.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=e.getAbsoluteOpacity()),t},pt.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},pt.prototype.toObject=function(){var t,e,i,n={},r=this.getAttrs();for(t in n.attrs={},r)e=r[t],M.isObject(e)&&!M._isPlainObject(e)&&!M._isArray(e)||(i="function"==typeof this[t]&&this[t],delete r[t],(i?i.call(this):null)!==(r[t]=e)&&(n.attrs[t]=e));return n.className=this.getClassName(),M._prepareToStringify(n)},pt.prototype.toJSON=function(){return JSON.stringify(this.toObject())},pt.prototype.getParent=function(){return this.parent},pt.prototype.findAncestors=function(t,e,i){var n=[];e&&this._isMatch(t)&&n.push(this);for(var r=this.parent;r;){if(r===i)return n;r._isMatch(t)&&n.push(r),r=r.parent}return n},pt.prototype.isAncestorOf=function(t){return!1},pt.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},pt.prototype._isMatch=function(t){if(!t)return!1;if("function"==typeof t)return t(this);var e,i,n=t.replace(/ /g,"").split(","),r=n.length;for(e=0;ethis.duration?this.yoyo?(this._time=this.duration,this.reverse()):this.finish():t<0?this.yoyo?(this._time=0,this.play()):this.reset():(this._time=t,this.update())},Re.prototype.getTime=function(){return this._time},Re.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},Re.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},Re.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},Re.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},Re.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},Re.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},Re.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},Re.prototype.update=function(){this.setPosition(this.getPosition(this._time))},Re.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},Re.prototype.pause=function(){this.state=1,this.fire("onPause")},Re.prototype.getTimer=function(){return(new Date).getTime()},Re);function Re(t,e,i,n,r,o,a){this.prop=t,this.propFunc=e,this.begin=n,this._pos=n,this.duration=o,this._change=0,this.prevPos=0,this.yoyo=a,this._time=0,this._position=0,this._startTime=0,this._finish=0,this.func=i,this._change=r-this.begin,this.pause()}var Oe=(Ie.prototype._addAttr=function(t,e){var i,n,r,o,a,s,h,d,l=this.node,c=l._id;if((r=Ie.tweens[c][t])&&delete Ie.attrs[c][r][t],i=l.getAttr(t),M._isArray(e))if(n=[],a=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=M._prepareArrayForTween(i,e,l.closed())):(s=e,e=M._prepareArrayForTween(e,i,l.closed()))),0===t.indexOf("fill"))for(o=0;othis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===n)return{x:(e=this.dataArray[i-1].points.slice(-2))[0],y:e[1]};if(t<.01)return{x:(e=this.dataArray[i].points.slice(0,2))[0],y:e[1]};var r=this.dataArray[i],o=r.points;switch(r.command){case"L":return ui.getPointOnLine(t,r.start.x,r.start.y,o[0],o[1]);case"C":return ui.getPointOnCubicBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3],o[4],o[5]);case"Q":return ui.getPointOnQuadraticBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3]);case"A":var a=o[0],s=o[1],h=o[2],d=o[3],l=o[4],c=o[5],p=o[6];return l+=c*t/r.pathLength,ui.getPointOnEllipticalArc(a,s,h,d,l,p)}return null},ui.getLineLength=function(t,e,i,n){return Math.sqrt((i-t)*(i-t)+(n-e)*(n-e))},ui.getPointOnLine=function(t,e,i,n,r,o,a){void 0===o&&(o=e),void 0===a&&(a=i);var s=(r-i)/(n-e+1e-8),h=Math.sqrt(t*t/(1+s*s));n>>1,k=_.slice(0,1+P),T=this._getTextWidth(k)+v;T<=d?(b=1+P,w=k+(g?"…":""),C=T):x=P}if(!w)break;if(f){var A,M=_[w.length];0<(A=(" "===M||"-"===M)&&C<=d?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(b=A,w=w.slice(0,b),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=n,!u||s&&le?g=pi.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var a=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=a+1e-8:iv.pathLength?1e-8:e/v.pathLength:ithis.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1;e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-left").x(this.findOne(".bottom-right").x()-e-0),this.findOne(".top-left").y(this.findOne(".bottom-right").y()-i-0)}}else if("top-center"===this._movingAnchorName)this.findOne(".top-left").y(r.y());else if("top-right"===this._movingAnchorName){l&&(n=Math.sqrt(Math.pow(r.x()-this.findOne(".bottom-left").x()-0,2)+Math.pow(this.findOne(".bottom-left").y()-r.y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-left").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-right").x(e+0),this.findOne(".top-right").y(this.findOne(".bottom-left").y()-i-0));var u=r.position();this.findOne(".top-left").y(u.y),this.findOne(".bottom-right").x(u.x)}else"middle-left"===this._movingAnchorName?this.findOne(".top-left").x(r.x()):"middle-right"===this._movingAnchorName?this.findOne(".bottom-right").x(r.x()):"bottom-left"===this._movingAnchorName?(l&&(n=Math.sqrt(Math.pow(this.findOne(".top-right").x()-r.x()-0,2)+Math.pow(r.y()-this.findOne(".top-right").y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".bottom-right").x(e+0),this.findOne(".bottom-right").y(i+0)):console.error(new Error("Wrong position argument of selection resizer: "+this._movingAnchorName));if("rotater"!==this._movingAnchorName){if(this.centeredScaling()||t.altKey){var f=this.findOne(".top-left"),g=this.findOne(".bottom-right"),v=f.x()+0,y=f.y()+0,m=this.getWidth()-g.x()+0,_=this.getHeight()-g.y()+0;Math.abs(y),g.move({x:-v,y:-y}),f.move({x:m,y:_})}var S=this.findOne(".top-left").getAbsolutePosition();e=S.x,i=S.y;var b=this.findOne(".bottom-right").x()-this.findOne(".top-left").x(),x=this.findOne(".bottom-right").y()-this.findOne(".top-left").y();this._fitNodesInto({x:e,y:i,width:b,height:x,rotation:A.getAngle(this.rotation())},t)}}else{var w=this._getNodeRect();e=r.x()-w.width/2,i=-r.y()+w.height/2;var C=Math.atan2(-i,e)+Math.PI/2;w.height<0&&(C-=Math.PI);var P=A.getAngle(this.rotation())+C,k=A.getAngle(this.rotationSnapTolerance()),T=Zi(w,function(t,e,i){for(var n=e,r=0;r>z,0!==C?(C=255/C,k[s]=(d*N>>z)*C,k[s+1]=(l*N>>z)*C,k[s+2]=(c*N>>z)*C):k[s]=k[s+1]=k[s+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=h+((o=i+e+1)>z,0>z)*C,k[o+1]=(l*N>>z)*C,k[o+2]=(c*N>>z)*C):k[o]=k[o+1]=k[o+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=i+((o=n+O)>16&255,g:e>>8&255,b:255&e}},getRandomColor:function(){for(var t=(16777215*Math.random()<<0).toString(16);t.length<6;)t="0"+t;return"#"+t},get:function(t,e){return void 0===t?e:t},getRGB:function(t){var e;return t in p?{r:(e=p[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=u.exec(t.replace(/ /g,"")),{r:parseInt(e[1],10),g:parseInt(e[2],10),b:parseInt(e[3],10)}):{r:0,g:0,b:0}},colorToRGBA:function(t){return t=t||"black",T._namedColorToRBA(t)||T._hex3ColorToRGBA(t)||T._hex6ColorToRGBA(t)||T._rgbColorToRGBA(t)||T._rgbaColorToRGBA(t)||T._hslColorToRGBA(t)},_namedColorToRBA:function(t){var e=p[t.toLowerCase()];return e?{r:e[0],g:e[1],b:e[2],a:1}:null},_rgbColorToRGBA:function(t){if(0===t.indexOf("rgb(")){var e=(t=t.match(/rgb\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:1}}},_rgbaColorToRGBA:function(t){if(0===t.indexOf("rgba(")){var e=(t=t.match(/rgba\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:e[3]}}},_hex6ColorToRGBA:function(t){if("#"===t[0]&&7===t.length)return{r:parseInt(t.slice(1,3),16),g:parseInt(t.slice(3,5),16),b:parseInt(t.slice(5,7),16),a:1}},_hex3ColorToRGBA:function(t){if("#"===t[0]&&4===t.length)return{r:parseInt(t[1]+t[1],16),g:parseInt(t[2]+t[2],16),b:parseInt(t[3]+t[3],16),a:1}},_hslColorToRGBA:function(t){if(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)){var e=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t),i=(e[0],e.slice(1)),n=Number(i[0])/360,r=Number(i[1])/100,o=Number(i[2])/100,a=void 0,s=void 0,h=void 0;if(0==r)return h=255*o,{r:Math.round(h),g:Math.round(h),b:Math.round(h),a:1};for(var d=2*o-(a=o<.5?o*(1+r):o+r-o*r),l=[0,0,0],c=0;c<3;c++)(s=n+1/3*-(c-1))<0&&s++,1t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var a=e;e=t,t=a}for(n=0;n=this.parent.children.length)&&T.warn("Unexpected value "+t+" for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to "+(this.parent.children.length-1)+".");var e=this.index;return this.parent.children.splice(e,1),this.parent.children.splice(t,0,this),this.parent._setChildrenIndices(),this},pt.prototype.getAbsoluteOpacity=function(){return this._getCache(Z,this._getAbsoluteOpacity)},pt.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=e.getAbsoluteOpacity()),t},pt.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},pt.prototype.toObject=function(){var t,e,i,n={},r=this.getAttrs();for(t in n.attrs={},r)e=r[t],T.isObject(e)&&!T._isPlainObject(e)&&!T._isArray(e)||(i="function"==typeof this[t]&&this[t],delete r[t],(i?i.call(this):null)!==(r[t]=e)&&(n.attrs[t]=e));return n.className=this.getClassName(),T._prepareToStringify(n)},pt.prototype.toJSON=function(){return JSON.stringify(this.toObject())},pt.prototype.getParent=function(){return this.parent},pt.prototype.findAncestors=function(t,e,i){var n=[];e&&this._isMatch(t)&&n.push(this);for(var r=this.parent;r;){if(r===i)return n;r._isMatch(t)&&n.push(r),r=r.parent}return n},pt.prototype.isAncestorOf=function(t){return!1},pt.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},pt.prototype._isMatch=function(t){if(!t)return!1;if("function"==typeof t)return t(this);var e,i,n=t.replace(/ /g,"").split(","),r=n.length;for(e=0;ethis.duration?this.yoyo?(this._time=this.duration,this.reverse()):this.finish():t<0?this.yoyo?(this._time=0,this.play()):this.reset():(this._time=t,this.update())},Re.prototype.getTime=function(){return this._time},Re.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},Re.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},Re.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},Re.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},Re.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},Re.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},Re.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},Re.prototype.update=function(){this.setPosition(this.getPosition(this._time))},Re.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},Re.prototype.pause=function(){this.state=1,this.fire("onPause")},Re.prototype.getTimer=function(){return(new Date).getTime()},Re);function Re(t,e,i,n,r,o,a){this.prop=t,this.propFunc=e,this.begin=n,this._pos=n,this.duration=o,this._change=0,this.prevPos=0,this.yoyo=a,this._time=0,this._position=0,this._startTime=0,this._finish=0,this.func=i,this._change=r-this.begin,this.pause()}var Oe=(Ie.prototype._addAttr=function(t,e){var i,n,r,o,a,s,h,d,l=this.node,c=l._id;if((r=Ie.tweens[c][t])&&delete Ie.attrs[c][r][t],i=l.getAttr(t),T._isArray(e))if(n=[],a=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=T._prepareArrayForTween(i,e,l.closed())):(s=e,e=T._prepareArrayForTween(e,i,l.closed()))),0===t.indexOf("fill"))for(o=0;othis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===n)return{x:(e=this.dataArray[i-1].points.slice(-2))[0],y:e[1]};if(t<.01)return{x:(e=this.dataArray[i].points.slice(0,2))[0],y:e[1]};var r=this.dataArray[i],o=r.points;switch(r.command){case"L":return ui.getPointOnLine(t,r.start.x,r.start.y,o[0],o[1]);case"C":return ui.getPointOnCubicBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3],o[4],o[5]);case"Q":return ui.getPointOnQuadraticBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3]);case"A":var a=o[0],s=o[1],h=o[2],d=o[3],l=o[4],c=o[5],p=o[6];return l+=c*t/r.pathLength,ui.getPointOnEllipticalArc(a,s,h,d,l,p)}return null},ui.getLineLength=function(t,e,i,n){return Math.sqrt((i-t)*(i-t)+(n-e)*(n-e))},ui.getPointOnLine=function(t,e,i,n,r,o,a){void 0===o&&(o=e),void 0===a&&(a=i);var s=(r-i)/(n-e+1e-8),h=Math.sqrt(t*t/(1+s*s));n>>1,k=_.slice(0,1+P),A=this._getTextWidth(k)+v;A<=d?(S=1+P,w=k+(g?"…":""),C=A):b=P}if(!w)break;if(f){var T,M=_[w.length];0<(T=(" "===M||"-"===M)&&C<=d?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(S=T,w=w.slice(0,S),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=n,!u||s&&le?g=pi.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var a=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=a+1e-8:iv.pathLength?1e-8:e/v.pathLength:ip.x?-1:1,f=this.findOne(".top-left").y()>p.y?-1:1;e=n*this.cos*u,i=n*this.sin*f,this.findOne(".top-left").x(p.x-e),this.findOne(".top-left").y(p.y-i)}}else if("top-center"===this._movingAnchorName)this.findOne(".top-left").y(r.y());else if("top-right"===this._movingAnchorName){l&&(p=c?{x:this.width()/2,y:this.height()/2}:{x:this.findOne(".bottom-left").x(),y:this.findOne(".bottom-left").y()},n=Math.sqrt(Math.pow(r.x()-p.x,2)+Math.pow(p.y-r.y(),2)),u=this.findOne(".top-right").x()p.y?-1:1,e=n*this.cos*u,i=n*this.sin*f,this.findOne(".top-right").x(p.x+e),this.findOne(".top-right").y(p.y-i));var g=r.position();this.findOne(".top-left").y(g.y),this.findOne(".bottom-right").x(g.x)}else"middle-left"===this._movingAnchorName?this.findOne(".top-left").x(r.x()):"middle-right"===this._movingAnchorName?this.findOne(".bottom-right").x(r.x()):"bottom-left"===this._movingAnchorName?(l&&(p=c?{x:this.width()/2,y:this.height()/2}:{x:this.findOne(".top-right").x(),y:this.findOne(".top-right").y()},n=Math.sqrt(Math.pow(p.x-r.x(),2)+Math.pow(r.y()-p.y,2)),u=p.x>z,0!==C?(C=255/C,k[s]=(d*N>>z)*C,k[s+1]=(l*N>>z)*C,k[s+2]=(c*N>>z)*C):k[s]=k[s+1]=k[s+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=h+((o=i+e+1)>z,0>z)*C,k[o+1]=(l*N>>z)*C,k[o+2]=(c*N>>z)*C):k[o]=k[o+1]=k[o+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=i+((o=n+O)) { - // if (shapes.length === 1) { - // const shape = shapes[0]; - - // return { - // x: shape.x, - // y: shape.y, - // width: shape.width, - // height: shape.height, - // rotation: shape.rotation - // }; - // } let x1 = 9999999999; let y1 = 9999999999; let x2 = -999999999; @@ -379,46 +363,15 @@ export class Transformer extends Group { return this; } setNode(node) { + Util.warn( + 'tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.' + ); return this.setNodes([node]); - // if (this._node) { - // this.detach(); - // } - // this._node = node; - // this._resetTransformCache(); - - // const additionalEvents = node._attrsAffectingSize - // .map(prop => prop + 'Change.' + EVENTS_NAME) - // .join(' '); - - // const onChange = () => { - // this._resetTransformCache(); - // if (!this._transforming) { - // this.update(); - // } - // }; - // node.on(additionalEvents, onChange); - // node.on(TRANSFORM_CHANGE_STR, onChange); - // node.on(`xChange.${EVENTS_NAME} yChange.${EVENTS_NAME}`, () => - // this._resetTransformCache() - // ); - // // we may need it if we set node in initial props - // // so elements are not defined yet - // var elementsCreated = !!this.findOne('.top-left'); - // if (elementsCreated) { - // this.update(); - // } - // return this; } getNode() { return this._nodes && this._nodes[0]; } - drawScene(can?, top?, caching?) { - return super.drawScene(can, top, caching); - } - // _attachTo(node) => { - - // } setNodes(nodes: Array = []) { if (this._nodes && this._nodes.length) { this.detach(); @@ -446,6 +399,7 @@ export class Transformer extends Group { this._resetTransformCache(); }); node.on(`xChange.${EVENTS_NAME} yChange.${EVENTS_NAME}`, onChange); + this._proxyDrag(node); }); this._resetTransformCache(); // we may need it if we set node in initial props @@ -457,6 +411,36 @@ export class Transformer extends Group { return this; } + _proxyDrag(node: Node) { + let lastPos; + node.on(`dragstart.${EVENTS_NAME}`, () => { + lastPos = node.getAbsolutePosition(); + }); + node.on(`dragmove.${EVENTS_NAME}`, () => { + if (!lastPos) { + return; + } + const abs = node.getAbsolutePosition(); + const dx = abs.x - lastPos.x; + const dy = abs.y - lastPos.y; + this.nodes().forEach(otherNode => { + if (otherNode === node) { + return; + } + if (otherNode.isDragging()) { + return; + } + const otherAbs = otherNode.getAbsolutePosition(); + otherNode.setAbsolutePosition({ + x: otherAbs.x + dx, + y: otherAbs.y + dy + }); + otherNode.startDrag(); + }); + lastPos = null; + }); + } + getNodes() { return this._nodes; } @@ -537,12 +521,6 @@ export class Transformer extends Group { }; } - if (node.parent && this.parent && node.parent !== this.parent) { - Util.warn( - 'Transformer and attached node have different parents. Konva does not support such case right now. Please move Transformer to the parent of attaching node.' - ); - } - const shapes = this.nodes().map(node => { return this.__getNodeShape(node); }); @@ -552,14 +530,6 @@ export class Transformer extends Group { x: 0, y: 0 }); - - // return { - // x: node.x() + dx * Math.cos(rotation) + dy * Math.sin(-rotation), - // y: node.y() + dy * Math.cos(rotation) + dx * Math.sin(rotation), - // width: rect.width * node.scaleX(), - // height: rect.height * node.scaleY(), - // rotation: node.rotation() - // }; } getX() { return this._getNodeRect().x; @@ -598,24 +568,11 @@ export class Transformer extends Group { anchor.on('mousedown touchstart', function(e) { self._handleMouseDown(e); }); - // anchor.on('dragstart', function(e) { - // e.cancelBubble = true; - // }); - // anchor.on('dragmove', function(e) { - // e.cancelBubble = true; - // }); - // anchor.on('dragend', function(e) { - // e.cancelBubble = true; - // }); // add hover styling anchor.on('mouseenter', () => { var rad = Konva.getAngle(this.rotation()); - - // var scale = this.getNode().getAbsoluteScale(); - // If scale.y < 0 xor scale.x < 0 we need to flip (not rotate). - // var isMirrored = false; - var cursor = getCursor(name, rad, false); + var cursor = getCursor(name, rad); anchor.getStage().content.style.cursor = cursor; this._cursorChange = true; }); @@ -633,6 +590,7 @@ export class Transformer extends Group { name: 'back', width: 0, height: 0, + draggable: true, sceneFunc(ctx) { var tr = this.getParent(); var padding = tr.padding(); @@ -653,21 +611,23 @@ export class Transformer extends Group { ctx.fillStrokeShape(this); }, - listening: false - // hitFunc(ctx) { - // var tr = this.getParent(); - // var padding = tr.padding(); - // ctx.beginPath(); - // ctx.rect( - // -padding, - // -padding, - // this.width() + padding * 2, - // this.height() + padding * 2 - // ); - // ctx.fillStrokeShape(this); - // } + hitFunc: (ctx, shape) => { + if (!this.shouldOverdrawWholeArea()) { + return; + } + var padding = this.padding(); + ctx.beginPath(); + ctx.rect( + -padding, + -padding, + shape.width() + padding * 2, + shape.height() + padding * 2 + ); + ctx.fillStrokeShape(shape); + } }); this.add(back); + this._proxyDrag(back); } _handleMouseDown(e) { this._movingAnchorName = e.target.name().split(' ')[0]; @@ -742,182 +702,97 @@ export class Transformer extends Group { return; } - var padding = 0; - // var centeredScaling = this.centeredScaling() || e.altKey; - // if (centeredScaling && this._movingAnchorName.indexOf('left') >= 0) { - // var topLeft = this.findOne('.top-left'); - // var bottomRight = this.findOne('.bottom-right'); - // var topOffsetX = topLeft.x() + padding; - // var topOffsetY = topLeft.y() + padding; - - // var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; - // var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; - - // bottomRight.move({ - // x: -topOffsetX, - // y: -topOffsetY - // }); - - // topLeft.move({ - // x: bottomOffsetX, - // y: bottomOffsetY - // }); - // } - var keepProportion = this.keepRatio() || e.shiftKey; + var centeredScaling = this.centeredScaling() || e.altKey; if (this._movingAnchorName === 'top-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: -anchorNode.y() - // }); - // } - if (keepProportion) { + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.bottom-right').x(), + y: this.findOne('.bottom-right').y() + }; newHypotenuse = Math.sqrt( - Math.pow( - this.findOne('.bottom-right').x() - anchorNode.x() - padding * 2, - 2 - ) + - Math.pow( - this.findOne('.bottom-right').y() - anchorNode.y() - padding * 2, - 2 - ) + Math.pow(comparePoint.x - anchorNode.x(), 2) + + Math.pow(comparePoint.y - anchorNode.y(), 2) ); - var reverseX = - this.findOne('.top-left').x() > this.findOne('.bottom-right').x() - ? -1 - : 1; + var reverseX = this.findOne('.top-left').x() > comparePoint.x ? -1 : 1; - var reverseY = - this.findOne('.top-left').y() > this.findOne('.bottom-right').y() - ? -1 - : 1; + var reverseY = this.findOne('.top-left').y() > comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.top-left').x( - this.findOne('.bottom-right').x() - x - padding * 2 - ); - this.findOne('.top-left').y( - this.findOne('.bottom-right').y() - y - padding * 2 - ); + this.findOne('.top-left').x(comparePoint.x - x); + this.findOne('.top-left').y(comparePoint.y - y); } } else if (this._movingAnchorName === 'top-center') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: 0, - // y: -anchorNode.y() - // }); - // } this.findOne('.top-left').y(anchorNode.y()); } else if (this._movingAnchorName === 'top-right') { - // if (centeredScaling) { - // // this.findOne('.bottom-left').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: -anchorNode.y() - // // }); - // // this.findOne('.top-left').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: anchorNode.y() - // // }); - // // this.findOne('.bottom-right').move({ - // // x: -(anchorNode.x() - this.width()), - // // y: anchorNode.y() - // // }); - // } - - // var center = getCenter({ - // x - // }) if (keepProportion) { + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.bottom-left').x(), + y: this.findOne('.bottom-left').y() + }; + newHypotenuse = Math.sqrt( - Math.pow( - anchorNode.x() - this.findOne('.bottom-left').x() - padding * 2, - 2 - ) + - Math.pow( - this.findOne('.bottom-left').y() - anchorNode.y() - padding * 2, - 2 - ) + Math.pow(anchorNode.x() - comparePoint.x, 2) + + Math.pow(comparePoint.y - anchorNode.y(), 2) ); - var reverseX = - this.findOne('.top-right').x() < this.findOne('.top-left').x() - ? -1 - : 1; + var reverseX = this.findOne('.top-right').x() < comparePoint.x ? -1 : 1; - var reverseY = - this.findOne('.top-right').y() > this.findOne('.bottom-left').y() - ? -1 - : 1; + var reverseY = this.findOne('.top-right').y() > comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.top-right').x(x + padding); - this.findOne('.top-right').y( - this.findOne('.bottom-left').y() - y - padding * 2 - ); + this.findOne('.top-right').x(comparePoint.x + x); + this.findOne('.top-right').y(comparePoint.y - y); } var pos = anchorNode.position(); this.findOne('.top-left').y(pos.y); this.findOne('.bottom-right').x(pos.x); } else if (this._movingAnchorName === 'middle-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: 0 - // }); - // } this.findOne('.top-left').x(anchorNode.x()); } else if (this._movingAnchorName === 'middle-right') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: 0 - // }); - // } this.findOne('.bottom-right').x(anchorNode.x()); } else if (this._movingAnchorName === 'bottom-left') { - // if (centeredScaling) { - // this.findOne('.bottom-right').move({ - // x: -anchorNode.x(), - // y: -(anchorNode.y() - this.height()) - // }); - // } if (keepProportion) { + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.top-right').x(), + y: this.findOne('.top-right').y() + }; + newHypotenuse = Math.sqrt( - Math.pow( - this.findOne('.top-right').x() - anchorNode.x() - padding * 2, - 2 - ) + - Math.pow( - anchorNode.y() - this.findOne('.top-right').y() - padding * 2, - 2 - ) + Math.pow(comparePoint.x - anchorNode.x(), 2) + + Math.pow(anchorNode.y() - comparePoint.y, 2) ); - var reverseX = - this.findOne('.top-right').x() < this.findOne('.bottom-left').x() - ? -1 - : 1; + var reverseX = comparePoint.x < anchorNode.x() ? -1 : 1; - var reverseY = - this.findOne('.bottom-left').y() < this.findOne('.top-right').y() - ? -1 - : 1; + var reverseY = anchorNode.y() < comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.bottom-left').x( - this.findOne('.top-right').x() - x - padding * 2 - ); - this.findOne('.bottom-left').y(y + padding); + anchorNode.x(comparePoint.x - x); + anchorNode.y(comparePoint.y + y); } pos = anchorNode.position(); @@ -925,42 +800,35 @@ export class Transformer extends Group { this.findOne('.top-left').x(pos.x); this.findOne('.bottom-right').y(pos.y); } else if (this._movingAnchorName === 'bottom-center') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: 0, - // y: -(anchorNode.y() - this.height()) - // }); - // } this.findOne('.bottom-right').y(anchorNode.y()); } else if (this._movingAnchorName === 'bottom-right') { - // if (centeredScaling) { - // this.findOne('.top-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: -(anchorNode.y() - this.height()) - // }); - // } - if (keepProportion) { + var comparePoint = centeredScaling + ? { + x: this.width() / 2, + y: this.height() / 2 + } + : { + x: this.findOne('.top-left').x(), + y: this.findOne('.top-left').y() + }; + newHypotenuse = Math.sqrt( - Math.pow(this.findOne('.bottom-right').x() - padding, 2) + - Math.pow(this.findOne('.bottom-right').y() - padding, 2) + Math.pow(anchorNode.x() - comparePoint.x, 2) + + Math.pow(anchorNode.y() - comparePoint.y, 2) ); var reverseX = - this.findOne('.top-left').x() > this.findOne('.bottom-right').x() - ? -1 - : 1; + this.findOne('.bottom-right').x() < comparePoint.x ? -1 : 1; var reverseY = - this.findOne('.top-left').y() > this.findOne('.bottom-right').y() - ? -1 - : 1; + this.findOne('.bottom-right').y() < comparePoint.y ? -1 : 1; x = newHypotenuse * this.cos * reverseX; y = newHypotenuse * this.sin * reverseY; - this.findOne('.bottom-right').x(x + padding); - this.findOne('.bottom-right').y(y + padding); + this.findOne('.bottom-right').x(comparePoint.x + x); + this.findOne('.bottom-right').y(comparePoint.y + y); } } else { console.error( @@ -971,23 +839,16 @@ export class Transformer extends Group { ); } - if (this._movingAnchorName === 'rotater') { - return; - } - var centeredScaling = this.centeredScaling() || e.altKey; if (centeredScaling) { var topLeft = this.findOne('.top-left'); var bottomRight = this.findOne('.bottom-right'); - var topOffsetX = topLeft.x() + padding; - var topOffsetY = topLeft.y() + padding; + var topOffsetX = topLeft.x(); + var topOffsetY = topLeft.y(); - var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; - var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; + var bottomOffsetX = this.getWidth() - bottomRight.x(); + var bottomOffsetY = this.getHeight() - bottomRight.y(); - if (Math.abs(topOffsetY) > 10) { - debugger; - } bottomRight.move({ x: -topOffsetX, y: -topOffsetY @@ -1061,14 +922,15 @@ export class Transformer extends Group { this.update(); return; } - // if (newAttrs.width < 0) { - // debugger; - // } - const an = this._movingAnchorName; + const allowNegativeScale = true; var t = new Transform(); t.rotate(Konva.getAngle(this.rotation())); - if (an && newAttrs.width < 0 && an.indexOf('left') >= 0) { + if ( + this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('left') >= 0 + ) { const offset = t.point({ x: -this.padding() * 2, y: 0 @@ -1076,19 +938,23 @@ export class Transformer extends Group { newAttrs.x += offset.x; newAttrs.y += offset.y; newAttrs.width += this.padding() * 2; - this._movingAnchorName = an.replace('left', 'right'); + this._movingAnchorName = this._movingAnchorName.replace('left', 'right'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; if (!allowNegativeScale) { this.update(); return; } - } else if (an && newAttrs.width < 0 && an.indexOf('right') >= 0) { + } else if ( + this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('right') >= 0 + ) { const offset = t.point({ x: this.padding() * 2, y: 0 }); - this._movingAnchorName = an.replace('right', 'left'); + this._movingAnchorName = this._movingAnchorName.replace('right', 'left'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.width += this.padding() * 2; @@ -1097,14 +963,18 @@ export class Transformer extends Group { return; } } - if (an && newAttrs.height < 0 && an.indexOf('top') >= 0) { + if ( + this._movingAnchorName && + newAttrs.height < 0 && + this._movingAnchorName.indexOf('top') >= 0 + ) { const offset = t.point({ x: 0, y: -this.padding() * 2 }); newAttrs.x += offset.x; newAttrs.y += offset.y; - this._movingAnchorName = an.replace('top', 'bottom'); + this._movingAnchorName = this._movingAnchorName.replace('top', 'bottom'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.height += this.padding() * 2; @@ -1112,12 +982,16 @@ export class Transformer extends Group { this.update(); return; } - } else if (an && newAttrs.height < 0 && an.indexOf('bottom') >= 0) { + } else if ( + this._movingAnchorName && + newAttrs.height < 0 && + this._movingAnchorName.indexOf('bottom') >= 0 + ) { const offset = t.point({ x: 0, y: this.padding() * 2 }); - this._movingAnchorName = an.replace('bottom', 'top'); + this._movingAnchorName = this._movingAnchorName.replace('bottom', 'top'); this._anchorDragOffset.x -= offset.x; this._anchorDragOffset.y -= offset.y; newAttrs.height += this.padding() * 2; @@ -1146,8 +1020,6 @@ export class Transformer extends Group { skipStroke: this.ignoreStroke() }); - var padding = 0; - const parentTransform = node .getParent() .getAbsoluteTransform() @@ -1163,20 +1035,13 @@ export class Transformer extends Group { pure.width *= absScale.x; pure.height *= absScale.y; - // pure.x -= absPos.x; - // pure.y -= absPos.y; - // newAttrs.x = (newAttrs.x - absPos.x) / absScale.x; - // newAttrs.y = (newAttrs.y - absPos.y) / absScale.y; - - var scaleX = pure.width ? (newAttrs.width - padding * 2) / pure.width : 1; - var scaleY = pure.height - ? (newAttrs.height - padding * 2) / pure.height - : 1; + var scaleX = pure.width ? newAttrs.width / pure.width : 1; + var scaleY = pure.height ? newAttrs.height / pure.height : 1; var rotation = Konva.getAngle(node.rotation()); - var dx = pure.x * scaleX - padding - node.offsetX() * scaleX; - var dy = pure.y * scaleY - padding - node.offsetY() * scaleY; + var dx = pure.x * scaleX - node.offsetX() * scaleX; + var dy = pure.y * scaleY - node.offsetY() * scaleY; node.setAttrs({ scaleX: scaleX, @@ -1287,7 +1152,9 @@ export class Transformer extends Group { visible: this.borderEnabled(), stroke: this.borderStroke(), strokeWidth: this.borderStrokeWidth(), - dash: this.borderDash() + dash: this.borderDash(), + x: 0, + y: 0 }); } /** @@ -1350,6 +1217,7 @@ export class Transformer extends Group { centeredScaling: GetSet; ignoreStroke: GetSet; boundBoxFunc: GetSet<(oldBox: IRect, newBox: IRect) => IRect, this>; + shouldOverdrawWholeArea: GetSet; } function validateAnchors(val) { @@ -1739,6 +1607,8 @@ Factory.addGetterSetter(Transformer, 'nodes'); */ Factory.addGetterSetter(Transformer, 'boundBoxFunc'); +Factory.addGetterSetter(Transformer, 'shouldOverdrawWholeArea', false); + Factory.backCompat(Transformer, { lineEnabled: 'borderEnabled', rotateHandlerOffset: 'rotateAnchorOffset', diff --git a/test/unit/shapes/Transformer-test.js b/test/unit/shapes/Transformer-test.js index c7b3a0c6..cbbb349b 100644 --- a/test/unit/shapes/Transformer-test.js +++ b/test/unit/shapes/Transformer-test.js @@ -21,6 +21,12 @@ suite('Transformer', function() { this.getStage().simulateMouseUp(pos || { x: 1, y: 1 }); }; + assert.almostEqual = function(val1, val2) { + if (!isClose(val1, val2)) { + throw new Error('Expected ' + val1 + ' to be almost equal to ' + val2); + } + }; + // ====================================================== test('init transformer on simple rectangle', function() { var stage = addStage(); @@ -38,7 +44,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -96,56 +102,6 @@ suite('Transformer', function() { assert.equal(tr.rotation(), 0); }); - test('try it on a parent of parent', function() { - var callCount = 0; - var oldWarn = Konva.Util.warn; - Konva.Util.warn = function() { - callCount += 1; - }; - - var stage = addStage(); - var layer = new Konva.Layer(); - stage.add(layer); - - var group = new Konva.Group({ - x: 50, - y: 50 - }); - layer.add(group); - - var rect = new Konva.Rect({ - x: 50, - y: 50, - draggable: true, - width: 100, - height: 100, - fill: 'yellow' - }); - group.add(rect); - - var tr = new Konva.Transformer({ - node: rect - }); - layer.add(tr); - - rect.width(120); - layer.draw(); - - assert.equal(callCount, 1); - Konva.Util.warn = oldWarn; - - // assert.equal(tr.x(), rect.x() + group.x()); - // assert.equal(tr.y(), rect.y() + group.y()); - // assert.equal(tr.width(), rect.width()); - // assert.equal(tr.height(), rect.height()); - - // // manual check of correct position of node - // var handler = tr.findOne('.bottom-right'); - // var pos = handler.getAbsolutePosition(); - // assert.equal(pos.x, rect.x() + rect.width()); - // assert.equal(pos.y, rect.y() + rect.height()); - }); - test('try set/get node', function() { var stage = addStage(); var layer = new Konva.Layer(); @@ -170,15 +126,15 @@ suite('Transformer', function() { layer.add(circle); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); - assert.equal(tr.node(), rect); + assert.equal(tr.nodes()[0], rect); - tr.attachTo(circle); - assert.equal(tr.node(), circle); + tr.nodes([circle]); + assert.equal(tr.nodes()[0], circle); layer.draw(); }); @@ -199,7 +155,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -235,7 +191,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -282,7 +238,7 @@ suite('Transformer', function() { ignoreStroke: true }); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -314,7 +270,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); @@ -352,7 +308,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); @@ -386,7 +342,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -426,7 +382,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); @@ -457,7 +413,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); tr._fitNodesInto({ x: 0, @@ -497,7 +453,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(circle); + tr.nodes([circle]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); @@ -525,7 +481,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(circle); + tr.nodes([circle]); tr._fitNodesInto({ x: 40, @@ -563,7 +519,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(circle); + tr.nodes([circle]); tr._fitNodesInto({ x: 80, @@ -603,7 +559,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(circle); + tr.nodes([circle]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); @@ -633,7 +589,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(circle); + tr.nodes([circle]); layer.draw(); @@ -679,7 +635,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(group); + tr.nodes([group]); layer.draw(); @@ -723,7 +679,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(group); + tr.nodes([group]); tr._fitNodesInto({ x: 100, @@ -781,7 +737,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(group); + tr.nodes([group]); layer.draw(); @@ -825,7 +781,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(group); + tr.nodes([group]); tr._fitNodesInto({ x: 0, @@ -866,7 +822,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -909,7 +865,7 @@ suite('Transformer', function() { assert.equal(tr.getWidth(), 0); - tr.attachTo(rect); + tr.nodes([rect]); assert.equal(tr.getWidth(), 100); }); @@ -934,7 +890,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -975,7 +931,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] padding: 20 }); layer.add(tr); @@ -1025,7 +981,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -1078,8 +1034,9 @@ suite('Transformer', function() { }); layer.add(image); var tr = new Konva.Transformer({ - node: image, - keepRatio: false + nodes: [image], + keepRatio: true, + centeredScaling: true }); layer.add(tr); layer.draw(); @@ -1104,7 +1061,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] rotationSnaps: [0, 90, 180, 270], rotationSnapTolerance: 45 }); @@ -1197,7 +1154,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] padding: 10 }); layer.add(tr); @@ -1226,12 +1183,12 @@ suite('Transformer', function() { y: 60 }); - assert.equal(rect.x(), 115); - assert.equal(rect.y(), 10); - assert.equal(rect.width(), 100); - assert.equal(rect.scaleX(), -0.05); - assert.equal(rect.height(), 100); - assert.equal(rect.scaleY(), 1); + assert.almostEqual(rect.x(), 115); + assert.almostEqual(rect.y(), 10); + assert.almostEqual(rect.width(), 100); + assert.almostEqual(rect.scaleX(), 0.05); + assert.almostEqual(rect.height(), 100); + assert.almostEqual(rect.scaleY(), -1); // switch again tr.simulateMouseMove({ @@ -1239,12 +1196,12 @@ suite('Transformer', function() { y: 60 }); - assert.equal(rect.x(), 100); - assert.equal(rect.y(), 10); - assert.equal(rect.width(), 100); - assert.equal(rect.scaleY(), -1); - assert.equal(rect.scaleX() + 0.1 < 0.0001, true); - assert.equal(rect.height(), 100); + assert.almostEqual(rect.x(), 100); + assert.almostEqual(rect.y(), 10); + assert.almostEqual(rect.width(), 100); + assert.almostEqual(rect.scaleY(), -1); + assert.almostEqual(rect.scaleX() + 0.1 < 0.0001, true); + assert.almostEqual(rect.height(), 100); tr.simulateMouseUp(); }); @@ -1265,7 +1222,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] padding: 10 }); layer.add(tr); @@ -1334,7 +1291,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1427,7 +1384,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1484,7 +1441,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] padding: 10 }); layer.add(tr); @@ -1513,12 +1470,12 @@ suite('Transformer', function() { y: 125 }); - assert.equal(rect.x(), 110); - assert.equal(rect.y(), 115); - assert.equal(rect.width(), 100); - assert.equal(rect.scaleX(), -0.05); - assert.equal(rect.height(), 100); - assert.equal(rect.scaleY(), 1); + assert.almostEqual(rect.x(), 110); + assert.almostEqual(rect.y(), 115); + assert.almostEqual(rect.width(), 100); + assert.almostEqual(rect.scaleX(), 0.05); + assert.almostEqual(rect.height(), 100); + assert.almostEqual(rect.scaleY(), -1); // switch again tr.simulateMouseMove({ @@ -1526,13 +1483,13 @@ suite('Transformer', function() { y: 90 }); - assert.equal(rect.x(), 110); - assert.equal(rect.y() - 120 < 0.001, true); - assert.equal(rect.width(), 100); - assert.equal(rect.scaleX() + 0.1 < 0.0001, true); - assert.equal(rect.scaleY(), -1); + assert.almostEqual(rect.x(), 110); + assert.almostEqual(rect.y() - 120 < 0.001, true); + assert.almostEqual(rect.width(), 100); + assert.almostEqual(rect.scaleX() + 0.1 < 0.0001, true); + assert.almostEqual(rect.scaleY(), -1); - assert.equal(rect.height(), 100); + assert.almostEqual(rect.height(), 100); tr.simulateMouseUp(); }); @@ -1554,7 +1511,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] padding: 10 }); layer.add(tr); @@ -1624,7 +1581,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1677,7 +1634,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1717,7 +1674,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1764,7 +1721,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -1813,7 +1770,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -1854,7 +1811,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -1882,7 +1839,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -1945,7 +1902,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -1973,7 +1930,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2005,7 +1962,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2048,7 +2005,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2092,7 +2049,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2146,7 +2103,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2221,7 +2178,7 @@ suite('Transformer', function() { var tr = new Konva.Transformer(); layer.add(tr); - tr.attachTo(group); + tr.nodes([group]); layer.draw(); @@ -2276,7 +2233,7 @@ suite('Transformer', function() { // make draw to set all caches layer.draw(); // then attach - tr.attachTo(rect); + tr.nodes([rect]); layer.draw(); @@ -2306,7 +2263,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2453,7 +2410,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -2517,7 +2474,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] centeredScaling: true, keepRatio: false }); @@ -2582,7 +2539,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] centeredScaling: true }); layer.add(tr); @@ -2635,7 +2592,7 @@ suite('Transformer', function() { }); // TODO: fix - test.skip('centered scaling on flip + keep ratio', function() { + test('centered scaling on flip + keep ratio', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2647,59 +2604,74 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] centeredScaling: true, keepRatio: true }); layer.add(tr); - rect.setAttrs({ - x: 0, - y: 0, - width: 100, - height: 100, - scaleX: 1, - scaleY: 1 - }); - tr.update(); + // try to move mouse from edge corners into different directions + var tl = { x: 0, y: 0 }; + var trr = { x: 200, y: 0 }; + var bl = { x: 0, y: 100 }; + var br = { x: 200, y: 100 }; - layer.draw(); + var tests = [ + [tl, trr], + [tl, bl], + [tl, br], + [trr, tl], + [trr, bl], + [trr, br], - tr.simulateMouseDown({ - x: 0, - y: 0 - }); - tr.simulateMouseMove({ - x: 100, - y: 0 - }); + [bl, tl], + [bl, trr], + [bl, br], - var box = rect.getClientRect(); - console.log(box); - // assert.equal(rect.x(), 110); - // assert.equal(isClose(rect.y(), 0), true); - // assert.equal(rect.width(), 200); - // assert.equal(Math.round(rect.scaleY()), 1); - // assert.equal(Math.round(rect.scaleX()), -1); - // assert.equal(rect.height(), 100); + [br, tl], + [br, trr], + [br, bl] + ]; + tests.forEach(test => { + var start = test[0]; + var end = test[1]; + console.log(start, end); + rect.setAttrs({ + x: 0, + y: 0, + width: 200, + height: 100, + scaleX: 1, + scaleY: 1, + rotation: 0 + }); + layer.draw(); - tr.simulateMouseMove({ - x: 100, - y: 0 + // move from start to end + tr.simulateMouseDown(start); + tr.simulateMouseMove(end); + var box = rect.getClientRect(); + assert.almostEqual(box.x, 0); + assert.almostEqual(box.y, 0); + assert.almostEqual(box.width, 200); + assert.almostEqual(box.height, 100); + + // make extra move on end + tr.simulateMouseMove(end); + var box = rect.getClientRect(); + assert.almostEqual(box.x, 0); + assert.almostEqual(box.y, 0); + assert.almostEqual(box.width, 200); + assert.almostEqual(box.height, 100); + + // move back + tr.simulateMouseMove(start); + tr.simulateMouseUp(); + assert.almostEqual(box.x, 0); + assert.almostEqual(box.y, 0); + assert.almostEqual(box.width, 200); + assert.almostEqual(box.height, 100); }); - var box = rect.getClientRect(); - console.log(box); - tr.simulateMouseUp({ - x: 0, - y: 0 - }); - layer.draw(); - // assert.equal(isClose(rect.x(), 200), true); - // assert.equal(isClose(rect.y(), 0), true); - // assert.equal(rect.width(), 200); - // assert.equal(Math.round(rect.scaleY()), -1); - // assert.equal(Math.round(rect.scaleX()), 1); - // assert.equal(rect.height(), 100); }); test('transform scaled (in one direction) node', function() { @@ -2721,7 +2693,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); @@ -2774,7 +2746,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2821,7 +2793,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2864,7 +2836,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect + nodes: [rect] }); layer.add(tr); layer.draw(); @@ -2898,7 +2870,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -2932,7 +2904,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + node: [shape] }); layer.add(tr); @@ -2967,7 +2939,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -2997,7 +2969,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3033,7 +3005,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3067,7 +3039,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3096,7 +3068,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3125,7 +3097,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3162,7 +3134,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3198,7 +3170,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3225,7 +3197,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3284,7 +3256,7 @@ suite('Transformer', function() { layer.add(shape); var tr = new Konva.Transformer({ - node: shape + nodes: [shape] }); layer.add(tr); @@ -3324,7 +3296,7 @@ suite('Transformer', function() { layer.add(rect1); var tr1 = new Konva.Transformer({ - node: rect1 + nodes: [rect1] }); layer.add(tr1); @@ -3338,7 +3310,7 @@ suite('Transformer', function() { tr1.destroy(); var tr2 = new Konva.Transformer({ - node: rect2 + nodes: [rect2] }); layer.add(tr2); @@ -3367,7 +3339,7 @@ suite('Transformer', function() { layer.add(rect); var tr = new Konva.Transformer({ - node: rect, + nodes: [rect,] keepRatio: false }); layer.add(tr); @@ -3474,6 +3446,199 @@ suite('Transformer', function() { assert.equal(tr.rotation(), 180); }); + test('drag several nodes', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + stage.add(layer); + + var rect1 = new Konva.Rect({ + x: 50, + y: 50, + draggable: true, + width: 50, + height: 50, + fill: 'yellow' + }); + layer.add(rect1); + + var rect2 = new Konva.Rect({ + x: 100, + y: 100, + draggable: true, + width: 50, + height: 50, + fill: 'red' + }); + + layer.add(rect2); + + var dragstart = 0; + var dragmove = 0; + var dragend = 0; + + rect2.on('dragstart', () => { + dragstart += 1; + }); + rect2.on('dragmove', () => { + dragmove += 1; + }); + rect2.on('dragend', () => { + dragend += 1; + }); + + var tr = new Konva.Transformer({ + nodes: [rect1, rect2] + }); + layer.add(tr); + layer.draw(); + + stage.simulateMouseDown({ + x: 75, + y: 75 + }); + stage.simulateMouseMove({ + x: 80, + y: 80 + }); + + stage.simulateMouseUp({ + x: 80, + y: 80 + }); + + // proxy drag to other nodes + assert.equal(rect2.x(), 105); + assert.equal(rect2.y(), 105); + assert.equal(dragstart, 1); + assert.equal(dragmove, 1); + assert.equal(dragend, 1); + }); + + test('transformer should not hide shapes', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + stage.add(layer); + + var rect1 = new Konva.Rect({ + x: 50, + y: 50, + draggable: true, + width: 50, + height: 50, + fill: 'yellow' + }); + layer.add(rect1); + + var click = 0; + + rect1.on('click', () => { + click += 1; + }); + + var tr = new Konva.Transformer({ + nodes: [rect1] + }); + layer.add(tr); + layer.draw(); + + stage.simulateMouseDown({ + x: 75, + y: 75 + }); + stage.simulateMouseMove({ + x: 75, + y: 75 + }); + + stage.simulateMouseUp({ + x: 75, + y: 75 + }); + + // proxy drag to other nodes + assert.equal(click, 1); + }); + + test('drag several nodes by transformer back', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + stage.add(layer); + + var rect1 = new Konva.Rect({ + x: 50, + y: 50, + draggable: true, + width: 50, + height: 50, + fill: 'yellow' + }); + layer.add(rect1); + + var rect2 = new Konva.Rect({ + x: 100, + y: 100, + draggable: true, + width: 50, + height: 50, + fill: 'red' + }); + + layer.add(rect2); + + var dragstart = 0; + var dragmove = 0; + var dragend = 0; + + rect1.on('dragstart', () => { + dragstart += 1; + }); + rect1.on('dragmove', () => { + dragmove += 1; + }); + rect1.on('dragend', () => { + dragend += 1; + }); + rect2.on('dragstart', () => { + dragstart += 1; + }); + rect2.on('dragmove', () => { + dragmove += 1; + }); + rect2.on('dragend', () => { + dragend += 1; + }); + + var tr = new Konva.Transformer({ + nodes: [rect1, rect2], + shouldOverdrawWholeArea: true + }); + layer.add(tr); + layer.draw(); + + stage.simulateMouseDown({ + x: 110, + y: 90 + }); + stage.simulateMouseMove({ + x: 120, + y: 90 + }); + + stage.simulateMouseUp({ + x: 120, + y: 90 + }); + + // proxy drag to other nodes + assert.equal(rect1.x(), 60); + assert.equal(rect1.y(), 50); + assert.equal(rect2.x(), 110); + assert.equal(rect2.y(), 100); + assert.equal(dragstart, 2); + assert.equal(dragmove, 2); + assert.equal(dragend, 2); + }); + test('reattach to several nodes', function() { var stage = addStage(); var layer = new Konva.Layer();