From 98afa3fac667ee4a4d1ccaf79dbc0a4439562737 Mon Sep 17 00:00:00 2001 From: Anton Lavrenov Date: Sat, 23 Feb 2019 20:54:20 -0500 Subject: [PATCH] refactoring --- CHANGELOG.md | 19 +- README.md | 4 +- bower.json | 2 +- konva-node/package.json | 2 +- konva.js | 853 ++++++++++++++++++++-------------------- konva.min.js | 4 +- package.json | 2 +- src/Container.ts | 4 +- src/Context.ts | 5 +- src/DragAndDrop.ts | 3 + src/Global.ts | 33 +- src/Layer.ts | 2 +- src/Node.ts | 33 +- src/Shape.ts | 5 +- src/internals.ts | 9 +- src/shapes/Text.ts | 22 +- 16 files changed, 504 insertions(+), 498 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d525c104..fa6934f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,25 +7,24 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Breaking -It is not possible to make custom build of `Konva` from npm installation, like `import Konva from 'konva/src/Core';` -The issue will be resolved later. +Customs builds are removed from npm package. You can not use `import Konva from 'konva/src/Core';`. +This feature will be added back later. ### Possibly breaking That changes are private and internal specific. They should not break most of `Konva` apps. -* `Konva.Util.addMethods` -* `Konva.Util._removeLastLetter` -* `Konva.Util._getImage` -* `Konv.Util._getRGBAString` -* `Konv.Util._merge` +* `Konva.Util.addMethods` is removed +* `Konva.Util._removeLastLetter` is removed +* `Konva.Util._getImage` is removed +* `Konv.Util._getRGBAString` is removed +* `Konv.Util._merge` is removed * Removed polyfill for `requestAnimationFrame`. * `id` and `name` properties defaults are empty strings, not `undefined` * internal `_cache` property was updated to use es2015 `Map` instead of `{}`. - ### Added * Show a warning when a stage has too many layers * Show a warning on duplicate ids @@ -627,8 +626,8 @@ That changes are private and internal specific. They should not break most of `K ### Added * new methods for working with node's name: `addName`, `removeName`, `hasName`. -* new `perfectDrawEnabled` property for shape. See [http://konvajs.github.io/docs/performance/Disable_Perfect_Draw.html](http://konvajs.github.io/docs/performance/Disable_Perfect_Draw.html) -* new `shadowForStrokeEnabled` property for shape. See [http://konvajs.github.io/docs/performance/All_Performance_Tips.html](http://konvajs.github.io/docs/performance/All_Performance_Tips.html) +* new `perfectDrawEnabled` property for shape. See [http://konvajs.org/docs/performance/Disable_Perfect_Draw.html](http://konvajs.org/docs/performance/Disable_Perfect_Draw.html) +* new `shadowForStrokeEnabled` property for shape. See [http://konvajs.org/docs/performance/All_Performance_Tips.html](http://konvajs.org/docs/performance/All_Performance_Tips.html) * new `getClientRect` method. * new `to` method for every node for shorter tweening diff --git a/README.md b/README.md index 9e0ac4b9..dc70b4e6 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ You can draw things onto the stage, add event listeners to them, move them, scal This repository began as a GitHub fork of [ericdrowell/KineticJS](https://github.com/ericdrowell/KineticJS). -* **Visit:** The [Home Page](http://konvajs.github.io/) and follow on [Twitter](https://twitter.com/lavrton) -* **Discover:** [Tutorials](http://konvajs.github.io/docs), [API Documentation](http://konvajs.github.io/api) +* **Visit:** The [Home Page](http://konvajs.org/) and follow on [Twitter](https://twitter.com/lavrton) +* **Discover:** [Tutorials](http://konvajs.org/docs), [API Documentation](http://konvajs.org/api) * **Help:** [StackOverflow](http://stackoverflow.com/questions/tagged/konvajs), [Chat](https://gitter.im/konvajs/konva) # Quick Look diff --git a/bower.json b/bower.json index 0a422f05..cc97733e 100644 --- a/bower.json +++ b/bower.json @@ -3,7 +3,7 @@ "authors": [ "Anton Lavrenov", "Eric Rowell" ], - "homepage": "http://konvajs.github.io", + "homepage": "http://konvajs.org", "description": "Konva is an HTML5 Canvas JavaScript framework that enables high performance animations, transitions, node nesting, layering, filtering, caching, event handling for desktop and mobile applications, and much more.", "keywords": [ "canvas", diff --git a/konva-node/package.json b/konva-node/package.json index 71fe605d..84b91ec1 100644 --- a/konva-node/package.json +++ b/konva-node/package.json @@ -18,7 +18,7 @@ "bugs": { "url": "https://github.com/konvajs/konva/issues" }, - "homepage": "http://konvajs.github.io/", + "homepage": "http://konvajs.org/", "repository": { "type": "git", "url": "git://github.com/konvajs/konva.git" diff --git a/konva.js b/konva.js index 48c4a6a4..f1859160 100644 --- a/konva.js +++ b/konva.js @@ -6,7 +6,7 @@ /* * Konva JavaScript Framework v3.0.0-3 - * http://konvajs.github.io/ + * http://konvajs.org/ * Licensed under the MIT * Date: Sat Feb 23 2019 * @@ -20,8 +20,6 @@ * @namespace Konva */ var version = '3.0.0-3'; - var names = {}; - var shapes = {}; var isBrowser = typeof window !== 'undefined' && // browser case ({}.toString.call(window) === '[object Window]' || @@ -60,32 +58,6 @@ } return false; }; - var _addName = function (node, name) { - if (name) { - if (!names[name]) { - names[name] = []; - } - names[name].push(node); - } - }; - var _removeName = function (name, _id) { - if (!name) { - return; - } - var nodes = names[name]; - if (!nodes) { - return; - } - for (var n = 0; n < nodes.length; n++) { - var no = nodes[n]; - if (no._id === _id) { - nodes.splice(n, 1); - } - } - if (nodes.length === 0) { - delete names[name]; - } - }; var getAngle = function (angle) { return getGlobalKonva().angleDeg ? angle * PI_OVER_180 : angle; }; @@ -1379,6 +1351,8 @@ 'globalAlpha', 'globalCompositeOperation' ]; + // TODO: document all context methods + var traceArrMax = 100; /** * Konva wrapper around native 2d canvas context. It has almost the same API of 2d context with some additional functions. * With core Konva shapes you don't need to use this object. But you have to use it if you want to create @@ -1490,7 +1464,7 @@ var traceArr = this.traceArr, len; traceArr.push(str); len = traceArr.length; - if (len >= getGlobalKonva().traceArrMax) { + if (len >= traceArrMax) { traceArr.shift(); } }; @@ -2284,6 +2258,8 @@ return Animation; }()); + // TODO: make better module, + // make sure other modules import it without global var DD = { startPointerPos: { x: 0, @@ -2385,6 +2361,7 @@ } var ids = {}; + var names = {}; var ID_WARNING = "Duplicate id \"{id}\".\nPlease do not use same id several times, it will break find() method look up.\nIf you have duplicates it is better to use \"name\" property instead.\n"; var _addId = function (node, id) { if (!id) { @@ -2406,6 +2383,32 @@ } delete ids[id]; }; + var _addName = function (node, name) { + if (name) { + if (!names[name]) { + names[name] = []; + } + names[name].push(node); + } + }; + var _removeName = function (name, _id) { + if (!name) { + return; + } + var nodes = names[name]; + if (!nodes) { + return; + } + for (var n = 0; n < nodes.length; n++) { + var no = nodes[n]; + if (no._id === _id) { + nodes.splice(n, 1); + } + } + if (nodes.length === 0) { + delete names[name]; + } + }; // CONSTANTS var ABSOLUTE_OPACITY = 'absoluteOpacity', ABSOLUTE_TRANSFORM = 'absoluteTransform', ABSOLUTE_SCALE = 'absoluteScale', CANVAS = 'canvas', CHANGE = 'Change', CHILDREN = 'children', KONVA = 'konva', LISTENING = 'listening', MOUSEENTER = 'mouseenter', MOUSELEAVE = 'mouseleave', NAME = 'name', SET$1 = 'set', SHAPE = 'Shape', SPACE = ' ', STAGE = 'stage', TRANSFORM = 'transform', UPPER_STAGE = 'Stage', VISIBLE = 'visible', CLONE_BLACK_LIST = ['id'], TRANSFORM_CHANGE_STR = [ 'xChange.konva', @@ -2539,7 +2542,7 @@ * cache node to improve drawing performance, apply filters, or create more accurate * hit regions. For all basic shapes size of cache canvas will be automatically detected. * If you need to cache your custom `Konva.Shape` instance you have to pass shape's bounding box - * properties. Look at [https://konvajs.github.io/docs/performance/Shape_Caching.html](https://konvajs.github.io/docs/performance/Shape_Caching.html) for more information. + * properties. Look at [https://konvajs.org/docs/performance/Shape_Caching.html](https://konvajs.org/docs/performance/Shape_Caching.html) for more information. * @method * @name Konva.Node#cache * @param {Object} [config] @@ -2980,9 +2983,9 @@ // remove from ids and names hashes _removeId(this.id(), this); // remove all names - var names$$1 = (this.name() || '').split(/\s/g); - for (var i = 0; i < names$$1.length; i++) { - var subname = names$$1[i]; + var names = (this.name() || '').split(/\s/g); + for (var i = 0; i < names.length; i++) { + var subname = names[i]; _removeName(subname, this._id); } this.remove(); @@ -4061,8 +4064,8 @@ * node.hasName('selected'); // return false */ Node.prototype.hasName = function (name) { - var names$$1 = (this.name() || '').split(/\s/g); - return names$$1.indexOf(name) !== -1; + var names = (this.name() || '').split(/\s/g); + return names.indexOf(name) !== -1; }; /** * remove name from node @@ -4077,11 +4080,11 @@ * node.name(); // return 'red' */ Node.prototype.removeName = function (name) { - var names$$1 = (this.name() || '').split(/\s/g); - var index = names$$1.indexOf(name); + var names = (this.name() || '').split(/\s/g); + var index = names.indexOf(name); if (index !== -1) { - names$$1.splice(index, 1); - this.setName(names$$1.join(' ')); + names.splice(index, 1); + this.setName(names.join(' ')); } return this; }; @@ -5375,10 +5378,10 @@ } }); // if child is group we need to make sure it has visible shapes inside - var shapes$$1 = this.find('Shape'); + var shapes = this.find('Shape'); var hasVisible = false; - for (var i = 0; i < shapes$$1.length; i++) { - var shape = shapes$$1[i]; + for (var i = 0; i < shapes.length; i++) { + var shape = shapes[i]; if (shape._isVisible(this)) { hasVisible = true; break; @@ -6492,372 +6495,6 @@ Factory.addGetterSetter(BaseLayer, 'clearBeforeDraw', true); Collection.mapMethods(BaseLayer); - // constants - var HASH$1 = '#', BEFORE_DRAW = 'beforeDraw', DRAW = 'draw', - /* - * 2 - 3 - 4 - * | | - * 1 - 0 5 - * | - * 8 - 7 - 6 - */ - INTERSECTION_OFFSETS = [ - { x: 0, y: 0 }, - { x: -1, y: -1 }, - { x: 1, y: -1 }, - { x: 1, y: 1 }, - { x: -1, y: 1 } // 8 - ], INTERSECTION_OFFSETS_LEN = INTERSECTION_OFFSETS.length; - /** - * Layer constructor. Layers are tied to their own canvas element and are used - * to contain groups or shapes. - * @constructor - * @memberof Konva - * @augments Konva.BaseLayer - * @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 - - * @example - * var layer = new Konva.Layer(); - * stage.add(layer); - * // now you can add shapes, groups into the layer - */ - var Layer = /** @class */ (function (_super) { - __extends(Layer, _super); - function Layer() { - var _this = _super !== null && _super.apply(this, arguments) || this; - _this.hitCanvas = new HitCanvas({ - pixelRatio: 1 - }); - return _this; - } - Layer.prototype._setCanvasSize = function (width, height) { - this.canvas.setSize(width, height); - this.hitCanvas.setSize(width, height); - }; - Layer.prototype._validateAdd = function (child) { - var type = child.getType(); - if (type !== 'Group' && type !== 'Shape') { - Util.throw('You may only add groups and shapes to a layer.'); - } - }; - /** - * get visible intersection shape. This is the preferred - * method for determining if a point intersects a shape or not - * also you may pass optional selector parameter to return ancestor of intersected shape - * @method - * @name Konva.Layer#getIntersection - * @param {Object} pos - * @param {Number} pos.x - * @param {Number} pos.y - * @param {String} [selector] - * @returns {Konva.Node} - * @example - * var shape = layer.getIntersection({x: 50, y: 50}); - * // or if you interested in shape parent: - * var group = layer.getIntersection({x: 50, y: 50}, 'Group'); - */ - Layer.prototype.getIntersection = function (pos, selector) { - var obj, i, intersectionOffset, shape; - if (!this.hitGraphEnabled() || !this.isVisible()) { - return null; - } - // in some cases antialiased area may be bigger than 1px - // it is possible if we will cache node, then scale it a lot - var spiralSearchDistance = 1; - var continueSearch = false; - while (true) { - for (i = 0; i < INTERSECTION_OFFSETS_LEN; i++) { - intersectionOffset = INTERSECTION_OFFSETS[i]; - obj = this._getIntersection({ - x: pos.x + intersectionOffset.x * spiralSearchDistance, - y: pos.y + intersectionOffset.y * spiralSearchDistance - }); - shape = obj.shape; - if (shape && selector) { - return shape.findAncestor(selector, true); - } - else if (shape) { - return shape; - } - // we should continue search if we found antialiased pixel - // that means our node somewhere very close - continueSearch = !!obj.antialiased; - // stop search if found empty pixel - if (!obj.antialiased) { - break; - } - } - // if no shape, and no antialiased pixel, we should end searching - if (continueSearch) { - spiralSearchDistance += 1; - } - else { - return null; - } - } - }; - Layer.prototype._getIntersection = function (pos) { - var ratio = this.hitCanvas.pixelRatio; - var p = this.hitCanvas.context.getImageData(Math.round(pos.x * ratio), Math.round(pos.y * ratio), 1, 1).data, p3 = p[3], colorKey, shape; - // fully opaque pixel - if (p3 === 255) { - colorKey = Util._rgbToHex(p[0], p[1], p[2]); - shape = shapes[HASH$1 + colorKey]; - if (shape) { - return { - shape: shape - }; - } - return { - antialiased: true - }; - } - else if (p3 > 0) { - // antialiased pixel - return { - antialiased: true - }; - } - // empty pixel - return {}; - }; - Layer.prototype.drawScene = function (can, top) { - var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas()); - this._fire(BEFORE_DRAW, { - node: this - }); - if (this.clearBeforeDraw()) { - canvas.getContext().clear(); - } - Container.prototype.drawScene.call(this, canvas, top); - this._fire(DRAW, { - node: this - }); - return this; - }; - Layer.prototype.drawHit = function (can, top) { - var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas); - if (layer && layer.clearBeforeDraw()) { - layer - .getHitCanvas() - .getContext() - .clear(); - } - Container.prototype.drawHit.call(this, canvas, top); - return this; - }; - Layer.prototype.clear = function (bounds) { - BaseLayer.prototype.clear.call(this, bounds); - this.getHitCanvas() - .getContext() - .clear(bounds); - return this; - }; - /** - * enable hit graph - * @name Konva.Layer#enableHitGraph - * @method - * @returns {Layer} - */ - Layer.prototype.enableHitGraph = function () { - this.hitGraphEnabled(true); - return this; - }; - /** - * disable hit graph - * @name Konva.Layer#disableHitGraph - * @method - * @returns {Layer} - */ - Layer.prototype.disableHitGraph = function () { - this.hitGraphEnabled(false); - return this; - }; - /** - * Show or hide hit canvas over the stage. May be useful for debugging custom hitFunc - * @name Konva.Layer#toggleHitCanvas - * @method - */ - Layer.prototype.toggleHitCanvas = function () { - if (!this.parent) { - return; - } - var parent = this.parent; - var added = !!this.hitCanvas._canvas.parentNode; - if (added) { - parent.content.removeChild(this.hitCanvas._canvas); - } - else { - parent.content.appendChild(this.hitCanvas._canvas); - } - }; - Layer.prototype.setSize = function (_a) { - var width = _a.width, height = _a.height; - _super.prototype.setSize.call(this, { width: width, height: height }); - this.hitCanvas.setSize(width, height); - return this; - }; - return Layer; - }(BaseLayer)); - Factory.addGetterSetter(Layer, 'hitGraphEnabled', true, Validators.getBooleanValidator()); - /** - * get/set hitGraphEnabled flag. Disabling the hit graph will greatly increase - * draw performance because the hit graph will not be redrawn each time the layer is - * drawn. This, however, also disables mouse/touch event detection - * @name Konva.Layer#hitGraphEnabled - * @method - * @param {Boolean} enabled - * @returns {Boolean} - * @example - * // get hitGraphEnabled flag - * var hitGraphEnabled = layer.hitGraphEnabled(); - * - * // disable hit graph - * layer.hitGraphEnabled(false); - * - * // enable hit graph - * layer.hitGraphEnabled(true); - */ - Collection.mapMethods(Layer); - - /** - * FastLayer constructor. Layers are tied to their own canvas element and are used - * to contain shapes only. If you don't need node nesting, mouse and touch interactions, - * or event pub/sub, you should use FastLayer instead of Layer to create your layers. - * It renders about 2x faster than normal layers. - * @constructor - * @memberof Konva - * @augments Konva.BaseLayer - * @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 {Boolean} [config.visible] - * @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 - - * @example - * var layer = new Konva.FastLayer(); - */ - var FastLayer = /** @class */ (function (_super) { - __extends(FastLayer, _super); - function FastLayer() { - return _super !== null && _super.apply(this, arguments) || this; - } - FastLayer.prototype._validateAdd = function (child) { - var type = child.getType(); - if (type !== 'Shape') { - Util.throw('You may only add shapes to a fast layer.'); - } - }; - FastLayer.prototype._setCanvasSize = function (width, height) { - this.canvas.setSize(width, height); - }; - FastLayer.prototype.hitGraphEnabled = function () { - return false; - }; - FastLayer.prototype.drawScene = function (can) { - var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas()); - if (this.clearBeforeDraw()) { - canvas.getContext().clear(); - } - Container.prototype.drawScene.call(this, canvas); - return this; - }; - FastLayer.prototype.draw = function () { - this.drawScene(); - return this; - }; - return FastLayer; - }(BaseLayer)); - Collection.mapMethods(FastLayer); - - /** - * Group constructor. Groups are used to contain shapes or other groups. - * @constructor - * @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 - - * @example - * var group = new Konva.Group(); - */ - var Group = /** @class */ (function (_super) { - __extends(Group, _super); - function Group() { - return _super !== null && _super.apply(this, arguments) || this; - } - Group.prototype._validateAdd = function (child) { - var type = child.getType(); - if (type !== 'Group' && type !== 'Shape') { - Util.throw('You may only add groups and shapes to groups.'); - } - }; - return Group; - }(Container)); - Group.prototype.nodeType = 'Group'; - Collection.mapMethods(Group); - var HAS_SHADOW = 'hasShadow'; var SHADOW_RGBA = 'shadowRGBA'; var patternImage = 'patternImage'; @@ -6871,6 +6508,7 @@ dummyContext = Util.createCanvasElement().getContext('2d'); return dummyContext; } + var shapes = {}; // TODO: idea - use only "remove" (or destroy method) // how? on add, check that every inner shape has reference in konva store with color // on remove - clear that reference @@ -7483,7 +7121,7 @@ Factory.addGetterSetter(Shape, 'perfectDrawEnabled', true, Validators.getBooleanValidator()); /** * get/set perfectDrawEnabled. If a shape has fill, stroke and opacity you may set `perfectDrawEnabled` to false to improve performance. - * See http://konvajs.github.io/docs/performance/Disable_Perfect_Draw.html for more information. + * See http://konvajs.org/docs/performance/Disable_Perfect_Draw.html for more information. * Default value is true * @name Konva.Shape#perfectDrawEnabled * @method @@ -8390,6 +8028,372 @@ }); Collection.mapMethods(Shape); + // constants + var HASH$1 = '#', BEFORE_DRAW = 'beforeDraw', DRAW = 'draw', + /* + * 2 - 3 - 4 + * | | + * 1 - 0 5 + * | + * 8 - 7 - 6 + */ + INTERSECTION_OFFSETS = [ + { x: 0, y: 0 }, + { x: -1, y: -1 }, + { x: 1, y: -1 }, + { x: 1, y: 1 }, + { x: -1, y: 1 } // 8 + ], INTERSECTION_OFFSETS_LEN = INTERSECTION_OFFSETS.length; + /** + * Layer constructor. Layers are tied to their own canvas element and are used + * to contain groups or shapes. + * @constructor + * @memberof Konva + * @augments Konva.BaseLayer + * @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 + + * @example + * var layer = new Konva.Layer(); + * stage.add(layer); + * // now you can add shapes, groups into the layer + */ + var Layer = /** @class */ (function (_super) { + __extends(Layer, _super); + function Layer() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.hitCanvas = new HitCanvas({ + pixelRatio: 1 + }); + return _this; + } + Layer.prototype._setCanvasSize = function (width, height) { + this.canvas.setSize(width, height); + this.hitCanvas.setSize(width, height); + }; + Layer.prototype._validateAdd = function (child) { + var type = child.getType(); + if (type !== 'Group' && type !== 'Shape') { + Util.throw('You may only add groups and shapes to a layer.'); + } + }; + /** + * get visible intersection shape. This is the preferred + * method for determining if a point intersects a shape or not + * also you may pass optional selector parameter to return ancestor of intersected shape + * @method + * @name Konva.Layer#getIntersection + * @param {Object} pos + * @param {Number} pos.x + * @param {Number} pos.y + * @param {String} [selector] + * @returns {Konva.Node} + * @example + * var shape = layer.getIntersection({x: 50, y: 50}); + * // or if you interested in shape parent: + * var group = layer.getIntersection({x: 50, y: 50}, 'Group'); + */ + Layer.prototype.getIntersection = function (pos, selector) { + var obj, i, intersectionOffset, shape; + if (!this.hitGraphEnabled() || !this.isVisible()) { + return null; + } + // in some cases antialiased area may be bigger than 1px + // it is possible if we will cache node, then scale it a lot + var spiralSearchDistance = 1; + var continueSearch = false; + while (true) { + for (i = 0; i < INTERSECTION_OFFSETS_LEN; i++) { + intersectionOffset = INTERSECTION_OFFSETS[i]; + obj = this._getIntersection({ + x: pos.x + intersectionOffset.x * spiralSearchDistance, + y: pos.y + intersectionOffset.y * spiralSearchDistance + }); + shape = obj.shape; + if (shape && selector) { + return shape.findAncestor(selector, true); + } + else if (shape) { + return shape; + } + // we should continue search if we found antialiased pixel + // that means our node somewhere very close + continueSearch = !!obj.antialiased; + // stop search if found empty pixel + if (!obj.antialiased) { + break; + } + } + // if no shape, and no antialiased pixel, we should end searching + if (continueSearch) { + spiralSearchDistance += 1; + } + else { + return null; + } + } + }; + Layer.prototype._getIntersection = function (pos) { + var ratio = this.hitCanvas.pixelRatio; + var p = this.hitCanvas.context.getImageData(Math.round(pos.x * ratio), Math.round(pos.y * ratio), 1, 1).data, p3 = p[3], colorKey, shape; + // fully opaque pixel + if (p3 === 255) { + colorKey = Util._rgbToHex(p[0], p[1], p[2]); + shape = shapes[HASH$1 + colorKey]; + if (shape) { + return { + shape: shape + }; + } + return { + antialiased: true + }; + } + else if (p3 > 0) { + // antialiased pixel + return { + antialiased: true + }; + } + // empty pixel + return {}; + }; + Layer.prototype.drawScene = function (can, top) { + var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas()); + this._fire(BEFORE_DRAW, { + node: this + }); + if (this.clearBeforeDraw()) { + canvas.getContext().clear(); + } + Container.prototype.drawScene.call(this, canvas, top); + this._fire(DRAW, { + node: this + }); + return this; + }; + Layer.prototype.drawHit = function (can, top) { + var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas); + if (layer && layer.clearBeforeDraw()) { + layer + .getHitCanvas() + .getContext() + .clear(); + } + Container.prototype.drawHit.call(this, canvas, top); + return this; + }; + Layer.prototype.clear = function (bounds) { + BaseLayer.prototype.clear.call(this, bounds); + this.getHitCanvas() + .getContext() + .clear(bounds); + return this; + }; + /** + * enable hit graph + * @name Konva.Layer#enableHitGraph + * @method + * @returns {Layer} + */ + Layer.prototype.enableHitGraph = function () { + this.hitGraphEnabled(true); + return this; + }; + /** + * disable hit graph + * @name Konva.Layer#disableHitGraph + * @method + * @returns {Layer} + */ + Layer.prototype.disableHitGraph = function () { + this.hitGraphEnabled(false); + return this; + }; + /** + * Show or hide hit canvas over the stage. May be useful for debugging custom hitFunc + * @name Konva.Layer#toggleHitCanvas + * @method + */ + Layer.prototype.toggleHitCanvas = function () { + if (!this.parent) { + return; + } + var parent = this.parent; + var added = !!this.hitCanvas._canvas.parentNode; + if (added) { + parent.content.removeChild(this.hitCanvas._canvas); + } + else { + parent.content.appendChild(this.hitCanvas._canvas); + } + }; + Layer.prototype.setSize = function (_a) { + var width = _a.width, height = _a.height; + _super.prototype.setSize.call(this, { width: width, height: height }); + this.hitCanvas.setSize(width, height); + return this; + }; + return Layer; + }(BaseLayer)); + Factory.addGetterSetter(Layer, 'hitGraphEnabled', true, Validators.getBooleanValidator()); + /** + * get/set hitGraphEnabled flag. Disabling the hit graph will greatly increase + * draw performance because the hit graph will not be redrawn each time the layer is + * drawn. This, however, also disables mouse/touch event detection + * @name Konva.Layer#hitGraphEnabled + * @method + * @param {Boolean} enabled + * @returns {Boolean} + * @example + * // get hitGraphEnabled flag + * var hitGraphEnabled = layer.hitGraphEnabled(); + * + * // disable hit graph + * layer.hitGraphEnabled(false); + * + * // enable hit graph + * layer.hitGraphEnabled(true); + */ + Collection.mapMethods(Layer); + + /** + * FastLayer constructor. Layers are tied to their own canvas element and are used + * to contain shapes only. If you don't need node nesting, mouse and touch interactions, + * or event pub/sub, you should use FastLayer instead of Layer to create your layers. + * It renders about 2x faster than normal layers. + * @constructor + * @memberof Konva + * @augments Konva.BaseLayer + * @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 {Boolean} [config.visible] + * @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 + + * @example + * var layer = new Konva.FastLayer(); + */ + var FastLayer = /** @class */ (function (_super) { + __extends(FastLayer, _super); + function FastLayer() { + return _super !== null && _super.apply(this, arguments) || this; + } + FastLayer.prototype._validateAdd = function (child) { + var type = child.getType(); + if (type !== 'Shape') { + Util.throw('You may only add shapes to a fast layer.'); + } + }; + FastLayer.prototype._setCanvasSize = function (width, height) { + this.canvas.setSize(width, height); + }; + FastLayer.prototype.hitGraphEnabled = function () { + return false; + }; + FastLayer.prototype.drawScene = function (can) { + var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas()); + if (this.clearBeforeDraw()) { + canvas.getContext().clear(); + } + Container.prototype.drawScene.call(this, canvas); + return this; + }; + FastLayer.prototype.draw = function () { + this.drawScene(); + return this; + }; + return FastLayer; + }(BaseLayer)); + Collection.mapMethods(FastLayer); + + /** + * Group constructor. Groups are used to contain shapes or other groups. + * @constructor + * @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 + + * @example + * var group = new Konva.Group(); + */ + var Group = /** @class */ (function (_super) { + __extends(Group, _super); + function Group() { + return _super !== null && _super.apply(this, arguments) || this; + } + Group.prototype._validateAdd = function (child) { + var type = child.getType(); + if (type !== 'Group' && type !== 'Shape') { + Util.throw('You may only add groups and shapes to groups.'); + } + }; + return Group; + }(Container)); + Group.prototype.nodeType = 'Group'; + Collection.mapMethods(Group); + var blacklist = { node: 1, duration: 1, @@ -12410,10 +12414,10 @@ return dummyContext$1; } function _fillFunc$1(context) { - context.fillText(this.partialText, this._textX, this._textY); + context.fillText(this._partialText, this._partialTextX, this._partialTextY); } function _strokeFunc$1(context) { - context.strokeText(this.partialText, this._textX, this._textY); + context.strokeText(this._partialText, this._partialTextX, this._partialTextY); } function checkDefaultFill(config) { config = config || {}; @@ -12528,8 +12532,8 @@ __extends(Text, _super); function Text(config) { var _this = _super.call(this, checkDefaultFill(config)) || this; - _this._textX = 0; - _this._textY = 0; + _this._partialTextX = 0; + _this._partialTextY = 0; // update text data for certain attr changes for (var n = 0; n < attrChangeListLen$1; n++) { _this.on(ATTR_CHANGE_LIST$1[n] + CHANGE_KONVA$1, _this._setTextData); @@ -12614,18 +12618,18 @@ // 0 // ); } - this._textX = lineTranslateX; - this._textY = translateY + lineTranslateY; - this.partialText = letter; + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = letter; context.fillStrokeShape(this); lineTranslateX += Math.round(this.measureSize(letter).width) + letterSpacing; } } else { - this._textX = lineTranslateX; - this._textY = translateY + lineTranslateY; - this.partialText = text; + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = text; context.fillStrokeShape(this); } context.restore(); @@ -16943,7 +16947,7 @@ */ var enableTrace = false; - var traceArrMax = 100; + // TODO: move that to stage? var listenClickTap = false; var inDblClickWindow = false; /** @@ -17026,7 +17030,6 @@ var Konva = ({ enableTrace: enableTrace, - traceArrMax: traceArrMax, listenClickTap: listenClickTap, inDblClickWindow: inDblClickWindow, pixelRatio: pixelRatio, @@ -17039,6 +17042,7 @@ Util: Util, Node: Node, ids: ids, + names: names, Container: Container, Stage: Stage, stages: stages, @@ -17047,6 +17051,7 @@ Group: Group, DD: DD, Shape: Shape, + shapes: shapes, Animation: Animation, Tween: Tween, Easings: Easings, @@ -17069,15 +17074,11 @@ Transformer: Transformer, Wedge: Wedge, version: version, - names: names, - shapes: shapes, isBrowser: isBrowser, isUnminified: isUnminified, dblClickWindow: dblClickWindow, isDragging: isDragging, isDragReady: isDragReady, - _addName: _addName, - _removeName: _removeName, getAngle: getAngle, _detectIE: _detectIE, _parseUA: _parseUA, diff --git a/konva.min.js b/konva.min.js index 04ddb783..1897e936 100644 --- a/konva.min.js +++ b/konva.min.js @@ -1,7 +1,7 @@ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Konva=e()}(this,function(){"use strict"; /* * Konva JavaScript Framework v3.0.0-3 - * http://konvajs.github.io/ + * http://konvajs.org/ * Licensed under the MIT * Date: Sat Feb 23 2019 * @@ -9,4 +9,4 @@ * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * * @license - */var e=Math.PI/180,n={},o={},a="undefined"!=typeof window&&("[object Window]"==={}.toString.call(window)||"[object global]"==={}.toString.call(window)),t=/comment/.test(function(){}.toString()),h=function(t,e){e&&(n[e]||(n[e]=[]),n[e].push(t))},l=function(t,e){if(t){var i=n[t];if(i){for(var r=0;r>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 y?{r:(e=y[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=m.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",O._namedColorToRBA(t)||O._hex3ColorToRGBA(t)||O._hex6ColorToRGBA(t)||O._rgbColorToRGBA(t)||O._rgbaColorToRGBA(t)},_namedColorToRBA:function(t){var e=y[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}},haveIntersection:function(t,e){return!(e.x>t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var o=e;e=t,t=o}for(r=0;r=D().traceArrMax&&e.shift()},t.prototype.reset=function(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)},t.prototype.getCanvas=function(){return this.canvas},t.prototype.clear=function(t){var e=this.getCanvas();t?this.clearRect(t.x||0,t.y||0,t.width||0,t.height||0):this.clearRect(0,0,e.getWidth()/e.pixelRatio,e.getHeight()/e.pixelRatio)},t.prototype._applyLineCap=function(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)},t.prototype._applyOpacity=function(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)},t.prototype._applyLineJoin=function(t){var e=t.getLineJoin();e&&this.setAttr("lineJoin",e)},t.prototype.setAttr=function(t,e){this._context[t]=e},t.prototype.arc=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.arcTo=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.beginPath=function(){this._context.beginPath()},t.prototype.bezierCurveTo=function(t,e,i,r,n,a){this._context.bezierCurveTo(t,e,i,r,n,a)},t.prototype.clearRect=function(t,e,i,r){this._context.clearRect(t,e,i,r)},t.prototype.clip=function(){this._context.clip()},t.prototype.closePath=function(){this._context.closePath()},t.prototype.createImageData=function(t,e){var i=arguments;return 2===i.length?this._context.createImageData(t,e):1===i.length?this._context.createImageData(t):void 0},t.prototype.createLinearGradient=function(t,e,i,r){return this._context.createLinearGradient(t,e,i,r)},t.prototype.createPattern=function(t,e){return this._context.createPattern(t,e)},t.prototype.createRadialGradient=function(t,e,i,r,n,a){return this._context.createRadialGradient(t,e,i,r,n,a)},t.prototype.drawImage=function(t,e,i,r,n,a,o,s,h){var l=arguments,d=this._context;3===l.length?d.drawImage(t,e,i):5===l.length?d.drawImage(t,e,i,r,n):9===l.length&&d.drawImage(t,e,i,r,n,a,o,s,h)},t.prototype.isPointInPath=function(t,e){return this._context.isPointInPath(t,e)},t.prototype.fill=function(){this._context.fill()},t.prototype.fillRect=function(t,e,i,r){this._context.fillRect(t,e,i,r)},t.prototype.strokeRect=function(t,e,i,r){this._context.strokeRect(t,e,i,r)},t.prototype.fillText=function(t,e,i){this._context.fillText(t,e,i)},t.prototype.measureText=function(t){return this._context.measureText(t)},t.prototype.getImageData=function(t,e,i,r){return this._context.getImageData(t,e,i,r)},t.prototype.lineTo=function(t,e){this._context.lineTo(t,e)},t.prototype.moveTo=function(t,e){this._context.moveTo(t,e)},t.prototype.rect=function(t,e,i,r){this._context.rect(t,e,i,r)},t.prototype.putImageData=function(t,e,i){this._context.putImageData(t,e,i)},t.prototype.quadraticCurveTo=function(t,e,i,r){this._context.quadraticCurveTo(t,e,i,r)},t.prototype.restore=function(){this._context.restore()},t.prototype.rotate=function(t){this._context.rotate(t)},t.prototype.save=function(){this._context.save()},t.prototype.scale=function(t,e){this._context.scale(t,e)},t.prototype.setLineDash=function(t){this._context.setLineDash?this._context.setLineDash(t):"mozDash"in this._context?this._context.mozDash=t:"webkitLineDash"in this._context&&(this._context.webkitLineDash=t)},t.prototype.getLineDash=function(){return this._context.getLineDash()},t.prototype.setTransform=function(t,e,i,r,n,a){this._context.setTransform(t,e,i,r,n,a)},t.prototype.stroke=function(){this._context.stroke()},t.prototype.strokeText=function(t,e,i,r){this._context.strokeText(t,e,i,r)},t.prototype.transform=function(t,e,i,r,n,a){this._context.transform(t,e,i,r,n,a)},t.prototype.translate=function(t,e){this._context.translate(t,e)},t.prototype._enableTrace=function(){var t,r,n=this,e=P.length,a=O._simplifyArray,i=this.setAttr,o=function(t){var e,i=n[t];n[t]=function(){return r=a(Array.prototype.slice.call(arguments,0)),e=i.apply(n,arguments),n._trace({method:t,args:r}),e}};for(t=0;t=this.parent.children.length)&&O.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},s.prototype.getAbsoluteOpacity=function(){return this._getCache(H,this._getAbsoluteOpacity)},s.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=this.getParent().getAbsoluteOpacity()),t},s.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},s.prototype.toObject=function(){var t,e,i,r={},n=this.getAttrs();for(t in r.attrs={},n)e=n[t],O.isObject(e)&&!O._isPlainObject(e)&&!O._isArray(e)||(i="function"==typeof this[t]&&this[t],delete n[t],(i?i.call(this):null)!==(n[t]=e)&&(r.attrs[t]=e));return r.className=this.getClassName(),O._prepareToStringify(r)},s.prototype.toJSON=function(){return JSON.stringify(this.toObject())},s.prototype.getParent=function(){return this.parent},s.prototype.findAncestors=function(t,e,i){var r=[];e&&this._isMatch(t)&&r.push(this);for(var n=this.parent;n;){if(n===i)return r;n._isMatch(t)&&r.push(n),n=n.parent}return r},s.prototype.isAncestorOf=function(t){return!1},s.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},s.prototype._isMatch=function(t){if(!t)return!1;var e,i,r=t.replace(/ /g,"").split(","),n=r.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())},t.prototype.getTime=function(){return this._time},t.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},t.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},t.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},t.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},t.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},t.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},t.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},t.prototype.update=function(){this.setPosition(this.getPosition(this._time))},t.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},t.prototype.pause=function(){this.state=1,this.fire("onPause")},t.prototype.getTimer=function(){return(new Date).getTime()},t}(),jt=function(){function p(t){var e,i,r=this,n=t.node,a=n._id,o=t.easing||Ut.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=n,this._id=Wt++;var h=n.getLayer()||(n instanceof D().Stage?n.getLayers():null);for(i in h||O.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new E(function(){r.tween.onEnterFrame()},h),this.tween=new Xt(i,function(t){r._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),p.attrs[a]||(p.attrs[a]={}),p.attrs[a][this._id]||(p.attrs[a][this._id]={}),p.tweens[a]||(p.tweens[a]={}),t)void 0===Ht[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset}return p.prototype._addAttr=function(t,e){var i,r,n,a,o,s,h,l,d=this.node,c=d._id;if((n=p.tweens[c][t])&&delete p.attrs[c][n][t],i=d.getAttr(t),O._isArray(e))if(r=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=O._prepareArrayForTween(i,e,d.closed())):(s=e,e=O._prepareArrayForTween(e,i,d.closed()))),0===t.indexOf("fill"))for(a=0;athis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===r)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 n=this.dataArray[i],a=n.points;switch(n.command){case"L":return p.getPointOnLine(t,n.start.x,n.start.y,a[0],a[1]);case"C":return p.getPointOnCubicBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3],a[4],a[5]);case"Q":return p.getPointOnQuadraticBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3]);case"A":var o=a[0],s=a[1],h=a[2],l=a[3],d=a[4],c=a[5],u=a[6];return d+=c*t/n.pathLength,p.getPointOnEllipticalArc(o,s,h,l,d,u)}return null},p.getLineLength=function(t,e,i,r){return Math.sqrt((i-t)*(i-t)+(r-e)*(r-e))},p.getPointOnLine=function(t,e,i,r,n,a,o){void 0===a&&(a=e),void 0===o&&(o=i);var s=(n-i)/(r-e+1e-8),h=Math.sqrt(t*t/(1+s*s));r>>1,P=_.slice(0,k+1),T=this._getTextWidth(P)+v;T<=l?(S=k+1,w=P+(g?"…":""),C=T):x=k}if(!w)break;if(f){var M,A=_[w.length];0<(M=(" "===A||"-"===A)&&C<=l?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(S=M,w=w.slice(0,S),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=r,!p||s&&de?g=se.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var o=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=o+1e-8:iv.pathLength?1e-8:e/v.pathLength:i>V,0!==C?(C=255/C,P[s]=(l*B>>V)*C,P[s+1]=(d*B>>V)*C,P[s+2]=(c*B>>V)*C):P[s]=P[s+1]=P[s+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=h+((a=i+e+1)>V,0>V)*C,P[a+1]=(d*B>>V)*C,P[a+2]=(c*B>>V)*C):P[a]=P[a+1]=P[a+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=i+((a=r+L)>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=f.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",O._namedColorToRBA(t)||O._hex3ColorToRGBA(t)||O._hex6ColorToRGBA(t)||O._rgbColorToRGBA(t)||O._rgbaColorToRGBA(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}},haveIntersection:function(t,e){return!(e.x>t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var o=e;e=t,t=o}for(r=0;r=this.parent.children.length)&&O.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},s.prototype.getAbsoluteOpacity=function(){return this._getCache(V,this._getAbsoluteOpacity)},s.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=this.getParent().getAbsoluteOpacity()),t},s.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},s.prototype.toObject=function(){var t,e,i,r={},n=this.getAttrs();for(t in r.attrs={},n)e=n[t],O.isObject(e)&&!O._isPlainObject(e)&&!O._isArray(e)||(i="function"==typeof this[t]&&this[t],delete n[t],(i?i.call(this):null)!==(n[t]=e)&&(r.attrs[t]=e));return r.className=this.getClassName(),O._prepareToStringify(r)},s.prototype.toJSON=function(){return JSON.stringify(this.toObject())},s.prototype.getParent=function(){return this.parent},s.prototype.findAncestors=function(t,e,i){var r=[];e&&this._isMatch(t)&&r.push(this);for(var n=this.parent;n;){if(n===i)return r;n._isMatch(t)&&r.push(n),n=n.parent}return r},s.prototype.isAncestorOf=function(t){return!1},s.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},s.prototype._isMatch=function(t){if(!t)return!1;var e,i,r=t.replace(/ /g,"").split(","),n=r.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())},t.prototype.getTime=function(){return this._time},t.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},t.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},t.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},t.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},t.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},t.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},t.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},t.prototype.update=function(){this.setPosition(this.getPosition(this._time))},t.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},t.prototype.pause=function(){this.state=1,this.fire("onPause")},t.prototype.getTimer=function(){return(new Date).getTime()},t}(),Xt=function(){function p(t){var e,i,r=this,n=t.node,a=n._id,o=t.easing||jt.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=n,this._id=Ht++;var h=n.getLayer()||(n instanceof D().Stage?n.getLayers():null);for(i in h||O.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new R(function(){r.tween.onEnterFrame()},h),this.tween=new Yt(i,function(t){r._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),p.attrs[a]||(p.attrs[a]={}),p.attrs[a][this._id]||(p.attrs[a][this._id]={}),p.tweens[a]||(p.tweens[a]={}),t)void 0===zt[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset}return p.prototype._addAttr=function(t,e){var i,r,n,a,o,s,h,l,d=this.node,c=d._id;if((n=p.tweens[c][t])&&delete p.attrs[c][n][t],i=d.getAttr(t),O._isArray(e))if(r=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=O._prepareArrayForTween(i,e,d.closed())):(s=e,e=O._prepareArrayForTween(e,i,d.closed()))),0===t.indexOf("fill"))for(a=0;athis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===r)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 n=this.dataArray[i],a=n.points;switch(n.command){case"L":return p.getPointOnLine(t,n.start.x,n.start.y,a[0],a[1]);case"C":return p.getPointOnCubicBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3],a[4],a[5]);case"Q":return p.getPointOnQuadraticBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3]);case"A":var o=a[0],s=a[1],h=a[2],l=a[3],d=a[4],c=a[5],u=a[6];return d+=c*t/n.pathLength,p.getPointOnEllipticalArc(o,s,h,l,d,u)}return null},p.getLineLength=function(t,e,i,r){return Math.sqrt((i-t)*(i-t)+(r-e)*(r-e))},p.getPointOnLine=function(t,e,i,r,n,a,o){void 0===a&&(a=e),void 0===o&&(o=i);var s=(n-i)/(r-e+1e-8),h=Math.sqrt(t*t/(1+s*s));r>>1,P=_.slice(0,k+1),T=this._getTextWidth(P)+v;T<=l?(S=k+1,w=P+(g?"…":""),C=T):x=k}if(!w)break;if(f){var M,A=_[w.length];0<(M=(" "===A||"-"===A)&&C<=l?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(S=M,w=w.slice(0,S),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=r,!p||s&&de?g=oe.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var o=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=o+1e-8:iv.pathLength?1e-8:e/v.pathLength:i>V,0!==C?(C=255/C,P[s]=(l*B>>V)*C,P[s+1]=(d*B>>V)*C,P[s+2]=(c*B>>V)*C):P[s]=P[s+1]=P[s+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=h+((a=i+e+1)>V,0>V)*C,P[a+1]=(d*B>>V)*C,P[a+2]=(c*B>>V)*C):P[a]=P[a+1]=P[a+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=i+((a=r+L)= getGlobalKonva().traceArrMax) { + if (len >= traceArrMax) { traceArr.shift(); } } diff --git a/src/DragAndDrop.ts b/src/DragAndDrop.ts index 394bfbff..ecdc4c0d 100644 --- a/src/DragAndDrop.ts +++ b/src/DragAndDrop.ts @@ -1,6 +1,9 @@ import { Animation } from './Animation'; import { isBrowser, getGlobalKonva } from './Global'; + +// TODO: make better module, +// make sure other modules import it without global export const DD = { startPointerPos: { x: 0, diff --git a/src/Global.ts b/src/Global.ts index eeab52d2..695abe3f 100644 --- a/src/Global.ts +++ b/src/Global.ts @@ -1,6 +1,6 @@ /* * Konva JavaScript Framework v@@version - * http://konvajs.github.io/ + * http://konvajs.org/ * Licensed under the MIT * Date: @@date * @@ -15,9 +15,6 @@ var PI_OVER_180 = Math.PI / 180; */ export const version = '@@version'; -export const names = {}; -export const shapes = {}; - export const isBrowser = typeof window !== 'undefined' && // browser case @@ -65,34 +62,6 @@ export const isDragReady = function() { return false; }; -export const _addName = function(node: any, name) { - if (name) { - if (!names[name]) { - names[name] = []; - } - names[name].push(node); - } -}; - -export const _removeName = function(name, _id) { - if (!name) { - return; - } - var nodes = names[name]; - if (!nodes) { - return; - } - for (var n = 0; n < nodes.length; n++) { - var no = nodes[n]; - if (no._id === _id) { - nodes.splice(n, 1); - } - } - if (nodes.length === 0) { - delete names[name]; - } -}; - export const getAngle = function(angle) { return getGlobalKonva().angleDeg ? angle * PI_OVER_180 : angle; }; diff --git a/src/Layer.ts b/src/Layer.ts index 3f04b4c3..f2bebad2 100644 --- a/src/Layer.ts +++ b/src/Layer.ts @@ -3,7 +3,7 @@ import { Container } from './Container'; import { Factory, Validators } from './Factory'; import { BaseLayer } from './BaseLayer'; import { HitCanvas } from './Canvas'; -import { shapes } from './Global'; +import { shapes } from './Shape'; import { GetSet } from './types'; diff --git a/src/Node.ts b/src/Node.ts index c08c25f4..5d77cd43 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,12 +1,13 @@ import { Util, Collection, Transform, RectConf, Point } from './Util'; import { Factory, Validators } from './Factory'; import { SceneCanvas, HitCanvas } from './Canvas'; -import { _removeName, _addName, getGlobalKonva } from './Global'; +import { getGlobalKonva } from './Global'; import { Container } from './Container'; import { GetSet, Vector2d } from './types'; import { DD } from './DragAndDrop'; export const ids = {}; +export const names = {}; const ID_WARNING = `Duplicate id "{id}". Please do not use same id several times, it will break find() method look up. @@ -35,6 +36,34 @@ export const _removeId = function(id: string, node: any) { delete ids[id]; }; +export const _addName = function(node: any, name) { + if (name) { + if (!names[name]) { + names[name] = []; + } + names[name].push(node); + } +}; + +export const _removeName = function(name, _id) { + if (!name) { + return; + } + var nodes = names[name]; + if (!nodes) { + return; + } + for (var n = 0; n < nodes.length; n++) { + var no = nodes[n]; + if (no._id === _id) { + nodes.splice(n, 1); + } + } + if (nodes.length === 0) { + delete names[name]; + } +}; + export type Filter = (this: Node, imageData: ImageData) => void; type globalCompositeOperationType = @@ -215,7 +244,7 @@ export abstract class Node { * cache node to improve drawing performance, apply filters, or create more accurate * hit regions. For all basic shapes size of cache canvas will be automatically detected. * If you need to cache your custom `Konva.Shape` instance you have to pass shape's bounding box - * properties. Look at [https://konvajs.github.io/docs/performance/Shape_Caching.html](https://konvajs.github.io/docs/performance/Shape_Caching.html) for more information. + * properties. Look at [https://konvajs.org/docs/performance/Shape_Caching.html](https://konvajs.org/docs/performance/Shape_Caching.html) for more information. * @method * @name Konva.Node#cache * @param {Object} [config] diff --git a/src/Shape.ts b/src/Shape.ts index eb5c996c..388bad96 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -1,6 +1,5 @@ import { Util, Collection } from './Util'; import { Factory, Validators } from './Factory'; -import { shapes } from './Global'; import { Node } from './Node'; import { GetSet, Vector2d } from './types'; @@ -21,6 +20,8 @@ function getDummyContext() { return dummyContext; } +export const shapes = {}; + // TODO: idea - use only "remove" (or destroy method) // how? on add, check that every inner shape has reference in konva store with color // on remove - clear that reference @@ -783,7 +784,7 @@ Factory.addGetterSetter( /** * get/set perfectDrawEnabled. If a shape has fill, stroke and opacity you may set `perfectDrawEnabled` to false to improve performance. - * See http://konvajs.github.io/docs/performance/Disable_Perfect_Draw.html for more information. + * See http://konvajs.org/docs/performance/Disable_Perfect_Draw.html for more information. * Default value is true * @name Konva.Shape#perfectDrawEnabled * @method diff --git a/src/internals.ts b/src/internals.ts index dec7a6f9..7812bf08 100644 --- a/src/internals.ts +++ b/src/internals.ts @@ -1,7 +1,7 @@ export * from './Global'; export { Collection, Util } from './Util'; -export { Node, ids } from './Node'; +export { Node, ids, names } from './Node'; export { Container } from './Container'; export { Stage, stages } from './Stage'; @@ -12,13 +12,14 @@ export { FastLayer } from './FastLayer'; export { Group } from './Group'; export { DD } from './DragAndDrop'; -export { Shape } from './Shape'; +export { Shape, shapes } from './Shape'; export { Animation } from './Animation'; export { Tween, Easings } from './Tween'; export const enableTrace = false; -export const traceArrMax = 100; + +// TODO: move that to stage? export const listenClickTap = false; export const inDblClickWindow = false; @@ -97,8 +98,8 @@ export { Text } from './shapes/Text'; export { TextPath } from './shapes/TextPath'; export { Transformer } from './shapes/Transformer'; export { Wedge } from './shapes/Wedge'; -// filters +// filters import { Blur } from './filters/Blur'; import { Brighten } from './filters/Brighten'; import { Contrast } from './filters/Contrast'; diff --git a/src/shapes/Text.ts b/src/shapes/Text.ts index cc700ec3..fc4bc9e6 100644 --- a/src/shapes/Text.ts +++ b/src/shapes/Text.ts @@ -55,10 +55,10 @@ function getDummyContext() { } function _fillFunc(context) { - context.fillText(this.partialText, this._textX, this._textY); + context.fillText(this._partialText, this._partialTextX, this._partialTextY); } function _strokeFunc(context) { - context.strokeText(this.partialText, this._textX, this._textY); + context.strokeText(this._partialText, this._partialTextX, this._partialTextY); } function checkDefaultFill(config) { @@ -107,9 +107,9 @@ function checkDefaultFill(config) { */ export class Text extends Shape { textArr: Array<{ text: string; width: number }>; - partialText: string; - _textX = 0; - _textY = 0; + _partialText: string; + _partialTextX = 0; + _partialTextY = 0; textWidth: number; textHeight: number; @@ -240,17 +240,17 @@ export class Text extends Shape { // 0 // ); } - this._textX = lineTranslateX; - this._textY = translateY + lineTranslateY; - this.partialText = letter; + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = letter; context.fillStrokeShape(this); lineTranslateX += Math.round(this.measureSize(letter).width) + letterSpacing; } } else { - this._textX = lineTranslateX; - this._textY = translateY + lineTranslateY; - this.partialText = text; + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = text; context.fillStrokeShape(this); }