diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..54c2d7af --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Node.js CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 15.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test diff --git a/CHANGELOG.md b/CHANGELOG.md index ff805166..df9891a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `Konva.Collection` is removed. `container.children` is a simple array now. `container.find()` will return also a simple array instead of `Konva.Collection()`. - Better typescript support. Now every module has its own `*.d.ts` file. - New method `layer.getNativeCanvasElement()` +- Removed `Konva.UA`, `Konva._parseUA` (it was used for old browser detection) ## 7.2.5 diff --git a/README.md b/README.md index d4ff6b87..7a0c8fa2 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,19 @@

Konva

-[![Financial Contributors on Open Collective](https://opencollective.com/konva/all/badge.svg?label=financial+contributors)](https://opencollective.com/konva) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/konvajs/konva?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -[![npm version](https://badge.fury.io/js/konva.svg)](http://badge.fury.io/js/konva) [![bower version](https://badge.fury.io/bo/konva.svg)](http://badge.fury.io/bo/konva) -[![Build Status](https://travis-ci.org/konvajs/konva.png)](https://travis-ci.org/konvajs/konva)  [![Code Climate](https://codeclimate.com/github/konvajs/konva/badges/gpa.svg)](https://codeclimate.com/github/konvajs/konva) [![CDNJS version](https://img.shields.io/cdnjs/v/konva.svg)](https://cdnjs.com/libraries/konva) +[![Financial Contributors on Open Collective](https://opencollective.com/konva/all/badge.svg?label=financial+contributors)](https://opencollective.com/konva) +[![npm version](https://badge.fury.io/js/konva.svg)](http://badge.fury.io/js/konva) +[![Build Status](https://travis-ci.org/konvajs/konva.png)](https://travis-ci.org/konvajs/konva) [![CDNJS version](https://img.shields.io/cdnjs/v/konva.svg)](https://cdnjs.com/libraries/konva) 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. - - You can draw things onto the stage, add event listeners to them, move them, scale them, and rotate them independently from other shapes to support high performance animations, even if your application uses thousands of shapes. Served hot with a side of awesomeness. This repository began as a GitHub fork of [ericdrowell/KineticJS](https://github.com/ericdrowell/KineticJS). -* **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) +- **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 @@ -26,38 +24,38 @@ This repository began as a GitHub fork of [ericdrowell/KineticJS](https://github
``` @@ -157,7 +155,6 @@ See file `konva-node/demo.js` file in this repo as a sample. - [myposter GmbH](https://www.myposter.de/) - [queue.gg](https://queue.gg/) - # Change log See [CHANGELOG.md](https://github.com/konvajs/konva/blob/master/CHANGELOG.md). @@ -170,9 +167,8 @@ To make a full build run `npm run build`. The command will compile all typescrip Konva uses Mocha for testing. -* If you need run test only one time run `npm run test`. -* While developing it is easy to use `npm start`. Just run it and go to [http://localhost:8080/test/runner.html](http://localhost:8080/test/runner.html). The watcher will rebuild the bundle on any change. - +- If you need run test only one time run `npm run test`. +- While developing it is easy to use `npm start`. Just run it and go to [http://localhost:8080/test/runner.html](http://localhost:8080/test/runner.html). The watcher will rebuild the bundle on any change. Konva is covered with hundreds of tests and well over a thousand assertions. Konva uses TDD (test driven development) which means that every new feature or bug fix is accompanied with at least one new test. @@ -188,7 +184,6 @@ in particular if you have a bug fix, enhancement, or a new shape (see `src/shape ## Contributors - ### Financial Contributors Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/konva/contribute)] diff --git a/gulpfile.js b/gulpfile.js index 2d9dc947..7cc811bd 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,8 +4,6 @@ import uglify from 'gulp-uglify-es'; import replace from 'gulp-replace'; import jsdoc from 'gulp-jsdoc3'; import connect from 'gulp-connect'; -import jscpd from 'gulp-jscpd'; -import eslint from 'gulp-eslint'; import gutil from 'gulp-util'; import fs from 'fs'; @@ -61,35 +59,6 @@ gulp.task('server', function () { connect.server(); }); -// lint files -gulp.task('lint', function () { - return ( - gulp - .src('./src/**/*.js') - .pipe( - eslint({ - configFile: './.eslintrc', - }) - ) - // eslint.format() outputs the lint results to the console. - // Alternatively use eslint.formatEach() (see Docs). - .pipe(eslint.format()) - // To have the process exit with an error code (1) on - // lint error, return the stream and pipe to failOnError last. - .pipe(eslint.failOnError()) - ); -}); - -// check code for duplication -gulp.task('inspect', function () { - return gulp.src('./src/**/*.js').pipe( - jscpd({ - 'min-lines': 10, - verbose: true, - }) - ); -}); - // // generate documentation gulp.task('api', function () { return gulp.src('./konva.js').pipe( diff --git a/konva.js b/konva.js index 3c2cb524..cbd2bfd7 100644 --- a/konva.js +++ b/konva.js @@ -1,14 +1,9 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' - ? (module.exports = factory()) - : typeof define === 'function' && define.amd - ? define(factory) - : ((global = - typeof globalThis !== 'undefined' ? globalThis : global || self), - (global.Konva = factory())); -})(this, function () { - 'use strict'; - +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Konva = factory()); +}(this, (function () { 'use strict'; + /* * Konva JavaScript Framework v@@version * http://konvajs.org/ @@ -25,193 +20,150 @@ * @namespace Konva */ function detectBrowser() { - return ( - typeof window !== 'undefined' && - // browser case - ({}.toString.call(window) === '[object Window]' || - // electron case - {}.toString.call(window) === '[object global]') - ); + return (typeof window !== 'undefined' && + // browser case + ({}.toString.call(window) === '[object Window]' || + // electron case + {}.toString.call(window) === '[object global]')); } - const _detectIE = function (ua) { - var msie = ua.indexOf('msie '); - if (msie > 0) { - // IE 10 or older => return version number - return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); - } - var trident = ua.indexOf('trident/'); - if (trident > 0) { - // IE 11 => return version number - var rv = ua.indexOf('rv:'); - return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); - } - var edge = ua.indexOf('edge/'); - if (edge > 0) { - // Edge (IE 12+) => return version number - return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); - } - // other browser - return false; - }; - const _parseUA = function (userAgent) { - var ua = userAgent.toLowerCase(), - // jQuery UA regex - match = - /(chrome)[ /]([\w.]+)/.exec(ua) || - /(webkit)[ /]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ /]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - (ua.indexOf('compatible') < 0 && - /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)) || - [], - // adding mobile flag as well - mobile = !!userAgent.match( - /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i - ), - ieMobile = !!userAgent.match(/IEMobile/i); - return { - browser: match[1] || '', - version: match[2] || '0', - isIE: _detectIE(ua), - // adding mobile flab - mobile: mobile, - ieMobile: ieMobile, // If this is true (i.e., WP8), then Konva touch events are executed instead of equivalent Konva mouse events - }; - }; - const glob = - typeof global !== 'undefined' + const glob = typeof global !== 'undefined' ? global : typeof window !== 'undefined' - ? window - : typeof WorkerGlobalScope !== 'undefined' - ? self - : {}; + ? window + : typeof WorkerGlobalScope !== 'undefined' + ? self + : {}; const Konva$2 = { - _global: glob, - version: '@@version', - isBrowser: detectBrowser(), - isUnminified: /param/.test(function (param) {}.toString()), - dblClickWindow: 400, - getAngle(angle) { - return Konva$2.angleDeg ? angle * PI_OVER_180 : angle; - }, - enableTrace: false, - _pointerEventsEnabled: false, - autoDrawEnabled: false, - /** - * Should we enable hit detection while dragging? For performance reasons, by default it is false. - * But on some rare cases you want to see hit graph and check intersections. Just set it to true. - * @property hitOnDragEnabled - * @default false - * @name hitOnDragEnabled - * @memberof Konva - * @example - * Konva.hitOnDragEnabled = true; - */ - hitOnDragEnabled: false, - /** - * Should we capture touch events and bind them to the touchstart target? That is how it works on DOM elements. - * The case: we touchstart on div1, then touchmove out of that element into another element div2. - * DOM will continue trigger touchmove events on div1 (not div2). Because events are "captured" into initial target. - * By default Konva do not do that and will trigger touchmove on another element, while pointer is moving. - * @property captureTouchEventsEnabled - * @default false - * @name captureTouchEventsEnabled - * @memberof Konva - * @example - * Konva.captureTouchEventsEnabled = true; - */ - captureTouchEventsEnabled: false, - // TODO: move that to stage? - listenClickTap: false, - inDblClickWindow: false, - /** - * Global pixel ratio configuration. KonvaJS automatically detect pixel ratio of current device. - * But you may override such property, if you want to use your value. Set this value before any components initializations. - * @property pixelRatio - * @default undefined - * @name pixelRatio - * @memberof Konva - * @example - * // before any Konva code: - * Konva.pixelRatio = 1; - */ - pixelRatio: (typeof window !== 'undefined' && window.devicePixelRatio) || 1, - /** - * Drag distance property. If you start to drag a node you may want to wait until pointer is moved to some distance from start point, - * only then start dragging. Default is 3px. - * @property dragDistance - * @default 0 - * @memberof Konva - * @example - * Konva.dragDistance = 10; - */ - dragDistance: 3, - /** - * Use degree values for angle properties. You may set this property to false if you want to use radian values. - * @property angleDeg - * @default true - * @memberof Konva - * @example - * node.rotation(45); // 45 degrees - * Konva.angleDeg = false; - * node.rotation(Math.PI / 2); // PI/2 radian - */ - angleDeg: true, - /** - * Show different warnings about errors or wrong API usage - * @property showWarnings - * @default true - * @memberof Konva - * @example - * Konva.showWarnings = false; - */ - showWarnings: true, - /** - * Configure what mouse buttons can be used for drag and drop. - * Default value is [0] - only left mouse button. - * @property dragButtons - * @default true - * @memberof Konva - * @example - * // enable left and right mouse buttons - * Konva.dragButtons = [0, 2]; - */ - dragButtons: [0, 1], - /** - * returns whether or not drag and drop is currently active - * @method - * @memberof Konva - */ - isDragging() { - return Konva$2['DD'].isDragging; - }, - /** - * returns whether or not a drag and drop operation is ready, but may - * not necessarily have started - * @method - * @memberof Konva - */ - isDragReady() { - return !!Konva$2['DD'].node; - }, - // user agent - UA: _parseUA((glob.navigator && glob.navigator.userAgent) || ''), - document: glob.document, - // insert Konva into global namespace (window) - // it is required for npm packages - _injectGlobal(Konva) { - glob.Konva = Konva; - }, - _parseUA, + _global: glob, + version: '@@version', + isBrowser: detectBrowser(), + isUnminified: /param/.test(function (param) { }.toString()), + dblClickWindow: 400, + getAngle(angle) { + return Konva$2.angleDeg ? angle * PI_OVER_180 : angle; + }, + enableTrace: false, + _pointerEventsEnabled: false, + /** + * Should Konva automatically update canvas on any changes. Default is true. + * @property autoDrawEnabled + * @default true + * @name autoDrawEnabled + * @memberof Konva + * @example + * Konva.autoDrawEnabled = true; + */ + autoDrawEnabled: true, + /** + * Should we enable hit detection while dragging? For performance reasons, by default it is false. + * But on some rare cases you want to see hit graph and check intersections. Just set it to true. + * @property hitOnDragEnabled + * @default false + * @name hitOnDragEnabled + * @memberof Konva + * @example + * Konva.hitOnDragEnabled = true; + */ + hitOnDragEnabled: false, + /** + * Should we capture touch events and bind them to the touchstart target? That is how it works on DOM elements. + * The case: we touchstart on div1, then touchmove out of that element into another element div2. + * DOM will continue trigger touchmove events on div1 (not div2). Because events are "captured" into initial target. + * By default Konva do not do that and will trigger touchmove on another element, while pointer is moving. + * @property captureTouchEventsEnabled + * @default false + * @name captureTouchEventsEnabled + * @memberof Konva + * @example + * Konva.captureTouchEventsEnabled = true; + */ + captureTouchEventsEnabled: false, + // TODO: move that to stage? + listenClickTap: false, + inDblClickWindow: false, + /** + * Global pixel ratio configuration. KonvaJS automatically detect pixel ratio of current device. + * But you may override such property, if you want to use your value. Set this value before any components initializations. + * @property pixelRatio + * @default undefined + * @name pixelRatio + * @memberof Konva + * @example + * // before any Konva code: + * Konva.pixelRatio = 1; + */ + pixelRatio: (typeof window !== 'undefined' && window.devicePixelRatio) || 1, + /** + * Drag distance property. If you start to drag a node you may want to wait until pointer is moved to some distance from start point, + * only then start dragging. Default is 3px. + * @property dragDistance + * @default 0 + * @memberof Konva + * @example + * Konva.dragDistance = 10; + */ + dragDistance: 3, + /** + * Use degree values for angle properties. You may set this property to false if you want to use radian values. + * @property angleDeg + * @default true + * @memberof Konva + * @example + * node.rotation(45); // 45 degrees + * Konva.angleDeg = false; + * node.rotation(Math.PI / 2); // PI/2 radian + */ + angleDeg: true, + /** + * Show different warnings about errors or wrong API usage + * @property showWarnings + * @default true + * @memberof Konva + * @example + * Konva.showWarnings = false; + */ + showWarnings: true, + /** + * Configure what mouse buttons can be used for drag and drop. + * Default value is [0] - only left mouse button. + * @property dragButtons + * @default true + * @memberof Konva + * @example + * // enable left and right mouse buttons + * Konva.dragButtons = [0, 2]; + */ + dragButtons: [0, 1], + /** + * returns whether or not drag and drop is currently active + * @method + * @memberof Konva + */ + isDragging() { + return Konva$2['DD'].isDragging; + }, + /** + * returns whether or not a drag and drop operation is ready, but may + * not necessarily have started + * @method + * @memberof Konva + */ + isDragReady() { + return !!Konva$2['DD'].node; + }, + // user agent + document: glob.document, + // insert Konva into global namespace (window) + // it is required for npm packages + _injectGlobal(Konva) { + glob.Konva = Konva; + }, }; - const _NODES_REGISTRY = {}; const _registerNode = (NodeClass) => { - _NODES_REGISTRY[NodeClass.prototype.getClassName()] = NodeClass; - Konva$2[NodeClass.prototype.getClassName()] = NodeClass; + Konva$2[NodeClass.prototype.getClassName()] = NodeClass; }; - Konva$2._injectGlobal(Konva$2); - + Konva$2._injectGlobal(Konva$2); + /* * Last updated November 2011 * By Simon Sarris @@ -236,258 +188,241 @@ * @memberof Konva */ class Transform { - constructor(m = [1, 0, 0, 1, 0, 0]) { - this.dirty = false; - this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0]; - } - reset() { - this.m[0] = 1; - this.m[1] = 0; - this.m[2] = 0; - this.m[3] = 1; - this.m[4] = 0; - this.m[5] = 0; - } - /** - * Copy Konva.Transform object - * @method - * @name Konva.Transform#copy - * @returns {Konva.Transform} - * @example - * const tr = shape.getTransform().copy() - */ - copy() { - return new Transform(this.m); - } - copyInto(tr) { - tr.m[0] = this.m[0]; - tr.m[1] = this.m[1]; - tr.m[2] = this.m[2]; - tr.m[3] = this.m[3]; - tr.m[4] = this.m[4]; - tr.m[5] = this.m[5]; - } - /** - * Transform point - * @method - * @name Konva.Transform#point - * @param {Object} point 2D point(x, y) - * @returns {Object} 2D point(x, y) - */ - point(point) { - var m = this.m; - return { - x: m[0] * point.x + m[2] * point.y + m[4], - y: m[1] * point.x + m[3] * point.y + m[5], - }; - } - /** - * Apply translation - * @method - * @name Konva.Transform#translate - * @param {Number} x - * @param {Number} y - * @returns {Konva.Transform} - */ - translate(x, y) { - this.m[4] += this.m[0] * x + this.m[2] * y; - this.m[5] += this.m[1] * x + this.m[3] * y; - return this; - } - /** - * Apply scale - * @method - * @name Konva.Transform#scale - * @param {Number} sx - * @param {Number} sy - * @returns {Konva.Transform} - */ - scale(sx, sy) { - this.m[0] *= sx; - this.m[1] *= sx; - this.m[2] *= sy; - this.m[3] *= sy; - return this; - } - /** - * Apply rotation - * @method - * @name Konva.Transform#rotate - * @param {Number} rad Angle in radians - * @returns {Konva.Transform} - */ - rotate(rad) { - var c = Math.cos(rad); - var s = Math.sin(rad); - var m11 = this.m[0] * c + this.m[2] * s; - var m12 = this.m[1] * c + this.m[3] * s; - var m21 = this.m[0] * -s + this.m[2] * c; - var m22 = this.m[1] * -s + this.m[3] * c; - this.m[0] = m11; - this.m[1] = m12; - this.m[2] = m21; - this.m[3] = m22; - return this; - } - /** - * Returns the translation - * @method - * @name Konva.Transform#getTranslation - * @returns {Object} 2D point(x, y) - */ - getTranslation() { - return { - x: this.m[4], - y: this.m[5], - }; - } - /** - * Apply skew - * @method - * @name Konva.Transform#skew - * @param {Number} sx - * @param {Number} sy - * @returns {Konva.Transform} - */ - skew(sx, sy) { - var m11 = this.m[0] + this.m[2] * sy; - var m12 = this.m[1] + this.m[3] * sy; - var m21 = this.m[2] + this.m[0] * sx; - var m22 = this.m[3] + this.m[1] * sx; - this.m[0] = m11; - this.m[1] = m12; - this.m[2] = m21; - this.m[3] = m22; - return this; - } - /** - * Transform multiplication - * @method - * @name Konva.Transform#multiply - * @param {Konva.Transform} matrix - * @returns {Konva.Transform} - */ - multiply(matrix) { - var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1]; - var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1]; - var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3]; - var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3]; - var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4]; - var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5]; - this.m[0] = m11; - this.m[1] = m12; - this.m[2] = m21; - this.m[3] = m22; - this.m[4] = dx; - this.m[5] = dy; - return this; - } - /** - * Invert the matrix - * @method - * @name Konva.Transform#invert - * @returns {Konva.Transform} - */ - invert() { - var d = 1 / (this.m[0] * this.m[3] - this.m[1] * this.m[2]); - var m0 = this.m[3] * d; - var m1 = -this.m[1] * d; - var m2 = -this.m[2] * d; - var m3 = this.m[0] * d; - var m4 = d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]); - var m5 = d * (this.m[1] * this.m[4] - this.m[0] * this.m[5]); - this.m[0] = m0; - this.m[1] = m1; - this.m[2] = m2; - this.m[3] = m3; - this.m[4] = m4; - this.m[5] = m5; - return this; - } - /** - * return matrix - * @method - * @name Konva.Transform#getMatrix - */ - getMatrix() { - return this.m; - } - /** - * set to absolute position via translation - * @method - * @name Konva.Transform#setAbsolutePosition - * @returns {Konva.Transform} - * @author ericdrowell - */ - setAbsolutePosition(x, y) { - var m0 = this.m[0], - m1 = this.m[1], - m2 = this.m[2], - m3 = this.m[3], - m4 = this.m[4], - m5 = this.m[5], - yt = (m0 * (y - m5) - m1 * (x - m4)) / (m0 * m3 - m1 * m2), - xt = (x - m4 - m2 * yt) / m0; - return this.translate(xt, yt); - } - /** - * convert transformation matrix back into node's attributes - * @method - * @name Konva.Transform#decompose - * @returns {Konva.Transform} - */ - decompose() { - var a = this.m[0]; - var b = this.m[1]; - var c = this.m[2]; - var d = this.m[3]; - var e = this.m[4]; - var f = this.m[5]; - var delta = a * d - b * c; - let result = { - x: e, - y: f, - rotation: 0, - scaleX: 0, - scaleY: 0, - skewX: 0, - skewY: 0, - }; - // Apply the QR-like decomposition. - if (a != 0 || b != 0) { - var r = Math.sqrt(a * a + b * b); - result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r); - result.scaleX = r; - result.scaleY = delta / r; - result.skewX = (a * c + b * d) / delta; - result.skewY = 0; - } else if (c != 0 || d != 0) { - var s = Math.sqrt(c * c + d * d); - result.rotation = - Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s)); - result.scaleX = delta / s; - result.scaleY = s; - result.skewX = 0; - result.skewY = (a * c + b * d) / delta; - } else; - result.rotation = Util._getRotation(result.rotation); - return result; - } + constructor(m = [1, 0, 0, 1, 0, 0]) { + this.dirty = false; + this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0]; + } + reset() { + this.m[0] = 1; + this.m[1] = 0; + this.m[2] = 0; + this.m[3] = 1; + this.m[4] = 0; + this.m[5] = 0; + } + /** + * Copy Konva.Transform object + * @method + * @name Konva.Transform#copy + * @returns {Konva.Transform} + * @example + * const tr = shape.getTransform().copy() + */ + copy() { + return new Transform(this.m); + } + copyInto(tr) { + tr.m[0] = this.m[0]; + tr.m[1] = this.m[1]; + tr.m[2] = this.m[2]; + tr.m[3] = this.m[3]; + tr.m[4] = this.m[4]; + tr.m[5] = this.m[5]; + } + /** + * Transform point + * @method + * @name Konva.Transform#point + * @param {Object} point 2D point(x, y) + * @returns {Object} 2D point(x, y) + */ + point(point) { + var m = this.m; + return { + x: m[0] * point.x + m[2] * point.y + m[4], + y: m[1] * point.x + m[3] * point.y + m[5], + }; + } + /** + * Apply translation + * @method + * @name Konva.Transform#translate + * @param {Number} x + * @param {Number} y + * @returns {Konva.Transform} + */ + translate(x, y) { + this.m[4] += this.m[0] * x + this.m[2] * y; + this.m[5] += this.m[1] * x + this.m[3] * y; + return this; + } + /** + * Apply scale + * @method + * @name Konva.Transform#scale + * @param {Number} sx + * @param {Number} sy + * @returns {Konva.Transform} + */ + scale(sx, sy) { + this.m[0] *= sx; + this.m[1] *= sx; + this.m[2] *= sy; + this.m[3] *= sy; + return this; + } + /** + * Apply rotation + * @method + * @name Konva.Transform#rotate + * @param {Number} rad Angle in radians + * @returns {Konva.Transform} + */ + rotate(rad) { + var c = Math.cos(rad); + var s = Math.sin(rad); + var m11 = this.m[0] * c + this.m[2] * s; + var m12 = this.m[1] * c + this.m[3] * s; + var m21 = this.m[0] * -s + this.m[2] * c; + var m22 = this.m[1] * -s + this.m[3] * c; + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + return this; + } + /** + * Returns the translation + * @method + * @name Konva.Transform#getTranslation + * @returns {Object} 2D point(x, y) + */ + getTranslation() { + return { + x: this.m[4], + y: this.m[5], + }; + } + /** + * Apply skew + * @method + * @name Konva.Transform#skew + * @param {Number} sx + * @param {Number} sy + * @returns {Konva.Transform} + */ + skew(sx, sy) { + var m11 = this.m[0] + this.m[2] * sy; + var m12 = this.m[1] + this.m[3] * sy; + var m21 = this.m[2] + this.m[0] * sx; + var m22 = this.m[3] + this.m[1] * sx; + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + return this; + } + /** + * Transform multiplication + * @method + * @name Konva.Transform#multiply + * @param {Konva.Transform} matrix + * @returns {Konva.Transform} + */ + multiply(matrix) { + var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1]; + var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1]; + var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3]; + var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3]; + var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4]; + var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5]; + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + this.m[4] = dx; + this.m[5] = dy; + return this; + } + /** + * Invert the matrix + * @method + * @name Konva.Transform#invert + * @returns {Konva.Transform} + */ + invert() { + var d = 1 / (this.m[0] * this.m[3] - this.m[1] * this.m[2]); + var m0 = this.m[3] * d; + var m1 = -this.m[1] * d; + var m2 = -this.m[2] * d; + var m3 = this.m[0] * d; + var m4 = d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]); + var m5 = d * (this.m[1] * this.m[4] - this.m[0] * this.m[5]); + this.m[0] = m0; + this.m[1] = m1; + this.m[2] = m2; + this.m[3] = m3; + this.m[4] = m4; + this.m[5] = m5; + return this; + } + /** + * return matrix + * @method + * @name Konva.Transform#getMatrix + */ + getMatrix() { + return this.m; + } + /** + * set to absolute position via translation + * @method + * @name Konva.Transform#setAbsolutePosition + * @returns {Konva.Transform} + * @author ericdrowell + */ + setAbsolutePosition(x, y) { + var m0 = this.m[0], m1 = this.m[1], m2 = this.m[2], m3 = this.m[3], m4 = this.m[4], m5 = this.m[5], yt = (m0 * (y - m5) - m1 * (x - m4)) / (m0 * m3 - m1 * m2), xt = (x - m4 - m2 * yt) / m0; + return this.translate(xt, yt); + } + /** + * convert transformation matrix back into node's attributes + * @method + * @name Konva.Transform#decompose + * @returns {Konva.Transform} + */ + decompose() { + var a = this.m[0]; + var b = this.m[1]; + var c = this.m[2]; + var d = this.m[3]; + var e = this.m[4]; + var f = this.m[5]; + var delta = a * d - b * c; + let result = { + x: e, + y: f, + rotation: 0, + scaleX: 0, + scaleY: 0, + skewX: 0, + skewY: 0, + }; + // Apply the QR-like decomposition. + if (a != 0 || b != 0) { + var r = Math.sqrt(a * a + b * b); + result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r); + result.scaleX = r; + result.scaleY = delta / r; + result.skewX = (a * c + b * d) / delta; + result.skewY = 0; + } + else if (c != 0 || d != 0) { + var s = Math.sqrt(c * c + d * d); + result.rotation = + Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s)); + result.scaleX = delta / s; + result.scaleY = s; + result.skewX = 0; + result.skewY = (a * c + b * d) / delta; + } + else ; + result.rotation = Util._getRotation(result.rotation); + return result; + } } // CONSTANTS - var OBJECT_ARRAY = '[object Array]', - OBJECT_NUMBER = '[object Number]', - OBJECT_STRING = '[object String]', - OBJECT_BOOLEAN = '[object Boolean]', - PI_OVER_DEG180 = Math.PI / 180, - DEG180_OVER_PI = 180 / Math.PI, - HASH$1 = '#', - EMPTY_STRING$2 = '', - ZERO = '0', - KONVA_WARNING = 'Konva warning: ', - KONVA_ERROR = 'Konva error: ', - RGB_PAREN = 'rgb(', - COLORS = { + var OBJECT_ARRAY = '[object Array]', OBJECT_NUMBER = '[object Number]', OBJECT_STRING = '[object String]', OBJECT_BOOLEAN = '[object Boolean]', PI_OVER_DEG180 = Math.PI / 180, DEG180_OVER_PI = 180 / Math.PI, HASH$1 = '#', EMPTY_STRING$2 = '', ZERO = '0', KONVA_WARNING = 'Konva warning: ', KONVA_ERROR = 'Konva error: ', RGB_PAREN = 'rgb(', COLORS = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], @@ -637,894 +572,830 @@ whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 5], - }, - RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/, - animQueue = []; + }, RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/, animQueue = []; /** * @namespace Util * @memberof Konva */ const Util = { - /* - * cherry-picked utilities from underscore.js - */ - _isElement(obj) { - return !!(obj && obj.nodeType == 1); - }, - _isFunction(obj) { - return !!(obj && obj.constructor && obj.call && obj.apply); - }, - _isPlainObject(obj) { - return !!obj && obj.constructor === Object; - }, - _isArray(obj) { - return Object.prototype.toString.call(obj) === OBJECT_ARRAY; - }, - _isNumber(obj) { - return ( - Object.prototype.toString.call(obj) === OBJECT_NUMBER && - !isNaN(obj) && - isFinite(obj) - ); - }, - _isString(obj) { - return Object.prototype.toString.call(obj) === OBJECT_STRING; - }, - _isBoolean(obj) { - return Object.prototype.toString.call(obj) === OBJECT_BOOLEAN; - }, - // arrays are objects too - isObject(val) { - return val instanceof Object; - }, - isValidSelector(selector) { - if (typeof selector !== 'string') { - return false; - } - var firstChar = selector[0]; - return ( - firstChar === '#' || - firstChar === '.' || - firstChar === firstChar.toUpperCase() - ); - }, - _sign(number) { - if (number === 0) { - // that is not what sign usually returns - // but that is what we need - return 1; - } - if (number > 0) { - return 1; - } else { - return -1; - } - }, - requestAnimFrame(callback) { - animQueue.push(callback); - const req = - (typeof requestAnimationFrame !== 'undefined' && - requestAnimationFrame) || - function (f) { - setTimeout(f, 60); - }; - if (animQueue.length === 1) { - req(function () { - const queue = animQueue; - animQueue = []; - queue.forEach(function (cb) { - cb(); - }); - }); - } - }, - createCanvasElement() { - var canvas = document.createElement('canvas'); - // on some environments canvas.style is readonly - try { - canvas.style = canvas.style || {}; - } catch (e) {} - return canvas; - }, - createImageElement() { - return document.createElement('img'); - }, - _isInDocument(el) { - while ((el = el.parentNode)) { - if (el == document) { - return true; - } - } - return false; - }, - _simplifyArray(arr) { - var retArr = [], - len = arr.length, - util = Util, - n, - val; - for (n = 0; n < len; n++) { - val = arr[n]; - if (util._isNumber(val)) { - val = Math.round(val * 1000) / 1000; - } else if (!util._isString(val)) { - val = val + ''; - } - retArr.push(val); - } - return retArr; - }, - /* - * arg can be an image object or image data - */ - _urlToImage(url, callback) { - // if arg is a string, then it's a data url - var imageObj = Util.createImageElement(); - imageObj.onload = function () { - callback(imageObj); - }; - imageObj.src = url; - }, - _rgbToHex(r, g, b) { - return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); - }, - _hexToRgb(hex) { - hex = hex.replace(HASH$1, EMPTY_STRING$2); - var bigint = parseInt(hex, 16); - return { - r: (bigint >> 16) & 255, - g: (bigint >> 8) & 255, - b: bigint & 255, - }; - }, - /** - * return random hex color - * @method - * @memberof Konva.Util - * @example - * shape.fill(Konva.Util.getRandomColor()); - */ - getRandomColor() { - var randColor = ((Math.random() * 0xffffff) << 0).toString(16); - while (randColor.length < 6) { - randColor = ZERO + randColor; - } - return HASH$1 + randColor; - }, - get(val, def) { - if (val === undefined) { - return def; - } else { - return val; - } - }, - /** - * get RGB components of a color - * @method - * @memberof Konva.Util - * @param {String} color - * @example - * // each of the following examples return {r:0, g:0, b:255} - * var rgb = Konva.Util.getRGB('blue'); - * var rgb = Konva.Util.getRGB('#0000ff'); - * var rgb = Konva.Util.getRGB('rgb(0,0,255)'); - */ - getRGB(color) { - var rgb; - // color string - if (color in COLORS) { - rgb = COLORS[color]; - return { - r: rgb[0], - g: rgb[1], - b: rgb[2], - }; - } else if (color[0] === HASH$1) { - // hex - return this._hexToRgb(color.substring(1)); - } else if (color.substr(0, 4) === RGB_PAREN) { - // rgb string - rgb = RGB_REGEX.exec(color.replace(/ /g, '')); - return { - r: parseInt(rgb[1], 10), - g: parseInt(rgb[2], 10), - b: parseInt(rgb[3], 10), - }; - } else { - // default - return { - r: 0, - g: 0, - b: 0, - }; - } - }, - // convert any color string to RGBA object - // from https://github.com/component/color-parser - colorToRGBA(str) { - str = str || 'black'; - return ( - Util._namedColorToRBA(str) || - Util._hex3ColorToRGBA(str) || - Util._hex6ColorToRGBA(str) || - Util._rgbColorToRGBA(str) || - Util._rgbaColorToRGBA(str) || - Util._hslColorToRGBA(str) - ); - }, - // Parse named css color. Like "green" - _namedColorToRBA(str) { - var c = COLORS[str.toLowerCase()]; - if (!c) { - return null; - } - return { - r: c[0], - g: c[1], - b: c[2], - a: 1, - }; - }, - // Parse rgb(n, n, n) - _rgbColorToRGBA(str) { - if (str.indexOf('rgb(') === 0) { - str = str.match(/rgb\(([^)]+)\)/)[1]; - var parts = str.split(/ *, */).map(Number); - return { - r: parts[0], - g: parts[1], - b: parts[2], - a: 1, - }; - } - }, - // Parse rgba(n, n, n, n) - _rgbaColorToRGBA(str) { - if (str.indexOf('rgba(') === 0) { - str = str.match(/rgba\(([^)]+)\)/)[1]; - var parts = str.split(/ *, */).map(Number); - return { - r: parts[0], - g: parts[1], - b: parts[2], - a: parts[3], - }; - } - }, - // Parse #nnnnnn - _hex6ColorToRGBA(str) { - if (str[0] === '#' && str.length === 7) { - return { - r: parseInt(str.slice(1, 3), 16), - g: parseInt(str.slice(3, 5), 16), - b: parseInt(str.slice(5, 7), 16), - a: 1, - }; - } - }, - // Parse #nnn - _hex3ColorToRGBA(str) { - if (str[0] === '#' && str.length === 4) { - return { - r: parseInt(str[1] + str[1], 16), - g: parseInt(str[2] + str[2], 16), - b: parseInt(str[3] + str[3], 16), - a: 1, - }; - } - }, - // Code adapted from https://github.com/Qix-/color-convert/blob/master/conversions.js#L244 - _hslColorToRGBA(str) { - // Check hsl() format - if (/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(str)) { - // Extract h, s, l - const [_, ...hsl] = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(str); - const h = Number(hsl[0]) / 360; - const s = Number(hsl[1]) / 100; - const l = Number(hsl[2]) / 100; - let t2; - let t3; - let val; - if (s === 0) { - val = l * 255; - return { - r: Math.round(val), - g: Math.round(val), - b: Math.round(val), - a: 1, + /* + * cherry-picked utilities from underscore.js + */ + _isElement(obj) { + return !!(obj && obj.nodeType == 1); + }, + _isFunction(obj) { + return !!(obj && obj.constructor && obj.call && obj.apply); + }, + _isPlainObject(obj) { + return !!obj && obj.constructor === Object; + }, + _isArray(obj) { + return Object.prototype.toString.call(obj) === OBJECT_ARRAY; + }, + _isNumber(obj) { + return (Object.prototype.toString.call(obj) === OBJECT_NUMBER && + !isNaN(obj) && + isFinite(obj)); + }, + _isString(obj) { + return Object.prototype.toString.call(obj) === OBJECT_STRING; + }, + _isBoolean(obj) { + return Object.prototype.toString.call(obj) === OBJECT_BOOLEAN; + }, + // arrays are objects too + isObject(val) { + return val instanceof Object; + }, + isValidSelector(selector) { + if (typeof selector !== 'string') { + return false; + } + var firstChar = selector[0]; + return (firstChar === '#' || + firstChar === '.' || + firstChar === firstChar.toUpperCase()); + }, + _sign(number) { + if (number === 0) { + // that is not what sign usually returns + // but that is what we need + return 1; + } + if (number > 0) { + return 1; + } + else { + return -1; + } + }, + requestAnimFrame(callback) { + animQueue.push(callback); + const req = (typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame) || + function (f) { + setTimeout(f, 60); + }; + if (animQueue.length === 1) { + req(function () { + const queue = animQueue; + animQueue = []; + queue.forEach(function (cb) { + cb(); + }); + }); + } + }, + createCanvasElement() { + var canvas = document.createElement('canvas'); + // on some environments canvas.style is readonly + try { + canvas.style = canvas.style || {}; + } + catch (e) { } + return canvas; + }, + createImageElement() { + return document.createElement('img'); + }, + _isInDocument(el) { + while ((el = el.parentNode)) { + if (el == document) { + return true; + } + } + return false; + }, + _simplifyArray(arr) { + var retArr = [], len = arr.length, util = Util, n, val; + for (n = 0; n < len; n++) { + val = arr[n]; + if (util._isNumber(val)) { + val = Math.round(val * 1000) / 1000; + } + else if (!util._isString(val)) { + val = val + ''; + } + retArr.push(val); + } + return retArr; + }, + /* + * arg can be an image object or image data + */ + _urlToImage(url, callback) { + // if arg is a string, then it's a data url + var imageObj = Util.createImageElement(); + imageObj.onload = function () { + callback(imageObj); }; - } - if (l < 0.5) { - t2 = l * (1 + s); - } else { - t2 = l + s - l * s; - } - const t1 = 2 * l - t2; - const rgb = [0, 0, 0]; - for (let i = 0; i < 3; i++) { - t3 = h + (1 / 3) * -(i - 1); - if (t3 < 0) { - t3++; + imageObj.src = url; + }, + _rgbToHex(r, g, b) { + return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); + }, + _hexToRgb(hex) { + hex = hex.replace(HASH$1, EMPTY_STRING$2); + var bigint = parseInt(hex, 16); + return { + r: (bigint >> 16) & 255, + g: (bigint >> 8) & 255, + b: bigint & 255, + }; + }, + /** + * return random hex color + * @method + * @memberof Konva.Util + * @example + * shape.fill(Konva.Util.getRandomColor()); + */ + getRandomColor() { + var randColor = ((Math.random() * 0xffffff) << 0).toString(16); + while (randColor.length < 6) { + randColor = ZERO + randColor; } - if (t3 > 1) { - t3--; + return HASH$1 + randColor; + }, + get(val, def) { + if (val === undefined) { + return def; } - if (6 * t3 < 1) { - val = t1 + (t2 - t1) * 6 * t3; - } else if (2 * t3 < 1) { - val = t2; - } else if (3 * t3 < 2) { - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; - } else { - val = t1; + else { + return val; } - rgb[i] = val * 255; - } - return { - r: Math.round(rgb[0]), - g: Math.round(rgb[1]), - b: Math.round(rgb[2]), - a: 1, - }; - } - }, - /** - * check intersection of two client rectangles - * @method - * @memberof Konva.Util - * @param {Object} r1 - { x, y, width, height } client rectangle - * @param {Object} r2 - { x, y, width, height } client rectangle - * @example - * const overlapping = Konva.Util.haveIntersection(shape1.getClientRect(), shape2.getClientRect()); - */ - haveIntersection(r1, r2) { - return !( - r2.x > r1.x + r1.width || - r2.x + r2.width < r1.x || - r2.y > r1.y + r1.height || - r2.y + r2.height < r1.y - ); - }, - cloneObject(obj) { - var retObj = {}; - for (var key in obj) { - if (this._isPlainObject(obj[key])) { - retObj[key] = this.cloneObject(obj[key]); - } else if (this._isArray(obj[key])) { - retObj[key] = this.cloneArray(obj[key]); - } else { - retObj[key] = obj[key]; - } - } - return retObj; - }, - cloneArray(arr) { - return arr.slice(0); - }, - _degToRad(deg) { - return deg * PI_OVER_DEG180; - }, - _radToDeg(rad) { - return rad * DEG180_OVER_PI; - }, - _getRotation(radians) { - return Konva$2.angleDeg ? Util._radToDeg(radians) : radians; - }, - _capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); - }, - throw(str) { - throw new Error(KONVA_ERROR + str); - }, - error(str) { - console.error(KONVA_ERROR + str); - }, - warn(str) { - if (!Konva$2.showWarnings) { - return; - } - console.warn(KONVA_WARNING + str); - }, - extend(child, parent) { - function Ctor() { - this.constructor = child; - } - Ctor.prototype = parent.prototype; - var oldProto = child.prototype; - child.prototype = new Ctor(); - for (var key in oldProto) { - if (oldProto.hasOwnProperty(key)) { - child.prototype[key] = oldProto[key]; - } - } - child.__super__ = parent.prototype; - // create reference to parent - child.super = parent; - }, - _getControlPoints(x0, y0, x1, y1, x2, y2, t) { - var d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)), - d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), - fa = (t * d01) / (d01 + d12), - fb = (t * d12) / (d01 + d12), - p1x = x1 - fa * (x2 - x0), - p1y = y1 - fa * (y2 - y0), - p2x = x1 + fb * (x2 - x0), - p2y = y1 + fb * (y2 - y0); - return [p1x, p1y, p2x, p2y]; - }, - _expandPoints(p, tension) { - var len = p.length, - allPoints = [], - n, - cp; - for (n = 2; n < len - 2; n += 2) { - cp = Util._getControlPoints( - p[n - 2], - p[n - 1], - p[n], - p[n + 1], - p[n + 2], - p[n + 3], - tension - ); - if (isNaN(cp[0])) { - continue; - } - allPoints.push(cp[0]); - allPoints.push(cp[1]); - allPoints.push(p[n]); - allPoints.push(p[n + 1]); - allPoints.push(cp[2]); - allPoints.push(cp[3]); - } - return allPoints; - }, - each(obj, func) { - for (var key in obj) { - func(key, obj[key]); - } - }, - _inRange(val, left, right) { - return left <= val && val < right; - }, - _getProjectionToSegment(x1, y1, x2, y2, x3, y3) { - var x, y, dist; - var pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); - if (pd2 == 0) { - x = x1; - y = y1; - dist = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2); - } else { - var u = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / pd2; - if (u < 0) { - x = x1; - y = y1; - dist = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3); - } else if (u > 1.0) { - x = x2; - y = y2; - dist = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3); - } else { - x = x1 + u * (x2 - x1); - y = y1 + u * (y2 - y1); - dist = (x - x3) * (x - x3) + (y - y3) * (y - y3); - } - } - return [x, y, dist]; - }, - // line as array of points. - // line might be closed - _getProjectionToLine(pt, line, isClosed) { - var pc = Util.cloneObject(pt); - var dist = Number.MAX_VALUE; - line.forEach(function (p1, i) { - if (!isClosed && i === line.length - 1) { - return; - } - var p2 = line[(i + 1) % line.length]; - var proj = Util._getProjectionToSegment( - p1.x, - p1.y, - p2.x, - p2.y, - pt.x, - pt.y - ); - var px = proj[0], - py = proj[1], - pdist = proj[2]; - if (pdist < dist) { - pc.x = px; - pc.y = py; - dist = pdist; - } - }); - return pc; - }, - _prepareArrayForTween(startArray, endArray, isClosed) { - var n, - start = [], - end = []; - if (startArray.length > endArray.length) { - var temp = endArray; - endArray = startArray; - startArray = temp; - } - for (n = 0; n < startArray.length; n += 2) { - start.push({ - x: startArray[n], - y: startArray[n + 1], - }); - } - for (n = 0; n < endArray.length; n += 2) { - end.push({ - x: endArray[n], - y: endArray[n + 1], - }); - } - var newStart = []; - end.forEach(function (point) { - var pr = Util._getProjectionToLine(point, start, isClosed); - newStart.push(pr.x); - newStart.push(pr.y); - }); - return newStart; - }, - _prepareToStringify(obj) { - var desc; - obj.visitedByCircularReferenceRemoval = true; - for (var key in obj) { - if ( - !(obj.hasOwnProperty(key) && obj[key] && typeof obj[key] == 'object') - ) { - continue; - } - desc = Object.getOwnPropertyDescriptor(obj, key); - if ( - obj[key].visitedByCircularReferenceRemoval || - Util._isElement(obj[key]) - ) { - if (desc.configurable) { - delete obj[key]; - } else { - return null; + }, + /** + * get RGB components of a color + * @method + * @memberof Konva.Util + * @param {String} color + * @example + * // each of the following examples return {r:0, g:0, b:255} + * var rgb = Konva.Util.getRGB('blue'); + * var rgb = Konva.Util.getRGB('#0000ff'); + * var rgb = Konva.Util.getRGB('rgb(0,0,255)'); + */ + getRGB(color) { + var rgb; + // color string + if (color in COLORS) { + rgb = COLORS[color]; + return { + r: rgb[0], + g: rgb[1], + b: rgb[2], + }; } - } else if (Util._prepareToStringify(obj[key]) === null) { - if (desc.configurable) { - delete obj[key]; - } else { - return null; + else if (color[0] === HASH$1) { + // hex + return this._hexToRgb(color.substring(1)); } - } - } - delete obj.visitedByCircularReferenceRemoval; - return obj; - }, - // very simplified version of Object.assign - _assign(target, source) { - for (var key in source) { - target[key] = source[key]; - } - return target; - }, - _getFirstPointerId(evt) { - if (!evt.touches) { - // fake id for mouse - return 999; - } else { - return evt.changedTouches[0].identifier; - } - }, - }; - + else if (color.substr(0, 4) === RGB_PAREN) { + // rgb string + rgb = RGB_REGEX.exec(color.replace(/ /g, '')); + return { + r: parseInt(rgb[1], 10), + g: parseInt(rgb[2], 10), + b: parseInt(rgb[3], 10), + }; + } + else { + // default + return { + r: 0, + g: 0, + b: 0, + }; + } + }, + // convert any color string to RGBA object + // from https://github.com/component/color-parser + colorToRGBA(str) { + str = str || 'black'; + return (Util._namedColorToRBA(str) || + Util._hex3ColorToRGBA(str) || + Util._hex6ColorToRGBA(str) || + Util._rgbColorToRGBA(str) || + Util._rgbaColorToRGBA(str) || + Util._hslColorToRGBA(str)); + }, + // Parse named css color. Like "green" + _namedColorToRBA(str) { + var c = COLORS[str.toLowerCase()]; + if (!c) { + return null; + } + return { + r: c[0], + g: c[1], + b: c[2], + a: 1, + }; + }, + // Parse rgb(n, n, n) + _rgbColorToRGBA(str) { + if (str.indexOf('rgb(') === 0) { + str = str.match(/rgb\(([^)]+)\)/)[1]; + var parts = str.split(/ *, */).map(Number); + return { + r: parts[0], + g: parts[1], + b: parts[2], + a: 1, + }; + } + }, + // Parse rgba(n, n, n, n) + _rgbaColorToRGBA(str) { + if (str.indexOf('rgba(') === 0) { + str = str.match(/rgba\(([^)]+)\)/)[1]; + var parts = str.split(/ *, */).map(Number); + return { + r: parts[0], + g: parts[1], + b: parts[2], + a: parts[3], + }; + } + }, + // Parse #nnnnnn + _hex6ColorToRGBA(str) { + if (str[0] === '#' && str.length === 7) { + return { + r: parseInt(str.slice(1, 3), 16), + g: parseInt(str.slice(3, 5), 16), + b: parseInt(str.slice(5, 7), 16), + a: 1, + }; + } + }, + // Parse #nnn + _hex3ColorToRGBA(str) { + if (str[0] === '#' && str.length === 4) { + return { + r: parseInt(str[1] + str[1], 16), + g: parseInt(str[2] + str[2], 16), + b: parseInt(str[3] + str[3], 16), + a: 1, + }; + } + }, + // Code adapted from https://github.com/Qix-/color-convert/blob/master/conversions.js#L244 + _hslColorToRGBA(str) { + // Check hsl() format + if (/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(str)) { + // Extract h, s, l + const [_, ...hsl] = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(str); + const h = Number(hsl[0]) / 360; + const s = Number(hsl[1]) / 100; + const l = Number(hsl[2]) / 100; + let t2; + let t3; + let val; + if (s === 0) { + val = l * 255; + return { + r: Math.round(val), + g: Math.round(val), + b: Math.round(val), + a: 1, + }; + } + if (l < 0.5) { + t2 = l * (1 + s); + } + else { + t2 = l + s - l * s; + } + const t1 = 2 * l - t2; + const rgb = [0, 0, 0]; + for (let i = 0; i < 3; i++) { + t3 = h + (1 / 3) * -(i - 1); + if (t3 < 0) { + t3++; + } + if (t3 > 1) { + t3--; + } + if (6 * t3 < 1) { + val = t1 + (t2 - t1) * 6 * t3; + } + else if (2 * t3 < 1) { + val = t2; + } + else if (3 * t3 < 2) { + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + } + else { + val = t1; + } + rgb[i] = val * 255; + } + return { + r: Math.round(rgb[0]), + g: Math.round(rgb[1]), + b: Math.round(rgb[2]), + a: 1, + }; + } + }, + /** + * check intersection of two client rectangles + * @method + * @memberof Konva.Util + * @param {Object} r1 - { x, y, width, height } client rectangle + * @param {Object} r2 - { x, y, width, height } client rectangle + * @example + * const overlapping = Konva.Util.haveIntersection(shape1.getClientRect(), shape2.getClientRect()); + */ + haveIntersection(r1, r2) { + return !(r2.x > r1.x + r1.width || + r2.x + r2.width < r1.x || + r2.y > r1.y + r1.height || + r2.y + r2.height < r1.y); + }, + cloneObject(obj) { + var retObj = {}; + for (var key in obj) { + if (this._isPlainObject(obj[key])) { + retObj[key] = this.cloneObject(obj[key]); + } + else if (this._isArray(obj[key])) { + retObj[key] = this.cloneArray(obj[key]); + } + else { + retObj[key] = obj[key]; + } + } + return retObj; + }, + cloneArray(arr) { + return arr.slice(0); + }, + _degToRad(deg) { + return deg * PI_OVER_DEG180; + }, + _radToDeg(rad) { + return rad * DEG180_OVER_PI; + }, + _getRotation(radians) { + return Konva$2.angleDeg ? Util._radToDeg(radians) : radians; + }, + _capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + }, + throw(str) { + throw new Error(KONVA_ERROR + str); + }, + error(str) { + console.error(KONVA_ERROR + str); + }, + warn(str) { + if (!Konva$2.showWarnings) { + return; + } + console.warn(KONVA_WARNING + str); + }, + extend(child, parent) { + function Ctor() { + this.constructor = child; + } + Ctor.prototype = parent.prototype; + var oldProto = child.prototype; + child.prototype = new Ctor(); + for (var key in oldProto) { + if (oldProto.hasOwnProperty(key)) { + child.prototype[key] = oldProto[key]; + } + } + child.__super__ = parent.prototype; + // create reference to parent + child.super = parent; + }, + _getControlPoints(x0, y0, x1, y1, x2, y2, t) { + var d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)), d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), fa = (t * d01) / (d01 + d12), fb = (t * d12) / (d01 + d12), p1x = x1 - fa * (x2 - x0), p1y = y1 - fa * (y2 - y0), p2x = x1 + fb * (x2 - x0), p2y = y1 + fb * (y2 - y0); + return [p1x, p1y, p2x, p2y]; + }, + _expandPoints(p, tension) { + var len = p.length, allPoints = [], n, cp; + for (n = 2; n < len - 2; n += 2) { + cp = Util._getControlPoints(p[n - 2], p[n - 1], p[n], p[n + 1], p[n + 2], p[n + 3], tension); + if (isNaN(cp[0])) { + continue; + } + allPoints.push(cp[0]); + allPoints.push(cp[1]); + allPoints.push(p[n]); + allPoints.push(p[n + 1]); + allPoints.push(cp[2]); + allPoints.push(cp[3]); + } + return allPoints; + }, + each(obj, func) { + for (var key in obj) { + func(key, obj[key]); + } + }, + _inRange(val, left, right) { + return left <= val && val < right; + }, + _getProjectionToSegment(x1, y1, x2, y2, x3, y3) { + var x, y, dist; + var pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + if (pd2 == 0) { + x = x1; + y = y1; + dist = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2); + } + else { + var u = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / pd2; + if (u < 0) { + x = x1; + y = y1; + dist = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3); + } + else if (u > 1.0) { + x = x2; + y = y2; + dist = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3); + } + else { + x = x1 + u * (x2 - x1); + y = y1 + u * (y2 - y1); + dist = (x - x3) * (x - x3) + (y - y3) * (y - y3); + } + } + return [x, y, dist]; + }, + // line as array of points. + // line might be closed + _getProjectionToLine(pt, line, isClosed) { + var pc = Util.cloneObject(pt); + var dist = Number.MAX_VALUE; + line.forEach(function (p1, i) { + if (!isClosed && i === line.length - 1) { + return; + } + var p2 = line[(i + 1) % line.length]; + var proj = Util._getProjectionToSegment(p1.x, p1.y, p2.x, p2.y, pt.x, pt.y); + var px = proj[0], py = proj[1], pdist = proj[2]; + if (pdist < dist) { + pc.x = px; + pc.y = py; + dist = pdist; + } + }); + return pc; + }, + _prepareArrayForTween(startArray, endArray, isClosed) { + var n, start = [], end = []; + if (startArray.length > endArray.length) { + var temp = endArray; + endArray = startArray; + startArray = temp; + } + for (n = 0; n < startArray.length; n += 2) { + start.push({ + x: startArray[n], + y: startArray[n + 1], + }); + } + for (n = 0; n < endArray.length; n += 2) { + end.push({ + x: endArray[n], + y: endArray[n + 1], + }); + } + var newStart = []; + end.forEach(function (point) { + var pr = Util._getProjectionToLine(point, start, isClosed); + newStart.push(pr.x); + newStart.push(pr.y); + }); + return newStart; + }, + _prepareToStringify(obj) { + var desc; + obj.visitedByCircularReferenceRemoval = true; + for (var key in obj) { + if (!(obj.hasOwnProperty(key) && obj[key] && typeof obj[key] == 'object')) { + continue; + } + desc = Object.getOwnPropertyDescriptor(obj, key); + if (obj[key].visitedByCircularReferenceRemoval || + Util._isElement(obj[key])) { + if (desc.configurable) { + delete obj[key]; + } + else { + return null; + } + } + else if (Util._prepareToStringify(obj[key]) === null) { + if (desc.configurable) { + delete obj[key]; + } + else { + return null; + } + } + } + delete obj.visitedByCircularReferenceRemoval; + return obj; + }, + // very simplified version of Object.assign + _assign(target, source) { + for (var key in source) { + target[key] = source[key]; + } + return target; + }, + _getFirstPointerId(evt) { + if (!evt.touches) { + // fake id for mouse + return 999; + } + else { + return evt.changedTouches[0].identifier; + } + }, + }; + function _formatValue(val) { - if (Util._isString(val)) { - return '"' + val + '"'; - } - if (Object.prototype.toString.call(val) === '[object Number]') { - return val; - } - if (Util._isBoolean(val)) { - return val; - } - return Object.prototype.toString.call(val); + if (Util._isString(val)) { + return '"' + val + '"'; + } + if (Object.prototype.toString.call(val) === '[object Number]') { + return val; + } + if (Util._isBoolean(val)) { + return val; + } + return Object.prototype.toString.call(val); } function RGBComponent(val) { - if (val > 255) { - return 255; - } else if (val < 0) { - return 0; - } - return Math.round(val); + if (val > 255) { + return 255; + } + else if (val < 0) { + return 0; + } + return Math.round(val); } function getNumberValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - if (!Util._isNumber(val)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a number.' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + if (!Util._isNumber(val)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a number.'); + } + return val; + }; + } } function getNumberOrArrayOfNumbersValidator(noOfElements) { - if (Konva$2.isUnminified) { - return function (val, attr) { - let isNumber = Util._isNumber(val); - let isValidArray = Util._isArray(val) && val.length == noOfElements; - if (!isNumber && !isValidArray) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a number or Array(' + - noOfElements + - ')' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + let isNumber = Util._isNumber(val); + let isValidArray = Util._isArray(val) && val.length == noOfElements; + if (!isNumber && !isValidArray) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a number or Array(' + + noOfElements + + ')'); + } + return val; + }; + } } function getNumberOrAutoValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - var isNumber = Util._isNumber(val); - var isAuto = val === 'auto'; - if (!(isNumber || isAuto)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a number or "auto".' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + var isNumber = Util._isNumber(val); + var isAuto = val === 'auto'; + if (!(isNumber || isAuto)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a number or "auto".'); + } + return val; + }; + } } function getStringValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - if (!Util._isString(val)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a string.' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + if (!Util._isString(val)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a string.'); + } + return val; + }; + } } function getStringOrGradientValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - const isString = Util._isString(val); - const isGradient = - Object.prototype.toString.call(val) === '[object CanvasGradient]' || - (val && val.addColorStop); - if (!(isString || isGradient)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a string or a native gradient.' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + const isString = Util._isString(val); + const isGradient = Object.prototype.toString.call(val) === '[object CanvasGradient]' || + (val && val.addColorStop); + if (!(isString || isGradient)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a string or a native gradient.'); + } + return val; + }; + } } function getNumberArrayValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - if (!Util._isArray(val)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a array of numbers.' - ); - } else { - val.forEach(function (item) { - if (!Util._isNumber(item)) { - Util.warn( - '"' + - attr + - '" attribute has non numeric element ' + - item + - '. Make sure that all elements are numbers.' - ); - } - }); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + if (!Util._isArray(val)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a array of numbers.'); + } + else { + val.forEach(function (item) { + if (!Util._isNumber(item)) { + Util.warn('"' + + attr + + '" attribute has non numeric element ' + + item + + '. Make sure that all elements are numbers.'); + } + }); + } + return val; + }; + } } function getBooleanValidator() { - if (Konva$2.isUnminified) { - return function (val, attr) { - var isBool = val === true || val === false; - if (!isBool) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be a boolean.' - ); - } - return val; - }; - } + if (Konva$2.isUnminified) { + return function (val, attr) { + var isBool = val === true || val === false; + if (!isBool) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a boolean.'); + } + return val; + }; + } } function getComponentValidator(components) { - if (Konva$2.isUnminified) { - return function (val, attr) { - if (!Util.isObject(val)) { - Util.warn( - _formatValue(val) + - ' is a not valid value for "' + - attr + - '" attribute. The value should be an object with properties ' + - components - ); - } - return val; - }; - } - } - - var GET = 'get', - SET$1 = 'set'; - const Factory = { - addGetterSetter(constructor, attr, def, validator, after) { - Factory.addGetter(constructor, attr, def); - Factory.addSetter(constructor, attr, validator, after); - Factory.addOverloadedGetterSetter(constructor, attr); - }, - addGetter(constructor, attr, def) { - var method = GET + Util._capitalize(attr); - constructor.prototype[method] = - constructor.prototype[method] || - function () { - var val = this.attrs[attr]; - return val === undefined ? def : val; - }; - }, - addSetter(constructor, attr, validator, after) { - var method = SET$1 + Util._capitalize(attr); - if (!constructor.prototype[method]) { - Factory.overWriteSetter(constructor, attr, validator, after); + if (Konva$2.isUnminified) { + return function (val, attr) { + if (!Util.isObject(val)) { + Util.warn(_formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be an object with properties ' + + components); + } + return val; + }; } - }, - overWriteSetter(constructor, attr, validator, after) { - var method = SET$1 + Util._capitalize(attr); - constructor.prototype[method] = function (val) { - if (validator && val !== undefined && val !== null) { - val = validator.call(this, val, attr); - } - this._setAttr(attr, val); - if (after) { - after.call(this); - } - return this; - }; - }, - addComponentsGetterSetter(constructor, attr, components, validator, after) { - var len = components.length, - capitalize = Util._capitalize, - getter = GET + capitalize(attr), - setter = SET$1 + capitalize(attr), - n, - component; - // getter - constructor.prototype[getter] = function () { - var ret = {}; - for (n = 0; n < len; n++) { - component = components[n]; - ret[component] = this.getAttr(attr + capitalize(component)); - } - return ret; - }; - var basicValidator = getComponentValidator(components); - // setter - constructor.prototype[setter] = function (val) { - var oldVal = this.attrs[attr], - key; - if (validator) { - val = validator.call(this, val); - } - if (basicValidator) { - basicValidator.call(this, val, attr); - } - for (key in val) { - if (!val.hasOwnProperty(key)) { - continue; + } + + var GET = 'get', SET$1 = 'set'; + const Factory = { + addGetterSetter(constructor, attr, def, validator, after) { + Factory.addGetter(constructor, attr, def); + Factory.addSetter(constructor, attr, validator, after); + Factory.addOverloadedGetterSetter(constructor, attr); + }, + addGetter(constructor, attr, def) { + var method = GET + Util._capitalize(attr); + constructor.prototype[method] = + constructor.prototype[method] || + function () { + var val = this.attrs[attr]; + return val === undefined ? def : val; + }; + }, + addSetter(constructor, attr, validator, after) { + var method = SET$1 + Util._capitalize(attr); + if (!constructor.prototype[method]) { + Factory.overWriteSetter(constructor, attr, validator, after); } - this._setAttr(attr + capitalize(key), val[key]); - } - this._fireChangeEvent(attr, oldVal, val); - if (after) { - after.call(this); - } - return this; - }; - Factory.addOverloadedGetterSetter(constructor, attr); - }, - addOverloadedGetterSetter(constructor, attr) { - var capitalizedAttr = Util._capitalize(attr), - setter = SET$1 + capitalizedAttr, - getter = GET + capitalizedAttr; - constructor.prototype[attr] = function () { - // setting - if (arguments.length) { - this[setter](arguments[0]); - return this; - } - // getting - return this[getter](); - }; - }, - addDeprecatedGetterSetter(constructor, attr, def, validator) { - Util.error('Adding deprecated ' + attr); - var method = GET + Util._capitalize(attr); - var message = - attr + - ' property is deprecated and will be removed soon. Look at Konva change log for more information.'; - constructor.prototype[method] = function () { - Util.error(message); - var val = this.attrs[attr]; - return val === undefined ? def : val; - }; - Factory.addSetter(constructor, attr, validator, function () { - Util.error(message); - }); - Factory.addOverloadedGetterSetter(constructor, attr); - }, - backCompat(constructor, methods) { - Util.each(methods, function (oldMethodName, newMethodName) { - var method = constructor.prototype[newMethodName]; - var oldGetter = GET + Util._capitalize(oldMethodName); - var oldSetter = SET$1 + Util._capitalize(oldMethodName); - function deprecated() { - method.apply(this, arguments); - Util.error( - '"' + - oldMethodName + - '" method is deprecated and will be removed soon. Use ""' + - newMethodName + - '" instead.' - ); - } - constructor.prototype[oldMethodName] = deprecated; - constructor.prototype[oldGetter] = deprecated; - constructor.prototype[oldSetter] = deprecated; - }); - }, - afterSetFilter() { - this._filterUpToDate = false; - }, - }; - - var COMMA = ',', - OPEN_PAREN = '(', - CLOSE_PAREN = ')', - OPEN_PAREN_BRACKET = '([', - CLOSE_BRACKET_PAREN = '])', - SEMICOLON = ';', - DOUBLE_PAREN = '()', - // EMPTY_STRING = '', - EQUALS = '=', - // SET = 'set', - CONTEXT_METHODS = [ + }, + overWriteSetter(constructor, attr, validator, after) { + var method = SET$1 + Util._capitalize(attr); + constructor.prototype[method] = function (val) { + if (validator && val !== undefined && val !== null) { + val = validator.call(this, val, attr); + } + this._setAttr(attr, val); + if (after) { + after.call(this); + } + return this; + }; + }, + addComponentsGetterSetter(constructor, attr, components, validator, after) { + var len = components.length, capitalize = Util._capitalize, getter = GET + capitalize(attr), setter = SET$1 + capitalize(attr), n, component; + // getter + constructor.prototype[getter] = function () { + var ret = {}; + for (n = 0; n < len; n++) { + component = components[n]; + ret[component] = this.getAttr(attr + capitalize(component)); + } + return ret; + }; + var basicValidator = getComponentValidator(components); + // setter + constructor.prototype[setter] = function (val) { + var oldVal = this.attrs[attr], key; + if (validator) { + val = validator.call(this, val); + } + if (basicValidator) { + basicValidator.call(this, val, attr); + } + for (key in val) { + if (!val.hasOwnProperty(key)) { + continue; + } + this._setAttr(attr + capitalize(key), val[key]); + } + this._fireChangeEvent(attr, oldVal, val); + if (after) { + after.call(this); + } + return this; + }; + Factory.addOverloadedGetterSetter(constructor, attr); + }, + addOverloadedGetterSetter(constructor, attr) { + var capitalizedAttr = Util._capitalize(attr), setter = SET$1 + capitalizedAttr, getter = GET + capitalizedAttr; + constructor.prototype[attr] = function () { + // setting + if (arguments.length) { + this[setter](arguments[0]); + return this; + } + // getting + return this[getter](); + }; + }, + addDeprecatedGetterSetter(constructor, attr, def, validator) { + Util.error('Adding deprecated ' + attr); + var method = GET + Util._capitalize(attr); + var message = attr + + ' property is deprecated and will be removed soon. Look at Konva change log for more information.'; + constructor.prototype[method] = function () { + Util.error(message); + var val = this.attrs[attr]; + return val === undefined ? def : val; + }; + Factory.addSetter(constructor, attr, validator, function () { + Util.error(message); + }); + Factory.addOverloadedGetterSetter(constructor, attr); + }, + backCompat(constructor, methods) { + Util.each(methods, function (oldMethodName, newMethodName) { + var method = constructor.prototype[newMethodName]; + var oldGetter = GET + Util._capitalize(oldMethodName); + var oldSetter = SET$1 + Util._capitalize(oldMethodName); + function deprecated() { + method.apply(this, arguments); + Util.error('"' + + oldMethodName + + '" method is deprecated and will be removed soon. Use ""' + + newMethodName + + '" instead.'); + } + constructor.prototype[oldMethodName] = deprecated; + constructor.prototype[oldGetter] = deprecated; + constructor.prototype[oldSetter] = deprecated; + }); + }, + afterSetFilter() { + this._filterUpToDate = false; + }, + }; + + var COMMA = ',', OPEN_PAREN = '(', CLOSE_PAREN = ')', OPEN_PAREN_BRACKET = '([', CLOSE_BRACKET_PAREN = '])', SEMICOLON = ';', DOUBLE_PAREN = '()', + // EMPTY_STRING = '', + EQUALS = '=', + // SET = 'set', + CONTEXT_METHODS = [ 'arc', 'arcTo', 'beginPath', @@ -1556,25 +1427,25 @@ 'strokeText', 'transform', 'translate', - ]; + ]; var CONTEXT_PROPERTIES = [ - 'fillStyle', - 'strokeStyle', - 'shadowColor', - 'shadowBlur', - 'shadowOffsetX', - 'shadowOffsetY', - 'lineCap', - 'lineDashOffset', - 'lineJoin', - 'lineWidth', - 'miterLimit', - 'font', - 'textAlign', - 'textBaseline', - 'globalAlpha', - 'globalCompositeOperation', - 'imageSmoothingEnabled', + 'fillStyle', + 'strokeStyle', + 'shadowColor', + 'shadowBlur', + 'shadowOffsetX', + 'shadowOffsetY', + 'lineCap', + 'lineDashOffset', + 'lineJoin', + 'lineWidth', + 'miterLimit', + 'font', + 'textAlign', + 'textBaseline', + 'globalAlpha', + 'globalCompositeOperation', + 'imageSmoothingEnabled', ]; const traceArrMax = 100; /** @@ -1600,741 +1471,704 @@ * }) */ class Context { - constructor(canvas) { - this.canvas = canvas; - this._context = canvas._canvas.getContext('2d'); - if (Konva$2.enableTrace) { - this.traceArr = []; - this._enableTrace(); + constructor(canvas) { + this.canvas = canvas; + this._context = canvas._canvas.getContext('2d'); + if (Konva$2.enableTrace) { + this.traceArr = []; + this._enableTrace(); + } } - } - /** - * fill shape - * @method - * @name Konva.Context#fillShape - * @param {Konva.Shape} shape - */ - fillShape(shape) { - if (shape.fillEnabled()) { - this._fill(shape); + /** + * fill shape + * @method + * @name Konva.Context#fillShape + * @param {Konva.Shape} shape + */ + fillShape(shape) { + if (shape.fillEnabled()) { + this._fill(shape); + } } - } - _fill(shape) { - // abstract - } - /** - * stroke shape - * @method - * @name Konva.Context#strokeShape - * @param {Konva.Shape} shape - */ - strokeShape(shape) { - if (shape.hasStroke()) { - this._stroke(shape); + _fill(shape) { + // abstract } - } - _stroke(shape) { - // abstract - } - /** - * fill then stroke - * @method - * @name Konva.Context#fillStrokeShape - * @param {Konva.Shape} shape - */ - fillStrokeShape(shape) { - if (shape.attrs.fillAfterStrokeEnabled) { - this.strokeShape(shape); - this.fillShape(shape); - } else { - this.fillShape(shape); - this.strokeShape(shape); + /** + * stroke shape + * @method + * @name Konva.Context#strokeShape + * @param {Konva.Shape} shape + */ + strokeShape(shape) { + if (shape.hasStroke()) { + this._stroke(shape); + } } - } - getTrace(relaxed, rounded) { - var traceArr = this.traceArr, - len = traceArr.length, - str = '', - n, - trace, - method, - args; - for (n = 0; n < len; n++) { - trace = traceArr[n]; - method = trace.method; - // methods - if (method) { - args = trace.args; - str += method; - if (relaxed) { - str += DOUBLE_PAREN; - } else { - if (Util._isArray(args[0])) { - str += - OPEN_PAREN_BRACKET + args.join(COMMA) + CLOSE_BRACKET_PAREN; - } else { - if (rounded) { - args = args.map((a) => - typeof a === 'number' ? Math.floor(a) : a - ); + _stroke(shape) { + // abstract + } + /** + * fill then stroke + * @method + * @name Konva.Context#fillStrokeShape + * @param {Konva.Shape} shape + */ + fillStrokeShape(shape) { + if (shape.attrs.fillAfterStrokeEnabled) { + this.strokeShape(shape); + this.fillShape(shape); + } + else { + this.fillShape(shape); + this.strokeShape(shape); + } + } + getTrace(relaxed, rounded) { + var traceArr = this.traceArr, len = traceArr.length, str = '', n, trace, method, args; + for (n = 0; n < len; n++) { + trace = traceArr[n]; + method = trace.method; + // methods + if (method) { + args = trace.args; + str += method; + if (relaxed) { + str += DOUBLE_PAREN; + } + else { + if (Util._isArray(args[0])) { + str += OPEN_PAREN_BRACKET + args.join(COMMA) + CLOSE_BRACKET_PAREN; + } + else { + if (rounded) { + args = args.map((a) => typeof a === 'number' ? Math.floor(a) : a); + } + str += OPEN_PAREN + args.join(COMMA) + CLOSE_PAREN; + } + } } - str += OPEN_PAREN + args.join(COMMA) + CLOSE_PAREN; - } + else { + // properties + str += trace.property; + if (!relaxed) { + str += EQUALS + trace.val; + } + } + str += SEMICOLON; } - } else { - // properties - str += trace.property; - if (!relaxed) { - str += EQUALS + trace.val; + return str; + } + clearTrace() { + this.traceArr = []; + } + _trace(str) { + var traceArr = this.traceArr, len; + traceArr.push(str); + len = traceArr.length; + if (len >= traceArrMax) { + traceArr.shift(); } - } - str += SEMICOLON; } - return str; - } - clearTrace() { - this.traceArr = []; - } - _trace(str) { - var traceArr = this.traceArr, - len; - traceArr.push(str); - len = traceArr.length; - if (len >= traceArrMax) { - traceArr.shift(); + /** + * reset canvas context transform + * @method + * @name Konva.Context#reset + */ + reset() { + var pixelRatio = this.getCanvas().getPixelRatio(); + this.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0); } - } - /** - * reset canvas context transform - * @method - * @name Konva.Context#reset - */ - reset() { - var pixelRatio = this.getCanvas().getPixelRatio(); - this.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0); - } - /** - * get canvas wrapper - * @method - * @name Konva.Context#getCanvas - * @returns {Konva.Canvas} - */ - getCanvas() { - return this.canvas; - } - /** - * clear canvas - * @method - * @name Konva.Context#clear - * @param {Object} [bounds] - * @param {Number} [bounds.x] - * @param {Number} [bounds.y] - * @param {Number} [bounds.width] - * @param {Number} [bounds.height] - */ - clear(bounds) { - var canvas = this.getCanvas(); - if (bounds) { - this.clearRect( - bounds.x || 0, - bounds.y || 0, - bounds.width || 0, - bounds.height || 0 - ); - } else { - this.clearRect( - 0, - 0, - canvas.getWidth() / canvas.pixelRatio, - canvas.getHeight() / canvas.pixelRatio - ); + /** + * get canvas wrapper + * @method + * @name Konva.Context#getCanvas + * @returns {Konva.Canvas} + */ + getCanvas() { + return this.canvas; } - } - _applyLineCap(shape) { - var lineCap = shape.getLineCap(); - if (lineCap) { - this.setAttr('lineCap', lineCap); + /** + * clear canvas + * @method + * @name Konva.Context#clear + * @param {Object} [bounds] + * @param {Number} [bounds.x] + * @param {Number} [bounds.y] + * @param {Number} [bounds.width] + * @param {Number} [bounds.height] + */ + clear(bounds) { + var canvas = this.getCanvas(); + if (bounds) { + this.clearRect(bounds.x || 0, bounds.y || 0, bounds.width || 0, bounds.height || 0); + } + else { + this.clearRect(0, 0, canvas.getWidth() / canvas.pixelRatio, canvas.getHeight() / canvas.pixelRatio); + } } - } - _applyOpacity(shape) { - var absOpacity = shape.getAbsoluteOpacity(); - if (absOpacity !== 1) { - this.setAttr('globalAlpha', absOpacity); + _applyLineCap(shape) { + var lineCap = shape.getLineCap(); + if (lineCap) { + this.setAttr('lineCap', lineCap); + } } - } - _applyLineJoin(shape) { - var lineJoin = shape.attrs.lineJoin; - if (lineJoin) { - this.setAttr('lineJoin', lineJoin); + _applyOpacity(shape) { + var absOpacity = shape.getAbsoluteOpacity(); + if (absOpacity !== 1) { + this.setAttr('globalAlpha', absOpacity); + } } - } - setAttr(attr, val) { - this._context[attr] = val; - } - /** - * arc function. - * @method - * @name Konva.Context#arc - */ - arc(a0, a1, a2, a3, a4, a5) { - this._context.arc(a0, a1, a2, a3, a4, a5); - } - /** - * arcTo function. - * @method - * @name Konva.Context#arcTo - */ - arcTo(a0, a1, a2, a3, a4) { - this._context.arcTo(a0, a1, a2, a3, a4); - } - /** - * beginPath function. - * @method - * @name Konva.Context#beginPath - */ - beginPath() { - this._context.beginPath(); - } - /** - * bezierCurveTo function. - * @method - * @name Konva.Context#bezierCurveTo - */ - bezierCurveTo(a0, a1, a2, a3, a4, a5) { - this._context.bezierCurveTo(a0, a1, a2, a3, a4, a5); - } - /** - * clearRect function. - * @method - * @name Konva.Context#clearRect - */ - clearRect(a0, a1, a2, a3) { - this._context.clearRect(a0, a1, a2, a3); - } - /** - * clip function. - * @method - * @name Konva.Context#clip - */ - clip() { - this._context.clip(); - } - /** - * closePath function. - * @method - * @name Konva.Context#closePath - */ - closePath() { - this._context.closePath(); - } - /** - * createImageData function. - * @method - * @name Konva.Context#createImageData - */ - createImageData(a0, a1) { - var a = arguments; - if (a.length === 2) { - return this._context.createImageData(a0, a1); - } else if (a.length === 1) { - return this._context.createImageData(a0); + _applyLineJoin(shape) { + var lineJoin = shape.attrs.lineJoin; + if (lineJoin) { + this.setAttr('lineJoin', lineJoin); + } } - } - /** - * createLinearGradient function. - * @method - * @name Konva.Context#createLinearGradient - */ - createLinearGradient(a0, a1, a2, a3) { - return this._context.createLinearGradient(a0, a1, a2, a3); - } - /** - * createPattern function. - * @method - * @name Konva.Context#createPattern - */ - createPattern(a0, a1) { - return this._context.createPattern(a0, a1); - } - /** - * createRadialGradient function. - * @method - * @name Konva.Context#createRadialGradient - */ - createRadialGradient(a0, a1, a2, a3, a4, a5) { - return this._context.createRadialGradient(a0, a1, a2, a3, a4, a5); - } - /** - * drawImage function. - * @method - * @name Konva.Context#drawImage - */ - drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8) { - var a = arguments, - _context = this._context; - if (a.length === 3) { - _context.drawImage(a0, a1, a2); - } else if (a.length === 5) { - _context.drawImage(a0, a1, a2, a3, a4); - } else if (a.length === 9) { - _context.drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8); + setAttr(attr, val) { + this._context[attr] = val; } - } - /** - * ellipse function. - * @method - * @name Konva.Context#ellipse - */ - ellipse(a0, a1, a2, a3, a4, a5, a6, a7) { - this._context.ellipse(a0, a1, a2, a3, a4, a5, a6, a7); - } - /** - * isPointInPath function. - * @method - * @name Konva.Context#isPointInPath - */ - isPointInPath(x, y) { - return this._context.isPointInPath(x, y); - } - /** - * fill function. - * @method - * @name Konva.Context#fill - */ - fill() { - this._context.fill(); - } - /** - * fillRect function. - * @method - * @name Konva.Context#fillRect - */ - fillRect(x, y, width, height) { - this._context.fillRect(x, y, width, height); - } - /** - * strokeRect function. - * @method - * @name Konva.Context#strokeRect - */ - strokeRect(x, y, width, height) { - this._context.strokeRect(x, y, width, height); - } - /** - * fillText function. - * @method - * @name Konva.Context#fillText - */ - fillText(a0, a1, a2) { - this._context.fillText(a0, a1, a2); - } - /** - * measureText function. - * @method - * @name Konva.Context#measureText - */ - measureText(text) { - return this._context.measureText(text); - } - /** - * getImageData function. - * @method - * @name Konva.Context#getImageData - */ - getImageData(a0, a1, a2, a3) { - return this._context.getImageData(a0, a1, a2, a3); - } - /** - * lineTo function. - * @method - * @name Konva.Context#lineTo - */ - lineTo(a0, a1) { - this._context.lineTo(a0, a1); - } - /** - * moveTo function. - * @method - * @name Konva.Context#moveTo - */ - moveTo(a0, a1) { - this._context.moveTo(a0, a1); - } - /** - * rect function. - * @method - * @name Konva.Context#rect - */ - rect(a0, a1, a2, a3) { - this._context.rect(a0, a1, a2, a3); - } - /** - * putImageData function. - * @method - * @name Konva.Context#putImageData - */ - putImageData(a0, a1, a2) { - this._context.putImageData(a0, a1, a2); - } - /** - * quadraticCurveTo function. - * @method - * @name Konva.Context#quadraticCurveTo - */ - quadraticCurveTo(a0, a1, a2, a3) { - this._context.quadraticCurveTo(a0, a1, a2, a3); - } - /** - * restore function. - * @method - * @name Konva.Context#restore - */ - restore() { - this._context.restore(); - } - /** - * rotate function. - * @method - * @name Konva.Context#rotate - */ - rotate(a0) { - this._context.rotate(a0); - } - /** - * save function. - * @method - * @name Konva.Context#save - */ - save() { - this._context.save(); - } - /** - * scale function. - * @method - * @name Konva.Context#scale - */ - scale(a0, a1) { - this._context.scale(a0, a1); - } - /** - * setLineDash function. - * @method - * @name Konva.Context#setLineDash - */ - setLineDash(a0) { - // works for Chrome and IE11 - if (this._context.setLineDash) { - this._context.setLineDash(a0); - } else if ('mozDash' in this._context) { - // verified that this works in firefox - this._context['mozDash'] = a0; - } else if ('webkitLineDash' in this._context) { - // does not currently work for Safari - this._context['webkitLineDash'] = a0; + /** + * arc function. + * @method + * @name Konva.Context#arc + */ + arc(a0, a1, a2, a3, a4, a5) { + this._context.arc(a0, a1, a2, a3, a4, a5); } - // no support for IE9 and IE10 - } - /** - * getLineDash function. - * @method - * @name Konva.Context#getLineDash - */ - getLineDash() { - return this._context.getLineDash(); - } - /** - * setTransform function. - * @method - * @name Konva.Context#setTransform - */ - setTransform(a0, a1, a2, a3, a4, a5) { - this._context.setTransform(a0, a1, a2, a3, a4, a5); - } - /** - * stroke function. - * @method - * @name Konva.Context#stroke - */ - stroke() { - this._context.stroke(); - } - /** - * strokeText function. - * @method - * @name Konva.Context#strokeText - */ - strokeText(a0, a1, a2, a3) { - this._context.strokeText(a0, a1, a2, a3); - } - /** - * transform function. - * @method - * @name Konva.Context#transform - */ - transform(a0, a1, a2, a3, a4, a5) { - this._context.transform(a0, a1, a2, a3, a4, a5); - } - /** - * translate function. - * @method - * @name Konva.Context#translate - */ - translate(a0, a1) { - this._context.translate(a0, a1); - } - _enableTrace() { - var that = this, - len = CONTEXT_METHODS.length, - origSetter = this.setAttr, - n, - args; - // to prevent creating scope function at each loop - var func = function (methodName) { - var origMethod = that[methodName], - ret; - that[methodName] = function () { - args = Util._simplifyArray(Array.prototype.slice.call(arguments, 0)); - ret = origMethod.apply(that, arguments); - that._trace({ - method: methodName, - args: args, - }); - return ret; - }; - }; - // methods - for (n = 0; n < len; n++) { - func(CONTEXT_METHODS[n]); + /** + * arcTo function. + * @method + * @name Konva.Context#arcTo + */ + arcTo(a0, a1, a2, a3, a4) { + this._context.arcTo(a0, a1, a2, a3, a4); } - // attrs - that.setAttr = function () { - origSetter.apply(that, arguments); - var prop = arguments[0]; - var val = arguments[1]; - if ( - prop === 'shadowOffsetX' || - prop === 'shadowOffsetY' || - prop === 'shadowBlur' - ) { - val = val / this.canvas.getPixelRatio(); - } - that._trace({ - property: prop, - val: val, - }); - }; - } - _applyGlobalCompositeOperation(node) { - var globalCompositeOperation = node.getGlobalCompositeOperation(); - if (globalCompositeOperation !== 'source-over') { - this.setAttr('globalCompositeOperation', globalCompositeOperation); + /** + * beginPath function. + * @method + * @name Konva.Context#beginPath + */ + beginPath() { + this._context.beginPath(); + } + /** + * bezierCurveTo function. + * @method + * @name Konva.Context#bezierCurveTo + */ + bezierCurveTo(a0, a1, a2, a3, a4, a5) { + this._context.bezierCurveTo(a0, a1, a2, a3, a4, a5); + } + /** + * clearRect function. + * @method + * @name Konva.Context#clearRect + */ + clearRect(a0, a1, a2, a3) { + this._context.clearRect(a0, a1, a2, a3); + } + /** + * clip function. + * @method + * @name Konva.Context#clip + */ + clip() { + this._context.clip(); + } + /** + * closePath function. + * @method + * @name Konva.Context#closePath + */ + closePath() { + this._context.closePath(); + } + /** + * createImageData function. + * @method + * @name Konva.Context#createImageData + */ + createImageData(a0, a1) { + var a = arguments; + if (a.length === 2) { + return this._context.createImageData(a0, a1); + } + else if (a.length === 1) { + return this._context.createImageData(a0); + } + } + /** + * createLinearGradient function. + * @method + * @name Konva.Context#createLinearGradient + */ + createLinearGradient(a0, a1, a2, a3) { + return this._context.createLinearGradient(a0, a1, a2, a3); + } + /** + * createPattern function. + * @method + * @name Konva.Context#createPattern + */ + createPattern(a0, a1) { + return this._context.createPattern(a0, a1); + } + /** + * createRadialGradient function. + * @method + * @name Konva.Context#createRadialGradient + */ + createRadialGradient(a0, a1, a2, a3, a4, a5) { + return this._context.createRadialGradient(a0, a1, a2, a3, a4, a5); + } + /** + * drawImage function. + * @method + * @name Konva.Context#drawImage + */ + drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8) { + var a = arguments, _context = this._context; + if (a.length === 3) { + _context.drawImage(a0, a1, a2); + } + else if (a.length === 5) { + _context.drawImage(a0, a1, a2, a3, a4); + } + else if (a.length === 9) { + _context.drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + } + /** + * ellipse function. + * @method + * @name Konva.Context#ellipse + */ + ellipse(a0, a1, a2, a3, a4, a5, a6, a7) { + this._context.ellipse(a0, a1, a2, a3, a4, a5, a6, a7); + } + /** + * isPointInPath function. + * @method + * @name Konva.Context#isPointInPath + */ + isPointInPath(x, y) { + return this._context.isPointInPath(x, y); + } + /** + * fill function. + * @method + * @name Konva.Context#fill + */ + fill() { + this._context.fill(); + } + /** + * fillRect function. + * @method + * @name Konva.Context#fillRect + */ + fillRect(x, y, width, height) { + this._context.fillRect(x, y, width, height); + } + /** + * strokeRect function. + * @method + * @name Konva.Context#strokeRect + */ + strokeRect(x, y, width, height) { + this._context.strokeRect(x, y, width, height); + } + /** + * fillText function. + * @method + * @name Konva.Context#fillText + */ + fillText(a0, a1, a2) { + this._context.fillText(a0, a1, a2); + } + /** + * measureText function. + * @method + * @name Konva.Context#measureText + */ + measureText(text) { + return this._context.measureText(text); + } + /** + * getImageData function. + * @method + * @name Konva.Context#getImageData + */ + getImageData(a0, a1, a2, a3) { + return this._context.getImageData(a0, a1, a2, a3); + } + /** + * lineTo function. + * @method + * @name Konva.Context#lineTo + */ + lineTo(a0, a1) { + this._context.lineTo(a0, a1); + } + /** + * moveTo function. + * @method + * @name Konva.Context#moveTo + */ + moveTo(a0, a1) { + this._context.moveTo(a0, a1); + } + /** + * rect function. + * @method + * @name Konva.Context#rect + */ + rect(a0, a1, a2, a3) { + this._context.rect(a0, a1, a2, a3); + } + /** + * putImageData function. + * @method + * @name Konva.Context#putImageData + */ + putImageData(a0, a1, a2) { + this._context.putImageData(a0, a1, a2); + } + /** + * quadraticCurveTo function. + * @method + * @name Konva.Context#quadraticCurveTo + */ + quadraticCurveTo(a0, a1, a2, a3) { + this._context.quadraticCurveTo(a0, a1, a2, a3); + } + /** + * restore function. + * @method + * @name Konva.Context#restore + */ + restore() { + this._context.restore(); + } + /** + * rotate function. + * @method + * @name Konva.Context#rotate + */ + rotate(a0) { + this._context.rotate(a0); + } + /** + * save function. + * @method + * @name Konva.Context#save + */ + save() { + this._context.save(); + } + /** + * scale function. + * @method + * @name Konva.Context#scale + */ + scale(a0, a1) { + this._context.scale(a0, a1); + } + /** + * setLineDash function. + * @method + * @name Konva.Context#setLineDash + */ + setLineDash(a0) { + // works for Chrome and IE11 + if (this._context.setLineDash) { + this._context.setLineDash(a0); + } + else if ('mozDash' in this._context) { + // verified that this works in firefox + this._context['mozDash'] = a0; + } + else if ('webkitLineDash' in this._context) { + // does not currently work for Safari + this._context['webkitLineDash'] = a0; + } + // no support for IE9 and IE10 + } + /** + * getLineDash function. + * @method + * @name Konva.Context#getLineDash + */ + getLineDash() { + return this._context.getLineDash(); + } + /** + * setTransform function. + * @method + * @name Konva.Context#setTransform + */ + setTransform(a0, a1, a2, a3, a4, a5) { + this._context.setTransform(a0, a1, a2, a3, a4, a5); + } + /** + * stroke function. + * @method + * @name Konva.Context#stroke + */ + stroke() { + this._context.stroke(); + } + /** + * strokeText function. + * @method + * @name Konva.Context#strokeText + */ + strokeText(a0, a1, a2, a3) { + this._context.strokeText(a0, a1, a2, a3); + } + /** + * transform function. + * @method + * @name Konva.Context#transform + */ + transform(a0, a1, a2, a3, a4, a5) { + this._context.transform(a0, a1, a2, a3, a4, a5); + } + /** + * translate function. + * @method + * @name Konva.Context#translate + */ + translate(a0, a1) { + this._context.translate(a0, a1); + } + _enableTrace() { + var that = this, len = CONTEXT_METHODS.length, origSetter = this.setAttr, n, args; + // to prevent creating scope function at each loop + var func = function (methodName) { + var origMethod = that[methodName], ret; + that[methodName] = function () { + args = Util._simplifyArray(Array.prototype.slice.call(arguments, 0)); + ret = origMethod.apply(that, arguments); + that._trace({ + method: methodName, + args: args, + }); + return ret; + }; + }; + // methods + for (n = 0; n < len; n++) { + func(CONTEXT_METHODS[n]); + } + // attrs + that.setAttr = function () { + origSetter.apply(that, arguments); + var prop = arguments[0]; + var val = arguments[1]; + if (prop === 'shadowOffsetX' || + prop === 'shadowOffsetY' || + prop === 'shadowBlur') { + val = val / this.canvas.getPixelRatio(); + } + that._trace({ + property: prop, + val: val, + }); + }; + } + _applyGlobalCompositeOperation(node) { + var globalCompositeOperation = node.getGlobalCompositeOperation(); + if (globalCompositeOperation !== 'source-over') { + this.setAttr('globalCompositeOperation', globalCompositeOperation); + } } - } } CONTEXT_PROPERTIES.forEach(function (prop) { - Object.defineProperty(Context.prototype, prop, { - get() { - return this._context[prop]; - }, - set(val) { - this._context[prop] = val; - }, - }); + Object.defineProperty(Context.prototype, prop, { + get() { + return this._context[prop]; + }, + set(val) { + this._context[prop] = val; + }, + }); }); class SceneContext extends Context { - _fillColor(shape) { - var fill = shape.fill(); - this.setAttr('fillStyle', fill); - shape._fillFunc(this); - } - _fillPattern(shape) { - var fillPatternX = shape.getFillPatternX(), - fillPatternY = shape.getFillPatternY(), - fillPatternRotation = Konva$2.getAngle(shape.getFillPatternRotation()), - fillPatternOffsetX = shape.getFillPatternOffsetX(), - fillPatternOffsetY = shape.getFillPatternOffsetY(); - shape.getFillPatternScaleX(); - shape.getFillPatternScaleY(); - if (fillPatternX || fillPatternY) { - this.translate(fillPatternX || 0, fillPatternY || 0); + _fillColor(shape) { + var fill = shape.fill(); + this.setAttr('fillStyle', fill); + shape._fillFunc(this); } - if (fillPatternRotation) { - this.rotate(fillPatternRotation); + _fillPattern(shape) { + var fillPatternX = shape.getFillPatternX(), fillPatternY = shape.getFillPatternY(), fillPatternRotation = Konva$2.getAngle(shape.getFillPatternRotation()), fillPatternOffsetX = shape.getFillPatternOffsetX(), fillPatternOffsetY = shape.getFillPatternOffsetY(); shape.getFillPatternScaleX(); shape.getFillPatternScaleY(); + if (fillPatternX || fillPatternY) { + this.translate(fillPatternX || 0, fillPatternY || 0); + } + if (fillPatternRotation) { + this.rotate(fillPatternRotation); + } + if (fillPatternOffsetX || fillPatternOffsetY) { + this.translate(-1 * fillPatternOffsetX, -1 * fillPatternOffsetY); + } + this.setAttr('fillStyle', shape._getFillPattern()); + shape._fillFunc(this); } - if (fillPatternOffsetX || fillPatternOffsetY) { - this.translate(-1 * fillPatternOffsetX, -1 * fillPatternOffsetY); + _fillLinearGradient(shape) { + var grd = shape._getLinearGradient(); + if (grd) { + this.setAttr('fillStyle', grd); + shape._fillFunc(this); + } } - this.setAttr('fillStyle', shape._getFillPattern()); - shape._fillFunc(this); - } - _fillLinearGradient(shape) { - var grd = shape._getLinearGradient(); - if (grd) { - this.setAttr('fillStyle', grd); - shape._fillFunc(this); + _fillRadialGradient(shape) { + var grd = shape._getRadialGradient(); + if (grd) { + this.setAttr('fillStyle', grd); + shape._fillFunc(this); + } } - } - _fillRadialGradient(shape) { - var grd = shape._getRadialGradient(); - if (grd) { - this.setAttr('fillStyle', grd); - shape._fillFunc(this); + _fill(shape) { + var hasColor = shape.fill(), fillPriority = shape.getFillPriority(); + // priority fills + if (hasColor && fillPriority === 'color') { + this._fillColor(shape); + return; + } + var hasPattern = shape.getFillPatternImage(); + if (hasPattern && fillPriority === 'pattern') { + this._fillPattern(shape); + return; + } + var hasLinearGradient = shape.getFillLinearGradientColorStops(); + if (hasLinearGradient && fillPriority === 'linear-gradient') { + this._fillLinearGradient(shape); + return; + } + var hasRadialGradient = shape.getFillRadialGradientColorStops(); + if (hasRadialGradient && fillPriority === 'radial-gradient') { + this._fillRadialGradient(shape); + return; + } + // now just try and fill with whatever is available + if (hasColor) { + this._fillColor(shape); + } + else if (hasPattern) { + this._fillPattern(shape); + } + else if (hasLinearGradient) { + this._fillLinearGradient(shape); + } + else if (hasRadialGradient) { + this._fillRadialGradient(shape); + } } - } - _fill(shape) { - var hasColor = shape.fill(), - fillPriority = shape.getFillPriority(); - // priority fills - if (hasColor && fillPriority === 'color') { - this._fillColor(shape); - return; + _strokeLinearGradient(shape) { + var start = shape.getStrokeLinearGradientStartPoint(), end = shape.getStrokeLinearGradientEndPoint(), colorStops = shape.getStrokeLinearGradientColorStops(), grd = this.createLinearGradient(start.x, start.y, end.x, end.y); + if (colorStops) { + // build color stops + for (var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + this.setAttr('strokeStyle', grd); + } } - var hasPattern = shape.getFillPatternImage(); - if (hasPattern && fillPriority === 'pattern') { - this._fillPattern(shape); - return; + _stroke(shape) { + var dash = shape.dash(), + // ignore strokeScaleEnabled for Text + strokeScaleEnabled = shape.getStrokeScaleEnabled(); + if (shape.hasStroke()) { + if (!strokeScaleEnabled) { + this.save(); + var pixelRatio = this.getCanvas().getPixelRatio(); + this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + } + this._applyLineCap(shape); + if (dash && shape.dashEnabled()) { + this.setLineDash(dash); + this.setAttr('lineDashOffset', shape.dashOffset()); + } + this.setAttr('lineWidth', shape.strokeWidth()); + if (!shape.getShadowForStrokeEnabled()) { + this.setAttr('shadowColor', 'rgba(0,0,0,0)'); + } + var hasLinearGradient = shape.getStrokeLinearGradientColorStops(); + if (hasLinearGradient) { + this._strokeLinearGradient(shape); + } + else { + this.setAttr('strokeStyle', shape.stroke()); + } + shape._strokeFunc(this); + if (!strokeScaleEnabled) { + this.restore(); + } + } } - var hasLinearGradient = shape.getFillLinearGradientColorStops(); - if (hasLinearGradient && fillPriority === 'linear-gradient') { - this._fillLinearGradient(shape); - return; + _applyShadow(shape) { + var util = Util, color = util.get(shape.getShadowRGBA(), 'black'), blur = util.get(shape.getShadowBlur(), 5), offset = util.get(shape.getShadowOffset(), { + x: 0, + y: 0, + }), scale = shape.getAbsoluteScale(), ratio = this.canvas.getPixelRatio(), scaleX = scale.x * ratio, scaleY = scale.y * ratio; + this.setAttr('shadowColor', color); + this.setAttr('shadowBlur', blur * Math.min(Math.abs(scaleX), Math.abs(scaleY))); + this.setAttr('shadowOffsetX', offset.x * scaleX); + this.setAttr('shadowOffsetY', offset.y * scaleY); } - var hasRadialGradient = shape.getFillRadialGradientColorStops(); - if (hasRadialGradient && fillPriority === 'radial-gradient') { - this._fillRadialGradient(shape); - return; - } - // now just try and fill with whatever is available - if (hasColor) { - this._fillColor(shape); - } else if (hasPattern) { - this._fillPattern(shape); - } else if (hasLinearGradient) { - this._fillLinearGradient(shape); - } else if (hasRadialGradient) { - this._fillRadialGradient(shape); - } - } - _strokeLinearGradient(shape) { - var start = shape.getStrokeLinearGradientStartPoint(), - end = shape.getStrokeLinearGradientEndPoint(), - colorStops = shape.getStrokeLinearGradientColorStops(), - grd = this.createLinearGradient(start.x, start.y, end.x, end.y); - if (colorStops) { - // build color stops - for (var n = 0; n < colorStops.length; n += 2) { - grd.addColorStop(colorStops[n], colorStops[n + 1]); - } - this.setAttr('strokeStyle', grd); - } - } - _stroke(shape) { - var dash = shape.dash(), - // ignore strokeScaleEnabled for Text - strokeScaleEnabled = shape.getStrokeScaleEnabled(); - if (shape.hasStroke()) { - if (!strokeScaleEnabled) { - this.save(); - var pixelRatio = this.getCanvas().getPixelRatio(); - this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - } - this._applyLineCap(shape); - if (dash && shape.dashEnabled()) { - this.setLineDash(dash); - this.setAttr('lineDashOffset', shape.dashOffset()); - } - this.setAttr('lineWidth', shape.strokeWidth()); - if (!shape.getShadowForStrokeEnabled()) { - this.setAttr('shadowColor', 'rgba(0,0,0,0)'); - } - var hasLinearGradient = shape.getStrokeLinearGradientColorStops(); - if (hasLinearGradient) { - this._strokeLinearGradient(shape); - } else { - this.setAttr('strokeStyle', shape.stroke()); - } - shape._strokeFunc(this); - if (!strokeScaleEnabled) { - this.restore(); - } - } - } - _applyShadow(shape) { - var util = Util, - color = util.get(shape.getShadowRGBA(), 'black'), - blur = util.get(shape.getShadowBlur(), 5), - offset = util.get(shape.getShadowOffset(), { - x: 0, - y: 0, - }), - scale = shape.getAbsoluteScale(), - ratio = this.canvas.getPixelRatio(), - scaleX = scale.x * ratio, - scaleY = scale.y * ratio; - this.setAttr('shadowColor', color); - this.setAttr( - 'shadowBlur', - blur * Math.min(Math.abs(scaleX), Math.abs(scaleY)) - ); - this.setAttr('shadowOffsetX', offset.x * scaleX); - this.setAttr('shadowOffsetY', offset.y * scaleY); - } } class HitContext extends Context { - _fill(shape) { - this.save(); - this.setAttr('fillStyle', shape.colorKey); - shape._fillFuncHit(this); - this.restore(); - } - strokeShape(shape) { - if (shape.hasHitStroke()) { - this._stroke(shape); - } - } - _stroke(shape) { - if (shape.hasHitStroke()) { - // ignore strokeScaleEnabled for Text - var strokeScaleEnabled = shape.getStrokeScaleEnabled(); - if (!strokeScaleEnabled) { + _fill(shape) { this.save(); - var pixelRatio = this.getCanvas().getPixelRatio(); - this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - } - this._applyLineCap(shape); - var hitStrokeWidth = shape.hitStrokeWidth(); - var strokeWidth = - hitStrokeWidth === 'auto' ? shape.strokeWidth() : hitStrokeWidth; - this.setAttr('lineWidth', strokeWidth); - this.setAttr('strokeStyle', shape.colorKey); - shape._strokeFuncHit(this); - if (!strokeScaleEnabled) { + this.setAttr('fillStyle', shape.colorKey); + shape._fillFuncHit(this); this.restore(); - } } - } - } - + strokeShape(shape) { + if (shape.hasHitStroke()) { + this._stroke(shape); + } + } + _stroke(shape) { + if (shape.hasHitStroke()) { + // ignore strokeScaleEnabled for Text + var strokeScaleEnabled = shape.getStrokeScaleEnabled(); + if (!strokeScaleEnabled) { + this.save(); + var pixelRatio = this.getCanvas().getPixelRatio(); + this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + } + this._applyLineCap(shape); + var hitStrokeWidth = shape.hitStrokeWidth(); + var strokeWidth = hitStrokeWidth === 'auto' ? shape.strokeWidth() : hitStrokeWidth; + this.setAttr('lineWidth', strokeWidth); + this.setAttr('strokeStyle', shape.colorKey); + shape._strokeFuncHit(this); + if (!strokeScaleEnabled) { + this.restore(); + } + } + } + } + // calculate pixel ratio var _pixelRatio; function getDevicePixelRatio() { - if (_pixelRatio) { + if (_pixelRatio) { + return _pixelRatio; + } + var canvas = Util.createCanvasElement(); + var context = canvas.getContext('2d'); + _pixelRatio = (function () { + var devicePixelRatio = Konva$2._global.devicePixelRatio || 1, backingStoreRatio = context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || + 1; + return devicePixelRatio / backingStoreRatio; + })(); return _pixelRatio; - } - var canvas = Util.createCanvasElement(); - var context = canvas.getContext('2d'); - _pixelRatio = (function () { - var devicePixelRatio = Konva$2._global.devicePixelRatio || 1, - backingStoreRatio = - context.webkitBackingStorePixelRatio || - context.mozBackingStorePixelRatio || - context.msBackingStorePixelRatio || - context.oBackingStorePixelRatio || - context.backingStorePixelRatio || - 1; - return devicePixelRatio / backingStoreRatio; - })(); - return _pixelRatio; } /** * Canvas Renderer constructor. It is a wrapper around native canvas element. @@ -2348,97 +2182,91 @@ * @param {Number} config.pixelRatio */ class Canvas { - constructor(config) { - this.pixelRatio = 1; - this.width = 0; - this.height = 0; - this.isCache = false; - var conf = config || {}; - var pixelRatio = - conf.pixelRatio || Konva$2.pixelRatio || getDevicePixelRatio(); - this.pixelRatio = pixelRatio; - this._canvas = Util.createCanvasElement(); - // set inline styles - this._canvas.style.padding = '0'; - this._canvas.style.margin = '0'; - this._canvas.style.border = '0'; - this._canvas.style.background = 'transparent'; - this._canvas.style.position = 'absolute'; - this._canvas.style.top = '0'; - this._canvas.style.left = '0'; - } - /** - * get canvas context - * @method - * @name Konva.Canvas#getContext - * @returns {CanvasContext} context - */ - getContext() { - return this.context; - } - getPixelRatio() { - return this.pixelRatio; - } - setPixelRatio(pixelRatio) { - var previousRatio = this.pixelRatio; - this.pixelRatio = pixelRatio; - this.setSize( - this.getWidth() / previousRatio, - this.getHeight() / previousRatio - ); - } - setWidth(width) { - // take into account pixel ratio - this.width = this._canvas.width = width * this.pixelRatio; - this._canvas.style.width = width + 'px'; - var pixelRatio = this.pixelRatio, - _context = this.getContext()._context; - _context.scale(pixelRatio, pixelRatio); - } - setHeight(height) { - // take into account pixel ratio - this.height = this._canvas.height = height * this.pixelRatio; - this._canvas.style.height = height + 'px'; - var pixelRatio = this.pixelRatio, - _context = this.getContext()._context; - _context.scale(pixelRatio, pixelRatio); - } - getWidth() { - return this.width; - } - getHeight() { - return this.height; - } - setSize(width, height) { - this.setWidth(width || 0); - this.setHeight(height || 0); - } - /** - * to data url - * @method - * @name Konva.Canvas#toDataURL - * @param {String} mimeType - * @param {Number} quality between 0 and 1 for jpg mime types - * @returns {String} data url string - */ - toDataURL(mimeType, quality) { - try { - // If this call fails (due to browser bug, like in Firefox 3.6), - // then revert to previous no-parameter image/png behavior - return this._canvas.toDataURL(mimeType, quality); - } catch (e) { - try { - return this._canvas.toDataURL(); - } catch (err) { - Util.error( - 'Unable to get data URL. ' + - err.message + - ' For more info read https://konvajs.org/docs/posts/Tainted_Canvas.html.' - ); - return ''; - } + constructor(config) { + this.pixelRatio = 1; + this.width = 0; + this.height = 0; + this.isCache = false; + var conf = config || {}; + var pixelRatio = conf.pixelRatio || Konva$2.pixelRatio || getDevicePixelRatio(); + this.pixelRatio = pixelRatio; + this._canvas = Util.createCanvasElement(); + // set inline styles + this._canvas.style.padding = '0'; + this._canvas.style.margin = '0'; + this._canvas.style.border = '0'; + this._canvas.style.background = 'transparent'; + this._canvas.style.position = 'absolute'; + this._canvas.style.top = '0'; + this._canvas.style.left = '0'; + } + /** + * get canvas context + * @method + * @name Konva.Canvas#getContext + * @returns {CanvasContext} context + */ + getContext() { + return this.context; + } + getPixelRatio() { + return this.pixelRatio; + } + setPixelRatio(pixelRatio) { + var previousRatio = this.pixelRatio; + this.pixelRatio = pixelRatio; + this.setSize(this.getWidth() / previousRatio, this.getHeight() / previousRatio); + } + setWidth(width) { + // take into account pixel ratio + this.width = this._canvas.width = width * this.pixelRatio; + this._canvas.style.width = width + 'px'; + var pixelRatio = this.pixelRatio, _context = this.getContext()._context; + _context.scale(pixelRatio, pixelRatio); + } + setHeight(height) { + // take into account pixel ratio + this.height = this._canvas.height = height * this.pixelRatio; + this._canvas.style.height = height + 'px'; + var pixelRatio = this.pixelRatio, _context = this.getContext()._context; + _context.scale(pixelRatio, pixelRatio); + } + getWidth() { + return this.width; + } + getHeight() { + return this.height; + } + setSize(width, height) { + this.setWidth(width || 0); + this.setHeight(height || 0); + } + /** + * to data url + * @method + * @name Konva.Canvas#toDataURL + * @param {String} mimeType + * @param {Number} quality between 0 and 1 for jpg mime types + * @returns {String} data url string + */ + toDataURL(mimeType, quality) { + try { + // If this call fails (due to browser bug, like in Firefox 3.6), + // then revert to previous no-parameter image/png behavior + return this._canvas.toDataURL(mimeType, quality); + } + catch (e) { + try { + return this._canvas.toDataURL(); + } + catch (err) { + Util.error('Unable to get data URL. ' + + err.message + + ' For more info read https://konvajs.org/docs/posts/Tainted_Canvas.html.'); + return ''; + } + } } - } } /** * get/set pixel ratio. @@ -2460,224 +2288,184 @@ * // set * layer.getCanvas().pixelRatio(3); */ - Factory.addGetterSetter( - Canvas, - 'pixelRatio', - undefined, - getNumberValidator() - ); + Factory.addGetterSetter(Canvas, 'pixelRatio', undefined, getNumberValidator()); class SceneCanvas extends Canvas { - constructor(config = { width: 0, height: 0 }) { - super(config); - this.context = new SceneContext(this); - this.setSize(config.width, config.height); - } + constructor(config = { width: 0, height: 0 }) { + super(config); + this.context = new SceneContext(this); + this.setSize(config.width, config.height); + } } class HitCanvas extends Canvas { - constructor(config = { width: 0, height: 0 }) { - super(config); - this.hitCanvas = true; - this.context = new HitContext(this); - this.setSize(config.width, config.height); - } - } - + constructor(config = { width: 0, height: 0 }) { + super(config); + this.hitCanvas = true; + this.context = new HitContext(this); + this.setSize(config.width, config.height); + } + } + const DD = { - get isDragging() { - var flag = false; - DD._dragElements.forEach((elem) => { - if (elem.dragStatus === 'dragging') { - flag = true; - } - }); - return flag; - }, - justDragged: false, - get node() { - // return first dragging node - var node; - DD._dragElements.forEach((elem) => { - node = elem.node; - }); - return node; - }, - _dragElements: new Map(), - // methods - _drag(evt) { - const nodesToFireEvents = []; - DD._dragElements.forEach((elem, key) => { - const { node } = elem; - // we need to find pointer relative to that node - const stage = node.getStage(); - stage.setPointersPositions(evt); - // it is possible that user call startDrag without any event - // it that case we need to detect first movable pointer and attach it into the node - if (elem.pointerId === undefined) { - elem.pointerId = Util._getFirstPointerId(evt); - } - const pos = stage._changedPointerPositions.find( - (pos) => pos.id === elem.pointerId - ); - // not related pointer - if (!pos) { - return; - } - if (elem.dragStatus !== 'dragging') { - var dragDistance = node.dragDistance(); - var distance = Math.max( - Math.abs(pos.x - elem.startPointerPos.x), - Math.abs(pos.y - elem.startPointerPos.y) - ); - if (distance < dragDistance) { - return; - } - node.startDrag({ evt }); - // a user can stop dragging inside `dragstart` - if (!node.isDragging()) { - return; - } - } - node._setDragPosition(evt, elem); - nodesToFireEvents.push(node); - }); - // call dragmove only after ALL positions are changed - nodesToFireEvents.forEach((node) => { - node.fire( - 'dragmove', - { - type: 'dragmove', - target: node, - evt: evt, - }, - true - ); - }); - }, - // dragBefore and dragAfter allows us to set correct order of events - // setup all in dragbefore, and stop dragging only after pointerup triggered. - _endDragBefore(evt) { - DD._dragElements.forEach((elem, key) => { - const { node } = elem; - // we need to find pointer relative to that node - const stage = node.getStage(); - if (evt) { - stage.setPointersPositions(evt); - } - const pos = stage._changedPointerPositions.find( - (pos) => pos.id === elem.pointerId - ); - // that pointer is not related - if (!pos) { - return; - } - if (elem.dragStatus === 'dragging' || elem.dragStatus === 'stopped') { - // if a node is stopped manully we still need to reset events: - DD.justDragged = true; - Konva$2.listenClickTap = false; - elem.dragStatus = 'stopped'; - } - const drawNode = - elem.node.getLayer() || - (elem.node instanceof Konva$2['Stage'] && elem.node); - if (drawNode) { - drawNode.batchDraw(); - } - }); - }, - _endDragAfter(evt) { - DD._dragElements.forEach((elem, key) => { - if (elem.dragStatus === 'stopped') { - elem.node.fire( - 'dragend', - { - type: 'dragend', - target: elem.node, - evt: evt, - }, - true - ); - } - if (elem.dragStatus !== 'dragging') { - DD._dragElements.delete(key); - } - }); - }, + get isDragging() { + var flag = false; + DD._dragElements.forEach((elem) => { + if (elem.dragStatus === 'dragging') { + flag = true; + } + }); + return flag; + }, + justDragged: false, + get node() { + // return first dragging node + var node; + DD._dragElements.forEach((elem) => { + node = elem.node; + }); + return node; + }, + _dragElements: new Map(), + // methods + _drag(evt) { + const nodesToFireEvents = []; + DD._dragElements.forEach((elem, key) => { + const { node } = elem; + // we need to find pointer relative to that node + const stage = node.getStage(); + stage.setPointersPositions(evt); + // it is possible that user call startDrag without any event + // it that case we need to detect first movable pointer and attach it into the node + if (elem.pointerId === undefined) { + elem.pointerId = Util._getFirstPointerId(evt); + } + const pos = stage._changedPointerPositions.find((pos) => pos.id === elem.pointerId); + // not related pointer + if (!pos) { + return; + } + if (elem.dragStatus !== 'dragging') { + var dragDistance = node.dragDistance(); + var distance = Math.max(Math.abs(pos.x - elem.startPointerPos.x), Math.abs(pos.y - elem.startPointerPos.y)); + if (distance < dragDistance) { + return; + } + node.startDrag({ evt }); + // a user can stop dragging inside `dragstart` + if (!node.isDragging()) { + return; + } + } + node._setDragPosition(evt, elem); + nodesToFireEvents.push(node); + }); + // call dragmove only after ALL positions are changed + nodesToFireEvents.forEach((node) => { + node.fire('dragmove', { + type: 'dragmove', + target: node, + evt: evt, + }, true); + }); + }, + // dragBefore and dragAfter allows us to set correct order of events + // setup all in dragbefore, and stop dragging only after pointerup triggered. + _endDragBefore(evt) { + DD._dragElements.forEach((elem, key) => { + const { node } = elem; + // we need to find pointer relative to that node + const stage = node.getStage(); + if (evt) { + stage.setPointersPositions(evt); + } + const pos = stage._changedPointerPositions.find((pos) => pos.id === elem.pointerId); + // that pointer is not related + if (!pos) { + return; + } + if (elem.dragStatus === 'dragging' || elem.dragStatus === 'stopped') { + // if a node is stopped manully we still need to reset events: + DD.justDragged = true; + Konva$2.listenClickTap = false; + elem.dragStatus = 'stopped'; + } + const drawNode = elem.node.getLayer() || + (elem.node instanceof Konva$2['Stage'] && elem.node); + if (drawNode) { + drawNode.batchDraw(); + } + }); + }, + _endDragAfter(evt) { + DD._dragElements.forEach((elem, key) => { + if (elem.dragStatus === 'stopped') { + elem.node.fire('dragend', { + type: 'dragend', + target: elem.node, + evt: evt, + }, true); + } + if (elem.dragStatus !== 'dragging') { + DD._dragElements.delete(key); + } + }); + }, }; if (Konva$2.isBrowser) { - window.addEventListener('mouseup', DD._endDragBefore, true); - window.addEventListener('touchend', DD._endDragBefore, true); - window.addEventListener('mousemove', DD._drag); - window.addEventListener('touchmove', DD._drag); - window.addEventListener('mouseup', DD._endDragAfter, false); - window.addEventListener('touchend', DD._endDragAfter, false); - } - + window.addEventListener('mouseup', DD._endDragBefore, true); + window.addEventListener('touchend', DD._endDragBefore, true); + window.addEventListener('mousemove', DD._drag); + window.addEventListener('touchmove', DD._drag); + window.addEventListener('mouseup', DD._endDragAfter, false); + window.addEventListener('touchend', DD._endDragAfter, false); + } + const ids = {}; const names = {}; const _addId = function (node, id) { - if (!id) { - return; - } - ids[id] = node; + if (!id) { + return; + } + ids[id] = node; }; const _removeId = function (id, node) { - // node has no id - if (!id) { - return; - } - // another node is registered (possible for duplicate ids) - if (ids[id] !== node) { - return; - } - delete ids[id]; + // node has no id + if (!id) { + return; + } + // another node is registered (possible for duplicate ids) + if (ids[id] !== node) { + return; + } + delete ids[id]; }; const _addName = function (node, name) { - if (name) { - if (!names[name]) { - names[name] = []; + if (name) { + if (!names[name]) { + names[name] = []; + } + names[name].push(node); } - names[name].push(node); - } }; 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 (!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]; } - } - if (nodes.length === 0) { - delete names[name]; - } }; // CONSTANTS - var ABSOLUTE_OPACITY = 'absoluteOpacity', - ALL_LISTENERS = 'allEventListeners', - ABSOLUTE_TRANSFORM = 'absoluteTransform', - ABSOLUTE_SCALE = 'absoluteScale', - CANVAS = 'canvas', - CHANGE = 'Change', - CHILDREN = 'children', - KONVA = 'konva', - LISTENING = 'listening', - MOUSEENTER$1 = 'mouseenter', - MOUSELEAVE$1 = 'mouseleave', - NAME = 'name', - SET = 'set', - SHAPE = 'Shape', - SPACE$1 = ' ', - STAGE$1 = 'stage', - TRANSFORM = 'transform', - UPPER_STAGE = 'Stage', - VISIBLE = 'visible', - TRANSFORM_CHANGE_STR$1 = [ + var ABSOLUTE_OPACITY = 'absoluteOpacity', ALL_LISTENERS = 'allEventListeners', ABSOLUTE_TRANSFORM = 'absoluteTransform', ABSOLUTE_SCALE = 'absoluteScale', CANVAS = 'canvas', CHANGE = 'Change', CHILDREN = 'children', KONVA = 'konva', LISTENING = 'listening', MOUSEENTER$1 = 'mouseenter', MOUSELEAVE$1 = 'mouseleave', NAME = 'name', SET = 'set', SHAPE = 'Shape', SPACE$1 = ' ', STAGE$1 = 'stage', TRANSFORM = 'transform', UPPER_STAGE = 'Stage', VISIBLE = 'visible', TRANSFORM_CHANGE_STR$1 = [ 'xChange.konva', 'yChange.konva', 'scaleXChange.konva', @@ -2688,9 +2476,7 @@ 'offsetXChange.konva', 'offsetYChange.konva', 'transformsEnabledChange.konva', - ].join(SPACE$1); - // TODO: can we remove children from node? - const emptyChildren = []; + ].join(SPACE$1); let idCounter$1 = 1; /** * Node constructor. Nodes are entities that can be transformed, layered, @@ -2701,2210 +2487,2088 @@ * @@nodeParams */ class Node { - constructor(config) { - this._id = idCounter$1++; - this.eventListeners = {}; - this.attrs = {}; - this.index = 0; - this._allEventListeners = null; - this.parent = null; - this._cache = new Map(); - this._attachedDepsListeners = new Map(); - this._lastPos = null; - this._batchingTransformChange = false; - this._needClearTransformCache = false; - this._filterUpToDate = false; - this._isUnderCache = false; - this._dragEventId = null; - this._shouldFireChangeEvents = false; - // on initial set attrs wi don't need to fire change events - // because nobody is listening to them yet - this.setAttrs(config); - this._shouldFireChangeEvents = true; - // all change event listeners are attached to the prototype - } - hasChildren() { - return false; - } - getChildren() { - return emptyChildren; - } - _clearCache(attr) { - // if we want to clear transform cache - // we don't really need to remove it from the cache - // but instead mark as "dirty" - // so we don't need to create a new instance next time - if ( - (attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM) && - this._cache.get(attr) - ) { - this._cache.get(attr).dirty = true; - } else if (attr) { - this._cache.delete(attr); - } else { - this._cache.clear(); + constructor(config) { + this._id = idCounter$1++; + this.eventListeners = {}; + this.attrs = {}; + this.index = 0; + this._allEventListeners = null; + this.parent = null; + this._cache = new Map(); + this._attachedDepsListeners = new Map(); + this._lastPos = null; + this._batchingTransformChange = false; + this._needClearTransformCache = false; + this._filterUpToDate = false; + this._isUnderCache = false; + this._dragEventId = null; + this._shouldFireChangeEvents = false; + // on initial set attrs wi don't need to fire change events + // because nobody is listening to them yet + this.setAttrs(config); + this._shouldFireChangeEvents = true; + // all change event listeners are attached to the prototype } - } - _getCache(attr, privateGetter) { - var cache = this._cache.get(attr); - // for transform the cache can be NOT empty - // but we still need to recalculate it if it is dirty - var isTransform = attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM; - var invalid = - cache === undefined || (isTransform && cache.dirty === true); - // if not cached, we need to set it using the private getter method. - if (invalid) { - cache = privateGetter.call(this); - this._cache.set(attr, cache); + hasChildren() { + return false; } - return cache; - } - _calculate(name, deps, getter) { - // if we are trying to calculate function for the first time - // we need to attach listeners for change events - if (!this._attachedDepsListeners.get(name)) { - const depsString = deps - .map((dep) => dep + 'Change.konva') - .join(SPACE$1); - this.on(depsString, () => { - this._clearCache(name); - }); - this._attachedDepsListeners.set(name, true); - } - // just use cache function - return this._getCache(name, getter); - } - _getCanvasCache() { - return this._cache.get(CANVAS); - } - /* - * when the logic for a cached result depends on ancestor propagation, use this - * method to clear self and children cache - */ - _clearSelfAndDescendantCache(attr, forceEvent) { - this._clearCache(attr); - // trigger clear cache, so transformer can use it - if (attr === ABSOLUTE_TRANSFORM) { - this.fire('absoluteTransformChange'); - } - } - /** - * clear cached canvas - * @method - * @name Konva.Node#clearCache - * @returns {Konva.Node} - * @example - * node.clearCache(); - */ - clearCache() { - this._cache.delete(CANVAS); - this._clearSelfAndDescendantCache(); - return this; - } - /** - * 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.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] - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Number} [config.offset] increase canvas size by `offset` pixel in all directions. - * @param {Boolean} [config.drawBorder] when set to true, a red border will be drawn around the cached - * region for debugging purposes - * @param {Number} [config.pixelRatio] change quality (or pixel ratio) of cached image. pixelRatio = 2 will produce 2x sized cache. - * @param {Boolean} [config.imageSmoothingEnabled] control imageSmoothingEnabled property of created canvas for cache - * @returns {Konva.Node} - * @example - * // cache a shape with the x,y position of the bounding box at the center and - * // the width and height of the bounding box equal to the width and height of - * // the shape obtained from shape.width() and shape.height() - * image.cache(); - * - * // cache a node and define the bounding box position and size - * node.cache({ - * x: -30, - * y: -30, - * width: 100, - * height: 200 - * }); - * - * // cache a node and draw a red border around the bounding box - * // for debugging purposes - * node.cache({ - * x: -30, - * y: -30, - * width: 100, - * height: 200, - * offset : 10, - * drawBorder: true - * }); - */ - cache(config) { - var conf = config || {}; - var rect = {}; - // don't call getClientRect if we have all attributes - // it means call it only if have one undefined - if ( - conf.x === undefined || - conf.y === undefined || - conf.width === undefined || - conf.height === undefined - ) { - rect = this.getClientRect({ - skipTransform: true, - relativeTo: this.getParent(), - }); - } - var width = Math.ceil(conf.width || rect.width), - height = Math.ceil(conf.height || rect.height), - pixelRatio = conf.pixelRatio, - x = conf.x === undefined ? rect.x : conf.x, - y = conf.y === undefined ? rect.y : conf.y, - offset = conf.offset || 0, - drawBorder = conf.drawBorder || false; - if (!width || !height) { - Util.error( - 'Can not cache the node. Width or height of the node equals 0. Caching is skipped.' - ); - return; - } - width += offset * 2; - height += offset * 2; - x -= offset; - y -= offset; - var cachedSceneCanvas = new SceneCanvas({ - pixelRatio: pixelRatio, - width: width, - height: height, - }), - cachedFilterCanvas = new SceneCanvas({ - pixelRatio: pixelRatio, - width: 0, - height: 0, - }), - cachedHitCanvas = new HitCanvas({ - pixelRatio: 1, - width: width, - height: height, - }), - sceneContext = cachedSceneCanvas.getContext(), - hitContext = cachedHitCanvas.getContext(); - cachedHitCanvas.isCache = true; - cachedSceneCanvas.isCache = true; - this._cache.delete('canvas'); - this._filterUpToDate = false; - if (conf.imageSmoothingEnabled === false) { - cachedSceneCanvas.getContext()._context.imageSmoothingEnabled = false; - cachedFilterCanvas.getContext()._context.imageSmoothingEnabled = false; - } - sceneContext.save(); - hitContext.save(); - sceneContext.translate(-x, -y); - hitContext.translate(-x, -y); - // extra flag to skip on getAbsolute opacity calc - this._isUnderCache = true; - this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); - this._clearSelfAndDescendantCache(ABSOLUTE_SCALE); - this.drawScene(cachedSceneCanvas, this); - this.drawHit(cachedHitCanvas, this); - this._isUnderCache = false; - sceneContext.restore(); - hitContext.restore(); - // this will draw a red border around the cached box for - // debugging purposes - if (drawBorder) { - sceneContext.save(); - sceneContext.beginPath(); - sceneContext.rect(0, 0, width, height); - sceneContext.closePath(); - sceneContext.setAttr('strokeStyle', 'red'); - sceneContext.setAttr('lineWidth', 5); - sceneContext.stroke(); - sceneContext.restore(); - } - this._cache.set(CANVAS, { - scene: cachedSceneCanvas, - filter: cachedFilterCanvas, - hit: cachedHitCanvas, - x: x, - y: y, - }); - return this; - } - /** - * determine if node is currently cached - * @method - * @name Konva.Node#isCached - * @returns {Boolean} - */ - isCached() { - return this._cache.has('canvas'); - } - /** - * Return client rectangle {x, y, width, height} of node. This rectangle also include all styling (strokes, shadows, etc). - * The purpose of the method is similar to getBoundingClientRect API of the DOM. - * @method - * @name Konva.Node#getClientRect - * @param {Object} config - * @param {Boolean} [config.skipTransform] should we apply transform to node for calculating rect? - * @param {Boolean} [config.skipShadow] should we apply shadow to the node for calculating bound box? - * @param {Boolean} [config.skipStroke] should we apply stroke to the node for calculating bound box? - * @param {Object} [config.relativeTo] calculate client rect relative to one of the parents - * @returns {Object} rect with {x, y, width, height} properties - * @example - * var rect = new Konva.Rect({ - * width : 100, - * height : 100, - * x : 50, - * y : 50, - * strokeWidth : 4, - * stroke : 'black', - * offsetX : 50, - * scaleY : 2 - * }); - * - * // get client rect without think off transformations (position, rotation, scale, offset, etc) - * rect.getClientRect({ skipTransform: true}); - * // returns { - * // x : -2, // two pixels for stroke / 2 - * // y : -2, - * // width : 104, // increased by 4 for stroke - * // height : 104 - * //} - * - * // get client rect with transformation applied - * rect.getClientRect(); - * // returns Object {x: -2, y: 46, width: 104, height: 208} - */ - getClientRect(config) { - // abstract method - // redefine in Container and Shape - throw new Error('abstract "getClientRect" method call'); - } - _transformedRect(rect, top) { - var points = [ - { x: rect.x, y: rect.y }, - { x: rect.x + rect.width, y: rect.y }, - { x: rect.x + rect.width, y: rect.y + rect.height }, - { x: rect.x, y: rect.y + rect.height }, - ]; - var minX, minY, maxX, maxY; - var trans = this.getAbsoluteTransform(top); - points.forEach(function (point) { - var transformed = trans.point(point); - if (minX === undefined) { - minX = maxX = transformed.x; - minY = maxY = transformed.y; - } - minX = Math.min(minX, transformed.x); - minY = Math.min(minY, transformed.y); - maxX = Math.max(maxX, transformed.x); - maxY = Math.max(maxY, transformed.y); - }); - return { - x: minX, - y: minY, - width: maxX - minX, - height: maxY - minY, - }; - } - _drawCachedSceneCanvas(context) { - context.save(); - context._applyOpacity(this); - context._applyGlobalCompositeOperation(this); - const canvasCache = this._getCanvasCache(); - context.translate(canvasCache.x, canvasCache.y); - var cacheCanvas = this._getCachedSceneCanvas(); - var ratio = cacheCanvas.pixelRatio; - context.drawImage( - cacheCanvas._canvas, - 0, - 0, - cacheCanvas.width / ratio, - cacheCanvas.height / ratio - ); - context.restore(); - } - _drawCachedHitCanvas(context) { - var canvasCache = this._getCanvasCache(), - hitCanvas = canvasCache.hit; - context.save(); - context.translate(canvasCache.x, canvasCache.y); - context.drawImage(hitCanvas._canvas, 0, 0); - context.restore(); - } - _getCachedSceneCanvas() { - var filters = this.filters(), - cachedCanvas = this._getCanvasCache(), - sceneCanvas = cachedCanvas.scene, - filterCanvas = cachedCanvas.filter, - filterContext = filterCanvas.getContext(), - len, - imageData, - n, - filter; - if (filters) { - if (!this._filterUpToDate) { - var ratio = sceneCanvas.pixelRatio; - filterCanvas.setSize( - sceneCanvas.width / sceneCanvas.pixelRatio, - sceneCanvas.height / sceneCanvas.pixelRatio - ); - try { - len = filters.length; - filterContext.clear(); - // copy cached canvas onto filter context - filterContext.drawImage( - sceneCanvas._canvas, - 0, - 0, - sceneCanvas.getWidth() / ratio, - sceneCanvas.getHeight() / ratio - ); - imageData = filterContext.getImageData( - 0, - 0, - filterCanvas.getWidth(), - filterCanvas.getHeight() - ); - // apply filters to filter context - for (n = 0; n < len; n++) { - filter = filters[n]; - if (typeof filter !== 'function') { - Util.error( - 'Filter should be type of function, but got ' + - typeof filter + - ' instead. Please check correct filters' - ); - continue; - } - filter.call(this, imageData); - filterContext.putImageData(imageData, 0, 0); - } - } catch (e) { - Util.error( - 'Unable to apply filter. ' + - e.message + - ' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.' - ); + _clearCache(attr) { + // if we want to clear transform cache + // we don't really need to remove it from the cache + // but instead mark as "dirty" + // so we don't need to create a new instance next time + if ((attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM) && + this._cache.get(attr)) { + this._cache.get(attr).dirty = true; + } + else if (attr) { + this._cache.delete(attr); + } + else { + this._cache.clear(); } - this._filterUpToDate = true; - } - return filterCanvas; } - return sceneCanvas; - } - /** - * bind events to the node. KonvaJS supports mouseover, mousemove, - * mouseout, mouseenter, mouseleave, mousedown, mouseup, wheel, contextmenu, click, dblclick, touchstart, touchmove, - * touchend, tap, dbltap, dragstart, dragmove, and dragend events. - * Pass in a string of events delimited by a space to bind multiple events at once - * such as 'mousedown mouseup mousemove'. Include a namespace to bind an - * event by name such as 'click.foobar'. - * @method - * @name Konva.Node#on - * @param {String} evtStr e.g. 'click', 'mousedown touchstart', 'mousedown.foo touchstart.foo' - * @param {Function} handler The handler function. The first argument of that function is event object. Event object has `target` as main target of the event, `currentTarget` as current node listener and `evt` as native browser event. - * @returns {Konva.Node} - * @example - * // add click listener - * node.on('click', function() { - * console.log('you clicked me!'); - * }); - * - * // get the target node - * node.on('click', function(evt) { - * console.log(evt.target); - * }); - * - * // stop event propagation - * node.on('click', function(evt) { - * evt.cancelBubble = true; - * }); - * - * // bind multiple listeners - * node.on('click touchstart', function() { - * console.log('you clicked/touched me!'); - * }); - * - * // namespace listener - * node.on('click.foo', function() { - * console.log('you clicked/touched me!'); - * }); - * - * // get the event type - * node.on('click tap', function(evt) { - * var eventType = evt.type; - * }); - * - * // get native event object - * node.on('click tap', function(evt) { - * var nativeEvent = evt.evt; - * }); - * - * // for change events, get the old and new val - * node.on('xChange', function(evt) { - * var oldVal = evt.oldVal; - * var newVal = evt.newVal; - * }); - * - * // get event targets - * // with event delegations - * layer.on('click', 'Group', function(evt) { - * var shape = evt.target; - * var group = evt.currentTarget; - * }); - */ - on(evtStr, handler) { - this._cache && this._cache.delete(ALL_LISTENERS); - if (arguments.length === 3) { - return this._delegate.apply(this, arguments); + _getCache(attr, privateGetter) { + var cache = this._cache.get(attr); + // for transform the cache can be NOT empty + // but we still need to recalculate it if it is dirty + var isTransform = attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM; + var invalid = cache === undefined || (isTransform && cache.dirty === true); + // if not cached, we need to set it using the private getter method. + if (invalid) { + cache = privateGetter.call(this); + this._cache.set(attr, cache); + } + return cache; + } + _calculate(name, deps, getter) { + // if we are trying to calculate function for the first time + // we need to attach listeners for change events + if (!this._attachedDepsListeners.get(name)) { + const depsString = deps.map((dep) => dep + 'Change.konva').join(SPACE$1); + this.on(depsString, () => { + this._clearCache(name); + }); + this._attachedDepsListeners.set(name, true); + } + // just use cache function + return this._getCache(name, getter); + } + _getCanvasCache() { + return this._cache.get(CANVAS); } - var events = evtStr.split(SPACE$1), - len = events.length, - n, - event, - parts, - baseEvent, - name; /* - * loop through types and attach event listeners to - * each one. eg. 'click mouseover.namespace mouseout' - * will create three event bindings + * when the logic for a cached result depends on ancestor propagation, use this + * method to clear self and children cache */ - for (n = 0; n < len; n++) { - event = events[n]; - parts = event.split('.'); - baseEvent = parts[0]; - name = parts[1] || ''; - // create events array if it doesn't exist - if (!this.eventListeners[baseEvent]) { - this.eventListeners[baseEvent] = []; - } - this.eventListeners[baseEvent].push({ - name: name, - handler: handler, - }); - } - return this; - } - /** - * remove event bindings from the node. Pass in a string of - * event types delimmited by a space to remove multiple event - * bindings at once such as 'mousedown mouseup mousemove'. - * include a namespace to remove an event binding by name - * such as 'click.foobar'. If you only give a name like '.foobar', - * all events in that namespace will be removed. - * @method - * @name Konva.Node#off - * @param {String} evtStr e.g. 'click', 'mousedown touchstart', '.foobar' - * @returns {Konva.Node} - * @example - * // remove listener - * node.off('click'); - * - * // remove multiple listeners - * node.off('click touchstart'); - * - * // remove listener by name - * node.off('click.foo'); - */ - off(evtStr, callback) { - var events = (evtStr || '').split(SPACE$1), - len = events.length, - n, - t, - event, - parts, - baseEvent, - name; - this._cache && this._cache.delete(ALL_LISTENERS); - if (!evtStr) { - // remove all events - for (t in this.eventListeners) { - this._off(t); - } - } - for (n = 0; n < len; n++) { - event = events[n]; - parts = event.split('.'); - baseEvent = parts[0]; - name = parts[1]; - if (baseEvent) { - if (this.eventListeners[baseEvent]) { - this._off(baseEvent, name, callback); + _clearSelfAndDescendantCache(attr, forceEvent) { + this._clearCache(attr); + // trigger clear cache, so transformer can use it + if (attr === ABSOLUTE_TRANSFORM) { + this.fire('absoluteTransformChange'); } - } else { - for (t in this.eventListeners) { - this._off(t, name, callback); - } - } } - return this; - } - // some event aliases for third party integration like HammerJS - dispatchEvent(evt) { - var e = { - target: this, - type: evt.type, - evt: evt, - }; - this.fire(evt.type, e); - return this; - } - addEventListener(type, handler) { - // we have to pass native event to handler - this.on(type, function (evt) { - handler.call(this, evt.evt); - }); - return this; - } - removeEventListener(type) { - this.off(type); - return this; - } - // like node.on - _delegate(event, selector, handler) { - var stopNode = this; - this.on(event, function (evt) { - var targets = evt.target.findAncestors(selector, true, stopNode); - for (var i = 0; i < targets.length; i++) { - evt = Util.cloneObject(evt); - evt.currentTarget = targets[i]; - handler.call(targets[i], evt); - } - }); - } - /** - * remove a node from parent, but don't destroy. You can reuse the node later. - * @method - * @name Konva.Node#remove - * @returns {Konva.Node} - * @example - * node.remove(); - */ - remove() { - if (this.isDragging()) { - this.stopDrag(); - } - // we can have drag element but that is not dragged yet - // so just clear it - DD._dragElements.delete(this._id); - this._remove(); - return this; - } - _clearCaches() { - this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); - this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); - this._clearSelfAndDescendantCache(ABSOLUTE_SCALE); - this._clearSelfAndDescendantCache(STAGE$1); - this._clearSelfAndDescendantCache(VISIBLE); - this._clearSelfAndDescendantCache(LISTENING); - } - _remove() { - // every cached attr that is calculated via node tree - // traversal must be cleared when removing a node - this._clearCaches(); - var parent = this.getParent(); - if (parent && parent.children) { - parent.children.splice(this.index, 1); - parent._setChildrenIndices(); - this.parent = null; - } - } - /** - * remove and destroy a node. Kill it and delete forever! You should not reuse node after destroy(). - * If the node is a container (Group, Stage or Layer) it will destroy all children too. - * @method - * @name Konva.Node#destroy - * @example - * node.destroy(); - */ - destroy() { - // remove from ids and names hashes - _removeId(this.id(), this); - // remove all names - 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(); - return this; - } - /** - * get attr - * @method - * @name Konva.Node#getAttr - * @param {String} attr - * @returns {Integer|String|Object|Array} - * @example - * var x = node.getAttr('x'); - */ - getAttr(attr) { - var method = 'get' + Util._capitalize(attr); - if (Util._isFunction(this[method])) { - return this[method](); - } - // otherwise get directly - return this.attrs[attr]; - } - /** - * get ancestors - * @method - * @name Konva.Node#getAncestors - * @returns {Array} - * @example - * shape.getAncestors().forEach(function(node) { - * console.log(node.getId()); - * }) - */ - getAncestors() { - var parent = this.getParent(), - ancestors = []; - while (parent) { - ancestors.push(parent); - parent = parent.getParent(); - } - return ancestors; - } - /** - * get attrs object literal - * @method - * @name Konva.Node#getAttrs - * @returns {Object} - */ - getAttrs() { - return this.attrs || {}; - } - /** - * set multiple attrs at once using an object literal - * @method - * @name Konva.Node#setAttrs - * @param {Object} config object containing key value pairs - * @returns {Konva.Node} - * @example - * node.setAttrs({ - * x: 5, - * fill: 'red' - * }); - */ - setAttrs(config) { - this._batchTransformChanges(() => { - var key, method; - if (!config) { + /** + * clear cached canvas + * @method + * @name Konva.Node#clearCache + * @returns {Konva.Node} + * @example + * node.clearCache(); + */ + clearCache() { + this._cache.delete(CANVAS); + this._clearSelfAndDescendantCache(); + this._requestDraw(); return this; - } - for (key in config) { - if (key === CHILDREN) { - continue; + } + /** + * 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.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] + * @param {Number} [config.x] + * @param {Number} [config.y] + * @param {Number} [config.width] + * @param {Number} [config.height] + * @param {Number} [config.offset] increase canvas size by `offset` pixel in all directions. + * @param {Boolean} [config.drawBorder] when set to true, a red border will be drawn around the cached + * region for debugging purposes + * @param {Number} [config.pixelRatio] change quality (or pixel ratio) of cached image. pixelRatio = 2 will produce 2x sized cache. + * @param {Boolean} [config.imageSmoothingEnabled] control imageSmoothingEnabled property of created canvas for cache + * @param {Number} [config.hitCanvasPixelRatio] change quality (or pixel ratio) of cached hit canvas. + * @returns {Konva.Node} + * @example + * // cache a shape with the x,y position of the bounding box at the center and + * // the width and height of the bounding box equal to the width and height of + * // the shape obtained from shape.width() and shape.height() + * image.cache(); + * + * // cache a node and define the bounding box position and size + * node.cache({ + * x: -30, + * y: -30, + * width: 100, + * height: 200 + * }); + * + * // cache a node and draw a red border around the bounding box + * // for debugging purposes + * node.cache({ + * x: -30, + * y: -30, + * width: 100, + * height: 200, + * offset : 10, + * drawBorder: true + * }); + */ + cache(config) { + var conf = config || {}; + var rect = {}; + // don't call getClientRect if we have all attributes + // it means call it only if have one undefined + if (conf.x === undefined || + conf.y === undefined || + conf.width === undefined || + conf.height === undefined) { + rect = this.getClientRect({ + skipTransform: true, + relativeTo: this.getParent(), + }); } - method = SET + Util._capitalize(key); - // use setter if available - if (Util._isFunction(this[method])) { - this[method](config[key]); - } else { - // otherwise set directly - this._setAttr(key, config[key]); + var width = Math.ceil(conf.width || rect.width), height = Math.ceil(conf.height || rect.height), pixelRatio = conf.pixelRatio, x = conf.x === undefined ? rect.x : conf.x, y = conf.y === undefined ? rect.y : conf.y, offset = conf.offset || 0, drawBorder = conf.drawBorder || false, hitCanvasPixelRatio = conf.hitCanvasPixelRatio || 1; + if (!width || !height) { + Util.error('Can not cache the node. Width or height of the node equals 0. Caching is skipped.'); + return; } - } - }); - return this; - } - /** - * determine if node is listening for events by taking into account ancestors. - * - * Parent | Self | isListening - * listening | listening | - * ----------+-----------+------------ - * T | T | T - * T | F | F - * F | T | F - * F | F | F - * - * @method - * @name Konva.Node#isListening - * @returns {Boolean} - */ - isListening() { - return this._getCache(LISTENING, this._isListening); - } - _isListening(relativeTo) { - const listening = this.listening(); - if (!listening) { - return false; - } - const parent = this.getParent(); - if (parent && parent !== relativeTo && this !== relativeTo) { - return parent._isListening(relativeTo); - } else { - return true; - } - } - /** - * determine if node is visible by taking into account ancestors. - * - * Parent | Self | isVisible - * visible | visible | - * ----------+-----------+------------ - * T | T | T - * T | F | F - * F | T | F - * F | F | F - * @method - * @name Konva.Node#isVisible - * @returns {Boolean} - */ - isVisible() { - return this._getCache(VISIBLE, this._isVisible); - } - _isVisible(relativeTo) { - const visible = this.visible(); - if (!visible) { - return false; - } - const parent = this.getParent(); - if (parent && parent !== relativeTo && this !== relativeTo) { - return parent._isVisible(relativeTo); - } else { - return true; - } - } - shouldDrawHit(top, skipDragCheck = false) { - if (top) { - return this._isVisible(top) && this._isListening(top); - } - var layer = this.getLayer(); - var layerUnderDrag = false; - DD._dragElements.forEach((elem) => { - if (elem.dragStatus !== 'dragging') { - return; - } else if (elem.node.nodeType === 'Stage') { - layerUnderDrag = true; - } else if (elem.node.getLayer() === layer) { - layerUnderDrag = true; - } - }); - var dragSkip = - !skipDragCheck && !Konva$2.hitOnDragEnabled && layerUnderDrag; - return this.isListening() && this.isVisible() && !dragSkip; - } - /** - * show node. set visible = true - * @method - * @name Konva.Node#show - * @returns {Konva.Node} - */ - show() { - this.visible(true); - return this; - } - /** - * hide node. Hidden nodes are no longer detectable - * @method - * @name Konva.Node#hide - * @returns {Konva.Node} - */ - hide() { - this.visible(false); - return this; - } - getZIndex() { - return this.index || 0; - } - /** - * get absolute z-index which takes into account sibling - * and ancestor indices - * @method - * @name Konva.Node#getAbsoluteZIndex - * @returns {Integer} - */ - getAbsoluteZIndex() { - var depth = this.getDepth(), - that = this, - index = 0, - nodes, - len, - n, - child; - function addChildren(children) { - nodes = []; - len = children.length; - for (n = 0; n < len; n++) { - child = children[n]; - index++; - if (child.nodeType !== SHAPE) { - nodes = nodes.concat(child.getChildren().slice()); + width += offset * 2; + height += offset * 2; + x -= offset; + y -= offset; + var cachedSceneCanvas = new SceneCanvas({ + pixelRatio: pixelRatio, + width: width, + height: height, + }), cachedFilterCanvas = new SceneCanvas({ + pixelRatio: pixelRatio, + width: 0, + height: 0, + }), cachedHitCanvas = new HitCanvas({ + pixelRatio: hitCanvasPixelRatio, + width: width, + height: height, + }), sceneContext = cachedSceneCanvas.getContext(), hitContext = cachedHitCanvas.getContext(); + cachedHitCanvas.isCache = true; + cachedSceneCanvas.isCache = true; + this._cache.delete(CANVAS); + this._filterUpToDate = false; + if (conf.imageSmoothingEnabled === false) { + cachedSceneCanvas.getContext()._context.imageSmoothingEnabled = false; + cachedFilterCanvas.getContext()._context.imageSmoothingEnabled = false; } - if (child._id === that._id) { - n = len; + sceneContext.save(); + hitContext.save(); + sceneContext.translate(-x, -y); + hitContext.translate(-x, -y); + // extra flag to skip on getAbsolute opacity calc + this._isUnderCache = true; + this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); + this._clearSelfAndDescendantCache(ABSOLUTE_SCALE); + this.drawScene(cachedSceneCanvas, this); + this.drawHit(cachedHitCanvas, this); + this._isUnderCache = false; + sceneContext.restore(); + hitContext.restore(); + // this will draw a red border around the cached box for + // debugging purposes + if (drawBorder) { + sceneContext.save(); + sceneContext.beginPath(); + sceneContext.rect(0, 0, width, height); + sceneContext.closePath(); + sceneContext.setAttr('strokeStyle', 'red'); + sceneContext.setAttr('lineWidth', 5); + sceneContext.stroke(); + sceneContext.restore(); } - } - if (nodes.length > 0 && nodes[0].getDepth() <= depth) { - addChildren(nodes); - } + this._cache.set(CANVAS, { + scene: cachedSceneCanvas, + filter: cachedFilterCanvas, + hit: cachedHitCanvas, + x: x, + y: y, + }); + this._requestDraw(); + return this; } - if (that.nodeType !== UPPER_STAGE) { - addChildren(that.getStage().getChildren()); + /** + * determine if node is currently cached + * @method + * @name Konva.Node#isCached + * @returns {Boolean} + */ + isCached() { + return this._cache.has(CANVAS); } - return index; - } - /** - * get node depth in node tree. Returns an integer. - * e.g. Stage depth will always be 0. Layers will always be 1. Groups and Shapes will always - * be >= 2 - * @method - * @name Konva.Node#getDepth - * @returns {Integer} - */ - getDepth() { - var depth = 0, - parent = this.parent; - while (parent) { - depth++; - parent = parent.parent; + /** + * Return client rectangle {x, y, width, height} of node. This rectangle also include all styling (strokes, shadows, etc). + * The purpose of the method is similar to getBoundingClientRect API of the DOM. + * @method + * @name Konva.Node#getClientRect + * @param {Object} config + * @param {Boolean} [config.skipTransform] should we apply transform to node for calculating rect? + * @param {Boolean} [config.skipShadow] should we apply shadow to the node for calculating bound box? + * @param {Boolean} [config.skipStroke] should we apply stroke to the node for calculating bound box? + * @param {Object} [config.relativeTo] calculate client rect relative to one of the parents + * @returns {Object} rect with {x, y, width, height} properties + * @example + * var rect = new Konva.Rect({ + * width : 100, + * height : 100, + * x : 50, + * y : 50, + * strokeWidth : 4, + * stroke : 'black', + * offsetX : 50, + * scaleY : 2 + * }); + * + * // get client rect without think off transformations (position, rotation, scale, offset, etc) + * rect.getClientRect({ skipTransform: true}); + * // returns { + * // x : -2, // two pixels for stroke / 2 + * // y : -2, + * // width : 104, // increased by 4 for stroke + * // height : 104 + * //} + * + * // get client rect with transformation applied + * rect.getClientRect(); + * // returns Object {x: -2, y: 46, width: 104, height: 208} + */ + getClientRect(config) { + // abstract method + // redefine in Container and Shape + throw new Error('abstract "getClientRect" method call'); } - return depth; - } - // sometimes we do several attributes changes - // like node.position(pos) - // for performance reasons, lets batch transform reset - // so it work faster - _batchTransformChanges(func) { - this._batchingTransformChange = true; - func(); - this._batchingTransformChange = false; - if (this._needClearTransformCache) { - this._clearCache(TRANSFORM); - this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM, true); + _transformedRect(rect, top) { + var points = [ + { x: rect.x, y: rect.y }, + { x: rect.x + rect.width, y: rect.y }, + { x: rect.x + rect.width, y: rect.y + rect.height }, + { x: rect.x, y: rect.y + rect.height }, + ]; + var minX, minY, maxX, maxY; + var trans = this.getAbsoluteTransform(top); + points.forEach(function (point) { + var transformed = trans.point(point); + if (minX === undefined) { + minX = maxX = transformed.x; + minY = maxY = transformed.y; + } + minX = Math.min(minX, transformed.x); + minY = Math.min(minY, transformed.y); + maxX = Math.max(maxX, transformed.x); + maxY = Math.max(maxY, transformed.y); + }); + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY, + }; } - this._needClearTransformCache = false; - } - setPosition(pos) { - this._batchTransformChanges(() => { - this.x(pos.x); - this.y(pos.y); - }); - return this; - } - getPosition() { - return { - x: this.x(), - y: this.y(), - }; - } - /** - * get absolute position of a node. That function can be used to calculate absolute position, but relative to any ancestor - * @method - * @name Konva.Node#getAbsolutePosition - * @param {Object} Ancestor optional ancestor node - * @returns {Konva.Node} - * @example - * - * // returns absolute position relative to top-left corner of canvas - * node.getAbsolutePosition(); - * - * // calculate absolute position of node, inside stage - * // so stage transforms are ignored - * node.getAbsolutePosition(stage) - */ - getAbsolutePosition(top) { - let haveCachedParent = false; - let parent = this.parent; - while (parent) { - if (parent.isCached()) { - haveCachedParent = true; - break; - } - parent = parent.parent; + _drawCachedSceneCanvas(context) { + context.save(); + context._applyOpacity(this); + context._applyGlobalCompositeOperation(this); + const canvasCache = this._getCanvasCache(); + context.translate(canvasCache.x, canvasCache.y); + var cacheCanvas = this._getCachedSceneCanvas(); + var ratio = cacheCanvas.pixelRatio; + context.drawImage(cacheCanvas._canvas, 0, 0, cacheCanvas.width / ratio, cacheCanvas.height / ratio); + context.restore(); } - if (haveCachedParent && !top) { - // make fake top element - // "true" is not a node, but it will just allow skip all caching - top = true; + _drawCachedHitCanvas(context) { + var canvasCache = this._getCanvasCache(), hitCanvas = canvasCache.hit; + context.save(); + context.translate(canvasCache.x, canvasCache.y); + context.drawImage(hitCanvas._canvas, 0, 0, hitCanvas.width / hitCanvas.pixelRatio, hitCanvas.height / hitCanvas.pixelRatio); + context.restore(); } - var absoluteMatrix = this.getAbsoluteTransform(top).getMatrix(), - absoluteTransform = new Transform(), - offset = this.offset(); - // clone the matrix array - absoluteTransform.m = absoluteMatrix.slice(); - absoluteTransform.translate(offset.x, offset.y); - return absoluteTransform.getTranslation(); - } - setAbsolutePosition(pos) { - var origTrans = this._clearTransform(); - // don't clear translation - this.attrs.x = origTrans.x; - this.attrs.y = origTrans.y; - delete origTrans.x; - delete origTrans.y; - // important, use non cached value - this._clearCache(TRANSFORM); - var it = this._getAbsoluteTransform().copy(); - it.invert(); - it.translate(pos.x, pos.y); - pos = { - x: this.attrs.x + it.getTranslation().x, - y: this.attrs.y + it.getTranslation().y, - }; - this._setTransform(origTrans); - this.setPosition({ x: pos.x, y: pos.y }); - this._clearCache(TRANSFORM); - this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); - return this; - } - _setTransform(trans) { - var key; - for (key in trans) { - this.attrs[key] = trans[key]; - } - // this._clearCache(TRANSFORM); - // this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); - } - _clearTransform() { - var trans = { - x: this.x(), - y: this.y(), - rotation: this.rotation(), - scaleX: this.scaleX(), - scaleY: this.scaleY(), - offsetX: this.offsetX(), - offsetY: this.offsetY(), - skewX: this.skewX(), - skewY: this.skewY(), - }; - this.attrs.x = 0; - this.attrs.y = 0; - this.attrs.rotation = 0; - this.attrs.scaleX = 1; - this.attrs.scaleY = 1; - this.attrs.offsetX = 0; - this.attrs.offsetY = 0; - this.attrs.skewX = 0; - this.attrs.skewY = 0; - // return original transform - return trans; - } - /** - * move node by an amount relative to its current position - * @method - * @name Konva.Node#move - * @param {Object} change - * @param {Number} change.x - * @param {Number} change.y - * @returns {Konva.Node} - * @example - * // move node in x direction by 1px and y direction by 2px - * node.move({ - * x: 1, - * y: 2 - * }); - */ - move(change) { - var changeX = change.x, - changeY = change.y, - x = this.x(), - y = this.y(); - if (changeX !== undefined) { - x += changeX; - } - if (changeY !== undefined) { - y += changeY; - } - this.setPosition({ x: x, y: y }); - return this; - } - _eachAncestorReverse(func, top) { - var family = [], - parent = this.getParent(), - len, - n; - // if top node is defined, and this node is top node, - // there's no need to build a family tree. just execute - // func with this because it will be the only node - if (top && top._id === this._id) { - // func(this); - return; - } - family.unshift(this); - while (parent && (!top || parent._id !== top._id)) { - family.unshift(parent); - parent = parent.parent; - } - len = family.length; - for (n = 0; n < len; n++) { - func(family[n]); - } - } - /** - * rotate node by an amount in degrees relative to its current rotation - * @method - * @name Konva.Node#rotate - * @param {Number} theta - * @returns {Konva.Node} - */ - rotate(theta) { - this.rotation(this.rotation() + theta); - return this; - } - /** - * move node to the top of its siblings - * @method - * @name Konva.Node#moveToTop - * @returns {Boolean} - */ - moveToTop() { - if (!this.parent) { - Util.warn('Node has no parent. moveToTop function is ignored.'); - return false; - } - var index = this.index; - this.parent.children.splice(index, 1); - this.parent.children.push(this); - this.parent._setChildrenIndices(); - return true; - } - /** - * move node up - * @method - * @name Konva.Node#moveUp - * @returns {Boolean} flag is moved or not - */ - moveUp() { - if (!this.parent) { - Util.warn('Node has no parent. moveUp function is ignored.'); - return false; - } - var index = this.index, - len = this.parent.getChildren().length; - if (index < len - 1) { - this.parent.children.splice(index, 1); - this.parent.children.splice(index + 1, 0, this); - this.parent._setChildrenIndices(); - return true; - } - return false; - } - /** - * move node down - * @method - * @name Konva.Node#moveDown - * @returns {Boolean} - */ - moveDown() { - if (!this.parent) { - Util.warn('Node has no parent. moveDown function is ignored.'); - return false; - } - var index = this.index; - if (index > 0) { - this.parent.children.splice(index, 1); - this.parent.children.splice(index - 1, 0, this); - this.parent._setChildrenIndices(); - return true; - } - return false; - } - /** - * move node to the bottom of its siblings - * @method - * @name Konva.Node#moveToBottom - * @returns {Boolean} - */ - moveToBottom() { - if (!this.parent) { - Util.warn('Node has no parent. moveToBottom function is ignored.'); - return false; - } - var index = this.index; - if (index > 0) { - this.parent.children.splice(index, 1); - this.parent.children.unshift(this); - this.parent._setChildrenIndices(); - return true; - } - return false; - } - setZIndex(zIndex) { - if (!this.parent) { - Util.warn('Node has no parent. zIndex parameter is ignored.'); - return this; - } - if (zIndex < 0 || zIndex >= this.parent.children.length) { - Util.warn( - 'Unexpected value ' + - zIndex + - ' 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 index = this.index; - this.parent.children.splice(index, 1); - this.parent.children.splice(zIndex, 0, this); - this.parent._setChildrenIndices(); - return this; - } - /** - * get absolute opacity - * @method - * @name Konva.Node#getAbsoluteOpacity - * @returns {Number} - */ - getAbsoluteOpacity() { - return this._getCache(ABSOLUTE_OPACITY, this._getAbsoluteOpacity); - } - _getAbsoluteOpacity() { - var absOpacity = this.opacity(); - var parent = this.getParent(); - if (parent && !parent._isUnderCache) { - absOpacity *= parent.getAbsoluteOpacity(); - } - return absOpacity; - } - /** - * move node to another container - * @method - * @name Konva.Node#moveTo - * @param {Container} newContainer - * @returns {Konva.Node} - * @example - * // move node from current layer into layer2 - * node.moveTo(layer2); - */ - moveTo(newContainer) { - // do nothing if new container is already parent - if (this.getParent() !== newContainer) { - this._remove(); - newContainer.add(this); - } - return this; - } - /** - * convert Node into an object for serialization. Returns an object. - * @method - * @name Konva.Node#toObject - * @returns {Object} - */ - toObject() { - var obj = {}, - attrs = this.getAttrs(), - key, - val, - getter, - defaultValue, - nonPlainObject; - obj.attrs = {}; - for (key in attrs) { - val = attrs[key]; - // if value is object and object is not plain - // like class instance, we should skip it and to not include - nonPlainObject = - Util.isObject(val) && - !Util._isPlainObject(val) && - !Util._isArray(val); - if (nonPlainObject) { - continue; - } - getter = typeof this[key] === 'function' && this[key]; - // remove attr value so that we can extract the default value from the getter - delete attrs[key]; - defaultValue = getter ? getter.call(this) : null; - // restore attr value - attrs[key] = val; - if (defaultValue !== val) { - obj.attrs[key] = val; - } - } - obj.className = this.getClassName(); - return Util._prepareToStringify(obj); - } - /** - * convert Node into a JSON string. Returns a JSON string. - * @method - * @name Konva.Node#toJSON - * @returns {String} - */ - toJSON() { - return JSON.stringify(this.toObject()); - } - /** - * get parent container - * @method - * @name Konva.Node#getParent - * @returns {Konva.Node} - */ - getParent() { - return this.parent; - } - /** - * get all ancestors (parent then parent of the parent, etc) of the node - * @method - * @name Konva.Node#findAncestors - * @param {String} selector selector for search - * @param {Boolean} [includeSelf] show we think that node is ancestro itself? - * @param {Konva.Node} [stopNode] optional node where we need to stop searching (one of ancestors) - * @returns {Array} [ancestors] - * @example - * // get one of the parent group - * var parentGroups = node.findAncestors('Group'); - */ - findAncestors(selector, includeSelf, stopNode) { - var res = []; - if (includeSelf && this._isMatch(selector)) { - res.push(this); - } - var ancestor = this.parent; - while (ancestor) { - if (ancestor === stopNode) { - return res; - } - if (ancestor._isMatch(selector)) { - res.push(ancestor); - } - ancestor = ancestor.parent; - } - return res; - } - isAncestorOf(node) { - return false; - } - /** - * get ancestor (parent or parent of the parent, etc) of the node that match passed selector - * @method - * @name Konva.Node#findAncestor - * @param {String} selector selector for search - * @param {Boolean} [includeSelf] show we think that node is ancestro itself? - * @param {Konva.Node} [stopNode] optional node where we need to stop searching (one of ancestors) - * @returns {Konva.Node} ancestor - * @example - * // get one of the parent group - * var group = node.findAncestors('.mygroup'); - */ - findAncestor(selector, includeSelf, stopNode) { - return this.findAncestors(selector, includeSelf, stopNode)[0]; - } - // is current node match passed selector? - _isMatch(selector) { - if (!selector) { - return false; - } - if (typeof selector === 'function') { - return selector(this); - } - var selectorArr = selector.replace(/ /g, '').split(','), - len = selectorArr.length, - n, - sel; - for (n = 0; n < len; n++) { - sel = selectorArr[n]; - if (!Util.isValidSelector(sel)) { - Util.warn( - 'Selector "' + - sel + - '" is invalid. Allowed selectors examples are "#foo", ".bar" or "Group".' - ); - Util.warn( - 'If you have a custom shape with such className, please change it to start with upper letter like "Triangle".' - ); - Util.warn('Konva is awesome, right?'); - } - // id selector - if (sel.charAt(0) === '#') { - if (this.id() === sel.slice(1)) { - return true; + _getCachedSceneCanvas() { + var filters = this.filters(), cachedCanvas = this._getCanvasCache(), sceneCanvas = cachedCanvas.scene, filterCanvas = cachedCanvas.filter, filterContext = filterCanvas.getContext(), len, imageData, n, filter; + if (filters) { + if (!this._filterUpToDate) { + var ratio = sceneCanvas.pixelRatio; + filterCanvas.setSize(sceneCanvas.width / sceneCanvas.pixelRatio, sceneCanvas.height / sceneCanvas.pixelRatio); + try { + len = filters.length; + filterContext.clear(); + // copy cached canvas onto filter context + filterContext.drawImage(sceneCanvas._canvas, 0, 0, sceneCanvas.getWidth() / ratio, sceneCanvas.getHeight() / ratio); + imageData = filterContext.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()); + // apply filters to filter context + for (n = 0; n < len; n++) { + filter = filters[n]; + if (typeof filter !== 'function') { + Util.error('Filter should be type of function, but got ' + + typeof filter + + ' instead. Please check correct filters'); + continue; + } + filter.call(this, imageData); + filterContext.putImageData(imageData, 0, 0); + } + } + catch (e) { + Util.error('Unable to apply filter. ' + + e.message + + ' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.'); + } + this._filterUpToDate = true; + } + return filterCanvas; } - } else if (sel.charAt(0) === '.') { - // name selector - if (this.hasName(sel.slice(1))) { - return true; + return sceneCanvas; + } + /** + * bind events to the node. KonvaJS supports mouseover, mousemove, + * mouseout, mouseenter, mouseleave, mousedown, mouseup, wheel, contextmenu, click, dblclick, touchstart, touchmove, + * touchend, tap, dbltap, dragstart, dragmove, and dragend events. + * Pass in a string of events delimited by a space to bind multiple events at once + * such as 'mousedown mouseup mousemove'. Include a namespace to bind an + * event by name such as 'click.foobar'. + * @method + * @name Konva.Node#on + * @param {String} evtStr e.g. 'click', 'mousedown touchstart', 'mousedown.foo touchstart.foo' + * @param {Function} handler The handler function. The first argument of that function is event object. Event object has `target` as main target of the event, `currentTarget` as current node listener and `evt` as native browser event. + * @returns {Konva.Node} + * @example + * // add click listener + * node.on('click', function() { + * console.log('you clicked me!'); + * }); + * + * // get the target node + * node.on('click', function(evt) { + * console.log(evt.target); + * }); + * + * // stop event propagation + * node.on('click', function(evt) { + * evt.cancelBubble = true; + * }); + * + * // bind multiple listeners + * node.on('click touchstart', function() { + * console.log('you clicked/touched me!'); + * }); + * + * // namespace listener + * node.on('click.foo', function() { + * console.log('you clicked/touched me!'); + * }); + * + * // get the event type + * node.on('click tap', function(evt) { + * var eventType = evt.type; + * }); + * + * // get native event object + * node.on('click tap', function(evt) { + * var nativeEvent = evt.evt; + * }); + * + * // for change events, get the old and new val + * node.on('xChange', function(evt) { + * var oldVal = evt.oldVal; + * var newVal = evt.newVal; + * }); + * + * // get event targets + * // with event delegations + * layer.on('click', 'Group', function(evt) { + * var shape = evt.target; + * var group = evt.currentTarget; + * }); + */ + on(evtStr, handler) { + this._cache && this._cache.delete(ALL_LISTENERS); + if (arguments.length === 3) { + return this._delegate.apply(this, arguments); } - } else if (this.className === sel || this.nodeType === sel) { - return true; - } - } - return false; - } - /** - * get layer ancestor - * @method - * @name Konva.Node#getLayer - * @returns {Konva.Layer} - */ - getLayer() { - var parent = this.getParent(); - return parent ? parent.getLayer() : null; - } - /** - * get stage ancestor - * @method - * @name Konva.Node#getStage - * @returns {Konva.Stage} - */ - getStage() { - return this._getCache(STAGE$1, this._getStage); - } - _getStage() { - var parent = this.getParent(); - if (parent) { - return parent.getStage(); - } else { - return undefined; - } - } - /** - * fire event - * @method - * @name Konva.Node#fire - * @param {String} eventType event type. can be a regular event, like click, mouseover, or mouseout, or it can be a custom event, like myCustomEvent - * @param {Event} [evt] event object - * @param {Boolean} [bubble] setting the value to false, or leaving it undefined, will result in the event - * not bubbling. Setting the value to true will result in the event bubbling. - * @returns {Konva.Node} - * @example - * // manually fire click event - * node.fire('click'); - * - * // fire custom event - * node.fire('foo'); - * - * // fire custom event with custom event object - * node.fire('foo', { - * bar: 10 - * }); - * - * // fire click event that bubbles - * node.fire('click', null, true); - */ - fire(eventType, evt = {}, bubble) { - evt.target = evt.target || this; - // bubble - if (bubble) { - this._fireAndBubble(eventType, evt); - } else { - // no bubble - this._fire(eventType, evt); - } - return this; - } - /** - * get absolute transform of the node which takes into - * account its ancestor transforms - * @method - * @name Konva.Node#getAbsoluteTransform - * @returns {Konva.Transform} - */ - getAbsoluteTransform(top) { - // if using an argument, we can't cache the result. - if (top) { - return this._getAbsoluteTransform(top); - } else { - // if no argument, we can cache the result - return this._getCache(ABSOLUTE_TRANSFORM, this._getAbsoluteTransform); - } - } - _getAbsoluteTransform(top) { - var at; - // we we need position relative to an ancestor, we will iterate for all - if (top) { - at = new Transform(); - // start with stage and traverse downwards to self - this._eachAncestorReverse(function (node) { - var transformsEnabled = node.transformsEnabled(); - if (transformsEnabled === 'all') { - at.multiply(node.getTransform()); - } else if (transformsEnabled === 'position') { - at.translate(node.x() - node.offsetX(), node.y() - node.offsetY()); - } - }, top); - return at; - } else { - // try to use a cached value - at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform(); - if (this.parent) { - // transform will be cached - this.parent.getAbsoluteTransform().copyInto(at); - } else { - at.reset(); - } - var transformsEnabled = this.transformsEnabled(); - if (transformsEnabled === 'all') { - at.multiply(this.getTransform()); - } else if (transformsEnabled === 'position') { - // use "attrs" directly, because it is a bit faster - const x = this.attrs.x || 0; - const y = this.attrs.y || 0; - const offsetX = this.attrs.offsetX || 0; - const offsetY = this.attrs.offsetY || 0; - at.translate(x - offsetX, y - offsetY); - } - at.dirty = false; - return at; - } - } - /** - * get absolute scale of the node which takes into - * account its ancestor scales - * @method - * @name Konva.Node#getAbsoluteScale - * @returns {Object} - * @example - * // get absolute scale x - * var scaleX = node.getAbsoluteScale().x; - */ - getAbsoluteScale(top) { - // do not cache this calculations, - // because it use cache transform - // this is special logic for caching with some shapes with shadow - var parent = this; - while (parent) { - if (parent._isUnderCache) { - top = parent; - } - parent = parent.getParent(); - } - const transform = this.getAbsoluteTransform(top); - const attrs = transform.decompose(); - return { - x: attrs.scaleX, - y: attrs.scaleY, - }; - } - /** - * get absolute rotation of the node which takes into - * account its ancestor rotations - * @method - * @name Konva.Node#getAbsoluteRotation - * @returns {Number} - * @example - * // get absolute rotation - * var rotation = node.getAbsoluteRotation(); - */ - getAbsoluteRotation() { - // var parent: Node = this; - // var rotation = 0; - // while (parent) { - // rotation += parent.rotation(); - // parent = parent.getParent(); - // } - // return rotation; - return this.getAbsoluteTransform().decompose().rotation; - } - /** - * get transform of the node - * @method - * @name Konva.Node#getTransform - * @returns {Konva.Transform} - */ - getTransform() { - return this._getCache(TRANSFORM, this._getTransform); - } - _getTransform() { - var _a, _b; - var m = this._cache.get(TRANSFORM) || new Transform(); - m.reset(); - // I was trying to use attributes directly here - // but it doesn't work for Transformer well - // because it overwrite x,y getters - var x = this.x(), - y = this.y(), - rotation = Konva$2.getAngle(this.rotation()), - scaleX = (_a = this.attrs.scaleX) !== null && _a !== void 0 ? _a : 1, - scaleY = (_b = this.attrs.scaleY) !== null && _b !== void 0 ? _b : 1, - skewX = this.attrs.skewX || 0, - skewY = this.attrs.skewY || 0, - offsetX = this.attrs.offsetX || 0, - offsetY = this.attrs.offsetY || 0; - if (x !== 0 || y !== 0) { - m.translate(x, y); - } - if (rotation !== 0) { - m.rotate(rotation); - } - if (skewX !== 0 || skewY !== 0) { - m.skew(skewX, skewY); - } - if (scaleX !== 1 || scaleY !== 1) { - m.scale(scaleX, scaleY); - } - if (offsetX !== 0 || offsetY !== 0) { - m.translate(-1 * offsetX, -1 * offsetY); - } - m.dirty = false; - return m; - } - /** - * clone node. Returns a new Node instance with identical attributes. You can also override - * the node properties with an object literal, enabling you to use an existing node as a template - * for another node - * @method - * @name Konva.Node#clone - * @param {Object} obj override attrs - * @returns {Konva.Node} - * @example - * // simple clone - * var clone = node.clone(); - * - * // clone a node and override the x position - * var clone = rect.clone({ - * x: 5 - * }); - */ - clone(obj) { - // instantiate new node - var attrs = Util.cloneObject(this.attrs), - key, - allListeners, - len, - n, - listener; - // apply attr overrides - for (key in obj) { - attrs[key] = obj[key]; - } - var node = new this.constructor(attrs); - // copy over listeners - for (key in this.eventListeners) { - allListeners = this.eventListeners[key]; - len = allListeners.length; - for (n = 0; n < len; n++) { - listener = allListeners[n]; + var events = evtStr.split(SPACE$1), len = events.length, n, event, parts, baseEvent, name; /* - * don't include konva namespaced listeners because - * these are generated by the constructors + * loop through types and attach event listeners to + * each one. eg. 'click mouseover.namespace mouseout' + * will create three event bindings */ - if (listener.name.indexOf(KONVA) < 0) { - // if listeners array doesn't exist, then create it - if (!node.eventListeners[key]) { - node.eventListeners[key] = []; - } - node.eventListeners[key].push(listener); + for (n = 0; n < len; n++) { + event = events[n]; + parts = event.split('.'); + baseEvent = parts[0]; + name = parts[1] || ''; + // create events array if it doesn't exist + if (!this.eventListeners[baseEvent]) { + this.eventListeners[baseEvent] = []; + } + this.eventListeners[baseEvent].push({ + name: name, + handler: handler, + }); } - } + return this; } - return node; - } - _toKonvaCanvas(config) { - config = config || {}; - var box = this.getClientRect(); - var stage = this.getStage(), - x = config.x !== undefined ? config.x : box.x, - y = config.y !== undefined ? config.y : box.y, - pixelRatio = config.pixelRatio || 1, - canvas = new SceneCanvas({ - width: config.width || box.width || (stage ? stage.width() : 0), - height: config.height || box.height || (stage ? stage.height() : 0), - pixelRatio: pixelRatio, - }), - context = canvas.getContext(); - context.save(); - if (x || y) { - context.translate(-1 * x, -1 * y); - } - this.drawScene(canvas); - context.restore(); - return canvas; - } - /** - * converts node into an canvas element. - * @method - * @name Konva.Node#toCanvas - * @param {Object} config - * @param {Function} config.callback function executed when the composite has completed - * @param {Number} [config.x] x position of canvas section - * @param {Number} [config.y] y position of canvas section - * @param {Number} [config.width] width of canvas section - * @param {Number} [config.height] height of canvas section - * @param {Number} [config.pixelRatio] pixelRatio of output canvas. Default is 1. - * You can use that property to increase quality of the image, for example for super hight quality exports - * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. - * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. - * @example - * var canvas = node.toCanvas(); - */ - toCanvas(config) { - return this._toKonvaCanvas(config)._canvas; - } - /** - * Creates a composite data URL (base64 string). If MIME type is not - * specified, then "image/png" will result. For "image/jpeg", specify a quality - * level as quality (range 0.0 - 1.0) - * @method - * @name Konva.Node#toDataURL - * @param {Object} config - * @param {String} [config.mimeType] can be "image/png" or "image/jpeg". - * "image/png" is the default - * @param {Number} [config.x] x position of canvas section - * @param {Number} [config.y] y position of canvas section - * @param {Number} [config.width] width of canvas section - * @param {Number} [config.height] height of canvas section - * @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType, - * you can specify the quality from 0 to 1, where 0 is very poor quality and 1 - * is very high quality - * @param {Number} [config.pixelRatio] pixelRatio of output image url. Default is 1. - * You can use that property to increase quality of the image, for example for super hight quality exports - * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. - * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. - * @returns {String} - */ - toDataURL(config) { - config = config || {}; - var mimeType = config.mimeType || null, - quality = config.quality || null; - var url = this._toKonvaCanvas(config).toDataURL(mimeType, quality); - if (config.callback) { - config.callback(url); - } - return url; - } - /** - * converts node into an image. Since the toImage - * method is asynchronous, a callback is required. toImage is most commonly used - * to cache complex drawings as an image so that they don't have to constantly be redrawn - * @method - * @name Konva.Node#toImage - * @param {Object} config - * @param {Function} config.callback function executed when the composite has completed - * @param {String} [config.mimeType] can be "image/png" or "image/jpeg". - * "image/png" is the default - * @param {Number} [config.x] x position of canvas section - * @param {Number} [config.y] y position of canvas section - * @param {Number} [config.width] width of canvas section - * @param {Number} [config.height] height of canvas section - * @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType, - * you can specify the quality from 0 to 1, where 0 is very poor quality and 1 - * is very high quality - * @param {Number} [config.pixelRatio] pixelRatio of output image. Default is 1. - * You can use that property to increase quality of the image, for example for super hight quality exports - * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. - * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. - * @example - * var image = node.toImage({ - * callback(img) { - * // do stuff with img - * } - * }); - */ - toImage(config) { - if (!config || !config.callback) { - throw 'callback required for toImage method config argument'; - } - var callback = config.callback; - delete config.callback; - Util._urlToImage(this.toDataURL(config), function (img) { - callback(img); - }); - } - setSize(size) { - this.width(size.width); - this.height(size.height); - return this; - } - getSize() { - return { - width: this.width(), - height: this.height(), - }; - } - /** - * get class name, which may return Stage, Layer, Group, or shape class names like Rect, Circle, Text, etc. - * @method - * @name Konva.Node#getClassName - * @returns {String} - */ - getClassName() { - return this.className || this.nodeType; - } - /** - * get the node type, which may return Stage, Layer, Group, or Shape - * @method - * @name Konva.Node#getType - * @returns {String} - */ - getType() { - return this.nodeType; - } - getDragDistance() { - // compare with undefined because we need to track 0 value - if (this.attrs.dragDistance !== undefined) { - return this.attrs.dragDistance; - } else if (this.parent) { - return this.parent.getDragDistance(); - } else { - return Konva$2.dragDistance; - } - } - _off(type, name, callback) { - var evtListeners = this.eventListeners[type], - i, - evtName, - handler; - for (i = 0; i < evtListeners.length; i++) { - evtName = evtListeners[i].name; - handler = evtListeners[i].handler; - // the following two conditions must be true in order to remove a handler: - // 1) the current event name cannot be konva unless the event name is konva - // this enables developers to force remove a konva specific listener for whatever reason - // 2) an event name is not specified, or if one is specified, it matches the current event name - if ( - (evtName !== 'konva' || name === 'konva') && - (!name || evtName === name) && - (!callback || callback === handler) - ) { - evtListeners.splice(i, 1); - if (evtListeners.length === 0) { - delete this.eventListeners[type]; - break; + /** + * remove event bindings from the node. Pass in a string of + * event types delimmited by a space to remove multiple event + * bindings at once such as 'mousedown mouseup mousemove'. + * include a namespace to remove an event binding by name + * such as 'click.foobar'. If you only give a name like '.foobar', + * all events in that namespace will be removed. + * @method + * @name Konva.Node#off + * @param {String} evtStr e.g. 'click', 'mousedown touchstart', '.foobar' + * @returns {Konva.Node} + * @example + * // remove listener + * node.off('click'); + * + * // remove multiple listeners + * node.off('click touchstart'); + * + * // remove listener by name + * node.off('click.foo'); + */ + off(evtStr, callback) { + var events = (evtStr || '').split(SPACE$1), len = events.length, n, t, event, parts, baseEvent, name; + this._cache && this._cache.delete(ALL_LISTENERS); + if (!evtStr) { + // remove all events + for (t in this.eventListeners) { + this._off(t); + } } - i--; - } - } - } - _fireChangeEvent(attr, oldVal, newVal) { - this._fire(attr + CHANGE, { - oldVal: oldVal, - newVal: newVal, - }); - } - setId(id) { - var oldId = this.id(); - _removeId(oldId, this); - _addId(this, id); - this._setAttr('id', id); - return this; - } - setName(name) { - var oldNames = (this.name() || '').split(/\s/g); - var newNames = (name || '').split(/\s/g); - var subname, i; - // remove all subnames - for (i = 0; i < oldNames.length; i++) { - subname = oldNames[i]; - if (newNames.indexOf(subname) === -1 && subname) { - _removeName(subname, this._id); - } - } - // add new names - for (i = 0; i < newNames.length; i++) { - subname = newNames[i]; - if (oldNames.indexOf(subname) === -1 && subname) { - _addName(this, subname); - } - } - this._setAttr(NAME, name); - return this; - } - /** - * add name to node - * @method - * @name Konva.Node#addName - * @param {String} name - * @returns {Konva.Node} - * @example - * node.name('red'); - * node.addName('selected'); - * node.name(); // return 'red selected' - */ - addName(name) { - if (!this.hasName(name)) { - var oldName = this.name(); - var newName = oldName ? oldName + ' ' + name : name; - this.setName(newName); - } - return this; - } - /** - * check is node has name - * @method - * @name Konva.Node#hasName - * @param {String} name - * @returns {Boolean} - * @example - * node.name('red'); - * node.hasName('red'); // return true - * node.hasName('selected'); // return false - * node.hasName(''); // return false - */ - hasName(name) { - if (!name) { - return false; - } - const fullName = this.name(); - if (!fullName) { - return false; - } - // if name is '' the "names" will be [''], so I added extra check above - var names = (fullName || '').split(/\s/g); - return names.indexOf(name) !== -1; - } - /** - * remove name from node - * @method - * @name Konva.Node#removeName - * @param {String} name - * @returns {Konva.Node} - * @example - * node.name('red selected'); - * node.removeName('selected'); - * node.hasName('selected'); // return false - * node.name(); // return 'red' - */ - removeName(name) { - var names = (this.name() || '').split(/\s/g); - var index = names.indexOf(name); - if (index !== -1) { - names.splice(index, 1); - this.setName(names.join(' ')); - } - return this; - } - /** - * set attr - * @method - * @name Konva.Node#setAttr - * @param {String} attr - * @param {*} val - * @returns {Konva.Node} - * @example - * node.setAttr('x', 5); - */ - setAttr(attr, val) { - var func = this[SET + Util._capitalize(attr)]; - if (Util._isFunction(func)) { - func.call(this, val); - } else { - // otherwise set directly - this._setAttr(attr, val); - } - return this; - } - _setAttr(key, val, skipFire = false) { - var oldVal = this.attrs[key]; - if (oldVal === val && !Util.isObject(val)) { - return; - } - if (val === undefined || val === null) { - delete this.attrs[key]; - } else { - this.attrs[key] = val; - } - if (this._shouldFireChangeEvents) { - this._fireChangeEvent(key, oldVal, val); - } - if (Konva$2.autoDrawEnabled) { - const drawNode = this.getLayer() || this.getStage(); - drawNode === null || drawNode === void 0 - ? void 0 - : drawNode.batchDraw(); - } - } - _setComponentAttr(key, component, val) { - var oldVal; - if (val !== undefined) { - oldVal = this.attrs[key]; - if (!oldVal) { - // set value to default value using getAttr - this.attrs[key] = this.getAttr(key); - } - this.attrs[key][component] = val; - this._fireChangeEvent(key, oldVal, val); - } - } - _fireAndBubble(eventType, evt, compareShape) { - if (evt && this.nodeType === SHAPE) { - evt.target = this; - } - var shouldStop = - (eventType === MOUSEENTER$1 || eventType === MOUSELEAVE$1) && - ((compareShape && - (this === compareShape || - (this.isAncestorOf && this.isAncestorOf(compareShape)))) || - (this.nodeType === 'Stage' && !compareShape)); - if (!shouldStop) { - this._fire(eventType, evt); - // simulate event bubbling - var stopBubble = - (eventType === MOUSEENTER$1 || eventType === MOUSELEAVE$1) && - compareShape && - compareShape.isAncestorOf && - compareShape.isAncestorOf(this) && - !compareShape.isAncestorOf(this.parent); - if ( - ((evt && !evt.cancelBubble) || !evt) && - this.parent && - this.parent.isListening() && - !stopBubble - ) { - if (compareShape && compareShape.parent) { - this._fireAndBubble.call(this.parent, eventType, evt, compareShape); - } else { - this._fireAndBubble.call(this.parent, eventType, evt); + for (n = 0; n < len; n++) { + event = events[n]; + parts = event.split('.'); + baseEvent = parts[0]; + name = parts[1]; + if (baseEvent) { + if (this.eventListeners[baseEvent]) { + this._off(baseEvent, name, callback); + } + } + else { + for (t in this.eventListeners) { + this._off(t, name, callback); + } + } } - } + return this; } - } - _getProtoListeners(eventType) { - let listeners = this._cache.get(ALL_LISTENERS); - // if no cache for listeners, we need to pre calculate it - if (!listeners) { - listeners = {}; - let obj = Object.getPrototypeOf(this); - while (obj) { - if (!obj.eventListeners) { - obj = Object.getPrototypeOf(obj); - continue; + // some event aliases for third party integration like HammerJS + dispatchEvent(evt) { + var e = { + target: this, + type: evt.type, + evt: evt, + }; + this.fire(evt.type, e); + return this; + } + addEventListener(type, handler) { + // we have to pass native event to handler + this.on(type, function (evt) { + handler.call(this, evt.evt); + }); + return this; + } + removeEventListener(type) { + this.off(type); + return this; + } + // like node.on + _delegate(event, selector, handler) { + var stopNode = this; + this.on(event, function (evt) { + var targets = evt.target.findAncestors(selector, true, stopNode); + for (var i = 0; i < targets.length; i++) { + evt = Util.cloneObject(evt); + evt.currentTarget = targets[i]; + handler.call(targets[i], evt); + } + }); + } + /** + * remove a node from parent, but don't destroy. You can reuse the node later. + * @method + * @name Konva.Node#remove + * @returns {Konva.Node} + * @example + * node.remove(); + */ + remove() { + if (this.isDragging()) { + this.stopDrag(); } - for (var event in obj.eventListeners) { - const newEvents = obj.eventListeners[event]; - const oldEvents = listeners[event] || []; - listeners[event] = newEvents.concat(oldEvents); - } - obj = Object.getPrototypeOf(obj); - } - this._cache.set(ALL_LISTENERS, listeners); - } - return listeners[eventType]; - } - _fire(eventType, evt) { - evt = evt || {}; - evt.currentTarget = this; - evt.type = eventType; - const topListeners = this._getProtoListeners(eventType); - if (topListeners) { - for (var i = 0; i < topListeners.length; i++) { - topListeners[i].handler.call(this, evt); - } - } - // it is important to iterate over self listeners without cache - // because events can be added/removed while firing - const selfListeners = this.eventListeners[eventType]; - if (selfListeners) { - for (var i = 0; i < selfListeners.length; i++) { - selfListeners[i].handler.call(this, evt); - } - } - } - /** - * draw both scene and hit graphs. If the node being drawn is the stage, all of the layers will be cleared and redrawn - * @method - * @name Konva.Node#draw - * @returns {Konva.Node} - */ - draw() { - this.drawScene(); - this.drawHit(); - return this; - } - // drag & drop - _createDragElement(evt) { - var pointerId = evt ? evt.pointerId : undefined; - var stage = this.getStage(); - var ap = this.getAbsolutePosition(); - var pos = - stage._getPointerById(pointerId) || - stage._changedPointerPositions[0] || - ap; - DD._dragElements.set(this._id, { - node: this, - startPointerPos: pos, - offset: { - x: pos.x - ap.x, - y: pos.y - ap.y, - }, - dragStatus: 'ready', - pointerId, - }); - } - /** - * initiate drag and drop. - * @method - * @name Konva.Node#startDrag - */ - startDrag(evt, bubbleEvent = true) { - if (!DD._dragElements.has(this._id)) { - this._createDragElement(evt); - } - const elem = DD._dragElements.get(this._id); - elem.dragStatus = 'dragging'; - this.fire( - 'dragstart', - { - type: 'dragstart', - target: this, - evt: evt && evt.evt, - }, - bubbleEvent - ); - } - _setDragPosition(evt, elem) { - // const pointers = this.getStage().getPointersPositions(); - // const pos = pointers.find(p => p.id === this._dragEventId); - const pos = this.getStage()._getPointerById(elem.pointerId); - if (!pos) { - return; - } - var newNodePos = { - x: pos.x - elem.offset.x, - y: pos.y - elem.offset.y, - }; - var dbf = this.dragBoundFunc(); - if (dbf !== undefined) { - const bounded = dbf.call(this, newNodePos, evt); - if (!bounded) { - Util.warn( - 'dragBoundFunc did not return any value. That is unexpected behavior. You must return new absolute position from dragBoundFunc.' - ); - } else { - newNodePos = bounded; - } - } - if ( - !this._lastPos || - this._lastPos.x !== newNodePos.x || - this._lastPos.y !== newNodePos.y - ) { - this.setAbsolutePosition(newNodePos); - if (this.getLayer()) { - this.getLayer().batchDraw(); - } else if (this.getStage()) { - this.getStage().batchDraw(); - } - } - this._lastPos = newNodePos; - } - /** - * stop drag and drop - * @method - * @name Konva.Node#stopDrag - */ - stopDrag(evt) { - const elem = DD._dragElements.get(this._id); - if (elem) { - elem.dragStatus = 'stopped'; - } - DD._endDragBefore(evt); - DD._endDragAfter(evt); - } - setDraggable(draggable) { - this._setAttr('draggable', draggable); - this._dragChange(); - } - /** - * determine if node is currently in drag and drop mode - * @method - * @name Konva.Node#isDragging - */ - isDragging() { - const elem = DD._dragElements.get(this._id); - return elem ? elem.dragStatus === 'dragging' : false; - } - _listenDrag() { - this._dragCleanup(); - this.on('mousedown.konva touchstart.konva', function (evt) { - var shouldCheckButton = evt.evt['button'] !== undefined; - var canDrag = - !shouldCheckButton || - Konva$2.dragButtons.indexOf(evt.evt['button']) >= 0; - if (!canDrag) { - return; - } - if (this.isDragging()) { - return; - } - var hasDraggingChild = false; - DD._dragElements.forEach((elem) => { - if (this.isAncestorOf(elem.node)) { - hasDraggingChild = true; - } - }); - // nested drag can be started - // in that case we don't need to start new drag - if (!hasDraggingChild) { - this._createDragElement(evt); - } - }); - } - _dragChange() { - if (this.attrs.draggable) { - this._listenDrag(); - } else { - // remove event listeners - this._dragCleanup(); - /* - * force drag and drop to end - * if this node is currently in - * drag and drop mode - */ - var stage = this.getStage(); - if (!stage) { - return; - } - const dragElement = DD._dragElements.get(this._id); - const isDragging = dragElement && dragElement.dragStatus === 'dragging'; - const isReady = dragElement && dragElement.dragStatus === 'ready'; - if (isDragging) { - this.stopDrag(); - } else if (isReady) { + // we can have drag element but that is not dragged yet + // so just clear it DD._dragElements.delete(this._id); - } + this._remove(); + return this; } - } - _dragCleanup() { - this.off('mousedown.konva'); - this.off('touchstart.konva'); - } - /** - * create node with JSON string or an Object. De-serializtion does not generate custom - * shape drawing functions, images, or event handlers (this would make the - * serialized object huge). If your app uses custom shapes, images, and - * event handlers (it probably does), then you need to select the appropriate - * shapes after loading the stage and set these properties via on(), setSceneFunc(), - * and setImage() methods - * @method - * @memberof Konva.Node - * @param {String|Object} json string or object - * @param {Element} [container] optional container dom element used only if you're - * creating a stage node - */ - static create(data, container) { - if (Util._isString(data)) { - data = JSON.parse(data); + _clearCaches() { + this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); + this._clearSelfAndDescendantCache(ABSOLUTE_SCALE); + this._clearSelfAndDescendantCache(STAGE$1); + this._clearSelfAndDescendantCache(VISIBLE); + this._clearSelfAndDescendantCache(LISTENING); } - return this._createNode(data, container); - } - static _createNode(obj, container) { - var className = Node.prototype.getClassName.call(obj), - children = obj.children, - no, - len, - n; - // if container was passed in, add it to attrs - if (container) { - obj.attrs.container = container; + _remove() { + // every cached attr that is calculated via node tree + // traversal must be cleared when removing a node + this._clearCaches(); + var parent = this.getParent(); + if (parent && parent.children) { + parent.children.splice(this.index, 1); + parent._setChildrenIndices(); + this.parent = null; + } } - if (!_NODES_REGISTRY[className]) { - Util.warn( - 'Can not find a node with class name "' + - className + - '". Fallback to "Shape".' - ); - className = 'Shape'; + /** + * remove and destroy a node. Kill it and delete forever! You should not reuse node after destroy(). + * If the node is a container (Group, Stage or Layer) it will destroy all children too. + * @method + * @name Konva.Node#destroy + * @example + * node.destroy(); + */ + destroy() { + // remove from ids and names hashes + _removeId(this.id(), this); + // remove all names + 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(); + return this; } - const Class = _NODES_REGISTRY[className]; - no = new Class(obj.attrs); - if (children) { - len = children.length; - for (n = 0; n < len; n++) { - no.add(Node._createNode(children[n])); - } + /** + * get attr + * @method + * @name Konva.Node#getAttr + * @param {String} attr + * @returns {Integer|String|Object|Array} + * @example + * var x = node.getAttr('x'); + */ + getAttr(attr) { + var method = 'get' + Util._capitalize(attr); + if (Util._isFunction(this[method])) { + return this[method](); + } + // otherwise get directly + return this.attrs[attr]; + } + /** + * get ancestors + * @method + * @name Konva.Node#getAncestors + * @returns {Array} + * @example + * shape.getAncestors().forEach(function(node) { + * console.log(node.getId()); + * }) + */ + getAncestors() { + var parent = this.getParent(), ancestors = []; + while (parent) { + ancestors.push(parent); + parent = parent.getParent(); + } + return ancestors; + } + /** + * get attrs object literal + * @method + * @name Konva.Node#getAttrs + * @returns {Object} + */ + getAttrs() { + return this.attrs || {}; + } + /** + * set multiple attrs at once using an object literal + * @method + * @name Konva.Node#setAttrs + * @param {Object} config object containing key value pairs + * @returns {Konva.Node} + * @example + * node.setAttrs({ + * x: 5, + * fill: 'red' + * }); + */ + setAttrs(config) { + this._batchTransformChanges(() => { + var key, method; + if (!config) { + return this; + } + for (key in config) { + if (key === CHILDREN) { + continue; + } + method = SET + Util._capitalize(key); + // use setter if available + if (Util._isFunction(this[method])) { + this[method](config[key]); + } + else { + // otherwise set directly + this._setAttr(key, config[key]); + } + } + }); + return this; + } + /** + * determine if node is listening for events by taking into account ancestors. + * + * Parent | Self | isListening + * listening | listening | + * ----------+-----------+------------ + * T | T | T + * T | F | F + * F | T | F + * F | F | F + * + * @method + * @name Konva.Node#isListening + * @returns {Boolean} + */ + isListening() { + return this._getCache(LISTENING, this._isListening); + } + _isListening(relativeTo) { + const listening = this.listening(); + if (!listening) { + return false; + } + const parent = this.getParent(); + if (parent && parent !== relativeTo && this !== relativeTo) { + return parent._isListening(relativeTo); + } + else { + return true; + } + } + /** + * determine if node is visible by taking into account ancestors. + * + * Parent | Self | isVisible + * visible | visible | + * ----------+-----------+------------ + * T | T | T + * T | F | F + * F | T | F + * F | F | F + * @method + * @name Konva.Node#isVisible + * @returns {Boolean} + */ + isVisible() { + return this._getCache(VISIBLE, this._isVisible); + } + _isVisible(relativeTo) { + const visible = this.visible(); + if (!visible) { + return false; + } + const parent = this.getParent(); + if (parent && parent !== relativeTo && this !== relativeTo) { + return parent._isVisible(relativeTo); + } + else { + return true; + } + } + shouldDrawHit(top, skipDragCheck = false) { + if (top) { + return this._isVisible(top) && this._isListening(top); + } + var layer = this.getLayer(); + var layerUnderDrag = false; + DD._dragElements.forEach((elem) => { + if (elem.dragStatus !== 'dragging') { + return; + } + else if (elem.node.nodeType === 'Stage') { + layerUnderDrag = true; + } + else if (elem.node.getLayer() === layer) { + layerUnderDrag = true; + } + }); + var dragSkip = !skipDragCheck && !Konva$2.hitOnDragEnabled && layerUnderDrag; + return this.isListening() && this.isVisible() && !dragSkip; + } + /** + * show node. set visible = true + * @method + * @name Konva.Node#show + * @returns {Konva.Node} + */ + show() { + this.visible(true); + return this; + } + /** + * hide node. Hidden nodes are no longer detectable + * @method + * @name Konva.Node#hide + * @returns {Konva.Node} + */ + hide() { + this.visible(false); + return this; + } + getZIndex() { + return this.index || 0; + } + /** + * get absolute z-index which takes into account sibling + * and ancestor indices + * @method + * @name Konva.Node#getAbsoluteZIndex + * @returns {Integer} + */ + getAbsoluteZIndex() { + var depth = this.getDepth(), that = this, index = 0, nodes, len, n, child; + function addChildren(children) { + nodes = []; + len = children.length; + for (n = 0; n < len; n++) { + child = children[n]; + index++; + if (child.nodeType !== SHAPE) { + nodes = nodes.concat(child.getChildren().slice()); + } + if (child._id === that._id) { + n = len; + } + } + if (nodes.length > 0 && nodes[0].getDepth() <= depth) { + addChildren(nodes); + } + } + if (that.nodeType !== UPPER_STAGE) { + addChildren(that.getStage().getChildren()); + } + return index; + } + /** + * get node depth in node tree. Returns an integer. + * e.g. Stage depth will always be 0. Layers will always be 1. Groups and Shapes will always + * be >= 2 + * @method + * @name Konva.Node#getDepth + * @returns {Integer} + */ + getDepth() { + var depth = 0, parent = this.parent; + while (parent) { + depth++; + parent = parent.parent; + } + return depth; + } + // sometimes we do several attributes changes + // like node.position(pos) + // for performance reasons, lets batch transform reset + // so it work faster + _batchTransformChanges(func) { + this._batchingTransformChange = true; + func(); + this._batchingTransformChange = false; + if (this._needClearTransformCache) { + this._clearCache(TRANSFORM); + this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM, true); + } + this._needClearTransformCache = false; + } + setPosition(pos) { + this._batchTransformChanges(() => { + this.x(pos.x); + this.y(pos.y); + }); + return this; + } + getPosition() { + return { + x: this.x(), + y: this.y(), + }; + } + /** + * get absolute position of a node. That function can be used to calculate absolute position, but relative to any ancestor + * @method + * @name Konva.Node#getAbsolutePosition + * @param {Object} Ancestor optional ancestor node + * @returns {Konva.Node} + * @example + * + * // returns absolute position relative to top-left corner of canvas + * node.getAbsolutePosition(); + * + * // calculate absolute position of node, inside stage + * // so stage transforms are ignored + * node.getAbsolutePosition(stage) + */ + getAbsolutePosition(top) { + let haveCachedParent = false; + let parent = this.parent; + while (parent) { + if (parent.isCached()) { + haveCachedParent = true; + break; + } + parent = parent.parent; + } + if (haveCachedParent && !top) { + // make fake top element + // "true" is not a node, but it will just allow skip all caching + top = true; + } + var absoluteMatrix = this.getAbsoluteTransform(top).getMatrix(), absoluteTransform = new Transform(), offset = this.offset(); + // clone the matrix array + absoluteTransform.m = absoluteMatrix.slice(); + absoluteTransform.translate(offset.x, offset.y); + return absoluteTransform.getTranslation(); + } + setAbsolutePosition(pos) { + var origTrans = this._clearTransform(); + // don't clear translation + this.attrs.x = origTrans.x; + this.attrs.y = origTrans.y; + delete origTrans.x; + delete origTrans.y; + // important, use non cached value + this._clearCache(TRANSFORM); + var it = this._getAbsoluteTransform().copy(); + it.invert(); + it.translate(pos.x, pos.y); + pos = { + x: this.attrs.x + it.getTranslation().x, + y: this.attrs.y + it.getTranslation().y, + }; + this._setTransform(origTrans); + this.setPosition({ x: pos.x, y: pos.y }); + this._clearCache(TRANSFORM); + this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + return this; + } + _setTransform(trans) { + var key; + for (key in trans) { + this.attrs[key] = trans[key]; + } + // this._clearCache(TRANSFORM); + // this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + } + _clearTransform() { + var trans = { + x: this.x(), + y: this.y(), + rotation: this.rotation(), + scaleX: this.scaleX(), + scaleY: this.scaleY(), + offsetX: this.offsetX(), + offsetY: this.offsetY(), + skewX: this.skewX(), + skewY: this.skewY(), + }; + this.attrs.x = 0; + this.attrs.y = 0; + this.attrs.rotation = 0; + this.attrs.scaleX = 1; + this.attrs.scaleY = 1; + this.attrs.offsetX = 0; + this.attrs.offsetY = 0; + this.attrs.skewX = 0; + this.attrs.skewY = 0; + // return original transform + return trans; + } + /** + * move node by an amount relative to its current position + * @method + * @name Konva.Node#move + * @param {Object} change + * @param {Number} change.x + * @param {Number} change.y + * @returns {Konva.Node} + * @example + * // move node in x direction by 1px and y direction by 2px + * node.move({ + * x: 1, + * y: 2 + * }); + */ + move(change) { + var changeX = change.x, changeY = change.y, x = this.x(), y = this.y(); + if (changeX !== undefined) { + x += changeX; + } + if (changeY !== undefined) { + y += changeY; + } + this.setPosition({ x: x, y: y }); + return this; + } + _eachAncestorReverse(func, top) { + var family = [], parent = this.getParent(), len, n; + // if top node is defined, and this node is top node, + // there's no need to build a family tree. just execute + // func with this because it will be the only node + if (top && top._id === this._id) { + // func(this); + return; + } + family.unshift(this); + while (parent && (!top || parent._id !== top._id)) { + family.unshift(parent); + parent = parent.parent; + } + len = family.length; + for (n = 0; n < len; n++) { + func(family[n]); + } + } + /** + * rotate node by an amount in degrees relative to its current rotation + * @method + * @name Konva.Node#rotate + * @param {Number} theta + * @returns {Konva.Node} + */ + rotate(theta) { + this.rotation(this.rotation() + theta); + return this; + } + /** + * move node to the top of its siblings + * @method + * @name Konva.Node#moveToTop + * @returns {Boolean} + */ + moveToTop() { + if (!this.parent) { + Util.warn('Node has no parent. moveToTop function is ignored.'); + return false; + } + var index = this.index; + this.parent.children.splice(index, 1); + this.parent.children.push(this); + this.parent._setChildrenIndices(); + return true; + } + /** + * move node up + * @method + * @name Konva.Node#moveUp + * @returns {Boolean} flag is moved or not + */ + moveUp() { + if (!this.parent) { + Util.warn('Node has no parent. moveUp function is ignored.'); + return false; + } + var index = this.index, len = this.parent.getChildren().length; + if (index < len - 1) { + this.parent.children.splice(index, 1); + this.parent.children.splice(index + 1, 0, this); + this.parent._setChildrenIndices(); + return true; + } + return false; + } + /** + * move node down + * @method + * @name Konva.Node#moveDown + * @returns {Boolean} + */ + moveDown() { + if (!this.parent) { + Util.warn('Node has no parent. moveDown function is ignored.'); + return false; + } + var index = this.index; + if (index > 0) { + this.parent.children.splice(index, 1); + this.parent.children.splice(index - 1, 0, this); + this.parent._setChildrenIndices(); + return true; + } + return false; + } + /** + * move node to the bottom of its siblings + * @method + * @name Konva.Node#moveToBottom + * @returns {Boolean} + */ + moveToBottom() { + if (!this.parent) { + Util.warn('Node has no parent. moveToBottom function is ignored.'); + return false; + } + var index = this.index; + if (index > 0) { + this.parent.children.splice(index, 1); + this.parent.children.unshift(this); + this.parent._setChildrenIndices(); + return true; + } + return false; + } + setZIndex(zIndex) { + if (!this.parent) { + Util.warn('Node has no parent. zIndex parameter is ignored.'); + return this; + } + if (zIndex < 0 || zIndex >= this.parent.children.length) { + Util.warn('Unexpected value ' + + zIndex + + ' 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 index = this.index; + this.parent.children.splice(index, 1); + this.parent.children.splice(zIndex, 0, this); + this.parent._setChildrenIndices(); + return this; + } + /** + * get absolute opacity + * @method + * @name Konva.Node#getAbsoluteOpacity + * @returns {Number} + */ + getAbsoluteOpacity() { + return this._getCache(ABSOLUTE_OPACITY, this._getAbsoluteOpacity); + } + _getAbsoluteOpacity() { + var absOpacity = this.opacity(); + var parent = this.getParent(); + if (parent && !parent._isUnderCache) { + absOpacity *= parent.getAbsoluteOpacity(); + } + return absOpacity; + } + /** + * move node to another container + * @method + * @name Konva.Node#moveTo + * @param {Container} newContainer + * @returns {Konva.Node} + * @example + * // move node from current layer into layer2 + * node.moveTo(layer2); + */ + moveTo(newContainer) { + // do nothing if new container is already parent + if (this.getParent() !== newContainer) { + this._remove(); + newContainer.add(this); + } + return this; + } + /** + * convert Node into an object for serialization. Returns an object. + * @method + * @name Konva.Node#toObject + * @returns {Object} + */ + toObject() { + var obj = {}, attrs = this.getAttrs(), key, val, getter, defaultValue, nonPlainObject; + obj.attrs = {}; + for (key in attrs) { + val = attrs[key]; + // if value is object and object is not plain + // like class instance, we should skip it and to not include + nonPlainObject = + Util.isObject(val) && !Util._isPlainObject(val) && !Util._isArray(val); + if (nonPlainObject) { + continue; + } + getter = typeof this[key] === 'function' && this[key]; + // remove attr value so that we can extract the default value from the getter + delete attrs[key]; + defaultValue = getter ? getter.call(this) : null; + // restore attr value + attrs[key] = val; + if (defaultValue !== val) { + obj.attrs[key] = val; + } + } + obj.className = this.getClassName(); + return Util._prepareToStringify(obj); + } + /** + * convert Node into a JSON string. Returns a JSON string. + * @method + * @name Konva.Node#toJSON + * @returns {String} + */ + toJSON() { + return JSON.stringify(this.toObject()); + } + /** + * get parent container + * @method + * @name Konva.Node#getParent + * @returns {Konva.Node} + */ + getParent() { + return this.parent; + } + /** + * get all ancestors (parent then parent of the parent, etc) of the node + * @method + * @name Konva.Node#findAncestors + * @param {String} selector selector for search + * @param {Boolean} [includeSelf] show we think that node is ancestro itself? + * @param {Konva.Node} [stopNode] optional node where we need to stop searching (one of ancestors) + * @returns {Array} [ancestors] + * @example + * // get one of the parent group + * var parentGroups = node.findAncestors('Group'); + */ + findAncestors(selector, includeSelf, stopNode) { + var res = []; + if (includeSelf && this._isMatch(selector)) { + res.push(this); + } + var ancestor = this.parent; + while (ancestor) { + if (ancestor === stopNode) { + return res; + } + if (ancestor._isMatch(selector)) { + res.push(ancestor); + } + ancestor = ancestor.parent; + } + return res; + } + isAncestorOf(node) { + return false; + } + /** + * get ancestor (parent or parent of the parent, etc) of the node that match passed selector + * @method + * @name Konva.Node#findAncestor + * @param {String} selector selector for search + * @param {Boolean} [includeSelf] show we think that node is ancestro itself? + * @param {Konva.Node} [stopNode] optional node where we need to stop searching (one of ancestors) + * @returns {Konva.Node} ancestor + * @example + * // get one of the parent group + * var group = node.findAncestors('.mygroup'); + */ + findAncestor(selector, includeSelf, stopNode) { + return this.findAncestors(selector, includeSelf, stopNode)[0]; + } + // is current node match passed selector? + _isMatch(selector) { + if (!selector) { + return false; + } + if (typeof selector === 'function') { + return selector(this); + } + var selectorArr = selector.replace(/ /g, '').split(','), len = selectorArr.length, n, sel; + for (n = 0; n < len; n++) { + sel = selectorArr[n]; + if (!Util.isValidSelector(sel)) { + Util.warn('Selector "' + + sel + + '" is invalid. Allowed selectors examples are "#foo", ".bar" or "Group".'); + Util.warn('If you have a custom shape with such className, please change it to start with upper letter like "Triangle".'); + Util.warn('Konva is awesome, right?'); + } + // id selector + if (sel.charAt(0) === '#') { + if (this.id() === sel.slice(1)) { + return true; + } + } + else if (sel.charAt(0) === '.') { + // name selector + if (this.hasName(sel.slice(1))) { + return true; + } + } + else if (this.className === sel || this.nodeType === sel) { + return true; + } + } + return false; + } + /** + * get layer ancestor + * @method + * @name Konva.Node#getLayer + * @returns {Konva.Layer} + */ + getLayer() { + var parent = this.getParent(); + return parent ? parent.getLayer() : null; + } + /** + * get stage ancestor + * @method + * @name Konva.Node#getStage + * @returns {Konva.Stage} + */ + getStage() { + return this._getCache(STAGE$1, this._getStage); + } + _getStage() { + var parent = this.getParent(); + if (parent) { + return parent.getStage(); + } + else { + return undefined; + } + } + /** + * fire event + * @method + * @name Konva.Node#fire + * @param {String} eventType event type. can be a regular event, like click, mouseover, or mouseout, or it can be a custom event, like myCustomEvent + * @param {Event} [evt] event object + * @param {Boolean} [bubble] setting the value to false, or leaving it undefined, will result in the event + * not bubbling. Setting the value to true will result in the event bubbling. + * @returns {Konva.Node} + * @example + * // manually fire click event + * node.fire('click'); + * + * // fire custom event + * node.fire('foo'); + * + * // fire custom event with custom event object + * node.fire('foo', { + * bar: 10 + * }); + * + * // fire click event that bubbles + * node.fire('click', null, true); + */ + fire(eventType, evt = {}, bubble) { + evt.target = evt.target || this; + // bubble + if (bubble) { + this._fireAndBubble(eventType, evt); + } + else { + // no bubble + this._fire(eventType, evt); + } + return this; + } + /** + * get absolute transform of the node which takes into + * account its ancestor transforms + * @method + * @name Konva.Node#getAbsoluteTransform + * @returns {Konva.Transform} + */ + getAbsoluteTransform(top) { + // if using an argument, we can't cache the result. + if (top) { + return this._getAbsoluteTransform(top); + } + else { + // if no argument, we can cache the result + return this._getCache(ABSOLUTE_TRANSFORM, this._getAbsoluteTransform); + } + } + _getAbsoluteTransform(top) { + var at; + // we we need position relative to an ancestor, we will iterate for all + if (top) { + at = new Transform(); + // start with stage and traverse downwards to self + this._eachAncestorReverse(function (node) { + var transformsEnabled = node.transformsEnabled(); + if (transformsEnabled === 'all') { + at.multiply(node.getTransform()); + } + else if (transformsEnabled === 'position') { + at.translate(node.x() - node.offsetX(), node.y() - node.offsetY()); + } + }, top); + return at; + } + else { + // try to use a cached value + at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform(); + if (this.parent) { + // transform will be cached + this.parent.getAbsoluteTransform().copyInto(at); + } + else { + at.reset(); + } + var transformsEnabled = this.transformsEnabled(); + if (transformsEnabled === 'all') { + at.multiply(this.getTransform()); + } + else if (transformsEnabled === 'position') { + // use "attrs" directly, because it is a bit faster + const x = this.attrs.x || 0; + const y = this.attrs.y || 0; + const offsetX = this.attrs.offsetX || 0; + const offsetY = this.attrs.offsetY || 0; + at.translate(x - offsetX, y - offsetY); + } + at.dirty = false; + return at; + } + } + /** + * get absolute scale of the node which takes into + * account its ancestor scales + * @method + * @name Konva.Node#getAbsoluteScale + * @returns {Object} + * @example + * // get absolute scale x + * var scaleX = node.getAbsoluteScale().x; + */ + getAbsoluteScale(top) { + // do not cache this calculations, + // because it use cache transform + // this is special logic for caching with some shapes with shadow + var parent = this; + while (parent) { + if (parent._isUnderCache) { + top = parent; + } + parent = parent.getParent(); + } + const transform = this.getAbsoluteTransform(top); + const attrs = transform.decompose(); + return { + x: attrs.scaleX, + y: attrs.scaleY, + }; + } + /** + * get absolute rotation of the node which takes into + * account its ancestor rotations + * @method + * @name Konva.Node#getAbsoluteRotation + * @returns {Number} + * @example + * // get absolute rotation + * var rotation = node.getAbsoluteRotation(); + */ + getAbsoluteRotation() { + // var parent: Node = this; + // var rotation = 0; + // while (parent) { + // rotation += parent.rotation(); + // parent = parent.getParent(); + // } + // return rotation; + return this.getAbsoluteTransform().decompose().rotation; + } + /** + * get transform of the node + * @method + * @name Konva.Node#getTransform + * @returns {Konva.Transform} + */ + getTransform() { + return this._getCache(TRANSFORM, this._getTransform); + } + _getTransform() { + var _a, _b; + var m = this._cache.get(TRANSFORM) || new Transform(); + m.reset(); + // I was trying to use attributes directly here + // but it doesn't work for Transformer well + // because it overwrite x,y getters + var x = this.x(), y = this.y(), rotation = Konva$2.getAngle(this.rotation()), scaleX = (_a = this.attrs.scaleX) !== null && _a !== void 0 ? _a : 1, scaleY = (_b = this.attrs.scaleY) !== null && _b !== void 0 ? _b : 1, skewX = this.attrs.skewX || 0, skewY = this.attrs.skewY || 0, offsetX = this.attrs.offsetX || 0, offsetY = this.attrs.offsetY || 0; + if (x !== 0 || y !== 0) { + m.translate(x, y); + } + if (rotation !== 0) { + m.rotate(rotation); + } + if (skewX !== 0 || skewY !== 0) { + m.skew(skewX, skewY); + } + if (scaleX !== 1 || scaleY !== 1) { + m.scale(scaleX, scaleY); + } + if (offsetX !== 0 || offsetY !== 0) { + m.translate(-1 * offsetX, -1 * offsetY); + } + m.dirty = false; + return m; + } + /** + * clone node. Returns a new Node instance with identical attributes. You can also override + * the node properties with an object literal, enabling you to use an existing node as a template + * for another node + * @method + * @name Konva.Node#clone + * @param {Object} obj override attrs + * @returns {Konva.Node} + * @example + * // simple clone + * var clone = node.clone(); + * + * // clone a node and override the x position + * var clone = rect.clone({ + * x: 5 + * }); + */ + clone(obj) { + // instantiate new node + var attrs = Util.cloneObject(this.attrs), key, allListeners, len, n, listener; + // apply attr overrides + for (key in obj) { + attrs[key] = obj[key]; + } + var node = new this.constructor(attrs); + // copy over listeners + for (key in this.eventListeners) { + allListeners = this.eventListeners[key]; + len = allListeners.length; + for (n = 0; n < len; n++) { + listener = allListeners[n]; + /* + * don't include konva namespaced listeners because + * these are generated by the constructors + */ + if (listener.name.indexOf(KONVA) < 0) { + // if listeners array doesn't exist, then create it + if (!node.eventListeners[key]) { + node.eventListeners[key] = []; + } + node.eventListeners[key].push(listener); + } + } + } + return node; + } + _toKonvaCanvas(config) { + config = config || {}; + var box = this.getClientRect(); + var stage = this.getStage(), x = config.x !== undefined ? config.x : box.x, y = config.y !== undefined ? config.y : box.y, pixelRatio = config.pixelRatio || 1, canvas = new SceneCanvas({ + width: config.width || box.width || (stage ? stage.width() : 0), + height: config.height || box.height || (stage ? stage.height() : 0), + pixelRatio: pixelRatio, + }), context = canvas.getContext(); + context.save(); + if (x || y) { + context.translate(-1 * x, -1 * y); + } + this.drawScene(canvas); + context.restore(); + return canvas; + } + /** + * converts node into an canvas element. + * @method + * @name Konva.Node#toCanvas + * @param {Object} config + * @param {Function} config.callback function executed when the composite has completed + * @param {Number} [config.x] x position of canvas section + * @param {Number} [config.y] y position of canvas section + * @param {Number} [config.width] width of canvas section + * @param {Number} [config.height] height of canvas section + * @param {Number} [config.pixelRatio] pixelRatio of output canvas. Default is 1. + * You can use that property to increase quality of the image, for example for super hight quality exports + * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. + * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. + * @example + * var canvas = node.toCanvas(); + */ + toCanvas(config) { + return this._toKonvaCanvas(config)._canvas; + } + /** + * Creates a composite data URL (base64 string). If MIME type is not + * specified, then "image/png" will result. For "image/jpeg", specify a quality + * level as quality (range 0.0 - 1.0) + * @method + * @name Konva.Node#toDataURL + * @param {Object} config + * @param {String} [config.mimeType] can be "image/png" or "image/jpeg". + * "image/png" is the default + * @param {Number} [config.x] x position of canvas section + * @param {Number} [config.y] y position of canvas section + * @param {Number} [config.width] width of canvas section + * @param {Number} [config.height] height of canvas section + * @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType, + * you can specify the quality from 0 to 1, where 0 is very poor quality and 1 + * is very high quality + * @param {Number} [config.pixelRatio] pixelRatio of output image url. Default is 1. + * You can use that property to increase quality of the image, for example for super hight quality exports + * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. + * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. + * @returns {String} + */ + toDataURL(config) { + config = config || {}; + var mimeType = config.mimeType || null, quality = config.quality || null; + var url = this._toKonvaCanvas(config).toDataURL(mimeType, quality); + if (config.callback) { + config.callback(url); + } + return url; + } + /** + * converts node into an image. Since the toImage + * method is asynchronous, a callback is required. toImage is most commonly used + * to cache complex drawings as an image so that they don't have to constantly be redrawn + * @method + * @name Konva.Node#toImage + * @param {Object} config + * @param {Function} config.callback function executed when the composite has completed + * @param {String} [config.mimeType] can be "image/png" or "image/jpeg". + * "image/png" is the default + * @param {Number} [config.x] x position of canvas section + * @param {Number} [config.y] y position of canvas section + * @param {Number} [config.width] width of canvas section + * @param {Number} [config.height] height of canvas section + * @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType, + * you can specify the quality from 0 to 1, where 0 is very poor quality and 1 + * is very high quality + * @param {Number} [config.pixelRatio] pixelRatio of output image. Default is 1. + * You can use that property to increase quality of the image, for example for super hight quality exports + * or usage on retina (or similar) displays. pixelRatio will be used to multiply the size of exported image. + * If you export to 500x500 size with pixelRatio = 2, then produced image will have size 1000x1000. + * @example + * var image = node.toImage({ + * callback(img) { + * // do stuff with img + * } + * }); + */ + toImage(config) { + if (!config || !config.callback) { + throw 'callback required for toImage method config argument'; + } + var callback = config.callback; + delete config.callback; + Util._urlToImage(this.toDataURL(config), function (img) { + callback(img); + }); + } + setSize(size) { + this.width(size.width); + this.height(size.height); + return this; + } + getSize() { + return { + width: this.width(), + height: this.height(), + }; + } + /** + * get class name, which may return Stage, Layer, Group, or shape class names like Rect, Circle, Text, etc. + * @method + * @name Konva.Node#getClassName + * @returns {String} + */ + getClassName() { + return this.className || this.nodeType; + } + /** + * get the node type, which may return Stage, Layer, Group, or Shape + * @method + * @name Konva.Node#getType + * @returns {String} + */ + getType() { + return this.nodeType; + } + getDragDistance() { + // compare with undefined because we need to track 0 value + if (this.attrs.dragDistance !== undefined) { + return this.attrs.dragDistance; + } + else if (this.parent) { + return this.parent.getDragDistance(); + } + else { + return Konva$2.dragDistance; + } + } + _off(type, name, callback) { + var evtListeners = this.eventListeners[type], i, evtName, handler; + for (i = 0; i < evtListeners.length; i++) { + evtName = evtListeners[i].name; + handler = evtListeners[i].handler; + // the following two conditions must be true in order to remove a handler: + // 1) the current event name cannot be konva unless the event name is konva + // this enables developers to force remove a konva specific listener for whatever reason + // 2) an event name is not specified, or if one is specified, it matches the current event name + if ((evtName !== 'konva' || name === 'konva') && + (!name || evtName === name) && + (!callback || callback === handler)) { + evtListeners.splice(i, 1); + if (evtListeners.length === 0) { + delete this.eventListeners[type]; + break; + } + i--; + } + } + } + _fireChangeEvent(attr, oldVal, newVal) { + this._fire(attr + CHANGE, { + oldVal: oldVal, + newVal: newVal, + }); + } + setId(id) { + var oldId = this.id(); + _removeId(oldId, this); + _addId(this, id); + this._setAttr('id', id); + return this; + } + setName(name) { + var oldNames = (this.name() || '').split(/\s/g); + var newNames = (name || '').split(/\s/g); + var subname, i; + // remove all subnames + for (i = 0; i < oldNames.length; i++) { + subname = oldNames[i]; + if (newNames.indexOf(subname) === -1 && subname) { + _removeName(subname, this._id); + } + } + // add new names + for (i = 0; i < newNames.length; i++) { + subname = newNames[i]; + if (oldNames.indexOf(subname) === -1 && subname) { + _addName(this, subname); + } + } + this._setAttr(NAME, name); + return this; + } + /** + * add name to node + * @method + * @name Konva.Node#addName + * @param {String} name + * @returns {Konva.Node} + * @example + * node.name('red'); + * node.addName('selected'); + * node.name(); // return 'red selected' + */ + addName(name) { + if (!this.hasName(name)) { + var oldName = this.name(); + var newName = oldName ? oldName + ' ' + name : name; + this.setName(newName); + } + return this; + } + /** + * check is node has name + * @method + * @name Konva.Node#hasName + * @param {String} name + * @returns {Boolean} + * @example + * node.name('red'); + * node.hasName('red'); // return true + * node.hasName('selected'); // return false + * node.hasName(''); // return false + */ + hasName(name) { + if (!name) { + return false; + } + const fullName = this.name(); + if (!fullName) { + return false; + } + // if name is '' the "names" will be [''], so I added extra check above + var names = (fullName || '').split(/\s/g); + return names.indexOf(name) !== -1; + } + /** + * remove name from node + * @method + * @name Konva.Node#removeName + * @param {String} name + * @returns {Konva.Node} + * @example + * node.name('red selected'); + * node.removeName('selected'); + * node.hasName('selected'); // return false + * node.name(); // return 'red' + */ + removeName(name) { + var names = (this.name() || '').split(/\s/g); + var index = names.indexOf(name); + if (index !== -1) { + names.splice(index, 1); + this.setName(names.join(' ')); + } + return this; + } + /** + * set attr + * @method + * @name Konva.Node#setAttr + * @param {String} attr + * @param {*} val + * @returns {Konva.Node} + * @example + * node.setAttr('x', 5); + */ + setAttr(attr, val) { + var func = this[SET + Util._capitalize(attr)]; + if (Util._isFunction(func)) { + func.call(this, val); + } + else { + // otherwise set directly + this._setAttr(attr, val); + } + return this; + } + _requestDraw() { + if (Konva$2.autoDrawEnabled) { + const drawNode = this.getLayer() || this.getStage(); + drawNode === null || drawNode === void 0 ? void 0 : drawNode.batchDraw(); + } + } + _setAttr(key, val, skipFire = false) { + var oldVal = this.attrs[key]; + if (oldVal === val && !Util.isObject(val)) { + return; + } + if (val === undefined || val === null) { + delete this.attrs[key]; + } + else { + this.attrs[key] = val; + } + if (this._shouldFireChangeEvents) { + this._fireChangeEvent(key, oldVal, val); + } + this._requestDraw(); + } + _setComponentAttr(key, component, val) { + var oldVal; + if (val !== undefined) { + oldVal = this.attrs[key]; + if (!oldVal) { + // set value to default value using getAttr + this.attrs[key] = this.getAttr(key); + } + this.attrs[key][component] = val; + this._fireChangeEvent(key, oldVal, val); + } + } + _fireAndBubble(eventType, evt, compareShape) { + if (evt && this.nodeType === SHAPE) { + evt.target = this; + } + var shouldStop = (eventType === MOUSEENTER$1 || eventType === MOUSELEAVE$1) && + ((compareShape && + (this === compareShape || + (this.isAncestorOf && this.isAncestorOf(compareShape)))) || + (this.nodeType === 'Stage' && !compareShape)); + if (!shouldStop) { + this._fire(eventType, evt); + // simulate event bubbling + var stopBubble = (eventType === MOUSEENTER$1 || eventType === MOUSELEAVE$1) && + compareShape && + compareShape.isAncestorOf && + compareShape.isAncestorOf(this) && + !compareShape.isAncestorOf(this.parent); + if (((evt && !evt.cancelBubble) || !evt) && + this.parent && + this.parent.isListening() && + !stopBubble) { + if (compareShape && compareShape.parent) { + this._fireAndBubble.call(this.parent, eventType, evt, compareShape); + } + else { + this._fireAndBubble.call(this.parent, eventType, evt); + } + } + } + } + _getProtoListeners(eventType) { + let listeners = this._cache.get(ALL_LISTENERS); + // if no cache for listeners, we need to pre calculate it + if (!listeners) { + listeners = {}; + let obj = Object.getPrototypeOf(this); + while (obj) { + if (!obj.eventListeners) { + obj = Object.getPrototypeOf(obj); + continue; + } + for (var event in obj.eventListeners) { + const newEvents = obj.eventListeners[event]; + const oldEvents = listeners[event] || []; + listeners[event] = newEvents.concat(oldEvents); + } + obj = Object.getPrototypeOf(obj); + } + this._cache.set(ALL_LISTENERS, listeners); + } + return listeners[eventType]; + } + _fire(eventType, evt) { + evt = evt || {}; + evt.currentTarget = this; + evt.type = eventType; + const topListeners = this._getProtoListeners(eventType); + if (topListeners) { + for (var i = 0; i < topListeners.length; i++) { + topListeners[i].handler.call(this, evt); + } + } + // it is important to iterate over self listeners without cache + // because events can be added/removed while firing + const selfListeners = this.eventListeners[eventType]; + if (selfListeners) { + for (var i = 0; i < selfListeners.length; i++) { + selfListeners[i].handler.call(this, evt); + } + } + } + /** + * draw both scene and hit graphs. If the node being drawn is the stage, all of the layers will be cleared and redrawn + * @method + * @name Konva.Node#draw + * @returns {Konva.Node} + */ + draw() { + this.drawScene(); + this.drawHit(); + return this; + } + // drag & drop + _createDragElement(evt) { + var pointerId = evt ? evt.pointerId : undefined; + var stage = this.getStage(); + var ap = this.getAbsolutePosition(); + var pos = stage._getPointerById(pointerId) || + stage._changedPointerPositions[0] || + ap; + DD._dragElements.set(this._id, { + node: this, + startPointerPos: pos, + offset: { + x: pos.x - ap.x, + y: pos.y - ap.y, + }, + dragStatus: 'ready', + pointerId, + }); + } + /** + * initiate drag and drop. + * @method + * @name Konva.Node#startDrag + */ + startDrag(evt, bubbleEvent = true) { + if (!DD._dragElements.has(this._id)) { + this._createDragElement(evt); + } + const elem = DD._dragElements.get(this._id); + elem.dragStatus = 'dragging'; + this.fire('dragstart', { + type: 'dragstart', + target: this, + evt: evt && evt.evt, + }, bubbleEvent); + } + _setDragPosition(evt, elem) { + // const pointers = this.getStage().getPointersPositions(); + // const pos = pointers.find(p => p.id === this._dragEventId); + const pos = this.getStage()._getPointerById(elem.pointerId); + if (!pos) { + return; + } + var newNodePos = { + x: pos.x - elem.offset.x, + y: pos.y - elem.offset.y, + }; + var dbf = this.dragBoundFunc(); + if (dbf !== undefined) { + const bounded = dbf.call(this, newNodePos, evt); + if (!bounded) { + Util.warn('dragBoundFunc did not return any value. That is unexpected behavior. You must return new absolute position from dragBoundFunc.'); + } + else { + newNodePos = bounded; + } + } + if (!this._lastPos || + this._lastPos.x !== newNodePos.x || + this._lastPos.y !== newNodePos.y) { + this.setAbsolutePosition(newNodePos); + this._requestDraw(); + } + this._lastPos = newNodePos; + } + /** + * stop drag and drop + * @method + * @name Konva.Node#stopDrag + */ + stopDrag(evt) { + const elem = DD._dragElements.get(this._id); + if (elem) { + elem.dragStatus = 'stopped'; + } + DD._endDragBefore(evt); + DD._endDragAfter(evt); + } + setDraggable(draggable) { + this._setAttr('draggable', draggable); + this._dragChange(); + } + /** + * determine if node is currently in drag and drop mode + * @method + * @name Konva.Node#isDragging + */ + isDragging() { + const elem = DD._dragElements.get(this._id); + return elem ? elem.dragStatus === 'dragging' : false; + } + _listenDrag() { + this._dragCleanup(); + this.on('mousedown.konva touchstart.konva', function (evt) { + var shouldCheckButton = evt.evt['button'] !== undefined; + var canDrag = !shouldCheckButton || Konva$2.dragButtons.indexOf(evt.evt['button']) >= 0; + if (!canDrag) { + return; + } + if (this.isDragging()) { + return; + } + var hasDraggingChild = false; + DD._dragElements.forEach((elem) => { + if (this.isAncestorOf(elem.node)) { + hasDraggingChild = true; + } + }); + // nested drag can be started + // in that case we don't need to start new drag + if (!hasDraggingChild) { + this._createDragElement(evt); + } + }); + } + _dragChange() { + if (this.attrs.draggable) { + this._listenDrag(); + } + else { + // remove event listeners + this._dragCleanup(); + /* + * force drag and drop to end + * if this node is currently in + * drag and drop mode + */ + var stage = this.getStage(); + if (!stage) { + return; + } + const dragElement = DD._dragElements.get(this._id); + const isDragging = dragElement && dragElement.dragStatus === 'dragging'; + const isReady = dragElement && dragElement.dragStatus === 'ready'; + if (isDragging) { + this.stopDrag(); + } + else if (isReady) { + DD._dragElements.delete(this._id); + } + } + } + _dragCleanup() { + this.off('mousedown.konva'); + this.off('touchstart.konva'); + } + /** + * create node with JSON string or an Object. De-serializtion does not generate custom + * shape drawing functions, images, or event handlers (this would make the + * serialized object huge). If your app uses custom shapes, images, and + * event handlers (it probably does), then you need to select the appropriate + * shapes after loading the stage and set these properties via on(), setSceneFunc(), + * and setImage() methods + * @method + * @memberof Konva.Node + * @param {String|Object} json string or object + * @param {Element} [container] optional container dom element used only if you're + * creating a stage node + */ + static create(data, container) { + if (Util._isString(data)) { + data = JSON.parse(data); + } + return this._createNode(data, container); + } + static _createNode(obj, container) { + var className = Node.prototype.getClassName.call(obj), children = obj.children, no, len, n; + // if container was passed in, add it to attrs + if (container) { + obj.attrs.container = container; + } + if (!Konva$2[className]) { + Util.warn('Can not find a node with class name "' + + className + + '". Fallback to "Shape".'); + className = 'Shape'; + } + const Class = Konva$2[className]; + no = new Class(obj.attrs); + if (children) { + len = children.length; + for (n = 0; n < len; n++) { + no.add(Node._createNode(children[n])); + } + } + return no; } - return no; - } } Node.prototype.nodeType = 'Node'; Node.prototype._attrsAffectingSize = []; @@ -4912,21 +4576,21 @@ // that way we don't spend too much time on making an new instance Node.prototype.eventListeners = {}; Node.prototype.on.call(Node.prototype, TRANSFORM_CHANGE_STR$1, function () { - if (this._batchingTransformChange) { - this._needClearTransformCache = true; - return; - } - this._clearCache(TRANSFORM); - this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + if (this._batchingTransformChange) { + this._needClearTransformCache = true; + return; + } + this._clearCache(TRANSFORM); + this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); }); Node.prototype.on.call(Node.prototype, 'visibleChange.konva', function () { - this._clearSelfAndDescendantCache(VISIBLE); + this._clearSelfAndDescendantCache(VISIBLE); }); Node.prototype.on.call(Node.prototype, 'listeningChange.konva', function () { - this._clearSelfAndDescendantCache(LISTENING); + this._clearSelfAndDescendantCache(LISTENING); }); Node.prototype.on.call(Node.prototype, 'opacityChange.konva', function () { - this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); + this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); }); const addGetterSetter = Factory.addGetterSetter; /** @@ -5010,12 +4674,7 @@ * // set y * node.y(5); */ - addGetterSetter( - Node, - 'globalCompositeOperation', - 'source-over', - getStringValidator() - ); + addGetterSetter(Node, 'globalCompositeOperation', 'source-over', getStringValidator()); /** * get/set globalCompositeOperation of a node. globalCompositeOperation DOESN'T affect hit graph of nodes. So they are still trigger to events as they have default "source-over" globalCompositeOperation. * @name Konva.Node#globalCompositeOperation @@ -5313,8 +4972,8 @@ */ addGetterSetter(Node, 'preventDefault', true, getBooleanValidator()); addGetterSetter(Node, 'filters', null, function (val) { - this._filterUpToDate = false; - return val; + this._filterUpToDate = false; + return val; }); /** * get/set filters. Filters are applied to cached canvases @@ -5434,11 +5093,11 @@ */ addGetterSetter(Node, 'draggable', false, getBooleanValidator()); Factory.backCompat(Node, { - rotateDeg: 'rotate', - setRotationDeg: 'setRotation', - getRotationDeg: 'getRotation', - }); - + rotateDeg: 'rotate', + setRotationDeg: 'setRotation', + getRotationDeg: 'getRotation', + }); + /** * Container constructor.  Containers are used to contain nodes or other containers * @constructor @@ -5450,461 +5109,447 @@ * @@containerParams */ class Container extends Node { - constructor() { - super(...arguments); - this.children = []; - } - /** - * returns an array of direct descendant nodes - * @method - * @name Konva.Container#getChildren - * @param {Function} [filterFunc] filter function - * @returns {Array} - * @example - * // get all children - * var children = layer.getChildren(); - * - * // get only circles - * var circles = layer.getChildren(function(node){ - * return node.getClassName() === 'Circle'; - * }); - */ - getChildren(filterFunc) { - if (!filterFunc) { - return this.children || []; + constructor() { + super(...arguments); + this.children = []; } - const children = this.children || []; - var results = []; - children.forEach(function (child) { - if (filterFunc(child)) { - results.push(child); - } - }); - return results; - } - /** - * determine if node has children - * @method - * @name Konva.Container#hasChildren - * @returns {Boolean} - */ - hasChildren() { - return this.getChildren().length > 0; - } - /** - * remove all children. Children will be still in memory. - * If you want to completely destroy all children please use "destroyChildren" method instead - * @method - * @name Konva.Container#removeChildren - */ - removeChildren() { - this.getChildren().forEach((child) => { - // reset parent to prevent many _setChildrenIndices calls - child.parent = null; - child.index = 0; - child.remove(); - }); - this.children = []; - return this; - } - /** - * destroy all children nodes. - * @method - * @name Konva.Container#destroyChildren - */ - destroyChildren() { - this.getChildren().forEach((child) => { - // reset parent to prevent many _setChildrenIndices calls - child.parent = null; - child.index = 0; - child.destroy(); - }); - this.children = []; - return this; - } - /** - * add a child and children into container - * @name Konva.Container#add - * @method - * @param {...Konva.Node} child - * @returns {Container} - * @example - * layer.add(rect); - * layer.add(shape1, shape2, shape3); - * // remember to redraw layer if you changed something - * layer.draw(); - */ - add(...children) { - if (arguments.length > 1) { - for (var i = 0; i < arguments.length; i++) { - this.add(arguments[i]); - } - return this; - } - var child = children[0]; - if (child.getParent()) { - child.moveTo(this); - return this; - } - this._validateAdd(child); - child._clearCaches(); - child.index = this.getChildren().length; - child.parent = this; - this.getChildren().push(child); - this._fire('add', { - child: child, - }); - // chainable - return this; - } - destroy() { - if (this.hasChildren()) { - this.destroyChildren(); - } - super.destroy(); - return this; - } - /** - * return an array of nodes that match the selector. - * You can provide a string with '#' for id selections and '.' for name selections. - * Or a function that will return true/false when a node is passed through. See example below. - * With strings you can also select by type or class name. Pass multiple selectors - * separated by a comma. - * @method - * @name Konva.Container#find - * @param {String | Function} selector - * @returns {Array} - * @example - * - * Passing a string as a selector - * // select node with id foo - * var node = stage.find('#foo'); - * - * // select nodes with name bar inside layer - * var nodes = layer.find('.bar'); - * - * // select all groups inside layer - * var nodes = layer.find('Group'); - * - * // select all rectangles inside layer - * var nodes = layer.find('Rect'); - * - * // select node with an id of foo or a name of bar inside layer - * var nodes = layer.find('#foo, .bar'); - * - * Passing a function as a selector - * - * // get all groups with a function - * var groups = stage.find(node => { - * return node.getType() === 'Group'; - * }); - * - * // get only Nodes with partial opacity - * var alphaNodes = layer.find(node => { - * return node.getType() === 'Node' && node.getAbsoluteOpacity() < 1; - * }); - */ - find(selector) { - // protecting _generalFind to prevent user from accidentally adding - // second argument and getting unexpected `findOne` result - return this._generalFind(selector, false); - } - /** - * return a first node from `find` method - * @method - * @name Konva.Container#findOne - * @param {String | Function} selector - * @returns {Konva.Node | Undefined} - * @example - * // select node with id foo - * var node = stage.findOne('#foo'); - * - * // select node with name bar inside layer - * var nodes = layer.findOne('.bar'); - * - * // select the first node to return true in a function - * var node = stage.findOne(node => { - * return node.getType() === 'Shape' - * }) - */ - findOne(selector) { - var result = this._generalFind(selector, true); - return result.length > 0 ? result[0] : undefined; - } - _generalFind(selector, findOne) { - var retArr = []; - this._descendants((node) => { - const valid = node._isMatch(selector); - if (valid) { - retArr.push(node); - } - if (valid && findOne) { - return true; - } - return false; - }); - return retArr; - } - _descendants(fn) { - let shouldStop = false; - const children = this.getChildren(); - for (const child of children) { - shouldStop = fn(child); - if (shouldStop) { - return true; - } - if (!child.hasChildren()) { - continue; - } - shouldStop = child._descendants(fn); - if (shouldStop) { - return true; - } - } - return false; - } - // extenders - toObject() { - var obj = Node.prototype.toObject.call(this); - obj.children = []; - this.getChildren().forEach((child) => { - obj.children.push(child.toObject()); - }); - return obj; - } - /** - * determine if node is an ancestor - * of descendant - * @method - * @name Konva.Container#isAncestorOf - * @param {Konva.Node} node - */ - isAncestorOf(node) { - var parent = node.getParent(); - while (parent) { - if (parent._id === this._id) { - return true; - } - parent = parent.getParent(); - } - return false; - } - clone(obj) { - // call super method - var node = Node.prototype.clone.call(this, obj); - this.getChildren().forEach(function (no) { - node.add(no.clone()); - }); - return node; - } - /** - * get all shapes that intersect a point. Note: because this method must clear a temporary - * canvas and redraw every shape inside the container, it should only be used for special situations - * because it performs very poorly. Please use the {@link Konva.Stage#getIntersection} method if at all possible - * because it performs much better - * @method - * @name Konva.Container#getAllIntersections - * @param {Object} pos - * @param {Number} pos.x - * @param {Number} pos.y - * @returns {Array} array of shapes - */ - getAllIntersections(pos) { - var arr = []; - this.find('Shape').forEach(function (shape) { - if (shape.isVisible() && shape.intersects(pos)) { - arr.push(shape); - } - }); - return arr; - } - _clearSelfAndDescendantCache(attr, forceEvent) { - var _a; - super._clearSelfAndDescendantCache(attr, forceEvent); - // skip clearing if node is cached with canvas - // for performance reasons !!! - if (this.isCached()) { - return; - } - (_a = this.children) === null || _a === void 0 - ? void 0 - : _a.forEach(function (node) { - node._clearSelfAndDescendantCache(attr, forceEvent); + /** + * returns an array of direct descendant nodes + * @method + * @name Konva.Container#getChildren + * @param {Function} [filterFunc] filter function + * @returns {Array} + * @example + * // get all children + * var children = layer.getChildren(); + * + * // get only circles + * var circles = layer.getChildren(function(node){ + * return node.getClassName() === 'Circle'; + * }); + */ + getChildren(filterFunc) { + if (!filterFunc) { + return this.children || []; + } + const children = this.children || []; + var results = []; + children.forEach(function (child) { + if (filterFunc(child)) { + results.push(child); + } }); - } - _setChildrenIndices() { - var _a; - (_a = this.children) === null || _a === void 0 - ? void 0 - : _a.forEach(function (child, n) { - child.index = n; + return results; + } + /** + * determine if node has children + * @method + * @name Konva.Container#hasChildren + * @returns {Boolean} + */ + hasChildren() { + return this.getChildren().length > 0; + } + /** + * remove all children. Children will be still in memory. + * If you want to completely destroy all children please use "destroyChildren" method instead + * @method + * @name Konva.Container#removeChildren + */ + removeChildren() { + this.getChildren().forEach((child) => { + // reset parent to prevent many _setChildrenIndices calls + child.parent = null; + child.index = 0; + child.remove(); }); - } - drawScene(can, top) { - var layer = this.getLayer(), - canvas = can || (layer && layer.getCanvas()), - context = canvas && canvas.getContext(), - cachedCanvas = this._getCanvasCache(), - cachedSceneCanvas = cachedCanvas && cachedCanvas.scene; - var caching = canvas && canvas.isCache; - if (!this.isVisible() && !caching) { - return this; + this.children = []; + return this; } - if (cachedSceneCanvas) { - context.save(); - var m = this.getAbsoluteTransform(top).getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - this._drawCachedSceneCanvas(context); - context.restore(); - } else { - this._drawChildren('drawScene', canvas, top); - } - return this; - } - drawHit(can, top) { - if (!this.shouldDrawHit(top)) { - return this; - } - var layer = this.getLayer(), - canvas = can || (layer && layer.hitCanvas), - context = canvas && canvas.getContext(), - cachedCanvas = this._getCanvasCache(), - cachedHitCanvas = cachedCanvas && cachedCanvas.hit; - if (cachedHitCanvas) { - context.save(); - var m = this.getAbsoluteTransform(top).getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - this._drawCachedHitCanvas(context); - context.restore(); - } else { - this._drawChildren('drawHit', canvas, top); - } - return this; - } - _drawChildren(drawMethod, canvas, top) { - var _a; - var context = canvas && canvas.getContext(), - clipWidth = this.clipWidth(), - clipHeight = this.clipHeight(), - clipFunc = this.clipFunc(), - hasClip = (clipWidth && clipHeight) || clipFunc; - const selfCache = top === this; - if (hasClip) { - context.save(); - var transform = this.getAbsoluteTransform(top); - var m = transform.getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - context.beginPath(); - if (clipFunc) { - clipFunc.call(this, context, this); - } else { - var clipX = this.clipX(); - var clipY = this.clipY(); - context.rect(clipX, clipY, clipWidth, clipHeight); - } - context.clip(); - m = transform.copy().invert().getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - } - var hasComposition = - !selfCache && - this.globalCompositeOperation() !== 'source-over' && - drawMethod === 'drawScene'; - if (hasComposition) { - context.save(); - context._applyGlobalCompositeOperation(this); - } - (_a = this.children) === null || _a === void 0 - ? void 0 - : _a.forEach(function (child) { - child[drawMethod](canvas, top); + /** + * destroy all children nodes. + * @method + * @name Konva.Container#destroyChildren + */ + destroyChildren() { + this.getChildren().forEach((child) => { + // reset parent to prevent many _setChildrenIndices calls + child.parent = null; + child.index = 0; + child.destroy(); }); - if (hasComposition) { - context.restore(); + this.children = []; + return this; } - if (hasClip) { - context.restore(); + /** + * add a child and children into container + * @name Konva.Container#add + * @method + * @param {...Konva.Node} child + * @returns {Container} + * @example + * layer.add(rect); + * layer.add(shape1, shape2, shape3); + * // remember to redraw layer if you changed something + * layer.draw(); + */ + add(...children) { + if (arguments.length > 1) { + for (var i = 0; i < arguments.length; i++) { + this.add(arguments[i]); + } + return this; + } + var child = children[0]; + if (child.getParent()) { + child.moveTo(this); + return this; + } + this._validateAdd(child); + child._clearCaches(); + child.index = this.getChildren().length; + child.parent = this; + this.getChildren().push(child); + this._fire('add', { + child: child, + }); + this._requestDraw(); + // chainable + return this; } - } - getClientRect(config) { - var _a; - config = config || {}; - var skipTransform = config.skipTransform; - var relativeTo = config.relativeTo; - var minX, minY, maxX, maxY; - var selfRect = { - x: Infinity, - y: Infinity, - width: 0, - height: 0, - }; - var that = this; - (_a = this.children) === null || _a === void 0 - ? void 0 - : _a.forEach(function (child) { - // skip invisible children - if (!child.visible()) { + destroy() { + if (this.hasChildren()) { + this.destroyChildren(); + } + super.destroy(); + return this; + } + /** + * return an array of nodes that match the selector. + * You can provide a string with '#' for id selections and '.' for name selections. + * Or a function that will return true/false when a node is passed through. See example below. + * With strings you can also select by type or class name. Pass multiple selectors + * separated by a comma. + * @method + * @name Konva.Container#find + * @param {String | Function} selector + * @returns {Array} + * @example + * + * Passing a string as a selector + * // select node with id foo + * var node = stage.find('#foo'); + * + * // select nodes with name bar inside layer + * var nodes = layer.find('.bar'); + * + * // select all groups inside layer + * var nodes = layer.find('Group'); + * + * // select all rectangles inside layer + * var nodes = layer.find('Rect'); + * + * // select node with an id of foo or a name of bar inside layer + * var nodes = layer.find('#foo, .bar'); + * + * Passing a function as a selector + * + * // get all groups with a function + * var groups = stage.find(node => { + * return node.getType() === 'Group'; + * }); + * + * // get only Nodes with partial opacity + * var alphaNodes = layer.find(node => { + * return node.getType() === 'Node' && node.getAbsoluteOpacity() < 1; + * }); + */ + find(selector) { + // protecting _generalFind to prevent user from accidentally adding + // second argument and getting unexpected `findOne` result + return this._generalFind(selector, false); + } + /** + * return a first node from `find` method + * @method + * @name Konva.Container#findOne + * @param {String | Function} selector + * @returns {Konva.Node | Undefined} + * @example + * // select node with id foo + * var node = stage.findOne('#foo'); + * + * // select node with name bar inside layer + * var nodes = layer.findOne('.bar'); + * + * // select the first node to return true in a function + * var node = stage.findOne(node => { + * return node.getType() === 'Shape' + * }) + */ + findOne(selector) { + var result = this._generalFind(selector, true); + return result.length > 0 ? result[0] : undefined; + } + _generalFind(selector, findOne) { + var retArr = []; + this._descendants((node) => { + const valid = node._isMatch(selector); + if (valid) { + retArr.push(node); + } + if (valid && findOne) { + return true; + } + return false; + }); + return retArr; + } + _descendants(fn) { + let shouldStop = false; + const children = this.getChildren(); + for (const child of children) { + shouldStop = fn(child); + if (shouldStop) { + return true; + } + if (!child.hasChildren()) { + continue; + } + shouldStop = child._descendants(fn); + if (shouldStop) { + return true; + } + } + return false; + } + // extenders + toObject() { + var obj = Node.prototype.toObject.call(this); + obj.children = []; + this.getChildren().forEach((child) => { + obj.children.push(child.toObject()); + }); + return obj; + } + /** + * determine if node is an ancestor + * of descendant + * @method + * @name Konva.Container#isAncestorOf + * @param {Konva.Node} node + */ + isAncestorOf(node) { + var parent = node.getParent(); + while (parent) { + if (parent._id === this._id) { + return true; + } + parent = parent.getParent(); + } + return false; + } + clone(obj) { + // call super method + var node = Node.prototype.clone.call(this, obj); + this.getChildren().forEach(function (no) { + node.add(no.clone()); + }); + return node; + } + /** + * get all shapes that intersect a point. Note: because this method must clear a temporary + * canvas and redraw every shape inside the container, it should only be used for special situations + * because it performs very poorly. Please use the {@link Konva.Stage#getIntersection} method if at all possible + * because it performs much better + * @method + * @name Konva.Container#getAllIntersections + * @param {Object} pos + * @param {Number} pos.x + * @param {Number} pos.y + * @returns {Array} array of shapes + */ + getAllIntersections(pos) { + var arr = []; + this.find('Shape').forEach(function (shape) { + if (shape.isVisible() && shape.intersects(pos)) { + arr.push(shape); + } + }); + return arr; + } + _clearSelfAndDescendantCache(attr, forceEvent) { + var _a; + super._clearSelfAndDescendantCache(attr, forceEvent); + // skip clearing if node is cached with canvas + // for performance reasons !!! + if (this.isCached()) { return; - } - var rect = child.getClientRect({ - relativeTo: that, - skipShadow: config.skipShadow, - skipStroke: config.skipStroke, - }); - // skip invisible children (like empty groups) - if (rect.width === 0 && rect.height === 0) { - return; - } - if (minX === undefined) { - // initial value for first child - minX = rect.x; - minY = rect.y; - maxX = rect.x + rect.width; - maxY = rect.y + rect.height; - } else { - minX = Math.min(minX, rect.x); - minY = Math.min(minY, rect.y); - maxX = Math.max(maxX, rect.x + rect.width); - maxY = Math.max(maxY, rect.y + rect.height); - } + } + (_a = this.children) === null || _a === void 0 ? void 0 : _a.forEach(function (node) { + node._clearSelfAndDescendantCache(attr, forceEvent); }); - // if child is group we need to make sure it has visible shapes inside - var shapes = this.find('Shape'); - var hasVisible = false; - for (var i = 0; i < shapes.length; i++) { - var shape = shapes[i]; - if (shape._isVisible(this)) { - hasVisible = true; - break; - } } - if (hasVisible && minX !== undefined) { - selfRect = { - x: minX, - y: minY, - width: maxX - minX, - height: maxY - minY, - }; - } else { - selfRect = { - x: 0, - y: 0, - width: 0, - height: 0, - }; + _setChildrenIndices() { + var _a; + (_a = this.children) === null || _a === void 0 ? void 0 : _a.forEach(function (child, n) { + child.index = n; + }); + this._requestDraw(); } - if (!skipTransform) { - return this._transformedRect(selfRect, relativeTo); + drawScene(can, top) { + var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas()), context = canvas && canvas.getContext(), cachedCanvas = this._getCanvasCache(), cachedSceneCanvas = cachedCanvas && cachedCanvas.scene; + var caching = canvas && canvas.isCache; + if (!this.isVisible() && !caching) { + return this; + } + if (cachedSceneCanvas) { + context.save(); + var m = this.getAbsoluteTransform(top).getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + this._drawCachedSceneCanvas(context); + context.restore(); + } + else { + this._drawChildren('drawScene', canvas, top); + } + return this; + } + drawHit(can, top) { + if (!this.shouldDrawHit(top)) { + return this; + } + var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas), context = canvas && canvas.getContext(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit; + if (cachedHitCanvas) { + context.save(); + var m = this.getAbsoluteTransform(top).getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + this._drawCachedHitCanvas(context); + context.restore(); + } + else { + this._drawChildren('drawHit', canvas, top); + } + return this; + } + _drawChildren(drawMethod, canvas, top) { + var _a; + var context = canvas && canvas.getContext(), clipWidth = this.clipWidth(), clipHeight = this.clipHeight(), clipFunc = this.clipFunc(), hasClip = (clipWidth && clipHeight) || clipFunc; + const selfCache = top === this; + if (hasClip) { + context.save(); + var transform = this.getAbsoluteTransform(top); + var m = transform.getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + context.beginPath(); + if (clipFunc) { + clipFunc.call(this, context, this); + } + else { + var clipX = this.clipX(); + var clipY = this.clipY(); + context.rect(clipX, clipY, clipWidth, clipHeight); + } + context.clip(); + m = transform.copy().invert().getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + } + var hasComposition = !selfCache && + this.globalCompositeOperation() !== 'source-over' && + drawMethod === 'drawScene'; + if (hasComposition) { + context.save(); + context._applyGlobalCompositeOperation(this); + } + (_a = this.children) === null || _a === void 0 ? void 0 : _a.forEach(function (child) { + child[drawMethod](canvas, top); + }); + if (hasComposition) { + context.restore(); + } + if (hasClip) { + context.restore(); + } + } + getClientRect(config) { + var _a; + config = config || {}; + var skipTransform = config.skipTransform; + var relativeTo = config.relativeTo; + var minX, minY, maxX, maxY; + var selfRect = { + x: Infinity, + y: Infinity, + width: 0, + height: 0, + }; + var that = this; + (_a = this.children) === null || _a === void 0 ? void 0 : _a.forEach(function (child) { + // skip invisible children + if (!child.visible()) { + return; + } + var rect = child.getClientRect({ + relativeTo: that, + skipShadow: config.skipShadow, + skipStroke: config.skipStroke, + }); + // skip invisible children (like empty groups) + if (rect.width === 0 && rect.height === 0) { + return; + } + if (minX === undefined) { + // initial value for first child + minX = rect.x; + minY = rect.y; + maxX = rect.x + rect.width; + maxY = rect.y + rect.height; + } + else { + minX = Math.min(minX, rect.x); + minY = Math.min(minY, rect.y); + maxX = Math.max(maxX, rect.x + rect.width); + maxY = Math.max(maxY, rect.y + rect.height); + } + }); + // if child is group we need to make sure it has visible shapes inside + var shapes = this.find('Shape'); + var hasVisible = false; + for (var i = 0; i < shapes.length; i++) { + var shape = shapes[i]; + if (shape._isVisible(this)) { + hasVisible = true; + break; + } + } + if (hasVisible && minX !== undefined) { + selfRect = { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY, + }; + } + else { + selfRect = { + x: 0, + y: 0, + width: 0, + height: 0, + }; + } + if (!skipTransform) { + return this._transformedRect(selfRect, relativeTo); + } + return selfRect; } - return selfRect; - } } // add getters setters Factory.addComponentsGetterSetter(Container, 'clip', [ - 'x', - 'y', - 'width', - 'height', + 'x', + 'y', + 'width', + 'height', ]); /** * get/set clip @@ -5956,12 +5601,7 @@ * // set clip y * container.clipY(10); */ - Factory.addGetterSetter( - Container, - 'clipWidth', - undefined, - getNumberValidator() - ); + Factory.addGetterSetter(Container, 'clipWidth', undefined, getNumberValidator()); /** * get/set clip width * @name Konva.Container#clipWidth @@ -5975,12 +5615,7 @@ * // set clip width * container.clipWidth(100); */ - Factory.addGetterSetter( - Container, - 'clipHeight', - undefined, - getNumberValidator() - ); + Factory.addGetterSetter(Container, 'clipHeight', undefined, getNumberValidator()); /** * get/set clip height * @name Konva.Container#clipHeight @@ -6009,97 +5644,50 @@ * container.clipFunc(function(ctx) { * ctx.rect(0, 0, 100, 100); * }); - */ - + */ + const Captures = new Map(); // we may use this module for capturing touch events too // so make sure we don't do something super specific to pointer const SUPPORT_POINTER_EVENTS = Konva$2._global['PointerEvent'] !== undefined; function getCapturedShape(pointerId) { - return Captures.get(pointerId); + return Captures.get(pointerId); } function createEvent(evt) { - return { - evt, - pointerId: evt.pointerId, - }; + return { + evt, + pointerId: evt.pointerId, + }; } function hasPointerCapture(pointerId, shape) { - return Captures.get(pointerId) === shape; + return Captures.get(pointerId) === shape; } function setPointerCapture(pointerId, shape) { - releaseCapture(pointerId); - const stage = shape.getStage(); - if (!stage) return; - Captures.set(pointerId, shape); - if (SUPPORT_POINTER_EVENTS) { - shape._fire( - 'gotpointercapture', - createEvent(new PointerEvent('gotpointercapture')) - ); - } + releaseCapture(pointerId); + const stage = shape.getStage(); + if (!stage) + return; + Captures.set(pointerId, shape); + if (SUPPORT_POINTER_EVENTS) { + shape._fire('gotpointercapture', createEvent(new PointerEvent('gotpointercapture'))); + } } function releaseCapture(pointerId, target) { - const shape = Captures.get(pointerId); - if (!shape) return; - const stage = shape.getStage(); - if (stage && stage.content); - Captures.delete(pointerId); - if (SUPPORT_POINTER_EVENTS) { - shape._fire( - 'lostpointercapture', - createEvent(new PointerEvent('lostpointercapture')) - ); - } - } - + const shape = Captures.get(pointerId); + if (!shape) + return; + const stage = shape.getStage(); + if (stage && stage.content) ; + Captures.delete(pointerId); + if (SUPPORT_POINTER_EVENTS) { + shape._fire('lostpointercapture', createEvent(new PointerEvent('lostpointercapture'))); + } + } + // CONSTANTS - var STAGE = 'Stage', - STRING = 'string', - PX = 'px', - MOUSEOUT = 'mouseout', - MOUSELEAVE = 'mouseleave', - MOUSEOVER = 'mouseover', - MOUSEENTER = 'mouseenter', - MOUSEMOVE = 'mousemove', - MOUSEDOWN = 'mousedown', - MOUSEUP = 'mouseup', - // TODO: add them into "on" method docs and into site docs - POINTERMOVE = 'pointermove', - POINTERDOWN = 'pointerdown', - POINTERUP = 'pointerup', - POINTERCANCEL = 'pointercancel', - LOSTPOINTERCAPTURE = 'lostpointercapture', - CONTEXTMENU = 'contextmenu', - CLICK = 'click', - DBL_CLICK = 'dblclick', - TOUCHSTART = 'touchstart', - TOUCHEND = 'touchend', - TAP = 'tap', - DBL_TAP = 'dbltap', - TOUCHMOVE = 'touchmove', - WHEEL = 'wheel', - CONTENT_MOUSEOUT = 'contentMouseout', - CONTENT_MOUSEOVER = 'contentMouseover', - CONTENT_MOUSEMOVE = 'contentMousemove', - CONTENT_MOUSEDOWN = 'contentMousedown', - CONTENT_MOUSEUP = 'contentMouseup', - CONTENT_CONTEXTMENU = 'contentContextmenu', - CONTENT_CLICK = 'contentClick', - CONTENT_DBL_CLICK = 'contentDblclick', - CONTENT_TOUCHSTART = 'contentTouchstart', - CONTENT_TOUCHEND = 'contentTouchend', - CONTENT_DBL_TAP = 'contentDbltap', - CONTENT_TAP = 'contentTap', - CONTENT_TOUCHMOVE = 'contentTouchmove', - CONTENT_WHEEL = 'contentWheel', - RELATIVE = 'relative', - KONVA_CONTENT = 'konvajs-content', - UNDERSCORE = '_', - CONTAINER = 'container', - MAX_LAYERS_NUMBER = 5, - EMPTY_STRING$1 = '', - EVENTS = [ + var STAGE = 'Stage', STRING = 'string', PX = 'px', MOUSEOUT = 'mouseout', MOUSELEAVE = 'mouseleave', MOUSEOVER = 'mouseover', MOUSEENTER = 'mouseenter', MOUSEMOVE = 'mousemove', MOUSEDOWN = 'mousedown', MOUSEUP = 'mouseup', + // TODO: add them into "on" method docs and into site docs + POINTERMOVE = 'pointermove', POINTERDOWN = 'pointerdown', POINTERUP = 'pointerup', POINTERCANCEL = 'pointercancel', LOSTPOINTERCAPTURE = 'lostpointercapture', CONTEXTMENU = 'contextmenu', CLICK = 'click', DBL_CLICK = 'dblclick', TOUCHSTART = 'touchstart', TOUCHEND = 'touchend', TAP = 'tap', DBL_TAP = 'dbltap', TOUCHMOVE = 'touchmove', WHEEL = 'wheel', CONTENT_MOUSEOUT = 'contentMouseout', CONTENT_MOUSEOVER = 'contentMouseover', CONTENT_MOUSEMOVE = 'contentMousemove', CONTENT_MOUSEDOWN = 'contentMousedown', CONTENT_MOUSEUP = 'contentMouseup', CONTENT_CONTEXTMENU = 'contentContextmenu', CONTENT_CLICK = 'contentClick', CONTENT_DBL_CLICK = 'contentDblclick', CONTENT_TOUCHSTART = 'contentTouchstart', CONTENT_TOUCHEND = 'contentTouchend', CONTENT_DBL_TAP = 'contentDbltap', CONTENT_TAP = 'contentTap', CONTENT_TOUCHMOVE = 'contentTouchmove', CONTENT_WHEEL = 'contentWheel', RELATIVE = 'relative', KONVA_CONTENT = 'konvajs-content', UNDERSCORE = '_', CONTAINER = 'container', MAX_LAYERS_NUMBER = 5, EMPTY_STRING$1 = '', EVENTS = [ MOUSEENTER, MOUSEDOWN, MOUSEMOVE, @@ -6116,27 +5704,21 @@ POINTERUP, POINTERCANCEL, LOSTPOINTERCAPTURE, - ], - // cached variables - eventsLength = EVENTS.length; + ], + // cached variables + eventsLength = EVENTS.length; function addEvent(ctx, eventName) { - ctx.content.addEventListener( - eventName, - function (evt) { - ctx[UNDERSCORE + eventName](evt); - }, - false - ); + ctx.content.addEventListener(eventName, function (evt) { + ctx[UNDERSCORE + eventName](evt); + }, false); } const NO_POINTERS_MESSAGE = `Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);`; const stages = []; function checkNoClip(attrs = {}) { - if (attrs.clipFunc || attrs.clipWidth || attrs.clipHeight) { - Util.warn( - 'Stage does not support clipping. Please use clip for Layers or Groups.' - ); - } - return attrs; + if (attrs.clipFunc || attrs.clipWidth || attrs.clipHeight) { + Util.warn('Stage does not support clipping. Please use clip for Layers or Groups.'); + } + return attrs; } /** * Stage constructor. A stage is used to contain multiple layers @@ -6154,871 +5736,808 @@ * }); */ class Stage extends Container { - constructor(config) { - super(checkNoClip(config)); - this._pointerPositions = []; - this._changedPointerPositions = []; - this._buildDOM(); - this._bindContentEvents(); - stages.push(this); - this.on('widthChange.konva heightChange.konva', this._resizeDOM); - this.on('visibleChange.konva', this._checkVisibility); - this.on( - 'clipWidthChange.konva clipHeightChange.konva clipFuncChange.konva', - () => { - checkNoClip(this.attrs); - } - ); - this._checkVisibility(); - } - _validateAdd(child) { - const isLayer = child.getType() === 'Layer'; - const isFastLayer = child.getType() === 'FastLayer'; - const valid = isLayer || isFastLayer; - if (!valid) { - Util.throw('You may only add layers to the stage.'); + constructor(config) { + super(checkNoClip(config)); + this._pointerPositions = []; + this._changedPointerPositions = []; + this._buildDOM(); + this._bindContentEvents(); + stages.push(this); + this.on('widthChange.konva heightChange.konva', this._resizeDOM); + this.on('visibleChange.konva', this._checkVisibility); + this.on('clipWidthChange.konva clipHeightChange.konva clipFuncChange.konva', () => { + checkNoClip(this.attrs); + }); + this._checkVisibility(); } - } - _checkVisibility() { - if (!this.content) { - return; - } - const style = this.visible() ? '' : 'none'; - this.content.style.display = style; - } - /** - * set container dom element which contains the stage wrapper div element - * @method - * @name Konva.Stage#setContainer - * @param {DomElement} container can pass in a dom element or id string - */ - setContainer(container) { - if (typeof container === STRING) { - if (container.charAt(0) === '.') { - var className = container.slice(1); - container = document.getElementsByClassName(className)[0]; - } else { - var id; - if (container.charAt(0) !== '#') { - id = container; - } else { - id = container.slice(1); + _validateAdd(child) { + const isLayer = child.getType() === 'Layer'; + const isFastLayer = child.getType() === 'FastLayer'; + const valid = isLayer || isFastLayer; + if (!valid) { + Util.throw('You may only add layers to the stage.'); } - container = document.getElementById(id); - } - if (!container) { - throw 'Can not find container in document with id ' + id; - } } - this._setAttr(CONTAINER, container); - if (this.content) { - if (this.content.parentElement) { - this.content.parentElement.removeChild(this.content); - } - container.appendChild(this.content); - } - return this; - } - shouldDrawHit() { - return true; - } - /** - * clear all layers - * @method - * @name Konva.Stage#clear - */ - clear() { - var layers = this.children, - len = layers.length, - n; - for (n = 0; n < len; n++) { - layers[n].clear(); - } - return this; - } - clone(obj) { - if (!obj) { - obj = {}; - } - obj.container = - typeof document !== 'undefined' && document.createElement('div'); - return Container.prototype.clone.call(this, obj); - } - destroy() { - super.destroy(); - var content = this.content; - if (content && Util._isInDocument(content)) { - this.container().removeChild(content); - } - var index = stages.indexOf(this); - if (index > -1) { - stages.splice(index, 1); - } - return this; - } - /** - * returns absolute pointer position which can be a touch position or mouse position - * pointer position doesn't include any transforms (such as scale) of the stage - * it is just a plain position of pointer relative to top-left corner of the stage container - * @method - * @name Konva.Stage#getPointerPosition - * @returns {Vector2d|null} - */ - getPointerPosition() { - const pos = this._pointerPositions[0] || this._changedPointerPositions[0]; - if (!pos) { - Util.warn(NO_POINTERS_MESSAGE); - return null; - } - return { - x: pos.x, - y: pos.y, - }; - } - _getPointerById(id) { - return this._pointerPositions.find((p) => p.id === id); - } - getPointersPositions() { - return this._pointerPositions; - } - getStage() { - return this; - } - getContent() { - return this.content; - } - _toKonvaCanvas(config) { - config = config || {}; - config.x = config.x || 0; - config.y = config.y || 0; - config.width = config.width || this.width(); - config.height = config.height || this.height(); - var canvas = new SceneCanvas({ - width: config.width, - height: config.height, - pixelRatio: config.pixelRatio || 1, - }); - var _context = canvas.getContext()._context; - var layers = this.children; - if (config.x || config.y) { - _context.translate(-1 * config.x, -1 * config.y); - } - layers.forEach(function (layer) { - if (!layer.isVisible()) { - return; - } - var layerCanvas = layer._toKonvaCanvas(config); - _context.drawImage( - layerCanvas._canvas, - config.x, - config.y, - layerCanvas.getWidth() / layerCanvas.getPixelRatio(), - layerCanvas.getHeight() / layerCanvas.getPixelRatio() - ); - }); - return canvas; - } - /** - * get visible intersection shape. This is the preferred - * method for determining if a point intersects a shape or not - * @method - * @name Konva.Stage#getIntersection - * @param {Object} pos - * @param {Number} pos.x - * @param {Number} pos.y - * @param {String} [selector] - * @returns {Konva.Node} - * @example - * var shape = stage.getIntersection({x: 50, y: 50}); - * // or if you interested in shape parent: - * var group = stage.getIntersection({x: 50, y: 50}, 'Group'); - */ - getIntersection(pos, selector) { - if (!pos) { - return null; - } - var layers = this.children, - len = layers.length, - end = len - 1, - n; - for (n = end; n >= 0; n--) { - const shape = layers[n].getIntersection(pos, selector); - if (shape) { - return shape; - } - } - return null; - } - _resizeDOM() { - var width = this.width(); - var height = this.height(); - if (this.content) { - // set content dimensions - this.content.style.width = width + PX; - this.content.style.height = height + PX; - } - this.bufferCanvas.setSize(width, height); - this.bufferHitCanvas.setSize(width, height); - // set layer dimensions - this.children.forEach((layer) => { - layer.setSize({ width, height }); - layer.draw(); - }); - } - add(layer, ...rest) { - if (arguments.length > 1) { - for (var i = 0; i < arguments.length; i++) { - this.add(arguments[i]); - } - return this; - } - super.add(layer); - var length = this.children.length; - if (length > MAX_LAYERS_NUMBER) { - Util.warn( - 'The stage has ' + - length + - ' layers. Recommended maximum number of layers is 3-5. Adding more layers into the stage may drop the performance. Rethink your tree structure, you can use Konva.Group.' - ); - } - layer.setSize({ width: this.width(), height: this.height() }); - // draw layer and append canvas to container - layer.draw(); - if (Konva$2.isBrowser) { - this.content.appendChild(layer.canvas._canvas); - } - // chainable - return this; - } - getParent() { - return null; - } - getLayer() { - return null; - } - hasPointerCapture(pointerId) { - return hasPointerCapture(pointerId, this); - } - setPointerCapture(pointerId) { - setPointerCapture(pointerId, this); - } - releaseCapture(pointerId) { - releaseCapture(pointerId); - } - /** - * returns an array of layers - * @method - * @name Konva.Stage#getLayers - */ - getLayers() { - return this.children; - } - _bindContentEvents() { - if (!Konva$2.isBrowser) { - return; - } - for (var n = 0; n < eventsLength; n++) { - addEvent(this, EVENTS[n]); - } - } - _mouseenter(evt) { - this.setPointersPositions(evt); - this._fire(MOUSEENTER, { evt: evt, target: this, currentTarget: this }); - } - _mouseover(evt) { - this.setPointersPositions(evt); - this._fire(CONTENT_MOUSEOVER, { evt: evt }); - this._fire(MOUSEOVER, { evt: evt, target: this, currentTarget: this }); - } - _mouseleave(evt) { - var _a; - this.setPointersPositions(evt); - var targetShape = ( - (_a = this.targetShape) === null || _a === void 0 - ? void 0 - : _a.getStage() - ) - ? this.targetShape - : null; - var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; - if (targetShape && eventsEnabled) { - targetShape._fireAndBubble(MOUSEOUT, { evt: evt }); - targetShape._fireAndBubble(MOUSELEAVE, { evt: evt }); - this._fire(MOUSELEAVE, { evt: evt, target: this, currentTarget: this }); - this.targetShape = null; - } else if (eventsEnabled) { - this._fire(MOUSELEAVE, { - evt: evt, - target: this, - currentTarget: this, - }); - this._fire(MOUSEOUT, { - evt: evt, - target: this, - currentTarget: this, - }); - } - this.pointerPos = undefined; - this._pointerPositions = []; - this._fire(CONTENT_MOUSEOUT, { evt: evt }); - } - _mousemove(evt) { - var _a; - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva$2.UA.ieMobile) { - return this._touchmove(evt); - } - this.setPointersPositions(evt); - var pointerId = Util._getFirstPointerId(evt); - var targetShape = ( - (_a = this.targetShape) === null || _a === void 0 - ? void 0 - : _a.getStage() - ) - ? this.targetShape - : null; - var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; - if (eventsEnabled) { - const shape = this.getIntersection(this.getPointerPosition()); - if (shape && shape.isListening()) { - var differentTarget = targetShape !== shape; - if (eventsEnabled && differentTarget) { - if (targetShape) { - targetShape._fireAndBubble( - MOUSEOUT, - { evt: evt, pointerId }, - shape - ); - targetShape._fireAndBubble( - MOUSELEAVE, - { evt: evt, pointerId }, - shape - ); - } - shape._fireAndBubble( - MOUSEOVER, - { evt: evt, pointerId }, - targetShape - ); - shape._fireAndBubble( - MOUSEENTER, - { evt: evt, pointerId }, - targetShape - ); - shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId }); - this.targetShape = shape; - } else { - shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId }); + _checkVisibility() { + if (!this.content) { + return; } - } else { - /* - * if no shape was detected, clear target shape and try - * to run mouseout from previous target shape - */ + const style = this.visible() ? '' : 'none'; + this.content.style.display = style; + } + /** + * set container dom element which contains the stage wrapper div element + * @method + * @name Konva.Stage#setContainer + * @param {DomElement} container can pass in a dom element or id string + */ + setContainer(container) { + if (typeof container === STRING) { + if (container.charAt(0) === '.') { + var className = container.slice(1); + container = document.getElementsByClassName(className)[0]; + } + else { + var id; + if (container.charAt(0) !== '#') { + id = container; + } + else { + id = container.slice(1); + } + container = document.getElementById(id); + } + if (!container) { + throw 'Can not find container in document with id ' + id; + } + } + this._setAttr(CONTAINER, container); + if (this.content) { + if (this.content.parentElement) { + this.content.parentElement.removeChild(this.content); + } + container.appendChild(this.content); + } + return this; + } + shouldDrawHit() { + return true; + } + /** + * clear all layers + * @method + * @name Konva.Stage#clear + */ + clear() { + var layers = this.children, len = layers.length, n; + for (n = 0; n < len; n++) { + layers[n].clear(); + } + return this; + } + clone(obj) { + if (!obj) { + obj = {}; + } + obj.container = + typeof document !== 'undefined' && document.createElement('div'); + return Container.prototype.clone.call(this, obj); + } + destroy() { + super.destroy(); + var content = this.content; + if (content && Util._isInDocument(content)) { + this.container().removeChild(content); + } + var index = stages.indexOf(this); + if (index > -1) { + stages.splice(index, 1); + } + return this; + } + /** + * returns absolute pointer position which can be a touch position or mouse position + * pointer position doesn't include any transforms (such as scale) of the stage + * it is just a plain position of pointer relative to top-left corner of the stage container + * @method + * @name Konva.Stage#getPointerPosition + * @returns {Vector2d|null} + */ + getPointerPosition() { + const pos = this._pointerPositions[0] || this._changedPointerPositions[0]; + if (!pos) { + Util.warn(NO_POINTERS_MESSAGE); + return null; + } + return { + x: pos.x, + y: pos.y, + }; + } + _getPointerById(id) { + return this._pointerPositions.find((p) => p.id === id); + } + getPointersPositions() { + return this._pointerPositions; + } + getStage() { + return this; + } + getContent() { + return this.content; + } + _toKonvaCanvas(config) { + config = config || {}; + config.x = config.x || 0; + config.y = config.y || 0; + config.width = config.width || this.width(); + config.height = config.height || this.height(); + var canvas = new SceneCanvas({ + width: config.width, + height: config.height, + pixelRatio: config.pixelRatio || 1, + }); + var _context = canvas.getContext()._context; + var layers = this.children; + if (config.x || config.y) { + _context.translate(-1 * config.x, -1 * config.y); + } + layers.forEach(function (layer) { + if (!layer.isVisible()) { + return; + } + var layerCanvas = layer._toKonvaCanvas(config); + _context.drawImage(layerCanvas._canvas, config.x, config.y, layerCanvas.getWidth() / layerCanvas.getPixelRatio(), layerCanvas.getHeight() / layerCanvas.getPixelRatio()); + }); + return canvas; + } + /** + * get visible intersection shape. This is the preferred + * method for determining if a point intersects a shape or not + * @method + * @name Konva.Stage#getIntersection + * @param {Object} pos + * @param {Number} pos.x + * @param {Number} pos.y + * @param {String} [selector] + * @returns {Konva.Node} + * @example + * var shape = stage.getIntersection({x: 50, y: 50}); + * // or if you interested in shape parent: + * var group = stage.getIntersection({x: 50, y: 50}, 'Group'); + */ + getIntersection(pos, selector) { + if (!pos) { + return null; + } + var layers = this.children, len = layers.length, end = len - 1, n; + for (n = end; n >= 0; n--) { + const shape = layers[n].getIntersection(pos, selector); + if (shape) { + return shape; + } + } + return null; + } + _resizeDOM() { + var width = this.width(); + var height = this.height(); + if (this.content) { + // set content dimensions + this.content.style.width = width + PX; + this.content.style.height = height + PX; + } + this.bufferCanvas.setSize(width, height); + this.bufferHitCanvas.setSize(width, height); + // set layer dimensions + this.children.forEach((layer) => { + layer.setSize({ width, height }); + layer.draw(); + }); + } + add(layer, ...rest) { + if (arguments.length > 1) { + for (var i = 0; i < arguments.length; i++) { + this.add(arguments[i]); + } + return this; + } + super.add(layer); + var length = this.children.length; + if (length > MAX_LAYERS_NUMBER) { + Util.warn('The stage has ' + + length + + ' layers. Recommended maximum number of layers is 3-5. Adding more layers into the stage may drop the performance. Rethink your tree structure, you can use Konva.Group.'); + } + layer.setSize({ width: this.width(), height: this.height() }); + // draw layer and append canvas to container + layer.draw(); + if (Konva$2.isBrowser) { + this.content.appendChild(layer.canvas._canvas); + } + // chainable + return this; + } + getParent() { + return null; + } + getLayer() { + return null; + } + hasPointerCapture(pointerId) { + return hasPointerCapture(pointerId, this); + } + setPointerCapture(pointerId) { + setPointerCapture(pointerId, this); + } + releaseCapture(pointerId) { + releaseCapture(pointerId); + } + /** + * returns an array of layers + * @method + * @name Konva.Stage#getLayers + */ + getLayers() { + return this.children; + } + _bindContentEvents() { + if (!Konva$2.isBrowser) { + return; + } + for (var n = 0; n < eventsLength; n++) { + addEvent(this, EVENTS[n]); + } + } + _mouseenter(evt) { + this.setPointersPositions(evt); + this._fire(MOUSEENTER, { evt: evt, target: this, currentTarget: this }); + } + _mouseover(evt) { + this.setPointersPositions(evt); + this._fire(CONTENT_MOUSEOVER, { evt: evt }); + this._fire(MOUSEOVER, { evt: evt, target: this, currentTarget: this }); + } + _mouseleave(evt) { + var _a; + this.setPointersPositions(evt); + var targetShape = ((_a = this.targetShape) === null || _a === void 0 ? void 0 : _a.getStage()) ? this.targetShape : null; + var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; if (targetShape && eventsEnabled) { - targetShape._fireAndBubble(MOUSEOUT, { evt: evt, pointerId }); - targetShape._fireAndBubble(MOUSELEAVE, { evt: evt, pointerId }); - this._fire(MOUSEOVER, { - evt: evt, - target: this, - currentTarget: this, - pointerId, - }); - this.targetShape = null; + targetShape._fireAndBubble(MOUSEOUT, { evt: evt }); + targetShape._fireAndBubble(MOUSELEAVE, { evt: evt }); + this._fire(MOUSELEAVE, { evt: evt, target: this, currentTarget: this }); + this.targetShape = null; } - this._fire(MOUSEMOVE, { - evt: evt, - target: this, - currentTarget: this, - pointerId, + else if (eventsEnabled) { + this._fire(MOUSELEAVE, { + evt: evt, + target: this, + currentTarget: this, + }); + this._fire(MOUSEOUT, { + evt: evt, + target: this, + currentTarget: this, + }); + } + this.pointerPos = undefined; + this._pointerPositions = []; + this._fire(CONTENT_MOUSEOUT, { evt: evt }); + } + _mousemove(evt) { + var _a; + this.setPointersPositions(evt); + var pointerId = Util._getFirstPointerId(evt); + var targetShape = ((_a = this.targetShape) === null || _a === void 0 ? void 0 : _a.getStage()) ? this.targetShape : null; + var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; + if (eventsEnabled) { + const shape = this.getIntersection(this.getPointerPosition()); + if (shape && shape.isListening()) { + var differentTarget = targetShape !== shape; + if (eventsEnabled && differentTarget) { + if (targetShape) { + targetShape._fireAndBubble(MOUSEOUT, { evt: evt, pointerId }, shape); + targetShape._fireAndBubble(MOUSELEAVE, { evt: evt, pointerId }, shape); + } + shape._fireAndBubble(MOUSEOVER, { evt: evt, pointerId }, targetShape); + shape._fireAndBubble(MOUSEENTER, { evt: evt, pointerId }, targetShape); + shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId }); + this.targetShape = shape; + } + else { + shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId }); + } + } + else { + /* + * if no shape was detected, clear target shape and try + * to run mouseout from previous target shape + */ + if (targetShape && eventsEnabled) { + targetShape._fireAndBubble(MOUSEOUT, { evt: evt, pointerId }); + targetShape._fireAndBubble(MOUSELEAVE, { evt: evt, pointerId }); + this._fire(MOUSEOVER, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + this.targetShape = null; + } + this._fire(MOUSEMOVE, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + } + // content event + this._fire(CONTENT_MOUSEMOVE, { evt: evt }); + } + // always call preventDefault for desktop events because some browsers + // try to drag and drop the canvas element + if (evt.cancelable) { + evt.preventDefault(); + } + } + _mousedown(evt) { + this.setPointersPositions(evt); + var pointerId = Util._getFirstPointerId(evt); + var shape = this.getIntersection(this.getPointerPosition()); + DD.justDragged = false; + Konva$2.listenClickTap = true; + if (shape && shape.isListening()) { + this.clickStartShape = shape; + shape._fireAndBubble(MOUSEDOWN, { evt: evt, pointerId }); + } + else { + this._fire(MOUSEDOWN, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + } + // content event + this._fire(CONTENT_MOUSEDOWN, { evt: evt }); + // Do not prevent default behavior, because it will prevent listening events outside of window iframe + // we used preventDefault for disabling native drag&drop + // but userSelect = none style will do the trick + // if (evt.cancelable) { + // evt.preventDefault(); + // } + } + _mouseup(evt) { + this.setPointersPositions(evt); + var pointerId = Util._getFirstPointerId(evt); + var shape = this.getIntersection(this.getPointerPosition()), clickStartShape = this.clickStartShape, clickEndShape = this.clickEndShape, fireDblClick = false; + if (Konva$2.inDblClickWindow) { + fireDblClick = true; + clearTimeout(this.dblTimeout); + // Konva.inDblClickWindow = false; + } + else if (!DD.justDragged) { + // don't set inDblClickWindow after dragging + Konva$2.inDblClickWindow = true; + clearTimeout(this.dblTimeout); + } + this.dblTimeout = setTimeout(function () { + Konva$2.inDblClickWindow = false; + }, Konva$2.dblClickWindow); + if (shape && shape.isListening()) { + this.clickEndShape = shape; + shape._fireAndBubble(MOUSEUP, { evt: evt, pointerId }); + // detect if click or double click occurred + if (Konva$2.listenClickTap && + clickStartShape && + clickStartShape._id === shape._id) { + shape._fireAndBubble(CLICK, { evt: evt, pointerId }); + if (fireDblClick && clickEndShape && clickEndShape === shape) { + shape._fireAndBubble(DBL_CLICK, { evt: evt, pointerId }); + } + } + } + else { + this.clickEndShape = null; + this._fire(MOUSEUP, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + if (Konva$2.listenClickTap) { + this._fire(CLICK, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + } + if (fireDblClick) { + this._fire(DBL_CLICK, { + evt: evt, + target: this, + currentTarget: this, + pointerId, + }); + } + } + // content events + this._fire(CONTENT_MOUSEUP, { evt: evt }); + if (Konva$2.listenClickTap) { + this._fire(CONTENT_CLICK, { evt: evt }); + if (fireDblClick) { + this._fire(CONTENT_DBL_CLICK, { evt: evt }); + } + } + Konva$2.listenClickTap = false; + // always call preventDefault for desktop events because some browsers + // try to drag and drop the canvas element + if (evt.cancelable) { + evt.preventDefault(); + } + } + _contextmenu(evt) { + this.setPointersPositions(evt); + var shape = this.getIntersection(this.getPointerPosition()); + if (shape && shape.isListening()) { + shape._fireAndBubble(CONTEXTMENU, { evt: evt }); + } + else { + this._fire(CONTEXTMENU, { + evt: evt, + target: this, + currentTarget: this, + }); + } + this._fire(CONTENT_CONTEXTMENU, { evt: evt }); + } + _touchstart(evt) { + this.setPointersPositions(evt); + var triggeredOnShape = false; + this._changedPointerPositions.forEach((pos) => { + var shape = this.getIntersection(pos); + Konva$2.listenClickTap = true; + DD.justDragged = false; + const hasShape = shape && shape.isListening(); + if (!hasShape) { + return; + } + if (Konva$2.captureTouchEventsEnabled) { + shape.setPointerCapture(pos.id); + } + this.tapStartShape = shape; + shape._fireAndBubble(TOUCHSTART, { evt: evt, pointerId: pos.id }, this); + triggeredOnShape = true; + // only call preventDefault if the shape is listening for events + if (shape.isListening() && shape.preventDefault() && evt.cancelable) { + evt.preventDefault(); + } }); - } - // content event - this._fire(CONTENT_MOUSEMOVE, { evt: evt }); - } - // always call preventDefault for desktop events because some browsers - // try to drag and drop the canvas element - if (evt.cancelable) { - evt.preventDefault(); - } - } - _mousedown(evt) { - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva$2.UA.ieMobile) { - return this._touchstart(evt); - } - this.setPointersPositions(evt); - var pointerId = Util._getFirstPointerId(evt); - var shape = this.getIntersection(this.getPointerPosition()); - DD.justDragged = false; - Konva$2.listenClickTap = true; - if (shape && shape.isListening()) { - this.clickStartShape = shape; - shape._fireAndBubble(MOUSEDOWN, { evt: evt, pointerId }); - } else { - this._fire(MOUSEDOWN, { - evt: evt, - target: this, - currentTarget: this, - pointerId, - }); - } - // content event - this._fire(CONTENT_MOUSEDOWN, { evt: evt }); - // Do not prevent default behavior, because it will prevent listening events outside of window iframe - // we used preventDefault for disabling native drag&drop - // but userSelect = none style will do the trick - // if (evt.cancelable) { - // evt.preventDefault(); - // } - } - _mouseup(evt) { - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva$2.UA.ieMobile) { - return this._touchend(evt); - } - this.setPointersPositions(evt); - var pointerId = Util._getFirstPointerId(evt); - var shape = this.getIntersection(this.getPointerPosition()), - clickStartShape = this.clickStartShape, - clickEndShape = this.clickEndShape, - fireDblClick = false; - if (Konva$2.inDblClickWindow) { - fireDblClick = true; - clearTimeout(this.dblTimeout); - // Konva.inDblClickWindow = false; - } else if (!DD.justDragged) { - // don't set inDblClickWindow after dragging - Konva$2.inDblClickWindow = true; - clearTimeout(this.dblTimeout); - } - this.dblTimeout = setTimeout(function () { - Konva$2.inDblClickWindow = false; - }, Konva$2.dblClickWindow); - if (shape && shape.isListening()) { - this.clickEndShape = shape; - shape._fireAndBubble(MOUSEUP, { evt: evt, pointerId }); - // detect if click or double click occurred - if ( - Konva$2.listenClickTap && - clickStartShape && - clickStartShape._id === shape._id - ) { - shape._fireAndBubble(CLICK, { evt: evt, pointerId }); - if (fireDblClick && clickEndShape && clickEndShape === shape) { - shape._fireAndBubble(DBL_CLICK, { evt: evt, pointerId }); + if (!triggeredOnShape) { + this._fire(TOUCHSTART, { + evt: evt, + target: this, + currentTarget: this, + pointerId: this._changedPointerPositions[0].id, + }); } - } - } else { - this.clickEndShape = null; - this._fire(MOUSEUP, { - evt: evt, - target: this, - currentTarget: this, - pointerId, - }); - if (Konva$2.listenClickTap) { - this._fire(CLICK, { - evt: evt, - target: this, - currentTarget: this, - pointerId, + // content event + this._fire(CONTENT_TOUCHSTART, { evt: evt }); + } + _touchmove(evt) { + this.setPointersPositions(evt); + var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; + if (eventsEnabled) { + var triggeredOnShape = false; + var processedShapesIds = {}; + this._changedPointerPositions.forEach((pos) => { + const shape = getCapturedShape(pos.id) || this.getIntersection(pos); + const hasShape = shape && shape.isListening(); + if (!hasShape) { + return; + } + if (processedShapesIds[shape._id]) { + return; + } + processedShapesIds[shape._id] = true; + shape._fireAndBubble(TOUCHMOVE, { evt: evt, pointerId: pos.id }); + triggeredOnShape = true; + // only call preventDefault if the shape is listening for events + if (shape.isListening() && shape.preventDefault() && evt.cancelable) { + evt.preventDefault(); + } + }); + if (!triggeredOnShape) { + this._fire(TOUCHMOVE, { + evt: evt, + target: this, + currentTarget: this, + pointerId: this._changedPointerPositions[0].id, + }); + } + this._fire(CONTENT_TOUCHMOVE, { evt: evt }); + } + if (DD.isDragging && DD.node.preventDefault() && evt.cancelable) { + evt.preventDefault(); + } + } + _touchend(evt) { + this.setPointersPositions(evt); + var tapEndShape = this.tapEndShape, fireDblClick = false; + if (Konva$2.inDblClickWindow) { + fireDblClick = true; + clearTimeout(this.dblTimeout); + // Konva.inDblClickWindow = false; + } + else if (!DD.justDragged) { + Konva$2.inDblClickWindow = true; + clearTimeout(this.dblTimeout); + } + this.dblTimeout = setTimeout(function () { + Konva$2.inDblClickWindow = false; + }, Konva$2.dblClickWindow); + var triggeredOnShape = false; + var processedShapesIds = {}; + var tapTriggered = false; + var dblTapTriggered = false; + this._changedPointerPositions.forEach((pos) => { + var shape = getCapturedShape(pos.id) || + this.getIntersection(pos); + if (shape) { + shape.releaseCapture(pos.id); + } + const hasShape = shape && shape.isListening(); + if (!hasShape) { + return; + } + if (processedShapesIds[shape._id]) { + return; + } + processedShapesIds[shape._id] = true; + this.tapEndShape = shape; + shape._fireAndBubble(TOUCHEND, { evt: evt, pointerId: pos.id }); + triggeredOnShape = true; + // detect if tap or double tap occurred + if (Konva$2.listenClickTap && shape === this.tapStartShape) { + tapTriggered = true; + shape._fireAndBubble(TAP, { evt: evt, pointerId: pos.id }); + if (fireDblClick && tapEndShape && tapEndShape === shape) { + dblTapTriggered = true; + shape._fireAndBubble(DBL_TAP, { evt: evt, pointerId: pos.id }); + } + } + // only call preventDefault if the shape is listening for events + if (shape.isListening() && shape.preventDefault() && evt.cancelable) { + evt.preventDefault(); + } }); - } - if (fireDblClick) { - this._fire(DBL_CLICK, { - evt: evt, - target: this, - currentTarget: this, - pointerId, + if (!triggeredOnShape) { + this._fire(TOUCHEND, { + evt: evt, + target: this, + currentTarget: this, + pointerId: this._changedPointerPositions[0].id, + }); + } + if (Konva$2.listenClickTap && !tapTriggered) { + this.tapEndShape = null; + this._fire(TAP, { + evt: evt, + target: this, + currentTarget: this, + pointerId: this._changedPointerPositions[0].id, + }); + } + if (fireDblClick && !dblTapTriggered) { + this._fire(DBL_TAP, { + evt: evt, + target: this, + currentTarget: this, + pointerId: this._changedPointerPositions[0].id, + }); + } + // content events + this._fire(CONTENT_TOUCHEND, { evt: evt }); + if (Konva$2.listenClickTap) { + this._fire(CONTENT_TAP, { evt: evt }); + if (fireDblClick) { + this._fire(CONTENT_DBL_TAP, { evt: evt }); + } + } + if (this.preventDefault() && evt.cancelable) { + evt.preventDefault(); + } + Konva$2.listenClickTap = false; + } + _wheel(evt) { + this.setPointersPositions(evt); + var shape = this.getIntersection(this.getPointerPosition()); + if (shape && shape.isListening()) { + shape._fireAndBubble(WHEEL, { evt: evt }); + } + else { + this._fire(WHEEL, { + evt: evt, + target: this, + currentTarget: this, + }); + } + this._fire(CONTENT_WHEEL, { evt: evt }); + } + _pointerdown(evt) { + if (!Konva$2._pointerEventsEnabled) { + return; + } + this.setPointersPositions(evt); + const shape = getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + if (shape) { + shape._fireAndBubble(POINTERDOWN, createEvent(evt)); + } + } + _pointermove(evt) { + if (!Konva$2._pointerEventsEnabled) { + return; + } + this.setPointersPositions(evt); + const shape = getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + if (shape) { + shape._fireAndBubble(POINTERMOVE, createEvent(evt)); + } + } + _pointerup(evt) { + if (!Konva$2._pointerEventsEnabled) { + return; + } + this.setPointersPositions(evt); + const shape = getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + if (shape) { + shape._fireAndBubble(POINTERUP, createEvent(evt)); + } + releaseCapture(evt.pointerId); + } + _pointercancel(evt) { + if (!Konva$2._pointerEventsEnabled) { + return; + } + this.setPointersPositions(evt); + const shape = getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + if (shape) { + shape._fireAndBubble(POINTERUP, createEvent(evt)); + } + releaseCapture(evt.pointerId); + } + _lostpointercapture(evt) { + releaseCapture(evt.pointerId); + } + /** + * manually register pointers positions (mouse/touch) in the stage. + * So you can use stage.getPointerPosition(). Usually you don't need to use that method + * because all internal events are automatically registered. It may be useful if event + * is triggered outside of the stage, but you still want to use Konva methods to get pointers position. + * @method + * @name Konva.Stage#setPointersPositions + * @param {Object} event Event object + * @example + * + * window.addEventListener('mousemove', (e) => { + * stage.setPointersPositions(e); + * }); + */ + setPointersPositions(evt) { + var contentPosition = this._getContentPosition(), x = null, y = null; + evt = evt ? evt : window.event; + // touch events + if (evt.touches !== undefined) { + // touchlist has not support for map method + // so we have to iterate + this._pointerPositions = []; + this._changedPointerPositions = []; + Array.prototype.forEach.call(evt.touches, (touch) => { + this._pointerPositions.push({ + id: touch.identifier, + x: (touch.clientX - contentPosition.left) / contentPosition.scaleX, + y: (touch.clientY - contentPosition.top) / contentPosition.scaleY, + }); + }); + Array.prototype.forEach.call(evt.changedTouches || evt.touches, (touch) => { + this._changedPointerPositions.push({ + id: touch.identifier, + x: (touch.clientX - contentPosition.left) / contentPosition.scaleX, + y: (touch.clientY - contentPosition.top) / contentPosition.scaleY, + }); + }); + } + else { + // mouse events + x = (evt.clientX - contentPosition.left) / contentPosition.scaleX; + y = (evt.clientY - contentPosition.top) / contentPosition.scaleY; + this.pointerPos = { + x: x, + y: y, + }; + this._pointerPositions = [{ x, y, id: Util._getFirstPointerId(evt) }]; + this._changedPointerPositions = [ + { x, y, id: Util._getFirstPointerId(evt) }, + ]; + } + } + _setPointerPosition(evt) { + Util.warn('Method _setPointerPosition is deprecated. Use "stage.setPointersPositions(event)" instead.'); + this.setPointersPositions(evt); + } + _getContentPosition() { + if (!this.content || !this.content.getBoundingClientRect) { + return { + top: 0, + left: 0, + scaleX: 1, + scaleY: 1, + }; + } + var rect = this.content.getBoundingClientRect(); + return { + top: rect.top, + left: rect.left, + // sometimes clientWidth can be equals to 0 + // i saw it in react-konva test, looks like it is because of hidden testing element + scaleX: rect.width / this.content.clientWidth || 1, + scaleY: rect.height / this.content.clientHeight || 1, + }; + } + _buildDOM() { + this.bufferCanvas = new SceneCanvas({ + width: this.width(), + height: this.height(), }); - } - } - // content events - this._fire(CONTENT_MOUSEUP, { evt: evt }); - if (Konva$2.listenClickTap) { - this._fire(CONTENT_CLICK, { evt: evt }); - if (fireDblClick) { - this._fire(CONTENT_DBL_CLICK, { evt: evt }); - } - } - Konva$2.listenClickTap = false; - // always call preventDefault for desktop events because some browsers - // try to drag and drop the canvas element - if (evt.cancelable) { - evt.preventDefault(); - } - } - _contextmenu(evt) { - this.setPointersPositions(evt); - var shape = this.getIntersection(this.getPointerPosition()); - if (shape && shape.isListening()) { - shape._fireAndBubble(CONTEXTMENU, { evt: evt }); - } else { - this._fire(CONTEXTMENU, { - evt: evt, - target: this, - currentTarget: this, - }); - } - this._fire(CONTENT_CONTEXTMENU, { evt: evt }); - } - _touchstart(evt) { - this.setPointersPositions(evt); - var triggeredOnShape = false; - this._changedPointerPositions.forEach((pos) => { - var shape = this.getIntersection(pos); - Konva$2.listenClickTap = true; - DD.justDragged = false; - const hasShape = shape && shape.isListening(); - if (!hasShape) { - return; - } - if (Konva$2.captureTouchEventsEnabled) { - shape.setPointerCapture(pos.id); - } - this.tapStartShape = shape; - shape._fireAndBubble(TOUCHSTART, { evt: evt, pointerId: pos.id }, this); - triggeredOnShape = true; - // only call preventDefault if the shape is listening for events - if (shape.isListening() && shape.preventDefault() && evt.cancelable) { - evt.preventDefault(); - } - }); - if (!triggeredOnShape) { - this._fire(TOUCHSTART, { - evt: evt, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }); - } - // content event - this._fire(CONTENT_TOUCHSTART, { evt: evt }); - } - _touchmove(evt) { - this.setPointersPositions(evt); - var eventsEnabled = !DD.isDragging || Konva$2.hitOnDragEnabled; - if (eventsEnabled) { - var triggeredOnShape = false; - var processedShapesIds = {}; - this._changedPointerPositions.forEach((pos) => { - const shape = getCapturedShape(pos.id) || this.getIntersection(pos); - const hasShape = shape && shape.isListening(); - if (!hasShape) { - return; - } - if (processedShapesIds[shape._id]) { - return; - } - processedShapesIds[shape._id] = true; - shape._fireAndBubble(TOUCHMOVE, { evt: evt, pointerId: pos.id }); - triggeredOnShape = true; - // only call preventDefault if the shape is listening for events - if (shape.isListening() && shape.preventDefault() && evt.cancelable) { - evt.preventDefault(); - } - }); - if (!triggeredOnShape) { - this._fire(TOUCHMOVE, { - evt: evt, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, + this.bufferHitCanvas = new HitCanvas({ + pixelRatio: 1, + width: this.width(), + height: this.height(), }); - } - this._fire(CONTENT_TOUCHMOVE, { evt: evt }); - } - if (DD.isDragging && DD.node.preventDefault() && evt.cancelable) { - evt.preventDefault(); - } - } - _touchend(evt) { - this.setPointersPositions(evt); - var tapEndShape = this.tapEndShape, - fireDblClick = false; - if (Konva$2.inDblClickWindow) { - fireDblClick = true; - clearTimeout(this.dblTimeout); - // Konva.inDblClickWindow = false; - } else if (!DD.justDragged) { - Konva$2.inDblClickWindow = true; - clearTimeout(this.dblTimeout); - } - this.dblTimeout = setTimeout(function () { - Konva$2.inDblClickWindow = false; - }, Konva$2.dblClickWindow); - var triggeredOnShape = false; - var processedShapesIds = {}; - var tapTriggered = false; - var dblTapTriggered = false; - this._changedPointerPositions.forEach((pos) => { - var shape = getCapturedShape(pos.id) || this.getIntersection(pos); - if (shape) { - shape.releaseCapture(pos.id); - } - const hasShape = shape && shape.isListening(); - if (!hasShape) { - return; - } - if (processedShapesIds[shape._id]) { - return; - } - processedShapesIds[shape._id] = true; - this.tapEndShape = shape; - shape._fireAndBubble(TOUCHEND, { evt: evt, pointerId: pos.id }); - triggeredOnShape = true; - // detect if tap or double tap occurred - if (Konva$2.listenClickTap && shape === this.tapStartShape) { - tapTriggered = true; - shape._fireAndBubble(TAP, { evt: evt, pointerId: pos.id }); - if (fireDblClick && tapEndShape && tapEndShape === shape) { - dblTapTriggered = true; - shape._fireAndBubble(DBL_TAP, { evt: evt, pointerId: pos.id }); + if (!Konva$2.isBrowser) { + return; } - } - // only call preventDefault if the shape is listening for events - if (shape.isListening() && shape.preventDefault() && evt.cancelable) { - evt.preventDefault(); - } - }); - if (!triggeredOnShape) { - this._fire(TOUCHEND, { - evt: evt, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }); + var container = this.container(); + if (!container) { + throw 'Stage has no container. A container is required.'; + } + // clear content inside container + container.innerHTML = EMPTY_STRING$1; + // content + this.content = document.createElement('div'); + this.content.style.position = RELATIVE; + this.content.style.userSelect = 'none'; + this.content.className = KONVA_CONTENT; + this.content.setAttribute('role', 'presentation'); + container.appendChild(this.content); + this._resizeDOM(); } - if (Konva$2.listenClickTap && !tapTriggered) { - this.tapEndShape = null; - this._fire(TAP, { - evt: evt, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }); + // currently cache function is now working for stage, because stage has no its own canvas element + cache() { + Util.warn('Cache function is not allowed for stage. You may use cache only for layers, groups and shapes.'); + return this; } - if (fireDblClick && !dblTapTriggered) { - this._fire(DBL_TAP, { - evt: evt, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }); + clearCache() { + return this; } - // content events - this._fire(CONTENT_TOUCHEND, { evt: evt }); - if (Konva$2.listenClickTap) { - this._fire(CONTENT_TAP, { evt: evt }); - if (fireDblClick) { - this._fire(CONTENT_DBL_TAP, { evt: evt }); - } - } - if (this.preventDefault() && evt.cancelable) { - evt.preventDefault(); - } - Konva$2.listenClickTap = false; - } - _wheel(evt) { - this.setPointersPositions(evt); - var shape = this.getIntersection(this.getPointerPosition()); - if (shape && shape.isListening()) { - shape._fireAndBubble(WHEEL, { evt: evt }); - } else { - this._fire(WHEEL, { - evt: evt, - target: this, - currentTarget: this, - }); - } - this._fire(CONTENT_WHEEL, { evt: evt }); - } - _pointerdown(evt) { - if (!Konva$2._pointerEventsEnabled) { - return; - } - this.setPointersPositions(evt); - const shape = - getCapturedShape(evt.pointerId) || - this.getIntersection(this.getPointerPosition()); - if (shape) { - shape._fireAndBubble(POINTERDOWN, createEvent(evt)); - } - } - _pointermove(evt) { - if (!Konva$2._pointerEventsEnabled) { - return; - } - this.setPointersPositions(evt); - const shape = - getCapturedShape(evt.pointerId) || - this.getIntersection(this.getPointerPosition()); - if (shape) { - shape._fireAndBubble(POINTERMOVE, createEvent(evt)); - } - } - _pointerup(evt) { - if (!Konva$2._pointerEventsEnabled) { - return; - } - this.setPointersPositions(evt); - const shape = - getCapturedShape(evt.pointerId) || - this.getIntersection(this.getPointerPosition()); - if (shape) { - shape._fireAndBubble(POINTERUP, createEvent(evt)); - } - releaseCapture(evt.pointerId); - } - _pointercancel(evt) { - if (!Konva$2._pointerEventsEnabled) { - return; - } - this.setPointersPositions(evt); - const shape = - getCapturedShape(evt.pointerId) || - this.getIntersection(this.getPointerPosition()); - if (shape) { - shape._fireAndBubble(POINTERUP, createEvent(evt)); - } - releaseCapture(evt.pointerId); - } - _lostpointercapture(evt) { - releaseCapture(evt.pointerId); - } - /** - * manually register pointers positions (mouse/touch) in the stage. - * So you can use stage.getPointerPosition(). Usually you don't need to use that method - * because all internal events are automatically registered. It may be useful if event - * is triggered outside of the stage, but you still want to use Konva methods to get pointers position. - * @method - * @name Konva.Stage#setPointersPositions - * @param {Object} event Event object - * @example - * - * window.addEventListener('mousemove', (e) => { - * stage.setPointersPositions(e); - * }); - */ - setPointersPositions(evt) { - var contentPosition = this._getContentPosition(), - x = null, - y = null; - evt = evt ? evt : window.event; - // touch events - if (evt.touches !== undefined) { - // touchlist has not support for map method - // so we have to iterate - this._pointerPositions = []; - this._changedPointerPositions = []; - Array.prototype.forEach.call(evt.touches, (touch) => { - this._pointerPositions.push({ - id: touch.identifier, - x: (touch.clientX - contentPosition.left) / contentPosition.scaleX, - y: (touch.clientY - contentPosition.top) / contentPosition.scaleY, + /** + * batch draw + * @method + * @name Konva.Stage#batchDraw + * @return {Konva.Stage} this + */ + batchDraw() { + this.getChildren().forEach(function (layer) { + layer.batchDraw(); }); - }); - Array.prototype.forEach.call( - evt.changedTouches || evt.touches, - (touch) => { - this._changedPointerPositions.push({ - id: touch.identifier, - x: - (touch.clientX - contentPosition.left) / contentPosition.scaleX, - y: (touch.clientY - contentPosition.top) / contentPosition.scaleY, - }); - } - ); - } else { - // mouse events - x = (evt.clientX - contentPosition.left) / contentPosition.scaleX; - y = (evt.clientY - contentPosition.top) / contentPosition.scaleY; - this.pointerPos = { - x: x, - y: y, - }; - this._pointerPositions = [{ x, y, id: Util._getFirstPointerId(evt) }]; - this._changedPointerPositions = [ - { x, y, id: Util._getFirstPointerId(evt) }, - ]; + return this; } - } - _setPointerPosition(evt) { - Util.warn( - 'Method _setPointerPosition is deprecated. Use "stage.setPointersPositions(event)" instead.' - ); - this.setPointersPositions(evt); - } - _getContentPosition() { - if (!this.content || !this.content.getBoundingClientRect) { - return { - top: 0, - left: 0, - scaleX: 1, - scaleY: 1, - }; - } - var rect = this.content.getBoundingClientRect(); - return { - top: rect.top, - left: rect.left, - // sometimes clientWidth can be equals to 0 - // i saw it in react-konva test, looks like it is because of hidden testing element - scaleX: rect.width / this.content.clientWidth || 1, - scaleY: rect.height / this.content.clientHeight || 1, - }; - } - _buildDOM() { - this.bufferCanvas = new SceneCanvas({ - width: this.width(), - height: this.height(), - }); - this.bufferHitCanvas = new HitCanvas({ - pixelRatio: 1, - width: this.width(), - height: this.height(), - }); - if (!Konva$2.isBrowser) { - return; - } - var container = this.container(); - if (!container) { - throw 'Stage has no container. A container is required.'; - } - // clear content inside container - container.innerHTML = EMPTY_STRING$1; - // content - this.content = document.createElement('div'); - this.content.style.position = RELATIVE; - this.content.style.userSelect = 'none'; - this.content.className = KONVA_CONTENT; - this.content.setAttribute('role', 'presentation'); - container.appendChild(this.content); - this._resizeDOM(); - } - // currently cache function is now working for stage, because stage has no its own canvas element - cache() { - Util.warn( - 'Cache function is not allowed for stage. You may use cache only for layers, groups and shapes.' - ); - return this; - } - clearCache() { - return this; - } - /** - * batch draw - * @method - * @name Konva.Stage#batchDraw - * @return {Konva.Stage} this - */ - batchDraw() { - this.children.forEach(function (layer) { - layer.batchDraw(); - }); - return this; - } } Stage.prototype.nodeType = STAGE; _registerNode(Stage); @@ -7035,8 +6554,8 @@ * body.appendChild(container); * stage.container(container); */ - Factory.addGetterSetter(Stage, 'container'); - + Factory.addGetterSetter(Stage, 'container'); + var HAS_SHADOW = 'hasShadow'; var SHADOW_RGBA = 'shadowRGBA'; var patternImage = 'patternImage'; @@ -7044,11 +6563,11 @@ var radialGradient = 'radialGradient'; let dummyContext$1; function getDummyContext$1() { - if (dummyContext$1) { + if (dummyContext$1) { + return dummyContext$1; + } + dummyContext$1 = Util.createCanvasElement().getContext('2d'); return dummyContext$1; - } - dummyContext$1 = Util.createCanvasElement().getContext('2d'); - return dummyContext$1; } const shapes = {}; // TODO: idea - use only "remove" (or destroy method) @@ -7057,31 +6576,31 @@ // the approach is good. But what if we want to cache the shape before we add it into the stage // what color to use for hit test? function _fillFunc$2(context) { - context.fill(); + context.fill(); } function _strokeFunc$2(context) { - context.stroke(); + context.stroke(); } function _fillFuncHit(context) { - context.fill(); + context.fill(); } function _strokeFuncHit(context) { - context.stroke(); + context.stroke(); } function _clearHasShadowCache() { - this._clearCache(HAS_SHADOW); + this._clearCache(HAS_SHADOW); } function _clearGetShadowRGBACache() { - this._clearCache(SHADOW_RGBA); + this._clearCache(SHADOW_RGBA); } function _clearFillPatternCache() { - this._clearCache(patternImage); + this._clearCache(patternImage); } function _clearLinearGradientCache() { - this._clearCache(linearGradient); + this._clearCache(linearGradient); } function _clearRadialGradientCache() { - this._clearCache(radialGradient); + this._clearCache(radialGradient); } /** * Shape constructor. Shapes are primitive objects such as rectangles, @@ -7110,533 +6629,463 @@ *}); */ class Shape extends Node { - constructor(config) { - super(config); - // set colorKey - let key; - while (true) { - key = Util.getRandomColor(); - if (key && !(key in shapes)) { - break; - } - } - this.colorKey = key; - shapes[key] = this; - } - /** - * get canvas context tied to the layer - * @method - * @name Konva.Shape#getContext - * @returns {Konva.Context} - */ - getContext() { - return this.getLayer().getContext(); - } - /** - * get canvas renderer tied to the layer. Note that this returns a canvas renderer, not a canvas element - * @method - * @name Konva.Shape#getCanvas - * @returns {Konva.Canvas} - */ - getCanvas() { - return this.getLayer().getCanvas(); - } - getSceneFunc() { - return this.attrs.sceneFunc || this['_sceneFunc']; - } - getHitFunc() { - return this.attrs.hitFunc || this['_hitFunc']; - } - /** - * returns whether or not a shadow will be rendered - * @method - * @name Konva.Shape#hasShadow - * @returns {Boolean} - */ - hasShadow() { - return this._getCache(HAS_SHADOW, this._hasShadow); - } - _hasShadow() { - return ( - this.shadowEnabled() && - this.shadowOpacity() !== 0 && - !!( - this.shadowColor() || - this.shadowBlur() || - this.shadowOffsetX() || - this.shadowOffsetY() - ) - ); - } - _getFillPattern() { - return this._getCache(patternImage, this.__getFillPattern); - } - __getFillPattern() { - if (this.fillPatternImage()) { - var ctx = getDummyContext$1(); - const pattern = ctx.createPattern( - this.fillPatternImage(), - this.fillPatternRepeat() || 'repeat' - ); - if (pattern && pattern.setTransform) { - pattern.setTransform({ - a: this.fillPatternScaleX(), - b: 0, - c: 0, - d: this.fillPatternScaleY(), - e: 0, - f: 0, // Vertical translation (moving). - }); - } - return pattern; - } - } - _getLinearGradient() { - return this._getCache(linearGradient, this.__getLinearGradient); - } - __getLinearGradient() { - var colorStops = this.fillLinearGradientColorStops(); - if (colorStops) { - var ctx = getDummyContext$1(); - var start = this.fillLinearGradientStartPoint(); - var end = this.fillLinearGradientEndPoint(); - var grd = ctx.createLinearGradient(start.x, start.y, end.x, end.y); - // build color stops - for (var n = 0; n < colorStops.length; n += 2) { - grd.addColorStop(colorStops[n], colorStops[n + 1]); - } - return grd; - } - } - _getRadialGradient() { - return this._getCache(radialGradient, this.__getRadialGradient); - } - __getRadialGradient() { - var colorStops = this.fillRadialGradientColorStops(); - if (colorStops) { - var ctx = getDummyContext$1(); - var start = this.fillRadialGradientStartPoint(); - var end = this.fillRadialGradientEndPoint(); - var grd = ctx.createRadialGradient( - start.x, - start.y, - this.fillRadialGradientStartRadius(), - end.x, - end.y, - this.fillRadialGradientEndRadius() - ); - // build color stops - for (var n = 0; n < colorStops.length; n += 2) { - grd.addColorStop(colorStops[n], colorStops[n + 1]); - } - return grd; - } - } - getShadowRGBA() { - return this._getCache(SHADOW_RGBA, this._getShadowRGBA); - } - _getShadowRGBA() { - if (this.hasShadow()) { - var rgba = Util.colorToRGBA(this.shadowColor()); - return ( - 'rgba(' + - rgba.r + - ',' + - rgba.g + - ',' + - rgba.b + - ',' + - rgba.a * (this.shadowOpacity() || 1) + - ')' - ); - } - } - /** - * returns whether or not the shape will be filled - * @method - * @name Konva.Shape#hasFill - * @returns {Boolean} - */ - hasFill() { - return this._calculate( - 'hasFill', - [ - 'fillEnabled', - 'fill', - 'fillPatternImage', - 'fillLinearGradientColorStops', - 'fillRadialGradientColorStops', - ], - () => { - return ( - this.fillEnabled() && - !!( - this.fill() || - this.fillPatternImage() || - this.fillLinearGradientColorStops() || - this.fillRadialGradientColorStops() - ) - ); - } - ); - } - /** - * returns whether or not the shape will be stroked - * @method - * @name Konva.Shape#hasStroke - * @returns {Boolean} - */ - hasStroke() { - return this._calculate( - 'hasStroke', - [ - 'strokeEnabled', - 'strokeWidth', - 'stroke', - 'strokeLinearGradientColorStops', - ], - () => { - return ( - this.strokeEnabled() && - this.strokeWidth() && - !!(this.stroke() || this.strokeLinearGradientColorStops()) - // this.getStrokeRadialGradientColorStops() - ); - } - ); - // return ( - // this.strokeEnabled() && - // this.strokeWidth() && - // !!(this.stroke() || this.strokeLinearGradientColorStops()) - // // this.getStrokeRadialGradientColorStops() - // ); - } - hasHitStroke() { - const width = this.hitStrokeWidth(); - // on auto just check by stroke - if (width === 'auto') { - return this.hasStroke(); - } - // we should enable hit stroke if stroke is enabled - // and we have some value from width - return this.strokeEnabled() && !!width; - } - /** - * determines if point is in the shape, regardless if other shapes are on top of it. Note: because - * this method clears a temporary canvas and then redraws the shape, it performs very poorly if executed many times - * consecutively. Please use the {@link Konva.Stage#getIntersection} method if at all possible - * because it performs much better - * @method - * @name Konva.Shape#intersects - * @param {Object} point - * @param {Number} point.x - * @param {Number} point.y - * @returns {Boolean} - */ - intersects(point) { - var stage = this.getStage(), - bufferHitCanvas = stage.bufferHitCanvas, - p; - bufferHitCanvas.getContext().clear(); - this.drawHit(bufferHitCanvas, null, true); - p = bufferHitCanvas.context.getImageData( - Math.round(point.x), - Math.round(point.y), - 1, - 1 - ).data; - return p[3] > 0; - } - destroy() { - Node.prototype.destroy.call(this); - delete shapes[this.colorKey]; - delete this.colorKey; - return this; - } - // why do we need buffer canvas? - // it give better result when a shape has - // stroke with fill and with some opacity - _useBufferCanvas(forceFill) { - // image and sprite still has "fill" as image - // so they use that method with forced fill - // it probably will be simpler, then copy/paste the code - var _a; - // buffer canvas is available only inside the stage - if (!this.getStage()) { - return false; - } - // force skip buffer canvas - const perfectDrawEnabled = - (_a = this.attrs.perfectDrawEnabled) !== null && _a !== void 0 - ? _a - : true; - if (!perfectDrawEnabled) { - return false; - } - const hasFill = forceFill || this.hasFill(); - const hasStroke = this.hasStroke(); - const isTransparent = this.getAbsoluteOpacity() !== 1; - if (hasFill && hasStroke && isTransparent) { - return true; - } - const hasShadow = this.hasShadow(); - const strokeForShadow = this.shadowForStrokeEnabled(); - if (hasFill && hasStroke && hasShadow && strokeForShadow) { - return true; - } - return false; - } - setStrokeHitEnabled(val) { - Util.warn( - 'strokeHitEnabled property is deprecated. Please use hitStrokeWidth instead.' - ); - if (val) { - this.hitStrokeWidth('auto'); - } else { - this.hitStrokeWidth(0); - } - } - getStrokeHitEnabled() { - if (this.hitStrokeWidth() === 0) { - return false; - } else { - return true; - } - } - /** - * return self rectangle (x, y, width, height) of shape. - * This method are not taken into account transformation and styles. - * @method - * @name Konva.Shape#getSelfRect - * @returns {Object} rect with {x, y, width, height} properties - * @example - * - * rect.getSelfRect(); // return {x:0, y:0, width:rect.width(), height:rect.height()} - * circle.getSelfRect(); // return {x: - circle.width() / 2, y: - circle.height() / 2, width:circle.width(), height:circle.height()} - * - */ - getSelfRect() { - var size = this.size(); - return { - x: this._centroid ? -size.width / 2 : 0, - y: this._centroid ? -size.height / 2 : 0, - width: size.width, - height: size.height, - }; - } - getClientRect(config = {}) { - const skipTransform = config.skipTransform; - const relativeTo = config.relativeTo; - const fillRect = this.getSelfRect(); - const applyStroke = !config.skipStroke && this.hasStroke(); - const strokeWidth = (applyStroke && this.strokeWidth()) || 0; - const fillAndStrokeWidth = fillRect.width + strokeWidth; - const fillAndStrokeHeight = fillRect.height + strokeWidth; - const applyShadow = !config.skipShadow && this.hasShadow(); - const shadowOffsetX = applyShadow ? this.shadowOffsetX() : 0; - const shadowOffsetY = applyShadow ? this.shadowOffsetY() : 0; - const preWidth = fillAndStrokeWidth + Math.abs(shadowOffsetX); - const preHeight = fillAndStrokeHeight + Math.abs(shadowOffsetY); - const blurRadius = (applyShadow && this.shadowBlur()) || 0; - const width = preWidth + blurRadius * 2; - const height = preHeight + blurRadius * 2; - // if stroke, for example = 3 - // we need to set x to 1.5, but after Math.round it will be 2 - // as we have additional offset we need to increase width and height by 1 pixel - let roundingOffset = 0; - if (Math.round(strokeWidth / 2) !== strokeWidth / 2) { - roundingOffset = 1; - } - const rect = { - width: width + roundingOffset, - height: height + roundingOffset, - x: - -Math.round(strokeWidth / 2 + blurRadius) + - Math.min(shadowOffsetX, 0) + - fillRect.x, - y: - -Math.round(strokeWidth / 2 + blurRadius) + - Math.min(shadowOffsetY, 0) + - fillRect.y, - }; - if (!skipTransform) { - return this._transformedRect(rect, relativeTo); - } - return rect; - } - drawScene(can, top) { - // basically there are 3 drawing modes - // 1 - simple drawing when nothing is cached. - // 2 - when we are caching current - // 3 - when node is cached and we need to draw it into layer - var layer = this.getLayer(), - canvas = can || layer.getCanvas(), - context = canvas.getContext(), - cachedCanvas = this._getCanvasCache(), - drawFunc = this.getSceneFunc(), - hasShadow = this.hasShadow(), - stage, - bufferCanvas, - bufferContext; - var caching = canvas.isCache; - var skipBuffer = canvas.isCache; - var cachingSelf = top === this; - if (!this.isVisible() && !caching) { - return this; - } - // if node is cached we just need to draw from cache - if (cachedCanvas) { - context.save(); - var m = this.getAbsoluteTransform(top).getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - this._drawCachedSceneCanvas(context); - context.restore(); - return this; - } - if (!drawFunc) { - return this; - } - context.save(); - // if buffer canvas is needed - if (this._useBufferCanvas() && !skipBuffer) { - stage = this.getStage(); - bufferCanvas = stage.bufferCanvas; - bufferContext = bufferCanvas.getContext(); - bufferContext.clear(); - bufferContext.save(); - bufferContext._applyLineJoin(this); - // layer might be undefined if we are using cache before adding to layer - var o = this.getAbsoluteTransform(top).getMatrix(); - bufferContext.transform(o[0], o[1], o[2], o[3], o[4], o[5]); - drawFunc.call(this, bufferContext, this); - bufferContext.restore(); - var ratio = bufferCanvas.pixelRatio; - if (hasShadow) { - context._applyShadow(this); - } - context._applyOpacity(this); - context._applyGlobalCompositeOperation(this); - context.drawImage( - bufferCanvas._canvas, - 0, - 0, - bufferCanvas.width / ratio, - bufferCanvas.height / ratio - ); - } else { - context._applyLineJoin(this); - if (!cachingSelf) { - var o = this.getAbsoluteTransform(top).getMatrix(); - context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); - context._applyOpacity(this); - context._applyGlobalCompositeOperation(this); - } - if (hasShadow) { - context._applyShadow(this); - } - drawFunc.call(this, context, this); - } - context.restore(); - return this; - } - drawHit(can, top, skipDragCheck = false) { - if (!this.shouldDrawHit(top, skipDragCheck)) { - return this; - } - var layer = this.getLayer(), - canvas = can || layer.hitCanvas, - context = canvas && canvas.getContext(), - drawFunc = this.hitFunc() || this.sceneFunc(), - cachedCanvas = this._getCanvasCache(), - cachedHitCanvas = cachedCanvas && cachedCanvas.hit; - if (!this.colorKey) { - Util.warn( - 'Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. If you want to reuse shape you should call remove() instead of destroy()' - ); - } - if (cachedHitCanvas) { - context.save(); - var m = this.getAbsoluteTransform(top).getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - this._drawCachedHitCanvas(context); - context.restore(); - return this; - } - if (!drawFunc) { - return this; - } - context.save(); - context._applyLineJoin(this); - const selfCache = this === top; - if (!selfCache) { - var o = this.getAbsoluteTransform(top).getMatrix(); - context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); - } - drawFunc.call(this, context, this); - context.restore(); - return this; - } - /** - * draw hit graph using the cached scene canvas - * @method - * @name Konva.Shape#drawHitFromCache - * @param {Integer} alphaThreshold alpha channel threshold that determines whether or not - * a pixel should be drawn onto the hit graph. Must be a value between 0 and 255. - * The default is 0 - * @returns {Konva.Shape} - * @example - * shape.cache(); - * shape.drawHitFromCache(); - */ - drawHitFromCache(alphaThreshold = 0) { - var cachedCanvas = this._getCanvasCache(), - sceneCanvas = this._getCachedSceneCanvas(), - hitCanvas = cachedCanvas.hit, - hitContext = hitCanvas.getContext(), - hitWidth = hitCanvas.getWidth(), - hitHeight = hitCanvas.getHeight(), - hitImageData, - hitData, - len, - rgbColorKey, - i, - alpha; - hitContext.clear(); - hitContext.drawImage(sceneCanvas._canvas, 0, 0, hitWidth, hitHeight); - try { - hitImageData = hitContext.getImageData(0, 0, hitWidth, hitHeight); - hitData = hitImageData.data; - len = hitData.length; - rgbColorKey = Util._hexToRgb(this.colorKey); - // replace non transparent pixels with color key - for (i = 0; i < len; i += 4) { - alpha = hitData[i + 3]; - if (alpha > alphaThreshold) { - hitData[i] = rgbColorKey.r; - hitData[i + 1] = rgbColorKey.g; - hitData[i + 2] = rgbColorKey.b; - hitData[i + 3] = 255; - } else { - hitData[i + 3] = 0; + constructor(config) { + super(config); + // set colorKey + let key; + while (true) { + key = Util.getRandomColor(); + if (key && !(key in shapes)) { + break; + } } - } - hitContext.putImageData(hitImageData, 0, 0); - } catch (e) { - Util.error( - 'Unable to draw hit graph from cached scene canvas. ' + e.message - ); + this.colorKey = key; + shapes[key] = this; + } + /** + * get canvas context tied to the layer + * @method + * @name Konva.Shape#getContext + * @returns {Konva.Context} + */ + // TODO: remove method + getContext() { + return this.getLayer().getContext(); + } + /** + * get canvas renderer tied to the layer. Note that this returns a canvas renderer, not a canvas element + * @method + * @name Konva.Shape#getCanvas + * @returns {Konva.Canvas} + */ + // TODO: remove method + getCanvas() { + return this.getLayer().getCanvas(); + } + getSceneFunc() { + return this.attrs.sceneFunc || this['_sceneFunc']; + } + getHitFunc() { + return this.attrs.hitFunc || this['_hitFunc']; + } + /** + * returns whether or not a shadow will be rendered + * @method + * @name Konva.Shape#hasShadow + * @returns {Boolean} + */ + hasShadow() { + return this._getCache(HAS_SHADOW, this._hasShadow); + } + _hasShadow() { + return (this.shadowEnabled() && + this.shadowOpacity() !== 0 && + !!(this.shadowColor() || + this.shadowBlur() || + this.shadowOffsetX() || + this.shadowOffsetY())); + } + _getFillPattern() { + return this._getCache(patternImage, this.__getFillPattern); + } + __getFillPattern() { + if (this.fillPatternImage()) { + var ctx = getDummyContext$1(); + const pattern = ctx.createPattern(this.fillPatternImage(), this.fillPatternRepeat() || 'repeat'); + if (pattern && pattern.setTransform) { + pattern.setTransform({ + a: this.fillPatternScaleX(), + b: 0, + c: 0, + d: this.fillPatternScaleY(), + e: 0, + f: 0, // Vertical translation (moving). + }); + } + return pattern; + } + } + _getLinearGradient() { + return this._getCache(linearGradient, this.__getLinearGradient); + } + __getLinearGradient() { + var colorStops = this.fillLinearGradientColorStops(); + if (colorStops) { + var ctx = getDummyContext$1(); + var start = this.fillLinearGradientStartPoint(); + var end = this.fillLinearGradientEndPoint(); + var grd = ctx.createLinearGradient(start.x, start.y, end.x, end.y); + // build color stops + for (var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + return grd; + } + } + _getRadialGradient() { + return this._getCache(radialGradient, this.__getRadialGradient); + } + __getRadialGradient() { + var colorStops = this.fillRadialGradientColorStops(); + if (colorStops) { + var ctx = getDummyContext$1(); + var start = this.fillRadialGradientStartPoint(); + var end = this.fillRadialGradientEndPoint(); + var grd = ctx.createRadialGradient(start.x, start.y, this.fillRadialGradientStartRadius(), end.x, end.y, this.fillRadialGradientEndRadius()); + // build color stops + for (var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + return grd; + } + } + getShadowRGBA() { + return this._getCache(SHADOW_RGBA, this._getShadowRGBA); + } + _getShadowRGBA() { + if (this.hasShadow()) { + var rgba = Util.colorToRGBA(this.shadowColor()); + return ('rgba(' + + rgba.r + + ',' + + rgba.g + + ',' + + rgba.b + + ',' + + rgba.a * (this.shadowOpacity() || 1) + + ')'); + } + } + /** + * returns whether or not the shape will be filled + * @method + * @name Konva.Shape#hasFill + * @returns {Boolean} + */ + hasFill() { + return this._calculate('hasFill', [ + 'fillEnabled', + 'fill', + 'fillPatternImage', + 'fillLinearGradientColorStops', + 'fillRadialGradientColorStops', + ], () => { + return (this.fillEnabled() && + !!(this.fill() || + this.fillPatternImage() || + this.fillLinearGradientColorStops() || + this.fillRadialGradientColorStops())); + }); + } + /** + * returns whether or not the shape will be stroked + * @method + * @name Konva.Shape#hasStroke + * @returns {Boolean} + */ + hasStroke() { + return this._calculate('hasStroke', [ + 'strokeEnabled', + 'strokeWidth', + 'stroke', + 'strokeLinearGradientColorStops', + ], () => { + return (this.strokeEnabled() && + this.strokeWidth() && + !!(this.stroke() || this.strokeLinearGradientColorStops()) + // this.getStrokeRadialGradientColorStops() + ); + }); + // return ( + // this.strokeEnabled() && + // this.strokeWidth() && + // !!(this.stroke() || this.strokeLinearGradientColorStops()) + // // this.getStrokeRadialGradientColorStops() + // ); + } + hasHitStroke() { + const width = this.hitStrokeWidth(); + // on auto just check by stroke + if (width === 'auto') { + return this.hasStroke(); + } + // we should enable hit stroke if stroke is enabled + // and we have some value from width + return this.strokeEnabled() && !!width; + } + /** + * determines if point is in the shape, regardless if other shapes are on top of it. Note: because + * this method clears a temporary canvas and then redraws the shape, it performs very poorly if executed many times + * consecutively. Please use the {@link Konva.Stage#getIntersection} method if at all possible + * because it performs much better + * @method + * @name Konva.Shape#intersects + * @param {Object} point + * @param {Number} point.x + * @param {Number} point.y + * @returns {Boolean} + */ + intersects(point) { + var stage = this.getStage(), bufferHitCanvas = stage.bufferHitCanvas, p; + bufferHitCanvas.getContext().clear(); + this.drawHit(bufferHitCanvas, null, true); + p = bufferHitCanvas.context.getImageData(Math.round(point.x), Math.round(point.y), 1, 1).data; + return p[3] > 0; + } + destroy() { + Node.prototype.destroy.call(this); + delete shapes[this.colorKey]; + delete this.colorKey; + return this; + } + // why do we need buffer canvas? + // it give better result when a shape has + // stroke with fill and with some opacity + _useBufferCanvas(forceFill) { + // image and sprite still has "fill" as image + // so they use that method with forced fill + // it probably will be simpler, then copy/paste the code + var _a; + // buffer canvas is available only inside the stage + if (!this.getStage()) { + return false; + } + // force skip buffer canvas + const perfectDrawEnabled = (_a = this.attrs.perfectDrawEnabled) !== null && _a !== void 0 ? _a : true; + if (!perfectDrawEnabled) { + return false; + } + const hasFill = forceFill || this.hasFill(); + const hasStroke = this.hasStroke(); + const isTransparent = this.getAbsoluteOpacity() !== 1; + if (hasFill && hasStroke && isTransparent) { + return true; + } + const hasShadow = this.hasShadow(); + const strokeForShadow = this.shadowForStrokeEnabled(); + if (hasFill && hasStroke && hasShadow && strokeForShadow) { + return true; + } + return false; + } + setStrokeHitEnabled(val) { + Util.warn('strokeHitEnabled property is deprecated. Please use hitStrokeWidth instead.'); + if (val) { + this.hitStrokeWidth('auto'); + } + else { + this.hitStrokeWidth(0); + } + } + getStrokeHitEnabled() { + if (this.hitStrokeWidth() === 0) { + return false; + } + else { + return true; + } + } + /** + * return self rectangle (x, y, width, height) of shape. + * This method are not taken into account transformation and styles. + * @method + * @name Konva.Shape#getSelfRect + * @returns {Object} rect with {x, y, width, height} properties + * @example + * + * rect.getSelfRect(); // return {x:0, y:0, width:rect.width(), height:rect.height()} + * circle.getSelfRect(); // return {x: - circle.width() / 2, y: - circle.height() / 2, width:circle.width(), height:circle.height()} + * + */ + getSelfRect() { + var size = this.size(); + return { + x: this._centroid ? -size.width / 2 : 0, + y: this._centroid ? -size.height / 2 : 0, + width: size.width, + height: size.height, + }; + } + getClientRect(config = {}) { + const skipTransform = config.skipTransform; + const relativeTo = config.relativeTo; + const fillRect = this.getSelfRect(); + const applyStroke = !config.skipStroke && this.hasStroke(); + const strokeWidth = (applyStroke && this.strokeWidth()) || 0; + const fillAndStrokeWidth = fillRect.width + strokeWidth; + const fillAndStrokeHeight = fillRect.height + strokeWidth; + const applyShadow = !config.skipShadow && this.hasShadow(); + const shadowOffsetX = applyShadow ? this.shadowOffsetX() : 0; + const shadowOffsetY = applyShadow ? this.shadowOffsetY() : 0; + const preWidth = fillAndStrokeWidth + Math.abs(shadowOffsetX); + const preHeight = fillAndStrokeHeight + Math.abs(shadowOffsetY); + const blurRadius = (applyShadow && this.shadowBlur()) || 0; + const width = preWidth + blurRadius * 2; + const height = preHeight + blurRadius * 2; + // if stroke, for example = 3 + // we need to set x to 1.5, but after Math.round it will be 2 + // as we have additional offset we need to increase width and height by 1 pixel + let roundingOffset = 0; + if (Math.round(strokeWidth / 2) !== strokeWidth / 2) { + roundingOffset = 1; + } + const rect = { + width: width + roundingOffset, + height: height + roundingOffset, + x: -Math.round(strokeWidth / 2 + blurRadius) + + Math.min(shadowOffsetX, 0) + + fillRect.x, + y: -Math.round(strokeWidth / 2 + blurRadius) + + Math.min(shadowOffsetY, 0) + + fillRect.y, + }; + if (!skipTransform) { + return this._transformedRect(rect, relativeTo); + } + return rect; + } + drawScene(can, top) { + // basically there are 3 drawing modes + // 1 - simple drawing when nothing is cached. + // 2 - when we are caching current + // 3 - when node is cached and we need to draw it into layer + var layer = this.getLayer(), canvas = can || layer.getCanvas(), context = canvas.getContext(), cachedCanvas = this._getCanvasCache(), drawFunc = this.getSceneFunc(), hasShadow = this.hasShadow(), stage, bufferCanvas, bufferContext; + var caching = canvas.isCache; + var skipBuffer = canvas.isCache; + var cachingSelf = top === this; + if (!this.isVisible() && !caching) { + return this; + } + // if node is cached we just need to draw from cache + if (cachedCanvas) { + context.save(); + var m = this.getAbsoluteTransform(top).getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + this._drawCachedSceneCanvas(context); + context.restore(); + return this; + } + if (!drawFunc) { + return this; + } + context.save(); + // if buffer canvas is needed + if (this._useBufferCanvas() && !skipBuffer) { + stage = this.getStage(); + bufferCanvas = stage.bufferCanvas; + bufferContext = bufferCanvas.getContext(); + bufferContext.clear(); + bufferContext.save(); + bufferContext._applyLineJoin(this); + // layer might be undefined if we are using cache before adding to layer + var o = this.getAbsoluteTransform(top).getMatrix(); + bufferContext.transform(o[0], o[1], o[2], o[3], o[4], o[5]); + drawFunc.call(this, bufferContext, this); + bufferContext.restore(); + var ratio = bufferCanvas.pixelRatio; + if (hasShadow) { + context._applyShadow(this); + } + context._applyOpacity(this); + context._applyGlobalCompositeOperation(this); + context.drawImage(bufferCanvas._canvas, 0, 0, bufferCanvas.width / ratio, bufferCanvas.height / ratio); + } + else { + context._applyLineJoin(this); + if (!cachingSelf) { + var o = this.getAbsoluteTransform(top).getMatrix(); + context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); + context._applyOpacity(this); + context._applyGlobalCompositeOperation(this); + } + if (hasShadow) { + context._applyShadow(this); + } + drawFunc.call(this, context, this); + } + context.restore(); + return this; + } + drawHit(can, top, skipDragCheck = false) { + if (!this.shouldDrawHit(top, skipDragCheck)) { + return this; + } + var layer = this.getLayer(), canvas = can || layer.hitCanvas, context = canvas && canvas.getContext(), drawFunc = this.hitFunc() || this.sceneFunc(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit; + if (!this.colorKey) { + Util.warn('Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. If you want to reuse shape you should call remove() instead of destroy()'); + } + if (cachedHitCanvas) { + context.save(); + var m = this.getAbsoluteTransform(top).getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + this._drawCachedHitCanvas(context); + context.restore(); + return this; + } + if (!drawFunc) { + return this; + } + context.save(); + context._applyLineJoin(this); + const selfCache = this === top; + if (!selfCache) { + var o = this.getAbsoluteTransform(top).getMatrix(); + context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); + } + drawFunc.call(this, context, this); + context.restore(); + return this; + } + /** + * draw hit graph using the cached scene canvas + * @method + * @name Konva.Shape#drawHitFromCache + * @param {Integer} alphaThreshold alpha channel threshold that determines whether or not + * a pixel should be drawn onto the hit graph. Must be a value between 0 and 255. + * The default is 0 + * @returns {Konva.Shape} + * @example + * shape.cache(); + * shape.drawHitFromCache(); + */ + drawHitFromCache(alphaThreshold = 0) { + var cachedCanvas = this._getCanvasCache(), sceneCanvas = this._getCachedSceneCanvas(), hitCanvas = cachedCanvas.hit, hitContext = hitCanvas.getContext(), hitWidth = hitCanvas.getWidth(), hitHeight = hitCanvas.getHeight(), hitImageData, hitData, len, rgbColorKey, i, alpha; + hitContext.clear(); + hitContext.drawImage(sceneCanvas._canvas, 0, 0, hitWidth, hitHeight); + try { + hitImageData = hitContext.getImageData(0, 0, hitWidth, hitHeight); + hitData = hitImageData.data; + len = hitData.length; + rgbColorKey = Util._hexToRgb(this.colorKey); + // replace non transparent pixels with color key + for (i = 0; i < len; i += 4) { + alpha = hitData[i + 3]; + if (alpha > alphaThreshold) { + hitData[i] = rgbColorKey.r; + hitData[i + 1] = rgbColorKey.g; + hitData[i + 2] = rgbColorKey.b; + hitData[i + 3] = 255; + } + else { + hitData[i + 3] = 0; + } + } + hitContext.putImageData(hitImageData, 0, 0); + } + catch (e) { + Util.error('Unable to draw hit graph from cached scene canvas. ' + e.message); + } + return this; + } + hasPointerCapture(pointerId) { + return hasPointerCapture(pointerId, this); + } + setPointerCapture(pointerId) { + setPointerCapture(pointerId, this); + } + releaseCapture(pointerId) { + releaseCapture(pointerId); } - return this; - } - hasPointerCapture(pointerId) { - return hasPointerCapture(pointerId, this); - } - setPointerCapture(pointerId) { - setPointerCapture(pointerId, this); - } - releaseCapture(pointerId) { - releaseCapture(pointerId); - } } Shape.prototype._fillFunc = _fillFunc$2; Shape.prototype._strokeFunc = _strokeFunc$2; @@ -7646,38 +7095,13 @@ Shape.prototype.nodeType = 'Shape'; _registerNode(Shape); Shape.prototype.eventListeners = {}; - Shape.prototype.on.call( - Shape.prototype, - 'shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', - _clearHasShadowCache - ); - Shape.prototype.on.call( - Shape.prototype, - 'shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', - _clearGetShadowRGBACache - ); - Shape.prototype.on.call( - Shape.prototype, - 'fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva fillPatternScaleXChange.konva fillPatternScaleYChange.konva', - _clearFillPatternCache - ); - Shape.prototype.on.call( - Shape.prototype, - 'fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva', - _clearLinearGradientCache - ); - Shape.prototype.on.call( - Shape.prototype, - 'fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva', - _clearRadialGradientCache - ); + Shape.prototype.on.call(Shape.prototype, 'shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearHasShadowCache); + Shape.prototype.on.call(Shape.prototype, 'shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearGetShadowRGBACache); + Shape.prototype.on.call(Shape.prototype, 'fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva fillPatternScaleXChange.konva fillPatternScaleYChange.konva', _clearFillPatternCache); + Shape.prototype.on.call(Shape.prototype, 'fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva', _clearLinearGradientCache); + Shape.prototype.on.call(Shape.prototype, 'fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva', _clearRadialGradientCache); // add getters and setters - Factory.addGetterSetter( - Shape, - 'stroke', - undefined, - getStringOrGradientValidator() - ); + Factory.addGetterSetter(Shape, 'stroke', undefined, getStringOrGradientValidator()); /** * get/set stroke color * @name Konva.Shape#stroke @@ -7731,12 +7155,7 @@ * // set stroke width * shape.fillAfterStrokeEnabled(true); */ - Factory.addGetterSetter( - Shape, - 'hitStrokeWidth', - 'auto', - getNumberOrAutoValidator() - ); + Factory.addGetterSetter(Shape, 'hitStrokeWidth', 'auto', getNumberOrAutoValidator()); /** * get/set stroke width for hit detection. Default value is "auto", it means it will be equals to strokeWidth * @name Konva.Shape#hitStrokeWidth @@ -7752,12 +7171,7 @@ * // set hit stroke width always equals to scene stroke width * shape.hitStrokeWidth('auto'); */ - Factory.addGetterSetter( - Shape, - 'strokeHitEnabled', - true, - getBooleanValidator() - ); + Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator()); /** * **deprecated, use hitStrokeWidth instead!** get/set strokeHitEnabled property. Useful for performance optimization. * You may set `shape.strokeHitEnabled(false)`. In this case stroke will be no draw on hit canvas, so hit area @@ -7775,12 +7189,7 @@ * // set strokeHitEnabled * shape.strokeHitEnabled(); */ - Factory.addGetterSetter( - Shape, - 'perfectDrawEnabled', - true, - getBooleanValidator() - ); + Factory.addGetterSetter(Shape, 'perfectDrawEnabled', true, getBooleanValidator()); /** * get/set perfectDrawEnabled. If a shape has fill, stroke and opacity you may set `perfectDrawEnabled` to false to improve performance. * See http://konvajs.org/docs/performance/Disable_Perfect_Draw.html for more information. @@ -7796,12 +7205,7 @@ * // set perfectDrawEnabled * shape.perfectDrawEnabled(); */ - Factory.addGetterSetter( - Shape, - 'shadowForStrokeEnabled', - true, - getBooleanValidator() - ); + Factory.addGetterSetter(Shape, 'shadowForStrokeEnabled', true, getBooleanValidator()); /** * get/set shadowForStrokeEnabled. Useful for performance optimization. * You may set `shape.shadowForStrokeEnabled(false)`. In this case stroke will no effect shadow. @@ -7916,12 +7320,7 @@ * line.dash([10, 5]); * line.dashOffset(5); */ - Factory.addGetterSetter( - Shape, - 'shadowColor', - undefined, - getStringValidator() - ); + Factory.addGetterSetter(Shape, 'shadowColor', undefined, getStringValidator()); /** * get/set shadow color * @name Konva.Shape#shadowColor @@ -8037,12 +7436,7 @@ * }; * imageObj.src = 'path/to/image/jpg'; */ - Factory.addGetterSetter( - Shape, - 'fill', - undefined, - getStringOrGradientValidator() - ); + Factory.addGetterSetter(Shape, 'fill', undefined, getStringOrGradientValidator()); /** * get/set fill color * @name Konva.Shape#fill @@ -8379,8 +7773,8 @@ * shape.fillPatternScaleY(2); */ Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientStartPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set fill linear gradient start point @@ -8401,8 +7795,8 @@ * }); */ Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientStartPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set stroke linear gradient start point @@ -8479,8 +7873,8 @@ * shape.strokeLinearGradientStartPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientEndPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set fill linear gradient end point @@ -8501,8 +7895,8 @@ * }); */ Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientEndPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set stroke linear gradient end point @@ -8579,8 +7973,8 @@ * shape.strokeLinearGradientEndPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientStartPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set fill radial gradient start point @@ -8629,8 +8023,8 @@ * shape.fillRadialGradientStartPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientEndPoint', [ - 'x', - 'y', + 'x', + 'y', ]); /** * get/set fill radial gradient end point @@ -8693,36 +8087,33 @@ * shape.fillPatternRotation(20); */ Factory.backCompat(Shape, { - dashArray: 'dash', - getDashArray: 'getDash', - setDashArray: 'getDash', - drawFunc: 'sceneFunc', - getDrawFunc: 'getSceneFunc', - setDrawFunc: 'setSceneFunc', - drawHitFunc: 'hitFunc', - getDrawHitFunc: 'getHitFunc', - setDrawHitFunc: 'setHitFunc', - }); - + dashArray: 'dash', + getDashArray: 'getDash', + setDashArray: 'getDash', + drawFunc: 'sceneFunc', + getDrawFunc: 'getSceneFunc', + setDrawFunc: 'setSceneFunc', + drawHitFunc: 'hitFunc', + getDrawHitFunc: 'getHitFunc', + setDrawHitFunc: 'setHitFunc', + }); + // constants - var HASH = '#', - BEFORE_DRAW = 'beforeDraw', - DRAW = 'draw', - /* - * 2 - 3 - 4 - * | | - * 1 - 0 5 - * | - * 8 - 7 - 6 - */ - INTERSECTION_OFFSETS = [ + var HASH = '#', 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; + ], INTERSECTION_OFFSETS_LEN = INTERSECTION_OFFSETS.length; /** * Layer constructor. Layers are tied to their own canvas element and are used * to contain groups or shapes. @@ -8740,417 +8131,397 @@ * // now you can add shapes, groups into the layer */ class Layer extends Container { - constructor(config) { - super(config); - this.canvas = new SceneCanvas(); - this.hitCanvas = new HitCanvas({ - pixelRatio: 1, - }); - this._waitingForDraw = false; - this.on('visibleChange.konva', this._checkVisibility); - this._checkVisibility(); - this.on('imageSmoothingEnabledChange.konva', this._setSmoothEnabled); - this._setSmoothEnabled(); - } - // for nodejs? - createPNGStream() { - const c = this.canvas._canvas; - return c.createPNGStream(); - } - /** - * get layer canvas wrapper - * @method - * @name Konva.Layer#getCanvas - */ - getCanvas() { - return this.canvas; - } - /** - * get native canvas element - * @method - * @name Konva.Layer#getCanvas - */ - getNativeCanvasElement() { - return this.canvas._canvas; - } - /** - * get layer hit canvas - * @method - * @name Konva.Layer#getHitCanvas - */ - getHitCanvas() { - return this.hitCanvas; - } - /** - * get layer canvas context - * @method - * @name Konva.Layer#getContext - */ - getContext() { - return this.getCanvas().getContext(); - } - /** - * clear scene and hit canvas contexts tied to the layer. - * This function doesn't remove any nodes. It just clear canvas element. - * @method - * @name Konva.Layer#clear - * @param {Object} [bounds] - * @param {Number} [bounds.x] - * @param {Number} [bounds.y] - * @param {Number} [bounds.width] - * @param {Number} [bounds.height] - * @example - * layer.clear(); - * layer.clear({ - * x : 0, - * y : 0, - * width : 100, - * height : 100 - * }); - */ - clear(bounds) { - this.getContext().clear(bounds); - this.getHitCanvas().getContext().clear(bounds); - return this; - } - // extend Node.prototype.setZIndex - setZIndex(index) { - super.setZIndex(index); - var stage = this.getStage(); - if (stage && stage.content) { - stage.content.removeChild(this.getNativeCanvasElement()); - if (index < stage.children.length - 1) { - stage.content.insertBefore( - this.getNativeCanvasElement(), - stage.children[index + 1].getCanvas()._canvas - ); - } else { - stage.content.appendChild(this.getNativeCanvasElement()); - } - } - return this; - } - moveToTop() { - Node.prototype.moveToTop.call(this); - var stage = this.getStage(); - if (stage && stage.content) { - stage.content.removeChild(this.getNativeCanvasElement()); - stage.content.appendChild(this.getNativeCanvasElement()); - } - return true; - } - moveUp() { - var moved = Node.prototype.moveUp.call(this); - if (!moved) { - return false; - } - var stage = this.getStage(); - if (!stage || !stage.content) { - return false; - } - stage.content.removeChild(this.getNativeCanvasElement()); - if (this.index < stage.children.length - 1) { - stage.content.insertBefore( - this.getNativeCanvasElement(), - stage.children[this.index + 1].getCanvas()._canvas - ); - } else { - stage.content.appendChild(this.getNativeCanvasElement()); - } - return true; - } - // extend Node.prototype.moveDown - moveDown() { - if (Node.prototype.moveDown.call(this)) { - var stage = this.getStage(); - if (stage) { - var children = stage.children; - if (stage.content) { - stage.content.removeChild(this.getNativeCanvasElement()); - stage.content.insertBefore( - this.getNativeCanvasElement(), - children[this.index + 1].getCanvas()._canvas - ); - } - } - return true; - } - return false; - } - // extend Node.prototype.moveToBottom - moveToBottom() { - if (Node.prototype.moveToBottom.call(this)) { - var stage = this.getStage(); - if (stage) { - var children = stage.children; - if (stage.content) { - stage.content.removeChild(this.getNativeCanvasElement()); - stage.content.insertBefore( - this.getNativeCanvasElement(), - children[1].getCanvas()._canvas - ); - } - } - return true; - } - return false; - } - getLayer() { - return this; - } - remove() { - var _canvas = this.getNativeCanvasElement(); - Node.prototype.remove.call(this); - if (_canvas && _canvas.parentNode && Util._isInDocument(_canvas)) { - _canvas.parentNode.removeChild(_canvas); - } - return this; - } - getStage() { - return this.parent; - } - setSize({ width, height }) { - this.canvas.setSize(width, height); - this.hitCanvas.setSize(width, height); - this._setSmoothEnabled(); - return this; - } - _validateAdd(child) { - var type = child.getType(); - if (type !== 'Group' && type !== 'Shape') { - Util.throw('You may only add groups and shapes to a layer.'); - } - } - _toKonvaCanvas(config) { - config = config || {}; - config.width = config.width || this.getWidth(); - config.height = config.height || this.getHeight(); - config.x = config.x !== undefined ? config.x : this.x(); - config.y = config.y !== undefined ? config.y : this.y(); - return Node.prototype._toKonvaCanvas.call(this, config); - } - _checkVisibility() { - const visible = this.visible(); - if (visible) { - this.canvas._canvas.style.display = 'block'; - } else { - this.canvas._canvas.style.display = 'none'; - } - } - _setSmoothEnabled() { - this.getContext()._context.imageSmoothingEnabled = this.imageSmoothingEnabled(); - } - /** - * get/set width of layer. getter return width of stage. setter doing nothing. - * if you want change width use `stage.width(value);` - * @name Konva.Layer#width - * @method - * @returns {Number} - * @example - * var width = layer.width(); - */ - getWidth() { - if (this.parent) { - return this.parent.width(); - } - } - setWidth() { - Util.warn( - 'Can not change width of layer. Use "stage.width(value)" function instead.' - ); - } - /** - * get/set height of layer.getter return height of stage. setter doing nothing. - * if you want change height use `stage.height(value);` - * @name Konva.Layer#height - * @method - * @returns {Number} - * @example - * var height = layer.height(); - */ - getHeight() { - if (this.parent) { - return this.parent.height(); - } - } - setHeight() { - Util.warn( - 'Can not change height of layer. Use "stage.height(value)" function instead.' - ); - } - /** - * batch draw. this function will not do immediate draw - * but it will schedule drawing to next tick (requestAnimFrame) - * @method - * @name Konva.Layer#batchDraw - * @return {Konva.Layer} this - */ - batchDraw() { - if (!this._waitingForDraw) { - this._waitingForDraw = true; - Util.requestAnimFrame(() => { - this.draw(); - this._waitingForDraw = false; - }); - } - return this; - } - /** - * 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'); - */ - getIntersection(pos, selector) { - if (!this.isListening() || !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 (let i = 0; i < INTERSECTION_OFFSETS_LEN; i++) { - const intersectionOffset = INTERSECTION_OFFSETS[i]; - const obj = this._getIntersection({ - x: pos.x + intersectionOffset.x * spiralSearchDistance, - y: pos.y + intersectionOffset.y * spiralSearchDistance, + constructor(config) { + super(config); + this.canvas = new SceneCanvas(); + this.hitCanvas = new HitCanvas({ + pixelRatio: 1, }); - const shape = obj.shape; - if (shape && selector) { - return shape.findAncestor(selector, true); - } else if (shape) { - return shape; + this._waitingForDraw = false; + this.on('visibleChange.konva', this._checkVisibility); + this._checkVisibility(); + this.on('imageSmoothingEnabledChange.konva', this._setSmoothEnabled); + this._setSmoothEnabled(); + } + // for nodejs? + createPNGStream() { + const c = this.canvas._canvas; + return c.createPNGStream(); + } + /** + * get layer canvas wrapper + * @method + * @name Konva.Layer#getCanvas + */ + getCanvas() { + return this.canvas; + } + /** + * get native canvas element + * @method + * @name Konva.Layer#getCanvas + */ + getNativeCanvasElement() { + return this.canvas._canvas; + } + /** + * get layer hit canvas + * @method + * @name Konva.Layer#getHitCanvas + */ + getHitCanvas() { + return this.hitCanvas; + } + /** + * get layer canvas context + * @method + * @name Konva.Layer#getContext + */ + getContext() { + return this.getCanvas().getContext(); + } + /** + * clear scene and hit canvas contexts tied to the layer. + * This function doesn't remove any nodes. It just clear canvas element. + * @method + * @name Konva.Layer#clear + * @param {Object} [bounds] + * @param {Number} [bounds.x] + * @param {Number} [bounds.y] + * @param {Number} [bounds.width] + * @param {Number} [bounds.height] + * @example + * layer.clear(); + * layer.clear({ + * x : 0, + * y : 0, + * width : 100, + * height : 100 + * }); + */ + clear(bounds) { + this.getContext().clear(bounds); + this.getHitCanvas().getContext().clear(bounds); + return this; + } + // extend Node.prototype.setZIndex + setZIndex(index) { + super.setZIndex(index); + var stage = this.getStage(); + if (stage && stage.content) { + stage.content.removeChild(this.getNativeCanvasElement()); + if (index < stage.children.length - 1) { + stage.content.insertBefore(this.getNativeCanvasElement(), stage.children[index + 1].getCanvas()._canvas); + } + else { + stage.content.appendChild(this.getNativeCanvasElement()); + } } - // 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; + return this; + } + moveToTop() { + Node.prototype.moveToTop.call(this); + var stage = this.getStage(); + if (stage && stage.content) { + stage.content.removeChild(this.getNativeCanvasElement()); + stage.content.appendChild(this.getNativeCanvasElement()); } - } - // if no shape, and no antialiased pixel, we should end searching - if (continueSearch) { - spiralSearchDistance += 1; - } else { - return null; - } + return true; } - } - _getIntersection(pos) { - const ratio = this.hitCanvas.pixelRatio; - const p = this.hitCanvas.context.getImageData( - Math.round(pos.x * ratio), - Math.round(pos.y * ratio), - 1, - 1 - ).data; - const p3 = p[3]; - // fully opaque pixel - if (p3 === 255) { - const colorKey = Util._rgbToHex(p[0], p[1], p[2]); - const shape = shapes[HASH + colorKey]; - if (shape) { - return { - shape: shape, - }; - } - return { - antialiased: true, - }; - } else if (p3 > 0) { - // antialiased pixel - return { - antialiased: true, - }; + moveUp() { + var moved = Node.prototype.moveUp.call(this); + if (!moved) { + return false; + } + var stage = this.getStage(); + if (!stage || !stage.content) { + return false; + } + stage.content.removeChild(this.getNativeCanvasElement()); + if (this.index < stage.children.length - 1) { + stage.content.insertBefore(this.getNativeCanvasElement(), stage.children[this.index + 1].getCanvas()._canvas); + } + else { + stage.content.appendChild(this.getNativeCanvasElement()); + } + return true; } - // empty pixel - return {}; - } - drawScene(can, top) { - var layer = this.getLayer(), - canvas = can || (layer && layer.getCanvas()); - this._fire(BEFORE_DRAW, { - node: this, - }); - if (this.clearBeforeDraw()) { - canvas.getContext().clear(); + // extend Node.prototype.moveDown + moveDown() { + if (Node.prototype.moveDown.call(this)) { + var stage = this.getStage(); + if (stage) { + var children = stage.children; + if (stage.content) { + stage.content.removeChild(this.getNativeCanvasElement()); + stage.content.insertBefore(this.getNativeCanvasElement(), children[this.index + 1].getCanvas()._canvas); + } + } + return true; + } + return false; } - Container.prototype.drawScene.call(this, canvas, top); - this._fire(DRAW, { - node: this, - }); - return this; - } - drawHit(can, top) { - var layer = this.getLayer(), - canvas = can || (layer && layer.hitCanvas); - if (layer && layer.clearBeforeDraw()) { - layer.getHitCanvas().getContext().clear(); + // extend Node.prototype.moveToBottom + moveToBottom() { + if (Node.prototype.moveToBottom.call(this)) { + var stage = this.getStage(); + if (stage) { + var children = stage.children; + if (stage.content) { + stage.content.removeChild(this.getNativeCanvasElement()); + stage.content.insertBefore(this.getNativeCanvasElement(), children[1].getCanvas()._canvas); + } + } + return true; + } + return false; } - Container.prototype.drawHit.call(this, canvas, top); - return this; - } - /** - * enable hit graph. **DEPRECATED!** Use `layer.listening(true)` instead. - * @name Konva.Layer#enableHitGraph - * @method - * @returns {Layer} - */ - enableHitGraph() { - this.hitGraphEnabled(true); - return this; - } - /** - * disable hit graph. **DEPRECATED!** Use `layer.listening(false)` instead. - * @name Konva.Layer#disableHitGraph - * @method - * @returns {Layer} - */ - disableHitGraph() { - this.hitGraphEnabled(false); - return this; - } - setHitGraphEnabled(val) { - Util.warn( - 'hitGraphEnabled method is deprecated. Please use layer.listening() instead.' - ); - this.listening(val); - } - getHitGraphEnabled(val) { - Util.warn( - 'hitGraphEnabled method is deprecated. Please use layer.listening() instead.' - ); - return this.listening(); - } - /** - * Show or hide hit canvas over the stage. May be useful for debugging custom hitFunc - * @name Konva.Layer#toggleHitCanvas - * @method - */ - toggleHitCanvas() { - if (!this.parent || !this.parent['content']) { - return; + getLayer() { + return this; } - 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); + remove() { + var _canvas = this.getNativeCanvasElement(); + Node.prototype.remove.call(this); + if (_canvas && _canvas.parentNode && Util._isInDocument(_canvas)) { + _canvas.parentNode.removeChild(_canvas); + } + return this; + } + getStage() { + return this.parent; + } + setSize({ width, height }) { + this.canvas.setSize(width, height); + this.hitCanvas.setSize(width, height); + this._setSmoothEnabled(); + return this; + } + _validateAdd(child) { + var type = child.getType(); + if (type !== 'Group' && type !== 'Shape') { + Util.throw('You may only add groups and shapes to a layer.'); + } + } + _toKonvaCanvas(config) { + config = config || {}; + config.width = config.width || this.getWidth(); + config.height = config.height || this.getHeight(); + config.x = config.x !== undefined ? config.x : this.x(); + config.y = config.y !== undefined ? config.y : this.y(); + return Node.prototype._toKonvaCanvas.call(this, config); + } + _checkVisibility() { + const visible = this.visible(); + if (visible) { + this.canvas._canvas.style.display = 'block'; + } + else { + this.canvas._canvas.style.display = 'none'; + } + } + _setSmoothEnabled() { + this.getContext()._context.imageSmoothingEnabled = this.imageSmoothingEnabled(); + } + /** + * get/set width of layer. getter return width of stage. setter doing nothing. + * if you want change width use `stage.width(value);` + * @name Konva.Layer#width + * @method + * @returns {Number} + * @example + * var width = layer.width(); + */ + getWidth() { + if (this.parent) { + return this.parent.width(); + } + } + setWidth() { + Util.warn('Can not change width of layer. Use "stage.width(value)" function instead.'); + } + /** + * get/set height of layer.getter return height of stage. setter doing nothing. + * if you want change height use `stage.height(value);` + * @name Konva.Layer#height + * @method + * @returns {Number} + * @example + * var height = layer.height(); + */ + getHeight() { + if (this.parent) { + return this.parent.height(); + } + } + setHeight() { + Util.warn('Can not change height of layer. Use "stage.height(value)" function instead.'); + } + /** + * batch draw. this function will not do immediate draw + * but it will schedule drawing to next tick (requestAnimFrame) + * @method + * @name Konva.Layer#batchDraw + * @return {Konva.Layer} this + */ + batchDraw() { + if (!this._waitingForDraw) { + this._waitingForDraw = true; + Util.requestAnimFrame(() => { + this.draw(); + this._waitingForDraw = false; + }); + } + return this; + } + /** + * 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'); + */ + getIntersection(pos, selector) { + if (!this.isListening() || !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 (let i = 0; i < INTERSECTION_OFFSETS_LEN; i++) { + const intersectionOffset = INTERSECTION_OFFSETS[i]; + const obj = this._getIntersection({ + x: pos.x + intersectionOffset.x * spiralSearchDistance, + y: pos.y + intersectionOffset.y * spiralSearchDistance, + }); + const 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; + } + } + } + _getIntersection(pos) { + const ratio = this.hitCanvas.pixelRatio; + const p = this.hitCanvas.context.getImageData(Math.round(pos.x * ratio), Math.round(pos.y * ratio), 1, 1).data; + const p3 = p[3]; + // fully opaque pixel + if (p3 === 255) { + const colorKey = Util._rgbToHex(p[0], p[1], p[2]); + const shape = shapes[HASH + colorKey]; + if (shape) { + return { + shape: shape, + }; + } + return { + antialiased: true, + }; + } + else if (p3 > 0) { + // antialiased pixel + return { + antialiased: true, + }; + } + // empty pixel + return {}; + } + drawScene(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; + } + drawHit(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; + } + /** + * enable hit graph. **DEPRECATED!** Use `layer.listening(true)` instead. + * @name Konva.Layer#enableHitGraph + * @method + * @returns {Layer} + */ + enableHitGraph() { + this.hitGraphEnabled(true); + return this; + } + /** + * disable hit graph. **DEPRECATED!** Use `layer.listening(false)` instead. + * @name Konva.Layer#disableHitGraph + * @method + * @returns {Layer} + */ + disableHitGraph() { + this.hitGraphEnabled(false); + return this; + } + setHitGraphEnabled(val) { + Util.warn('hitGraphEnabled method is deprecated. Please use layer.listening() instead.'); + this.listening(val); + } + getHitGraphEnabled(val) { + Util.warn('hitGraphEnabled method is deprecated. Please use layer.listening() instead.'); + return this.listening(); + } + /** + * Show or hide hit canvas over the stage. May be useful for debugging custom hitFunc + * @name Konva.Layer#toggleHitCanvas + * @method + */ + toggleHitCanvas() { + if (!this.parent || !this.parent['content']) { + 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.nodeType = 'Layer'; _registerNode(Layer); @@ -9188,12 +8559,7 @@ * layer.clearBeforeDraw(true); */ Factory.addGetterSetter(Layer, 'clearBeforeDraw', true); - Factory.addGetterSetter( - Layer, - 'hitGraphEnabled', - true, - getBooleanValidator() - ); + Factory.addGetterSetter(Layer, 'hitGraphEnabled', true, getBooleanValidator()); /** * get/set hitGraphEnabled flag. **DEPRECATED!** Use `layer.listening(false)` instead. * Disabling the hit graph will greatly increase @@ -9212,8 +8578,8 @@ * * // enable hit graph * layer.hitGraphEnabled(true); - */ - + */ + /** * FastLayer constructor. **DEPRECATED!** Please use `Konva.Layer({ listening: false})` instead. 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, @@ -9228,17 +8594,15 @@ * var layer = new Konva.FastLayer(); */ class FastLayer extends Layer { - constructor(attrs) { - super(attrs); - this.listening(false); - Util.warn( - 'Konva.Fast layer is deprecated. Please use "new Konva.Layer({ listening: false })" instead.' - ); - } + constructor(attrs) { + super(attrs); + this.listening(false); + Util.warn('Konva.Fast layer is deprecated. Please use "new Konva.Layer({ listening: false })" instead.'); + } } FastLayer.prototype.nodeType = 'FastLayer'; - _registerNode(FastLayer); - + _registerNode(FastLayer); + /** * Group constructor. Groups are used to contain shapes or other groups. * @constructor @@ -9251,25 +8615,25 @@ * var group = new Konva.Group(); */ class Group extends Container { - _validateAdd(child) { - var type = child.getType(); - if (type !== 'Group' && type !== 'Shape') { - Util.throw('You may only add groups and shapes to groups.'); + _validateAdd(child) { + var type = child.getType(); + if (type !== 'Group' && type !== 'Shape') { + Util.throw('You may only add groups and shapes to groups.'); + } } - } } Group.prototype.nodeType = 'Group'; - _registerNode(Group); - + _registerNode(Group); + var now = (function () { - if (glob.performance && glob.performance.now) { + if (glob.performance && glob.performance.now) { + return function () { + return glob.performance.now(); + }; + } return function () { - return glob.performance.now(); + return new Date().getTime(); }; - } - return function () { - return new Date().getTime(); - }; })(); /** * Animation constructor. @@ -9294,326 +8658,312 @@ * anim.start(); */ class Animation { - constructor(func, layers) { - this.id = Animation.animIdCounter++; - this.frame = { - time: 0, - timeDiff: 0, - lastTime: now(), - frameRate: 0, - }; - this.func = func; - this.setLayers(layers); - } - /** - * set layers to be redrawn on each animation frame - * @method - * @name Konva.Animation#setLayers - * @param {Konva.Layer|Array} [layers] layer(s) to be redrawn. Can be a layer, an array of layers, or null. Not specifying a node will result in no redraw. - * @return {Konva.Animation} this - */ - setLayers(layers) { - var lays = []; - // if passing in no layers - if (!layers) { - lays = []; - } else if (layers.length > 0) { - // if passing in an array of Layers - // NOTE: layers could be an array. for simplicity, I'm just inspecting - // the length property to check for both cases - lays = layers; - } else { - // if passing in a Layer - lays = [layers]; + constructor(func, layers) { + this.id = Animation.animIdCounter++; + this.frame = { + time: 0, + timeDiff: 0, + lastTime: now(), + frameRate: 0, + }; + this.func = func; + this.setLayers(layers); } - this.layers = lays; - return this; - } - /** - * get layers - * @method - * @name Konva.Animation#getLayers - * @return {Array} Array of Konva.Layer - */ - getLayers() { - return this.layers; - } - /** - * add layer. Returns true if the layer was added, and false if it was not - * @method - * @name Konva.Animation#addLayer - * @param {Konva.Layer} layer to add - * @return {Bool} true if layer is added to animation, otherwise false - */ - addLayer(layer) { - var layers = this.layers, - len = layers.length, - n; - // don't add the layer if it already exists - for (n = 0; n < len; n++) { - if (layers[n]._id === layer._id) { - return false; - } - } - this.layers.push(layer); - return true; - } - /** - * determine if animation is running or not. returns true or false - * @method - * @name Konva.Animation#isRunning - * @return {Bool} is animation running? - */ - isRunning() { - var a = Animation, - animations = a.animations, - len = animations.length, - n; - for (n = 0; n < len; n++) { - if (animations[n].id === this.id) { - return true; - } - } - return false; - } - /** - * start animation - * @method - * @name Konva.Animation#start - * @return {Konva.Animation} this - */ - start() { - this.stop(); - this.frame.timeDiff = 0; - this.frame.lastTime = now(); - Animation._addAnimation(this); - return this; - } - /** - * stop animation - * @method - * @name Konva.Animation#stop - * @return {Konva.Animation} this - */ - stop() { - Animation._removeAnimation(this); - return this; - } - _updateFrameObject(time) { - this.frame.timeDiff = time - this.frame.lastTime; - this.frame.lastTime = time; - this.frame.time += this.frame.timeDiff; - this.frame.frameRate = 1000 / this.frame.timeDiff; - } - static _addAnimation(anim) { - this.animations.push(anim); - this._handleAnimation(); - } - static _removeAnimation(anim) { - var id = anim.id, - animations = this.animations, - len = animations.length, - n; - for (n = 0; n < len; n++) { - if (animations[n].id === id) { - this.animations.splice(n, 1); - break; - } - } - } - static _runFrames() { - var layerHash = {}, - animations = this.animations, - anim, - layers, - func, - n, - i, - layersLen, - layer, - key, - needRedraw; - /* - * loop through all animations and execute animation - * function. if the animation object has specified node, - * we can add the node to the nodes hash to eliminate - * drawing the same node multiple times. The node property - * can be the stage itself or a layer + /** + * set layers to be redrawn on each animation frame + * @method + * @name Konva.Animation#setLayers + * @param {Konva.Layer|Array} [layers] layer(s) to be redrawn. Can be a layer, an array of layers, or null. Not specifying a node will result in no redraw. + * @return {Konva.Animation} this */ - /* - * WARNING: don't cache animations.length because it could change while - * the for loop is running, causing a JS error - */ - for (n = 0; n < animations.length; n++) { - anim = animations[n]; - layers = anim.layers; - func = anim.func; - anim._updateFrameObject(now()); - layersLen = layers.length; - // if animation object has a function, execute it - if (func) { - // allow anim bypassing drawing - needRedraw = func.call(anim, anim.frame) !== false; - } else { - needRedraw = true; - } - if (!needRedraw) { - continue; - } - for (i = 0; i < layersLen; i++) { - layer = layers[i]; - if (layer._id !== undefined) { - layerHash[layer._id] = layer; + setLayers(layers) { + var lays = []; + // if passing in no layers + if (!layers) { + lays = []; } - } + else if (layers.length > 0) { + // if passing in an array of Layers + // NOTE: layers could be an array. for simplicity, I'm just inspecting + // the length property to check for both cases + lays = layers; + } + else { + // if passing in a Layer + lays = [layers]; + } + this.layers = lays; + return this; } - for (key in layerHash) { - if (!layerHash.hasOwnProperty(key)) { - continue; - } - layerHash[key].draw(); + /** + * get layers + * @method + * @name Konva.Animation#getLayers + * @return {Array} Array of Konva.Layer + */ + getLayers() { + return this.layers; } - } - static _animationLoop() { - var Anim = Animation; - if (Anim.animations.length) { - Anim._runFrames(); - Util.requestAnimFrame(Anim._animationLoop); - } else { - Anim.animRunning = false; + /** + * add layer. Returns true if the layer was added, and false if it was not + * @method + * @name Konva.Animation#addLayer + * @param {Konva.Layer} layer to add + * @return {Bool} true if layer is added to animation, otherwise false + */ + addLayer(layer) { + var layers = this.layers, len = layers.length, n; + // don't add the layer if it already exists + for (n = 0; n < len; n++) { + if (layers[n]._id === layer._id) { + return false; + } + } + this.layers.push(layer); + return true; } - } - static _handleAnimation() { - if (!this.animRunning) { - this.animRunning = true; - Util.requestAnimFrame(this._animationLoop); + /** + * determine if animation is running or not. returns true or false + * @method + * @name Konva.Animation#isRunning + * @return {Bool} is animation running? + */ + isRunning() { + var a = Animation, animations = a.animations, len = animations.length, n; + for (n = 0; n < len; n++) { + if (animations[n].id === this.id) { + return true; + } + } + return false; + } + /** + * start animation + * @method + * @name Konva.Animation#start + * @return {Konva.Animation} this + */ + start() { + this.stop(); + this.frame.timeDiff = 0; + this.frame.lastTime = now(); + Animation._addAnimation(this); + return this; + } + /** + * stop animation + * @method + * @name Konva.Animation#stop + * @return {Konva.Animation} this + */ + stop() { + Animation._removeAnimation(this); + return this; + } + _updateFrameObject(time) { + this.frame.timeDiff = time - this.frame.lastTime; + this.frame.lastTime = time; + this.frame.time += this.frame.timeDiff; + this.frame.frameRate = 1000 / this.frame.timeDiff; + } + static _addAnimation(anim) { + this.animations.push(anim); + this._handleAnimation(); + } + static _removeAnimation(anim) { + var id = anim.id, animations = this.animations, len = animations.length, n; + for (n = 0; n < len; n++) { + if (animations[n].id === id) { + this.animations.splice(n, 1); + break; + } + } + } + static _runFrames() { + var layerHash = {}, animations = this.animations, anim, layers, func, n, i, layersLen, layer, key, needRedraw; + /* + * loop through all animations and execute animation + * function. if the animation object has specified node, + * we can add the node to the nodes hash to eliminate + * drawing the same node multiple times. The node property + * can be the stage itself or a layer + */ + /* + * WARNING: don't cache animations.length because it could change while + * the for loop is running, causing a JS error + */ + for (n = 0; n < animations.length; n++) { + anim = animations[n]; + layers = anim.layers; + func = anim.func; + anim._updateFrameObject(now()); + layersLen = layers.length; + // if animation object has a function, execute it + if (func) { + // allow anim bypassing drawing + needRedraw = func.call(anim, anim.frame) !== false; + } + else { + needRedraw = true; + } + if (!needRedraw) { + continue; + } + for (i = 0; i < layersLen; i++) { + layer = layers[i]; + if (layer._id !== undefined) { + layerHash[layer._id] = layer; + } + } + } + for (key in layerHash) { + if (!layerHash.hasOwnProperty(key)) { + continue; + } + layerHash[key].batchDraw(); + } + } + static _animationLoop() { + var Anim = Animation; + if (Anim.animations.length) { + Anim._runFrames(); + Util.requestAnimFrame(Anim._animationLoop); + } + else { + Anim.animRunning = false; + } + } + static _handleAnimation() { + if (!this.animRunning) { + this.animRunning = true; + Util.requestAnimFrame(this._animationLoop); + } } - } } Animation.animations = []; Animation.animIdCounter = 0; - Animation.animRunning = false; - + Animation.animRunning = false; + var blacklist = { node: 1, duration: 1, easing: 1, onFinish: 1, yoyo: 1, - }, - PAUSED = 1, - PLAYING = 2, - REVERSING = 3, - idCounter = 0, - colorAttrs = ['fill', 'stroke', 'shadowColor']; + }, PAUSED = 1, PLAYING = 2, REVERSING = 3, idCounter = 0, colorAttrs = ['fill', 'stroke', 'shadowColor']; class TweenEngine { - constructor(prop, propFunc, func, begin, finish, duration, yoyo) { - this.prop = prop; - this.propFunc = propFunc; - this.begin = begin; - this._pos = begin; - this.duration = duration; - this._change = 0; - this.prevPos = 0; - this.yoyo = yoyo; - this._time = 0; - this._position = 0; - this._startTime = 0; - this._finish = 0; - this.func = func; - this._change = finish - this.begin; - this.pause(); - } - fire(str) { - var handler = this[str]; - if (handler) { - handler(); - } - } - setTime(t) { - if (t > this.duration) { - if (this.yoyo) { - this._time = this.duration; - this.reverse(); - } else { - this.finish(); - } - } else if (t < 0) { - if (this.yoyo) { + constructor(prop, propFunc, func, begin, finish, duration, yoyo) { + this.prop = prop; + this.propFunc = propFunc; + this.begin = begin; + this._pos = begin; + this.duration = duration; + this._change = 0; + this.prevPos = 0; + this.yoyo = yoyo; this._time = 0; - this.play(); - } else { - this.reset(); - } - } else { - this._time = t; - this.update(); + this._position = 0; + this._startTime = 0; + this._finish = 0; + this.func = func; + this._change = finish - this.begin; + this.pause(); } - } - getTime() { - return this._time; - } - setPosition(p) { - this.prevPos = this._pos; - this.propFunc(p); - this._pos = p; - } - getPosition(t) { - if (t === undefined) { - t = this._time; + fire(str) { + var handler = this[str]; + if (handler) { + handler(); + } } - return this.func(t, this.begin, this._change, this.duration); - } - play() { - this.state = PLAYING; - this._startTime = this.getTimer() - this._time; - this.onEnterFrame(); - this.fire('onPlay'); - } - reverse() { - this.state = REVERSING; - this._time = this.duration - this._time; - this._startTime = this.getTimer() - this._time; - this.onEnterFrame(); - this.fire('onReverse'); - } - seek(t) { - this.pause(); - this._time = t; - this.update(); - this.fire('onSeek'); - } - reset() { - this.pause(); - this._time = 0; - this.update(); - this.fire('onReset'); - } - finish() { - this.pause(); - this._time = this.duration; - this.update(); - this.fire('onFinish'); - } - update() { - this.setPosition(this.getPosition(this._time)); - this.fire('onUpdate'); - } - onEnterFrame() { - var t = this.getTimer() - this._startTime; - if (this.state === PLAYING) { - this.setTime(t); - } else if (this.state === REVERSING) { - this.setTime(this.duration - t); + setTime(t) { + if (t > this.duration) { + if (this.yoyo) { + this._time = this.duration; + this.reverse(); + } + else { + this.finish(); + } + } + else if (t < 0) { + if (this.yoyo) { + this._time = 0; + this.play(); + } + else { + this.reset(); + } + } + else { + this._time = t; + this.update(); + } + } + getTime() { + return this._time; + } + setPosition(p) { + this.prevPos = this._pos; + this.propFunc(p); + this._pos = p; + } + getPosition(t) { + if (t === undefined) { + t = this._time; + } + return this.func(t, this.begin, this._change, this.duration); + } + play() { + this.state = PLAYING; + this._startTime = this.getTimer() - this._time; + this.onEnterFrame(); + this.fire('onPlay'); + } + reverse() { + this.state = REVERSING; + this._time = this.duration - this._time; + this._startTime = this.getTimer() - this._time; + this.onEnterFrame(); + this.fire('onReverse'); + } + seek(t) { + this.pause(); + this._time = t; + this.update(); + this.fire('onSeek'); + } + reset() { + this.pause(); + this._time = 0; + this.update(); + this.fire('onReset'); + } + finish() { + this.pause(); + this._time = this.duration; + this.update(); + this.fire('onFinish'); + } + update() { + this.setPosition(this.getPosition(this._time)); + this.fire('onUpdate'); + } + onEnterFrame() { + var t = this.getTimer() - this._startTime; + if (this.state === PLAYING) { + this.setTime(t); + } + else if (this.state === REVERSING) { + this.setTime(this.duration - t); + } + } + pause() { + this.state = PAUSED; + this.fire('onPause'); + } + getTimer() { + return new Date().getTime(); } - } - pause() { - this.state = PAUSED; - this.fire('onPause'); - } - getTimer() { - return new Date().getTime(); - } } /** * Tween constructor. Tweens enable you to animate a node between the current state and a new state. @@ -9642,321 +8992,292 @@ * tween.pause(); */ class Tween { - constructor(config) { - var that = this, - node = config.node, - nodeId = node._id, - duration, - easing = config.easing || Easings.Linear, - yoyo = !!config.yoyo, - key; - if (typeof config.duration === 'undefined') { - duration = 0.3; - } else if (config.duration === 0) { - // zero is bad value for duration - duration = 0.001; - } else { - duration = config.duration; - } - this.node = node; - this._id = idCounter++; - var layers = - node.getLayer() || - (node instanceof Konva$2['Stage'] ? node.getLayers() : null); - if (!layers) { - Util.error( - 'Tween constructor have `node` that is not in a layer. Please add node into layer first.' - ); - } - this.anim = new Animation(function () { - that.tween.onEnterFrame(); - }, layers); - this.tween = new TweenEngine( - key, - function (i) { - that._tweenFunc(i); - }, - easing, - 0, - 1, - duration * 1000, - yoyo - ); - this._addListeners(); - // init attrs map - if (!Tween.attrs[nodeId]) { - Tween.attrs[nodeId] = {}; - } - if (!Tween.attrs[nodeId][this._id]) { - Tween.attrs[nodeId][this._id] = {}; - } - // init tweens map - if (!Tween.tweens[nodeId]) { - Tween.tweens[nodeId] = {}; - } - for (key in config) { - if (blacklist[key] === undefined) { - this._addAttr(key, config[key]); - } - } - this.reset(); - // callbacks - this.onFinish = config.onFinish; - this.onReset = config.onReset; - this.onUpdate = config.onUpdate; - } - _addAttr(key, end) { - var node = this.node, - nodeId = node._id, - start, - diff, - tweenId, - n, - len, - trueEnd, - trueStart, - endRGBA; - // remove conflict from tween map if it exists - tweenId = Tween.tweens[nodeId][key]; - if (tweenId) { - delete Tween.attrs[nodeId][tweenId][key]; - } - // add to tween map - start = node.getAttr(key); - if (Util._isArray(end)) { - diff = []; - len = Math.max(end.length, start.length); - if (key === 'points' && end.length !== start.length) { - // before tweening points we need to make sure that start.length === end.length - // Util._prepareArrayForTween thinking that end.length > start.length - if (end.length > start.length) { - // so in this case we will increase number of starting points - trueStart = start; - start = Util._prepareArrayForTween(start, end, node.closed()); - } else { - // in this case we will increase number of eding points - trueEnd = end; - end = Util._prepareArrayForTween(end, start, node.closed()); + constructor(config) { + var that = this, node = config.node, nodeId = node._id, duration, easing = config.easing || Easings.Linear, yoyo = !!config.yoyo, key; + if (typeof config.duration === 'undefined') { + duration = 0.3; } - } - if (key.indexOf('fill') === 0) { - for (n = 0; n < len; n++) { - if (n % 2 === 0) { - diff.push(end[n] - start[n]); - } else { - var startRGBA = Util.colorToRGBA(start[n]); - endRGBA = Util.colorToRGBA(end[n]); - start[n] = startRGBA; - diff.push({ - r: endRGBA.r - startRGBA.r, - g: endRGBA.g - startRGBA.g, - b: endRGBA.b - startRGBA.b, - a: endRGBA.a - startRGBA.a, - }); - } + else if (config.duration === 0) { + // zero is bad value for duration + duration = 0.001; } - } else { - for (n = 0; n < len; n++) { - diff.push(end[n] - start[n]); + else { + duration = config.duration; } - } - } else if (colorAttrs.indexOf(key) !== -1) { - start = Util.colorToRGBA(start); - endRGBA = Util.colorToRGBA(end); - diff = { - r: endRGBA.r - start.r, - g: endRGBA.g - start.g, - b: endRGBA.b - start.b, - a: endRGBA.a - start.a, - }; - } else { - diff = end - start; - } - Tween.attrs[nodeId][this._id][key] = { - start: start, - diff: diff, - end: end, - trueEnd: trueEnd, - trueStart: trueStart, - }; - Tween.tweens[nodeId][key] = this._id; - } - _tweenFunc(i) { - var node = this.node, - attrs = Tween.attrs[node._id][this._id], - key, - attr, - start, - diff, - newVal, - n, - len, - end; - for (key in attrs) { - attr = attrs[key]; - start = attr.start; - diff = attr.diff; - end = attr.end; - if (Util._isArray(start)) { - newVal = []; - len = Math.max(start.length, end.length); - if (key.indexOf('fill') === 0) { - for (n = 0; n < len; n++) { - if (n % 2 === 0) { - newVal.push((start[n] || 0) + diff[n] * i); - } else { - newVal.push( - 'rgba(' + - Math.round(start[n].r + diff[n].r * i) + - ',' + - Math.round(start[n].g + diff[n].g * i) + - ',' + - Math.round(start[n].b + diff[n].b * i) + - ',' + - (start[n].a + diff[n].a * i) + - ')' - ); + this.node = node; + this._id = idCounter++; + var layers = node.getLayer() || + (node instanceof Konva$2['Stage'] ? node.getLayers() : null); + if (!layers) { + Util.error('Tween constructor have `node` that is not in a layer. Please add node into layer first.'); + } + this.anim = new Animation(function () { + that.tween.onEnterFrame(); + }, layers); + this.tween = new TweenEngine(key, function (i) { + that._tweenFunc(i); + }, easing, 0, 1, duration * 1000, yoyo); + this._addListeners(); + // init attrs map + if (!Tween.attrs[nodeId]) { + Tween.attrs[nodeId] = {}; + } + if (!Tween.attrs[nodeId][this._id]) { + Tween.attrs[nodeId][this._id] = {}; + } + // init tweens map + if (!Tween.tweens[nodeId]) { + Tween.tweens[nodeId] = {}; + } + for (key in config) { + if (blacklist[key] === undefined) { + this._addAttr(key, config[key]); } - } - } else { - for (n = 0; n < len; n++) { - newVal.push((start[n] || 0) + diff[n] * i); - } } - } else if (colorAttrs.indexOf(key) !== -1) { - newVal = - 'rgba(' + - Math.round(start.r + diff.r * i) + - ',' + - Math.round(start.g + diff.g * i) + - ',' + - Math.round(start.b + diff.b * i) + - ',' + - (start.a + diff.a * i) + - ')'; - } else { - newVal = start + diff * i; - } - node.setAttr(key, newVal); + this.reset(); + // callbacks + this.onFinish = config.onFinish; + this.onReset = config.onReset; + this.onUpdate = config.onUpdate; } - } - _addListeners() { - // start listeners - this.tween.onPlay = () => { - this.anim.start(); - }; - this.tween.onReverse = () => { - this.anim.start(); - }; - // stop listeners - this.tween.onPause = () => { - this.anim.stop(); - }; - this.tween.onFinish = () => { - var node = this.node; - // after tweening points of line we need to set original end - var attrs = Tween.attrs[node._id][this._id]; - if (attrs.points && attrs.points.trueEnd) { - node.setAttr('points', attrs.points.trueEnd); - } - if (this.onFinish) { - this.onFinish.call(this); - } - }; - this.tween.onReset = () => { - var node = this.node; - // after tweening points of line we need to set original start - var attrs = Tween.attrs[node._id][this._id]; - if (attrs.points && attrs.points.trueStart) { - node.points(attrs.points.trueStart); - } - if (this.onReset) { - this.onReset(); - } - }; - this.tween.onUpdate = () => { - if (this.onUpdate) { - this.onUpdate.call(this); - } - }; - } - /** - * play - * @method - * @name Konva.Tween#play - * @returns {Tween} - */ - play() { - this.tween.play(); - return this; - } - /** - * reverse - * @method - * @name Konva.Tween#reverse - * @returns {Tween} - */ - reverse() { - this.tween.reverse(); - return this; - } - /** - * reset - * @method - * @name Konva.Tween#reset - * @returns {Tween} - */ - reset() { - this.tween.reset(); - return this; - } - /** - * seek - * @method - * @name Konva.Tween#seek( - * @param {Integer} t time in seconds between 0 and the duration - * @returns {Tween} - */ - seek(t) { - this.tween.seek(t * 1000); - return this; - } - /** - * pause - * @method - * @name Konva.Tween#pause - * @returns {Tween} - */ - pause() { - this.tween.pause(); - return this; - } - /** - * finish - * @method - * @name Konva.Tween#finish - * @returns {Tween} - */ - finish() { - this.tween.finish(); - return this; - } - /** - * destroy - * @method - * @name Konva.Tween#destroy - */ - destroy() { - var nodeId = this.node._id, - thisId = this._id, - attrs = Tween.tweens[nodeId], - key; - this.pause(); - for (key in attrs) { - delete Tween.tweens[nodeId][key]; + _addAttr(key, end) { + var node = this.node, nodeId = node._id, start, diff, tweenId, n, len, trueEnd, trueStart, endRGBA; + // remove conflict from tween map if it exists + tweenId = Tween.tweens[nodeId][key]; + if (tweenId) { + delete Tween.attrs[nodeId][tweenId][key]; + } + // add to tween map + start = node.getAttr(key); + if (Util._isArray(end)) { + diff = []; + len = Math.max(end.length, start.length); + if (key === 'points' && end.length !== start.length) { + // before tweening points we need to make sure that start.length === end.length + // Util._prepareArrayForTween thinking that end.length > start.length + if (end.length > start.length) { + // so in this case we will increase number of starting points + trueStart = start; + start = Util._prepareArrayForTween(start, end, node.closed()); + } + else { + // in this case we will increase number of eding points + trueEnd = end; + end = Util._prepareArrayForTween(end, start, node.closed()); + } + } + if (key.indexOf('fill') === 0) { + for (n = 0; n < len; n++) { + if (n % 2 === 0) { + diff.push(end[n] - start[n]); + } + else { + var startRGBA = Util.colorToRGBA(start[n]); + endRGBA = Util.colorToRGBA(end[n]); + start[n] = startRGBA; + diff.push({ + r: endRGBA.r - startRGBA.r, + g: endRGBA.g - startRGBA.g, + b: endRGBA.b - startRGBA.b, + a: endRGBA.a - startRGBA.a, + }); + } + } + } + else { + for (n = 0; n < len; n++) { + diff.push(end[n] - start[n]); + } + } + } + else if (colorAttrs.indexOf(key) !== -1) { + start = Util.colorToRGBA(start); + endRGBA = Util.colorToRGBA(end); + diff = { + r: endRGBA.r - start.r, + g: endRGBA.g - start.g, + b: endRGBA.b - start.b, + a: endRGBA.a - start.a, + }; + } + else { + diff = end - start; + } + Tween.attrs[nodeId][this._id][key] = { + start: start, + diff: diff, + end: end, + trueEnd: trueEnd, + trueStart: trueStart, + }; + Tween.tweens[nodeId][key] = this._id; + } + _tweenFunc(i) { + var node = this.node, attrs = Tween.attrs[node._id][this._id], key, attr, start, diff, newVal, n, len, end; + for (key in attrs) { + attr = attrs[key]; + start = attr.start; + diff = attr.diff; + end = attr.end; + if (Util._isArray(start)) { + newVal = []; + len = Math.max(start.length, end.length); + if (key.indexOf('fill') === 0) { + for (n = 0; n < len; n++) { + if (n % 2 === 0) { + newVal.push((start[n] || 0) + diff[n] * i); + } + else { + newVal.push('rgba(' + + Math.round(start[n].r + diff[n].r * i) + + ',' + + Math.round(start[n].g + diff[n].g * i) + + ',' + + Math.round(start[n].b + diff[n].b * i) + + ',' + + (start[n].a + diff[n].a * i) + + ')'); + } + } + } + else { + for (n = 0; n < len; n++) { + newVal.push((start[n] || 0) + diff[n] * i); + } + } + } + else if (colorAttrs.indexOf(key) !== -1) { + newVal = + 'rgba(' + + Math.round(start.r + diff.r * i) + + ',' + + Math.round(start.g + diff.g * i) + + ',' + + Math.round(start.b + diff.b * i) + + ',' + + (start.a + diff.a * i) + + ')'; + } + else { + newVal = start + diff * i; + } + node.setAttr(key, newVal); + } + } + _addListeners() { + // start listeners + this.tween.onPlay = () => { + this.anim.start(); + }; + this.tween.onReverse = () => { + this.anim.start(); + }; + // stop listeners + this.tween.onPause = () => { + this.anim.stop(); + }; + this.tween.onFinish = () => { + var node = this.node; + // after tweening points of line we need to set original end + var attrs = Tween.attrs[node._id][this._id]; + if (attrs.points && attrs.points.trueEnd) { + node.setAttr('points', attrs.points.trueEnd); + } + if (this.onFinish) { + this.onFinish.call(this); + } + }; + this.tween.onReset = () => { + var node = this.node; + // after tweening points of line we need to set original start + var attrs = Tween.attrs[node._id][this._id]; + if (attrs.points && attrs.points.trueStart) { + node.points(attrs.points.trueStart); + } + if (this.onReset) { + this.onReset(); + } + }; + this.tween.onUpdate = () => { + if (this.onUpdate) { + this.onUpdate.call(this); + } + }; + } + /** + * play + * @method + * @name Konva.Tween#play + * @returns {Tween} + */ + play() { + this.tween.play(); + return this; + } + /** + * reverse + * @method + * @name Konva.Tween#reverse + * @returns {Tween} + */ + reverse() { + this.tween.reverse(); + return this; + } + /** + * reset + * @method + * @name Konva.Tween#reset + * @returns {Tween} + */ + reset() { + this.tween.reset(); + return this; + } + /** + * seek + * @method + * @name Konva.Tween#seek( + * @param {Integer} t time in seconds between 0 and the duration + * @returns {Tween} + */ + seek(t) { + this.tween.seek(t * 1000); + return this; + } + /** + * pause + * @method + * @name Konva.Tween#pause + * @returns {Tween} + */ + pause() { + this.tween.pause(); + return this; + } + /** + * finish + * @method + * @name Konva.Tween#finish + * @returns {Tween} + */ + finish() { + this.tween.finish(); + return this; + } + /** + * destroy + * @method + * @name Konva.Tween#destroy + */ + destroy() { + var nodeId = this.node._id, thisId = this._id, attrs = Tween.tweens[nodeId], key; + this.pause(); + for (key in attrs) { + delete Tween.tweens[nodeId][key]; + } + delete Tween.attrs[nodeId][thisId]; } - delete Tween.attrs[nodeId][thisId]; - } } Tween.attrs = {}; Tween.tweens = {}; @@ -9975,16 +9296,16 @@ * }); */ Node.prototype.to = function (params) { - var onFinish = params.onFinish; - params.node = this; - params.onFinish = function () { - this.destroy(); - if (onFinish) { - onFinish(); - } - }; - var tween = new Tween(params); - tween.play(); + var onFinish = params.onFinish; + params.node = this; + params.onFinish = function () { + this.destroy(); + if (onFinish) { + onFinish(); + } + }; + var tween = new Tween(params); + tween.play(); }; /* * These eases were ported from an Adobe Flash tweening library to JavaScript @@ -9995,260 +9316,257 @@ * @memberof Konva */ const Easings = { - /** - * back ease in - * @function - * @memberof Konva.Easings - */ - BackEaseIn(t, b, c, d) { - var s = 1.70158; - return c * (t /= d) * t * ((s + 1) * t - s) + b; - }, - /** - * back ease out - * @function - * @memberof Konva.Easings - */ - BackEaseOut(t, b, c, d) { - var s = 1.70158; - return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; - }, - /** - * back ease in out - * @function - * @memberof Konva.Easings - */ - BackEaseInOut(t, b, c, d) { - var s = 1.70158; - if ((t /= d / 2) < 1) { - return (c / 2) * (t * t * (((s *= 1.525) + 1) * t - s)) + b; - } - return (c / 2) * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b; - }, - /** - * elastic ease in - * @function - * @memberof Konva.Easings - */ - ElasticEaseIn(t, b, c, d, a, p) { - // added s = 0 - var s = 0; - if (t === 0) { - return b; - } - if ((t /= d) === 1) { - return b + c; - } - if (!p) { - p = d * 0.3; - } - if (!a || a < Math.abs(c)) { - a = c; - s = p / 4; - } else { - s = (p / (2 * Math.PI)) * Math.asin(c / a); - } - return ( - -( - a * - Math.pow(2, 10 * (t -= 1)) * - Math.sin(((t * d - s) * (2 * Math.PI)) / p) - ) + b - ); - }, - /** - * elastic ease out - * @function - * @memberof Konva.Easings - */ - ElasticEaseOut(t, b, c, d, a, p) { - // added s = 0 - var s = 0; - if (t === 0) { - return b; - } - if ((t /= d) === 1) { - return b + c; - } - if (!p) { - p = d * 0.3; - } - if (!a || a < Math.abs(c)) { - a = c; - s = p / 4; - } else { - s = (p / (2 * Math.PI)) * Math.asin(c / a); - } - return ( - a * Math.pow(2, -10 * t) * Math.sin(((t * d - s) * (2 * Math.PI)) / p) + - c + - b - ); - }, - /** - * elastic ease in out - * @function - * @memberof Konva.Easings - */ - ElasticEaseInOut(t, b, c, d, a, p) { - // added s = 0 - var s = 0; - if (t === 0) { - return b; - } - if ((t /= d / 2) === 2) { - return b + c; - } - if (!p) { - p = d * (0.3 * 1.5); - } - if (!a || a < Math.abs(c)) { - a = c; - s = p / 4; - } else { - s = (p / (2 * Math.PI)) * Math.asin(c / a); - } - if (t < 1) { - return ( - -0.5 * - (a * + /** + * back ease in + * @function + * @memberof Konva.Easings + */ + BackEaseIn(t, b, c, d) { + var s = 1.70158; + return c * (t /= d) * t * ((s + 1) * t - s) + b; + }, + /** + * back ease out + * @function + * @memberof Konva.Easings + */ + BackEaseOut(t, b, c, d) { + var s = 1.70158; + return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; + }, + /** + * back ease in out + * @function + * @memberof Konva.Easings + */ + BackEaseInOut(t, b, c, d) { + var s = 1.70158; + if ((t /= d / 2) < 1) { + return (c / 2) * (t * t * (((s *= 1.525) + 1) * t - s)) + b; + } + return (c / 2) * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b; + }, + /** + * elastic ease in + * @function + * @memberof Konva.Easings + */ + ElasticEaseIn(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if (t === 0) { + return b; + } + if ((t /= d) === 1) { + return b + c; + } + if (!p) { + p = d * 0.3; + } + if (!a || a < Math.abs(c)) { + a = c; + s = p / 4; + } + else { + s = (p / (2 * Math.PI)) * Math.asin(c / a); + } + return (-(a * Math.pow(2, 10 * (t -= 1)) * - Math.sin(((t * d - s) * (2 * Math.PI)) / p)) + - b - ); - } - return ( - a * - Math.pow(2, -10 * (t -= 1)) * - Math.sin(((t * d - s) * (2 * Math.PI)) / p) * - 0.5 + - c + - b - ); - }, - /** - * bounce ease out - * @function - * @memberof Konva.Easings - */ - BounceEaseOut(t, b, c, d) { - if ((t /= d) < 1 / 2.75) { - return c * (7.5625 * t * t) + b; - } else if (t < 2 / 2.75) { - return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b; - } else if (t < 2.5 / 2.75) { - return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b; - } else { - return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b; - } - }, - /** - * bounce ease in - * @function - * @memberof Konva.Easings - */ - BounceEaseIn(t, b, c, d) { - return c - Easings.BounceEaseOut(d - t, 0, c, d) + b; - }, - /** - * bounce ease in out - * @function - * @memberof Konva.Easings - */ - BounceEaseInOut(t, b, c, d) { - if (t < d / 2) { - return Easings.BounceEaseIn(t * 2, 0, c, d) * 0.5 + b; - } else { - return Easings.BounceEaseOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; - } - }, - /** - * ease in - * @function - * @memberof Konva.Easings - */ - EaseIn(t, b, c, d) { - return c * (t /= d) * t + b; - }, - /** - * ease out - * @function - * @memberof Konva.Easings - */ - EaseOut(t, b, c, d) { - return -c * (t /= d) * (t - 2) + b; - }, - /** - * ease in out - * @function - * @memberof Konva.Easings - */ - EaseInOut(t, b, c, d) { - if ((t /= d / 2) < 1) { - return (c / 2) * t * t + b; - } - return (-c / 2) * (--t * (t - 2) - 1) + b; - }, - /** - * strong ease in - * @function - * @memberof Konva.Easings - */ - StrongEaseIn(t, b, c, d) { - return c * (t /= d) * t * t * t * t + b; - }, - /** - * strong ease out - * @function - * @memberof Konva.Easings - */ - StrongEaseOut(t, b, c, d) { - return c * ((t = t / d - 1) * t * t * t * t + 1) + b; - }, - /** - * strong ease in out - * @function - * @memberof Konva.Easings - */ - StrongEaseInOut(t, b, c, d) { - if ((t /= d / 2) < 1) { - return (c / 2) * t * t * t * t * t + b; - } - return (c / 2) * ((t -= 2) * t * t * t * t + 2) + b; - }, - /** - * linear - * @function - * @memberof Konva.Easings - */ - Linear(t, b, c, d) { - return (c * t) / d + b; - }, - }; - + Math.sin(((t * d - s) * (2 * Math.PI)) / p)) + b); + }, + /** + * elastic ease out + * @function + * @memberof Konva.Easings + */ + ElasticEaseOut(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if (t === 0) { + return b; + } + if ((t /= d) === 1) { + return b + c; + } + if (!p) { + p = d * 0.3; + } + if (!a || a < Math.abs(c)) { + a = c; + s = p / 4; + } + else { + s = (p / (2 * Math.PI)) * Math.asin(c / a); + } + return (a * Math.pow(2, -10 * t) * Math.sin(((t * d - s) * (2 * Math.PI)) / p) + + c + + b); + }, + /** + * elastic ease in out + * @function + * @memberof Konva.Easings + */ + ElasticEaseInOut(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if (t === 0) { + return b; + } + if ((t /= d / 2) === 2) { + return b + c; + } + if (!p) { + p = d * (0.3 * 1.5); + } + if (!a || a < Math.abs(c)) { + a = c; + s = p / 4; + } + else { + s = (p / (2 * Math.PI)) * Math.asin(c / a); + } + if (t < 1) { + return (-0.5 * + (a * + Math.pow(2, 10 * (t -= 1)) * + Math.sin(((t * d - s) * (2 * Math.PI)) / p)) + + b); + } + return (a * + Math.pow(2, -10 * (t -= 1)) * + Math.sin(((t * d - s) * (2 * Math.PI)) / p) * + 0.5 + + c + + b); + }, + /** + * bounce ease out + * @function + * @memberof Konva.Easings + */ + BounceEaseOut(t, b, c, d) { + if ((t /= d) < 1 / 2.75) { + return c * (7.5625 * t * t) + b; + } + else if (t < 2 / 2.75) { + return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b; + } + else if (t < 2.5 / 2.75) { + return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b; + } + else { + return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b; + } + }, + /** + * bounce ease in + * @function + * @memberof Konva.Easings + */ + BounceEaseIn(t, b, c, d) { + return c - Easings.BounceEaseOut(d - t, 0, c, d) + b; + }, + /** + * bounce ease in out + * @function + * @memberof Konva.Easings + */ + BounceEaseInOut(t, b, c, d) { + if (t < d / 2) { + return Easings.BounceEaseIn(t * 2, 0, c, d) * 0.5 + b; + } + else { + return Easings.BounceEaseOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; + } + }, + /** + * ease in + * @function + * @memberof Konva.Easings + */ + EaseIn(t, b, c, d) { + return c * (t /= d) * t + b; + }, + /** + * ease out + * @function + * @memberof Konva.Easings + */ + EaseOut(t, b, c, d) { + return -c * (t /= d) * (t - 2) + b; + }, + /** + * ease in out + * @function + * @memberof Konva.Easings + */ + EaseInOut(t, b, c, d) { + if ((t /= d / 2) < 1) { + return (c / 2) * t * t + b; + } + return (-c / 2) * (--t * (t - 2) - 1) + b; + }, + /** + * strong ease in + * @function + * @memberof Konva.Easings + */ + StrongEaseIn(t, b, c, d) { + return c * (t /= d) * t * t * t * t + b; + }, + /** + * strong ease out + * @function + * @memberof Konva.Easings + */ + StrongEaseOut(t, b, c, d) { + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; + }, + /** + * strong ease in out + * @function + * @memberof Konva.Easings + */ + StrongEaseInOut(t, b, c, d) { + if ((t /= d / 2) < 1) { + return (c / 2) * t * t * t * t * t + b; + } + return (c / 2) * ((t -= 2) * t * t * t * t + 2) + b; + }, + /** + * linear + * @function + * @memberof Konva.Easings + */ + Linear(t, b, c, d) { + return (c * t) / d + b; + }, + }; + // what is core parts of Konva? const Konva$1 = Util._assign(Konva$2, { - Util, - Transform, - Node, - ids, - names, - Container, - Stage, - stages, - Layer, - FastLayer, - Group, - DD, - Shape, - shapes, - Animation, - Tween, - Easings, - Context, - Canvas, - }); - + Util, + Transform, + Node, + ids, + names, + Container, + Stage, + stages, + Layer, + FastLayer, + Group, + DD, + Shape, + shapes, + Animation, + Tween, + Easings, + Context, + Canvas, + }); + /** * Arc constructor * @constructor @@ -10274,27 +9592,26 @@ * }); */ class Arc extends Shape { - _sceneFunc(context) { - var angle = Konva$2.getAngle(this.angle()), - clockwise = this.clockwise(); - context.beginPath(); - context.arc(0, 0, this.outerRadius(), 0, angle, clockwise); - context.arc(0, 0, this.innerRadius(), angle, 0, !clockwise); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.outerRadius() * 2; - } - getHeight() { - return this.outerRadius() * 2; - } - setWidth(width) { - this.outerRadius(width / 2); - } - setHeight(height) { - this.outerRadius(height / 2); - } + _sceneFunc(context) { + var angle = Konva$2.getAngle(this.angle()), clockwise = this.clockwise(); + context.beginPath(); + context.arc(0, 0, this.outerRadius(), 0, angle, clockwise); + context.arc(0, 0, this.innerRadius(), angle, 0, !clockwise); + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + return this.outerRadius() * 2; + } + getHeight() { + return this.outerRadius() * 2; + } + setWidth(width) { + this.outerRadius(width / 2); + } + setHeight(height) { + this.outerRadius(height / 2); + } } Arc.prototype._centroid = true; Arc.prototype.className = 'Arc'; @@ -10359,8 +9676,8 @@ * * // draw arc clockwise * arc.clockwise(true); - */ - + */ + /** * Line constructor.  Lines are defined by an array of points and * a tension @@ -10385,180 +9702,134 @@ * }); */ class Line extends Shape { - constructor(config) { - super(config); - this.on( - 'pointsChange.konva tensionChange.konva closedChange.konva bezierChange.konva', - function () { - this._clearCache('tensionPoints'); - } - ); - } - _sceneFunc(context) { - var points = this.points(), - length = points.length, - tension = this.tension(), - closed = this.closed(), - bezier = this.bezier(), - tp, - len, - n; - if (!length) { - return; + constructor(config) { + super(config); + this.on('pointsChange.konva tensionChange.konva closedChange.konva bezierChange.konva', function () { + this._clearCache('tensionPoints'); + }); } - context.beginPath(); - context.moveTo(points[0], points[1]); - // tension - if (tension !== 0 && length > 4) { - tp = this.getTensionPoints(); - len = tp.length; - n = closed ? 0 : 4; - if (!closed) { - context.quadraticCurveTo(tp[0], tp[1], tp[2], tp[3]); - } - while (n < len - 2) { - context.bezierCurveTo( - tp[n++], - tp[n++], - tp[n++], - tp[n++], - tp[n++], - tp[n++] - ); - } - if (!closed) { - context.quadraticCurveTo( - tp[len - 2], - tp[len - 1], - points[length - 2], - points[length - 1] - ); - } - } else if (bezier) { - // no tension but bezier - n = 2; - while (n < length) { - context.bezierCurveTo( - points[n++], - points[n++], - points[n++], - points[n++], - points[n++], - points[n++] - ); - } - } else { - // no tension - for (n = 2; n < length; n += 2) { - context.lineTo(points[n], points[n + 1]); - } + _sceneFunc(context) { + var points = this.points(), length = points.length, tension = this.tension(), closed = this.closed(), bezier = this.bezier(), tp, len, n; + if (!length) { + return; + } + context.beginPath(); + context.moveTo(points[0], points[1]); + // tension + if (tension !== 0 && length > 4) { + tp = this.getTensionPoints(); + len = tp.length; + n = closed ? 0 : 4; + if (!closed) { + context.quadraticCurveTo(tp[0], tp[1], tp[2], tp[3]); + } + while (n < len - 2) { + context.bezierCurveTo(tp[n++], tp[n++], tp[n++], tp[n++], tp[n++], tp[n++]); + } + if (!closed) { + context.quadraticCurveTo(tp[len - 2], tp[len - 1], points[length - 2], points[length - 1]); + } + } + else if (bezier) { + // no tension but bezier + n = 2; + while (n < length) { + context.bezierCurveTo(points[n++], points[n++], points[n++], points[n++], points[n++], points[n++]); + } + } + else { + // no tension + for (n = 2; n < length; n += 2) { + context.lineTo(points[n], points[n + 1]); + } + } + // closed e.g. polygons and blobs + if (closed) { + context.closePath(); + context.fillStrokeShape(this); + } + else { + // open e.g. lines and splines + context.strokeShape(this); + } } - // closed e.g. polygons and blobs - if (closed) { - context.closePath(); - context.fillStrokeShape(this); - } else { - // open e.g. lines and splines - context.strokeShape(this); + getTensionPoints() { + return this._getCache('tensionPoints', this._getTensionPoints); } - } - getTensionPoints() { - return this._getCache('tensionPoints', this._getTensionPoints); - } - _getTensionPoints() { - if (this.closed()) { - return this._getTensionPointsClosed(); - } else { - return Util._expandPoints(this.points(), this.tension()); + _getTensionPoints() { + if (this.closed()) { + return this._getTensionPointsClosed(); + } + else { + return Util._expandPoints(this.points(), this.tension()); + } } - } - _getTensionPointsClosed() { - var p = this.points(), - len = p.length, - tension = this.tension(), - firstControlPoints = Util._getControlPoints( - p[len - 2], - p[len - 1], - p[0], - p[1], - p[2], - p[3], - tension - ), - lastControlPoints = Util._getControlPoints( - p[len - 4], - p[len - 3], - p[len - 2], - p[len - 1], - p[0], - p[1], - tension - ), - middle = Util._expandPoints(p, tension), - tp = [firstControlPoints[2], firstControlPoints[3]] - .concat(middle) - .concat([ - lastControlPoints[0], - lastControlPoints[1], - p[len - 2], - p[len - 1], - lastControlPoints[2], - lastControlPoints[3], - firstControlPoints[0], - firstControlPoints[1], - p[0], - p[1], + _getTensionPointsClosed() { + var p = this.points(), len = p.length, tension = this.tension(), firstControlPoints = Util._getControlPoints(p[len - 2], p[len - 1], p[0], p[1], p[2], p[3], tension), lastControlPoints = Util._getControlPoints(p[len - 4], p[len - 3], p[len - 2], p[len - 1], p[0], p[1], tension), middle = Util._expandPoints(p, tension), tp = [firstControlPoints[2], firstControlPoints[3]] + .concat(middle) + .concat([ + lastControlPoints[0], + lastControlPoints[1], + p[len - 2], + p[len - 1], + lastControlPoints[2], + lastControlPoints[3], + firstControlPoints[0], + firstControlPoints[1], + p[0], + p[1], ]); - return tp; - } - getWidth() { - return this.getSelfRect().width; - } - getHeight() { - return this.getSelfRect().height; - } - // overload size detection - getSelfRect() { - var points = this.points(); - if (points.length < 4) { - return { - x: points[0] || 0, - y: points[1] || 0, - width: 0, - height: 0, - }; + return tp; } - if (this.tension() !== 0) { - points = [ - points[0], - points[1], - ...this._getTensionPoints(), - points[points.length - 2], - points[points.length - 1], - ]; - } else { - points = this.points(); + getWidth() { + return this.getSelfRect().width; } - var minX = points[0]; - var maxX = points[0]; - var minY = points[1]; - var maxY = points[1]; - var x, y; - for (var i = 0; i < points.length / 2; i++) { - x = points[i * 2]; - y = points[i * 2 + 1]; - minX = Math.min(minX, x); - maxX = Math.max(maxX, x); - minY = Math.min(minY, y); - maxY = Math.max(maxY, y); + getHeight() { + return this.getSelfRect().height; + } + // overload size detection + getSelfRect() { + var points = this.points(); + if (points.length < 4) { + return { + x: points[0] || 0, + y: points[1] || 0, + width: 0, + height: 0, + }; + } + if (this.tension() !== 0) { + points = [ + points[0], + points[1], + ...this._getTensionPoints(), + points[points.length - 2], + points[points.length - 1], + ]; + } + else { + points = this.points(); + } + var minX = points[0]; + var maxX = points[0]; + var minY = points[1]; + var maxY = points[1]; + var x, y; + for (var i = 0; i < points.length / 2; i++) { + x = points[i * 2]; + y = points[i * 2 + 1]; + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + } + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY, + }; } - return { - x: minX, - y: minY, - width: maxX - minX, - height: maxY - minY, - }; - } } Line.prototype.className = 'Line'; Line.prototype._attrsAffectingSize = ['points', 'bezier', 'tension']; @@ -10625,8 +9896,8 @@ * * // push a new point * line.points(line.points().concat([70, 80])); - */ - + */ + /** * Arrow constructor * @constructor @@ -10638,7 +9909,8 @@ * The default is 0 * @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 {Boolean} config.pointerAtBeginning Do we need to draw pointer on beginning position?. Default false. + * @param {Boolean} config.pointerAtEnding Do we need to draw pointer on ending position?. Default true. * @@shapeParams * @@nodeParams * @example @@ -10651,79 +9923,83 @@ * }); */ class Arrow extends Line { - _sceneFunc(ctx) { - super._sceneFunc(ctx); - var PI2 = Math.PI * 2; - var points = this.points(); - var tp = points; - var fromTension = this.tension() !== 0 && points.length > 4; - if (fromTension) { - tp = this.getTensionPoints(); + _sceneFunc(ctx) { + super._sceneFunc(ctx); + var PI2 = Math.PI * 2; + var points = this.points(); + var tp = points; + var fromTension = this.tension() !== 0 && points.length > 4; + if (fromTension) { + tp = this.getTensionPoints(); + } + var n = points.length; + var dx, dy; + if (fromTension) { + dx = points[n - 2] - (tp[tp.length - 2] + tp[tp.length - 4]) / 2; + dy = points[n - 1] - (tp[tp.length - 1] + tp[tp.length - 3]) / 2; + } + else { + dx = points[n - 2] - points[n - 4]; + dy = points[n - 1] - points[n - 3]; + } + var radians = (Math.atan2(dy, dx) + PI2) % PI2; + var length = this.pointerLength(); + var width = this.pointerWidth(); + if (this.pointerAtEnding()) { + ctx.save(); + ctx.beginPath(); + ctx.translate(points[n - 2], points[n - 1]); + ctx.rotate(radians); + ctx.moveTo(0, 0); + ctx.lineTo(-length, width / 2); + ctx.lineTo(-length, -width / 2); + ctx.closePath(); + ctx.restore(); + } + if (this.pointerAtBeginning()) { + ctx.save(); + ctx.translate(points[0], points[1]); + if (fromTension) { + dx = (tp[0] + tp[2]) / 2 - points[0]; + dy = (tp[1] + tp[3]) / 2 - points[1]; + } + else { + dx = points[2] - points[0]; + dy = points[3] - points[1]; + } + ctx.rotate((Math.atan2(-dy, -dx) + PI2) % PI2); + ctx.moveTo(0, 0); + ctx.lineTo(-length, width / 2); + ctx.lineTo(-length, -width / 2); + ctx.closePath(); + ctx.restore(); + } + // here is a tricky part + // we need to disable dash for arrow pointers + var isDashEnabled = this.dashEnabled(); + if (isDashEnabled) { + // manually disable dash for head + // it is better not to use setter here, + // because it will trigger attr change event + this.attrs.dashEnabled = false; + ctx.setLineDash([]); + } + ctx.fillStrokeShape(this); + // restore old value + if (isDashEnabled) { + this.attrs.dashEnabled = true; + } } - var n = points.length; - var dx, dy; - if (fromTension) { - dx = points[n - 2] - (tp[tp.length - 2] + tp[tp.length - 4]) / 2; - dy = points[n - 1] - (tp[tp.length - 1] + tp[tp.length - 3]) / 2; - } else { - dx = points[n - 2] - points[n - 4]; - dy = points[n - 1] - points[n - 3]; + getSelfRect() { + const lineRect = super.getSelfRect(); + const offset = this.pointerWidth() / 2; + return { + x: lineRect.x - offset, + y: lineRect.y - offset, + width: lineRect.width + offset * 2, + height: lineRect.height + offset * 2, + }; } - var radians = (Math.atan2(dy, dx) + PI2) % PI2; - var length = this.pointerLength(); - var width = this.pointerWidth(); - ctx.save(); - ctx.beginPath(); - ctx.translate(points[n - 2], points[n - 1]); - ctx.rotate(radians); - ctx.moveTo(0, 0); - ctx.lineTo(-length, width / 2); - ctx.lineTo(-length, -width / 2); - ctx.closePath(); - ctx.restore(); - if (this.pointerAtBeginning()) { - ctx.save(); - ctx.translate(points[0], points[1]); - if (fromTension) { - dx = (tp[0] + tp[2]) / 2 - points[0]; - dy = (tp[1] + tp[3]) / 2 - points[1]; - } else { - dx = points[2] - points[0]; - dy = points[3] - points[1]; - } - ctx.rotate((Math.atan2(-dy, -dx) + PI2) % PI2); - ctx.moveTo(0, 0); - ctx.lineTo(-length, width / 2); - ctx.lineTo(-length, -width / 2); - ctx.closePath(); - ctx.restore(); - } - // here is a tricky part - // we need to disable dash for arrow pointers - var isDashEnabled = this.dashEnabled(); - if (isDashEnabled) { - // manually disable dash for head - // it is better not to use setter here, - // because it will trigger attr change event - this.attrs.dashEnabled = false; - ctx.setLineDash([]); - } - ctx.fillStrokeShape(this); - // restore old value - if (isDashEnabled) { - this.attrs.dashEnabled = true; - } - } - getSelfRect() { - const lineRect = super.getSelfRect(); - const offset = this.pointerWidth() / 2; - return { - x: lineRect.x - offset, - y: lineRect.y - offset, - width: lineRect.width + offset * 2, - height: lineRect.height + offset * 2, - }; - } } Arrow.prototype.className = 'Arrow'; _registerNode(Arrow); @@ -10770,7 +10046,21 @@ * line.pointerAtBeginning(true); */ Factory.addGetterSetter(Arrow, 'pointerAtBeginning', false); - + /** + * get/set pointerAtEnding + * @name Konva.Arrow#pointerAtEnding + * @method + * @param {Number} Should pointer displayed at ending of arrow. The default is true. + * @returns {Boolean} + * @example + * // get value + * var pointerAtEnding = line.pointerAtEnding(); + * + * // set value + * line.pointerAtEnding(false); + */ + Factory.addGetterSetter(Arrow, 'pointerAtEnding', true); + /** * Circle constructor * @constructor @@ -10790,28 +10080,28 @@ * }); */ class Circle extends Shape { - _sceneFunc(context) { - context.beginPath(); - context.arc(0, 0, this.attrs.radius || 0, 0, Math.PI * 2, false); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.radius() * 2; - } - getHeight() { - return this.radius() * 2; - } - setWidth(width) { - if (this.radius() !== width / 2) { - this.radius(width / 2); + _sceneFunc(context) { + context.beginPath(); + context.arc(0, 0, this.attrs.radius || 0, 0, Math.PI * 2, false); + context.closePath(); + context.fillStrokeShape(this); } - } - setHeight(height) { - if (this.radius() !== height / 2) { - this.radius(height / 2); + getWidth() { + return this.radius() * 2; + } + getHeight() { + return this.radius() * 2; + } + setWidth(width) { + if (this.radius() !== width / 2) { + this.radius(width / 2); + } + } + setHeight(height) { + if (this.radius() !== height / 2) { + this.radius(height / 2); + } } - } } Circle.prototype._centroid = true; Circle.prototype.className = 'Circle'; @@ -10830,8 +10120,8 @@ * // set radius * circle.radius(10); */ - Factory.addGetterSetter(Circle, 'radius', 0, getNumberValidator()); - + Factory.addGetterSetter(Circle, 'radius', 0, getNumberValidator()); + /** * Ellipse constructor * @constructor @@ -10851,31 +10141,30 @@ * }); */ class Ellipse extends Shape { - _sceneFunc(context) { - var rx = this.radiusX(), - ry = this.radiusY(); - context.beginPath(); - context.save(); - if (rx !== ry) { - context.scale(1, ry / rx); + _sceneFunc(context) { + var rx = this.radiusX(), ry = this.radiusY(); + context.beginPath(); + context.save(); + if (rx !== ry) { + context.scale(1, ry / rx); + } + context.arc(0, 0, rx, 0, Math.PI * 2, false); + context.restore(); + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + return this.radiusX() * 2; + } + getHeight() { + return this.radiusY() * 2; + } + setWidth(width) { + this.radiusX(width / 2); + } + setHeight(height) { + this.radiusY(height / 2); } - context.arc(0, 0, rx, 0, Math.PI * 2, false); - context.restore(); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.radiusX() * 2; - } - getHeight() { - return this.radiusY() * 2; - } - setWidth(width) { - this.radiusX(width / 2); - } - setHeight(height) { - this.radiusY(height / 2); - } } Ellipse.prototype.className = 'Ellipse'; Ellipse.prototype._centroid = true; @@ -10928,8 +10217,8 @@ * * // set radius y * ellipse.radiusY(200); - */ - + */ + /** * Image constructor * @constructor @@ -10954,91 +10243,98 @@ * imageObj.src = '/path/to/image.jpg' */ class Image extends Shape { - _useBufferCanvas() { - return super._useBufferCanvas(true); - } - _sceneFunc(context) { - const width = this.getWidth(); - const height = this.getHeight(); - const image = this.attrs.image; - let params; - if (image) { - const cropWidth = this.attrs.cropWidth; - const cropHeight = this.attrs.cropHeight; - if (cropWidth && cropHeight) { - params = [ - image, - this.cropX(), - this.cropY(), - cropWidth, - cropHeight, - 0, - 0, - width, - height, - ]; - } else { - params = [image, 0, 0, width, height]; - } + constructor(attrs) { + super(attrs); + this.on('imageChange.konva', () => { + this._setImageLoad(); + }); + this._setImageLoad(); } - if (this.hasFill() || this.hasStroke()) { - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - context.fillStrokeShape(this); + _setImageLoad() { + const image = this.image(); + if (image && image['addEventListener']) { + image['addEventListener']('load', () => { + this._requestDraw(); + }); + } } - if (image) { - context.drawImage.apply(context, params); + _useBufferCanvas() { + return super._useBufferCanvas(true); + } + _sceneFunc(context) { + const width = this.getWidth(); + const height = this.getHeight(); + const image = this.attrs.image; + let params; + if (image) { + const cropWidth = this.attrs.cropWidth; + const cropHeight = this.attrs.cropHeight; + if (cropWidth && cropHeight) { + params = [ + image, + this.cropX(), + this.cropY(), + cropWidth, + cropHeight, + 0, + 0, + width, + height, + ]; + } + else { + params = [image, 0, 0, width, height]; + } + } + if (this.hasFill() || this.hasStroke()) { + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + context.fillStrokeShape(this); + } + if (image) { + context.drawImage.apply(context, params); + } + } + _hitFunc(context) { + var width = this.width(), height = this.height(); + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + var _a, _b; + return (_a = this.attrs.width) !== null && _a !== void 0 ? _a : (_b = this.image()) === null || _b === void 0 ? void 0 : _b.width; + } + getHeight() { + var _a, _b; + return (_a = this.attrs.height) !== null && _a !== void 0 ? _a : (_b = this.image()) === null || _b === void 0 ? void 0 : _b.height; + } + /** + * load image from given url and create `Konva.Image` instance + * @method + * @memberof Konva.Image + * @param {String} url image source + * @param {Function} callback with Konva.Image instance as first argument + * @example + * Konva.Image.fromURL(imageURL, function(image){ + * // image is Konva.Image instance + * layer.add(image); + * layer.draw(); + * }); + */ + static fromURL(url, callback) { + var img = Util.createImageElement(); + img.onload = function () { + var image = new Image({ + image: img, + }); + callback(image); + }; + img.crossOrigin = 'Anonymous'; + img.src = url; } - } - _hitFunc(context) { - var width = this.width(), - height = this.height(); - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - var _a, _b; - return (_a = this.attrs.width) !== null && _a !== void 0 - ? _a - : (_b = this.image()) === null || _b === void 0 - ? void 0 - : _b.width; - } - getHeight() { - var _a, _b; - return (_a = this.attrs.height) !== null && _a !== void 0 - ? _a - : (_b = this.image()) === null || _b === void 0 - ? void 0 - : _b.height; - } - /** - * load image from given url and create `Konva.Image` instance - * @method - * @memberof Konva.Image - * @param {String} url image source - * @param {Function} callback with Konva.Image instance as first argument - * @example - * Konva.Image.fromURL(imageURL, function(image){ - * // image is Konva.Image instance - * layer.add(image); - * layer.draw(); - * }); - */ - static fromURL(url, callback) { - var img = Util.createImageElement(); - img.onload = function () { - var image = new Image({ - image: img, - }); - callback(image); - }; - img.crossOrigin = 'Anonymous'; - img.src = url; - } } Image.prototype.className = 'Image'; _registerNode(Image); @@ -11056,12 +10352,7 @@ * shape.image(img); */ Factory.addGetterSetter(Image, 'image'); - Factory.addComponentsGetterSetter(Image, 'crop', [ - 'x', - 'y', - 'width', - 'height', - ]); + Factory.addComponentsGetterSetter(Image, 'crop', ['x', 'y', 'width', 'height']); /** * get/set crop * @method @@ -11139,8 +10430,8 @@ * * // set crop height * image.cropHeight(20); - */ - + */ + // constants var ATTR_CHANGE_LIST$2 = [ 'fontFamily', @@ -11151,15 +10442,9 @@ 'text', 'width', 'height', - ], - CHANGE_KONVA$1 = 'Change.konva', - NONE$1 = 'none', - UP = 'up', - RIGHT$1 = 'right', - DOWN = 'down', - LEFT$1 = 'left', - // cached variables - attrChangeListLen$1 = ATTR_CHANGE_LIST$2.length; + ], CHANGE_KONVA$1 = 'Change.konva', NONE$1 = 'none', UP = 'up', RIGHT$1 = 'right', DOWN = 'down', LEFT$1 = 'left', + // cached variables + attrChangeListLen$1 = ATTR_CHANGE_LIST$2.length; /** * Label constructor.  Labels are groups that contain a Text and Tag shape * @constructor @@ -11199,98 +10484,89 @@ * })); */ class Label extends Group { - constructor(config) { - super(config); - this.on('add.konva', function (evt) { - this._addListeners(evt.child); - this._sync(); - }); - } - /** - * get Text shape for the label. You need to access the Text shape in order to update - * the text properties - * @name Konva.Label#getText - * @method - * @example - * label.getText().fill('red') - */ - getText() { - return this.find('Text')[0]; - } - /** - * get Tag shape for the label. You need to access the Tag shape in order to update - * the pointer properties and the corner radius - * @name Konva.Label#getTag - * @method - */ - getTag() { - return this.find('Tag')[0]; - } - _addListeners(text) { - var that = this, - n; - var func = function () { - that._sync(); - }; - // update text data for certain attr changes - for (n = 0; n < attrChangeListLen$1; n++) { - text.on(ATTR_CHANGE_LIST$2[n] + CHANGE_KONVA$1, func); + constructor(config) { + super(config); + this.on('add.konva', function (evt) { + this._addListeners(evt.child); + this._sync(); + }); } - } - getWidth() { - return this.getText().width(); - } - getHeight() { - return this.getText().height(); - } - _sync() { - var text = this.getText(), - tag = this.getTag(), - width, - height, - pointerDirection, - pointerWidth, - x, - y, - pointerHeight; - if (text && tag) { - width = text.width(); - height = text.height(); - pointerDirection = tag.pointerDirection(); - pointerWidth = tag.pointerWidth(); - pointerHeight = tag.pointerHeight(); - x = 0; - y = 0; - switch (pointerDirection) { - case UP: - x = width / 2; - y = -1 * pointerHeight; - break; - case RIGHT$1: - x = width + pointerWidth; - y = height / 2; - break; - case DOWN: - x = width / 2; - y = height + pointerHeight; - break; - case LEFT$1: - x = -1 * pointerWidth; - y = height / 2; - break; - } - tag.setAttrs({ - x: -1 * x, - y: -1 * y, - width: width, - height: height, - }); - text.setAttrs({ - x: -1 * x, - y: -1 * y, - }); + /** + * get Text shape for the label. You need to access the Text shape in order to update + * the text properties + * @name Konva.Label#getText + * @method + * @example + * label.getText().fill('red') + */ + getText() { + return this.find('Text')[0]; + } + /** + * get Tag shape for the label. You need to access the Tag shape in order to update + * the pointer properties and the corner radius + * @name Konva.Label#getTag + * @method + */ + getTag() { + return this.find('Tag')[0]; + } + _addListeners(text) { + var that = this, n; + var func = function () { + that._sync(); + }; + // update text data for certain attr changes + for (n = 0; n < attrChangeListLen$1; n++) { + text.on(ATTR_CHANGE_LIST$2[n] + CHANGE_KONVA$1, func); + } + } + getWidth() { + return this.getText().width(); + } + getHeight() { + return this.getText().height(); + } + _sync() { + var text = this.getText(), tag = this.getTag(), width, height, pointerDirection, pointerWidth, x, y, pointerHeight; + if (text && tag) { + width = text.width(); + height = text.height(); + pointerDirection = tag.pointerDirection(); + pointerWidth = tag.pointerWidth(); + pointerHeight = tag.pointerHeight(); + x = 0; + y = 0; + switch (pointerDirection) { + case UP: + x = width / 2; + y = -1 * pointerHeight; + break; + case RIGHT$1: + x = width + pointerWidth; + y = height / 2; + break; + case DOWN: + x = width / 2; + y = height + pointerHeight; + break; + case LEFT$1: + x = -1 * pointerWidth; + y = height / 2; + break; + } + tag.setAttrs({ + x: -1 * x, + y: -1 * y, + width: width, + height: height, + }); + text.setAttrs({ + x: -1 * x, + y: -1 * y, + }); + } } - } } Label.prototype.className = 'Label'; _registerNode(Label); @@ -11307,110 +10583,78 @@ * @param {Number} [config.cornerRadius] */ class Tag extends Shape { - _sceneFunc(context) { - var width = this.width(), - height = this.height(), - pointerDirection = this.pointerDirection(), - pointerWidth = this.pointerWidth(), - pointerHeight = this.pointerHeight(), - cornerRadius = this.cornerRadius(); - let topLeft = 0; - let topRight = 0; - let bottomLeft = 0; - let bottomRight = 0; - if (typeof cornerRadius === 'number') { - topLeft = topRight = bottomLeft = bottomRight = Math.min( - cornerRadius, - width / 2, - height / 2 - ); - } else { - topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); - topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); - bottomRight = Math.min(cornerRadius[2] || 0, width / 2, height / 2); - bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); + _sceneFunc(context) { + var width = this.width(), height = this.height(), pointerDirection = this.pointerDirection(), pointerWidth = this.pointerWidth(), pointerHeight = this.pointerHeight(), cornerRadius = this.cornerRadius(); + let topLeft = 0; + let topRight = 0; + let bottomLeft = 0; + let bottomRight = 0; + if (typeof cornerRadius === 'number') { + topLeft = topRight = bottomLeft = bottomRight = Math.min(cornerRadius, width / 2, height / 2); + } + else { + topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); + topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); + bottomRight = Math.min(cornerRadius[2] || 0, width / 2, height / 2); + bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); + } + context.beginPath(); + context.moveTo(topLeft, 0); + if (pointerDirection === UP) { + context.lineTo((width - pointerWidth) / 2, 0); + context.lineTo(width / 2, -1 * pointerHeight); + context.lineTo((width + pointerWidth) / 2, 0); + } + context.lineTo(width - topRight, 0); + context.arc(width - topRight, topRight, topRight, (Math.PI * 3) / 2, 0, false); + if (pointerDirection === RIGHT$1) { + context.lineTo(width, (height - pointerHeight) / 2); + context.lineTo(width + pointerWidth, height / 2); + context.lineTo(width, (height + pointerHeight) / 2); + } + context.lineTo(width, height - bottomRight); + context.arc(width - bottomRight, height - bottomRight, bottomRight, 0, Math.PI / 2, false); + if (pointerDirection === DOWN) { + context.lineTo((width + pointerWidth) / 2, height); + context.lineTo(width / 2, height + pointerHeight); + context.lineTo((width - pointerWidth) / 2, height); + } + context.lineTo(bottomLeft, height); + context.arc(bottomLeft, height - bottomLeft, bottomLeft, Math.PI / 2, Math.PI, false); + if (pointerDirection === LEFT$1) { + context.lineTo(0, (height + pointerHeight) / 2); + context.lineTo(-1 * pointerWidth, height / 2); + context.lineTo(0, (height - pointerHeight) / 2); + } + context.lineTo(0, topLeft); + context.arc(topLeft, topLeft, topLeft, Math.PI, (Math.PI * 3) / 2, false); + context.closePath(); + context.fillStrokeShape(this); } - context.beginPath(); - context.moveTo(topLeft, 0); - if (pointerDirection === UP) { - context.lineTo((width - pointerWidth) / 2, 0); - context.lineTo(width / 2, -1 * pointerHeight); - context.lineTo((width + pointerWidth) / 2, 0); + getSelfRect() { + var x = 0, y = 0, pointerWidth = this.pointerWidth(), pointerHeight = this.pointerHeight(), direction = this.pointerDirection(), width = this.width(), height = this.height(); + if (direction === UP) { + y -= pointerHeight; + height += pointerHeight; + } + else if (direction === DOWN) { + height += pointerHeight; + } + else if (direction === LEFT$1) { + // ARGH!!! I have no idea why should I used magic 1.5!!!!!!!!! + x -= pointerWidth * 1.5; + width += pointerWidth; + } + else if (direction === RIGHT$1) { + width += pointerWidth * 1.5; + } + return { + x: x, + y: y, + width: width, + height: height, + }; } - context.lineTo(width - topRight, 0); - context.arc( - width - topRight, - topRight, - topRight, - (Math.PI * 3) / 2, - 0, - false - ); - if (pointerDirection === RIGHT$1) { - context.lineTo(width, (height - pointerHeight) / 2); - context.lineTo(width + pointerWidth, height / 2); - context.lineTo(width, (height + pointerHeight) / 2); - } - context.lineTo(width, height - bottomRight); - context.arc( - width - bottomRight, - height - bottomRight, - bottomRight, - 0, - Math.PI / 2, - false - ); - if (pointerDirection === DOWN) { - context.lineTo((width + pointerWidth) / 2, height); - context.lineTo(width / 2, height + pointerHeight); - context.lineTo((width - pointerWidth) / 2, height); - } - context.lineTo(bottomLeft, height); - context.arc( - bottomLeft, - height - bottomLeft, - bottomLeft, - Math.PI / 2, - Math.PI, - false - ); - if (pointerDirection === LEFT$1) { - context.lineTo(0, (height + pointerHeight) / 2); - context.lineTo(-1 * pointerWidth, height / 2); - context.lineTo(0, (height - pointerHeight) / 2); - } - context.lineTo(0, topLeft); - context.arc(topLeft, topLeft, topLeft, Math.PI, (Math.PI * 3) / 2, false); - context.closePath(); - context.fillStrokeShape(this); - } - getSelfRect() { - var x = 0, - y = 0, - pointerWidth = this.pointerWidth(), - pointerHeight = this.pointerHeight(), - direction = this.pointerDirection(), - width = this.width(), - height = this.height(); - if (direction === UP) { - y -= pointerHeight; - height += pointerHeight; - } else if (direction === DOWN) { - height += pointerHeight; - } else if (direction === LEFT$1) { - // ARGH!!! I have no idea why should I used magic 1.5!!!!!!!!! - x -= pointerWidth * 1.5; - width += pointerWidth; - } else if (direction === RIGHT$1) { - width += pointerWidth * 1.5; - } - return { - x: x, - y: y, - width: width, - height: height, - }; - } } Tag.prototype.className = 'Tag'; _registerNode(Tag); @@ -11457,13 +10701,8 @@ * // top-left, top-right, bottom-right, bottom-left * tag.cornerRadius([0, 10, 20, 30]); */ - Factory.addGetterSetter( - Tag, - 'cornerRadius', - 0, - getNumberOrArrayOfNumbersValidator(4) - ); - + Factory.addGetterSetter(Tag, 'cornerRadius', 0, getNumberOrArrayOfNumbersValidator(4)); + /** * Path constructor. * @author Jason Follas @@ -11485,870 +10724,710 @@ * }); */ class Path extends Shape { - constructor(config) { - super(config); - this.dataArray = []; - this.pathLength = 0; - this.dataArray = Path.parsePathData(this.data()); - this.pathLength = 0; - for (var i = 0; i < this.dataArray.length; ++i) { - this.pathLength += this.dataArray[i].pathLength; - } - this.on('dataChange.konva', function () { - this.dataArray = Path.parsePathData(this.data()); - this.pathLength = 0; - for (var i = 0; i < this.dataArray.length; ++i) { - this.pathLength += this.dataArray[i].pathLength; - } - }); - } - _sceneFunc(context) { - var ca = this.dataArray; - // context position - context.beginPath(); - var isClosed = false; - for (var n = 0; n < ca.length; n++) { - var c = ca[n].command; - var p = ca[n].points; - switch (c) { - case 'L': - context.lineTo(p[0], p[1]); - break; - case 'M': - context.moveTo(p[0], p[1]); - break; - case 'C': - context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]); - break; - case 'Q': - context.quadraticCurveTo(p[0], p[1], p[2], p[3]); - break; - case 'A': - var cx = p[0], - cy = p[1], - rx = p[2], - ry = p[3], - theta = p[4], - dTheta = p[5], - psi = p[6], - fs = p[7]; - var r = rx > ry ? rx : ry; - var scaleX = rx > ry ? 1 : rx / ry; - var scaleY = rx > ry ? ry / rx : 1; - context.translate(cx, cy); - context.rotate(psi); - context.scale(scaleX, scaleY); - context.arc(0, 0, r, theta, theta + dTheta, 1 - fs); - context.scale(1 / scaleX, 1 / scaleY); - context.rotate(-psi); - context.translate(-cx, -cy); - break; - case 'z': - isClosed = true; - context.closePath(); - break; - } - } - if (!isClosed && !this.hasFill()) { - context.strokeShape(this); - } else { - context.fillStrokeShape(this); - } - } - getSelfRect() { - var points = []; - this.dataArray.forEach(function (data) { - if (data.command === 'A') { - // Approximates by breaking curve into line segments - var start = data.points[4]; - // 4 = theta - var dTheta = data.points[5]; - // 5 = dTheta - var end = data.points[4] + dTheta; - var inc = Math.PI / 180.0; - // 1 degree resolution - if (Math.abs(start - end) < inc) { - inc = Math.abs(start - end); + constructor(config) { + super(config); + this.dataArray = []; + this.pathLength = 0; + this.dataArray = Path.parsePathData(this.data()); + this.pathLength = 0; + for (var i = 0; i < this.dataArray.length; ++i) { + this.pathLength += this.dataArray[i].pathLength; } - if (dTheta < 0) { - // clockwise - for (let t = start - inc; t > end; t -= inc) { - const point = Path.getPointOnEllipticalArc( - data.points[0], - data.points[1], - data.points[2], - data.points[3], - t, - 0 - ); - points.push(point.x, point.y); - } - } else { - // counter-clockwise - for (let t = start + inc; t < end; t += inc) { - const point = Path.getPointOnEllipticalArc( - data.points[0], - data.points[1], - data.points[2], - data.points[3], - t, - 0 - ); - points.push(point.x, point.y); - } + this.on('dataChange.konva', function () { + this.dataArray = Path.parsePathData(this.data()); + this.pathLength = 0; + for (var i = 0; i < this.dataArray.length; ++i) { + this.pathLength += this.dataArray[i].pathLength; + } + }); + } + _sceneFunc(context) { + var ca = this.dataArray; + // context position + context.beginPath(); + var isClosed = false; + for (var n = 0; n < ca.length; n++) { + var c = ca[n].command; + var p = ca[n].points; + switch (c) { + case 'L': + context.lineTo(p[0], p[1]); + break; + case 'M': + context.moveTo(p[0], p[1]); + break; + case 'C': + context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]); + break; + case 'Q': + context.quadraticCurveTo(p[0], p[1], p[2], p[3]); + break; + case 'A': + var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6], fs = p[7]; + var r = rx > ry ? rx : ry; + var scaleX = rx > ry ? 1 : rx / ry; + var scaleY = rx > ry ? ry / rx : 1; + context.translate(cx, cy); + context.rotate(psi); + context.scale(scaleX, scaleY); + context.arc(0, 0, r, theta, theta + dTheta, 1 - fs); + context.scale(1 / scaleX, 1 / scaleY); + context.rotate(-psi); + context.translate(-cx, -cy); + break; + case 'z': + isClosed = true; + context.closePath(); + break; + } } - } else if (data.command === 'C') { - // Approximates by breaking curve into 100 line segments - for (let t = 0.0; t <= 1; t += 0.01) { - const point = Path.getPointOnCubicBezier( - t, - data.start.x, - data.start.y, - data.points[0], - data.points[1], - data.points[2], - data.points[3], - data.points[4], - data.points[5] - ); - points.push(point.x, point.y); + if (!isClosed && !this.hasFill()) { + context.strokeShape(this); } - } else { - // TODO: how can we calculate bezier curves better? - points = points.concat(data.points); - } - }); - var minX = points[0]; - var maxX = points[0]; - var minY = points[1]; - var maxY = points[1]; - var x, y; - for (var i = 0; i < points.length / 2; i++) { - x = points[i * 2]; - y = points[i * 2 + 1]; - // skip bad values - if (!isNaN(x)) { - minX = Math.min(minX, x); - maxX = Math.max(maxX, x); - } - if (!isNaN(y)) { - minY = Math.min(minY, y); - maxY = Math.max(maxY, y); - } - } - return { - x: Math.round(minX), - y: Math.round(minY), - width: Math.round(maxX - minX), - height: Math.round(maxY - minY), - }; - } - /** - * Return length of the path. - * @method - * @name Konva.Path#getLength - * @returns {Number} length - * @example - * var length = path.getLength(); - */ - getLength() { - return this.pathLength; - } - /** - * Get point on path at specific length of the path - * @method - * @name Konva.Path#getPointAtLength - * @param {Number} length length - * @returns {Object} point {x,y} point - * @example - * var point = path.getPointAtLength(10); - */ - getPointAtLength(length) { - var point, - i = 0, - ii = this.dataArray.length; - if (!ii) { - return null; - } - while (i < ii && length > this.dataArray[i].pathLength) { - length -= this.dataArray[i].pathLength; - ++i; - } - if (i === ii) { - point = this.dataArray[i - 1].points.slice(-2); - return { - x: point[0], - y: point[1], - }; - } - if (length < 0.01) { - point = this.dataArray[i].points.slice(0, 2); - return { - x: point[0], - y: point[1], - }; - } - var cp = this.dataArray[i]; - var p = cp.points; - switch (cp.command) { - case 'L': - return Path.getPointOnLine( - length, - cp.start.x, - cp.start.y, - p[0], - p[1] - ); - case 'C': - return Path.getPointOnCubicBezier( - length / cp.pathLength, - cp.start.x, - cp.start.y, - p[0], - p[1], - p[2], - p[3], - p[4], - p[5] - ); - case 'Q': - return Path.getPointOnQuadraticBezier( - length / cp.pathLength, - cp.start.x, - cp.start.y, - p[0], - p[1], - p[2], - p[3] - ); - case 'A': - var cx = p[0], - cy = p[1], - rx = p[2], - ry = p[3], - theta = p[4], - dTheta = p[5], - psi = p[6]; - theta += (dTheta * length) / cp.pathLength; - return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi); - } - return null; - } - static getLineLength(x1, y1, x2, y2) { - return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - } - static getPointOnLine(dist, P1x, P1y, P2x, P2y, fromX, fromY) { - if (fromX === undefined) { - fromX = P1x; - } - if (fromY === undefined) { - fromY = P1y; - } - var m = (P2y - P1y) / (P2x - P1x + 0.00000001); - var run = Math.sqrt((dist * dist) / (1 + m * m)); - if (P2x < P1x) { - run *= -1; - } - var rise = m * run; - var pt; - if (P2x === P1x) { - // vertical line - pt = { - x: fromX, - y: fromY + rise, - }; - } else if ((fromY - P1y) / (fromX - P1x + 0.00000001) === m) { - pt = { - x: fromX + run, - y: fromY + rise, - }; - } else { - var ix, iy; - var len = this.getLineLength(P1x, P1y, P2x, P2y); - // if (len < 0.00000001) { - // return { - // x: P1x, - // y: P1y, - // }; - // } - var u = (fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y); - u = u / (len * len); - ix = P1x + u * (P2x - P1x); - iy = P1y + u * (P2y - P1y); - var pRise = this.getLineLength(fromX, fromY, ix, iy); - var pRun = Math.sqrt(dist * dist - pRise * pRise); - run = Math.sqrt((pRun * pRun) / (1 + m * m)); - if (P2x < P1x) { - run *= -1; - } - rise = m * run; - pt = { - x: ix + run, - y: iy + rise, - }; - } - return pt; - } - static getPointOnCubicBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) { - function CB1(t) { - return t * t * t; - } - function CB2(t) { - return 3 * t * t * (1 - t); - } - function CB3(t) { - return 3 * t * (1 - t) * (1 - t); - } - function CB4(t) { - return (1 - t) * (1 - t) * (1 - t); - } - var x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct); - var y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct); - return { - x: x, - y: y, - }; - } - static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) { - function QB1(t) { - return t * t; - } - function QB2(t) { - return 2 * t * (1 - t); - } - function QB3(t) { - return (1 - t) * (1 - t); - } - var x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct); - var y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct); - return { - x: x, - y: y, - }; - } - static getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) { - var cosPsi = Math.cos(psi), - sinPsi = Math.sin(psi); - var pt = { - x: rx * Math.cos(theta), - y: ry * Math.sin(theta), - }; - return { - x: cx + (pt.x * cosPsi - pt.y * sinPsi), - y: cy + (pt.x * sinPsi + pt.y * cosPsi), - }; - } - /* - * get parsed data array from the data - * string. V, v, H, h, and l data are converted to - * L data for the purpose of high performance Path - * rendering - */ - static parsePathData(data) { - // Path Data Segment must begin with a moveTo - //m (x y)+ Relative moveTo (subsequent points are treated as lineTo) - //M (x y)+ Absolute moveTo (subsequent points are treated as lineTo) - //l (x y)+ Relative lineTo - //L (x y)+ Absolute LineTo - //h (x)+ Relative horizontal lineTo - //H (x)+ Absolute horizontal lineTo - //v (y)+ Relative vertical lineTo - //V (y)+ Absolute vertical lineTo - //z (closepath) - //Z (closepath) - //c (x1 y1 x2 y2 x y)+ Relative Bezier curve - //C (x1 y1 x2 y2 x y)+ Absolute Bezier curve - //q (x1 y1 x y)+ Relative Quadratic Bezier - //Q (x1 y1 x y)+ Absolute Quadratic Bezier - //t (x y)+ Shorthand/Smooth Relative Quadratic Bezier - //T (x y)+ Shorthand/Smooth Absolute Quadratic Bezier - //s (x2 y2 x y)+ Shorthand/Smooth Relative Bezier curve - //S (x2 y2 x y)+ Shorthand/Smooth Absolute Bezier curve - //a (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Relative Elliptical Arc - //A (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Absolute Elliptical Arc - // return early if data is not defined - if (!data) { - return []; - } - // command string - var cs = data; - // command chars - var cc = [ - 'm', - 'M', - 'l', - 'L', - 'v', - 'V', - 'h', - 'H', - 'z', - 'Z', - 'c', - 'C', - 'q', - 'Q', - 't', - 'T', - 's', - 'S', - 'a', - 'A', - ]; - // convert white spaces to commas - cs = cs.replace(new RegExp(' ', 'g'), ','); - // create pipes so that we can split the data - for (var n = 0; n < cc.length; n++) { - cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]); - } - // create array - var arr = cs.split('|'); - var ca = []; - var coords = []; - // init context point - var cpx = 0; - var cpy = 0; - var re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi; - var match; - for (n = 1; n < arr.length; n++) { - var str = arr[n]; - var c = str.charAt(0); - str = str.slice(1); - coords.length = 0; - while ((match = re.exec(str))) { - coords.push(match[0]); - } - // while ((match = re.exec(str))) { - // coords.push(match[0]); - // } - var p = []; - for (var j = 0, jlen = coords.length; j < jlen; j++) { - var parsed = parseFloat(coords[j]); - if (!isNaN(parsed)) { - p.push(parsed); - } else { - p.push(0); + else { + context.fillStrokeShape(this); } - } - while (p.length > 0) { - if (isNaN(p[0])) { - // case for a trailing comma before next command - break; - } - var cmd = null; + } + getSelfRect() { var points = []; - var startX = cpx, - startY = cpy; - // Move var from within the switch to up here (jshint) - var prevCmd, ctlPtx, ctlPty; // Ss, Tt - var rx, ry, psi, fa, fs, x1, y1; // Aa - // convert l, H, h, V, and v to L - switch (c) { - // Note: Keep the lineTo's above the moveTo's in this switch - case 'l': - cpx += p.shift(); - cpy += p.shift(); - cmd = 'L'; - points.push(cpx, cpy); - break; - case 'L': - cpx = p.shift(); - cpy = p.shift(); - points.push(cpx, cpy); - break; - // Note: lineTo handlers need to be above this point - case 'm': - var dx = p.shift(); - var dy = p.shift(); - cpx += dx; - cpy += dy; - cmd = 'M'; - // After closing the path move the current position - // to the the first point of the path (if any). - if (ca.length > 2 && ca[ca.length - 1].command === 'z') { - for (var idx = ca.length - 2; idx >= 0; idx--) { - if (ca[idx].command === 'M') { - cpx = ca[idx].points[0] + dx; - cpy = ca[idx].points[1] + dy; - break; + this.dataArray.forEach(function (data) { + if (data.command === 'A') { + // Approximates by breaking curve into line segments + var start = data.points[4]; + // 4 = theta + var dTheta = data.points[5]; + // 5 = dTheta + var end = data.points[4] + dTheta; + var inc = Math.PI / 180.0; + // 1 degree resolution + if (Math.abs(start - end) < inc) { + inc = Math.abs(start - end); + } + if (dTheta < 0) { + // clockwise + for (let t = start - inc; t > end; t -= inc) { + const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2], data.points[3], t, 0); + points.push(point.x, point.y); + } + } + else { + // counter-clockwise + for (let t = start + inc; t < end; t += inc) { + const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2], data.points[3], t, 0); + points.push(point.x, point.y); + } } - } } - points.push(cpx, cpy); - c = 'l'; - // subsequent points are treated as relative lineTo - break; - case 'M': - cpx = p.shift(); - cpy = p.shift(); - cmd = 'M'; - points.push(cpx, cpy); - c = 'L'; - // subsequent points are treated as absolute lineTo - break; - case 'h': - cpx += p.shift(); - cmd = 'L'; - points.push(cpx, cpy); - break; - case 'H': - cpx = p.shift(); - cmd = 'L'; - points.push(cpx, cpy); - break; - case 'v': - cpy += p.shift(); - cmd = 'L'; - points.push(cpx, cpy); - break; - case 'V': - cpy = p.shift(); - cmd = 'L'; - points.push(cpx, cpy); - break; - case 'C': - points.push(p.shift(), p.shift(), p.shift(), p.shift()); - cpx = p.shift(); - cpy = p.shift(); - points.push(cpx, cpy); - break; - case 'c': - points.push( - cpx + p.shift(), - cpy + p.shift(), - cpx + p.shift(), - cpy + p.shift() - ); - cpx += p.shift(); - cpy += p.shift(); - cmd = 'C'; - points.push(cpx, cpy); - break; - case 'S': - ctlPtx = cpx; - ctlPty = cpy; - prevCmd = ca[ca.length - 1]; - if (prevCmd.command === 'C') { - ctlPtx = cpx + (cpx - prevCmd.points[2]); - ctlPty = cpy + (cpy - prevCmd.points[3]); + else if (data.command === 'C') { + // Approximates by breaking curve into 100 line segments + for (let t = 0.0; t <= 1; t += 0.01) { + const point = Path.getPointOnCubicBezier(t, data.start.x, data.start.y, data.points[0], data.points[1], data.points[2], data.points[3], data.points[4], data.points[5]); + points.push(point.x, point.y); + } } - points.push(ctlPtx, ctlPty, p.shift(), p.shift()); - cpx = p.shift(); - cpy = p.shift(); - cmd = 'C'; - points.push(cpx, cpy); - break; - case 's': - ctlPtx = cpx; - ctlPty = cpy; - prevCmd = ca[ca.length - 1]; - if (prevCmd.command === 'C') { - ctlPtx = cpx + (cpx - prevCmd.points[2]); - ctlPty = cpy + (cpy - prevCmd.points[3]); + else { + // TODO: how can we calculate bezier curves better? + points = points.concat(data.points); } - points.push(ctlPtx, ctlPty, cpx + p.shift(), cpy + p.shift()); - cpx += p.shift(); - cpy += p.shift(); - cmd = 'C'; - points.push(cpx, cpy); - break; - case 'Q': - points.push(p.shift(), p.shift()); - cpx = p.shift(); - cpy = p.shift(); - points.push(cpx, cpy); - break; - case 'q': - points.push(cpx + p.shift(), cpy + p.shift()); - cpx += p.shift(); - cpy += p.shift(); - cmd = 'Q'; - points.push(cpx, cpy); - break; - case 'T': - ctlPtx = cpx; - ctlPty = cpy; - prevCmd = ca[ca.length - 1]; - if (prevCmd.command === 'Q') { - ctlPtx = cpx + (cpx - prevCmd.points[0]); - ctlPty = cpy + (cpy - prevCmd.points[1]); - } - cpx = p.shift(); - cpy = p.shift(); - cmd = 'Q'; - points.push(ctlPtx, ctlPty, cpx, cpy); - break; - case 't': - ctlPtx = cpx; - ctlPty = cpy; - prevCmd = ca[ca.length - 1]; - if (prevCmd.command === 'Q') { - ctlPtx = cpx + (cpx - prevCmd.points[0]); - ctlPty = cpy + (cpy - prevCmd.points[1]); - } - cpx += p.shift(); - cpy += p.shift(); - cmd = 'Q'; - points.push(ctlPtx, ctlPty, cpx, cpy); - break; - case 'A': - rx = p.shift(); - ry = p.shift(); - psi = p.shift(); - fa = p.shift(); - fs = p.shift(); - x1 = cpx; - y1 = cpy; - cpx = p.shift(); - cpy = p.shift(); - cmd = 'A'; - points = this.convertEndpointToCenterParameterization( - x1, - y1, - cpx, - cpy, - fa, - fs, - rx, - ry, - psi - ); - break; - case 'a': - rx = p.shift(); - ry = p.shift(); - psi = p.shift(); - fa = p.shift(); - fs = p.shift(); - x1 = cpx; - y1 = cpy; - cpx += p.shift(); - cpy += p.shift(); - cmd = 'A'; - points = this.convertEndpointToCenterParameterization( - x1, - y1, - cpx, - cpy, - fa, - fs, - rx, - ry, - psi - ); - break; - } - ca.push({ - command: cmd || c, - points: points, - start: { - x: startX, - y: startY, - }, - pathLength: this.calcLength(startX, startY, cmd || c, points), }); - } - if (c === 'z' || c === 'Z') { - ca.push({ - command: 'z', - points: [], - start: undefined, - pathLength: 0, - }); - } - } - return ca; - } - static calcLength(x, y, cmd, points) { - var len, p1, p2, t; - var path = Path; - switch (cmd) { - case 'L': - return path.getLineLength(x, y, points[0], points[1]); - case 'C': - // Approximates by breaking curve into 100 line segments - len = 0.0; - p1 = path.getPointOnCubicBezier( - 0, - x, - y, - points[0], - points[1], - points[2], - points[3], - points[4], - points[5] - ); - for (t = 0.01; t <= 1; t += 0.01) { - p2 = path.getPointOnCubicBezier( - t, - x, - y, - points[0], - points[1], - points[2], - points[3], - points[4], - points[5] - ); - len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); - p1 = p2; + var minX = points[0]; + var maxX = points[0]; + var minY = points[1]; + var maxY = points[1]; + var x, y; + for (var i = 0; i < points.length / 2; i++) { + x = points[i * 2]; + y = points[i * 2 + 1]; + // skip bad values + if (!isNaN(x)) { + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + if (!isNaN(y)) { + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + } } - return len; - case 'Q': - // Approximates by breaking curve into 100 line segments - len = 0.0; - p1 = path.getPointOnQuadraticBezier( - 0, - x, - y, - points[0], - points[1], - points[2], - points[3] - ); - for (t = 0.01; t <= 1; t += 0.01) { - p2 = path.getPointOnQuadraticBezier( - t, - x, - y, - points[0], - points[1], - points[2], - points[3] - ); - len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); - p1 = p2; + return { + x: Math.round(minX), + y: Math.round(minY), + width: Math.round(maxX - minX), + height: Math.round(maxY - minY), + }; + } + /** + * Return length of the path. + * @method + * @name Konva.Path#getLength + * @returns {Number} length + * @example + * var length = path.getLength(); + */ + getLength() { + return this.pathLength; + } + /** + * Get point on path at specific length of the path + * @method + * @name Konva.Path#getPointAtLength + * @param {Number} length length + * @returns {Object} point {x,y} point + * @example + * var point = path.getPointAtLength(10); + */ + getPointAtLength(length) { + var point, i = 0, ii = this.dataArray.length; + if (!ii) { + return null; } - return len; - case 'A': - // Approximates by breaking curve into line segments - len = 0.0; - var start = points[4]; - // 4 = theta - var dTheta = points[5]; - // 5 = dTheta - var end = points[4] + dTheta; - var inc = Math.PI / 180.0; - // 1 degree resolution - if (Math.abs(start - end) < inc) { - inc = Math.abs(start - end); + while (i < ii && length > this.dataArray[i].pathLength) { + length -= this.dataArray[i].pathLength; + ++i; } - // Note: for purpose of calculating arc length, not going to worry about rotating X-axis by angle psi - p1 = path.getPointOnEllipticalArc( - points[0], - points[1], - points[2], - points[3], - start, - 0 - ); - if (dTheta < 0) { - // clockwise - for (t = start - inc; t > end; t -= inc) { - p2 = path.getPointOnEllipticalArc( - points[0], - points[1], - points[2], - points[3], - t, - 0 - ); - len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); - p1 = p2; - } - } else { - // counter-clockwise - for (t = start + inc; t < end; t += inc) { - p2 = path.getPointOnEllipticalArc( - points[0], - points[1], - points[2], - points[3], - t, - 0 - ); - len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); - p1 = p2; - } + if (i === ii) { + point = this.dataArray[i - 1].points.slice(-2); + return { + x: point[0], + y: point[1], + }; } - p2 = path.getPointOnEllipticalArc( - points[0], - points[1], - points[2], - points[3], - end, - 0 - ); - len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); - return len; + if (length < 0.01) { + point = this.dataArray[i].points.slice(0, 2); + return { + x: point[0], + y: point[1], + }; + } + var cp = this.dataArray[i]; + var p = cp.points; + switch (cp.command) { + case 'L': + return Path.getPointOnLine(length, cp.start.x, cp.start.y, p[0], p[1]); + case 'C': + return Path.getPointOnCubicBezier(length / cp.pathLength, cp.start.x, cp.start.y, p[0], p[1], p[2], p[3], p[4], p[5]); + case 'Q': + return Path.getPointOnQuadraticBezier(length / cp.pathLength, cp.start.x, cp.start.y, p[0], p[1], p[2], p[3]); + case 'A': + var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6]; + theta += (dTheta * length) / cp.pathLength; + return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi); + } + return null; } - return 0; - } - static convertEndpointToCenterParameterization( - x1, - y1, - x2, - y2, - fa, - fs, - rx, - ry, - psiDeg - ) { - // Derived from: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes - var psi = psiDeg * (Math.PI / 180.0); - var xp = - (Math.cos(psi) * (x1 - x2)) / 2.0 + (Math.sin(psi) * (y1 - y2)) / 2.0; - var yp = - (-1 * Math.sin(psi) * (x1 - x2)) / 2.0 + - (Math.cos(psi) * (y1 - y2)) / 2.0; - var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry); - if (lambda > 1) { - rx *= Math.sqrt(lambda); - ry *= Math.sqrt(lambda); + static getLineLength(x1, y1, x2, y2) { + return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); } - var f = Math.sqrt( - (rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / - (rx * rx * (yp * yp) + ry * ry * (xp * xp)) - ); - if (fa === fs) { - f *= -1; + static getPointOnLine(dist, P1x, P1y, P2x, P2y, fromX, fromY) { + if (fromX === undefined) { + fromX = P1x; + } + if (fromY === undefined) { + fromY = P1y; + } + var m = (P2y - P1y) / (P2x - P1x + 0.00000001); + var run = Math.sqrt((dist * dist) / (1 + m * m)); + if (P2x < P1x) { + run *= -1; + } + var rise = m * run; + var pt; + if (P2x === P1x) { + // vertical line + pt = { + x: fromX, + y: fromY + rise, + }; + } + else if ((fromY - P1y) / (fromX - P1x + 0.00000001) === m) { + pt = { + x: fromX + run, + y: fromY + rise, + }; + } + else { + var ix, iy; + var len = this.getLineLength(P1x, P1y, P2x, P2y); + // if (len < 0.00000001) { + // return { + // x: P1x, + // y: P1y, + // }; + // } + var u = (fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y); + u = u / (len * len); + ix = P1x + u * (P2x - P1x); + iy = P1y + u * (P2y - P1y); + var pRise = this.getLineLength(fromX, fromY, ix, iy); + var pRun = Math.sqrt(dist * dist - pRise * pRise); + run = Math.sqrt((pRun * pRun) / (1 + m * m)); + if (P2x < P1x) { + run *= -1; + } + rise = m * run; + pt = { + x: ix + run, + y: iy + rise, + }; + } + return pt; } - if (isNaN(f)) { - f = 0; + static getPointOnCubicBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) { + function CB1(t) { + return t * t * t; + } + function CB2(t) { + return 3 * t * t * (1 - t); + } + function CB3(t) { + return 3 * t * (1 - t) * (1 - t); + } + function CB4(t) { + return (1 - t) * (1 - t) * (1 - t); + } + var x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct); + var y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct); + return { + x: x, + y: y, + }; } - var cxp = (f * rx * yp) / ry; - var cyp = (f * -ry * xp) / rx; - var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp; - var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp; - var vMag = function (v) { - return Math.sqrt(v[0] * v[0] + v[1] * v[1]); - }; - var vRatio = function (u, v) { - return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); - }; - var vAngle = function (u, v) { - return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v)); - }; - var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]); - var u = [(xp - cxp) / rx, (yp - cyp) / ry]; - var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry]; - var dTheta = vAngle(u, v); - if (vRatio(u, v) <= -1) { - dTheta = Math.PI; + static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) { + function QB1(t) { + return t * t; + } + function QB2(t) { + return 2 * t * (1 - t); + } + function QB3(t) { + return (1 - t) * (1 - t); + } + var x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct); + var y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct); + return { + x: x, + y: y, + }; } - if (vRatio(u, v) >= 1) { - dTheta = 0; + static getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) { + var cosPsi = Math.cos(psi), sinPsi = Math.sin(psi); + var pt = { + x: rx * Math.cos(theta), + y: ry * Math.sin(theta), + }; + return { + x: cx + (pt.x * cosPsi - pt.y * sinPsi), + y: cy + (pt.x * sinPsi + pt.y * cosPsi), + }; } - if (fs === 0 && dTheta > 0) { - dTheta = dTheta - 2 * Math.PI; + /* + * get parsed data array from the data + * string. V, v, H, h, and l data are converted to + * L data for the purpose of high performance Path + * rendering + */ + static parsePathData(data) { + // Path Data Segment must begin with a moveTo + //m (x y)+ Relative moveTo (subsequent points are treated as lineTo) + //M (x y)+ Absolute moveTo (subsequent points are treated as lineTo) + //l (x y)+ Relative lineTo + //L (x y)+ Absolute LineTo + //h (x)+ Relative horizontal lineTo + //H (x)+ Absolute horizontal lineTo + //v (y)+ Relative vertical lineTo + //V (y)+ Absolute vertical lineTo + //z (closepath) + //Z (closepath) + //c (x1 y1 x2 y2 x y)+ Relative Bezier curve + //C (x1 y1 x2 y2 x y)+ Absolute Bezier curve + //q (x1 y1 x y)+ Relative Quadratic Bezier + //Q (x1 y1 x y)+ Absolute Quadratic Bezier + //t (x y)+ Shorthand/Smooth Relative Quadratic Bezier + //T (x y)+ Shorthand/Smooth Absolute Quadratic Bezier + //s (x2 y2 x y)+ Shorthand/Smooth Relative Bezier curve + //S (x2 y2 x y)+ Shorthand/Smooth Absolute Bezier curve + //a (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Relative Elliptical Arc + //A (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Absolute Elliptical Arc + // return early if data is not defined + if (!data) { + return []; + } + // command string + var cs = data; + // command chars + var cc = [ + 'm', + 'M', + 'l', + 'L', + 'v', + 'V', + 'h', + 'H', + 'z', + 'Z', + 'c', + 'C', + 'q', + 'Q', + 't', + 'T', + 's', + 'S', + 'a', + 'A', + ]; + // convert white spaces to commas + cs = cs.replace(new RegExp(' ', 'g'), ','); + // create pipes so that we can split the data + for (var n = 0; n < cc.length; n++) { + cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]); + } + // create array + var arr = cs.split('|'); + var ca = []; + var coords = []; + // init context point + var cpx = 0; + var cpy = 0; + var re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi; + var match; + for (n = 1; n < arr.length; n++) { + var str = arr[n]; + var c = str.charAt(0); + str = str.slice(1); + coords.length = 0; + while ((match = re.exec(str))) { + coords.push(match[0]); + } + // while ((match = re.exec(str))) { + // coords.push(match[0]); + // } + var p = []; + for (var j = 0, jlen = coords.length; j < jlen; j++) { + var parsed = parseFloat(coords[j]); + if (!isNaN(parsed)) { + p.push(parsed); + } + else { + p.push(0); + } + } + while (p.length > 0) { + if (isNaN(p[0])) { + // case for a trailing comma before next command + break; + } + var cmd = null; + var points = []; + var startX = cpx, startY = cpy; + // Move var from within the switch to up here (jshint) + var prevCmd, ctlPtx, ctlPty; // Ss, Tt + var rx, ry, psi, fa, fs, x1, y1; // Aa + // convert l, H, h, V, and v to L + switch (c) { + // Note: Keep the lineTo's above the moveTo's in this switch + case 'l': + cpx += p.shift(); + cpy += p.shift(); + cmd = 'L'; + points.push(cpx, cpy); + break; + case 'L': + cpx = p.shift(); + cpy = p.shift(); + points.push(cpx, cpy); + break; + // Note: lineTo handlers need to be above this point + case 'm': + var dx = p.shift(); + var dy = p.shift(); + cpx += dx; + cpy += dy; + cmd = 'M'; + // After closing the path move the current position + // to the the first point of the path (if any). + if (ca.length > 2 && ca[ca.length - 1].command === 'z') { + for (var idx = ca.length - 2; idx >= 0; idx--) { + if (ca[idx].command === 'M') { + cpx = ca[idx].points[0] + dx; + cpy = ca[idx].points[1] + dy; + break; + } + } + } + points.push(cpx, cpy); + c = 'l'; + // subsequent points are treated as relative lineTo + break; + case 'M': + cpx = p.shift(); + cpy = p.shift(); + cmd = 'M'; + points.push(cpx, cpy); + c = 'L'; + // subsequent points are treated as absolute lineTo + break; + case 'h': + cpx += p.shift(); + cmd = 'L'; + points.push(cpx, cpy); + break; + case 'H': + cpx = p.shift(); + cmd = 'L'; + points.push(cpx, cpy); + break; + case 'v': + cpy += p.shift(); + cmd = 'L'; + points.push(cpx, cpy); + break; + case 'V': + cpy = p.shift(); + cmd = 'L'; + points.push(cpx, cpy); + break; + case 'C': + points.push(p.shift(), p.shift(), p.shift(), p.shift()); + cpx = p.shift(); + cpy = p.shift(); + points.push(cpx, cpy); + break; + case 'c': + points.push(cpx + p.shift(), cpy + p.shift(), cpx + p.shift(), cpy + p.shift()); + cpx += p.shift(); + cpy += p.shift(); + cmd = 'C'; + points.push(cpx, cpy); + break; + case 'S': + ctlPtx = cpx; + ctlPty = cpy; + prevCmd = ca[ca.length - 1]; + if (prevCmd.command === 'C') { + ctlPtx = cpx + (cpx - prevCmd.points[2]); + ctlPty = cpy + (cpy - prevCmd.points[3]); + } + points.push(ctlPtx, ctlPty, p.shift(), p.shift()); + cpx = p.shift(); + cpy = p.shift(); + cmd = 'C'; + points.push(cpx, cpy); + break; + case 's': + ctlPtx = cpx; + ctlPty = cpy; + prevCmd = ca[ca.length - 1]; + if (prevCmd.command === 'C') { + ctlPtx = cpx + (cpx - prevCmd.points[2]); + ctlPty = cpy + (cpy - prevCmd.points[3]); + } + points.push(ctlPtx, ctlPty, cpx + p.shift(), cpy + p.shift()); + cpx += p.shift(); + cpy += p.shift(); + cmd = 'C'; + points.push(cpx, cpy); + break; + case 'Q': + points.push(p.shift(), p.shift()); + cpx = p.shift(); + cpy = p.shift(); + points.push(cpx, cpy); + break; + case 'q': + points.push(cpx + p.shift(), cpy + p.shift()); + cpx += p.shift(); + cpy += p.shift(); + cmd = 'Q'; + points.push(cpx, cpy); + break; + case 'T': + ctlPtx = cpx; + ctlPty = cpy; + prevCmd = ca[ca.length - 1]; + if (prevCmd.command === 'Q') { + ctlPtx = cpx + (cpx - prevCmd.points[0]); + ctlPty = cpy + (cpy - prevCmd.points[1]); + } + cpx = p.shift(); + cpy = p.shift(); + cmd = 'Q'; + points.push(ctlPtx, ctlPty, cpx, cpy); + break; + case 't': + ctlPtx = cpx; + ctlPty = cpy; + prevCmd = ca[ca.length - 1]; + if (prevCmd.command === 'Q') { + ctlPtx = cpx + (cpx - prevCmd.points[0]); + ctlPty = cpy + (cpy - prevCmd.points[1]); + } + cpx += p.shift(); + cpy += p.shift(); + cmd = 'Q'; + points.push(ctlPtx, ctlPty, cpx, cpy); + break; + case 'A': + rx = p.shift(); + ry = p.shift(); + psi = p.shift(); + fa = p.shift(); + fs = p.shift(); + x1 = cpx; + y1 = cpy; + cpx = p.shift(); + cpy = p.shift(); + cmd = 'A'; + points = this.convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi); + break; + case 'a': + rx = p.shift(); + ry = p.shift(); + psi = p.shift(); + fa = p.shift(); + fs = p.shift(); + x1 = cpx; + y1 = cpy; + cpx += p.shift(); + cpy += p.shift(); + cmd = 'A'; + points = this.convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi); + break; + } + ca.push({ + command: cmd || c, + points: points, + start: { + x: startX, + y: startY, + }, + pathLength: this.calcLength(startX, startY, cmd || c, points), + }); + } + if (c === 'z' || c === 'Z') { + ca.push({ + command: 'z', + points: [], + start: undefined, + pathLength: 0, + }); + } + } + return ca; } - if (fs === 1 && dTheta < 0) { - dTheta = dTheta + 2 * Math.PI; + static calcLength(x, y, cmd, points) { + var len, p1, p2, t; + var path = Path; + switch (cmd) { + case 'L': + return path.getLineLength(x, y, points[0], points[1]); + case 'C': + // Approximates by breaking curve into 100 line segments + len = 0.0; + p1 = path.getPointOnCubicBezier(0, x, y, points[0], points[1], points[2], points[3], points[4], points[5]); + for (t = 0.01; t <= 1; t += 0.01) { + p2 = path.getPointOnCubicBezier(t, x, y, points[0], points[1], points[2], points[3], points[4], points[5]); + len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); + p1 = p2; + } + return len; + case 'Q': + // Approximates by breaking curve into 100 line segments + len = 0.0; + p1 = path.getPointOnQuadraticBezier(0, x, y, points[0], points[1], points[2], points[3]); + for (t = 0.01; t <= 1; t += 0.01) { + p2 = path.getPointOnQuadraticBezier(t, x, y, points[0], points[1], points[2], points[3]); + len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); + p1 = p2; + } + return len; + case 'A': + // Approximates by breaking curve into line segments + len = 0.0; + var start = points[4]; + // 4 = theta + var dTheta = points[5]; + // 5 = dTheta + var end = points[4] + dTheta; + var inc = Math.PI / 180.0; + // 1 degree resolution + if (Math.abs(start - end) < inc) { + inc = Math.abs(start - end); + } + // Note: for purpose of calculating arc length, not going to worry about rotating X-axis by angle psi + p1 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], start, 0); + if (dTheta < 0) { + // clockwise + for (t = start - inc; t > end; t -= inc) { + p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0); + len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); + p1 = p2; + } + } + else { + // counter-clockwise + for (t = start + inc; t < end; t += inc) { + p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0); + len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); + p1 = p2; + } + } + p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], end, 0); + len += path.getLineLength(p1.x, p1.y, p2.x, p2.y); + return len; + } + return 0; + } + static convertEndpointToCenterParameterization(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg) { + // Derived from: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + var psi = psiDeg * (Math.PI / 180.0); + var xp = (Math.cos(psi) * (x1 - x2)) / 2.0 + (Math.sin(psi) * (y1 - y2)) / 2.0; + var yp = (-1 * Math.sin(psi) * (x1 - x2)) / 2.0 + + (Math.cos(psi) * (y1 - y2)) / 2.0; + var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry); + if (lambda > 1) { + rx *= Math.sqrt(lambda); + ry *= Math.sqrt(lambda); + } + var f = Math.sqrt((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / + (rx * rx * (yp * yp) + ry * ry * (xp * xp))); + if (fa === fs) { + f *= -1; + } + if (isNaN(f)) { + f = 0; + } + var cxp = (f * rx * yp) / ry; + var cyp = (f * -ry * xp) / rx; + var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp; + var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp; + var vMag = function (v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); + }; + var vRatio = function (u, v) { + return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); + }; + var vAngle = function (u, v) { + return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v)); + }; + var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]); + var u = [(xp - cxp) / rx, (yp - cyp) / ry]; + var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry]; + var dTheta = vAngle(u, v); + if (vRatio(u, v) <= -1) { + dTheta = Math.PI; + } + if (vRatio(u, v) >= 1) { + dTheta = 0; + } + if (fs === 0 && dTheta > 0) { + dTheta = dTheta - 2 * Math.PI; + } + if (fs === 1 && dTheta < 0) { + dTheta = dTheta + 2 * Math.PI; + } + return [cx, cy, rx, ry, theta, dTheta, psi, fs]; } - return [cx, cy, rx, ry, theta, dTheta, psi, fs]; - } } Path.prototype.className = 'Path'; Path.prototype._attrsAffectingSize = ['data']; @@ -12369,8 +11448,8 @@ * // set data * path.data('M200,100h100v50z'); */ - Factory.addGetterSetter(Path, 'data'); - + Factory.addGetterSetter(Path, 'data'); + /** * Rect constructor * @constructor @@ -12390,72 +11469,40 @@ * }); */ class Rect extends Shape { - _sceneFunc(context) { - var cornerRadius = this.cornerRadius(), - width = this.width(), - height = this.height(); - context.beginPath(); - if (!cornerRadius) { - // simple rect - don't bother doing all that complicated maths stuff. - context.rect(0, 0, width, height); - } else { - let topLeft = 0; - let topRight = 0; - let bottomLeft = 0; - let bottomRight = 0; - if (typeof cornerRadius === 'number') { - topLeft = topRight = bottomLeft = bottomRight = Math.min( - cornerRadius, - width / 2, - height / 2 - ); - } else { - topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); - topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); - bottomRight = Math.min(cornerRadius[2] || 0, width / 2, height / 2); - bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); - } - context.moveTo(topLeft, 0); - context.lineTo(width - topRight, 0); - context.arc( - width - topRight, - topRight, - topRight, - (Math.PI * 3) / 2, - 0, - false - ); - context.lineTo(width, height - bottomRight); - context.arc( - width - bottomRight, - height - bottomRight, - bottomRight, - 0, - Math.PI / 2, - false - ); - context.lineTo(bottomLeft, height); - context.arc( - bottomLeft, - height - bottomLeft, - bottomLeft, - Math.PI / 2, - Math.PI, - false - ); - context.lineTo(0, topLeft); - context.arc( - topLeft, - topLeft, - topLeft, - Math.PI, - (Math.PI * 3) / 2, - false - ); + _sceneFunc(context) { + var cornerRadius = this.cornerRadius(), width = this.width(), height = this.height(); + context.beginPath(); + if (!cornerRadius) { + // simple rect - don't bother doing all that complicated maths stuff. + context.rect(0, 0, width, height); + } + else { + let topLeft = 0; + let topRight = 0; + let bottomLeft = 0; + let bottomRight = 0; + if (typeof cornerRadius === 'number') { + topLeft = topRight = bottomLeft = bottomRight = Math.min(cornerRadius, width / 2, height / 2); + } + else { + topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); + topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); + bottomRight = Math.min(cornerRadius[2] || 0, width / 2, height / 2); + bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); + } + context.moveTo(topLeft, 0); + context.lineTo(width - topRight, 0); + context.arc(width - topRight, topRight, topRight, (Math.PI * 3) / 2, 0, false); + context.lineTo(width, height - bottomRight); + context.arc(width - bottomRight, height - bottomRight, bottomRight, 0, Math.PI / 2, false); + context.lineTo(bottomLeft, height); + context.arc(bottomLeft, height - bottomLeft, bottomLeft, Math.PI / 2, Math.PI, false); + context.lineTo(0, topLeft); + context.arc(topLeft, topLeft, topLeft, Math.PI, (Math.PI * 3) / 2, false); + } + context.closePath(); + context.fillStrokeShape(this); } - context.closePath(); - context.fillStrokeShape(this); - } } Rect.prototype.className = 'Rect'; _registerNode(Rect); @@ -12476,13 +11523,8 @@ * // top-left, top-right, bottom-right, bottom-left * rect.cornerRadius([0, 10, 20, 30]); */ - Factory.addGetterSetter( - Rect, - 'cornerRadius', - 0, - getNumberOrArrayOfNumbersValidator(4) - ); - + Factory.addGetterSetter(Rect, 'cornerRadius', 0, getNumberOrArrayOfNumbersValidator(4)); + /** * RegularPolygon constructor. Examples include triangles, squares, pentagons, hexagons, etc. * @constructor @@ -12505,59 +11547,59 @@ * }); */ class RegularPolygon extends Shape { - _sceneFunc(context) { - const points = this._getPoints(); - context.beginPath(); - context.moveTo(points[0].x, points[0].y); - for (var n = 1; n < points.length; n++) { - context.lineTo(points[n].x, points[n].y); + _sceneFunc(context) { + const points = this._getPoints(); + context.beginPath(); + context.moveTo(points[0].x, points[0].y); + for (var n = 1; n < points.length; n++) { + context.lineTo(points[n].x, points[n].y); + } + context.closePath(); + context.fillStrokeShape(this); } - context.closePath(); - context.fillStrokeShape(this); - } - _getPoints() { - const sides = this.attrs.sides; - const radius = this.attrs.radius || 0; - const points = []; - for (var n = 0; n < sides; n++) { - points.push({ - x: radius * Math.sin((n * 2 * Math.PI) / sides), - y: -1 * radius * Math.cos((n * 2 * Math.PI) / sides), - }); + _getPoints() { + const sides = this.attrs.sides; + const radius = this.attrs.radius || 0; + const points = []; + for (var n = 0; n < sides; n++) { + points.push({ + x: radius * Math.sin((n * 2 * Math.PI) / sides), + y: -1 * radius * Math.cos((n * 2 * Math.PI) / sides), + }); + } + return points; + } + getSelfRect() { + const points = this._getPoints(); + var minX = points[0].x; + var maxX = points[0].y; + var minY = points[0].x; + var maxY = points[0].y; + points.forEach((point) => { + minX = Math.min(minX, point.x); + maxX = Math.max(maxX, point.x); + minY = Math.min(minY, point.y); + maxY = Math.max(maxY, point.y); + }); + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY, + }; + } + getWidth() { + return this.radius() * 2; + } + getHeight() { + return this.radius() * 2; + } + setWidth(width) { + this.radius(width / 2); + } + setHeight(height) { + this.radius(height / 2); } - return points; - } - getSelfRect() { - const points = this._getPoints(); - var minX = points[0].x; - var maxX = points[0].y; - var minY = points[0].x; - var maxY = points[0].y; - points.forEach((point) => { - minX = Math.min(minX, point.x); - maxX = Math.max(maxX, point.x); - minY = Math.min(minY, point.y); - maxY = Math.max(maxY, point.y); - }); - return { - x: minX, - y: minY, - width: maxX - minX, - height: maxY - minY, - }; - } - getWidth() { - return this.radius() * 2; - } - getHeight() { - return this.radius() * 2; - } - setWidth(width) { - this.radius(width / 2); - } - setHeight(height) { - this.radius(height / 2); - } } RegularPolygon.prototype.className = 'RegularPolygon'; RegularPolygon.prototype._centroid = true; @@ -12590,8 +11632,8 @@ * // set sides * shape.sides(10); */ - Factory.addGetterSetter(RegularPolygon, 'sides', 0, getNumberValidator()); - + Factory.addGetterSetter(RegularPolygon, 'sides', 0, getNumberValidator()); + var PIx2 = Math.PI * 2; /** * Ring constructor @@ -12614,26 +11656,26 @@ * }); */ class Ring extends Shape { - _sceneFunc(context) { - context.beginPath(); - context.arc(0, 0, this.innerRadius(), 0, PIx2, false); - context.moveTo(this.outerRadius(), 0); - context.arc(0, 0, this.outerRadius(), PIx2, 0, true); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.outerRadius() * 2; - } - getHeight() { - return this.outerRadius() * 2; - } - setWidth(width) { - this.outerRadius(width / 2); - } - setHeight(height) { - this.outerRadius(height / 2); - } + _sceneFunc(context) { + context.beginPath(); + context.arc(0, 0, this.innerRadius(), 0, PIx2, false); + context.moveTo(this.outerRadius(), 0); + context.arc(0, 0, this.outerRadius(), PIx2, 0, true); + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + return this.outerRadius() * 2; + } + getHeight() { + return this.outerRadius() * 2; + } + setWidth(width) { + this.outerRadius(width / 2); + } + setHeight(height) { + this.outerRadius(height / 2); + } } Ring.prototype.className = 'Ring'; Ring.prototype._centroid = true; @@ -12666,8 +11708,8 @@ * // set outer radius * ring.outerRadius(20); */ - Factory.addGetterSetter(Ring, 'outerRadius', 0, getNumberValidator()); - + Factory.addGetterSetter(Ring, 'outerRadius', 0, getNumberValidator()); + /** * Sprite constructor * @constructor @@ -12716,146 +11758,119 @@ * imageObj.src = '/path/to/image.jpg' */ class Sprite extends Shape { - constructor(config) { - super(config); - this._updated = true; - this.anim = new Animation(() => { - // if we don't need to redraw layer we should return false - var updated = this._updated; - this._updated = false; - return updated; - }); - this.on('animationChange.konva', function () { - // reset index when animation changes - this.frameIndex(0); - }); - this.on('frameIndexChange.konva', function () { - this._updated = true; - }); - // smooth change for frameRate - this.on('frameRateChange.konva', function () { - if (!this.anim.isRunning()) { - return; - } - clearInterval(this.interval); - this._setInterval(); - }); - } - _sceneFunc(context) { - var anim = this.animation(), - index = this.frameIndex(), - ix4 = index * 4, - set = this.animations()[anim], - offsets = this.frameOffsets(), - x = set[ix4 + 0], - y = set[ix4 + 1], - width = set[ix4 + 2], - height = set[ix4 + 3], - image = this.image(); - if (this.hasFill() || this.hasStroke()) { - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - context.fillStrokeShape(this); + constructor(config) { + super(config); + this._updated = true; + this.anim = new Animation(() => { + // if we don't need to redraw layer we should return false + var updated = this._updated; + this._updated = false; + return updated; + }); + this.on('animationChange.konva', function () { + // reset index when animation changes + this.frameIndex(0); + }); + this.on('frameIndexChange.konva', function () { + this._updated = true; + }); + // smooth change for frameRate + this.on('frameRateChange.konva', function () { + if (!this.anim.isRunning()) { + return; + } + clearInterval(this.interval); + this._setInterval(); + }); } - if (image) { - if (offsets) { - var offset = offsets[anim], - ix2 = index * 2; - context.drawImage( - image, - x, - y, - width, - height, - offset[ix2 + 0], - offset[ix2 + 1], - width, - height - ); - } else { - context.drawImage(image, x, y, width, height, 0, 0, width, height); - } + _sceneFunc(context) { + var anim = this.animation(), index = this.frameIndex(), ix4 = index * 4, set = this.animations()[anim], offsets = this.frameOffsets(), x = set[ix4 + 0], y = set[ix4 + 1], width = set[ix4 + 2], height = set[ix4 + 3], image = this.image(); + if (this.hasFill() || this.hasStroke()) { + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + context.fillStrokeShape(this); + } + if (image) { + if (offsets) { + var offset = offsets[anim], ix2 = index * 2; + context.drawImage(image, x, y, width, height, offset[ix2 + 0], offset[ix2 + 1], width, height); + } + else { + context.drawImage(image, x, y, width, height, 0, 0, width, height); + } + } } - } - _hitFunc(context) { - var anim = this.animation(), - index = this.frameIndex(), - ix4 = index * 4, - set = this.animations()[anim], - offsets = this.frameOffsets(), - width = set[ix4 + 2], - height = set[ix4 + 3]; - context.beginPath(); - if (offsets) { - var offset = offsets[anim]; - var ix2 = index * 2; - context.rect(offset[ix2 + 0], offset[ix2 + 1], width, height); - } else { - context.rect(0, 0, width, height); + _hitFunc(context) { + var anim = this.animation(), index = this.frameIndex(), ix4 = index * 4, set = this.animations()[anim], offsets = this.frameOffsets(), width = set[ix4 + 2], height = set[ix4 + 3]; + context.beginPath(); + if (offsets) { + var offset = offsets[anim]; + var ix2 = index * 2; + context.rect(offset[ix2 + 0], offset[ix2 + 1], width, height); + } + else { + context.rect(0, 0, width, height); + } + context.closePath(); + context.fillShape(this); } - context.closePath(); - context.fillShape(this); - } - _useBufferCanvas() { - return super._useBufferCanvas(true); - } - _setInterval() { - var that = this; - this.interval = setInterval(function () { - that._updateIndex(); - }, 1000 / this.frameRate()); - } - /** - * start sprite animation - * @method - * @name Konva.Sprite#start - */ - start() { - if (this.isRunning()) { - return; + _useBufferCanvas() { + return super._useBufferCanvas(true); } - var layer = this.getLayer(); - /* - * animation object has no executable function because - * the updates are done with a fixed FPS with the setInterval - * below. The anim object only needs the layer reference for - * redraw + _setInterval() { + var that = this; + this.interval = setInterval(function () { + that._updateIndex(); + }, 1000 / this.frameRate()); + } + /** + * start sprite animation + * @method + * @name Konva.Sprite#start */ - this.anim.setLayers(layer); - this._setInterval(); - this.anim.start(); - } - /** - * stop sprite animation - * @method - * @name Konva.Sprite#stop - */ - stop() { - this.anim.stop(); - clearInterval(this.interval); - } - /** - * determine if animation of sprite is running or not. returns true or false - * @method - * @name Konva.Sprite#isRunning - * @returns {Boolean} - */ - isRunning() { - return this.anim.isRunning(); - } - _updateIndex() { - var index = this.frameIndex(), - animation = this.animation(), - animations = this.animations(), - anim = animations[animation], - len = anim.length / 4; - if (index < len - 1) { - this.frameIndex(index + 1); - } else { - this.frameIndex(0); + start() { + if (this.isRunning()) { + return; + } + var layer = this.getLayer(); + /* + * animation object has no executable function because + * the updates are done with a fixed FPS with the setInterval + * below. The anim object only needs the layer reference for + * redraw + */ + this.anim.setLayers(layer); + this._setInterval(); + this.anim.start(); + } + /** + * stop sprite animation + * @method + * @name Konva.Sprite#stop + */ + stop() { + this.anim.stop(); + clearInterval(this.interval); + } + /** + * determine if animation of sprite is running or not. returns true or false + * @method + * @name Konva.Sprite#isRunning + * @returns {Boolean} + */ + isRunning() { + return this.anim.isRunning(); + } + _updateIndex() { + var index = this.frameIndex(), animation = this.animation(), animations = this.animations(), anim = animations[animation], len = anim.length / 4; + if (index < len - 1) { + this.frameIndex(index + 1); + } + else { + this.frameIndex(0); + } } - } } Sprite.prototype.className = 'Sprite'; _registerNode(Sprite); @@ -12985,11 +12000,11 @@ * sprite.frameRate(2); */ Factory.backCompat(Sprite, { - index: 'frameIndex', - getIndex: 'getFrameIndex', - setIndex: 'setFrameIndex', - }); - + index: 'frameIndex', + getIndex: 'getFrameIndex', + setIndex: 'setFrameIndex', + }); + /** * Star constructor * @constructor @@ -13014,33 +12029,31 @@ * }); */ class Star extends Shape { - _sceneFunc(context) { - var innerRadius = this.innerRadius(), - outerRadius = this.outerRadius(), - numPoints = this.numPoints(); - context.beginPath(); - context.moveTo(0, 0 - outerRadius); - for (var n = 1; n < numPoints * 2; n++) { - var radius = n % 2 === 0 ? outerRadius : innerRadius; - var x = radius * Math.sin((n * Math.PI) / numPoints); - var y = -1 * radius * Math.cos((n * Math.PI) / numPoints); - context.lineTo(x, y); + _sceneFunc(context) { + var innerRadius = this.innerRadius(), outerRadius = this.outerRadius(), numPoints = this.numPoints(); + context.beginPath(); + context.moveTo(0, 0 - outerRadius); + for (var n = 1; n < numPoints * 2; n++) { + var radius = n % 2 === 0 ? outerRadius : innerRadius; + var x = radius * Math.sin((n * Math.PI) / numPoints); + var y = -1 * radius * Math.cos((n * Math.PI) / numPoints); + context.lineTo(x, y); + } + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + return this.outerRadius() * 2; + } + getHeight() { + return this.outerRadius() * 2; + } + setWidth(width) { + this.outerRadius(width / 2); + } + setHeight(height) { + this.outerRadius(height / 2); } - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.outerRadius() * 2; - } - getHeight() { - return this.outerRadius() * 2; - } - setWidth(width) { - this.outerRadius(width / 2); - } - setHeight(height) { - this.outerRadius(height / 2); - } } Star.prototype.className = 'Star'; Star.prototype._centroid = true; @@ -13087,38 +12100,19 @@ * // set inner radius * star.outerRadius(20); */ - Factory.addGetterSetter(Star, 'outerRadius', 0, getNumberValidator()); - + Factory.addGetterSetter(Star, 'outerRadius', 0, getNumberValidator()); + function stringToArray(string) { - // we need to use `Array.from` because it can split unicode string correctly - // we also can use some regexp magic from lodash: - // https://github.com/lodash/lodash/blob/fb1f99d9d90ad177560d771bc5953a435b2dc119/lodash.toarray/index.js#L256 - // but I decided it is too much code for that small fix - return Array.from(string); + // we need to use `Array.from` because it can split unicode string correctly + // we also can use some regexp magic from lodash: + // https://github.com/lodash/lodash/blob/fb1f99d9d90ad177560d771bc5953a435b2dc119/lodash.toarray/index.js#L256 + // but I decided it is too much code for that small fix + return Array.from(string); } // constants - var AUTO = 'auto', - //CANVAS = 'canvas', - CENTER = 'center', - JUSTIFY = 'justify', - CHANGE_KONVA = 'Change.konva', - CONTEXT_2D = '2d', - DASH = '-', - LEFT = 'left', - TEXT = 'text', - TEXT_UPPER = 'Text', - TOP = 'top', - BOTTOM = 'bottom', - MIDDLE = 'middle', - NORMAL$1 = 'normal', - PX_SPACE = 'px ', - SPACE = ' ', - RIGHT = 'right', - WORD = 'word', - CHAR = 'char', - NONE = 'none', - ELLIPSIS = '…', - ATTR_CHANGE_LIST$1 = [ + var AUTO = 'auto', + //CANVAS = 'canvas', + CENTER = 'center', JUSTIFY = 'justify', CHANGE_KONVA = 'Change.konva', CONTEXT_2D = '2d', DASH = '-', LEFT = 'left', TEXT = 'text', TEXT_UPPER = 'Text', TOP = 'top', BOTTOM = 'bottom', MIDDLE = 'middle', NORMAL$1 = 'normal', PX_SPACE = 'px ', SPACE = ' ', RIGHT = 'right', WORD = 'word', CHAR = 'char', NONE = 'none', ELLIPSIS = '…', ATTR_CHANGE_LIST$1 = [ 'fontFamily', 'fontSize', 'fontStyle', @@ -13133,52 +12127,46 @@ 'wrap', 'ellipsis', 'letterSpacing', - ], - // cached variables - attrChangeListLen = ATTR_CHANGE_LIST$1.length; + ], + // cached variables + attrChangeListLen = ATTR_CHANGE_LIST$1.length; function normalizeFontFamily(fontFamily) { - return fontFamily - .split(',') - .map((family) => { - family = family.trim(); - const hasSpace = family.indexOf(' ') >= 0; - const hasQuotes = family.indexOf('"') >= 0 || family.indexOf("'") >= 0; - if (hasSpace && !hasQuotes) { - family = `"${family}"`; - } - return family; + return fontFamily + .split(',') + .map((family) => { + family = family.trim(); + const hasSpace = family.indexOf(' ') >= 0; + const hasQuotes = family.indexOf('"') >= 0 || family.indexOf("'") >= 0; + if (hasSpace && !hasQuotes) { + family = `"${family}"`; + } + return family; }) - .join(', '); + .join(', '); } var dummyContext; function getDummyContext() { - if (dummyContext) { + if (dummyContext) { + return dummyContext; + } + dummyContext = Util.createCanvasElement().getContext(CONTEXT_2D); return dummyContext; - } - dummyContext = Util.createCanvasElement().getContext(CONTEXT_2D); - return dummyContext; } function _fillFunc$1(context) { - context.fillText(this._partialText, this._partialTextX, this._partialTextY); + context.fillText(this._partialText, this._partialTextX, this._partialTextY); } function _strokeFunc$1(context) { - context.strokeText( - this._partialText, - this._partialTextX, - this._partialTextY - ); + context.strokeText(this._partialText, this._partialTextX, this._partialTextY); } function checkDefaultFill(config) { - config = config || {}; - // set default color to black - if ( - !config.fillLinearGradientColorStops && - !config.fillRadialGradientColorStops && - !config.fillPatternImage - ) { - config.fill = config.fill || 'black'; - } - return config; + config = config || {}; + // set default color to black + if (!config.fillLinearGradientColorStops && + !config.fillRadialGradientColorStops && + !config.fillPatternImage) { + config.fill = config.fill || 'black'; + } + return config; } /** * Text constructor @@ -13211,413 +12199,336 @@ * }); */ class Text extends Shape { - constructor(config) { - super(checkDefaultFill(config)); - this._partialTextX = 0; - this._partialTextY = 0; - // update text data for certain attr changes - for (var n = 0; n < attrChangeListLen; n++) { - this.on(ATTR_CHANGE_LIST$1[n] + CHANGE_KONVA, this._setTextData); - } - this._setTextData(); - } - _sceneFunc(context) { - var textArr = this.textArr, - textArrLen = textArr.length; - if (!this.text()) { - return; - } - var padding = this.padding(), - fontSize = this.fontSize(), - lineHeightPx = this.lineHeight() * fontSize, - verticalAlign = this.verticalAlign(), - alignY = 0, - align = this.align(), - totalWidth = this.getWidth(), - letterSpacing = this.letterSpacing(), - fill = this.fill(), - textDecoration = this.textDecoration(), - shouldUnderline = textDecoration.indexOf('underline') !== -1, - shouldLineThrough = textDecoration.indexOf('line-through') !== -1, - n; - var translateY = 0; - var translateY = lineHeightPx / 2; - var lineTranslateX = 0; - var lineTranslateY = 0; - context.setAttr('font', this._getContextFont()); - context.setAttr('textBaseline', MIDDLE); - context.setAttr('textAlign', LEFT); - // handle vertical alignment - if (verticalAlign === MIDDLE) { - alignY = - (this.getHeight() - textArrLen * lineHeightPx - padding * 2) / 2; - } else if (verticalAlign === BOTTOM) { - alignY = this.getHeight() - textArrLen * lineHeightPx - padding * 2; - } - context.translate(padding, alignY + padding); - // draw text lines - for (n = 0; n < textArrLen; n++) { - var lineTranslateX = 0; - var lineTranslateY = 0; - var obj = textArr[n], - text = obj.text, - width = obj.width, - lastLine = n !== textArrLen - 1, - spacesNumber, - oneWord, - lineWidth; - // horizontal alignment - context.save(); - if (align === RIGHT) { - lineTranslateX += totalWidth - width - padding * 2; - } else if (align === CENTER) { - lineTranslateX += (totalWidth - width - padding * 2) / 2; - } - if (shouldUnderline) { - context.save(); - context.beginPath(); - context.moveTo( - lineTranslateX, - translateY + lineTranslateY + Math.round(fontSize / 2) - ); - spacesNumber = text.split(' ').length - 1; - oneWord = spacesNumber === 0; - lineWidth = - align === JUSTIFY && lastLine && !oneWord - ? totalWidth - padding * 2 - : width; - context.lineTo( - lineTranslateX + Math.round(lineWidth), - translateY + lineTranslateY + Math.round(fontSize / 2) - ); - // I have no idea what is real ratio - // just /15 looks good enough - context.lineWidth = fontSize / 15; - context.strokeStyle = fill; - context.stroke(); - context.restore(); - } - if (shouldLineThrough) { - context.save(); - context.beginPath(); - context.moveTo(lineTranslateX, translateY + lineTranslateY); - spacesNumber = text.split(' ').length - 1; - oneWord = spacesNumber === 0; - lineWidth = - align === JUSTIFY && lastLine && !oneWord - ? totalWidth - padding * 2 - : width; - context.lineTo( - lineTranslateX + Math.round(lineWidth), - translateY + lineTranslateY - ); - context.lineWidth = fontSize / 15; - context.strokeStyle = fill; - context.stroke(); - context.restore(); - } - if (letterSpacing !== 0 || align === JUSTIFY) { - // var words = text.split(' '); - spacesNumber = text.split(' ').length - 1; - var array = stringToArray(text); - for (var li = 0; li < array.length; li++) { - var letter = array[li]; - // skip justify for the last line - if (letter === ' ' && n !== textArrLen - 1 && align === JUSTIFY) { - lineTranslateX += - (totalWidth - padding * 2 - width) / spacesNumber; - // context.translate( - // Math.floor((totalWidth - padding * 2 - width) / spacesNumber), - // 0 - // ); - } - this._partialTextX = lineTranslateX; - this._partialTextY = translateY + lineTranslateY; - this._partialText = letter; - context.fillStrokeShape(this); - lineTranslateX += this.measureSize(letter).width + letterSpacing; + constructor(config) { + super(checkDefaultFill(config)); + this._partialTextX = 0; + this._partialTextY = 0; + // update text data for certain attr changes + for (var n = 0; n < attrChangeListLen; n++) { + this.on(ATTR_CHANGE_LIST$1[n] + CHANGE_KONVA, this._setTextData); } - } else { - this._partialTextX = lineTranslateX; - this._partialTextY = translateY + lineTranslateY; - this._partialText = text; - context.fillStrokeShape(this); - } - context.restore(); - if (textArrLen > 1) { - translateY += lineHeightPx; - } + this._setTextData(); } - } - _hitFunc(context) { - var width = this.getWidth(), - height = this.getHeight(); - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - context.fillStrokeShape(this); - } - setText(text) { - var str = Util._isString(text) - ? text - : text === null || text === undefined - ? '' - : text + ''; - this._setAttr(TEXT, str); - return this; - } - getWidth() { - var isAuto = this.attrs.width === AUTO || this.attrs.width === undefined; - return isAuto - ? this.getTextWidth() + this.padding() * 2 - : this.attrs.width; - } - getHeight() { - var isAuto = - this.attrs.height === AUTO || this.attrs.height === undefined; - return isAuto - ? this.fontSize() * this.textArr.length * this.lineHeight() + - this.padding() * 2 - : this.attrs.height; - } - /** - * get pure text width without padding - * @method - * @name Konva.Text#getTextWidth - * @returns {Number} - */ - getTextWidth() { - return this.textWidth; - } - getTextHeight() { - Util.warn( - 'text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.' - ); - return this.textHeight; - } - /** - * measure string with the font of current text shape. - * That method can't handle multiline text. - * @method - * @name Konva.Text#measureSize - * @param {String} [text] text to measure - * @returns {Object} { width , height} of measured text - */ - measureSize(text) { - var _context = getDummyContext(), - fontSize = this.fontSize(), - metrics; - _context.save(); - _context.font = this._getContextFont(); - metrics = _context.measureText(text); - _context.restore(); - return { - width: metrics.width, - height: fontSize, - }; - } - _getContextFont() { - // IE don't want to work with usual font style - // bold was not working - // removing font variant will solve - // fix for: https://github.com/konvajs/konva/issues/94 - if (Konva$2.UA.isIE) { - return ( - this.fontStyle() + - SPACE + - this.fontSize() + - PX_SPACE + - this.fontFamily() - ); - } - return ( - this.fontStyle() + - SPACE + - this.fontVariant() + - SPACE + - (this.fontSize() + PX_SPACE) + - // wrap font family into " so font families with spaces works ok - normalizeFontFamily(this.fontFamily()) - ); - } - _addTextLine(line) { - if (this.align() === JUSTIFY) { - line = line.trim(); - } - var width = this._getTextWidth(line); - return this.textArr.push({ text: line, width: width }); - } - _getTextWidth(text) { - var letterSpacing = this.letterSpacing(); - var length = text.length; - return ( - getDummyContext().measureText(text).width + - (length ? letterSpacing * (length - 1) : 0) - ); - } - _setTextData() { - var lines = this.text().split('\n'), - fontSize = +this.fontSize(), - textWidth = 0, - lineHeightPx = this.lineHeight() * fontSize, - width = this.attrs.width, - height = this.attrs.height, - fixedWidth = width !== AUTO && width !== undefined, - fixedHeight = height !== AUTO && height !== undefined, - padding = this.padding(), - maxWidth = width - padding * 2, - maxHeightPx = height - padding * 2, - currentHeightPx = 0, - wrap = this.wrap(), - // align = this.align(), - shouldWrap = wrap !== NONE, - wrapAtWord = wrap !== CHAR && shouldWrap, - shouldAddEllipsis = this.ellipsis(); - this.textArr = []; - getDummyContext().font = this._getContextFont(); - var additionalWidth = shouldAddEllipsis - ? this._getTextWidth(ELLIPSIS) - : 0; - for (var i = 0, max = lines.length; i < max; ++i) { - var line = lines[i]; - var lineWidth = this._getTextWidth(line); - if (fixedWidth && lineWidth > maxWidth) { - /* - * if width is fixed and line does not fit entirely - * break the line into multiple fitting lines - */ - while (line.length > 0) { - /* - * use binary search to find the longest substring that - * that would fit in the specified width - */ - var low = 0, - high = line.length, - match = '', - matchWidth = 0; - while (low < high) { - var mid = (low + high) >>> 1, - substr = line.slice(0, mid + 1), - substrWidth = this._getTextWidth(substr) + additionalWidth; - if (substrWidth <= maxWidth) { - low = mid + 1; - match = substr; - matchWidth = substrWidth; - } else { - high = mid; + _sceneFunc(context) { + var textArr = this.textArr, textArrLen = textArr.length; + if (!this.text()) { + return; + } + var padding = this.padding(), fontSize = this.fontSize(), lineHeightPx = this.lineHeight() * fontSize, verticalAlign = this.verticalAlign(), alignY = 0, align = this.align(), totalWidth = this.getWidth(), letterSpacing = this.letterSpacing(), fill = this.fill(), textDecoration = this.textDecoration(), shouldUnderline = textDecoration.indexOf('underline') !== -1, shouldLineThrough = textDecoration.indexOf('line-through') !== -1, n; + var translateY = 0; + var translateY = lineHeightPx / 2; + var lineTranslateX = 0; + var lineTranslateY = 0; + context.setAttr('font', this._getContextFont()); + context.setAttr('textBaseline', MIDDLE); + context.setAttr('textAlign', LEFT); + // handle vertical alignment + if (verticalAlign === MIDDLE) { + alignY = (this.getHeight() - textArrLen * lineHeightPx - padding * 2) / 2; + } + else if (verticalAlign === BOTTOM) { + alignY = this.getHeight() - textArrLen * lineHeightPx - padding * 2; + } + context.translate(padding, alignY + padding); + // draw text lines + for (n = 0; n < textArrLen; n++) { + var lineTranslateX = 0; + var lineTranslateY = 0; + var obj = textArr[n], text = obj.text, width = obj.width, lastLine = n !== textArrLen - 1, spacesNumber, oneWord, lineWidth; + // horizontal alignment + context.save(); + if (align === RIGHT) { + lineTranslateX += totalWidth - width - padding * 2; } - } - /* - * 'low' is now the index of the substring end - * 'match' is the substring - * 'matchWidth' is the substring width in px - */ - if (match) { - // a fitting substring was found - if (wrapAtWord) { - // try to find a space or dash where wrapping could be done - var wrapIndex; - var nextChar = line[match.length]; - var nextIsSpaceOrDash = nextChar === SPACE || nextChar === DASH; - if (nextIsSpaceOrDash && matchWidth <= maxWidth) { - wrapIndex = match.length; - } else { - wrapIndex = - Math.max( - match.lastIndexOf(SPACE), - match.lastIndexOf(DASH) - ) + 1; - } - if (wrapIndex > 0) { - // re-cut the substring found at the space/dash position - low = wrapIndex; - match = match.slice(0, low); - matchWidth = this._getTextWidth(match); - } + else if (align === CENTER) { + lineTranslateX += (totalWidth - width - padding * 2) / 2; } - // if (align === 'right') { - match = match.trimRight(); - // } - this._addTextLine(match); - textWidth = Math.max(textWidth, matchWidth); - currentHeightPx += lineHeightPx; - if ( - !shouldWrap || - (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) - ) { - var lastLine = this.textArr[this.textArr.length - 1]; - if (lastLine) { - if (shouldAddEllipsis) { - var haveSpace = - this._getTextWidth(lastLine.text + ELLIPSIS) < maxWidth; - if (!haveSpace) { - lastLine.text = lastLine.text.slice( - 0, - lastLine.text.length - 3 - ); - } - this.textArr.splice(this.textArr.length - 1, 1); - this._addTextLine(lastLine.text + ELLIPSIS); + if (shouldUnderline) { + context.save(); + context.beginPath(); + context.moveTo(lineTranslateX, translateY + lineTranslateY + Math.round(fontSize / 2)); + spacesNumber = text.split(' ').length - 1; + oneWord = spacesNumber === 0; + lineWidth = + align === JUSTIFY && lastLine && !oneWord + ? totalWidth - padding * 2 + : width; + context.lineTo(lineTranslateX + Math.round(lineWidth), translateY + lineTranslateY + Math.round(fontSize / 2)); + // I have no idea what is real ratio + // just /15 looks good enough + context.lineWidth = fontSize / 15; + context.strokeStyle = fill; + context.stroke(); + context.restore(); + } + if (shouldLineThrough) { + context.save(); + context.beginPath(); + context.moveTo(lineTranslateX, translateY + lineTranslateY); + spacesNumber = text.split(' ').length - 1; + oneWord = spacesNumber === 0; + lineWidth = + align === JUSTIFY && lastLine && !oneWord + ? totalWidth - padding * 2 + : width; + context.lineTo(lineTranslateX + Math.round(lineWidth), translateY + lineTranslateY); + context.lineWidth = fontSize / 15; + context.strokeStyle = fill; + context.stroke(); + context.restore(); + } + if (letterSpacing !== 0 || align === JUSTIFY) { + // var words = text.split(' '); + spacesNumber = text.split(' ').length - 1; + var array = stringToArray(text); + for (var li = 0; li < array.length; li++) { + var letter = array[li]; + // skip justify for the last line + if (letter === ' ' && n !== textArrLen - 1 && align === JUSTIFY) { + lineTranslateX += (totalWidth - padding * 2 - width) / spacesNumber; + // context.translate( + // Math.floor((totalWidth - padding * 2 - width) / spacesNumber), + // 0 + // ); + } + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = letter; + context.fillStrokeShape(this); + lineTranslateX += this.measureSize(letter).width + letterSpacing; } - } - /* - * stop wrapping if wrapping is disabled or if adding - * one more line would overflow the fixed height - */ - break; } - line = line.slice(low); - line = line.trimLeft(); - if (line.length > 0) { - // Check if the remaining text would fit on one line - lineWidth = this._getTextWidth(line); - if (lineWidth <= maxWidth) { - // if it does, add the line and break out of the loop + else { + this._partialTextX = lineTranslateX; + this._partialTextY = translateY + lineTranslateY; + this._partialText = text; + context.fillStrokeShape(this); + } + context.restore(); + if (textArrLen > 1) { + translateY += lineHeightPx; + } + } + } + _hitFunc(context) { + var width = this.getWidth(), height = this.getHeight(); + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + context.fillStrokeShape(this); + } + setText(text) { + var str = Util._isString(text) + ? text + : text === null || text === undefined + ? '' + : text + ''; + this._setAttr(TEXT, str); + return this; + } + getWidth() { + var isAuto = this.attrs.width === AUTO || this.attrs.width === undefined; + return isAuto ? this.getTextWidth() + this.padding() * 2 : this.attrs.width; + } + getHeight() { + var isAuto = this.attrs.height === AUTO || this.attrs.height === undefined; + return isAuto + ? this.fontSize() * this.textArr.length * this.lineHeight() + + this.padding() * 2 + : this.attrs.height; + } + /** + * get pure text width without padding + * @method + * @name Konva.Text#getTextWidth + * @returns {Number} + */ + getTextWidth() { + return this.textWidth; + } + getTextHeight() { + Util.warn('text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.'); + return this.textHeight; + } + /** + * measure string with the font of current text shape. + * That method can't handle multiline text. + * @method + * @name Konva.Text#measureSize + * @param {String} [text] text to measure + * @returns {Object} { width , height} of measured text + */ + measureSize(text) { + var _context = getDummyContext(), fontSize = this.fontSize(), metrics; + _context.save(); + _context.font = this._getContextFont(); + metrics = _context.measureText(text); + _context.restore(); + return { + width: metrics.width, + height: fontSize, + }; + } + _getContextFont() { + return (this.fontStyle() + + SPACE + + this.fontVariant() + + SPACE + + (this.fontSize() + PX_SPACE) + + // wrap font family into " so font families with spaces works ok + normalizeFontFamily(this.fontFamily())); + } + _addTextLine(line) { + if (this.align() === JUSTIFY) { + line = line.trim(); + } + var width = this._getTextWidth(line); + return this.textArr.push({ text: line, width: width }); + } + _getTextWidth(text) { + var letterSpacing = this.letterSpacing(); + var length = text.length; + return (getDummyContext().measureText(text).width + + (length ? letterSpacing * (length - 1) : 0)); + } + _setTextData() { + var lines = this.text().split('\n'), fontSize = +this.fontSize(), textWidth = 0, lineHeightPx = this.lineHeight() * fontSize, width = this.attrs.width, height = this.attrs.height, fixedWidth = width !== AUTO && width !== undefined, fixedHeight = height !== AUTO && height !== undefined, padding = this.padding(), maxWidth = width - padding * 2, maxHeightPx = height - padding * 2, currentHeightPx = 0, wrap = this.wrap(), + // align = this.align(), + shouldWrap = wrap !== NONE, wrapAtWord = wrap !== CHAR && shouldWrap, shouldAddEllipsis = this.ellipsis(); + this.textArr = []; + getDummyContext().font = this._getContextFont(); + var additionalWidth = shouldAddEllipsis ? this._getTextWidth(ELLIPSIS) : 0; + for (var i = 0, max = lines.length; i < max; ++i) { + var line = lines[i]; + var lineWidth = this._getTextWidth(line); + if (fixedWidth && lineWidth > maxWidth) { + /* + * if width is fixed and line does not fit entirely + * break the line into multiple fitting lines + */ + while (line.length > 0) { + /* + * use binary search to find the longest substring that + * that would fit in the specified width + */ + var low = 0, high = line.length, match = '', matchWidth = 0; + while (low < high) { + var mid = (low + high) >>> 1, substr = line.slice(0, mid + 1), substrWidth = this._getTextWidth(substr) + additionalWidth; + if (substrWidth <= maxWidth) { + low = mid + 1; + match = substr; + matchWidth = substrWidth; + } + else { + high = mid; + } + } + /* + * 'low' is now the index of the substring end + * 'match' is the substring + * 'matchWidth' is the substring width in px + */ + if (match) { + // a fitting substring was found + if (wrapAtWord) { + // try to find a space or dash where wrapping could be done + var wrapIndex; + var nextChar = line[match.length]; + var nextIsSpaceOrDash = nextChar === SPACE || nextChar === DASH; + if (nextIsSpaceOrDash && matchWidth <= maxWidth) { + wrapIndex = match.length; + } + else { + wrapIndex = + Math.max(match.lastIndexOf(SPACE), match.lastIndexOf(DASH)) + + 1; + } + if (wrapIndex > 0) { + // re-cut the substring found at the space/dash position + low = wrapIndex; + match = match.slice(0, low); + matchWidth = this._getTextWidth(match); + } + } + // if (align === 'right') { + match = match.trimRight(); + // } + this._addTextLine(match); + textWidth = Math.max(textWidth, matchWidth); + currentHeightPx += lineHeightPx; + if (!shouldWrap || + (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx)) { + var lastLine = this.textArr[this.textArr.length - 1]; + if (lastLine) { + if (shouldAddEllipsis) { + var haveSpace = this._getTextWidth(lastLine.text + ELLIPSIS) < maxWidth; + if (!haveSpace) { + lastLine.text = lastLine.text.slice(0, lastLine.text.length - 3); + } + this.textArr.splice(this.textArr.length - 1, 1); + this._addTextLine(lastLine.text + ELLIPSIS); + } + } + /* + * stop wrapping if wrapping is disabled or if adding + * one more line would overflow the fixed height + */ + break; + } + line = line.slice(low); + line = line.trimLeft(); + if (line.length > 0) { + // Check if the remaining text would fit on one line + lineWidth = this._getTextWidth(line); + if (lineWidth <= maxWidth) { + // if it does, add the line and break out of the loop + this._addTextLine(line); + currentHeightPx += lineHeightPx; + textWidth = Math.max(textWidth, lineWidth); + break; + } + } + } + else { + // not even one character could fit in the element, abort + break; + } + } + } + else { + // element width is automatically adjusted to max line width this._addTextLine(line); currentHeightPx += lineHeightPx; textWidth = Math.max(textWidth, lineWidth); - break; - } } - } else { - // not even one character could fit in the element, abort - break; - } + // if element height is fixed, abort if adding one more line would overflow + if (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) { + break; + } } - } else { - // element width is automatically adjusted to max line width - this._addTextLine(line); - currentHeightPx += lineHeightPx; - textWidth = Math.max(textWidth, lineWidth); - } - // if element height is fixed, abort if adding one more line would overflow - if (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) { - break; - } + this.textHeight = fontSize; + // var maxTextWidth = 0; + // for(var j = 0; j < this.textArr.length; j++) { + // maxTextWidth = Math.max(maxTextWidth, this.textArr[j].width); + // } + this.textWidth = textWidth; + } + // for text we can't disable stroke scaling + // if we do, the result will be unexpected + getStrokeScaleEnabled() { + return true; } - this.textHeight = fontSize; - // var maxTextWidth = 0; - // for(var j = 0; j < this.textArr.length; j++) { - // maxTextWidth = Math.max(maxTextWidth, this.textArr[j].width); - // } - this.textWidth = textWidth; - } - // for text we can't disable stroke scaling - // if we do, the result will be unexpected - getStrokeScaleEnabled() { - return true; - } } Text.prototype._fillFunc = _fillFunc$1; Text.prototype._strokeFunc = _strokeFunc$1; Text.prototype.className = TEXT_UPPER; Text.prototype._attrsAffectingSize = [ - 'text', - 'fontSize', - 'padding', - 'wrap', - 'lineHeight', - 'letterSpacing', + 'text', + 'fontSize', + 'padding', + 'wrap', + 'lineHeight', + 'letterSpacing', ]; _registerNode(Text); /** @@ -13843,15 +12754,14 @@ * // underline and strike text * text.textDecoration('underline line-through'); */ - Factory.addGetterSetter(Text, 'textDecoration', ''); - - var EMPTY_STRING = '', - NORMAL = 'normal'; + Factory.addGetterSetter(Text, 'textDecoration', ''); + + var EMPTY_STRING = '', NORMAL = 'normal'; function _fillFunc(context) { - context.fillText(this.partialText, 0, 0); + context.fillText(this.partialText, 0, 0); } function _strokeFunc(context) { - context.strokeText(this.partialText, 0, 0); + context.strokeText(this.partialText, 0, 0); } /** * Path constructor. @@ -13899,407 +12809,352 @@ * }); */ class TextPath extends Shape { - constructor(config) { - // call super constructor - super(config); - this.dummyCanvas = Util.createCanvasElement(); - this.dataArray = []; - this.dataArray = Path.parsePathData(this.attrs.data); - this.on('dataChange.konva', function () { - this.dataArray = Path.parsePathData(this.attrs.data); - this._setTextData(); - }); - // update text data for certain attr changes - this.on( - 'textChange.konva alignChange.konva letterSpacingChange.konva kerningFuncChange.konva fontSizeChange.konva', - this._setTextData - ); - if (config && config['getKerning']) { - Util.warn( - 'getKerning TextPath API is deprecated. Please use "kerningFunc" instead.' - ); - this.kerningFunc(config['getKerning']); - } - this._setTextData(); - } - _sceneFunc(context) { - context.setAttr('font', this._getContextFont()); - context.setAttr('textBaseline', this.textBaseline()); - context.setAttr('textAlign', 'left'); - context.save(); - var textDecoration = this.textDecoration(); - var fill = this.fill(); - var fontSize = this.fontSize(); - var glyphInfo = this.glyphInfo; - if (textDecoration === 'underline') { - context.beginPath(); - } - for (var i = 0; i < glyphInfo.length; i++) { - context.save(); - var p0 = glyphInfo[i].p0; - context.translate(p0.x, p0.y); - context.rotate(glyphInfo[i].rotation); - this.partialText = glyphInfo[i].text; - context.fillStrokeShape(this); - if (textDecoration === 'underline') { - if (i === 0) { - context.moveTo(0, fontSize / 2 + 1); + constructor(config) { + // call super constructor + super(config); + this.dummyCanvas = Util.createCanvasElement(); + this.dataArray = []; + this.dataArray = Path.parsePathData(this.attrs.data); + this.on('dataChange.konva', function () { + this.dataArray = Path.parsePathData(this.attrs.data); + this._setTextData(); + }); + // update text data for certain attr changes + this.on('textChange.konva alignChange.konva letterSpacingChange.konva kerningFuncChange.konva fontSizeChange.konva', this._setTextData); + if (config && config['getKerning']) { + Util.warn('getKerning TextPath API is deprecated. Please use "kerningFunc" instead.'); + this.kerningFunc(config['getKerning']); } - context.lineTo(fontSize, fontSize / 2 + 1); - } - context.restore(); - //// To assist with debugging visually, uncomment following - // - // if (i % 2) context.strokeStyle = 'cyan'; - // else context.strokeStyle = 'green'; - // var p1 = glyphInfo[i].p1; - // context.moveTo(p0.x, p0.y); - // context.lineTo(p1.x, p1.y); - // context.stroke(); + this._setTextData(); } - if (textDecoration === 'underline') { - context.strokeStyle = fill; - context.lineWidth = fontSize / 20; - context.stroke(); - } - context.restore(); - } - _hitFunc(context) { - context.beginPath(); - var glyphInfo = this.glyphInfo; - if (glyphInfo.length >= 1) { - var p0 = glyphInfo[0].p0; - context.moveTo(p0.x, p0.y); - } - for (var i = 0; i < glyphInfo.length; i++) { - var p1 = glyphInfo[i].p1; - context.lineTo(p1.x, p1.y); - } - context.setAttr('lineWidth', this.fontSize()); - context.setAttr('strokeStyle', this.colorKey); - context.stroke(); - } - /** - * get text width in pixels - * @method - * @name Konva.TextPath#getTextWidth - */ - getTextWidth() { - return this.textWidth; - } - getTextHeight() { - Util.warn( - 'text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.' - ); - return this.textHeight; - } - setText(text) { - return Text.prototype.setText.call(this, text); - } - _getContextFont() { - return Text.prototype._getContextFont.call(this); - } - _getTextSize(text) { - var dummyCanvas = this.dummyCanvas; - var _context = dummyCanvas.getContext('2d'); - _context.save(); - _context.font = this._getContextFont(); - var metrics = _context.measureText(text); - _context.restore(); - return { - width: metrics.width, - height: parseInt(this.attrs.fontSize, 10), - }; - } - _setTextData() { - var that = this; - var size = this._getTextSize(this.attrs.text); - var letterSpacing = this.letterSpacing(); - var align = this.align(); - var kerningFunc = this.kerningFunc(); - this.textWidth = size.width; - this.textHeight = size.height; - var textFullWidth = Math.max( - this.textWidth + ((this.attrs.text || '').length - 1) * letterSpacing, - 0 - ); - this.glyphInfo = []; - var fullPathWidth = 0; - for (var l = 0; l < that.dataArray.length; l++) { - if (that.dataArray[l].pathLength > 0) { - fullPathWidth += that.dataArray[l].pathLength; - } - } - var offset = 0; - if (align === 'center') { - offset = Math.max(0, fullPathWidth / 2 - textFullWidth / 2); - } - if (align === 'right') { - offset = Math.max(0, fullPathWidth - textFullWidth); - } - var charArr = stringToArray(this.text()); - var spacesNumber = this.text().split(' ').length - 1; - var p0, p1, pathCmd; - var pIndex = -1; - var currentT = 0; - // var sumLength = 0; - // for(var j = 0; j < that.dataArray.length; j++) { - // if(that.dataArray[j].pathLength > 0) { - // - // if (sumLength + that.dataArray[j].pathLength > offset) {} - // fullPathWidth += that.dataArray[j].pathLength; - // } - // } - var getNextPathSegment = function () { - currentT = 0; - var pathData = that.dataArray; - for (var j = pIndex + 1; j < pathData.length; j++) { - if (pathData[j].pathLength > 0) { - pIndex = j; - return pathData[j]; - } else if (pathData[j].command === 'M') { - p0 = { - x: pathData[j].points[0], - y: pathData[j].points[1], - }; + _sceneFunc(context) { + context.setAttr('font', this._getContextFont()); + context.setAttr('textBaseline', this.textBaseline()); + context.setAttr('textAlign', 'left'); + context.save(); + var textDecoration = this.textDecoration(); + var fill = this.fill(); + var fontSize = this.fontSize(); + var glyphInfo = this.glyphInfo; + if (textDecoration === 'underline') { + context.beginPath(); } - } - return {}; - }; - var findSegmentToFitCharacter = function (c) { - var glyphWidth = that._getTextSize(c).width + letterSpacing; - if (c === ' ' && align === 'justify') { - glyphWidth += (fullPathWidth - textFullWidth) / spacesNumber; - } - var currLen = 0; - var attempts = 0; - p1 = undefined; - while ( - Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 && - attempts < 20 - ) { - attempts++; - var cumulativePathLength = currLen; - while (pathCmd === undefined) { - pathCmd = getNextPathSegment(); - if ( - pathCmd && - cumulativePathLength + pathCmd.pathLength < glyphWidth - ) { - cumulativePathLength += pathCmd.pathLength; - pathCmd = undefined; - } - } - if (pathCmd === {} || p0 === undefined) { - return undefined; - } - var needNewSegment = false; - switch (pathCmd.command) { - case 'L': - if ( - Path.getLineLength( - p0.x, - p0.y, - pathCmd.points[0], - pathCmd.points[1] - ) > glyphWidth - ) { - p1 = Path.getPointOnLine( - glyphWidth, - p0.x, - p0.y, - pathCmd.points[0], - pathCmd.points[1], - p0.x, - p0.y - ); - } else { - pathCmd = undefined; + for (var i = 0; i < glyphInfo.length; i++) { + context.save(); + var p0 = glyphInfo[i].p0; + context.translate(p0.x, p0.y); + context.rotate(glyphInfo[i].rotation); + this.partialText = glyphInfo[i].text; + context.fillStrokeShape(this); + if (textDecoration === 'underline') { + if (i === 0) { + context.moveTo(0, fontSize / 2 + 1); + } + context.lineTo(fontSize, fontSize / 2 + 1); } - break; - case 'A': - var start = pathCmd.points[4]; - // 4 = theta - var dTheta = pathCmd.points[5]; - // 5 = dTheta - var end = pathCmd.points[4] + dTheta; - if (currentT === 0) { - currentT = start + 0.00000001; - } else if (glyphWidth > currLen) { - // Just in case start is 0 - currentT += ((Math.PI / 180.0) * dTheta) / Math.abs(dTheta); - } else { - currentT -= ((Math.PI / 360.0) * dTheta) / Math.abs(dTheta); - } - // Credit for bug fix: @therth https://github.com/ericdrowell/KonvaJS/issues/249 - // Old code failed to render text along arc of this path: "M 50 50 a 150 50 0 0 1 250 50 l 50 0" - if ( - (dTheta < 0 && currentT < end) || - (dTheta >= 0 && currentT > end) - ) { - currentT = end; - needNewSegment = true; - } - p1 = Path.getPointOnEllipticalArc( - pathCmd.points[0], - pathCmd.points[1], - pathCmd.points[2], - pathCmd.points[3], - currentT, - pathCmd.points[6] - ); - break; - case 'C': - if (currentT === 0) { - if (glyphWidth > pathCmd.pathLength) { - currentT = 0.00000001; - } else { - currentT = glyphWidth / pathCmd.pathLength; - } - } else if (glyphWidth > currLen) { - currentT += (glyphWidth - currLen) / pathCmd.pathLength / 2; - } else { - currentT = Math.max( - currentT - (currLen - glyphWidth) / pathCmd.pathLength / 2, - 0 - ); - } - if (currentT > 1.0) { - currentT = 1.0; - needNewSegment = true; - } - p1 = Path.getPointOnCubicBezier( - currentT, - pathCmd.start.x, - pathCmd.start.y, - pathCmd.points[0], - pathCmd.points[1], - pathCmd.points[2], - pathCmd.points[3], - pathCmd.points[4], - pathCmd.points[5] - ); - break; - case 'Q': - if (currentT === 0) { - currentT = glyphWidth / pathCmd.pathLength; - } else if (glyphWidth > currLen) { - currentT += (glyphWidth - currLen) / pathCmd.pathLength; - } else { - currentT -= (currLen - glyphWidth) / pathCmd.pathLength; - } - if (currentT > 1.0) { - currentT = 1.0; - needNewSegment = true; - } - p1 = Path.getPointOnQuadraticBezier( - currentT, - pathCmd.start.x, - pathCmd.start.y, - pathCmd.points[0], - pathCmd.points[1], - pathCmd.points[2], - pathCmd.points[3] - ); - break; + context.restore(); + //// To assist with debugging visually, uncomment following + // + // if (i % 2) context.strokeStyle = 'cyan'; + // else context.strokeStyle = 'green'; + // var p1 = glyphInfo[i].p1; + // context.moveTo(p0.x, p0.y); + // context.lineTo(p1.x, p1.y); + // context.stroke(); } - if (p1 !== undefined) { - currLen = Path.getLineLength(p0.x, p0.y, p1.x, p1.y); + if (textDecoration === 'underline') { + context.strokeStyle = fill; + context.lineWidth = fontSize / 20; + context.stroke(); } - if (needNewSegment) { - needNewSegment = false; - pathCmd = undefined; + context.restore(); + } + _hitFunc(context) { + context.beginPath(); + var glyphInfo = this.glyphInfo; + if (glyphInfo.length >= 1) { + var p0 = glyphInfo[0].p0; + context.moveTo(p0.x, p0.y); } - } - }; - // fake search for offset, this is the best approach - var testChar = 'C'; - var glyphWidth = that._getTextSize(testChar).width + letterSpacing; - var lettersInOffset = offset / glyphWidth - 1; - // the idea is simple - // try to draw testChar until we fill offset - for (var k = 0; k < lettersInOffset; k++) { - findSegmentToFitCharacter(testChar); - if (p0 === undefined || p1 === undefined) { - break; - } - p0 = p1; - } - for (var i = 0; i < charArr.length; i++) { - // Find p1 such that line segment between p0 and p1 is approx. width of glyph - findSegmentToFitCharacter(charArr[i]); - if (p0 === undefined || p1 === undefined) { - break; - } - var width = Path.getLineLength(p0.x, p0.y, p1.x, p1.y); - var kern = 0; - if (kerningFunc) { - try { - // getKerning is a user provided getter. Make sure it never breaks our logic - kern = kerningFunc(charArr[i - 1], charArr[i]) * this.fontSize(); - } catch (e) { - kern = 0; + for (var i = 0; i < glyphInfo.length; i++) { + var p1 = glyphInfo[i].p1; + context.lineTo(p1.x, p1.y); } - } - p0.x += kern; - p1.x += kern; - this.textWidth += kern; - var midpoint = Path.getPointOnLine( - kern + width / 2.0, - p0.x, - p0.y, - p1.x, - p1.y - ); - var rotation = Math.atan2(p1.y - p0.y, p1.x - p0.x); - this.glyphInfo.push({ - transposeX: midpoint.x, - transposeY: midpoint.y, - text: charArr[i], - rotation: rotation, - p0: p0, - p1: p1, - }); - p0 = p1; + context.setAttr('lineWidth', this.fontSize()); + context.setAttr('strokeStyle', this.colorKey); + context.stroke(); } - } - getSelfRect() { - if (!this.glyphInfo.length) { - return { - x: 0, - y: 0, - width: 0, - height: 0, - }; + /** + * get text width in pixels + * @method + * @name Konva.TextPath#getTextWidth + */ + getTextWidth() { + return this.textWidth; } - var points = []; - this.glyphInfo.forEach(function (info) { - points.push(info.p0.x); - points.push(info.p0.y); - points.push(info.p1.x); - points.push(info.p1.y); - }); - var minX = points[0] || 0; - var maxX = points[0] || 0; - var minY = points[1] || 0; - var maxY = points[1] || 0; - var x, y; - for (var i = 0; i < points.length / 2; i++) { - x = points[i * 2]; - y = points[i * 2 + 1]; - minX = Math.min(minX, x); - maxX = Math.max(maxX, x); - minY = Math.min(minY, y); - maxY = Math.max(maxY, y); + getTextHeight() { + Util.warn('text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.'); + return this.textHeight; + } + setText(text) { + return Text.prototype.setText.call(this, text); + } + _getContextFont() { + return Text.prototype._getContextFont.call(this); + } + _getTextSize(text) { + var dummyCanvas = this.dummyCanvas; + var _context = dummyCanvas.getContext('2d'); + _context.save(); + _context.font = this._getContextFont(); + var metrics = _context.measureText(text); + _context.restore(); + return { + width: metrics.width, + height: parseInt(this.attrs.fontSize, 10), + }; + } + _setTextData() { + var that = this; + var size = this._getTextSize(this.attrs.text); + var letterSpacing = this.letterSpacing(); + var align = this.align(); + var kerningFunc = this.kerningFunc(); + this.textWidth = size.width; + this.textHeight = size.height; + var textFullWidth = Math.max(this.textWidth + ((this.attrs.text || '').length - 1) * letterSpacing, 0); + this.glyphInfo = []; + var fullPathWidth = 0; + for (var l = 0; l < that.dataArray.length; l++) { + if (that.dataArray[l].pathLength > 0) { + fullPathWidth += that.dataArray[l].pathLength; + } + } + var offset = 0; + if (align === 'center') { + offset = Math.max(0, fullPathWidth / 2 - textFullWidth / 2); + } + if (align === 'right') { + offset = Math.max(0, fullPathWidth - textFullWidth); + } + var charArr = stringToArray(this.text()); + var spacesNumber = this.text().split(' ').length - 1; + var p0, p1, pathCmd; + var pIndex = -1; + var currentT = 0; + // var sumLength = 0; + // for(var j = 0; j < that.dataArray.length; j++) { + // if(that.dataArray[j].pathLength > 0) { + // + // if (sumLength + that.dataArray[j].pathLength > offset) {} + // fullPathWidth += that.dataArray[j].pathLength; + // } + // } + var getNextPathSegment = function () { + currentT = 0; + var pathData = that.dataArray; + for (var j = pIndex + 1; j < pathData.length; j++) { + if (pathData[j].pathLength > 0) { + pIndex = j; + return pathData[j]; + } + else if (pathData[j].command === 'M') { + p0 = { + x: pathData[j].points[0], + y: pathData[j].points[1], + }; + } + } + return {}; + }; + var findSegmentToFitCharacter = function (c) { + var glyphWidth = that._getTextSize(c).width + letterSpacing; + if (c === ' ' && align === 'justify') { + glyphWidth += (fullPathWidth - textFullWidth) / spacesNumber; + } + var currLen = 0; + var attempts = 0; + p1 = undefined; + while (Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 && + attempts < 20) { + attempts++; + var cumulativePathLength = currLen; + while (pathCmd === undefined) { + pathCmd = getNextPathSegment(); + if (pathCmd && + cumulativePathLength + pathCmd.pathLength < glyphWidth) { + cumulativePathLength += pathCmd.pathLength; + pathCmd = undefined; + } + } + if (pathCmd === {} || p0 === undefined) { + return undefined; + } + var needNewSegment = false; + switch (pathCmd.command) { + case 'L': + if (Path.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) { + p1 = Path.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y); + } + else { + pathCmd = undefined; + } + break; + case 'A': + var start = pathCmd.points[4]; + // 4 = theta + var dTheta = pathCmd.points[5]; + // 5 = dTheta + var end = pathCmd.points[4] + dTheta; + if (currentT === 0) { + currentT = start + 0.00000001; + } + else if (glyphWidth > currLen) { + // Just in case start is 0 + currentT += ((Math.PI / 180.0) * dTheta) / Math.abs(dTheta); + } + else { + currentT -= ((Math.PI / 360.0) * dTheta) / Math.abs(dTheta); + } + // Credit for bug fix: @therth https://github.com/ericdrowell/KonvaJS/issues/249 + // Old code failed to render text along arc of this path: "M 50 50 a 150 50 0 0 1 250 50 l 50 0" + if ((dTheta < 0 && currentT < end) || + (dTheta >= 0 && currentT > end)) { + currentT = end; + needNewSegment = true; + } + p1 = Path.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]); + break; + case 'C': + if (currentT === 0) { + if (glyphWidth > pathCmd.pathLength) { + currentT = 0.00000001; + } + else { + currentT = glyphWidth / pathCmd.pathLength; + } + } + else if (glyphWidth > currLen) { + currentT += (glyphWidth - currLen) / pathCmd.pathLength / 2; + } + else { + currentT = Math.max(currentT - (currLen - glyphWidth) / pathCmd.pathLength / 2, 0); + } + if (currentT > 1.0) { + currentT = 1.0; + needNewSegment = true; + } + p1 = Path.getPointOnCubicBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], pathCmd.points[4], pathCmd.points[5]); + break; + case 'Q': + if (currentT === 0) { + currentT = glyphWidth / pathCmd.pathLength; + } + else if (glyphWidth > currLen) { + currentT += (glyphWidth - currLen) / pathCmd.pathLength; + } + else { + currentT -= (currLen - glyphWidth) / pathCmd.pathLength; + } + if (currentT > 1.0) { + currentT = 1.0; + needNewSegment = true; + } + p1 = Path.getPointOnQuadraticBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3]); + break; + } + if (p1 !== undefined) { + currLen = Path.getLineLength(p0.x, p0.y, p1.x, p1.y); + } + if (needNewSegment) { + needNewSegment = false; + pathCmd = undefined; + } + } + }; + // fake search for offset, this is the best approach + var testChar = 'C'; + var glyphWidth = that._getTextSize(testChar).width + letterSpacing; + var lettersInOffset = offset / glyphWidth - 1; + // the idea is simple + // try to draw testChar until we fill offset + for (var k = 0; k < lettersInOffset; k++) { + findSegmentToFitCharacter(testChar); + if (p0 === undefined || p1 === undefined) { + break; + } + p0 = p1; + } + for (var i = 0; i < charArr.length; i++) { + // Find p1 such that line segment between p0 and p1 is approx. width of glyph + findSegmentToFitCharacter(charArr[i]); + if (p0 === undefined || p1 === undefined) { + break; + } + var width = Path.getLineLength(p0.x, p0.y, p1.x, p1.y); + var kern = 0; + if (kerningFunc) { + try { + // getKerning is a user provided getter. Make sure it never breaks our logic + kern = kerningFunc(charArr[i - 1], charArr[i]) * this.fontSize(); + } + catch (e) { + kern = 0; + } + } + p0.x += kern; + p1.x += kern; + this.textWidth += kern; + var midpoint = Path.getPointOnLine(kern + width / 2.0, p0.x, p0.y, p1.x, p1.y); + var rotation = Math.atan2(p1.y - p0.y, p1.x - p0.x); + this.glyphInfo.push({ + transposeX: midpoint.x, + transposeY: midpoint.y, + text: charArr[i], + rotation: rotation, + p0: p0, + p1: p1, + }); + p0 = p1; + } + } + getSelfRect() { + if (!this.glyphInfo.length) { + return { + x: 0, + y: 0, + width: 0, + height: 0, + }; + } + var points = []; + this.glyphInfo.forEach(function (info) { + points.push(info.p0.x); + points.push(info.p0.y); + points.push(info.p1.x); + points.push(info.p1.y); + }); + var minX = points[0] || 0; + var maxX = points[0] || 0; + var minY = points[1] || 0; + var maxY = points[1] || 0; + var x, y; + for (var i = 0; i < points.length / 2; i++) { + x = points[i * 2]; + y = points[i * 2 + 1]; + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + } + var fontSize = this.fontSize(); + return { + x: minX - fontSize / 2, + y: minY - fontSize / 2, + width: maxX - minX + fontSize, + height: maxY - minY + fontSize, + }; } - var fontSize = this.fontSize(); - return { - x: minX - fontSize / 2, - y: minY - fontSize / 2, - width: maxX - minX + fontSize, - height: maxY - minY + fontSize, - }; - } } TextPath.prototype._fillFunc = _fillFunc; TextPath.prototype._strokeFunc = _strokeFunc; @@ -14469,148 +13324,144 @@ * return 1; * }); */ - Factory.addGetterSetter(TextPath, 'kerningFunc', null); - + Factory.addGetterSetter(TextPath, 'kerningFunc', null); + var EVENTS_NAME = 'tr-konva'; var ATTR_CHANGE_LIST = [ - 'resizeEnabledChange', - 'rotateAnchorOffsetChange', - 'rotateEnabledChange', - 'enabledAnchorsChange', - 'anchorSizeChange', - 'borderEnabledChange', - 'borderStrokeChange', - 'borderStrokeWidthChange', - 'borderDashChange', - 'anchorStrokeChange', - 'anchorStrokeWidthChange', - 'anchorFillChange', - 'anchorCornerRadiusChange', - 'ignoreStrokeChange', + 'resizeEnabledChange', + 'rotateAnchorOffsetChange', + 'rotateEnabledChange', + 'enabledAnchorsChange', + 'anchorSizeChange', + 'borderEnabledChange', + 'borderStrokeChange', + 'borderStrokeWidthChange', + 'borderDashChange', + 'anchorStrokeChange', + 'anchorStrokeWidthChange', + 'anchorFillChange', + 'anchorCornerRadiusChange', + 'ignoreStrokeChange', ] - .map((e) => e + `.${EVENTS_NAME}`) - .join(' '); + .map((e) => e + `.${EVENTS_NAME}`) + .join(' '); var NODES_RECT = 'nodesRect'; var TRANSFORM_CHANGE_STR = [ - 'widthChange', - 'heightChange', - 'scaleXChange', - 'scaleYChange', - 'skewXChange', - 'skewYChange', - 'rotationChange', - 'offsetXChange', - 'offsetYChange', - 'transformsEnabledChange', - 'strokeWidthChange', + 'widthChange', + 'heightChange', + 'scaleXChange', + 'scaleYChange', + 'skewXChange', + 'skewYChange', + 'rotationChange', + 'offsetXChange', + 'offsetYChange', + 'transformsEnabledChange', + 'strokeWidthChange', ] - .map((e) => e + `.${EVENTS_NAME}`) - .join(' '); + .map((e) => e + `.${EVENTS_NAME}`) + .join(' '); var ANGLES = { - 'top-left': -45, - 'top-center': 0, - 'top-right': 45, - 'middle-right': -90, - 'middle-left': 90, - 'bottom-left': -135, - 'bottom-center': 180, - 'bottom-right': 135, + 'top-left': -45, + 'top-center': 0, + 'top-right': 45, + 'middle-right': -90, + 'middle-left': 90, + 'bottom-left': -135, + 'bottom-center': 180, + 'bottom-right': 135, }; const TOUCH_DEVICE = 'ontouchstart' in Konva$2._global; function getCursor(anchorName, rad) { - if (anchorName === 'rotater') { - return 'crosshair'; - } - rad += Util._degToRad(ANGLES[anchorName] || 0); - var angle = ((Util._radToDeg(rad) % 360) + 360) % 360; - if ( - Util._inRange(angle, 315 + 22.5, 360) || - Util._inRange(angle, 0, 22.5) - ) { - // TOP - return 'ns-resize'; - } else if (Util._inRange(angle, 45 - 22.5, 45 + 22.5)) { - // TOP - RIGHT - return 'nesw-resize'; - } else if (Util._inRange(angle, 90 - 22.5, 90 + 22.5)) { - // RIGHT - return 'ew-resize'; - } else if (Util._inRange(angle, 135 - 22.5, 135 + 22.5)) { - // BOTTOM - RIGHT - return 'nwse-resize'; - } else if (Util._inRange(angle, 180 - 22.5, 180 + 22.5)) { - // BOTTOM - return 'ns-resize'; - } else if (Util._inRange(angle, 225 - 22.5, 225 + 22.5)) { - // BOTTOM - LEFT - return 'nesw-resize'; - } else if (Util._inRange(angle, 270 - 22.5, 270 + 22.5)) { - // RIGHT - return 'ew-resize'; - } else if (Util._inRange(angle, 315 - 22.5, 315 + 22.5)) { - // BOTTOM - RIGHT - return 'nwse-resize'; - } else { - // how can we can there? - Util.error( - 'Transformer has unknown angle for cursor detection: ' + angle - ); - return 'pointer'; - } + if (anchorName === 'rotater') { + return 'crosshair'; + } + rad += Util._degToRad(ANGLES[anchorName] || 0); + var angle = ((Util._radToDeg(rad) % 360) + 360) % 360; + if (Util._inRange(angle, 315 + 22.5, 360) || Util._inRange(angle, 0, 22.5)) { + // TOP + return 'ns-resize'; + } + else if (Util._inRange(angle, 45 - 22.5, 45 + 22.5)) { + // TOP - RIGHT + return 'nesw-resize'; + } + else if (Util._inRange(angle, 90 - 22.5, 90 + 22.5)) { + // RIGHT + return 'ew-resize'; + } + else if (Util._inRange(angle, 135 - 22.5, 135 + 22.5)) { + // BOTTOM - RIGHT + return 'nwse-resize'; + } + else if (Util._inRange(angle, 180 - 22.5, 180 + 22.5)) { + // BOTTOM + return 'ns-resize'; + } + else if (Util._inRange(angle, 225 - 22.5, 225 + 22.5)) { + // BOTTOM - LEFT + return 'nesw-resize'; + } + else if (Util._inRange(angle, 270 - 22.5, 270 + 22.5)) { + // RIGHT + return 'ew-resize'; + } + else if (Util._inRange(angle, 315 - 22.5, 315 + 22.5)) { + // BOTTOM - RIGHT + return 'nwse-resize'; + } + else { + // how can we can there? + Util.error('Transformer has unknown angle for cursor detection: ' + angle); + return 'pointer'; + } } var ANCHORS_NAMES = [ - 'top-left', - 'top-center', - 'top-right', - 'middle-right', - 'middle-left', - 'bottom-left', - 'bottom-center', - 'bottom-right', + 'top-left', + 'top-center', + 'top-right', + 'middle-right', + 'middle-left', + 'bottom-left', + 'bottom-center', + 'bottom-right', ]; var MAX_SAFE_INTEGER = 100000000; function getCenter(shape) { - return { - x: - shape.x + - (shape.width / 2) * Math.cos(shape.rotation) + - (shape.height / 2) * Math.sin(-shape.rotation), - y: - shape.y + - (shape.height / 2) * Math.cos(shape.rotation) + - (shape.width / 2) * Math.sin(shape.rotation), - }; + return { + x: shape.x + + (shape.width / 2) * Math.cos(shape.rotation) + + (shape.height / 2) * Math.sin(-shape.rotation), + y: shape.y + + (shape.height / 2) * Math.cos(shape.rotation) + + (shape.width / 2) * Math.sin(shape.rotation), + }; } function rotateAroundPoint(shape, angleRad, point) { - const x = - point.x + - (shape.x - point.x) * Math.cos(angleRad) - - (shape.y - point.y) * Math.sin(angleRad); - const y = - point.y + - (shape.x - point.x) * Math.sin(angleRad) + - (shape.y - point.y) * Math.cos(angleRad); - return Object.assign(Object.assign({}, shape), { - rotation: shape.rotation + angleRad, - x, - y, - }); + const x = point.x + + (shape.x - point.x) * Math.cos(angleRad) - + (shape.y - point.y) * Math.sin(angleRad); + const y = point.y + + (shape.x - point.x) * Math.sin(angleRad) + + (shape.y - point.y) * Math.cos(angleRad); + return Object.assign(Object.assign({}, shape), { rotation: shape.rotation + angleRad, x, + y }); } function rotateAroundCenter(shape, deltaRad) { - const center = getCenter(shape); - return rotateAroundPoint(shape, deltaRad, center); + const center = getCenter(shape); + return rotateAroundPoint(shape, deltaRad, center); } function getSnap(snaps, newRotationRad, tol) { - let snapped = newRotationRad; - for (let i = 0; i < snaps.length; i++) { - const angle = Konva$2.getAngle(snaps[i]); - const absDiff = Math.abs(angle - newRotationRad) % (Math.PI * 2); - const dif = Math.min(absDiff, Math.PI * 2 - absDiff); - if (dif < tol) { - snapped = angle; + let snapped = newRotationRad; + for (let i = 0; i < snaps.length; i++) { + const angle = Konva$2.getAngle(snaps[i]); + const absDiff = Math.abs(angle - newRotationRad) % (Math.PI * 2); + const dif = Math.min(absDiff, Math.PI * 2 - absDiff); + if (dif < tol) { + snapped = angle; + } } - } - return snapped; + return snapped; } /** * Transformer constructor. Transformer is a special type of group that allow you transform Konva @@ -14649,907 +13500,846 @@ * layer.add(transformer); */ class Transformer extends Group { - constructor(config) { - // call super constructor - super(config); - this._transforming = false; - this._createElements(); - // bindings - this._handleMouseMove = this._handleMouseMove.bind(this); - this._handleMouseUp = this._handleMouseUp.bind(this); - this.update = this.update.bind(this); - // update transformer data for certain attr changes - this.on(ATTR_CHANGE_LIST, this.update); - if (this.getNode()) { - this.update(); - } - } - /** - * alias to `tr.nodes([shape])`/ This method is deprecated and will be removed soon. - * @method - * @name Konva.Transformer#attachTo - * @returns {Konva.Transformer} - * @example - * transformer.attachTo(shape); - */ - attachTo(node) { - this.setNode(node); - 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]); - } - getNode() { - return this._nodes && this._nodes[0]; - } - setNodes(nodes = []) { - if (this._nodes && this._nodes.length) { - this.detach(); - } - this._nodes = nodes; - if (nodes.length === 1) { - this.rotation(nodes[0].getAbsoluteRotation()); - } else { - this.rotation(0); - } - this._nodes.forEach((node) => { - const additionalEvents = node._attrsAffectingSize - .map((prop) => prop + 'Change.' + EVENTS_NAME) - .join(' '); - const onChange = () => { - // - if (this.nodes().length === 1) { - this.rotation(this.nodes()[0].getAbsoluteRotation()); + constructor(config) { + // call super constructor + super(config); + this._transforming = false; + this._createElements(); + // bindings + this._handleMouseMove = this._handleMouseMove.bind(this); + this._handleMouseUp = this._handleMouseUp.bind(this); + this.update = this.update.bind(this); + // update transformer data for certain attr changes + this.on(ATTR_CHANGE_LIST, this.update); + if (this.getNode()) { + this.update(); } + } + /** + * alias to `tr.nodes([shape])`/ This method is deprecated and will be removed soon. + * @method + * @name Konva.Transformer#attachTo + * @returns {Konva.Transformer} + * @example + * transformer.attachTo(shape); + */ + attachTo(node) { + this.setNode(node); + 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]); + } + getNode() { + return this._nodes && this._nodes[0]; + } + setNodes(nodes = []) { + if (this._nodes && this._nodes.length) { + this.detach(); + } + this._nodes = nodes; + if (nodes.length === 1) { + this.rotation(nodes[0].getAbsoluteRotation()); + } + else { + this.rotation(0); + } + this._nodes.forEach((node) => { + const additionalEvents = node._attrsAffectingSize + .map((prop) => prop + 'Change.' + EVENTS_NAME) + .join(' '); + const onChange = () => { + // + if (this.nodes().length === 1) { + this.rotation(this.nodes()[0].getAbsoluteRotation()); + } + this._resetTransformCache(); + if (!this._transforming && !this.isDragging()) { + this.update(); + } + }; + node.on(additionalEvents, onChange); + node.on(TRANSFORM_CHANGE_STR, onChange); + node.on(`absoluteTransformChange.${EVENTS_NAME}`, onChange); + node.on(`xChange.${EVENTS_NAME} yChange.${EVENTS_NAME}`, onChange); + this._proxyDrag(node); + }); this._resetTransformCache(); - if (!this._transforming && !this.isDragging()) { - this.update(); + // 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(); } - }; - node.on(additionalEvents, onChange); - node.on(TRANSFORM_CHANGE_STR, onChange); - node.on(`absoluteTransformChange.${EVENTS_NAME}`, onChange); - 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 - // so elements are not defined yet - var elementsCreated = !!this.findOne('.top-left'); - if (elementsCreated) { - this.update(); + return this; } - return this; - } - _proxyDrag(node) { - let lastPos; - node.on(`dragstart.${EVENTS_NAME}`, (e) => { - lastPos = node.getAbsolutePosition(); - // actual dragging of Transformer doesn't make sense - // but we need to proxy drag events - if (!this.isDragging() && node !== this.findOne('.back')) { - this.startDrag(e, false); - } - }); - node.on(`dragmove.${EVENTS_NAME}`, (e) => { - 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, + _proxyDrag(node) { + let lastPos; + node.on(`dragstart.${EVENTS_NAME}`, (e) => { + lastPos = node.getAbsolutePosition(); + // actual dragging of Transformer doesn't make sense + // but we need to proxy drag events + if (!this.isDragging() && node !== this.findOne('.back')) { + this.startDrag(e, false); + } + }); + node.on(`dragmove.${EVENTS_NAME}`, (e) => { + 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(e); + }); + lastPos = null; }); - otherNode.startDrag(e); - }); - lastPos = null; - }); - } - getNodes() { - return this._nodes || []; - } - /** - * return the name of current active anchor - * @method - * @name Konva.Transformer#getActiveAnchor - * @returns {String | Null} - * @example - * transformer.getActiveAnchor(); - */ - getActiveAnchor() { - return this._movingAnchorName; - } - /** - * detach transformer from an attached node - * @method - * @name Konva.Transformer#detach - * @returns {Konva.Transformer} - * @example - * transformer.detach(); - */ - detach() { - // remove events - if (this._nodes) { - this._nodes.forEach((node) => { - node.off('.' + EVENTS_NAME); - }); } - this._nodes = []; - this._resetTransformCache(); - } - _resetTransformCache() { - this._clearCache(NODES_RECT); - this._clearCache('transform'); - this._clearSelfAndDescendantCache('absoluteTransform'); - } - _getNodeRect() { - return this._getCache(NODES_RECT, this.__getNodeRect); - } - // return absolute rotated bounding rectangle - __getNodeShape(node, rot = this.rotation(), relative) { - var rect = node.getClientRect({ - skipTransform: true, - skipShadow: true, - skipStroke: this.ignoreStroke(), - }); - var absScale = node.getAbsoluteScale(relative); - var absPos = node.getAbsolutePosition(relative); - var dx = rect.x * absScale.x - node.offsetX() * absScale.x; - var dy = rect.y * absScale.y - node.offsetY() * absScale.y; - const rotation = - (Konva$2.getAngle(node.getAbsoluteRotation()) + Math.PI * 2) % - (Math.PI * 2); - const box = { - x: absPos.x + dx * Math.cos(rotation) + dy * Math.sin(-rotation), - y: absPos.y + dy * Math.cos(rotation) + dx * Math.sin(rotation), - width: rect.width * absScale.x, - height: rect.height * absScale.y, - rotation: rotation, - }; - return rotateAroundPoint(box, -Konva$2.getAngle(rot), { - x: 0, - y: 0, - }); - } - // returns box + rotation of all shapes - __getNodeRect() { - var node = this.getNode(); - if (!node) { - return { - x: -MAX_SAFE_INTEGER, - y: -MAX_SAFE_INTEGER, - width: 0, - height: 0, - rotation: 0, - }; + getNodes() { + return this._nodes || []; } - const totalPoints = []; - this.nodes().map((node) => { - const box = node.getClientRect({ - skipTransform: true, - skipShadow: true, - skipStroke: this.ignoreStroke(), - }); - var points = [ - { x: box.x, y: box.y }, - { x: box.x + box.width, y: box.y }, - { x: box.x + box.width, y: box.y + box.height }, - { x: box.x, y: box.y + box.height }, - ]; - var trans = node.getAbsoluteTransform(); - points.forEach(function (point) { - var transformed = trans.point(point); - totalPoints.push(transformed); - }); - }); - const tr = new Transform(); - tr.rotate(-Konva$2.getAngle(this.rotation())); - var minX, minY, maxX, maxY; - totalPoints.forEach(function (point) { - var transformed = tr.point(point); - if (minX === undefined) { - minX = maxX = transformed.x; - minY = maxY = transformed.y; - } - minX = Math.min(minX, transformed.x); - minY = Math.min(minY, transformed.y); - maxX = Math.max(maxX, transformed.x); - maxY = Math.max(maxY, transformed.y); - }); - tr.invert(); - const p = tr.point({ x: minX, y: minY }); - return { - x: p.x, - y: p.y, - width: maxX - minX, - height: maxY - minY, - rotation: Konva$2.getAngle(this.rotation()), - }; - // const shapes = this.nodes().map(node => { - // return this.__getNodeShape(node); - // }); - // const box = getShapesRect(shapes); - // return rotateAroundPoint(box, Konva.getAngle(this.rotation()), { - // x: 0, - // y: 0 - // }); - } - getX() { - return this._getNodeRect().x; - } - getY() { - return this._getNodeRect().y; - } - getWidth() { - return this._getNodeRect().width; - } - getHeight() { - return this._getNodeRect().height; - } - _createElements() { - this._createBack(); - ANCHORS_NAMES.forEach( - function (name) { - this._createAnchor(name); - }.bind(this) - ); - this._createAnchor('rotater'); - } - _createAnchor(name) { - var anchor = new Rect({ - stroke: 'rgb(0, 161, 255)', - fill: 'white', - strokeWidth: 1, - name: name + ' _anchor', - dragDistance: 0, - // make it draggable, - // so activating the anchor will not start drag&drop of any parent - draggable: true, - hitStrokeWidth: TOUCH_DEVICE ? 10 : 'auto', - }); - var self = this; - anchor.on('mousedown touchstart', function (e) { - self._handleMouseDown(e); - }); - anchor.on('dragstart', (e) => { - anchor.stopDrag(); - e.cancelBubble = true; - }); - anchor.on('dragend', (e) => { - e.cancelBubble = true; - }); - // add hover styling - anchor.on('mouseenter', () => { - var rad = Konva$2.getAngle(this.rotation()); - var cursor = getCursor(name, rad); - anchor.getStage().content && - (anchor.getStage().content.style.cursor = cursor); - this._cursorChange = true; - }); - anchor.on('mouseout', () => { - anchor.getStage().content && - (anchor.getStage().content.style.cursor = ''); - this._cursorChange = false; - }); - this.add(anchor); - } - _createBack() { - var back = new Shape({ - name: 'back', - width: 0, - height: 0, - draggable: true, - sceneFunc(ctx) { - var tr = this.getParent(); - var padding = tr.padding(); - ctx.beginPath(); - ctx.rect( - -padding, - -padding, - this.width() + padding * 2, - this.height() + padding * 2 - ); - ctx.moveTo(this.width() / 2, -padding); - if (tr.rotateEnabled()) { - ctx.lineTo( - this.width() / 2, - -tr.rotateAnchorOffset() * Util._sign(this.height()) - padding - ); + /** + * return the name of current active anchor + * @method + * @name Konva.Transformer#getActiveAnchor + * @returns {String | Null} + * @example + * transformer.getActiveAnchor(); + */ + getActiveAnchor() { + return this._movingAnchorName; + } + /** + * detach transformer from an attached node + * @method + * @name Konva.Transformer#detach + * @returns {Konva.Transformer} + * @example + * transformer.detach(); + */ + detach() { + // remove events + if (this._nodes) { + this._nodes.forEach((node) => { + node.off('.' + EVENTS_NAME); + }); } - ctx.fillStrokeShape(this); - }, - hitFunc: (ctx, shape) => { - if (!this.shouldOverdrawWholeArea()) { - return; + this._nodes = []; + this._resetTransformCache(); + } + _resetTransformCache() { + this._clearCache(NODES_RECT); + this._clearCache('transform'); + this._clearSelfAndDescendantCache('absoluteTransform'); + } + _getNodeRect() { + return this._getCache(NODES_RECT, this.__getNodeRect); + } + // return absolute rotated bounding rectangle + __getNodeShape(node, rot = this.rotation(), relative) { + var rect = node.getClientRect({ + skipTransform: true, + skipShadow: true, + skipStroke: this.ignoreStroke(), + }); + var absScale = node.getAbsoluteScale(relative); + var absPos = node.getAbsolutePosition(relative); + var dx = rect.x * absScale.x - node.offsetX() * absScale.x; + var dy = rect.y * absScale.y - node.offsetY() * absScale.y; + const rotation = (Konva$2.getAngle(node.getAbsoluteRotation()) + Math.PI * 2) % + (Math.PI * 2); + const box = { + x: absPos.x + dx * Math.cos(rotation) + dy * Math.sin(-rotation), + y: absPos.y + dy * Math.cos(rotation) + dx * Math.sin(rotation), + width: rect.width * absScale.x, + height: rect.height * absScale.y, + rotation: rotation, + }; + return rotateAroundPoint(box, -Konva$2.getAngle(rot), { + x: 0, + y: 0, + }); + } + // returns box + rotation of all shapes + __getNodeRect() { + var node = this.getNode(); + if (!node) { + return { + x: -MAX_SAFE_INTEGER, + y: -MAX_SAFE_INTEGER, + width: 0, + height: 0, + rotation: 0, + }; } - 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); - // do not bubble drag from the back shape - // because we already "drag" whole transformer - // so we don't want to trigger drag twice on transformer - back.on('dragstart', (e) => { - e.cancelBubble = true; - }); - back.on('dragmove', (e) => { - e.cancelBubble = true; - }); - back.on('dragend', (e) => { - e.cancelBubble = true; - }); - } - _handleMouseDown(e) { - this._movingAnchorName = e.target.name().split(' ')[0]; - var attrs = this._getNodeRect(); - var width = attrs.width; - var height = attrs.height; - var hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); - this.sin = Math.abs(height / hypotenuse); - this.cos = Math.abs(width / hypotenuse); - if (typeof window !== 'undefined') { - window.addEventListener('mousemove', this._handleMouseMove); - window.addEventListener('touchmove', this._handleMouseMove); - window.addEventListener('mouseup', this._handleMouseUp, true); - window.addEventListener('touchend', this._handleMouseUp, true); - } - this._transforming = true; - var ap = e.target.getAbsolutePosition(); - var pos = e.target.getStage().getPointerPosition(); - this._anchorDragOffset = { - x: pos.x - ap.x, - y: pos.y - ap.y, - }; - this._fire('transformstart', { evt: e, target: this.getNode() }); - this._nodes.forEach((target) => { - target._fire('transformstart', { evt: e, target }); - }); - } - _handleMouseMove(e) { - var x, y, newHypotenuse; - var anchorNode = this.findOne('.' + this._movingAnchorName); - var stage = anchorNode.getStage(); - stage.setPointersPositions(e); - const pp = stage.getPointerPosition(); - var newNodePos = { - x: pp.x - this._anchorDragOffset.x, - y: pp.y - this._anchorDragOffset.y, - }; - const oldAbs = anchorNode.getAbsolutePosition(); - anchorNode.setAbsolutePosition(newNodePos); - const newAbs = anchorNode.getAbsolutePosition(); - if (oldAbs.x === newAbs.x && oldAbs.y === newAbs.y) { - return; - } - // rotater is working very differently, so do it first - if (this._movingAnchorName === 'rotater') { - var attrs = this._getNodeRect(); - x = anchorNode.x() - attrs.width / 2; - y = -anchorNode.y() + attrs.height / 2; - // hor angle is changed? - let delta = Math.atan2(-y, x) + Math.PI / 2; - if (attrs.height < 0) { - delta -= Math.PI; - } - var oldRotation = Konva$2.getAngle(this.rotation()); - const newRotation = oldRotation + delta; - const tol = Konva$2.getAngle(this.rotationSnapTolerance()); - const snappedRot = getSnap(this.rotationSnaps(), newRotation, tol); - const diff = snappedRot - attrs.rotation; - const shape = rotateAroundCenter(attrs, diff); - this._fitNodesInto(shape, e); - return; - } - var keepProportion = this.keepRatio() || e.shiftKey; - var centeredScaling = this.centeredScaling() || e.altKey; - if (this._movingAnchorName === 'top-left') { - if (keepProportion) { - var comparePoint = centeredScaling - ? { - x: this.width() / 2, - y: this.height() / 2, + const totalPoints = []; + this.nodes().map((node) => { + const box = node.getClientRect({ + skipTransform: true, + skipShadow: true, + skipStroke: this.ignoreStroke(), + }); + var points = [ + { x: box.x, y: box.y }, + { x: box.x + box.width, y: box.y }, + { x: box.x + box.width, y: box.y + box.height }, + { x: box.x, y: box.y + box.height }, + ]; + var trans = node.getAbsoluteTransform(); + points.forEach(function (point) { + var transformed = trans.point(point); + totalPoints.push(transformed); + }); + }); + const tr = new Transform(); + tr.rotate(-Konva$2.getAngle(this.rotation())); + var minX, minY, maxX, maxY; + totalPoints.forEach(function (point) { + var transformed = tr.point(point); + if (minX === undefined) { + minX = maxX = transformed.x; + minY = maxY = transformed.y; } - : { - 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(comparePoint.x - x); - this.findOne('.top-left').y(comparePoint.y - y); - } - } else if (this._movingAnchorName === 'top-center') { - this.findOne('.top-left').y(anchorNode.y()); - } else if (this._movingAnchorName === 'top-right') { - 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() - 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(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') { - this.findOne('.top-left').x(anchorNode.x()); - } else if (this._movingAnchorName === 'middle-right') { - this.findOne('.bottom-right').x(anchorNode.x()); - } else if (this._movingAnchorName === 'bottom-left') { - 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(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; - 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') { - this.findOne('.bottom-right').y(anchorNode.y()); - } else if (this._movingAnchorName === 'bottom-right') { - 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(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(comparePoint.x + x); - this.findOne('.bottom-right').y(comparePoint.y + y); - } - } else { - console.error( - new Error( - 'Wrong position argument of selection resizer: ' + - this._movingAnchorName - ) - ); + minX = Math.min(minX, transformed.x); + minY = Math.min(minY, transformed.y); + maxX = Math.max(maxX, transformed.x); + maxY = Math.max(maxY, transformed.y); + }); + tr.invert(); + const p = tr.point({ x: minX, y: minY }); + return { + x: p.x, + y: p.y, + width: maxX - minX, + height: maxY - minY, + rotation: Konva$2.getAngle(this.rotation()), + }; + // const shapes = this.nodes().map(node => { + // return this.__getNodeShape(node); + // }); + // const box = getShapesRect(shapes); + // return rotateAroundPoint(box, Konva.getAngle(this.rotation()), { + // x: 0, + // y: 0 + // }); } - var centeredScaling = this.centeredScaling() || e.altKey; - if (centeredScaling) { - var topLeft = this.findOne('.top-left'); - var bottomRight = this.findOne('.bottom-right'); - 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, - }); - topLeft.move({ - x: bottomOffsetX, - y: bottomOffsetY, - }); + getX() { + return this._getNodeRect().x; } - var absPos = this.findOne('.top-left').getAbsolutePosition(); - x = absPos.x; - y = absPos.y; - var width = - this.findOne('.bottom-right').x() - this.findOne('.top-left').x(); - var height = - this.findOne('.bottom-right').y() - this.findOne('.top-left').y(); - this._fitNodesInto( - { - x: x, - y: y, - width: width, - height: height, - rotation: Konva$2.getAngle(this.rotation()), - }, - e - ); - } - _handleMouseUp(e) { - this._removeEvents(e); - } - getAbsoluteTransform() { - return this.getTransform(); - } - _removeEvents(e) { - if (this._transforming) { - this._transforming = false; - if (typeof window !== 'undefined') { - window.removeEventListener('mousemove', this._handleMouseMove); - window.removeEventListener('touchmove', this._handleMouseMove); - window.removeEventListener('mouseup', this._handleMouseUp, true); - window.removeEventListener('touchend', this._handleMouseUp, true); - } - var node = this.getNode(); - this._fire('transformend', { evt: e, target: node }); - if (node) { + getY() { + return this._getNodeRect().y; + } + getWidth() { + return this._getNodeRect().width; + } + getHeight() { + return this._getNodeRect().height; + } + _createElements() { + this._createBack(); + ANCHORS_NAMES.forEach(function (name) { + this._createAnchor(name); + }.bind(this)); + this._createAnchor('rotater'); + } + _createAnchor(name) { + var anchor = new Rect({ + stroke: 'rgb(0, 161, 255)', + fill: 'white', + strokeWidth: 1, + name: name + ' _anchor', + dragDistance: 0, + // make it draggable, + // so activating the anchor will not start drag&drop of any parent + draggable: true, + hitStrokeWidth: TOUCH_DEVICE ? 10 : 'auto', + }); + var self = this; + anchor.on('mousedown touchstart', function (e) { + self._handleMouseDown(e); + }); + anchor.on('dragstart', (e) => { + anchor.stopDrag(); + e.cancelBubble = true; + }); + anchor.on('dragend', (e) => { + e.cancelBubble = true; + }); + // add hover styling + anchor.on('mouseenter', () => { + var rad = Konva$2.getAngle(this.rotation()); + var cursor = getCursor(name, rad); + anchor.getStage().content && + (anchor.getStage().content.style.cursor = cursor); + this._cursorChange = true; + }); + anchor.on('mouseout', () => { + anchor.getStage().content && + (anchor.getStage().content.style.cursor = ''); + this._cursorChange = false; + }); + this.add(anchor); + } + _createBack() { + var back = new Shape({ + name: 'back', + width: 0, + height: 0, + draggable: true, + sceneFunc(ctx) { + var tr = this.getParent(); + var padding = tr.padding(); + ctx.beginPath(); + ctx.rect(-padding, -padding, this.width() + padding * 2, this.height() + padding * 2); + ctx.moveTo(this.width() / 2, -padding); + if (tr.rotateEnabled()) { + ctx.lineTo(this.width() / 2, -tr.rotateAnchorOffset() * Util._sign(this.height()) - padding); + } + 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); + // do not bubble drag from the back shape + // because we already "drag" whole transformer + // so we don't want to trigger drag twice on transformer + back.on('dragstart', (e) => { + e.cancelBubble = true; + }); + back.on('dragmove', (e) => { + e.cancelBubble = true; + }); + back.on('dragend', (e) => { + e.cancelBubble = true; + }); + } + _handleMouseDown(e) { + this._movingAnchorName = e.target.name().split(' ')[0]; + var attrs = this._getNodeRect(); + var width = attrs.width; + var height = attrs.height; + var hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); + this.sin = Math.abs(height / hypotenuse); + this.cos = Math.abs(width / hypotenuse); + if (typeof window !== 'undefined') { + window.addEventListener('mousemove', this._handleMouseMove); + window.addEventListener('touchmove', this._handleMouseMove); + window.addEventListener('mouseup', this._handleMouseUp, true); + window.addEventListener('touchend', this._handleMouseUp, true); + } + this._transforming = true; + var ap = e.target.getAbsolutePosition(); + var pos = e.target.getStage().getPointerPosition(); + this._anchorDragOffset = { + x: pos.x - ap.x, + y: pos.y - ap.y, + }; + this._fire('transformstart', { evt: e, target: this.getNode() }); this._nodes.forEach((target) => { - target._fire('transformend', { evt: e, target }); + target._fire('transformstart', { evt: e, target }); }); - } - this._movingAnchorName = null; } - } - _fitNodesInto(newAttrs, evt) { - var oldAttrs = this._getNodeRect(); - const minSize = 1; - if ( - Util._inRange(newAttrs.width, -this.padding() * 2 - minSize, minSize) - ) { - this.update(); - return; + _handleMouseMove(e) { + var x, y, newHypotenuse; + var anchorNode = this.findOne('.' + this._movingAnchorName); + var stage = anchorNode.getStage(); + stage.setPointersPositions(e); + const pp = stage.getPointerPosition(); + var newNodePos = { + x: pp.x - this._anchorDragOffset.x, + y: pp.y - this._anchorDragOffset.y, + }; + const oldAbs = anchorNode.getAbsolutePosition(); + anchorNode.setAbsolutePosition(newNodePos); + const newAbs = anchorNode.getAbsolutePosition(); + if (oldAbs.x === newAbs.x && oldAbs.y === newAbs.y) { + return; + } + // rotater is working very differently, so do it first + if (this._movingAnchorName === 'rotater') { + var attrs = this._getNodeRect(); + x = anchorNode.x() - attrs.width / 2; + y = -anchorNode.y() + attrs.height / 2; + // hor angle is changed? + let delta = Math.atan2(-y, x) + Math.PI / 2; + if (attrs.height < 0) { + delta -= Math.PI; + } + var oldRotation = Konva$2.getAngle(this.rotation()); + const newRotation = oldRotation + delta; + const tol = Konva$2.getAngle(this.rotationSnapTolerance()); + const snappedRot = getSnap(this.rotationSnaps(), newRotation, tol); + const diff = snappedRot - attrs.rotation; + const shape = rotateAroundCenter(attrs, diff); + this._fitNodesInto(shape, e); + return; + } + var keepProportion = this.keepRatio() || e.shiftKey; + var centeredScaling = this.centeredScaling() || e.altKey; + if (this._movingAnchorName === 'top-left') { + 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(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(comparePoint.x - x); + this.findOne('.top-left').y(comparePoint.y - y); + } + } + else if (this._movingAnchorName === 'top-center') { + this.findOne('.top-left').y(anchorNode.y()); + } + else if (this._movingAnchorName === 'top-right') { + 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() - 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(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') { + this.findOne('.top-left').x(anchorNode.x()); + } + else if (this._movingAnchorName === 'middle-right') { + this.findOne('.bottom-right').x(anchorNode.x()); + } + else if (this._movingAnchorName === 'bottom-left') { + 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(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; + 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') { + this.findOne('.bottom-right').y(anchorNode.y()); + } + else if (this._movingAnchorName === 'bottom-right') { + 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(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(comparePoint.x + x); + this.findOne('.bottom-right').y(comparePoint.y + y); + } + } + else { + console.error(new Error('Wrong position argument of selection resizer: ' + + this._movingAnchorName)); + } + var centeredScaling = this.centeredScaling() || e.altKey; + if (centeredScaling) { + var topLeft = this.findOne('.top-left'); + var bottomRight = this.findOne('.bottom-right'); + 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, + }); + topLeft.move({ + x: bottomOffsetX, + y: bottomOffsetY, + }); + } + var absPos = this.findOne('.top-left').getAbsolutePosition(); + x = absPos.x; + y = absPos.y; + var width = this.findOne('.bottom-right').x() - this.findOne('.top-left').x(); + var height = this.findOne('.bottom-right').y() - this.findOne('.top-left').y(); + this._fitNodesInto({ + x: x, + y: y, + width: width, + height: height, + rotation: Konva$2.getAngle(this.rotation()), + }, e); } - if ( - Util._inRange(newAttrs.height, -this.padding() * 2 - minSize, minSize) - ) { - this.update(); - return; + _handleMouseUp(e) { + this._removeEvents(e); } - var t = new Transform(); - t.rotate(Konva$2.getAngle(this.rotation())); - if ( - this._movingAnchorName && - newAttrs.width < 0 && - this._movingAnchorName.indexOf('left') >= 0 - ) { - const offset = t.point({ - x: -this.padding() * 2, - y: 0, - }); - newAttrs.x += offset.x; - newAttrs.y += offset.y; - newAttrs.width += this.padding() * 2; - this._movingAnchorName = this._movingAnchorName.replace( - 'left', - 'right' - ); - this._anchorDragOffset.x -= offset.x; - this._anchorDragOffset.y -= offset.y; - } else if ( - this._movingAnchorName && - newAttrs.width < 0 && - this._movingAnchorName.indexOf('right') >= 0 - ) { - const offset = t.point({ - x: this.padding() * 2, - y: 0, - }); - this._movingAnchorName = this._movingAnchorName.replace( - 'right', - 'left' - ); - this._anchorDragOffset.x -= offset.x; - this._anchorDragOffset.y -= offset.y; - newAttrs.width += this.padding() * 2; + getAbsoluteTransform() { + return this.getTransform(); } - 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 = this._movingAnchorName.replace( - 'top', - 'bottom' - ); - this._anchorDragOffset.x -= offset.x; - this._anchorDragOffset.y -= offset.y; - newAttrs.height += this.padding() * 2; - } else if ( - this._movingAnchorName && - newAttrs.height < 0 && - this._movingAnchorName.indexOf('bottom') >= 0 - ) { - const offset = t.point({ - x: 0, - y: this.padding() * 2, - }); - this._movingAnchorName = this._movingAnchorName.replace( - 'bottom', - 'top' - ); - this._anchorDragOffset.x -= offset.x; - this._anchorDragOffset.y -= offset.y; - newAttrs.height += this.padding() * 2; + _removeEvents(e) { + if (this._transforming) { + this._transforming = false; + if (typeof window !== 'undefined') { + window.removeEventListener('mousemove', this._handleMouseMove); + window.removeEventListener('touchmove', this._handleMouseMove); + window.removeEventListener('mouseup', this._handleMouseUp, true); + window.removeEventListener('touchend', this._handleMouseUp, true); + } + var node = this.getNode(); + this._fire('transformend', { evt: e, target: node }); + if (node) { + this._nodes.forEach((target) => { + target._fire('transformend', { evt: e, target }); + }); + } + this._movingAnchorName = null; + } } - if (this.boundBoxFunc()) { - const bounded = this.boundBoxFunc()(oldAttrs, newAttrs); - if (bounded) { - newAttrs = bounded; - } else { - Util.warn( - 'boundBoxFunc returned falsy. You should return new bound rect from it!' - ); - } + _fitNodesInto(newAttrs, evt) { + var oldAttrs = this._getNodeRect(); + const minSize = 1; + if (Util._inRange(newAttrs.width, -this.padding() * 2 - minSize, minSize)) { + this.update(); + return; + } + if (Util._inRange(newAttrs.height, -this.padding() * 2 - minSize, minSize)) { + this.update(); + return; + } + var t = new Transform(); + t.rotate(Konva$2.getAngle(this.rotation())); + if (this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('left') >= 0) { + const offset = t.point({ + x: -this.padding() * 2, + y: 0, + }); + newAttrs.x += offset.x; + newAttrs.y += offset.y; + newAttrs.width += this.padding() * 2; + this._movingAnchorName = this._movingAnchorName.replace('left', 'right'); + this._anchorDragOffset.x -= offset.x; + this._anchorDragOffset.y -= offset.y; + } + else if (this._movingAnchorName && + newAttrs.width < 0 && + this._movingAnchorName.indexOf('right') >= 0) { + const offset = t.point({ + x: this.padding() * 2, + y: 0, + }); + this._movingAnchorName = this._movingAnchorName.replace('right', 'left'); + this._anchorDragOffset.x -= offset.x; + this._anchorDragOffset.y -= offset.y; + newAttrs.width += this.padding() * 2; + } + 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 = this._movingAnchorName.replace('top', 'bottom'); + this._anchorDragOffset.x -= offset.x; + this._anchorDragOffset.y -= offset.y; + newAttrs.height += this.padding() * 2; + } + else if (this._movingAnchorName && + newAttrs.height < 0 && + this._movingAnchorName.indexOf('bottom') >= 0) { + const offset = t.point({ + x: 0, + y: this.padding() * 2, + }); + this._movingAnchorName = this._movingAnchorName.replace('bottom', 'top'); + this._anchorDragOffset.x -= offset.x; + this._anchorDragOffset.y -= offset.y; + newAttrs.height += this.padding() * 2; + } + if (this.boundBoxFunc()) { + const bounded = this.boundBoxFunc()(oldAttrs, newAttrs); + if (bounded) { + newAttrs = bounded; + } + else { + Util.warn('boundBoxFunc returned falsy. You should return new bound rect from it!'); + } + } + // base size value doesn't really matter + // we just need to think about bounding boxes as transforms + // but how? + // the idea is that we have a transformed rectangle with the size of "baseSize" + const baseSize = 10000000; + const oldTr = new Transform(); + oldTr.translate(oldAttrs.x, oldAttrs.y); + oldTr.rotate(oldAttrs.rotation); + oldTr.scale(oldAttrs.width / baseSize, oldAttrs.height / baseSize); + const newTr = new Transform(); + newTr.translate(newAttrs.x, newAttrs.y); + newTr.rotate(newAttrs.rotation); + newTr.scale(newAttrs.width / baseSize, newAttrs.height / baseSize); + // now lets think we had [old transform] and n ow we have [new transform] + // Now, the questions is: how can we transform "parent" to go from [old transform] into [new transform] + // in equation it will be: + // [delta transform] * [old transform] = [new transform] + // that means that + // [delta transform] = [new transform] * [old transform inverted] + const delta = newTr.multiply(oldTr.invert()); + this._nodes.forEach((node) => { + var _a; + // for each node we have the same [delta transform] + // the equations is + // [delta transform] * [parent transform] * [old local transform] = [parent transform] * [new local transform] + // and we need to find [new local transform] + // [new local] = [parent inverted] * [delta] * [parent] * [old local] + const parentTransform = node.getParent().getAbsoluteTransform(); + const localTransform = node.getTransform().copy(); + // skip offset: + localTransform.translate(node.offsetX(), node.offsetY()); + const newLocalTransform = new Transform(); + newLocalTransform + .multiply(parentTransform.copy().invert()) + .multiply(delta) + .multiply(parentTransform) + .multiply(localTransform); + const attrs = newLocalTransform.decompose(); + node.setAttrs(attrs); + this._fire('transform', { evt: evt, target: node }); + node._fire('transform', { evt: evt, target: node }); + (_a = node.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw(); + }); + this.rotation(Util._getRotation(newAttrs.rotation)); + this._resetTransformCache(); + this.update(); + this.getLayer().batchDraw(); } - // base size value doesn't really matter - // we just need to think about bounding boxes as transforms - // but how? - // the idea is that we have a transformed rectangle with the size of "baseSize" - const baseSize = 10000000; - const oldTr = new Transform(); - oldTr.translate(oldAttrs.x, oldAttrs.y); - oldTr.rotate(oldAttrs.rotation); - oldTr.scale(oldAttrs.width / baseSize, oldAttrs.height / baseSize); - const newTr = new Transform(); - newTr.translate(newAttrs.x, newAttrs.y); - newTr.rotate(newAttrs.rotation); - newTr.scale(newAttrs.width / baseSize, newAttrs.height / baseSize); - // now lets think we had [old transform] and n ow we have [new transform] - // Now, the questions is: how can we transform "parent" to go from [old transform] into [new transform] - // in equation it will be: - // [delta transform] * [old transform] = [new transform] - // that means that - // [delta transform] = [new transform] * [old transform inverted] - const delta = newTr.multiply(oldTr.invert()); - this._nodes.forEach((node) => { - var _a; - // for each node we have the same [delta transform] - // the equations is - // [delta transform] * [parent transform] * [old local transform] = [parent transform] * [new local transform] - // and we need to find [new local transform] - // [new local] = [parent inverted] * [delta] * [parent] * [old local] - const parentTransform = node.getParent().getAbsoluteTransform(); - const localTransform = node.getTransform().copy(); - // skip offset: - localTransform.translate(node.offsetX(), node.offsetY()); - const newLocalTransform = new Transform(); - newLocalTransform - .multiply(parentTransform.copy().invert()) - .multiply(delta) - .multiply(parentTransform) - .multiply(localTransform); - const attrs = newLocalTransform.decompose(); - node.setAttrs(attrs); - this._fire('transform', { evt: evt, target: node }); - node._fire('transform', { evt: evt, target: node }); - (_a = node.getLayer()) === null || _a === void 0 - ? void 0 - : _a.batchDraw(); - }); - this.rotation(Util._getRotation(newAttrs.rotation)); - this._resetTransformCache(); - this.update(); - this.getLayer().batchDraw(); - } - /** - * force update of Konva.Transformer. - * Use it when you updated attached Konva.Group and now you need to reset transformer size - * @method - * @name Konva.Transformer#forceUpdate - */ - forceUpdate() { - this._resetTransformCache(); - this.update(); - } - _batchChangeChild(selector, attrs) { - const anchor = this.findOne(selector); - anchor.setAttrs(attrs); - } - update() { - var _a; - var attrs = this._getNodeRect(); - this.rotation(Util._getRotation(attrs.rotation)); - var width = attrs.width; - var height = attrs.height; - var enabledAnchors = this.enabledAnchors(); - var resizeEnabled = this.resizeEnabled(); - var padding = this.padding(); - var anchorSize = this.anchorSize(); - this.find('._anchor').forEach((node) => { - node.setAttrs({ - width: anchorSize, - height: anchorSize, - offsetX: anchorSize / 2, - offsetY: anchorSize / 2, - stroke: this.anchorStroke(), - strokeWidth: this.anchorStrokeWidth(), - fill: this.anchorFill(), - cornerRadius: this.anchorCornerRadius(), - }); - }); - this._batchChangeChild('.top-left', { - x: 0, - y: 0, - offsetX: anchorSize / 2 + padding, - offsetY: anchorSize / 2 + padding, - visible: resizeEnabled && enabledAnchors.indexOf('top-left') >= 0, - }); - this._batchChangeChild('.top-center', { - x: width / 2, - y: 0, - offsetY: anchorSize / 2 + padding, - visible: resizeEnabled && enabledAnchors.indexOf('top-center') >= 0, - }); - this._batchChangeChild('.top-right', { - x: width, - y: 0, - offsetX: anchorSize / 2 - padding, - offsetY: anchorSize / 2 + padding, - visible: resizeEnabled && enabledAnchors.indexOf('top-right') >= 0, - }); - this._batchChangeChild('.middle-left', { - x: 0, - y: height / 2, - offsetX: anchorSize / 2 + padding, - visible: resizeEnabled && enabledAnchors.indexOf('middle-left') >= 0, - }); - this._batchChangeChild('.middle-right', { - x: width, - y: height / 2, - offsetX: anchorSize / 2 - padding, - visible: resizeEnabled && enabledAnchors.indexOf('middle-right') >= 0, - }); - this._batchChangeChild('.bottom-left', { - x: 0, - y: height, - offsetX: anchorSize / 2 + padding, - offsetY: anchorSize / 2 - padding, - visible: resizeEnabled && enabledAnchors.indexOf('bottom-left') >= 0, - }); - this._batchChangeChild('.bottom-center', { - x: width / 2, - y: height, - offsetY: anchorSize / 2 - padding, - visible: resizeEnabled && enabledAnchors.indexOf('bottom-center') >= 0, - }); - this._batchChangeChild('.bottom-right', { - x: width, - y: height, - offsetX: anchorSize / 2 - padding, - offsetY: anchorSize / 2 - padding, - visible: resizeEnabled && enabledAnchors.indexOf('bottom-right') >= 0, - }); - this._batchChangeChild('.rotater', { - x: width / 2, - y: -this.rotateAnchorOffset() * Util._sign(height) - padding, - visible: this.rotateEnabled(), - }); - this._batchChangeChild('.back', { - width: width, - height: height, - visible: this.borderEnabled(), - stroke: this.borderStroke(), - strokeWidth: this.borderStrokeWidth(), - dash: this.borderDash(), - x: 0, - y: 0, - }); - (_a = this.getLayer()) === null || _a === void 0 - ? void 0 - : _a.batchDraw(); - } - /** - * determine if transformer is in active transform - * @method - * @name Konva.Transformer#isTransforming - * @returns {Boolean} - */ - isTransforming() { - return this._transforming; - } - /** - * Stop active transform action - * @method - * @name Konva.Transformer#stopTransform - * @returns {Boolean} - */ - stopTransform() { - if (this._transforming) { - this._removeEvents(); - var anchorNode = this.findOne('.' + this._movingAnchorName); - if (anchorNode) { - anchorNode.stopDrag(); - } + /** + * force update of Konva.Transformer. + * Use it when you updated attached Konva.Group and now you need to reset transformer size + * @method + * @name Konva.Transformer#forceUpdate + */ + forceUpdate() { + this._resetTransformCache(); + this.update(); } - } - destroy() { - if (this.getStage() && this._cursorChange) { - this.getStage().content && (this.getStage().content.style.cursor = ''); + _batchChangeChild(selector, attrs) { + const anchor = this.findOne(selector); + anchor.setAttrs(attrs); + } + update() { + var _a; + var attrs = this._getNodeRect(); + this.rotation(Util._getRotation(attrs.rotation)); + var width = attrs.width; + var height = attrs.height; + var enabledAnchors = this.enabledAnchors(); + var resizeEnabled = this.resizeEnabled(); + var padding = this.padding(); + var anchorSize = this.anchorSize(); + this.find('._anchor').forEach((node) => { + node.setAttrs({ + width: anchorSize, + height: anchorSize, + offsetX: anchorSize / 2, + offsetY: anchorSize / 2, + stroke: this.anchorStroke(), + strokeWidth: this.anchorStrokeWidth(), + fill: this.anchorFill(), + cornerRadius: this.anchorCornerRadius(), + }); + }); + this._batchChangeChild('.top-left', { + x: 0, + y: 0, + offsetX: anchorSize / 2 + padding, + offsetY: anchorSize / 2 + padding, + visible: resizeEnabled && enabledAnchors.indexOf('top-left') >= 0, + }); + this._batchChangeChild('.top-center', { + x: width / 2, + y: 0, + offsetY: anchorSize / 2 + padding, + visible: resizeEnabled && enabledAnchors.indexOf('top-center') >= 0, + }); + this._batchChangeChild('.top-right', { + x: width, + y: 0, + offsetX: anchorSize / 2 - padding, + offsetY: anchorSize / 2 + padding, + visible: resizeEnabled && enabledAnchors.indexOf('top-right') >= 0, + }); + this._batchChangeChild('.middle-left', { + x: 0, + y: height / 2, + offsetX: anchorSize / 2 + padding, + visible: resizeEnabled && enabledAnchors.indexOf('middle-left') >= 0, + }); + this._batchChangeChild('.middle-right', { + x: width, + y: height / 2, + offsetX: anchorSize / 2 - padding, + visible: resizeEnabled && enabledAnchors.indexOf('middle-right') >= 0, + }); + this._batchChangeChild('.bottom-left', { + x: 0, + y: height, + offsetX: anchorSize / 2 + padding, + offsetY: anchorSize / 2 - padding, + visible: resizeEnabled && enabledAnchors.indexOf('bottom-left') >= 0, + }); + this._batchChangeChild('.bottom-center', { + x: width / 2, + y: height, + offsetY: anchorSize / 2 - padding, + visible: resizeEnabled && enabledAnchors.indexOf('bottom-center') >= 0, + }); + this._batchChangeChild('.bottom-right', { + x: width, + y: height, + offsetX: anchorSize / 2 - padding, + offsetY: anchorSize / 2 - padding, + visible: resizeEnabled && enabledAnchors.indexOf('bottom-right') >= 0, + }); + this._batchChangeChild('.rotater', { + x: width / 2, + y: -this.rotateAnchorOffset() * Util._sign(height) - padding, + visible: this.rotateEnabled(), + }); + this._batchChangeChild('.back', { + width: width, + height: height, + visible: this.borderEnabled(), + stroke: this.borderStroke(), + strokeWidth: this.borderStrokeWidth(), + dash: this.borderDash(), + x: 0, + y: 0, + }); + (_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw(); + } + /** + * determine if transformer is in active transform + * @method + * @name Konva.Transformer#isTransforming + * @returns {Boolean} + */ + isTransforming() { + return this._transforming; + } + /** + * Stop active transform action + * @method + * @name Konva.Transformer#stopTransform + * @returns {Boolean} + */ + stopTransform() { + if (this._transforming) { + this._removeEvents(); + var anchorNode = this.findOne('.' + this._movingAnchorName); + if (anchorNode) { + anchorNode.stopDrag(); + } + } + } + destroy() { + if (this.getStage() && this._cursorChange) { + this.getStage().content && (this.getStage().content.style.cursor = ''); + } + Group.prototype.destroy.call(this); + this.detach(); + this._removeEvents(); + return this; + } + // do not work as a container + // we will recreate inner nodes manually + toObject() { + return Node.prototype.toObject.call(this); } - Group.prototype.destroy.call(this); - this.detach(); - this._removeEvents(); - return this; - } - // do not work as a container - // we will recreate inner nodes manually - toObject() { - return Node.prototype.toObject.call(this); - } } function validateAnchors(val) { - if (!(val instanceof Array)) { - Util.warn('enabledAnchors value should be an array'); - } - if (val instanceof Array) { - val.forEach(function (name) { - if (ANCHORS_NAMES.indexOf(name) === -1) { - Util.warn( - 'Unknown anchor name: ' + - name + - '. Available names are: ' + - ANCHORS_NAMES.join(', ') - ); - } - }); - } - return val || []; + if (!(val instanceof Array)) { + Util.warn('enabledAnchors value should be an array'); + } + if (val instanceof Array) { + val.forEach(function (name) { + if (ANCHORS_NAMES.indexOf(name) === -1) { + Util.warn('Unknown anchor name: ' + + name + + '. Available names are: ' + + ANCHORS_NAMES.join(', ')); + } + }); + } + return val || []; } Transformer.prototype.className = 'Transformer'; _registerNode(Transformer); @@ -15566,12 +14356,7 @@ * // set handlers * transformer.enabledAnchors(['top-left', 'top-center', 'top-right', 'middle-right', 'middle-left', 'bottom-left', 'bottom-center', 'bottom-right']); */ - Factory.addGetterSetter( - Transformer, - 'enabledAnchors', - ANCHORS_NAMES, - validateAnchors - ); + Factory.addGetterSetter(Transformer, 'enabledAnchors', ANCHORS_NAMES, validateAnchors); /** * get/set resize ability. If false it will automatically hide resizing handlers * @name Konva.Transformer#resizeEnabled @@ -15641,12 +14426,7 @@ * // set * transformer.rotateAnchorOffset(100); */ - Factory.addGetterSetter( - Transformer, - 'rotateAnchorOffset', - 50, - getNumberValidator() - ); + Factory.addGetterSetter(Transformer, 'rotateAnchorOffset', 50, getNumberValidator()); /** * get/set distance for rotation tolerance * @name Konva.Transformer#rotationSnapTolerance @@ -15660,12 +14440,7 @@ * // set * transformer.rotationSnapTolerance(100); */ - Factory.addGetterSetter( - Transformer, - 'rotationSnapTolerance', - 5, - getNumberValidator() - ); + Factory.addGetterSetter(Transformer, 'rotationSnapTolerance', 5, getNumberValidator()); /** * get/set visibility of border * @name Konva.Transformer#borderEnabled @@ -15707,12 +14482,7 @@ * // set * transformer.anchorStrokeWidth(3); */ - Factory.addGetterSetter( - Transformer, - 'anchorStrokeWidth', - 1, - getNumberValidator() - ); + Factory.addGetterSetter(Transformer, 'anchorStrokeWidth', 1, getNumberValidator()); /** * get/set anchor fill color * @name Konva.Transformer#anchorFill @@ -15740,12 +14510,7 @@ * // set * transformer.anchorCornerRadius(3); */ - Factory.addGetterSetter( - Transformer, - 'anchorCornerRadius', - 0, - getNumberValidator() - ); + Factory.addGetterSetter(Transformer, 'anchorCornerRadius', 0, getNumberValidator()); /** * get/set border stroke color * @name Konva.Transformer#borderStroke @@ -15773,12 +14538,7 @@ * // set * transformer.borderStrokeWidth(3); */ - Factory.addGetterSetter( - Transformer, - 'borderStrokeWidth', - 1, - getNumberValidator() - ); + Factory.addGetterSetter(Transformer, 'borderStrokeWidth', 1, getNumberValidator()); /** * get/set border dash array * @name Konva.Transformer#borderDash @@ -15893,11 +14653,11 @@ Factory.addGetterSetter(Transformer, 'boundBoxFunc'); Factory.addGetterSetter(Transformer, 'shouldOverdrawWholeArea', false); Factory.backCompat(Transformer, { - lineEnabled: 'borderEnabled', - rotateHandlerOffset: 'rotateAnchorOffset', - enabledHandlers: 'enabledAnchors', - }); - + lineEnabled: 'borderEnabled', + rotateHandlerOffset: 'rotateAnchorOffset', + enabledHandlers: 'enabledAnchors', + }); + /** * Wedge constructor * @constructor @@ -15921,32 +14681,25 @@ * }); */ class Wedge extends Shape { - _sceneFunc(context) { - context.beginPath(); - context.arc( - 0, - 0, - this.radius(), - 0, - Konva$2.getAngle(this.angle()), - this.clockwise() - ); - context.lineTo(0, 0); - context.closePath(); - context.fillStrokeShape(this); - } - getWidth() { - return this.radius() * 2; - } - getHeight() { - return this.radius() * 2; - } - setWidth(width) { - this.radius(width / 2); - } - setHeight(height) { - this.radius(height / 2); - } + _sceneFunc(context) { + context.beginPath(); + context.arc(0, 0, this.radius(), 0, Konva$2.getAngle(this.angle()), this.clockwise()); + context.lineTo(0, 0); + context.closePath(); + context.fillStrokeShape(this); + } + getWidth() { + return this.radius() * 2; + } + getHeight() { + return this.radius() * 2; + } + setWidth(width) { + this.radius(width / 2); + } + setHeight(height) { + this.radius(height / 2); + } } Wedge.prototype.className = 'Wedge'; Wedge.prototype._centroid = true; @@ -15998,34 +14751,34 @@ */ Factory.addGetterSetter(Wedge, 'clockwise', false); Factory.backCompat(Wedge, { - angleDeg: 'angle', - getAngleDeg: 'getAngle', - setAngleDeg: 'setAngle', - }); - + angleDeg: 'angle', + getAngleDeg: 'getAngle', + setAngleDeg: 'setAngle', + }); + /* the Gauss filter master repo: https://github.com/pavelpower/kineticjsGaussFilter */ /* - + StackBlur - a fast almost Gaussian Blur For Canvas - + Version: 0.5 Author: Mario Klingemann Contact: mario@quasimondo.com Website: http://www.quasimondo.com/StackBlurForCanvas Twitter: @quasimondo - + In case you find this class useful - especially in commercial projects - I am not totally unhappy for a small donation to my PayPal account mario@quasimondo.de - + Or support me on flattr: https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript - + Copyright (c) 2010 Mario Klingemann - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without @@ -16034,10 +14787,10 @@ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -16048,726 +14801,691 @@ OTHER DEALINGS IN THE SOFTWARE. */ function BlurStack() { - this.r = 0; - this.g = 0; - this.b = 0; - this.a = 0; - this.next = null; + this.r = 0; + this.g = 0; + this.b = 0; + this.a = 0; + this.next = null; } var mul_table = [ - 512, - 512, - 456, - 512, - 328, - 456, - 335, - 512, - 405, - 328, - 271, - 456, - 388, - 335, - 292, - 512, - 454, - 405, - 364, - 328, - 298, - 271, - 496, - 456, - 420, - 388, - 360, - 335, - 312, - 292, - 273, - 512, - 482, - 454, - 428, - 405, - 383, - 364, - 345, - 328, - 312, - 298, - 284, - 271, - 259, - 496, - 475, - 456, - 437, - 420, - 404, - 388, - 374, - 360, - 347, - 335, - 323, - 312, - 302, - 292, - 282, - 273, - 265, - 512, - 497, - 482, - 468, - 454, - 441, - 428, - 417, - 405, - 394, - 383, - 373, - 364, - 354, - 345, - 337, - 328, - 320, - 312, - 305, - 298, - 291, - 284, - 278, - 271, - 265, - 259, - 507, - 496, - 485, - 475, - 465, - 456, - 446, - 437, - 428, - 420, - 412, - 404, - 396, - 388, - 381, - 374, - 367, - 360, - 354, - 347, - 341, - 335, - 329, - 323, - 318, - 312, - 307, - 302, - 297, - 292, - 287, - 282, - 278, - 273, - 269, - 265, - 261, - 512, - 505, - 497, - 489, - 482, - 475, - 468, - 461, - 454, - 447, - 441, - 435, - 428, - 422, - 417, - 411, - 405, - 399, - 394, - 389, - 383, - 378, - 373, - 368, - 364, - 359, - 354, - 350, - 345, - 341, - 337, - 332, - 328, - 324, - 320, - 316, - 312, - 309, - 305, - 301, - 298, - 294, - 291, - 287, - 284, - 281, - 278, - 274, - 271, - 268, - 265, - 262, - 259, - 257, - 507, - 501, - 496, - 491, - 485, - 480, - 475, - 470, - 465, - 460, - 456, - 451, - 446, - 442, - 437, - 433, - 428, - 424, - 420, - 416, - 412, - 408, - 404, - 400, - 396, - 392, - 388, - 385, - 381, - 377, - 374, - 370, - 367, - 363, - 360, - 357, - 354, - 350, - 347, - 344, - 341, - 338, - 335, - 332, - 329, - 326, - 323, - 320, - 318, - 315, - 312, - 310, - 307, - 304, - 302, - 299, - 297, - 294, - 292, - 289, - 287, - 285, - 282, - 280, - 278, - 275, - 273, - 271, - 269, - 267, - 265, - 263, - 261, - 259, + 512, + 512, + 456, + 512, + 328, + 456, + 335, + 512, + 405, + 328, + 271, + 456, + 388, + 335, + 292, + 512, + 454, + 405, + 364, + 328, + 298, + 271, + 496, + 456, + 420, + 388, + 360, + 335, + 312, + 292, + 273, + 512, + 482, + 454, + 428, + 405, + 383, + 364, + 345, + 328, + 312, + 298, + 284, + 271, + 259, + 496, + 475, + 456, + 437, + 420, + 404, + 388, + 374, + 360, + 347, + 335, + 323, + 312, + 302, + 292, + 282, + 273, + 265, + 512, + 497, + 482, + 468, + 454, + 441, + 428, + 417, + 405, + 394, + 383, + 373, + 364, + 354, + 345, + 337, + 328, + 320, + 312, + 305, + 298, + 291, + 284, + 278, + 271, + 265, + 259, + 507, + 496, + 485, + 475, + 465, + 456, + 446, + 437, + 428, + 420, + 412, + 404, + 396, + 388, + 381, + 374, + 367, + 360, + 354, + 347, + 341, + 335, + 329, + 323, + 318, + 312, + 307, + 302, + 297, + 292, + 287, + 282, + 278, + 273, + 269, + 265, + 261, + 512, + 505, + 497, + 489, + 482, + 475, + 468, + 461, + 454, + 447, + 441, + 435, + 428, + 422, + 417, + 411, + 405, + 399, + 394, + 389, + 383, + 378, + 373, + 368, + 364, + 359, + 354, + 350, + 345, + 341, + 337, + 332, + 328, + 324, + 320, + 316, + 312, + 309, + 305, + 301, + 298, + 294, + 291, + 287, + 284, + 281, + 278, + 274, + 271, + 268, + 265, + 262, + 259, + 257, + 507, + 501, + 496, + 491, + 485, + 480, + 475, + 470, + 465, + 460, + 456, + 451, + 446, + 442, + 437, + 433, + 428, + 424, + 420, + 416, + 412, + 408, + 404, + 400, + 396, + 392, + 388, + 385, + 381, + 377, + 374, + 370, + 367, + 363, + 360, + 357, + 354, + 350, + 347, + 344, + 341, + 338, + 335, + 332, + 329, + 326, + 323, + 320, + 318, + 315, + 312, + 310, + 307, + 304, + 302, + 299, + 297, + 294, + 292, + 289, + 287, + 285, + 282, + 280, + 278, + 275, + 273, + 271, + 269, + 267, + 265, + 263, + 261, + 259, ]; var shg_table = [ - 9, - 11, - 12, - 13, - 13, - 14, - 14, - 15, - 15, - 15, - 15, - 16, - 16, - 16, - 16, - 17, - 17, - 17, - 17, - 17, - 17, - 17, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, + 9, + 11, + 12, + 13, + 13, + 14, + 14, + 15, + 15, + 15, + 15, + 16, + 16, + 16, + 16, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, ]; function filterGaussBlurRGBA(imageData, radius) { - var pixels = imageData.data, - width = imageData.width, - height = imageData.height; - var x, - y, - i, - p, - yp, - yi, - yw, - r_sum, - g_sum, - b_sum, - a_sum, - r_out_sum, - g_out_sum, - b_out_sum, - a_out_sum, - r_in_sum, - g_in_sum, - b_in_sum, - a_in_sum, - pr, - pg, - pb, - pa, - rbs; - var div = radius + radius + 1, - widthMinus1 = width - 1, - heightMinus1 = height - 1, - radiusPlus1 = radius + 1, - sumFactor = (radiusPlus1 * (radiusPlus1 + 1)) / 2, - stackStart = new BlurStack(), - stackEnd = null, - stack = stackStart, - stackIn = null, - stackOut = null, - mul_sum = mul_table[radius], - shg_sum = shg_table[radius]; - for (i = 1; i < div; i++) { - stack = stack.next = new BlurStack(); - if (i === radiusPlus1) { - stackEnd = stack; + var pixels = imageData.data, width = imageData.width, height = imageData.height; + var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, r_out_sum, g_out_sum, b_out_sum, a_out_sum, r_in_sum, g_in_sum, b_in_sum, a_in_sum, pr, pg, pb, pa, rbs; + var div = radius + radius + 1, widthMinus1 = width - 1, heightMinus1 = height - 1, radiusPlus1 = radius + 1, sumFactor = (radiusPlus1 * (radiusPlus1 + 1)) / 2, stackStart = new BlurStack(), stackEnd = null, stack = stackStart, stackIn = null, stackOut = null, mul_sum = mul_table[radius], shg_sum = shg_table[radius]; + for (i = 1; i < div; i++) { + stack = stack.next = new BlurStack(); + if (i === radiusPlus1) { + stackEnd = stack; + } } - } - stack.next = stackStart; - yw = yi = 0; - for (y = 0; y < height; y++) { - r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; - r_out_sum = radiusPlus1 * (pr = pixels[yi]); - g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]); - b_out_sum = radiusPlus1 * (pb = pixels[yi + 2]); - a_out_sum = radiusPlus1 * (pa = pixels[yi + 3]); - r_sum += sumFactor * pr; - g_sum += sumFactor * pg; - b_sum += sumFactor * pb; - a_sum += sumFactor * pa; - stack = stackStart; - for (i = 0; i < radiusPlus1; i++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack.a = pa; - stack = stack.next; - } - for (i = 1; i < radiusPlus1; i++) { - p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); - r_sum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i); - g_sum += (stack.g = pg = pixels[p + 1]) * rbs; - b_sum += (stack.b = pb = pixels[p + 2]) * rbs; - a_sum += (stack.a = pa = pixels[p + 3]) * rbs; - r_in_sum += pr; - g_in_sum += pg; - b_in_sum += pb; - a_in_sum += pa; - stack = stack.next; - } - stackIn = stackStart; - stackOut = stackEnd; - for (x = 0; x < width; x++) { - pixels[yi + 3] = pa = (a_sum * mul_sum) >> shg_sum; - if (pa !== 0) { - pa = 255 / pa; - pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; - pixels[yi + 1] = ((g_sum * mul_sum) >> shg_sum) * pa; - pixels[yi + 2] = ((b_sum * mul_sum) >> shg_sum) * pa; - } else { - pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0; - } - r_sum -= r_out_sum; - g_sum -= g_out_sum; - b_sum -= b_out_sum; - a_sum -= a_out_sum; - r_out_sum -= stackIn.r; - g_out_sum -= stackIn.g; - b_out_sum -= stackIn.b; - a_out_sum -= stackIn.a; - p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; - r_in_sum += stackIn.r = pixels[p]; - g_in_sum += stackIn.g = pixels[p + 1]; - b_in_sum += stackIn.b = pixels[p + 2]; - a_in_sum += stackIn.a = pixels[p + 3]; - r_sum += r_in_sum; - g_sum += g_in_sum; - b_sum += b_in_sum; - a_sum += a_in_sum; - stackIn = stackIn.next; - r_out_sum += pr = stackOut.r; - g_out_sum += pg = stackOut.g; - b_out_sum += pb = stackOut.b; - a_out_sum += pa = stackOut.a; - r_in_sum -= pr; - g_in_sum -= pg; - b_in_sum -= pb; - a_in_sum -= pa; - stackOut = stackOut.next; - yi += 4; - } - yw += width; - } - for (x = 0; x < width; x++) { - g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; - yi = x << 2; - r_out_sum = radiusPlus1 * (pr = pixels[yi]); - g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]); - b_out_sum = radiusPlus1 * (pb = pixels[yi + 2]); - a_out_sum = radiusPlus1 * (pa = pixels[yi + 3]); - r_sum += sumFactor * pr; - g_sum += sumFactor * pg; - b_sum += sumFactor * pb; - a_sum += sumFactor * pa; - stack = stackStart; - for (i = 0; i < radiusPlus1; i++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack.a = pa; - stack = stack.next; - } - yp = width; - for (i = 1; i <= radius; i++) { - yi = (yp + x) << 2; - r_sum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i); - g_sum += (stack.g = pg = pixels[yi + 1]) * rbs; - b_sum += (stack.b = pb = pixels[yi + 2]) * rbs; - a_sum += (stack.a = pa = pixels[yi + 3]) * rbs; - r_in_sum += pr; - g_in_sum += pg; - b_in_sum += pb; - a_in_sum += pa; - stack = stack.next; - if (i < heightMinus1) { - yp += width; - } - } - yi = x; - stackIn = stackStart; - stackOut = stackEnd; + stack.next = stackStart; + yw = yi = 0; for (y = 0; y < height; y++) { - p = yi << 2; - pixels[p + 3] = pa = (a_sum * mul_sum) >> shg_sum; - if (pa > 0) { - pa = 255 / pa; - pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa; - pixels[p + 1] = ((g_sum * mul_sum) >> shg_sum) * pa; - pixels[p + 2] = ((b_sum * mul_sum) >> shg_sum) * pa; - } else { - pixels[p] = pixels[p + 1] = pixels[p + 2] = 0; - } - r_sum -= r_out_sum; - g_sum -= g_out_sum; - b_sum -= b_out_sum; - a_sum -= a_out_sum; - r_out_sum -= stackIn.r; - g_out_sum -= stackIn.g; - b_out_sum -= stackIn.b; - a_out_sum -= stackIn.a; - p = - (x + - ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * - width) << - 2; - r_sum += r_in_sum += stackIn.r = pixels[p]; - g_sum += g_in_sum += stackIn.g = pixels[p + 1]; - b_sum += b_in_sum += stackIn.b = pixels[p + 2]; - a_sum += a_in_sum += stackIn.a = pixels[p + 3]; - stackIn = stackIn.next; - r_out_sum += pr = stackOut.r; - g_out_sum += pg = stackOut.g; - b_out_sum += pb = stackOut.b; - a_out_sum += pa = stackOut.a; - r_in_sum -= pr; - g_in_sum -= pg; - b_in_sum -= pb; - a_in_sum -= pa; - stackOut = stackOut.next; - yi += width; + r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; + r_out_sum = radiusPlus1 * (pr = pixels[yi]); + g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]); + b_out_sum = radiusPlus1 * (pb = pixels[yi + 2]); + a_out_sum = radiusPlus1 * (pa = pixels[yi + 3]); + r_sum += sumFactor * pr; + g_sum += sumFactor * pg; + b_sum += sumFactor * pb; + a_sum += sumFactor * pa; + stack = stackStart; + for (i = 0; i < radiusPlus1; i++) { + stack.r = pr; + stack.g = pg; + stack.b = pb; + stack.a = pa; + stack = stack.next; + } + for (i = 1; i < radiusPlus1; i++) { + p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); + r_sum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i); + g_sum += (stack.g = pg = pixels[p + 1]) * rbs; + b_sum += (stack.b = pb = pixels[p + 2]) * rbs; + a_sum += (stack.a = pa = pixels[p + 3]) * rbs; + r_in_sum += pr; + g_in_sum += pg; + b_in_sum += pb; + a_in_sum += pa; + stack = stack.next; + } + stackIn = stackStart; + stackOut = stackEnd; + for (x = 0; x < width; x++) { + pixels[yi + 3] = pa = (a_sum * mul_sum) >> shg_sum; + if (pa !== 0) { + pa = 255 / pa; + pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; + pixels[yi + 1] = ((g_sum * mul_sum) >> shg_sum) * pa; + pixels[yi + 2] = ((b_sum * mul_sum) >> shg_sum) * pa; + } + else { + pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0; + } + r_sum -= r_out_sum; + g_sum -= g_out_sum; + b_sum -= b_out_sum; + a_sum -= a_out_sum; + r_out_sum -= stackIn.r; + g_out_sum -= stackIn.g; + b_out_sum -= stackIn.b; + a_out_sum -= stackIn.a; + p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; + r_in_sum += stackIn.r = pixels[p]; + g_in_sum += stackIn.g = pixels[p + 1]; + b_in_sum += stackIn.b = pixels[p + 2]; + a_in_sum += stackIn.a = pixels[p + 3]; + r_sum += r_in_sum; + g_sum += g_in_sum; + b_sum += b_in_sum; + a_sum += a_in_sum; + stackIn = stackIn.next; + r_out_sum += pr = stackOut.r; + g_out_sum += pg = stackOut.g; + b_out_sum += pb = stackOut.b; + a_out_sum += pa = stackOut.a; + r_in_sum -= pr; + g_in_sum -= pg; + b_in_sum -= pb; + a_in_sum -= pa; + stackOut = stackOut.next; + yi += 4; + } + yw += width; + } + for (x = 0; x < width; x++) { + g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; + yi = x << 2; + r_out_sum = radiusPlus1 * (pr = pixels[yi]); + g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]); + b_out_sum = radiusPlus1 * (pb = pixels[yi + 2]); + a_out_sum = radiusPlus1 * (pa = pixels[yi + 3]); + r_sum += sumFactor * pr; + g_sum += sumFactor * pg; + b_sum += sumFactor * pb; + a_sum += sumFactor * pa; + stack = stackStart; + for (i = 0; i < radiusPlus1; i++) { + stack.r = pr; + stack.g = pg; + stack.b = pb; + stack.a = pa; + stack = stack.next; + } + yp = width; + for (i = 1; i <= radius; i++) { + yi = (yp + x) << 2; + r_sum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i); + g_sum += (stack.g = pg = pixels[yi + 1]) * rbs; + b_sum += (stack.b = pb = pixels[yi + 2]) * rbs; + a_sum += (stack.a = pa = pixels[yi + 3]) * rbs; + r_in_sum += pr; + g_in_sum += pg; + b_in_sum += pb; + a_in_sum += pa; + stack = stack.next; + if (i < heightMinus1) { + yp += width; + } + } + yi = x; + stackIn = stackStart; + stackOut = stackEnd; + for (y = 0; y < height; y++) { + p = yi << 2; + pixels[p + 3] = pa = (a_sum * mul_sum) >> shg_sum; + if (pa > 0) { + pa = 255 / pa; + pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa; + pixels[p + 1] = ((g_sum * mul_sum) >> shg_sum) * pa; + pixels[p + 2] = ((b_sum * mul_sum) >> shg_sum) * pa; + } + else { + pixels[p] = pixels[p + 1] = pixels[p + 2] = 0; + } + r_sum -= r_out_sum; + g_sum -= g_out_sum; + b_sum -= b_out_sum; + a_sum -= a_out_sum; + r_out_sum -= stackIn.r; + g_out_sum -= stackIn.g; + b_out_sum -= stackIn.b; + a_out_sum -= stackIn.a; + p = + (x + + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width) << + 2; + r_sum += r_in_sum += stackIn.r = pixels[p]; + g_sum += g_in_sum += stackIn.g = pixels[p + 1]; + b_sum += b_in_sum += stackIn.b = pixels[p + 2]; + a_sum += a_in_sum += stackIn.a = pixels[p + 3]; + stackIn = stackIn.next; + r_out_sum += pr = stackOut.r; + g_out_sum += pg = stackOut.g; + b_out_sum += pb = stackOut.b; + a_out_sum += pa = stackOut.a; + r_in_sum -= pr; + g_in_sum -= pg; + b_in_sum -= pb; + a_in_sum -= pa; + stackOut = stackOut.next; + yi += width; + } } - } } /** * Blur Filter @@ -16781,26 +15499,20 @@ * node.blurRadius(10); */ const Blur = function Blur(imageData) { - var radius = Math.round(this.blurRadius()); - if (radius > 0) { - filterGaussBlurRGBA(imageData, radius); - } + var radius = Math.round(this.blurRadius()); + if (radius > 0) { + filterGaussBlurRGBA(imageData, radius); + } }; - Factory.addGetterSetter( - Node, - 'blurRadius', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'blurRadius', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set blur radius. Use with {@link Konva.Filters.Blur} filter * @name Konva.Node#blurRadius * @method * @param {Integer} radius * @returns {Integer} - */ - + */ + /** * Brighten Filter. * @function @@ -16812,36 +15524,27 @@ * node.brightness(0.8); */ const Brighten = function (imageData) { - var brightness = this.brightness() * 255, - data = imageData.data, - len = data.length, - i; - for (i = 0; i < len; i += 4) { - // red - data[i] += brightness; - // green - data[i + 1] += brightness; - // blue - data[i + 2] += brightness; - } + var brightness = this.brightness() * 255, data = imageData.data, len = data.length, i; + for (i = 0; i < len; i += 4) { + // red + data[i] += brightness; + // green + data[i + 1] += brightness; + // blue + data[i + 2] += brightness; + } }; - Factory.addGetterSetter( - Node, - 'brightness', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'brightness', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set filter brightness. The brightness is a number between -1 and 1.  Positive values * brighten the pixels and negative values darken them. Use with {@link Konva.Filters.Brighten} filter. * @name Konva.Node#brightness * @method - + * @param {Number} brightness value between -1 and 1 * @returns {Number} - */ - + */ + /** * Contrast Filter. * @function @@ -16853,42 +15556,37 @@ * node.contrast(10); */ const Contrast = function (imageData) { - var adjust = Math.pow((this.contrast() + 100) / 100, 2); - var data = imageData.data, - nPixels = data.length, - red = 150, - green = 150, - blue = 150, - i; - for (i = 0; i < nPixels; i += 4) { - red = data[i]; - green = data[i + 1]; - blue = data[i + 2]; - //Red channel - red /= 255; - red -= 0.5; - red *= adjust; - red += 0.5; - red *= 255; - //Green channel - green /= 255; - green -= 0.5; - green *= adjust; - green += 0.5; - green *= 255; - //Blue channel - blue /= 255; - blue -= 0.5; - blue *= adjust; - blue += 0.5; - blue *= 255; - red = red < 0 ? 0 : red > 255 ? 255 : red; - green = green < 0 ? 0 : green > 255 ? 255 : green; - blue = blue < 0 ? 0 : blue > 255 ? 255 : blue; - data[i] = red; - data[i + 1] = green; - data[i + 2] = blue; - } + var adjust = Math.pow((this.contrast() + 100) / 100, 2); + var data = imageData.data, nPixels = data.length, red = 150, green = 150, blue = 150, i; + for (i = 0; i < nPixels; i += 4) { + red = data[i]; + green = data[i + 1]; + blue = data[i + 2]; + //Red channel + red /= 255; + red -= 0.5; + red *= adjust; + red += 0.5; + red *= 255; + //Green channel + green /= 255; + green -= 0.5; + green *= adjust; + green += 0.5; + green *= 255; + //Blue channel + blue /= 255; + blue -= 0.5; + blue *= adjust; + blue += 0.5; + blue *= 255; + red = red < 0 ? 0 : red > 255 ? 255 : red; + green = green < 0 ? 0 : green > 255 ? 255 : green; + blue = blue < 0 ? 0 : blue > 255 ? 255 : blue; + data[i] = red; + data[i + 1] = green; + data[i + 2] = blue; + } }; /** * get/set filter contrast. The contrast is a number between -100 and 100. @@ -16898,14 +15596,8 @@ * @param {Number} contrast value between -100 and 100 * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'contrast', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); - + Factory.addGetterSetter(Node, 'contrast', 0, getNumberValidator(), Factory.afterSetFilter); + /** * Emboss Filter. * Pixastic Lib - Emboss filter - v0.1.0 @@ -16923,118 +15615,104 @@ * node.embossBlend(true); */ const Emboss = function (imageData) { - // pixastic strength is between 0 and 10. I want it between 0 and 1 - // pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also, - // a max value of greyLevel yields a white emboss, and the min value yields a black - // emboss. Therefore, I changed greyLevel to whiteLevel - var strength = this.embossStrength() * 10, - greyLevel = this.embossWhiteLevel() * 255, - direction = this.embossDirection(), - blend = this.embossBlend(), - dirY = 0, - dirX = 0, - data = imageData.data, - w = imageData.width, - h = imageData.height, - w4 = w * 4, - y = h; - switch (direction) { - case 'top-left': - dirY = -1; - dirX = -1; - break; - case 'top': - dirY = -1; - dirX = 0; - break; - case 'top-right': - dirY = -1; - dirX = 1; - break; - case 'right': - dirY = 0; - dirX = 1; - break; - case 'bottom-right': - dirY = 1; - dirX = 1; - break; - case 'bottom': - dirY = 1; - dirX = 0; - break; - case 'bottom-left': - dirY = 1; - dirX = -1; - break; - case 'left': - dirY = 0; - dirX = -1; - break; - default: - Util.error('Unknown emboss direction: ' + direction); - } - do { - var offsetY = (y - 1) * w4; - var otherY = dirY; - if (y + otherY < 1) { - otherY = 0; + // pixastic strength is between 0 and 10. I want it between 0 and 1 + // pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also, + // a max value of greyLevel yields a white emboss, and the min value yields a black + // emboss. Therefore, I changed greyLevel to whiteLevel + var strength = this.embossStrength() * 10, greyLevel = this.embossWhiteLevel() * 255, direction = this.embossDirection(), blend = this.embossBlend(), dirY = 0, dirX = 0, data = imageData.data, w = imageData.width, h = imageData.height, w4 = w * 4, y = h; + switch (direction) { + case 'top-left': + dirY = -1; + dirX = -1; + break; + case 'top': + dirY = -1; + dirX = 0; + break; + case 'top-right': + dirY = -1; + dirX = 1; + break; + case 'right': + dirY = 0; + dirX = 1; + break; + case 'bottom-right': + dirY = 1; + dirX = 1; + break; + case 'bottom': + dirY = 1; + dirX = 0; + break; + case 'bottom-left': + dirY = 1; + dirX = -1; + break; + case 'left': + dirY = 0; + dirX = -1; + break; + default: + Util.error('Unknown emboss direction: ' + direction); } - if (y + otherY > h) { - otherY = 0; - } - var offsetYOther = (y - 1 + otherY) * w * 4; - var x = w; do { - var offset = offsetY + (x - 1) * 4; - var otherX = dirX; - if (x + otherX < 1) { - otherX = 0; - } - if (x + otherX > w) { - otherX = 0; - } - var offsetOther = offsetYOther + (x - 1 + otherX) * 4; - var dR = data[offset] - data[offsetOther]; - var dG = data[offset + 1] - data[offsetOther + 1]; - var dB = data[offset + 2] - data[offsetOther + 2]; - var dif = dR; - var absDif = dif > 0 ? dif : -dif; - var absG = dG > 0 ? dG : -dG; - var absB = dB > 0 ? dB : -dB; - if (absG > absDif) { - dif = dG; - } - if (absB > absDif) { - dif = dB; - } - dif *= strength; - if (blend) { - var r = data[offset] + dif; - var g = data[offset + 1] + dif; - var b = data[offset + 2] + dif; - data[offset] = r > 255 ? 255 : r < 0 ? 0 : r; - data[offset + 1] = g > 255 ? 255 : g < 0 ? 0 : g; - data[offset + 2] = b > 255 ? 255 : b < 0 ? 0 : b; - } else { - var grey = greyLevel - dif; - if (grey < 0) { - grey = 0; - } else if (grey > 255) { - grey = 255; + var offsetY = (y - 1) * w4; + var otherY = dirY; + if (y + otherY < 1) { + otherY = 0; } - data[offset] = data[offset + 1] = data[offset + 2] = grey; - } - } while (--x); - } while (--y); + if (y + otherY > h) { + otherY = 0; + } + var offsetYOther = (y - 1 + otherY) * w * 4; + var x = w; + do { + var offset = offsetY + (x - 1) * 4; + var otherX = dirX; + if (x + otherX < 1) { + otherX = 0; + } + if (x + otherX > w) { + otherX = 0; + } + var offsetOther = offsetYOther + (x - 1 + otherX) * 4; + var dR = data[offset] - data[offsetOther]; + var dG = data[offset + 1] - data[offsetOther + 1]; + var dB = data[offset + 2] - data[offsetOther + 2]; + var dif = dR; + var absDif = dif > 0 ? dif : -dif; + var absG = dG > 0 ? dG : -dG; + var absB = dB > 0 ? dB : -dB; + if (absG > absDif) { + dif = dG; + } + if (absB > absDif) { + dif = dB; + } + dif *= strength; + if (blend) { + var r = data[offset] + dif; + var g = data[offset + 1] + dif; + var b = data[offset + 2] + dif; + data[offset] = r > 255 ? 255 : r < 0 ? 0 : r; + data[offset + 1] = g > 255 ? 255 : g < 0 ? 0 : g; + data[offset + 2] = b > 255 ? 255 : b < 0 ? 0 : b; + } + else { + var grey = greyLevel - dif; + if (grey < 0) { + grey = 0; + } + else if (grey > 255) { + grey = 255; + } + data[offset] = data[offset + 1] = data[offset + 2] = grey; + } + } while (--x); + } while (--y); }; - Factory.addGetterSetter( - Node, - 'embossStrength', - 0.5, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'embossStrength', 0.5, getNumberValidator(), Factory.afterSetFilter); /** * get/set emboss strength. Use with {@link Konva.Filters.Emboss} filter. * @name Konva.Node#embossStrength @@ -17042,13 +15720,7 @@ * @param {Number} level between 0 and 1. Default is 0.5 * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'embossWhiteLevel', - 0.5, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'embossWhiteLevel', 0.5, getNumberValidator(), Factory.afterSetFilter); /** * get/set emboss white level. Use with {@link Konva.Filters.Emboss} filter. * @name Konva.Node#embossWhiteLevel @@ -17056,13 +15728,7 @@ * @param {Number} embossWhiteLevel between 0 and 1. Default is 0.5 * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'embossDirection', - 'top-left', - null, - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'embossDirection', 'top-left', null, Factory.afterSetFilter); /** * get/set emboss direction. Use with {@link Konva.Filters.Emboss} filter. * @name Konva.Node#embossDirection @@ -17071,37 +15737,29 @@ * The default is top-left * @returns {String} */ - Factory.addGetterSetter( - Node, - 'embossBlend', - false, - null, - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'embossBlend', false, null, Factory.afterSetFilter); /** * get/set emboss blend. Use with {@link Konva.Filters.Emboss} filter. * @name Konva.Node#embossBlend * @method * @param {Boolean} embossBlend * @returns {Boolean} - */ - + */ + function remap(fromValue, fromMin, fromMax, toMin, toMax) { - // Compute the range of the data - var fromRange = fromMax - fromMin, - toRange = toMax - toMin, - toValue; - // If either range is 0, then the value can only be mapped to 1 value - if (fromRange === 0) { - return toMin + toRange / 2; - } - if (toRange === 0) { - return toMin; - } - // (1) untranslate, (2) unscale, (3) rescale, (4) retranslate - toValue = (fromValue - fromMin) / fromRange; - toValue = toRange * toValue + toMin; - return toValue; + // Compute the range of the data + var fromRange = fromMax - fromMin, toRange = toMax - toMin, toValue; + // If either range is 0, then the value can only be mapped to 1 value + if (fromRange === 0) { + return toMin + toRange / 2; + } + if (toRange === 0) { + return toMin; + } + // (1) untranslate, (2) unscale, (3) rescale, (4) retranslate + toValue = (fromValue - fromMin) / fromRange; + toValue = toRange * toValue + toMin; + return toValue; } /** * Enhance Filter. Adjusts the colors so that they span the widest @@ -17118,96 +15776,81 @@ * node.enhance(0.4); */ const Enhance = function (imageData) { - var data = imageData.data, - nSubPixels = data.length, - rMin = data[0], - rMax = rMin, - r, - gMin = data[1], - gMax = gMin, - g, - bMin = data[2], - bMax = bMin, - b, - i; - // If we are not enhancing anything - don't do any computation - var enhanceAmount = this.enhance(); - if (enhanceAmount === 0) { - return; - } - // 1st Pass - find the min and max for each channel: - for (i = 0; i < nSubPixels; i += 4) { - r = data[i + 0]; - if (r < rMin) { - rMin = r; - } else if (r > rMax) { - rMax = r; + var data = imageData.data, nSubPixels = data.length, rMin = data[0], rMax = rMin, r, gMin = data[1], gMax = gMin, g, bMin = data[2], bMax = bMin, b, i; + // If we are not enhancing anything - don't do any computation + var enhanceAmount = this.enhance(); + if (enhanceAmount === 0) { + return; } - g = data[i + 1]; - if (g < gMin) { - gMin = g; - } else if (g > gMax) { - gMax = g; + // 1st Pass - find the min and max for each channel: + for (i = 0; i < nSubPixels; i += 4) { + r = data[i + 0]; + if (r < rMin) { + rMin = r; + } + else if (r > rMax) { + rMax = r; + } + g = data[i + 1]; + if (g < gMin) { + gMin = g; + } + else if (g > gMax) { + gMax = g; + } + b = data[i + 2]; + if (b < bMin) { + bMin = b; + } + else if (b > bMax) { + bMax = b; + } + //a = data[i + 3]; + //if (a < aMin) { aMin = a; } else + //if (a > aMax) { aMax = a; } } - b = data[i + 2]; - if (b < bMin) { - bMin = b; - } else if (b > bMax) { - bMax = b; + // If there is only 1 level - don't remap + if (rMax === rMin) { + rMax = 255; + rMin = 0; + } + if (gMax === gMin) { + gMax = 255; + gMin = 0; + } + if (bMax === bMin) { + bMax = 255; + bMin = 0; + } + var rMid, rGoalMax, rGoalMin, gMid, gGoalMax, gGoalMin, bMid, bGoalMax, bGoalMin; + // If the enhancement is positive - stretch the histogram + if (enhanceAmount > 0) { + rGoalMax = rMax + enhanceAmount * (255 - rMax); + rGoalMin = rMin - enhanceAmount * (rMin - 0); + gGoalMax = gMax + enhanceAmount * (255 - gMax); + gGoalMin = gMin - enhanceAmount * (gMin - 0); + bGoalMax = bMax + enhanceAmount * (255 - bMax); + bGoalMin = bMin - enhanceAmount * (bMin - 0); + // If the enhancement is negative - compress the histogram + } + else { + rMid = (rMax + rMin) * 0.5; + rGoalMax = rMax + enhanceAmount * (rMax - rMid); + rGoalMin = rMin + enhanceAmount * (rMin - rMid); + gMid = (gMax + gMin) * 0.5; + gGoalMax = gMax + enhanceAmount * (gMax - gMid); + gGoalMin = gMin + enhanceAmount * (gMin - gMid); + bMid = (bMax + bMin) * 0.5; + bGoalMax = bMax + enhanceAmount * (bMax - bMid); + bGoalMin = bMin + enhanceAmount * (bMin - bMid); + } + // Pass 2 - remap everything, except the alpha + for (i = 0; i < nSubPixels; i += 4) { + data[i + 0] = remap(data[i + 0], rMin, rMax, rGoalMin, rGoalMax); + data[i + 1] = remap(data[i + 1], gMin, gMax, gGoalMin, gGoalMax); + data[i + 2] = remap(data[i + 2], bMin, bMax, bGoalMin, bGoalMax); + //data[i + 3] = remap(data[i + 3], aMin, aMax, aGoalMin, aGoalMax); } - //a = data[i + 3]; - //if (a < aMin) { aMin = a; } else - //if (a > aMax) { aMax = a; } - } - // If there is only 1 level - don't remap - if (rMax === rMin) { - rMax = 255; - rMin = 0; - } - if (gMax === gMin) { - gMax = 255; - gMin = 0; - } - if (bMax === bMin) { - bMax = 255; - bMin = 0; - } - var rMid, - rGoalMax, - rGoalMin, - gMid, - gGoalMax, - gGoalMin, - bMid, - bGoalMax, - bGoalMin; - // If the enhancement is positive - stretch the histogram - if (enhanceAmount > 0) { - rGoalMax = rMax + enhanceAmount * (255 - rMax); - rGoalMin = rMin - enhanceAmount * (rMin - 0); - gGoalMax = gMax + enhanceAmount * (255 - gMax); - gGoalMin = gMin - enhanceAmount * (gMin - 0); - bGoalMax = bMax + enhanceAmount * (255 - bMax); - bGoalMin = bMin - enhanceAmount * (bMin - 0); - // If the enhancement is negative - compress the histogram - } else { - rMid = (rMax + rMin) * 0.5; - rGoalMax = rMax + enhanceAmount * (rMax - rMid); - rGoalMin = rMin + enhanceAmount * (rMin - rMid); - gMid = (gMax + gMin) * 0.5; - gGoalMax = gMax + enhanceAmount * (gMax - gMid); - gGoalMin = gMin + enhanceAmount * (gMin - gMid); - bMid = (bMax + bMin) * 0.5; - bGoalMax = bMax + enhanceAmount * (bMax - bMid); - bGoalMin = bMin + enhanceAmount * (bMin - bMid); - } - // Pass 2 - remap everything, except the alpha - for (i = 0; i < nSubPixels; i += 4) { - data[i + 0] = remap(data[i + 0], rMin, rMax, rGoalMin, rGoalMax); - data[i + 1] = remap(data[i + 1], gMin, gMax, gGoalMin, gGoalMax); - data[i + 2] = remap(data[i + 2], bMin, bMax, bGoalMin, bGoalMax); - //data[i + 3] = remap(data[i + 3], aMin, aMax, aGoalMin, aGoalMax); - } }; /** * get/set enhance. Use with {@link Konva.Filters.Enhance} filter. -1 to 1 values @@ -17216,14 +15859,8 @@ * @param {Float} amount * @returns {Float} */ - Factory.addGetterSetter( - Node, - 'enhance', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); - + Factory.addGetterSetter(Node, 'enhance', 0, getNumberValidator(), Factory.afterSetFilter); + /** * Grayscale Filter * @function @@ -17234,28 +15871,19 @@ * node.filters([Konva.Filters.Grayscale]); */ const Grayscale = function (imageData) { - var data = imageData.data, - len = data.length, - i, - brightness; - for (i = 0; i < len; i += 4) { - brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]; - // red - data[i] = brightness; - // green - data[i + 1] = brightness; - // blue - data[i + 2] = brightness; - } - }; - - Factory.addGetterSetter( - Node, - 'hue', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + var data = imageData.data, len = data.length, i, brightness; + for (i = 0; i < len; i += 4) { + brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]; + // red + data[i] = brightness; + // green + data[i + 1] = brightness; + // blue + data[i + 2] = brightness; + } + }; + + Factory.addGetterSetter(Node, 'hue', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsv hue in degrees. Use with {@link Konva.Filters.HSV} or {@link Konva.Filters.HSL} filter. * @name Konva.Node#hue @@ -17263,13 +15891,7 @@ * @param {Number} hue value between 0 and 359 * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'saturation', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'saturation', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsv saturation. Use with {@link Konva.Filters.HSV} or {@link Konva.Filters.HSL} filter. * @name Konva.Node#saturation @@ -17277,13 +15899,7 @@ * @param {Number} saturation 0 is no change, -1.0 halves the saturation, 1.0 doubles, etc.. * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'luminance', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'luminance', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsl luminance. Use with {@link Konva.Filters.HSL} filter. * @name Konva.Node#luminance @@ -17302,49 +15918,36 @@ * image.luminance(0.2); */ const HSL = function (imageData) { - var data = imageData.data, - nPixels = data.length, - v = 1, - s = Math.pow(2, this.saturation()), - h = Math.abs(this.hue() + 360) % 360, - l = this.luminance() * 127, - i; - // Basis for the technique used: - // http://beesbuzz.biz/code/hsv_color_transforms.php - // V is the value multiplier (1 for none, 2 for double, 0.5 for half) - // S is the saturation multiplier (1 for none, 2 for double, 0.5 for half) - // H is the hue shift in degrees (0 to 360) - // vsu = V*S*cos(H*PI/180); - // vsw = V*S*sin(H*PI/180); - //[ .299V+.701vsu+.168vsw .587V-.587vsu+.330vsw .114V-.114vsu-.497vsw ] [R] - //[ .299V-.299vsu-.328vsw .587V+.413vsu+.035vsw .114V-.114vsu+.292vsw ]*[G] - //[ .299V-.300vsu+1.25vsw .587V-.588vsu-1.05vsw .114V+.886vsu-.203vsw ] [B] - // Precompute the values in the matrix: - var vsu = v * s * Math.cos((h * Math.PI) / 180), - vsw = v * s * Math.sin((h * Math.PI) / 180); - // (result spot)(source spot) - var rr = 0.299 * v + 0.701 * vsu + 0.167 * vsw, - rg = 0.587 * v - 0.587 * vsu + 0.33 * vsw, - rb = 0.114 * v - 0.114 * vsu - 0.497 * vsw; - var gr = 0.299 * v - 0.299 * vsu - 0.328 * vsw, - gg = 0.587 * v + 0.413 * vsu + 0.035 * vsw, - gb = 0.114 * v - 0.114 * vsu + 0.293 * vsw; - var br = 0.299 * v - 0.3 * vsu + 1.25 * vsw, - bg = 0.587 * v - 0.586 * vsu - 1.05 * vsw, - bb = 0.114 * v + 0.886 * vsu - 0.2 * vsw; - var r, g, b, a; - for (i = 0; i < nPixels; i += 4) { - r = data[i + 0]; - g = data[i + 1]; - b = data[i + 2]; - a = data[i + 3]; - data[i + 0] = rr * r + rg * g + rb * b + l; - data[i + 1] = gr * r + gg * g + gb * b + l; - data[i + 2] = br * r + bg * g + bb * b + l; - data[i + 3] = a; // alpha - } - }; - + var data = imageData.data, nPixels = data.length, v = 1, s = Math.pow(2, this.saturation()), h = Math.abs(this.hue() + 360) % 360, l = this.luminance() * 127, i; + // Basis for the technique used: + // http://beesbuzz.biz/code/hsv_color_transforms.php + // V is the value multiplier (1 for none, 2 for double, 0.5 for half) + // S is the saturation multiplier (1 for none, 2 for double, 0.5 for half) + // H is the hue shift in degrees (0 to 360) + // vsu = V*S*cos(H*PI/180); + // vsw = V*S*sin(H*PI/180); + //[ .299V+.701vsu+.168vsw .587V-.587vsu+.330vsw .114V-.114vsu-.497vsw ] [R] + //[ .299V-.299vsu-.328vsw .587V+.413vsu+.035vsw .114V-.114vsu+.292vsw ]*[G] + //[ .299V-.300vsu+1.25vsw .587V-.588vsu-1.05vsw .114V+.886vsu-.203vsw ] [B] + // Precompute the values in the matrix: + var vsu = v * s * Math.cos((h * Math.PI) / 180), vsw = v * s * Math.sin((h * Math.PI) / 180); + // (result spot)(source spot) + var rr = 0.299 * v + 0.701 * vsu + 0.167 * vsw, rg = 0.587 * v - 0.587 * vsu + 0.33 * vsw, rb = 0.114 * v - 0.114 * vsu - 0.497 * vsw; + var gr = 0.299 * v - 0.299 * vsu - 0.328 * vsw, gg = 0.587 * v + 0.413 * vsu + 0.035 * vsw, gb = 0.114 * v - 0.114 * vsu + 0.293 * vsw; + var br = 0.299 * v - 0.3 * vsu + 1.25 * vsw, bg = 0.587 * v - 0.586 * vsu - 1.05 * vsw, bb = 0.114 * v + 0.886 * vsu - 0.2 * vsw; + var r, g, b, a; + for (i = 0; i < nPixels; i += 4) { + r = data[i + 0]; + g = data[i + 1]; + b = data[i + 2]; + a = data[i + 3]; + data[i + 0] = rr * r + rg * g + rb * b + l; + data[i + 1] = gr * r + gg * g + gb * b + l; + data[i + 2] = br * r + bg * g + bb * b + l; + data[i + 3] = a; // alpha + } + }; + /** * HSV Filter. Adjusts the hue, saturation and value * @function @@ -17357,54 +15960,36 @@ * image.value(200); */ const HSV = function (imageData) { - var data = imageData.data, - nPixels = data.length, - v = Math.pow(2, this.value()), - s = Math.pow(2, this.saturation()), - h = Math.abs(this.hue() + 360) % 360, - i; - // Basis for the technique used: - // http://beesbuzz.biz/code/hsv_color_transforms.php - // V is the value multiplier (1 for none, 2 for double, 0.5 for half) - // S is the saturation multiplier (1 for none, 2 for double, 0.5 for half) - // H is the hue shift in degrees (0 to 360) - // vsu = V*S*cos(H*PI/180); - // vsw = V*S*sin(H*PI/180); - //[ .299V+.701vsu+.168vsw .587V-.587vsu+.330vsw .114V-.114vsu-.497vsw ] [R] - //[ .299V-.299vsu-.328vsw .587V+.413vsu+.035vsw .114V-.114vsu+.292vsw ]*[G] - //[ .299V-.300vsu+1.25vsw .587V-.588vsu-1.05vsw .114V+.886vsu-.203vsw ] [B] - // Precompute the values in the matrix: - var vsu = v * s * Math.cos((h * Math.PI) / 180), - vsw = v * s * Math.sin((h * Math.PI) / 180); - // (result spot)(source spot) - var rr = 0.299 * v + 0.701 * vsu + 0.167 * vsw, - rg = 0.587 * v - 0.587 * vsu + 0.33 * vsw, - rb = 0.114 * v - 0.114 * vsu - 0.497 * vsw; - var gr = 0.299 * v - 0.299 * vsu - 0.328 * vsw, - gg = 0.587 * v + 0.413 * vsu + 0.035 * vsw, - gb = 0.114 * v - 0.114 * vsu + 0.293 * vsw; - var br = 0.299 * v - 0.3 * vsu + 1.25 * vsw, - bg = 0.587 * v - 0.586 * vsu - 1.05 * vsw, - bb = 0.114 * v + 0.886 * vsu - 0.2 * vsw; - var r, g, b, a; - for (i = 0; i < nPixels; i += 4) { - r = data[i + 0]; - g = data[i + 1]; - b = data[i + 2]; - a = data[i + 3]; - data[i + 0] = rr * r + rg * g + rb * b; - data[i + 1] = gr * r + gg * g + gb * b; - data[i + 2] = br * r + bg * g + bb * b; - data[i + 3] = a; // alpha - } + var data = imageData.data, nPixels = data.length, v = Math.pow(2, this.value()), s = Math.pow(2, this.saturation()), h = Math.abs(this.hue() + 360) % 360, i; + // Basis for the technique used: + // http://beesbuzz.biz/code/hsv_color_transforms.php + // V is the value multiplier (1 for none, 2 for double, 0.5 for half) + // S is the saturation multiplier (1 for none, 2 for double, 0.5 for half) + // H is the hue shift in degrees (0 to 360) + // vsu = V*S*cos(H*PI/180); + // vsw = V*S*sin(H*PI/180); + //[ .299V+.701vsu+.168vsw .587V-.587vsu+.330vsw .114V-.114vsu-.497vsw ] [R] + //[ .299V-.299vsu-.328vsw .587V+.413vsu+.035vsw .114V-.114vsu+.292vsw ]*[G] + //[ .299V-.300vsu+1.25vsw .587V-.588vsu-1.05vsw .114V+.886vsu-.203vsw ] [B] + // Precompute the values in the matrix: + var vsu = v * s * Math.cos((h * Math.PI) / 180), vsw = v * s * Math.sin((h * Math.PI) / 180); + // (result spot)(source spot) + var rr = 0.299 * v + 0.701 * vsu + 0.167 * vsw, rg = 0.587 * v - 0.587 * vsu + 0.33 * vsw, rb = 0.114 * v - 0.114 * vsu - 0.497 * vsw; + var gr = 0.299 * v - 0.299 * vsu - 0.328 * vsw, gg = 0.587 * v + 0.413 * vsu + 0.035 * vsw, gb = 0.114 * v - 0.114 * vsu + 0.293 * vsw; + var br = 0.299 * v - 0.3 * vsu + 1.25 * vsw, bg = 0.587 * v - 0.586 * vsu - 1.05 * vsw, bb = 0.114 * v + 0.886 * vsu - 0.2 * vsw; + var r, g, b, a; + for (i = 0; i < nPixels; i += 4) { + r = data[i + 0]; + g = data[i + 1]; + b = data[i + 2]; + a = data[i + 3]; + data[i + 0] = rr * r + rg * g + rb * b; + data[i + 1] = gr * r + gg * g + gb * b; + data[i + 2] = br * r + bg * g + bb * b; + data[i + 3] = a; // alpha + } }; - Factory.addGetterSetter( - Node, - 'hue', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'hue', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsv hue in degrees. Use with {@link Konva.Filters.HSV} or {@link Konva.Filters.HSL} filter. * @name Konva.Node#hue @@ -17412,13 +15997,7 @@ * @param {Number} hue value between 0 and 359 * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'saturation', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'saturation', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsv saturation. Use with {@link Konva.Filters.HSV} or {@link Konva.Filters.HSL} filter. * @name Konva.Node#saturation @@ -17426,21 +16005,15 @@ * @param {Number} saturation 0 is no change, -1.0 halves the saturation, 1.0 doubles, etc.. * @returns {Number} */ - Factory.addGetterSetter( - Node, - 'value', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'value', 0, getNumberValidator(), Factory.afterSetFilter); /** * get/set hsv value. Use with {@link Konva.Filters.HSV} filter. * @name Konva.Node#value * @method * @param {Number} value 0 is no change, -1.0 halves the value, 1.0 doubles, etc.. * @returns {Number} - */ - + */ + /** * Invert Filter * @function @@ -17451,19 +16024,17 @@ * node.filters([Konva.Filters.Invert]); */ const Invert = function (imageData) { - var data = imageData.data, - len = data.length, - i; - for (i = 0; i < len; i += 4) { - // red - data[i] = 255 - data[i]; - // green - data[i + 1] = 255 - data[i + 1]; - // blue - data[i + 2] = 255 - data[i + 2]; - } - }; - + var data = imageData.data, len = data.length, i; + for (i = 0; i < len; i += 4) { + // red + data[i] = 255 - data[i]; + // green + data[i + 1] = 255 - data[i + 1]; + // blue + data[i + 2] = 255 - data[i + 2]; + } + }; + /* * ToPolar Filter. Converts image data to polar coordinates. Performs * w*h*4 pixel reads and w*h pixel writes. The r axis is placed along @@ -17480,57 +16051,39 @@ * default is in the middle */ var ToPolar = function (src, dst, opt) { - var srcPixels = src.data, - dstPixels = dst.data, - xSize = src.width, - ySize = src.height, - xMid = opt.polarCenterX || xSize / 2, - yMid = opt.polarCenterY || ySize / 2, - i, - x, - y, - r = 0, - g = 0, - b = 0, - a = 0; - // Find the largest radius - var rad, - rMax = Math.sqrt(xMid * xMid + yMid * yMid); - x = xSize - xMid; - y = ySize - yMid; - rad = Math.sqrt(x * x + y * y); - rMax = rad > rMax ? rad : rMax; - // We'll be uisng y as the radius, and x as the angle (theta=t) - var rSize = ySize, - tSize = xSize, - radius, - theta; - // We want to cover all angles (0-360) and we need to convert to - // radians (*PI/180) - var conversion = ((360 / tSize) * Math.PI) / 180, - sin, - cos; - // var x1, x2, x1i, x2i, y1, y2, y1i, y2i, scale; - for (theta = 0; theta < tSize; theta += 1) { - sin = Math.sin(theta * conversion); - cos = Math.cos(theta * conversion); - for (radius = 0; radius < rSize; radius += 1) { - x = Math.floor(xMid + ((rMax * radius) / rSize) * cos); - y = Math.floor(yMid + ((rMax * radius) / rSize) * sin); - i = (y * xSize + x) * 4; - r = srcPixels[i + 0]; - g = srcPixels[i + 1]; - b = srcPixels[i + 2]; - a = srcPixels[i + 3]; - // Store it - //i = (theta * xSize + radius) * 4; - i = (theta + radius * xSize) * 4; - dstPixels[i + 0] = r; - dstPixels[i + 1] = g; - dstPixels[i + 2] = b; - dstPixels[i + 3] = a; + var srcPixels = src.data, dstPixels = dst.data, xSize = src.width, ySize = src.height, xMid = opt.polarCenterX || xSize / 2, yMid = opt.polarCenterY || ySize / 2, i, x, y, r = 0, g = 0, b = 0, a = 0; + // Find the largest radius + var rad, rMax = Math.sqrt(xMid * xMid + yMid * yMid); + x = xSize - xMid; + y = ySize - yMid; + rad = Math.sqrt(x * x + y * y); + rMax = rad > rMax ? rad : rMax; + // We'll be uisng y as the radius, and x as the angle (theta=t) + var rSize = ySize, tSize = xSize, radius, theta; + // We want to cover all angles (0-360) and we need to convert to + // radians (*PI/180) + var conversion = ((360 / tSize) * Math.PI) / 180, sin, cos; + // var x1, x2, x1i, x2i, y1, y2, y1i, y2i, scale; + for (theta = 0; theta < tSize; theta += 1) { + sin = Math.sin(theta * conversion); + cos = Math.cos(theta * conversion); + for (radius = 0; radius < rSize; radius += 1) { + x = Math.floor(xMid + ((rMax * radius) / rSize) * cos); + y = Math.floor(yMid + ((rMax * radius) / rSize) * sin); + i = (y * xSize + x) * 4; + r = srcPixels[i + 0]; + g = srcPixels[i + 1]; + b = srcPixels[i + 2]; + a = srcPixels[i + 3]; + // Store it + //i = (theta * xSize + radius) * 4; + i = (theta + radius * xSize) * 4; + dstPixels[i + 0] = r; + dstPixels[i + 1] = g; + dstPixels[i + 2] = b; + dstPixels[i + 3] = a; + } } - } }; /* * FromPolar Filter. Converts image data from polar coordinates back to rectangular. @@ -17549,61 +16102,42 @@ * 0 is no rotation, 360 degrees is a full rotation */ var FromPolar = function (src, dst, opt) { - var srcPixels = src.data, - dstPixels = dst.data, - xSize = src.width, - ySize = src.height, - xMid = opt.polarCenterX || xSize / 2, - yMid = opt.polarCenterY || ySize / 2, - i, - x, - y, - dx, - dy, - r = 0, - g = 0, - b = 0, - a = 0; - // Find the largest radius - var rad, - rMax = Math.sqrt(xMid * xMid + yMid * yMid); - x = xSize - xMid; - y = ySize - yMid; - rad = Math.sqrt(x * x + y * y); - rMax = rad > rMax ? rad : rMax; - // We'll be uisng x as the radius, and y as the angle (theta=t) - var rSize = ySize, - tSize = xSize, - radius, - theta, - phaseShift = opt.polarRotation || 0; - // We need to convert to degrees and we need to make sure - // it's between (0-360) - // var conversion = tSize/360*180/Math.PI; - //var conversion = tSize/360*180/Math.PI; - var x1, y1; - for (x = 0; x < xSize; x += 1) { - for (y = 0; y < ySize; y += 1) { - dx = x - xMid; - dy = y - yMid; - radius = (Math.sqrt(dx * dx + dy * dy) * rSize) / rMax; - theta = ((Math.atan2(dy, dx) * 180) / Math.PI + 360 + phaseShift) % 360; - theta = (theta * tSize) / 360; - x1 = Math.floor(theta); - y1 = Math.floor(radius); - i = (y1 * xSize + x1) * 4; - r = srcPixels[i + 0]; - g = srcPixels[i + 1]; - b = srcPixels[i + 2]; - a = srcPixels[i + 3]; - // Store it - i = (y * xSize + x) * 4; - dstPixels[i + 0] = r; - dstPixels[i + 1] = g; - dstPixels[i + 2] = b; - dstPixels[i + 3] = a; + var srcPixels = src.data, dstPixels = dst.data, xSize = src.width, ySize = src.height, xMid = opt.polarCenterX || xSize / 2, yMid = opt.polarCenterY || ySize / 2, i, x, y, dx, dy, r = 0, g = 0, b = 0, a = 0; + // Find the largest radius + var rad, rMax = Math.sqrt(xMid * xMid + yMid * yMid); + x = xSize - xMid; + y = ySize - yMid; + rad = Math.sqrt(x * x + y * y); + rMax = rad > rMax ? rad : rMax; + // We'll be uisng x as the radius, and y as the angle (theta=t) + var rSize = ySize, tSize = xSize, radius, theta, phaseShift = opt.polarRotation || 0; + // We need to convert to degrees and we need to make sure + // it's between (0-360) + // var conversion = tSize/360*180/Math.PI; + //var conversion = tSize/360*180/Math.PI; + var x1, y1; + for (x = 0; x < xSize; x += 1) { + for (y = 0; y < ySize; y += 1) { + dx = x - xMid; + dy = y - yMid; + radius = (Math.sqrt(dx * dx + dy * dy) * rSize) / rMax; + theta = ((Math.atan2(dy, dx) * 180) / Math.PI + 360 + phaseShift) % 360; + theta = (theta * tSize) / 360; + x1 = Math.floor(theta); + y1 = Math.floor(radius); + i = (y1 * xSize + x1) * 4; + r = srcPixels[i + 0]; + g = srcPixels[i + 1]; + b = srcPixels[i + 2]; + a = srcPixels[i + 3]; + // Store it + i = (y * xSize + x) * 4; + dstPixels[i + 0] = r; + dstPixels[i + 1] = g; + dstPixels[i + 2] = b; + dstPixels[i + 3] = a; + } } - } }; //Konva.Filters.ToPolar = Util._FilterWrapDoubleBuffer(ToPolar); //Konva.Filters.FromPolar = Util._FilterWrapDoubleBuffer(FromPolar); @@ -17621,83 +16155,80 @@ * node.kaleidoscopeAngle(45); */ const Kaleidoscope = function (imageData) { - var xSize = imageData.width, - ySize = imageData.height; - var x, y, xoff, i, r, g, b, a, srcPos, dstPos; - var power = Math.round(this.kaleidoscopePower()); - var angle = Math.round(this.kaleidoscopeAngle()); - var offset = Math.floor((xSize * (angle % 360)) / 360); - if (power < 1) { - return; - } - // Work with our shared buffer canvas - var tempCanvas = Util.createCanvasElement(); - tempCanvas.width = xSize; - tempCanvas.height = ySize; - var scratchData = tempCanvas - .getContext('2d') - .getImageData(0, 0, xSize, ySize); - // Convert thhe original to polar coordinates - ToPolar(imageData, scratchData, { - polarCenterX: xSize / 2, - polarCenterY: ySize / 2, - }); - // Determine how big each section will be, if it's too small - // make it bigger - var minSectionSize = xSize / Math.pow(2, power); - while (minSectionSize <= 8) { - minSectionSize = minSectionSize * 2; - power -= 1; - } - minSectionSize = Math.ceil(minSectionSize); - var sectionSize = minSectionSize; - // Copy the offset region to 0 - // Depending on the size of filter and location of the offset we may need - // to copy the section backwards to prevent it from rewriting itself - var xStart = 0, - xEnd = sectionSize, - xDelta = 1; - if (offset + minSectionSize > xSize) { - xStart = sectionSize; - xEnd = 0; - xDelta = -1; - } - for (y = 0; y < ySize; y += 1) { - for (x = xStart; x !== xEnd; x += xDelta) { - xoff = Math.round(x + offset) % xSize; - srcPos = (xSize * y + xoff) * 4; - r = scratchData.data[srcPos + 0]; - g = scratchData.data[srcPos + 1]; - b = scratchData.data[srcPos + 2]; - a = scratchData.data[srcPos + 3]; - dstPos = (xSize * y + x) * 4; - scratchData.data[dstPos + 0] = r; - scratchData.data[dstPos + 1] = g; - scratchData.data[dstPos + 2] = b; - scratchData.data[dstPos + 3] = a; + var xSize = imageData.width, ySize = imageData.height; + var x, y, xoff, i, r, g, b, a, srcPos, dstPos; + var power = Math.round(this.kaleidoscopePower()); + var angle = Math.round(this.kaleidoscopeAngle()); + var offset = Math.floor((xSize * (angle % 360)) / 360); + if (power < 1) { + return; } - } - // Perform the actual effect - for (y = 0; y < ySize; y += 1) { - sectionSize = Math.floor(minSectionSize); - for (i = 0; i < power; i += 1) { - for (x = 0; x < sectionSize + 1; x += 1) { - srcPos = (xSize * y + x) * 4; - r = scratchData.data[srcPos + 0]; - g = scratchData.data[srcPos + 1]; - b = scratchData.data[srcPos + 2]; - a = scratchData.data[srcPos + 3]; - dstPos = (xSize * y + sectionSize * 2 - x - 1) * 4; - scratchData.data[dstPos + 0] = r; - scratchData.data[dstPos + 1] = g; - scratchData.data[dstPos + 2] = b; - scratchData.data[dstPos + 3] = a; - } - sectionSize *= 2; + // Work with our shared buffer canvas + var tempCanvas = Util.createCanvasElement(); + tempCanvas.width = xSize; + tempCanvas.height = ySize; + var scratchData = tempCanvas + .getContext('2d') + .getImageData(0, 0, xSize, ySize); + // Convert thhe original to polar coordinates + ToPolar(imageData, scratchData, { + polarCenterX: xSize / 2, + polarCenterY: ySize / 2, + }); + // Determine how big each section will be, if it's too small + // make it bigger + var minSectionSize = xSize / Math.pow(2, power); + while (minSectionSize <= 8) { + minSectionSize = minSectionSize * 2; + power -= 1; } - } - // Convert back from polar coordinates - FromPolar(scratchData, imageData, { polarRotation: 0 }); + minSectionSize = Math.ceil(minSectionSize); + var sectionSize = minSectionSize; + // Copy the offset region to 0 + // Depending on the size of filter and location of the offset we may need + // to copy the section backwards to prevent it from rewriting itself + var xStart = 0, xEnd = sectionSize, xDelta = 1; + if (offset + minSectionSize > xSize) { + xStart = sectionSize; + xEnd = 0; + xDelta = -1; + } + for (y = 0; y < ySize; y += 1) { + for (x = xStart; x !== xEnd; x += xDelta) { + xoff = Math.round(x + offset) % xSize; + srcPos = (xSize * y + xoff) * 4; + r = scratchData.data[srcPos + 0]; + g = scratchData.data[srcPos + 1]; + b = scratchData.data[srcPos + 2]; + a = scratchData.data[srcPos + 3]; + dstPos = (xSize * y + x) * 4; + scratchData.data[dstPos + 0] = r; + scratchData.data[dstPos + 1] = g; + scratchData.data[dstPos + 2] = b; + scratchData.data[dstPos + 3] = a; + } + } + // Perform the actual effect + for (y = 0; y < ySize; y += 1) { + sectionSize = Math.floor(minSectionSize); + for (i = 0; i < power; i += 1) { + for (x = 0; x < sectionSize + 1; x += 1) { + srcPos = (xSize * y + x) * 4; + r = scratchData.data[srcPos + 0]; + g = scratchData.data[srcPos + 1]; + b = scratchData.data[srcPos + 2]; + a = scratchData.data[srcPos + 3]; + dstPos = (xSize * y + sectionSize * 2 - x - 1) * 4; + scratchData.data[dstPos + 0] = r; + scratchData.data[dstPos + 1] = g; + scratchData.data[dstPos + 2] = b; + scratchData.data[dstPos + 3] = a; + } + sectionSize *= 2; + } + } + // Convert back from polar coordinates + FromPolar(scratchData, imageData, { polarRotation: 0 }); }; /** * get/set kaleidoscope power. Use with {@link Konva.Filters.Kaleidoscope} filter. @@ -17706,13 +16237,7 @@ * @param {Integer} power of kaleidoscope * @returns {Integer} */ - Factory.addGetterSetter( - Node, - 'kaleidoscopePower', - 2, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'kaleidoscopePower', 2, getNumberValidator(), Factory.afterSetFilter); /** * get/set kaleidoscope angle. Use with {@link Konva.Filters.Kaleidoscope} filter. * @name Konva.Node#kaleidoscopeAngle @@ -17720,160 +16245,135 @@ * @param {Integer} degrees * @returns {Integer} */ - Factory.addGetterSetter( - Node, - 'kaleidoscopeAngle', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); - + Factory.addGetterSetter(Node, 'kaleidoscopeAngle', 0, getNumberValidator(), Factory.afterSetFilter); + function pixelAt(idata, x, y) { - var idx = (y * idata.width + x) * 4; - var d = []; - d.push( - idata.data[idx++], - idata.data[idx++], - idata.data[idx++], - idata.data[idx++] - ); - return d; + var idx = (y * idata.width + x) * 4; + var d = []; + d.push(idata.data[idx++], idata.data[idx++], idata.data[idx++], idata.data[idx++]); + return d; } function rgbDistance(p1, p2) { - return Math.sqrt( - Math.pow(p1[0] - p2[0], 2) + - Math.pow(p1[1] - p2[1], 2) + - Math.pow(p1[2] - p2[2], 2) - ); + return Math.sqrt(Math.pow(p1[0] - p2[0], 2) + + Math.pow(p1[1] - p2[1], 2) + + Math.pow(p1[2] - p2[2], 2)); } function rgbMean(pTab) { - var m = [0, 0, 0]; - for (var i = 0; i < pTab.length; i++) { - m[0] += pTab[i][0]; - m[1] += pTab[i][1]; - m[2] += pTab[i][2]; - } - m[0] /= pTab.length; - m[1] /= pTab.length; - m[2] /= pTab.length; - return m; + var m = [0, 0, 0]; + for (var i = 0; i < pTab.length; i++) { + m[0] += pTab[i][0]; + m[1] += pTab[i][1]; + m[2] += pTab[i][2]; + } + m[0] /= pTab.length; + m[1] /= pTab.length; + m[2] /= pTab.length; + return m; } function backgroundMask(idata, threshold) { - var rgbv_no = pixelAt(idata, 0, 0); - var rgbv_ne = pixelAt(idata, idata.width - 1, 0); - var rgbv_so = pixelAt(idata, 0, idata.height - 1); - var rgbv_se = pixelAt(idata, idata.width - 1, idata.height - 1); - var thres = threshold || 10; - if ( - rgbDistance(rgbv_no, rgbv_ne) < thres && - rgbDistance(rgbv_ne, rgbv_se) < thres && - rgbDistance(rgbv_se, rgbv_so) < thres && - rgbDistance(rgbv_so, rgbv_no) < thres - ) { - // Mean color - var mean = rgbMean([rgbv_ne, rgbv_no, rgbv_se, rgbv_so]); - // Mask based on color distance - var mask = []; - for (var i = 0; i < idata.width * idata.height; i++) { - var d = rgbDistance(mean, [ - idata.data[i * 4], - idata.data[i * 4 + 1], - idata.data[i * 4 + 2], - ]); - mask[i] = d < thres ? 0 : 255; + var rgbv_no = pixelAt(idata, 0, 0); + var rgbv_ne = pixelAt(idata, idata.width - 1, 0); + var rgbv_so = pixelAt(idata, 0, idata.height - 1); + var rgbv_se = pixelAt(idata, idata.width - 1, idata.height - 1); + var thres = threshold || 10; + if (rgbDistance(rgbv_no, rgbv_ne) < thres && + rgbDistance(rgbv_ne, rgbv_se) < thres && + rgbDistance(rgbv_se, rgbv_so) < thres && + rgbDistance(rgbv_so, rgbv_no) < thres) { + // Mean color + var mean = rgbMean([rgbv_ne, rgbv_no, rgbv_se, rgbv_so]); + // Mask based on color distance + var mask = []; + for (var i = 0; i < idata.width * idata.height; i++) { + var d = rgbDistance(mean, [ + idata.data[i * 4], + idata.data[i * 4 + 1], + idata.data[i * 4 + 2], + ]); + mask[i] = d < thres ? 0 : 255; + } + return mask; } - return mask; - } } function applyMask(idata, mask) { - for (var i = 0; i < idata.width * idata.height; i++) { - idata.data[4 * i + 3] = mask[i]; - } + for (var i = 0; i < idata.width * idata.height; i++) { + idata.data[4 * i + 3] = mask[i]; + } } function erodeMask(mask, sw, sh) { - var weights = [1, 1, 1, 1, 0, 1, 1, 1, 1]; - var side = Math.round(Math.sqrt(weights.length)); - var halfSide = Math.floor(side / 2); - var maskResult = []; - for (var y = 0; y < sh; y++) { - for (var x = 0; x < sw; x++) { - var so = y * sw + x; - var a = 0; - for (var cy = 0; cy < side; cy++) { - for (var cx = 0; cx < side; cx++) { - var scy = y + cy - halfSide; - var scx = x + cx - halfSide; - if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { - var srcOff = scy * sw + scx; - var wt = weights[cy * side + cx]; - a += mask[srcOff] * wt; - } + var weights = [1, 1, 1, 1, 0, 1, 1, 1, 1]; + var side = Math.round(Math.sqrt(weights.length)); + var halfSide = Math.floor(side / 2); + var maskResult = []; + for (var y = 0; y < sh; y++) { + for (var x = 0; x < sw; x++) { + var so = y * sw + x; + var a = 0; + for (var cy = 0; cy < side; cy++) { + for (var cx = 0; cx < side; cx++) { + var scy = y + cy - halfSide; + var scx = x + cx - halfSide; + if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { + var srcOff = scy * sw + scx; + var wt = weights[cy * side + cx]; + a += mask[srcOff] * wt; + } + } + } + maskResult[so] = a === 255 * 8 ? 255 : 0; } - } - maskResult[so] = a === 255 * 8 ? 255 : 0; } - } - return maskResult; + return maskResult; } function dilateMask(mask, sw, sh) { - var weights = [1, 1, 1, 1, 1, 1, 1, 1, 1]; - var side = Math.round(Math.sqrt(weights.length)); - var halfSide = Math.floor(side / 2); - var maskResult = []; - for (var y = 0; y < sh; y++) { - for (var x = 0; x < sw; x++) { - var so = y * sw + x; - var a = 0; - for (var cy = 0; cy < side; cy++) { - for (var cx = 0; cx < side; cx++) { - var scy = y + cy - halfSide; - var scx = x + cx - halfSide; - if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { - var srcOff = scy * sw + scx; - var wt = weights[cy * side + cx]; - a += mask[srcOff] * wt; - } + var weights = [1, 1, 1, 1, 1, 1, 1, 1, 1]; + var side = Math.round(Math.sqrt(weights.length)); + var halfSide = Math.floor(side / 2); + var maskResult = []; + for (var y = 0; y < sh; y++) { + for (var x = 0; x < sw; x++) { + var so = y * sw + x; + var a = 0; + for (var cy = 0; cy < side; cy++) { + for (var cx = 0; cx < side; cx++) { + var scy = y + cy - halfSide; + var scx = x + cx - halfSide; + if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { + var srcOff = scy * sw + scx; + var wt = weights[cy * side + cx]; + a += mask[srcOff] * wt; + } + } + } + maskResult[so] = a >= 255 * 4 ? 255 : 0; } - } - maskResult[so] = a >= 255 * 4 ? 255 : 0; } - } - return maskResult; + return maskResult; } function smoothEdgeMask(mask, sw, sh) { - var weights = [ - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - ]; - var side = Math.round(Math.sqrt(weights.length)); - var halfSide = Math.floor(side / 2); - var maskResult = []; - for (var y = 0; y < sh; y++) { - for (var x = 0; x < sw; x++) { - var so = y * sw + x; - var a = 0; - for (var cy = 0; cy < side; cy++) { - for (var cx = 0; cx < side; cx++) { - var scy = y + cy - halfSide; - var scx = x + cx - halfSide; - if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { - var srcOff = scy * sw + scx; - var wt = weights[cy * side + cx]; - a += mask[srcOff] * wt; - } + var weights = [1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9]; + var side = Math.round(Math.sqrt(weights.length)); + var halfSide = Math.floor(side / 2); + var maskResult = []; + for (var y = 0; y < sh; y++) { + for (var x = 0; x < sw; x++) { + var so = y * sw + x; + var a = 0; + for (var cy = 0; cy < side; cy++) { + for (var cx = 0; cx < side; cx++) { + var scy = y + cy - halfSide; + var scx = x + cx - halfSide; + if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { + var srcOff = scy * sw + scx; + var wt = weights[cy * side + cx]; + a += mask[srcOff] * wt; + } + } + } + maskResult[so] = a; } - } - maskResult[so] = a; } - } - return maskResult; + return maskResult; } /** * Mask Filter @@ -17887,29 +16387,22 @@ * node.threshold(200); */ const Mask = function (imageData) { - // Detect pixels close to the background color - var threshold = this.threshold(), - mask = backgroundMask(imageData, threshold); - if (mask) { - // Erode - mask = erodeMask(mask, imageData.width, imageData.height); - // Dilate - mask = dilateMask(mask, imageData.width, imageData.height); - // Gradient - mask = smoothEdgeMask(mask, imageData.width, imageData.height); - // Apply mask - applyMask(imageData, mask); - } - return imageData; + // Detect pixels close to the background color + var threshold = this.threshold(), mask = backgroundMask(imageData, threshold); + if (mask) { + // Erode + mask = erodeMask(mask, imageData.width, imageData.height); + // Dilate + mask = dilateMask(mask, imageData.width, imageData.height); + // Gradient + mask = smoothEdgeMask(mask, imageData.width, imageData.height); + // Apply mask + applyMask(imageData, mask); + } + return imageData; }; - Factory.addGetterSetter( - Node, - 'threshold', - 0, - getNumberValidator(), - Factory.afterSetFilter - ); - + Factory.addGetterSetter(Node, 'threshold', 0, getNumberValidator(), Factory.afterSetFilter); + /** * Noise Filter. Randomly adds or substracts to the color channels * @function @@ -17923,32 +16416,22 @@ * node.noise(0.8); */ const Noise = function (imageData) { - var amount = this.noise() * 255, - data = imageData.data, - nPixels = data.length, - half = amount / 2, - i; - for (i = 0; i < nPixels; i += 4) { - data[i + 0] += half - 2 * half * Math.random(); - data[i + 1] += half - 2 * half * Math.random(); - data[i + 2] += half - 2 * half * Math.random(); - } + var amount = this.noise() * 255, data = imageData.data, nPixels = data.length, half = amount / 2, i; + for (i = 0; i < nPixels; i += 4) { + data[i + 0] += half - 2 * half * Math.random(); + data[i + 1] += half - 2 * half * Math.random(); + data[i + 2] += half - 2 * half * Math.random(); + } }; - Factory.addGetterSetter( - Node, - 'noise', - 0.2, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'noise', 0.2, getNumberValidator(), Factory.afterSetFilter); /** * get/set noise amount. Must be a value between 0 and 1. Use with {@link Konva.Filters.Noise} filter. * @name Konva.Node#noise * @method * @param {Number} noise * @returns {Number} - */ - + */ + /*eslint-disable max-depth */ /** * Pixelate Filter. Averages groups of pixels and redraws @@ -17964,100 +16447,76 @@ * node.pixelSize(10); */ const Pixelate = function (imageData) { - var pixelSize = Math.ceil(this.pixelSize()), - width = imageData.width, - height = imageData.height, - x, - y, - i, + var pixelSize = Math.ceil(this.pixelSize()), width = imageData.width, height = imageData.height, x, y, i, //pixelsPerBin = pixelSize * pixelSize, - red, - green, - blue, - alpha, - nBinsX = Math.ceil(width / pixelSize), - nBinsY = Math.ceil(height / pixelSize), - xBinStart, - xBinEnd, - yBinStart, - yBinEnd, - xBin, - yBin, - pixelsInBin, - data = imageData.data; - if (pixelSize <= 0) { - Util.error('pixelSize value can not be <= 0'); - return; - } - for (xBin = 0; xBin < nBinsX; xBin += 1) { - for (yBin = 0; yBin < nBinsY; yBin += 1) { - // Initialize the color accumlators to 0 - red = 0; - green = 0; - blue = 0; - alpha = 0; - // Determine which pixels are included in this bin - xBinStart = xBin * pixelSize; - xBinEnd = xBinStart + pixelSize; - yBinStart = yBin * pixelSize; - yBinEnd = yBinStart + pixelSize; - // Add all of the pixels to this bin! - pixelsInBin = 0; - for (x = xBinStart; x < xBinEnd; x += 1) { - if (x >= width) { - continue; - } - for (y = yBinStart; y < yBinEnd; y += 1) { - if (y >= height) { - continue; - } - i = (width * y + x) * 4; - red += data[i + 0]; - green += data[i + 1]; - blue += data[i + 2]; - alpha += data[i + 3]; - pixelsInBin += 1; - } - } - // Make sure the channels are between 0-255 - red = red / pixelsInBin; - green = green / pixelsInBin; - blue = blue / pixelsInBin; - alpha = alpha / pixelsInBin; - // Draw this bin - for (x = xBinStart; x < xBinEnd; x += 1) { - if (x >= width) { - continue; - } - for (y = yBinStart; y < yBinEnd; y += 1) { - if (y >= height) { - continue; - } - i = (width * y + x) * 4; - data[i + 0] = red; - data[i + 1] = green; - data[i + 2] = blue; - data[i + 3] = alpha; - } - } + red, green, blue, alpha, nBinsX = Math.ceil(width / pixelSize), nBinsY = Math.ceil(height / pixelSize), xBinStart, xBinEnd, yBinStart, yBinEnd, xBin, yBin, pixelsInBin, data = imageData.data; + if (pixelSize <= 0) { + Util.error('pixelSize value can not be <= 0'); + return; + } + for (xBin = 0; xBin < nBinsX; xBin += 1) { + for (yBin = 0; yBin < nBinsY; yBin += 1) { + // Initialize the color accumlators to 0 + red = 0; + green = 0; + blue = 0; + alpha = 0; + // Determine which pixels are included in this bin + xBinStart = xBin * pixelSize; + xBinEnd = xBinStart + pixelSize; + yBinStart = yBin * pixelSize; + yBinEnd = yBinStart + pixelSize; + // Add all of the pixels to this bin! + pixelsInBin = 0; + for (x = xBinStart; x < xBinEnd; x += 1) { + if (x >= width) { + continue; + } + for (y = yBinStart; y < yBinEnd; y += 1) { + if (y >= height) { + continue; + } + i = (width * y + x) * 4; + red += data[i + 0]; + green += data[i + 1]; + blue += data[i + 2]; + alpha += data[i + 3]; + pixelsInBin += 1; + } + } + // Make sure the channels are between 0-255 + red = red / pixelsInBin; + green = green / pixelsInBin; + blue = blue / pixelsInBin; + alpha = alpha / pixelsInBin; + // Draw this bin + for (x = xBinStart; x < xBinEnd; x += 1) { + if (x >= width) { + continue; + } + for (y = yBinStart; y < yBinEnd; y += 1) { + if (y >= height) { + continue; + } + i = (width * y + x) * 4; + data[i + 0] = red; + data[i + 1] = green; + data[i + 2] = blue; + data[i + 3] = alpha; + } + } + } } - } }; - Factory.addGetterSetter( - Node, - 'pixelSize', - 8, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'pixelSize', 8, getNumberValidator(), Factory.afterSetFilter); /** * get/set pixel size. Use with {@link Konva.Filters.Pixelate} filter. * @name Konva.Node#pixelSize * @method * @param {Integer} pixelSize * @returns {Integer} - */ - + */ + /** * Posterize Filter. Adjusts the channels so that there are no more * than n different values for that channel. This is also applied @@ -18073,31 +16532,21 @@ * node.levels(0.8); // between 0 and 1 */ const Posterize = function (imageData) { - // level must be between 1 and 255 - var levels = Math.round(this.levels() * 254) + 1, - data = imageData.data, - len = data.length, - scale = 255 / levels, - i; - for (i = 0; i < len; i += 1) { - data[i] = Math.floor(data[i] / scale) * scale; - } + // level must be between 1 and 255 + var levels = Math.round(this.levels() * 254) + 1, data = imageData.data, len = data.length, scale = 255 / levels, i; + for (i = 0; i < len; i += 1) { + data[i] = Math.floor(data[i] / scale) * scale; + } }; - Factory.addGetterSetter( - Node, - 'levels', - 0.5, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'levels', 0.5, getNumberValidator(), Factory.afterSetFilter); /** * get/set levels. Must be a number between 0 and 1. Use with {@link Konva.Filters.Posterize} filter. * @name Konva.Node#levels * @method * @param {Number} level between 0 and 1 * @returns {Number} - */ - + */ + /** * RGB Filter * @function @@ -18112,31 +16561,27 @@ * node.green(200); */ const RGB = function (imageData) { - var data = imageData.data, - nPixels = data.length, - red = this.red(), - green = this.green(), - blue = this.blue(), - i, - brightness; - for (i = 0; i < nPixels; i += 4) { - brightness = - (0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]) / 255; - data[i] = brightness * red; // r - data[i + 1] = brightness * green; // g - data[i + 2] = brightness * blue; // b - data[i + 3] = data[i + 3]; // alpha - } + var data = imageData.data, nPixels = data.length, red = this.red(), green = this.green(), blue = this.blue(), i, brightness; + for (i = 0; i < nPixels; i += 4) { + brightness = + (0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]) / 255; + data[i] = brightness * red; // r + data[i + 1] = brightness * green; // g + data[i + 2] = brightness * blue; // b + data[i + 3] = data[i + 3]; // alpha + } }; Factory.addGetterSetter(Node, 'red', 0, function (val) { - this._filterUpToDate = false; - if (val > 255) { - return 255; - } else if (val < 0) { - return 0; - } else { - return Math.round(val); - } + this._filterUpToDate = false; + if (val > 255) { + return 255; + } + else if (val < 0) { + return 0; + } + else { + return Math.round(val); + } }); /** * get/set filter red value. Use with {@link Konva.Filters.RGB} filter. @@ -18147,14 +16592,16 @@ * @returns {Integer} */ Factory.addGetterSetter(Node, 'green', 0, function (val) { - this._filterUpToDate = false; - if (val > 255) { - return 255; - } else if (val < 0) { - return 0; - } else { - return Math.round(val); - } + this._filterUpToDate = false; + if (val > 255) { + return 255; + } + else if (val < 0) { + return 0; + } + else { + return Math.round(val); + } }); /** * get/set filter green value. Use with {@link Konva.Filters.RGB} filter. @@ -18164,13 +16611,7 @@ * @param {Integer} green value between 0 and 255 * @returns {Integer} */ - Factory.addGetterSetter( - Node, - 'blue', - 0, - RGBComponent, - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'blue', 0, RGBComponent, Factory.afterSetFilter); /** * get/set filter blue value. Use with {@link Konva.Filters.RGB} filter. * @name blue @@ -18178,8 +16619,8 @@ * @memberof Konva.Node.prototype * @param {Integer} blue value between 0 and 255 * @returns {Integer} - */ - + */ + /** * RGBA Filter * @function @@ -18195,30 +16636,25 @@ * node.alpha(0.3); */ const RGBA = function (imageData) { - var data = imageData.data, - nPixels = data.length, - red = this.red(), - green = this.green(), - blue = this.blue(), - alpha = this.alpha(), - i, - ia; - for (i = 0; i < nPixels; i += 4) { - ia = 1 - alpha; - data[i] = red * alpha + data[i] * ia; // r - data[i + 1] = green * alpha + data[i + 1] * ia; // g - data[i + 2] = blue * alpha + data[i + 2] * ia; // b - } + var data = imageData.data, nPixels = data.length, red = this.red(), green = this.green(), blue = this.blue(), alpha = this.alpha(), i, ia; + for (i = 0; i < nPixels; i += 4) { + ia = 1 - alpha; + data[i] = red * alpha + data[i] * ia; // r + data[i + 1] = green * alpha + data[i + 1] * ia; // g + data[i + 2] = blue * alpha + data[i + 2] * ia; // b + } }; Factory.addGetterSetter(Node, 'red', 0, function (val) { - this._filterUpToDate = false; - if (val > 255) { - return 255; - } else if (val < 0) { - return 0; - } else { - return Math.round(val); - } + this._filterUpToDate = false; + if (val > 255) { + return 255; + } + else if (val < 0) { + return 0; + } + else { + return Math.round(val); + } }); /** * get/set filter red value. Use with {@link Konva.Filters.RGBA} filter. @@ -18229,14 +16665,16 @@ * @returns {Integer} */ Factory.addGetterSetter(Node, 'green', 0, function (val) { - this._filterUpToDate = false; - if (val > 255) { - return 255; - } else if (val < 0) { - return 0; - } else { - return Math.round(val); - } + this._filterUpToDate = false; + if (val > 255) { + return 255; + } + else if (val < 0) { + return 0; + } + else { + return Math.round(val); + } }); /** * get/set filter green value. Use with {@link Konva.Filters.RGBA} filter. @@ -18246,13 +16684,7 @@ * @param {Integer} green value between 0 and 255 * @returns {Integer} */ - Factory.addGetterSetter( - Node, - 'blue', - 0, - RGBComponent, - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'blue', 0, RGBComponent, Factory.afterSetFilter); /** * get/set filter blue value. Use with {@link Konva.Filters.RGBA} filter. * @name blue @@ -18262,14 +16694,16 @@ * @returns {Integer} */ Factory.addGetterSetter(Node, 'alpha', 1, function (val) { - this._filterUpToDate = false; - if (val > 1) { - return 1; - } else if (val < 0) { - return 0; - } else { - return val; - } + this._filterUpToDate = false; + if (val > 1) { + return 1; + } + else if (val < 0) { + return 0; + } + else { + return val; + } }); /** * get/set filter alpha value. Use with {@link Konva.Filters.RGBA} filter. @@ -18278,8 +16712,8 @@ * @memberof Konva.Node.prototype * @param {Float} alpha value between 0 and 1 * @returns {Float} - */ - + */ + // based on https://stackoverflow.com/questions/1061093/how-is-a-sepia-tone-created /** * @function @@ -18291,22 +16725,17 @@ * node.filters([Konva.Filters.Sepia]); */ const Sepia = function (imageData) { - var data = imageData.data, - nPixels = data.length, - i, - r, - g, - b; - for (i = 0; i < nPixels; i += 4) { - r = data[i + 0]; - g = data[i + 1]; - b = data[i + 2]; - data[i + 0] = Math.min(255, r * 0.393 + g * 0.769 + b * 0.189); - data[i + 1] = Math.min(255, r * 0.349 + g * 0.686 + b * 0.168); - data[i + 2] = Math.min(255, r * 0.272 + g * 0.534 + b * 0.131); - } - }; - + var data = imageData.data, nPixels = data.length, i, r, g, b; + for (i = 0; i < nPixels; i += 4) { + r = data[i + 0]; + g = data[i + 1]; + b = data[i + 2]; + data[i + 0] = Math.min(255, r * 0.393 + g * 0.769 + b * 0.189); + data[i + 1] = Math.min(255, r * 0.349 + g * 0.686 + b * 0.168); + data[i + 2] = Math.min(255, r * 0.272 + g * 0.534 + b * 0.131); + } + }; + /** * Solarize Filter * Pixastic Lib - Solarize filter - v0.1.0 @@ -18321,35 +16750,31 @@ * node.filters([Konva.Filters.Solarize]); */ const Solarize = function (imageData) { - var data = imageData.data, - w = imageData.width, - h = imageData.height, - w4 = w * 4, - y = h; - do { - var offsetY = (y - 1) * w4; - var x = w; + var data = imageData.data, w = imageData.width, h = imageData.height, w4 = w * 4, y = h; do { - var offset = offsetY + (x - 1) * 4; - var r = data[offset]; - var g = data[offset + 1]; - var b = data[offset + 2]; - if (r > 127) { - r = 255 - r; - } - if (g > 127) { - g = 255 - g; - } - if (b > 127) { - b = 255 - b; - } - data[offset] = r; - data[offset + 1] = g; - data[offset + 2] = b; - } while (--x); - } while (--y); - }; - + var offsetY = (y - 1) * w4; + var x = w; + do { + var offset = offsetY + (x - 1) * 4; + var r = data[offset]; + var g = data[offset + 1]; + var b = data[offset + 2]; + if (r > 127) { + r = 255 - r; + } + if (g > 127) { + g = 255 - g; + } + if (b > 127) { + b = 255 - b; + } + data[offset] = r; + data[offset + 1] = g; + data[offset + 2] = b; + } while (--x); + } while (--y); + }; + /** * Threshold Filter. Pushes any value above the mid point to * the max and any value below the mid point to the min. @@ -18365,21 +16790,12 @@ * node.threshold(0.1); */ const Threshold = function (imageData) { - var level = this.threshold() * 255, - data = imageData.data, - len = data.length, - i; - for (i = 0; i < len; i += 1) { - data[i] = data[i] < level ? 0 : 255; - } + var level = this.threshold() * 255, data = imageData.data, len = data.length, i; + for (i = 0; i < len; i += 1) { + data[i] = data[i] < level ? 0 : 255; + } }; - Factory.addGetterSetter( - Node, - 'threshold', - 0.5, - getNumberValidator(), - Factory.afterSetFilter - ); + Factory.addGetterSetter(Node, 'threshold', 0.5, getNumberValidator(), Factory.afterSetFilter); /** * get/set threshold. Must be a value between 0 and 1. Use with {@link Konva.Filters.Threshold} or {@link Konva.Filters.Mask} filter. * @name threshold @@ -18387,54 +16803,55 @@ * @memberof Konva.Node.prototype * @param {Number} threshold * @returns {Number} - */ - + */ + // we need to import core of the Konva and then extend it with all additional objects const Konva = Konva$1.Util._assign(Konva$1, { - Arc, - Arrow, - Circle, - Ellipse, - Image, - Label, - Tag, - Line, - Path, - Rect, - RegularPolygon, - Ring, - Sprite, - Star, - Text, - TextPath, - Transformer, - Wedge, - /** - * @namespace Filters - * @memberof Konva - */ - Filters: { - Blur, - Brighten, - Contrast, - Emboss, - Enhance, - Grayscale, - HSL, - HSV, - Invert, - Kaleidoscope, - Mask, - Noise, - Pixelate, - Posterize, - RGB, - RGBA, - Sepia, - Solarize, - Threshold, - }, - }); - - return Konva; -}); + Arc, + Arrow, + Circle, + Ellipse, + Image, + Label, + Tag, + Line, + Path, + Rect, + RegularPolygon, + Ring, + Sprite, + Star, + Text, + TextPath, + Transformer, + Wedge, + /** + * @namespace Filters + * @memberof Konva + */ + Filters: { + Blur, + Brighten, + Contrast, + Emboss, + Enhance, + Grayscale, + HSL, + HSV, + Invert, + Kaleidoscope, + Mask, + Noise, + Pixelate, + Posterize, + RGB, + RGBA, + Sepia, + Solarize, + Threshold, + }, + }); + + return Konva; + +}))); diff --git a/konva.min.js b/konva.min.js index 073a3b9c..368a104b 100644 --- a/konva.min.js +++ b/konva.min.js @@ -1,9262 +1,12 @@ -!(function (t, e) { - 'object' == typeof exports && 'undefined' != typeof module - ? (module.exports = e()) - : 'function' == typeof define && define.amd - ? define(e) - : ((t = - 'undefined' != typeof globalThis ? globalThis : t || self).Konva = e()); -})(this, function () { - 'use strict'; - /* +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Konva=e()}(this,(function(){"use strict"; +/* * Konva JavaScript Framework v7.2.5 * http://konvajs.org/ * Licensed under the MIT - * Date: Thu Apr 29 2021 + * Date: Tue May 04 2021 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * * @license - */ var t = Math.PI / 180; - const e = function (t) { - var e = t.indexOf('msie '); - if (e > 0) return parseInt(t.substring(e + 5, t.indexOf('.', e)), 10); - if (t.indexOf('trident/') > 0) { - var i = t.indexOf('rv:'); - return parseInt(t.substring(i + 3, t.indexOf('.', i)), 10); - } - var r = t.indexOf('edge/'); - return r > 0 && parseInt(t.substring(r + 5, t.indexOf('.', r)), 10); - }, - i = function (t) { - var i = t.toLowerCase(), - r = - /(chrome)[ /]([\w.]+)/.exec(i) || - /(webkit)[ /]([\w.]+)/.exec(i) || - /(opera)(?:.*version|)[ /]([\w.]+)/.exec(i) || - /(msie) ([\w.]+)/.exec(i) || - (i.indexOf('compatible') < 0 && - /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(i)) || - [], - a = !!t.match( - /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i - ), - n = !!t.match(/IEMobile/i); - return { - browser: r[1] || '', - version: r[2] || '0', - isIE: e(i), - mobile: a, - ieMobile: n, - }; - }, - r = - 'undefined' != typeof global - ? global - : 'undefined' != typeof window - ? window - : 'undefined' != typeof WorkerGlobalScope - ? self - : {}, - a = { - _global: r, - version: '7.2.5', - isBrowser: - 'undefined' != typeof window && - ('[object Window]' === {}.toString.call(window) || - '[object global]' === {}.toString.call(window)), - isUnminified: /param/.test(function (t) {}.toString()), - dblClickWindow: 400, - getAngle: (e) => (a.angleDeg ? e * t : e), - enableTrace: !1, - _pointerEventsEnabled: !1, - autoDrawEnabled: !1, - hitOnDragEnabled: !1, - captureTouchEventsEnabled: !1, - listenClickTap: !1, - inDblClickWindow: !1, - pixelRatio: - ('undefined' != typeof window && window.devicePixelRatio) || 1, - dragDistance: 3, - angleDeg: !0, - showWarnings: !0, - dragButtons: [0, 1], - isDragging: () => a.DD.isDragging, - isDragReady: () => !!a.DD.node, - UA: i((r.navigator && r.navigator.userAgent) || ''), - document: r.document, - _injectGlobal(t) { - r.Konva = t; - }, - _parseUA: i, - }, - n = {}, - s = (t) => { - (n[t.prototype.getClassName()] = t), (a[t.prototype.getClassName()] = t); - }; - a._injectGlobal(a); - class o { - constructor(t = [1, 0, 0, 1, 0, 0]) { - (this.dirty = !1), (this.m = (t && t.slice()) || [1, 0, 0, 1, 0, 0]); - } - reset() { - (this.m[0] = 1), - (this.m[1] = 0), - (this.m[2] = 0), - (this.m[3] = 1), - (this.m[4] = 0), - (this.m[5] = 0); - } - copy() { - return new o(this.m); - } - copyInto(t) { - (t.m[0] = this.m[0]), - (t.m[1] = this.m[1]), - (t.m[2] = this.m[2]), - (t.m[3] = this.m[3]), - (t.m[4] = this.m[4]), - (t.m[5] = this.m[5]); - } - point(t) { - var e = this.m; - return { - x: e[0] * t.x + e[2] * t.y + e[4], - y: e[1] * t.x + e[3] * t.y + e[5], - }; - } - translate(t, e) { - return ( - (this.m[4] += this.m[0] * t + this.m[2] * e), - (this.m[5] += this.m[1] * t + this.m[3] * e), - this - ); - } - scale(t, e) { - return ( - (this.m[0] *= t), - (this.m[1] *= t), - (this.m[2] *= e), - (this.m[3] *= e), - this - ); - } - rotate(t) { - var e = Math.cos(t), - i = Math.sin(t), - r = this.m[0] * e + this.m[2] * i, - a = this.m[1] * e + this.m[3] * i, - n = this.m[0] * -i + this.m[2] * e, - s = this.m[1] * -i + this.m[3] * e; - return ( - (this.m[0] = r), (this.m[1] = a), (this.m[2] = n), (this.m[3] = s), this - ); - } - getTranslation() { - return { x: this.m[4], y: this.m[5] }; - } - skew(t, e) { - var i = this.m[0] + this.m[2] * e, - r = this.m[1] + this.m[3] * e, - a = this.m[2] + this.m[0] * t, - n = this.m[3] + this.m[1] * t; - return ( - (this.m[0] = i), (this.m[1] = r), (this.m[2] = a), (this.m[3] = n), this - ); - } - multiply(t) { - var e = this.m[0] * t.m[0] + this.m[2] * t.m[1], - i = this.m[1] * t.m[0] + this.m[3] * t.m[1], - r = this.m[0] * t.m[2] + this.m[2] * t.m[3], - a = this.m[1] * t.m[2] + this.m[3] * t.m[3], - n = this.m[0] * t.m[4] + this.m[2] * t.m[5] + this.m[4], - s = this.m[1] * t.m[4] + this.m[3] * t.m[5] + this.m[5]; - return ( - (this.m[0] = e), - (this.m[1] = i), - (this.m[2] = r), - (this.m[3] = a), - (this.m[4] = n), - (this.m[5] = s), - this - ); - } - invert() { - var t = 1 / (this.m[0] * this.m[3] - this.m[1] * this.m[2]), - e = this.m[3] * t, - i = -this.m[1] * t, - r = -this.m[2] * t, - a = this.m[0] * t, - n = t * (this.m[2] * this.m[5] - this.m[3] * this.m[4]), - s = t * (this.m[1] * this.m[4] - this.m[0] * this.m[5]); - return ( - (this.m[0] = e), - (this.m[1] = i), - (this.m[2] = r), - (this.m[3] = a), - (this.m[4] = n), - (this.m[5] = s), - this - ); - } - getMatrix() { - return this.m; - } - setAbsolutePosition(t, e) { - var i = this.m[0], - r = this.m[1], - a = this.m[2], - n = this.m[3], - s = this.m[4], - o = (i * (e - this.m[5]) - r * (t - s)) / (i * n - r * a), - h = (t - s - a * o) / i; - return this.translate(h, o); - } - decompose() { - var t = this.m[0], - e = this.m[1], - i = this.m[2], - r = this.m[3], - a = t * r - e * i; - let n = { - x: this.m[4], - y: this.m[5], - rotation: 0, - scaleX: 0, - scaleY: 0, - skewX: 0, - skewY: 0, - }; - if (0 != t || 0 != e) { - var s = Math.sqrt(t * t + e * e); - (n.rotation = e > 0 ? Math.acos(t / s) : -Math.acos(t / s)), - (n.scaleX = s), - (n.scaleY = a / s), - (n.skewX = (t * i + e * r) / a), - (n.skewY = 0); - } else if (0 != i || 0 != r) { - var o = Math.sqrt(i * i + r * r); - (n.rotation = - Math.PI / 2 - (r > 0 ? Math.acos(-i / o) : -Math.acos(i / o))), - (n.scaleX = a / o), - (n.scaleY = o), - (n.skewX = 0), - (n.skewY = (t * i + e * r) / a); - } - return (n.rotation = u._getRotation(n.rotation)), n; - } - } - var h = Math.PI / 180, - l = 180 / Math.PI, - d = { - aliceblue: [240, 248, 255], - antiquewhite: [250, 235, 215], - aqua: [0, 255, 255], - aquamarine: [127, 255, 212], - azure: [240, 255, 255], - beige: [245, 245, 220], - bisque: [255, 228, 196], - black: [0, 0, 0], - blanchedalmond: [255, 235, 205], - blue: [0, 0, 255], - blueviolet: [138, 43, 226], - brown: [165, 42, 42], - burlywood: [222, 184, 135], - cadetblue: [95, 158, 160], - chartreuse: [127, 255, 0], - chocolate: [210, 105, 30], - coral: [255, 127, 80], - cornflowerblue: [100, 149, 237], - cornsilk: [255, 248, 220], - crimson: [220, 20, 60], - cyan: [0, 255, 255], - darkblue: [0, 0, 139], - darkcyan: [0, 139, 139], - darkgoldenrod: [184, 132, 11], - darkgray: [169, 169, 169], - darkgreen: [0, 100, 0], - darkgrey: [169, 169, 169], - darkkhaki: [189, 183, 107], - darkmagenta: [139, 0, 139], - darkolivegreen: [85, 107, 47], - darkorange: [255, 140, 0], - darkorchid: [153, 50, 204], - darkred: [139, 0, 0], - darksalmon: [233, 150, 122], - darkseagreen: [143, 188, 143], - darkslateblue: [72, 61, 139], - darkslategray: [47, 79, 79], - darkslategrey: [47, 79, 79], - darkturquoise: [0, 206, 209], - darkviolet: [148, 0, 211], - deeppink: [255, 20, 147], - deepskyblue: [0, 191, 255], - dimgray: [105, 105, 105], - dimgrey: [105, 105, 105], - dodgerblue: [30, 144, 255], - firebrick: [178, 34, 34], - floralwhite: [255, 255, 240], - forestgreen: [34, 139, 34], - fuchsia: [255, 0, 255], - gainsboro: [220, 220, 220], - ghostwhite: [248, 248, 255], - gold: [255, 215, 0], - goldenrod: [218, 165, 32], - gray: [128, 128, 128], - green: [0, 128, 0], - greenyellow: [173, 255, 47], - grey: [128, 128, 128], - honeydew: [240, 255, 240], - hotpink: [255, 105, 180], - indianred: [205, 92, 92], - indigo: [75, 0, 130], - ivory: [255, 255, 240], - khaki: [240, 230, 140], - lavender: [230, 230, 250], - lavenderblush: [255, 240, 245], - lawngreen: [124, 252, 0], - lemonchiffon: [255, 250, 205], - lightblue: [173, 216, 230], - lightcoral: [240, 128, 128], - lightcyan: [224, 255, 255], - lightgoldenrodyellow: [250, 250, 210], - lightgray: [211, 211, 211], - lightgreen: [144, 238, 144], - lightgrey: [211, 211, 211], - lightpink: [255, 182, 193], - lightsalmon: [255, 160, 122], - lightseagreen: [32, 178, 170], - lightskyblue: [135, 206, 250], - lightslategray: [119, 136, 153], - lightslategrey: [119, 136, 153], - lightsteelblue: [176, 196, 222], - lightyellow: [255, 255, 224], - lime: [0, 255, 0], - limegreen: [50, 205, 50], - linen: [250, 240, 230], - magenta: [255, 0, 255], - maroon: [128, 0, 0], - mediumaquamarine: [102, 205, 170], - mediumblue: [0, 0, 205], - mediumorchid: [186, 85, 211], - mediumpurple: [147, 112, 219], - mediumseagreen: [60, 179, 113], - mediumslateblue: [123, 104, 238], - mediumspringgreen: [0, 250, 154], - mediumturquoise: [72, 209, 204], - mediumvioletred: [199, 21, 133], - midnightblue: [25, 25, 112], - mintcream: [245, 255, 250], - mistyrose: [255, 228, 225], - moccasin: [255, 228, 181], - navajowhite: [255, 222, 173], - navy: [0, 0, 128], - oldlace: [253, 245, 230], - olive: [128, 128, 0], - olivedrab: [107, 142, 35], - orange: [255, 165, 0], - orangered: [255, 69, 0], - orchid: [218, 112, 214], - palegoldenrod: [238, 232, 170], - palegreen: [152, 251, 152], - paleturquoise: [175, 238, 238], - palevioletred: [219, 112, 147], - papayawhip: [255, 239, 213], - peachpuff: [255, 218, 185], - peru: [205, 133, 63], - pink: [255, 192, 203], - plum: [221, 160, 203], - powderblue: [176, 224, 230], - purple: [128, 0, 128], - rebeccapurple: [102, 51, 153], - red: [255, 0, 0], - rosybrown: [188, 143, 143], - royalblue: [65, 105, 225], - saddlebrown: [139, 69, 19], - salmon: [250, 128, 114], - sandybrown: [244, 164, 96], - seagreen: [46, 139, 87], - seashell: [255, 245, 238], - sienna: [160, 82, 45], - silver: [192, 192, 192], - skyblue: [135, 206, 235], - slateblue: [106, 90, 205], - slategray: [119, 128, 144], - slategrey: [119, 128, 144], - snow: [255, 255, 250], - springgreen: [0, 255, 127], - steelblue: [70, 130, 180], - tan: [210, 180, 140], - teal: [0, 128, 128], - thistle: [216, 191, 216], - transparent: [255, 255, 255, 0], - tomato: [255, 99, 71], - turquoise: [64, 224, 208], - violet: [238, 130, 238], - wheat: [245, 222, 179], - white: [255, 255, 255], - whitesmoke: [245, 245, 245], - yellow: [255, 255, 0], - yellowgreen: [154, 205, 5], - }, - c = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/, - g = []; - const u = { - _isElement: (t) => !(!t || 1 != t.nodeType), - _isFunction: (t) => !!(t && t.constructor && t.call && t.apply), - _isPlainObject: (t) => !!t && t.constructor === Object, - _isArray: (t) => '[object Array]' === Object.prototype.toString.call(t), - _isNumber: (t) => - '[object Number]' === Object.prototype.toString.call(t) && - !isNaN(t) && - isFinite(t), - _isString: (t) => '[object String]' === Object.prototype.toString.call(t), - _isBoolean: (t) => '[object Boolean]' === Object.prototype.toString.call(t), - isObject: (t) => t instanceof Object, - isValidSelector(t) { - if ('string' != typeof t) return !1; - var e = t[0]; - return '#' === e || '.' === e || e === e.toUpperCase(); - }, - _sign: (t) => (0 === t || t > 0 ? 1 : -1), - requestAnimFrame(t) { - g.push(t); - const e = - ('undefined' != typeof requestAnimationFrame && - requestAnimationFrame) || - function (t) { - setTimeout(t, 60); - }; - 1 === g.length && - e(function () { - const t = g; - (g = []), - t.forEach(function (t) { - t(); - }); - }); - }, - createCanvasElement() { - var t = document.createElement('canvas'); - try { - t.style = t.style || {}; - } catch (t) {} - return t; - }, - createImageElement: () => document.createElement('img'), - _isInDocument(t) { - for (; (t = t.parentNode); ) if (t == document) return !0; - return !1; - }, - _simplifyArray(t) { - var e, - i, - r = [], - a = t.length, - n = u; - for (e = 0; e < a; e++) - (i = t[e]), - n._isNumber(i) - ? (i = Math.round(1e3 * i) / 1e3) - : n._isString(i) || (i += ''), - r.push(i); - return r; - }, - _urlToImage(t, e) { - var i = u.createImageElement(); - (i.onload = function () { - e(i); - }), - (i.src = t); - }, - _rgbToHex: (t, e, i) => - ((1 << 24) + (t << 16) + (e << 8) + i).toString(16).slice(1), - _hexToRgb(t) { - t = t.replace('#', ''); - var e = parseInt(t, 16); - return { r: (e >> 16) & 255, g: (e >> 8) & 255, b: 255 & e }; - }, - getRandomColor() { - for ( - var t = ((16777215 * Math.random()) << 0).toString(16); - t.length < 6; - - ) - t = '0' + t; - return '#' + t; - }, - get: (t, e) => (void 0 === t ? e : t), - getRGB(t) { - var e; - return t in d - ? { r: (e = d[t])[0], g: e[1], b: e[2] } - : '#' === t[0] - ? this._hexToRgb(t.substring(1)) - : 'rgb(' === t.substr(0, 4) - ? ((e = c.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: (t) => ( - (t = t || 'black'), - u._namedColorToRBA(t) || - u._hex3ColorToRGBA(t) || - u._hex6ColorToRGBA(t) || - u._rgbColorToRGBA(t) || - u._rgbaColorToRGBA(t) || - u._hslColorToRGBA(t) - ), - _namedColorToRBA(t) { - var e = d[t.toLowerCase()]; - return e ? { r: e[0], g: e[1], b: e[2], a: 1 } : null; - }, - _rgbColorToRGBA(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(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(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(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(t) { - if (/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)) { - const [e, ...i] = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t), - r = Number(i[0]) / 360, - a = Number(i[1]) / 100, - n = Number(i[2]) / 100; - let s, o, h; - if (0 === a) - return ( - (h = 255 * n), - { r: Math.round(h), g: Math.round(h), b: Math.round(h), a: 1 } - ); - s = n < 0.5 ? n * (1 + a) : n + a - n * a; - const l = 2 * n - s, - d = [0, 0, 0]; - for (let t = 0; t < 3; t++) - (o = r + (1 / 3) * -(t - 1)), - o < 0 && o++, - o > 1 && o--, - (h = - 6 * o < 1 - ? l + 6 * (s - l) * o - : 2 * o < 1 - ? s - : 3 * o < 2 - ? l + (s - l) * (2 / 3 - o) * 6 - : l), - (d[t] = 255 * h); - return { - r: Math.round(d[0]), - g: Math.round(d[1]), - b: Math.round(d[2]), - a: 1, - }; - } - }, - haveIntersection: (t, e) => - !( - e.x > t.x + t.width || - e.x + e.width < t.x || - e.y > t.y + t.height || - e.y + e.height < t.y - ), - cloneObject(t) { - var e = {}; - for (var i in t) - this._isPlainObject(t[i]) - ? (e[i] = this.cloneObject(t[i])) - : this._isArray(t[i]) - ? (e[i] = this.cloneArray(t[i])) - : (e[i] = t[i]); - return e; - }, - cloneArray: (t) => t.slice(0), - _degToRad: (t) => t * h, - _radToDeg: (t) => t * l, - _getRotation: (t) => (a.angleDeg ? u._radToDeg(t) : t), - _capitalize: (t) => t.charAt(0).toUpperCase() + t.slice(1), - throw(t) { - throw new Error('Konva error: ' + t); - }, - error(t) { - console.error('Konva error: ' + t); - }, - warn(t) { - a.showWarnings && console.warn('Konva warning: ' + t); - }, - extend(t, e) { - function i() { - this.constructor = t; - } - i.prototype = e.prototype; - var r = t.prototype; - for (var a in ((t.prototype = new i()), r)) - r.hasOwnProperty(a) && (t.prototype[a] = r[a]); - (t.__super__ = e.prototype), (t.super = e); - }, - _getControlPoints(t, e, i, r, a, n, s) { - var o = Math.sqrt(Math.pow(i - t, 2) + Math.pow(r - e, 2)), - h = Math.sqrt(Math.pow(a - i, 2) + Math.pow(n - r, 2)), - l = (s * o) / (o + h), - d = (s * h) / (o + h); - return [ - i - l * (a - t), - r - l * (n - e), - i + d * (a - t), - r + d * (n - e), - ]; - }, - _expandPoints(t, e) { - var i, - r, - a = t.length, - n = []; - for (i = 2; i < a - 2; i += 2) - (r = u._getControlPoints( - t[i - 2], - t[i - 1], - t[i], - t[i + 1], - t[i + 2], - t[i + 3], - e - )), - isNaN(r[0]) || - (n.push(r[0]), - n.push(r[1]), - n.push(t[i]), - n.push(t[i + 1]), - n.push(r[2]), - n.push(r[3])); - return n; - }, - each(t, e) { - for (var i in t) e(i, t[i]); - }, - _inRange: (t, e, i) => e <= t && t < i, - _getProjectionToSegment(t, e, i, r, a, n) { - var s, - o, - h, - l = (t - i) * (t - i) + (e - r) * (e - r); - if (0 == l) (s = t), (o = e), (h = (a - i) * (a - i) + (n - r) * (n - r)); - else { - var d = ((a - t) * (i - t) + (n - e) * (r - e)) / l; - d < 0 - ? ((s = t), (o = e), (h = (t - a) * (t - a) + (e - n) * (e - n))) - : d > 1 - ? ((s = i), (o = r), (h = (i - a) * (i - a) + (r - n) * (r - n))) - : (h = - ((s = t + d * (i - t)) - a) * (s - a) + - ((o = e + d * (r - e)) - n) * (o - n)); - } - return [s, o, h]; - }, - _getProjectionToLine(t, e, i) { - var r = u.cloneObject(t), - a = Number.MAX_VALUE; - return ( - e.forEach(function (n, s) { - if (i || s !== e.length - 1) { - var o = e[(s + 1) % e.length], - h = u._getProjectionToSegment(n.x, n.y, o.x, o.y, t.x, t.y), - l = h[0], - d = h[1], - c = h[2]; - c < a && ((r.x = l), (r.y = d), (a = c)); - } - }), - r - ); - }, - _prepareArrayForTween(t, e, i) { - var r, - a = [], - n = []; - if (t.length > e.length) { - var s = e; - (e = t), (t = s); - } - for (r = 0; r < t.length; r += 2) a.push({ x: t[r], y: t[r + 1] }); - for (r = 0; r < e.length; r += 2) n.push({ x: e[r], y: e[r + 1] }); - var o = []; - return ( - n.forEach(function (t) { - var e = u._getProjectionToLine(t, a, i); - o.push(e.x), o.push(e.y); - }), - o - ); - }, - _prepareToStringify(t) { - var e; - for (var i in ((t.visitedByCircularReferenceRemoval = !0), t)) - if (t.hasOwnProperty(i) && t[i] && 'object' == typeof t[i]) - if ( - ((e = Object.getOwnPropertyDescriptor(t, i)), - t[i].visitedByCircularReferenceRemoval || u._isElement(t[i])) - ) { - if (!e.configurable) return null; - delete t[i]; - } else if (null === u._prepareToStringify(t[i])) { - if (!e.configurable) return null; - delete t[i]; - } - return delete t.visitedByCircularReferenceRemoval, t; - }, - _assign(t, e) { - for (var i in e) t[i] = e[i]; - return t; - }, - _getFirstPointerId: (t) => - t.touches ? t.changedTouches[0].identifier : 999, - }; - function f(t) { - return u._isString(t) - ? '"' + t + '"' - : '[object Number]' === Object.prototype.toString.call(t) || - u._isBoolean(t) - ? t - : Object.prototype.toString.call(t); - } - function p(t) { - return t > 255 ? 255 : t < 0 ? 0 : Math.round(t); - } - function v() { - if (a.isUnminified) - return function (t, e) { - return ( - u._isNumber(t) || - u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a number.' - ), - t - ); - }; - } - function m(t) { - if (a.isUnminified) - return function (e, i) { - let r = u._isNumber(e), - a = u._isArray(e) && e.length == t; - return ( - r || - a || - u.warn( - f(e) + - ' is a not valid value for "' + - i + - '" attribute. The value should be a number or Array(' + - t + - ')' - ), - e - ); - }; - } - function _() { - if (a.isUnminified) - return function (t, e) { - return ( - u._isNumber(t) || - 'auto' === t || - u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a number or "auto".' - ), - t - ); - }; - } - function y() { - if (a.isUnminified) - return function (t, e) { - return ( - u._isString(t) || - u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a string.' - ), - t - ); - }; - } - function x() { - if (a.isUnminified) - return function (t, e) { - const i = u._isString(t), - r = '[object CanvasGradient]' === Object.prototype.toString.call(t); - return ( - i || - r || - u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a string or a native gradient.' - ), - t - ); - }; - } - function b() { - if (a.isUnminified) - return function (t, e) { - return ( - !0 === t || - !1 === t || - u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a boolean.' - ), - t - ); - }; - } - const S = { - addGetterSetter(t, e, i, r, a) { - S.addGetter(t, e, i), - S.addSetter(t, e, r, a), - S.addOverloadedGetterSetter(t, e); - }, - addGetter(t, e, i) { - var r = 'get' + u._capitalize(e); - t.prototype[r] = - t.prototype[r] || - function () { - var t = this.attrs[e]; - return void 0 === t ? i : t; - }; - }, - addSetter(t, e, i, r) { - var a = 'set' + u._capitalize(e); - t.prototype[a] || S.overWriteSetter(t, e, i, r); - }, - overWriteSetter(t, e, i, r) { - var a = 'set' + u._capitalize(e); - t.prototype[a] = function (t) { - return ( - i && null != t && (t = i.call(this, t, e)), - this._setAttr(e, t), - r && r.call(this), - this - ); - }; - }, - addComponentsGetterSetter(t, e, i, r, n) { - var s, - o, - h = i.length, - l = u._capitalize, - d = 'get' + l(e), - c = 'set' + l(e); - t.prototype[d] = function () { - var t = {}; - for (s = 0; s < h; s++) t[(o = i[s])] = this.getAttr(e + l(o)); - return t; - }; - var g = (function (t) { - if (a.isUnminified) - return function (e, i) { - return ( - u.isObject(e) || - u.warn( - f(e) + - ' is a not valid value for "' + - i + - '" attribute. The value should be an object with properties ' + - t - ), - e - ); - }; - })(i); - (t.prototype[c] = function (t) { - var i, - a = this.attrs[e]; - for (i in (r && (t = r.call(this, t)), g && g.call(this, t, e), t)) - t.hasOwnProperty(i) && this._setAttr(e + l(i), t[i]); - return this._fireChangeEvent(e, a, t), n && n.call(this), this; - }), - S.addOverloadedGetterSetter(t, e); - }, - addOverloadedGetterSetter(t, e) { - var i = u._capitalize(e), - r = 'set' + i, - a = 'get' + i; - t.prototype[e] = function () { - return arguments.length ? (this[r](arguments[0]), this) : this[a](); - }; - }, - addDeprecatedGetterSetter(t, e, i, r) { - u.error('Adding deprecated ' + e); - var a = 'get' + u._capitalize(e), - n = - e + - ' property is deprecated and will be removed soon. Look at Konva change log for more information.'; - (t.prototype[a] = function () { - u.error(n); - var t = this.attrs[e]; - return void 0 === t ? i : t; - }), - S.addSetter(t, e, r, function () { - u.error(n); - }), - S.addOverloadedGetterSetter(t, e); - }, - backCompat(t, e) { - u.each(e, function (e, i) { - var r = t.prototype[i], - a = 'get' + u._capitalize(e), - n = 'set' + u._capitalize(e); - function s() { - r.apply(this, arguments), - u.error( - '"' + - e + - '" method is deprecated and will be removed soon. Use ""' + - i + - '" instead.' - ); - } - (t.prototype[e] = s), (t.prototype[a] = s), (t.prototype[n] = s); - }); - }, - afterSetFilter() { - this._filterUpToDate = !1; - }, - }; - var w = [ - 'arc', - 'arcTo', - 'beginPath', - 'bezierCurveTo', - 'clearRect', - 'clip', - 'closePath', - 'createLinearGradient', - 'createPattern', - 'createRadialGradient', - 'drawImage', - 'ellipse', - 'fill', - 'fillText', - 'getImageData', - 'createImageData', - 'lineTo', - 'moveTo', - 'putImageData', - 'quadraticCurveTo', - 'rect', - 'restore', - 'rotate', - 'save', - 'scale', - 'setLineDash', - 'setTransform', - 'stroke', - 'strokeText', - 'transform', - 'translate', - ]; - class C { - constructor(t) { - (this.canvas = t), - (this._context = t._canvas.getContext('2d')), - a.enableTrace && ((this.traceArr = []), this._enableTrace()); - } - fillShape(t) { - t.fillEnabled() && this._fill(t); - } - _fill(t) {} - strokeShape(t) { - t.hasStroke() && this._stroke(t); - } - _stroke(t) {} - fillStrokeShape(t) { - t.attrs.fillAfterStrokeEnabled - ? (this.strokeShape(t), this.fillShape(t)) - : (this.fillShape(t), this.strokeShape(t)); - } - getTrace(t) { - var e, - i, - r, - a, - n = this.traceArr, - s = n.length, - o = ''; - for (e = 0; e < s; e++) - (r = (i = n[e]).method) - ? ((a = i.args), - (o += r), - t - ? (o += '()') - : u._isArray(a[0]) - ? (o += '([' + a.join(',') + '])') - : (o += '(' + a.join(',') + ')')) - : ((o += i.property), t || (o += '=' + i.val)), - (o += ';'); - return o; - } - clearTrace() { - this.traceArr = []; - } - _trace(t) { - var e = this.traceArr; - e.push(t), e.length >= 100 && e.shift(); - } - reset() { - var t = this.getCanvas().getPixelRatio(); - this.setTransform(1 * t, 0, 0, 1 * t, 0, 0); - } - getCanvas() { - return this.canvas; - } - clear(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 - ); - } - _applyLineCap(t) { - var e = t.getLineCap(); - e && this.setAttr('lineCap', e); - } - _applyOpacity(t) { - var e = t.getAbsoluteOpacity(); - 1 !== e && this.setAttr('globalAlpha', e); - } - _applyLineJoin(t) { - var e = t.attrs.lineJoin; - e && this.setAttr('lineJoin', e); - } - setAttr(t, e) { - this._context[t] = e; - } - arc(t, e, i, r, a, n) { - this._context.arc(t, e, i, r, a, n); - } - arcTo(t, e, i, r, a) { - this._context.arcTo(t, e, i, r, a); - } - beginPath() { - this._context.beginPath(); - } - bezierCurveTo(t, e, i, r, a, n) { - this._context.bezierCurveTo(t, e, i, r, a, n); - } - clearRect(t, e, i, r) { - this._context.clearRect(t, e, i, r); - } - clip() { - this._context.clip(); - } - closePath() { - this._context.closePath(); - } - createImageData(t, e) { - var i = arguments; - return 2 === i.length - ? this._context.createImageData(t, e) - : 1 === i.length - ? this._context.createImageData(t) - : void 0; - } - createLinearGradient(t, e, i, r) { - return this._context.createLinearGradient(t, e, i, r); - } - createPattern(t, e) { - return this._context.createPattern(t, e); - } - createRadialGradient(t, e, i, r, a, n) { - return this._context.createRadialGradient(t, e, i, r, a, n); - } - drawImage(t, e, i, r, a, n, s, o, h) { - var l = arguments, - d = this._context; - 3 === l.length - ? d.drawImage(t, e, i) - : 5 === l.length - ? d.drawImage(t, e, i, r, a) - : 9 === l.length && d.drawImage(t, e, i, r, a, n, s, o, h); - } - ellipse(t, e, i, r, a, n, s, o) { - this._context.ellipse(t, e, i, r, a, n, s, o); - } - isPointInPath(t, e) { - return this._context.isPointInPath(t, e); - } - fill() { - this._context.fill(); - } - fillRect(t, e, i, r) { - this._context.fillRect(t, e, i, r); - } - strokeRect(t, e, i, r) { - this._context.strokeRect(t, e, i, r); - } - fillText(t, e, i) { - this._context.fillText(t, e, i); - } - measureText(t) { - return this._context.measureText(t); - } - getImageData(t, e, i, r) { - return this._context.getImageData(t, e, i, r); - } - lineTo(t, e) { - this._context.lineTo(t, e); - } - moveTo(t, e) { - this._context.moveTo(t, e); - } - rect(t, e, i, r) { - this._context.rect(t, e, i, r); - } - putImageData(t, e, i) { - this._context.putImageData(t, e, i); - } - quadraticCurveTo(t, e, i, r) { - this._context.quadraticCurveTo(t, e, i, r); - } - restore() { - this._context.restore(); - } - rotate(t) { - this._context.rotate(t); - } - save() { - this._context.save(); - } - scale(t, e) { - this._context.scale(t, e); - } - setLineDash(t) { - this._context.setLineDash - ? this._context.setLineDash(t) - : 'mozDash' in this._context - ? (this._context.mozDash = t) - : 'webkitLineDash' in this._context && - (this._context.webkitLineDash = t); - } - getLineDash() { - return this._context.getLineDash(); - } - setTransform(t, e, i, r, a, n) { - this._context.setTransform(t, e, i, r, a, n); - } - stroke() { - this._context.stroke(); - } - strokeText(t, e, i, r) { - this._context.strokeText(t, e, i, r); - } - transform(t, e, i, r, a, n) { - this._context.transform(t, e, i, r, a, n); - } - translate(t, e) { - this._context.translate(t, e); - } - _enableTrace() { - var t, - e, - i = this, - r = w.length, - a = this.setAttr, - n = function (t) { - var r, - a = i[t]; - i[t] = function () { - return ( - (e = u._simplifyArray(Array.prototype.slice.call(arguments, 0))), - (r = a.apply(i, arguments)), - i._trace({ method: t, args: e }), - r - ); - }; - }; - for (t = 0; t < r; t++) n(w[t]); - i.setAttr = function () { - a.apply(i, arguments); - var t = arguments[0], - e = arguments[1]; - ('shadowOffsetX' !== t && - 'shadowOffsetY' !== t && - 'shadowBlur' !== t) || - (e /= this.canvas.getPixelRatio()), - i._trace({ property: t, val: e }); - }; - } - _applyGlobalCompositeOperation(t) { - var e = t.getGlobalCompositeOperation(); - 'source-over' !== e && this.setAttr('globalCompositeOperation', e); - } - } - [ - 'fillStyle', - 'strokeStyle', - 'shadowColor', - 'shadowBlur', - 'shadowOffsetX', - 'shadowOffsetY', - 'lineCap', - 'lineDashOffset', - 'lineJoin', - 'lineWidth', - 'miterLimit', - 'font', - 'textAlign', - 'textBaseline', - 'globalAlpha', - 'globalCompositeOperation', - 'imageSmoothingEnabled', - ].forEach(function (t) { - Object.defineProperty(C.prototype, t, { - get() { - return this._context[t]; - }, - set(e) { - this._context[t] = e; - }, - }); - }); - class P extends C { - _fillColor(t) { - var e = t.fill(); - this.setAttr('fillStyle', e), t._fillFunc(this); - } - _fillPattern(t) { - var e = t.getFillPatternX(), - i = t.getFillPatternY(), - r = a.getAngle(t.getFillPatternRotation()), - n = t.getFillPatternOffsetX(), - s = t.getFillPatternOffsetY(); - t.getFillPatternScaleX(), - t.getFillPatternScaleY(), - (e || i) && this.translate(e || 0, i || 0), - r && this.rotate(r), - (n || s) && this.translate(-1 * n, -1 * s), - this.setAttr('fillStyle', t._getFillPattern()), - t._fillFunc(this); - } - _fillLinearGradient(t) { - var e = t._getLinearGradient(); - e && (this.setAttr('fillStyle', e), t._fillFunc(this)); - } - _fillRadialGradient(t) { - var e = t._getRadialGradient(); - e && (this.setAttr('fillStyle', e), t._fillFunc(this)); - } - _fill(t) { - var e = t.fill(), - i = t.getFillPriority(); - if (e && 'color' === i) this._fillColor(t); - else { - var r = t.getFillPatternImage(); - if (r && 'pattern' === i) this._fillPattern(t); - else { - var a = t.getFillLinearGradientColorStops(); - if (a && 'linear-gradient' === i) this._fillLinearGradient(t); - else { - var n = t.getFillRadialGradientColorStops(); - n && 'radial-gradient' === i - ? this._fillRadialGradient(t) - : e - ? this._fillColor(t) - : r - ? this._fillPattern(t) - : a - ? this._fillLinearGradient(t) - : n && this._fillRadialGradient(t); - } - } - } - } - _strokeLinearGradient(t) { - var e = t.getStrokeLinearGradientStartPoint(), - i = t.getStrokeLinearGradientEndPoint(), - r = t.getStrokeLinearGradientColorStops(), - a = this.createLinearGradient(e.x, e.y, i.x, i.y); - if (r) { - for (var n = 0; n < r.length; n += 2) a.addColorStop(r[n], r[n + 1]); - this.setAttr('strokeStyle', a); - } - } - _stroke(t) { - var e = t.dash(), - i = t.getStrokeScaleEnabled(); - if (t.hasStroke()) { - if (!i) { - this.save(); - var r = this.getCanvas().getPixelRatio(); - this.setTransform(r, 0, 0, r, 0, 0); - } - this._applyLineCap(t), - e && - t.dashEnabled() && - (this.setLineDash(e), - this.setAttr('lineDashOffset', t.dashOffset())), - this.setAttr('lineWidth', t.strokeWidth()), - t.getShadowForStrokeEnabled() || - this.setAttr('shadowColor', 'rgba(0,0,0,0)'), - t.getStrokeLinearGradientColorStops() - ? this._strokeLinearGradient(t) - : this.setAttr('strokeStyle', t.stroke()), - t._strokeFunc(this), - i || this.restore(); - } - } - _applyShadow(t) { - var e = u, - i = e.get(t.getShadowRGBA(), 'black'), - r = e.get(t.getShadowBlur(), 5), - a = e.get(t.getShadowOffset(), { x: 0, y: 0 }), - n = t.getAbsoluteScale(), - s = this.canvas.getPixelRatio(), - o = n.x * s, - h = n.y * s; - this.setAttr('shadowColor', i), - this.setAttr('shadowBlur', r * Math.min(Math.abs(o), Math.abs(h))), - this.setAttr('shadowOffsetX', a.x * o), - this.setAttr('shadowOffsetY', a.y * h); - } - } - class k extends C { - _fill(t) { - this.save(), - this.setAttr('fillStyle', t.colorKey), - t._fillFuncHit(this), - this.restore(); - } - strokeShape(t) { - t.hasHitStroke() && this._stroke(t); - } - _stroke(t) { - if (t.hasHitStroke()) { - var e = t.getStrokeScaleEnabled(); - if (!e) { - this.save(); - var i = this.getCanvas().getPixelRatio(); - this.setTransform(i, 0, 0, i, 0, 0); - } - this._applyLineCap(t); - var r = t.hitStrokeWidth(), - a = 'auto' === r ? t.strokeWidth() : r; - this.setAttr('lineWidth', a), - this.setAttr('strokeStyle', t.colorKey), - t._strokeFuncHit(this), - e || this.restore(); - } - } - } - var T; - class A { - constructor(t) { - (this.pixelRatio = 1), - (this.width = 0), - (this.height = 0), - (this.isCache = !1); - var e = - (t || {}).pixelRatio || - a.pixelRatio || - (function () { - if (T) return T; - var t = u.createCanvasElement().getContext('2d'); - return (T = - (a._global.devicePixelRatio || 1) / - (t.webkitBackingStorePixelRatio || - t.mozBackingStorePixelRatio || - t.msBackingStorePixelRatio || - t.oBackingStorePixelRatio || - t.backingStorePixelRatio || - 1)); - })(); - (this.pixelRatio = e), - (this._canvas = u.createCanvasElement()), - (this._canvas.style.padding = '0'), - (this._canvas.style.margin = '0'), - (this._canvas.style.border = '0'), - (this._canvas.style.background = 'transparent'), - (this._canvas.style.position = 'absolute'), - (this._canvas.style.top = '0'), - (this._canvas.style.left = '0'); - } - getContext() { - return this.context; - } - getPixelRatio() { - return this.pixelRatio; - } - setPixelRatio(t) { - var e = this.pixelRatio; - (this.pixelRatio = t), - this.setSize(this.getWidth() / e, this.getHeight() / e); - } - setWidth(t) { - (this.width = this._canvas.width = t * this.pixelRatio), - (this._canvas.style.width = t + 'px'); - var e = this.pixelRatio; - this.getContext()._context.scale(e, e); - } - setHeight(t) { - (this.height = this._canvas.height = t * this.pixelRatio), - (this._canvas.style.height = t + 'px'); - var e = this.pixelRatio; - this.getContext()._context.scale(e, e); - } - getWidth() { - return this.width; - } - getHeight() { - return this.height; - } - setSize(t, e) { - this.setWidth(t || 0), this.setHeight(e || 0); - } - toDataURL(t, e) { - try { - return this._canvas.toDataURL(t, e); - } catch (t) { - try { - return this._canvas.toDataURL(); - } catch (t) { - return ( - u.error( - 'Unable to get data URL. ' + - t.message + - ' For more info read https://konvajs.org/docs/posts/Tainted_Canvas.html.' - ), - '' - ); - } - } - } - } - S.addGetterSetter(A, 'pixelRatio', void 0, v()); - class M extends A { - constructor(t = { width: 0, height: 0 }) { - super(t), (this.context = new P(this)), this.setSize(t.width, t.height); - } - } - class G extends A { - constructor(t = { width: 0, height: 0 }) { - super(t), - (this.hitCanvas = !0), - (this.context = new k(this)), - this.setSize(t.width, t.height); - } - } - const E = { - get isDragging() { - var t = !1; - return ( - E._dragElements.forEach((e) => { - 'dragging' === e.dragStatus && (t = !0); - }), - t - ); - }, - justDragged: !1, - get node() { - var t; - return ( - E._dragElements.forEach((e) => { - t = e.node; - }), - t - ); - }, - _dragElements: new Map(), - _drag(t) { - const e = []; - E._dragElements.forEach((i, r) => { - const { node: a } = i, - n = a.getStage(); - n.setPointersPositions(t), - void 0 === i.pointerId && (i.pointerId = u._getFirstPointerId(t)); - const s = n._changedPointerPositions.find((t) => t.id === i.pointerId); - if (s) { - if ('dragging' !== i.dragStatus) { - var o = a.dragDistance(); - if ( - Math.max( - Math.abs(s.x - i.startPointerPos.x), - Math.abs(s.y - i.startPointerPos.y) - ) < o - ) - return; - if ((a.startDrag({ evt: t }), !a.isDragging())) return; - } - a._setDragPosition(t, i), e.push(a); - } - }), - e.forEach((e) => { - e.fire('dragmove', { type: 'dragmove', target: e, evt: t }, !0); - }); - }, - _endDragBefore(t) { - E._dragElements.forEach((e, i) => { - const { node: r } = e, - n = r.getStage(); - t && n.setPointersPositions(t); - if (!n._changedPointerPositions.find((t) => t.id === e.pointerId)) - return; - ('dragging' !== e.dragStatus && 'stopped' !== e.dragStatus) || - ((E.justDragged = !0), - (a.listenClickTap = !1), - (e.dragStatus = 'stopped')); - const s = e.node.getLayer() || (e.node instanceof a.Stage && e.node); - s && s.batchDraw(); - }); - }, - _endDragAfter(t) { - E._dragElements.forEach((e, i) => { - 'stopped' === e.dragStatus && - e.node.fire( - 'dragend', - { type: 'dragend', target: e.node, evt: t }, - !0 - ), - 'dragging' !== e.dragStatus && E._dragElements.delete(i); - }); - }, - }; - a.isBrowser && - (window.addEventListener('mouseup', E._endDragBefore, !0), - window.addEventListener('touchend', E._endDragBefore, !0), - window.addEventListener('mousemove', E._drag), - window.addEventListener('touchmove', E._drag), - window.addEventListener('mouseup', E._endDragAfter, !1), - window.addEventListener('touchend', E._endDragAfter, !1)); - const R = {}, - L = {}, - D = function (t, e) { - t && R[t] === e && delete R[t]; - }, - I = function (t, e) { - e && (L[e] || (L[e] = []), L[e].push(t)); - }, - O = function (t, e) { - if (t) { - var i = L[t]; - if (i) { - for (var r = 0; r < i.length; r++) { - i[r]._id === e && i.splice(r, 1); - } - 0 === i.length && delete L[t]; - } - } - }; - var F = [ - 'xChange.konva', - 'yChange.konva', - 'scaleXChange.konva', - 'scaleYChange.konva', - 'skewXChange.konva', - 'skewYChange.konva', - 'rotationChange.konva', - 'offsetXChange.konva', - 'offsetYChange.konva', - 'transformsEnabledChange.konva', - ].join(' '); - const B = []; - let N = 1; - class z { - constructor(t) { - (this._id = N++), - (this.eventListeners = {}), - (this.attrs = {}), - (this.index = 0), - (this._allEventListeners = null), - (this.parent = null), - (this._cache = new Map()), - (this._attachedDepsListeners = new Map()), - (this._lastPos = null), - (this._batchingTransformChange = !1), - (this._needClearTransformCache = !1), - (this._filterUpToDate = !1), - (this._isUnderCache = !1), - (this._dragEventId = null), - (this._shouldFireChangeEvents = !1), - this.setAttrs(t), - (this._shouldFireChangeEvents = !0); - } - hasChildren() { - return !1; - } - getChildren() { - return B; - } - _clearCache(t) { - ('transform' !== t && 'absoluteTransform' !== t) || !this._cache.get(t) - ? t - ? this._cache.delete(t) - : this._cache.clear() - : (this._cache.get(t).dirty = !0); - } - _getCache(t, e) { - var i = this._cache.get(t); - return ( - (void 0 === i || - (('transform' === t || 'absoluteTransform' === t) && - !0 === i.dirty)) && - ((i = e.call(this)), this._cache.set(t, i)), - i - ); - } - _calculate(t, e, i) { - if (!this._attachedDepsListeners.get(t)) { - const i = e.map((t) => t + 'Change.konva').join(' '); - this.on(i, () => { - this._clearCache(t); - }), - this._attachedDepsListeners.set(t, !0); - } - return this._getCache(t, i); - } - _getCanvasCache() { - return this._cache.get('canvas'); - } - _clearSelfAndDescendantCache(t, e) { - this._clearCache(t), - e && 'absoluteTransform' === t && this.fire('_clearTransformCache'); - } - clearCache() { - return ( - this._cache.delete('canvas'), this._clearSelfAndDescendantCache(), this - ); - } - cache(t) { - var e = t || {}, - i = {}; - (void 0 !== e.x && - void 0 !== e.y && - void 0 !== e.width && - void 0 !== e.height) || - (i = this.getClientRect({ - skipTransform: !0, - relativeTo: this.getParent(), - })); - var r = Math.ceil(e.width || i.width), - a = Math.ceil(e.height || i.height), - n = e.pixelRatio, - s = void 0 === e.x ? i.x : e.x, - o = void 0 === e.y ? i.y : e.y, - h = e.offset || 0, - l = e.drawBorder || !1; - if (r && a) { - (s -= h), (o -= h); - var d = new M({ - pixelRatio: n, - width: (r += 2 * h), - height: (a += 2 * h), - }), - c = new M({ pixelRatio: n, width: 0, height: 0 }), - g = new G({ pixelRatio: 1, width: r, height: a }), - f = d.getContext(), - p = g.getContext(); - return ( - (g.isCache = !0), - (d.isCache = !0), - this._cache.delete('canvas'), - (this._filterUpToDate = !1), - !1 === e.imageSmoothingEnabled && - ((d.getContext()._context.imageSmoothingEnabled = !1), - (c.getContext()._context.imageSmoothingEnabled = !1)), - f.save(), - p.save(), - f.translate(-s, -o), - p.translate(-s, -o), - (this._isUnderCache = !0), - this._clearSelfAndDescendantCache('absoluteOpacity'), - this._clearSelfAndDescendantCache('absoluteScale'), - this.drawScene(d, this), - this.drawHit(g, this), - (this._isUnderCache = !1), - f.restore(), - p.restore(), - l && - (f.save(), - f.beginPath(), - f.rect(0, 0, r, a), - f.closePath(), - f.setAttr('strokeStyle', 'red'), - f.setAttr('lineWidth', 5), - f.stroke(), - f.restore()), - this._cache.set('canvas', { - scene: d, - filter: c, - hit: g, - x: s, - y: o, - }), - this - ); - } - u.error( - 'Can not cache the node. Width or height of the node equals 0. Caching is skipped.' - ); - } - isCached() { - return this._cache.has('canvas'); - } - getClientRect(t) { - throw new Error('abstract "getClientRect" method call'); - } - _transformedRect(t, e) { - var i, - r, - a, - n, - s = [ - { x: t.x, y: t.y }, - { x: t.x + t.width, y: t.y }, - { x: t.x + t.width, y: t.y + t.height }, - { x: t.x, y: t.y + t.height }, - ], - o = this.getAbsoluteTransform(e); - return ( - s.forEach(function (t) { - var e = o.point(t); - void 0 === i && ((i = a = e.x), (r = n = e.y)), - (i = Math.min(i, e.x)), - (r = Math.min(r, e.y)), - (a = Math.max(a, e.x)), - (n = Math.max(n, e.y)); - }), - { x: i, y: r, width: a - i, height: n - r } - ); - } - _drawCachedSceneCanvas(t) { - t.save(), t._applyOpacity(this), t._applyGlobalCompositeOperation(this); - const e = this._getCanvasCache(); - t.translate(e.x, e.y); - var i = this._getCachedSceneCanvas(), - r = i.pixelRatio; - t.drawImage(i._canvas, 0, 0, i.width / r, i.height / r), t.restore(); - } - _drawCachedHitCanvas(t) { - var e = this._getCanvasCache(), - i = e.hit; - t.save(), - t.translate(e.x, e.y), - t.drawImage(i._canvas, 0, 0), - t.restore(); - } - _getCachedSceneCanvas() { - var t, - e, - i, - r, - a = this.filters(), - n = this._getCanvasCache(), - s = n.scene, - o = n.filter, - h = o.getContext(); - if (a) { - if (!this._filterUpToDate) { - var l = s.pixelRatio; - o.setSize(s.width / s.pixelRatio, s.height / s.pixelRatio); - try { - for ( - t = a.length, - h.clear(), - h.drawImage( - s._canvas, - 0, - 0, - s.getWidth() / l, - s.getHeight() / l - ), - e = h.getImageData(0, 0, o.getWidth(), o.getHeight()), - i = 0; - i < t; - i++ - ) - 'function' == typeof (r = a[i]) - ? (r.call(this, e), h.putImageData(e, 0, 0)) - : u.error( - 'Filter should be type of function, but got ' + - typeof r + - ' instead. Please check correct filters' - ); - } catch (t) { - u.error( - 'Unable to apply filter. ' + - t.message + - ' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.' - ); - } - this._filterUpToDate = !0; - } - return o; - } - return s; - } - on(t, e) { - if ( - (this._cache && this._cache.delete('allEventListeners'), - 3 === arguments.length) - ) - return this._delegate.apply(this, arguments); - var i, - r, - a, - n, - s = t.split(' '), - o = s.length; - for (i = 0; i < o; i++) - (a = (r = s[i].split('.'))[0]), - (n = r[1] || ''), - this.eventListeners[a] || (this.eventListeners[a] = []), - this.eventListeners[a].push({ name: n, handler: e }); - return this; - } - off(t, e) { - var i, - r, - a, - n, - s, - o = (t || '').split(' '), - h = o.length; - if ((this._cache && this._cache.delete('allEventListeners'), !t)) - for (r in this.eventListeners) this._off(r); - for (i = 0; i < h; i++) - if (((n = (a = o[i].split('.'))[0]), (s = a[1]), n)) - this.eventListeners[n] && this._off(n, s, e); - else for (r in this.eventListeners) this._off(r, s, e); - return this; - } - dispatchEvent(t) { - var e = { target: this, type: t.type, evt: t }; - return this.fire(t.type, e), this; - } - addEventListener(t, e) { - return ( - this.on(t, function (t) { - e.call(this, t.evt); - }), - this - ); - } - removeEventListener(t) { - return this.off(t), this; - } - _delegate(t, e, i) { - var r = this; - this.on(t, function (t) { - for (var a = t.target.findAncestors(e, !0, r), n = 0; n < a.length; n++) - ((t = u.cloneObject(t)).currentTarget = a[n]), i.call(a[n], t); - }); - } - remove() { - return ( - this.isDragging() && this.stopDrag(), - E._dragElements.delete(this._id), - this._remove(), - this - ); - } - _clearCaches() { - this._clearSelfAndDescendantCache('absoluteTransform'), - this._clearSelfAndDescendantCache('absoluteOpacity'), - this._clearSelfAndDescendantCache('absoluteScale'), - this._clearSelfAndDescendantCache('stage'), - this._clearSelfAndDescendantCache('visible'), - this._clearSelfAndDescendantCache('listening'); - } - _remove() { - this._clearCaches(); - var t = this.getParent(); - t && - t.children && - (t.children.splice(this.index, 1), - t._setChildrenIndices(), - (this.parent = null)); - } - destroy() { - D(this.id(), this); - for (var t = (this.name() || '').split(/\s/g), e = 0; e < t.length; e++) { - var i = t[e]; - O(i, this._id); - } - return this.remove(), this; - } - getAttr(t) { - var e = 'get' + u._capitalize(t); - return u._isFunction(this[e]) ? this[e]() : this.attrs[t]; - } - getAncestors() { - for (var t = this.getParent(), e = []; t; ) - e.push(t), (t = t.getParent()); - return e; - } - getAttrs() { - return this.attrs || {}; - } - setAttrs(t) { - return ( - this._batchTransformChanges(() => { - var e, i; - if (!t) return this; - for (e in t) - 'children' !== e && - ((i = 'set' + u._capitalize(e)), - u._isFunction(this[i]) ? this[i](t[e]) : this._setAttr(e, t[e])); - }), - this - ); - } - isListening() { - return this._getCache('listening', this._isListening); - } - _isListening(t) { - if (!this.listening()) return !1; - const e = this.getParent(); - return !e || e === t || this === t || e._isListening(t); - } - isVisible() { - return this._getCache('visible', this._isVisible); - } - _isVisible(t) { - if (!this.visible()) return !1; - const e = this.getParent(); - return !e || e === t || this === t || e._isVisible(t); - } - shouldDrawHit(t, e = !1) { - if (t) return this._isVisible(t) && this._isListening(t); - var i = this.getLayer(), - r = !1; - E._dragElements.forEach((t) => { - 'dragging' === t.dragStatus && - ('Stage' === t.node.nodeType || t.node.getLayer() === i) && - (r = !0); - }); - var n = !e && !a.hitOnDragEnabled && r; - return this.isListening() && this.isVisible() && !n; - } - show() { - return this.visible(!0), this; - } - hide() { - return this.visible(!1), this; - } - getZIndex() { - return this.index || 0; - } - getAbsoluteZIndex() { - var t, - e, - i, - r, - a = this.getDepth(), - n = this, - s = 0; - return ( - 'Stage' !== n.nodeType && - (function o(h) { - for (t = [], e = h.length, i = 0; i < e; i++) - (r = h[i]), - s++, - 'Shape' !== r.nodeType && - (t = t.concat(r.getChildren().slice())), - r._id === n._id && (i = e); - t.length > 0 && t[0].getDepth() <= a && o(t); - })(n.getStage().getChildren()), - s - ); - } - getDepth() { - for (var t = 0, e = this.parent; e; ) t++, (e = e.parent); - return t; - } - _batchTransformChanges(t) { - (this._batchingTransformChange = !0), - t(), - (this._batchingTransformChange = !1), - this._needClearTransformCache && - (this._clearCache('transform'), - this._clearSelfAndDescendantCache('absoluteTransform', !0)), - (this._needClearTransformCache = !1); - } - setPosition(t) { - return ( - this._batchTransformChanges(() => { - this.x(t.x), this.y(t.y); - }), - this - ); - } - getPosition() { - return { x: this.x(), y: this.y() }; - } - getAbsolutePosition(t) { - let e = !1, - i = this.parent; - for (; i; ) { - if (i.isCached()) { - e = !0; - break; - } - i = i.parent; - } - e && !t && (t = !0); - var r = this.getAbsoluteTransform(t).getMatrix(), - a = new o(), - n = this.offset(); - return (a.m = r.slice()), a.translate(n.x, n.y), a.getTranslation(); - } - setAbsolutePosition(t) { - var e = this._clearTransform(); - (this.attrs.x = e.x), - (this.attrs.y = e.y), - delete e.x, - delete e.y, - this._clearCache('transform'); - var i = this._getAbsoluteTransform().copy(); - return ( - i.invert(), - i.translate(t.x, t.y), - (t = { - x: this.attrs.x + i.getTranslation().x, - y: this.attrs.y + i.getTranslation().y, - }), - this._setTransform(e), - this.setPosition({ x: t.x, y: t.y }), - this._clearCache('transform'), - this._clearSelfAndDescendantCache('absoluteTransform'), - this - ); - } - _setTransform(t) { - var e; - for (e in t) this.attrs[e] = t[e]; - } - _clearTransform() { - var t = { - x: this.x(), - y: this.y(), - rotation: this.rotation(), - scaleX: this.scaleX(), - scaleY: this.scaleY(), - offsetX: this.offsetX(), - offsetY: this.offsetY(), - skewX: this.skewX(), - skewY: this.skewY(), - }; - return ( - (this.attrs.x = 0), - (this.attrs.y = 0), - (this.attrs.rotation = 0), - (this.attrs.scaleX = 1), - (this.attrs.scaleY = 1), - (this.attrs.offsetX = 0), - (this.attrs.offsetY = 0), - (this.attrs.skewX = 0), - (this.attrs.skewY = 0), - t - ); - } - move(t) { - var e = t.x, - i = t.y, - r = this.x(), - a = this.y(); - return ( - void 0 !== e && (r += e), - void 0 !== i && (a += i), - this.setPosition({ x: r, y: a }), - this - ); - } - _eachAncestorReverse(t, e) { - var i, - r, - a = [], - n = this.getParent(); - if (!e || e._id !== this._id) { - for (a.unshift(this); n && (!e || n._id !== e._id); ) - a.unshift(n), (n = n.parent); - for (i = a.length, r = 0; r < i; r++) t(a[r]); - } - } - rotate(t) { - return this.rotation(this.rotation() + t), this; - } - moveToTop() { - if (!this.parent) - return u.warn('Node has no parent. moveToTop function is ignored.'), !1; - var t = this.index; - return ( - this.parent.children.splice(t, 1), - this.parent.children.push(this), - this.parent._setChildrenIndices(), - !0 - ); - } - moveUp() { - if (!this.parent) - return u.warn('Node has no parent. moveUp function is ignored.'), !1; - var t = this.index; - return ( - t < this.parent.getChildren().length - 1 && - (this.parent.children.splice(t, 1), - this.parent.children.splice(t + 1, 0, this), - this.parent._setChildrenIndices(), - !0) - ); - } - moveDown() { - if (!this.parent) - return u.warn('Node has no parent. moveDown function is ignored.'), !1; - var t = this.index; - return ( - t > 0 && - (this.parent.children.splice(t, 1), - this.parent.children.splice(t - 1, 0, this), - this.parent._setChildrenIndices(), - !0) - ); - } - moveToBottom() { - if (!this.parent) - return ( - u.warn('Node has no parent. moveToBottom function is ignored.'), !1 - ); - var t = this.index; - return ( - t > 0 && - (this.parent.children.splice(t, 1), - this.parent.children.unshift(this), - this.parent._setChildrenIndices(), - !0) - ); - } - setZIndex(t) { - if (!this.parent) - return u.warn('Node has no parent. zIndex parameter is ignored.'), this; - (t < 0 || t >= this.parent.children.length) && - u.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 - ); - } - getAbsoluteOpacity() { - return this._getCache('absoluteOpacity', this._getAbsoluteOpacity); - } - _getAbsoluteOpacity() { - var t = this.opacity(), - e = this.getParent(); - return e && !e._isUnderCache && (t *= e.getAbsoluteOpacity()), t; - } - moveTo(t) { - return this.getParent() !== t && (this._remove(), t.add(this)), this; - } - toObject() { - var t, - e, - i, - r, - a = {}, - n = this.getAttrs(); - for (t in ((a.attrs = {}), n)) - (e = n[t]), - (u.isObject(e) && !u._isPlainObject(e) && !u._isArray(e)) || - ((i = 'function' == typeof this[t] && this[t]), - delete n[t], - (r = i ? i.call(this) : null), - (n[t] = e), - r !== e && (a.attrs[t] = e)); - return (a.className = this.getClassName()), u._prepareToStringify(a); - } - toJSON() { - return JSON.stringify(this.toObject()); - } - getParent() { - return this.parent; - } - findAncestors(t, e, i) { - var r = []; - e && this._isMatch(t) && r.push(this); - for (var a = this.parent; a; ) { - if (a === i) return r; - a._isMatch(t) && r.push(a), (a = a.parent); - } - return r; - } - isAncestorOf(t) { - return !1; - } - findAncestor(t, e, i) { - return this.findAncestors(t, e, i)[0]; - } - _isMatch(t) { - if (!t) return !1; - if ('function' == typeof t) return t(this); - var e, - i, - r = t.replace(/ /g, '').split(','), - a = r.length; - for (e = 0; e < a; e++) - if ( - ((i = r[e]), - u.isValidSelector(i) || - (u.warn( - 'Selector "' + - i + - '" is invalid. Allowed selectors examples are "#foo", ".bar" or "Group".' - ), - u.warn( - 'If you have a custom shape with such className, please change it to start with upper letter like "Triangle".' - ), - u.warn('Konva is awesome, right?')), - '#' === i.charAt(0)) - ) { - if (this.id() === i.slice(1)) return !0; - } else if ('.' === i.charAt(0)) { - if (this.hasName(i.slice(1))) return !0; - } else if (this.className === i || this.nodeType === i) return !0; - return !1; - } - getLayer() { - var t = this.getParent(); - return t ? t.getLayer() : null; - } - getStage() { - return this._getCache('stage', this._getStage); - } - _getStage() { - var t = this.getParent(); - return t ? t.getStage() : void 0; - } - fire(t, e = {}, i) { - return ( - (e.target = e.target || this), - i ? this._fireAndBubble(t, e) : this._fire(t, e), - this - ); - } - getAbsoluteTransform(t) { - return t - ? this._getAbsoluteTransform(t) - : this._getCache('absoluteTransform', this._getAbsoluteTransform); - } - _getAbsoluteTransform(t) { - var e; - if (t) - return ( - (e = new o()), - this._eachAncestorReverse(function (t) { - var i = t.transformsEnabled(); - 'all' === i - ? e.multiply(t.getTransform()) - : 'position' === i && - e.translate(t.x() - t.offsetX(), t.y() - t.offsetY()); - }, t), - e - ); - (e = this._cache.get('absoluteTransform') || new o()), - this.parent - ? this.parent.getAbsoluteTransform().copyInto(e) - : e.reset(); - var i = this.transformsEnabled(); - if ('all' === i) e.multiply(this.getTransform()); - else if ('position' === i) { - const t = this.attrs.x || 0, - i = this.attrs.y || 0, - r = this.attrs.offsetX || 0, - a = this.attrs.offsetY || 0; - e.translate(t - r, i - a); - } - return (e.dirty = !1), e; - } - getAbsoluteScale(t) { - for (var e = this; e; ) e._isUnderCache && (t = e), (e = e.getParent()); - const i = this.getAbsoluteTransform(t).decompose(); - return { x: i.scaleX, y: i.scaleY }; - } - getAbsoluteRotation() { - return this.getAbsoluteTransform().decompose().rotation; - } - getTransform() { - return this._getCache('transform', this._getTransform); - } - _getTransform() { - var t, - e, - i = this._cache.get('transform') || new o(); - i.reset(); - var r = this.x(), - n = this.y(), - s = a.getAngle(this.rotation()), - h = null !== (t = this.attrs.scaleX) && void 0 !== t ? t : 1, - l = null !== (e = this.attrs.scaleY) && void 0 !== e ? e : 1, - d = this.attrs.skewX || 0, - c = this.attrs.skewY || 0, - g = this.attrs.offsetX || 0, - u = this.attrs.offsetY || 0; - return ( - (0 === r && 0 === n) || i.translate(r, n), - 0 !== s && i.rotate(s), - (0 === d && 0 === c) || i.skew(d, c), - (1 === h && 1 === l) || i.scale(h, l), - (0 === g && 0 === u) || i.translate(-1 * g, -1 * u), - (i.dirty = !1), - i - ); - } - clone(t) { - var e, - i, - r, - a, - n, - s = u.cloneObject(this.attrs); - for (e in t) s[e] = t[e]; - var o = new this.constructor(s); - for (e in this.eventListeners) - for (r = (i = this.eventListeners[e]).length, a = 0; a < r; a++) - (n = i[a]).name.indexOf('konva') < 0 && - (o.eventListeners[e] || (o.eventListeners[e] = []), - o.eventListeners[e].push(n)); - return o; - } - _toKonvaCanvas(t) { - t = t || {}; - var e = this.getClientRect(), - i = this.getStage(), - r = void 0 !== t.x ? t.x : e.x, - a = void 0 !== t.y ? t.y : e.y, - n = t.pixelRatio || 1, - s = new M({ - width: t.width || e.width || (i ? i.width() : 0), - height: t.height || e.height || (i ? i.height() : 0), - pixelRatio: n, - }), - o = s.getContext(); - return ( - o.save(), - (r || a) && o.translate(-1 * r, -1 * a), - this.drawScene(s), - o.restore(), - s - ); - } - toCanvas(t) { - return this._toKonvaCanvas(t)._canvas; - } - toDataURL(t) { - var e = (t = t || {}).mimeType || null, - i = t.quality || null, - r = this._toKonvaCanvas(t).toDataURL(e, i); - return t.callback && t.callback(r), r; - } - toImage(t) { - if (!t || !t.callback) - throw 'callback required for toImage method config argument'; - var e = t.callback; - delete t.callback, - u._urlToImage(this.toDataURL(t), function (t) { - e(t); - }); - } - setSize(t) { - return this.width(t.width), this.height(t.height), this; - } - getSize() { - return { width: this.width(), height: this.height() }; - } - getClassName() { - return this.className || this.nodeType; - } - getType() { - return this.nodeType; - } - getDragDistance() { - return void 0 !== this.attrs.dragDistance - ? this.attrs.dragDistance - : this.parent - ? this.parent.getDragDistance() - : a.dragDistance; - } - _off(t, e, i) { - var r, - a, - n, - s = this.eventListeners[t]; - for (r = 0; r < s.length; r++) - if ( - ((a = s[r].name), - (n = s[r].handler), - !( - ('konva' === a && 'konva' !== e) || - (e && a !== e) || - (i && i !== n) - )) - ) { - if ((s.splice(r, 1), 0 === s.length)) { - delete this.eventListeners[t]; - break; - } - r--; - } - } - _fireChangeEvent(t, e, i) { - this._fire(t + 'Change', { oldVal: e, newVal: i }); - } - setId(t) { - var e = this.id(); - return ( - D(e, this), - (function (t, e) { - e && (R[e] = t); - })(this, t), - this._setAttr('id', t), - this - ); - } - setName(t) { - var e, - i, - r = (this.name() || '').split(/\s/g), - a = (t || '').split(/\s/g); - for (i = 0; i < r.length; i++) - (e = r[i]), -1 === a.indexOf(e) && e && O(e, this._id); - for (i = 0; i < a.length; i++) - (e = a[i]), -1 === r.indexOf(e) && e && I(this, e); - return this._setAttr('name', t), this; - } - addName(t) { - if (!this.hasName(t)) { - var e = this.name(), - i = e ? e + ' ' + t : t; - this.setName(i); - } - return this; - } - hasName(t) { - if (!t) return !1; - const e = this.name(); - return !!e && -1 !== (e || '').split(/\s/g).indexOf(t); - } - removeName(t) { - var e = (this.name() || '').split(/\s/g), - i = e.indexOf(t); - return -1 !== i && (e.splice(i, 1), this.setName(e.join(' '))), this; - } - setAttr(t, e) { - var i = this['set' + u._capitalize(t)]; - return u._isFunction(i) ? i.call(this, e) : this._setAttr(t, e), this; - } - _setAttr(t, e, i = !1) { - var r = this.attrs[t]; - if ( - (r !== e || u.isObject(e)) && - (null == e ? delete this.attrs[t] : (this.attrs[t] = e), - this._shouldFireChangeEvents && this._fireChangeEvent(t, r, e), - a.autoDrawEnabled) - ) { - const t = this.getLayer() || this.getStage(); - null == t || t.batchDraw(); - } - } - _setComponentAttr(t, e, i) { - var r; - void 0 !== i && - ((r = this.attrs[t]) || (this.attrs[t] = this.getAttr(t)), - (this.attrs[t][e] = i), - this._fireChangeEvent(t, r, i)); - } - _fireAndBubble(t, e, i) { - if ( - (e && 'Shape' === this.nodeType && (e.target = this), - !( - ('mouseenter' === t || 'mouseleave' === t) && - ((i && (this === i || (this.isAncestorOf && this.isAncestorOf(i)))) || - ('Stage' === this.nodeType && !i)) - )) - ) { - this._fire(t, e); - var r = - ('mouseenter' === t || 'mouseleave' === t) && - i && - i.isAncestorOf && - i.isAncestorOf(this) && - !i.isAncestorOf(this.parent); - ((e && !e.cancelBubble) || !e) && - this.parent && - this.parent.isListening() && - !r && - (i && i.parent - ? this._fireAndBubble.call(this.parent, t, e, i) - : this._fireAndBubble.call(this.parent, t, e)); - } - } - _getProtoListeners(t) { - let e = this._cache.get('allEventListeners'); - if (!e) { - e = {}; - let t = Object.getPrototypeOf(this); - for (; t; ) - if (t.eventListeners) { - for (var i in t.eventListeners) { - const r = t.eventListeners[i], - a = e[i] || []; - e[i] = r.concat(a); - } - t = Object.getPrototypeOf(t); - } else t = Object.getPrototypeOf(t); - this._cache.set('allEventListeners', e); - } - return e[t]; - } - _fire(t, e) { - ((e = e || {}).currentTarget = this), (e.type = t); - const i = this._getProtoListeners(t); - if (i) for (var r = 0; r < i.length; r++) i[r].handler.call(this, e); - const a = this.eventListeners[t]; - if (a) for (r = 0; r < a.length; r++) a[r].handler.call(this, e); - } - draw() { - return this.drawScene(), this.drawHit(), this; - } - _createDragElement(t) { - var e = t ? t.pointerId : void 0, - i = this.getStage(), - r = this.getAbsolutePosition(), - a = i._getPointerById(e) || i._changedPointerPositions[0] || r; - E._dragElements.set(this._id, { - node: this, - startPointerPos: a, - offset: { x: a.x - r.x, y: a.y - r.y }, - dragStatus: 'ready', - pointerId: e, - }); - } - startDrag(t, e = !0) { - E._dragElements.has(this._id) || this._createDragElement(t); - (E._dragElements.get(this._id).dragStatus = 'dragging'), - this.fire( - 'dragstart', - { type: 'dragstart', target: this, evt: t && t.evt }, - e - ); - } - _setDragPosition(t, e) { - const i = this.getStage()._getPointerById(e.pointerId); - if (i) { - var r = { x: i.x - e.offset.x, y: i.y - e.offset.y }, - a = this.dragBoundFunc(); - if (void 0 !== a) { - const e = a.call(this, r, t); - e - ? (r = e) - : u.warn( - 'dragBoundFunc did not return any value. That is unexpected behavior. You must return new absolute position from dragBoundFunc.' - ); - } - (this._lastPos && this._lastPos.x === r.x && this._lastPos.y === r.y) || - (this.setAbsolutePosition(r), - this.getLayer() - ? this.getLayer().batchDraw() - : this.getStage() && this.getStage().batchDraw()), - (this._lastPos = r); - } - } - stopDrag(t) { - const e = E._dragElements.get(this._id); - e && (e.dragStatus = 'stopped'), E._endDragBefore(t), E._endDragAfter(t); - } - setDraggable(t) { - this._setAttr('draggable', t), this._dragChange(); - } - isDragging() { - const t = E._dragElements.get(this._id); - return !!t && 'dragging' === t.dragStatus; - } - _listenDrag() { - this._dragCleanup(), - this.on('mousedown.konva touchstart.konva', function (t) { - if ( - (!(void 0 !== t.evt.button) || - a.dragButtons.indexOf(t.evt.button) >= 0) && - !this.isDragging() - ) { - var e = !1; - E._dragElements.forEach((t) => { - this.isAncestorOf(t.node) && (e = !0); - }), - e || this._createDragElement(t); - } - }); - } - _dragChange() { - if (this.attrs.draggable) this._listenDrag(); - else { - if ((this._dragCleanup(), !this.getStage())) return; - const t = E._dragElements.get(this._id), - e = t && 'dragging' === t.dragStatus, - i = t && 'ready' === t.dragStatus; - e ? this.stopDrag() : i && E._dragElements.delete(this._id); - } - } - _dragCleanup() { - this.off('mousedown.konva'), this.off('touchstart.konva'); - } - static create(t, e) { - return u._isString(t) && (t = JSON.parse(t)), this._createNode(t, e); - } - static _createNode(t, e) { - var i, - r, - a, - s = z.prototype.getClassName.call(t), - o = t.children; - e && (t.attrs.container = e), - n[s] || - (u.warn( - 'Can not find a node with class name "' + - s + - '". Fallback to "Shape".' - ), - (s = 'Shape')); - if (((i = new (0, n[s])(t.attrs)), o)) - for (r = o.length, a = 0; a < r; a++) i.add(z._createNode(o[a])); - return i; - } - } - (z.prototype.nodeType = 'Node'), - (z.prototype._attrsAffectingSize = []), - (z.prototype.eventListeners = {}), - z.prototype.on.call(z.prototype, F, function () { - this._batchingTransformChange - ? (this._needClearTransformCache = !0) - : (this._clearCache('transform'), - this._clearSelfAndDescendantCache('absoluteTransform')); - }), - z.prototype.on.call(z.prototype, 'visibleChange.konva', function () { - this._clearSelfAndDescendantCache('visible'); - }), - z.prototype.on.call(z.prototype, 'listeningChange.konva', function () { - this._clearSelfAndDescendantCache('listening'); - }), - z.prototype.on.call(z.prototype, 'opacityChange.konva', function () { - this._clearSelfAndDescendantCache('absoluteOpacity'); - }); - const W = S.addGetterSetter; - W(z, 'zIndex'), - W(z, 'absolutePosition'), - W(z, 'position'), - W(z, 'x', 0, v()), - W(z, 'y', 0, v()), - W(z, 'globalCompositeOperation', 'source-over', y()), - W(z, 'opacity', 1, v()), - W(z, 'name', '', y()), - W(z, 'id', '', y()), - W(z, 'rotation', 0, v()), - S.addComponentsGetterSetter(z, 'scale', ['x', 'y']), - W(z, 'scaleX', 1, v()), - W(z, 'scaleY', 1, v()), - S.addComponentsGetterSetter(z, 'skew', ['x', 'y']), - W(z, 'skewX', 0, v()), - W(z, 'skewY', 0, v()), - S.addComponentsGetterSetter(z, 'offset', ['x', 'y']), - W(z, 'offsetX', 0, v()), - W(z, 'offsetY', 0, v()), - W(z, 'dragDistance', null, v()), - W(z, 'width', 0, v()), - W(z, 'height', 0, v()), - W(z, 'listening', !0, b()), - W(z, 'preventDefault', !0, b()), - W(z, 'filters', null, function (t) { - return (this._filterUpToDate = !1), t; - }), - W(z, 'visible', !0, b()), - W(z, 'transformsEnabled', 'all', y()), - W(z, 'size'), - W(z, 'dragBoundFunc'), - W(z, 'draggable', !1, b()), - S.backCompat(z, { - rotateDeg: 'rotate', - setRotationDeg: 'setRotation', - getRotationDeg: 'getRotation', - }); - class H extends z { - constructor() { - super(...arguments), (this.children = []); - } - getChildren(t) { - if (!t) return this.children || []; - const e = this.children || []; - var i = []; - return ( - e.forEach(function (e) { - t(e) && i.push(e); - }), - i - ); - } - hasChildren() { - return this.getChildren().length > 0; - } - removeChildren() { - return ( - this.getChildren().forEach((t) => { - (t.parent = null), (t.index = 0), t.remove(); - }), - (this.children = []), - this - ); - } - destroyChildren() { - return ( - this.getChildren().forEach((t) => { - (t.parent = null), (t.index = 0), t.destroy(); - }), - (this.children = []), - this - ); - } - add(...t) { - if (arguments.length > 1) { - for (var e = 0; e < arguments.length; e++) this.add(arguments[e]); - return this; - } - var i = t[0]; - return i.getParent() - ? (i.moveTo(this), this) - : (this._validateAdd(i), - i._clearCaches(), - (i.index = this.getChildren().length), - (i.parent = this), - this.getChildren().push(i), - this._fire('add', { child: i }), - this); - } - destroy() { - return ( - this.hasChildren() && this.destroyChildren(), super.destroy(), this - ); - } - find(t) { - return this._generalFind(t, !1); - } - findOne(t) { - var e = this._generalFind(t, !0); - return e.length > 0 ? e[0] : void 0; - } - _generalFind(t, e) { - var i = []; - return ( - this._descendants((r) => { - const a = r._isMatch(t); - return a && i.push(r), !(!a || !e); - }), - i - ); - } - _descendants(t) { - let e = !1; - const i = this.getChildren(); - for (const r of i) { - if (((e = t(r)), e)) return !0; - if (r.hasChildren() && ((e = r._descendants(t)), e)) return !0; - } - return !1; - } - toObject() { - var t = z.prototype.toObject.call(this); - return ( - (t.children = []), - this.getChildren().forEach((e) => { - t.children.push(e.toObject()); - }), - t - ); - } - isAncestorOf(t) { - for (var e = t.getParent(); e; ) { - if (e._id === this._id) return !0; - e = e.getParent(); - } - return !1; - } - clone(t) { - var e = z.prototype.clone.call(this, t); - return ( - this.getChildren().forEach(function (t) { - e.add(t.clone()); - }), - e - ); - } - getAllIntersections(t) { - var e = []; - return ( - this.find('Shape').forEach(function (i) { - i.isVisible() && i.intersects(t) && e.push(i); - }), - e - ); - } - _clearSelfAndDescendantCache(t, e) { - var i; - super._clearSelfAndDescendantCache(t, e), - this.isCached() || - null === (i = this.children) || - void 0 === i || - i.forEach(function (i) { - i._clearSelfAndDescendantCache(t, e); - }); - } - _setChildrenIndices() { - var t; - null === (t = this.children) || - void 0 === t || - t.forEach(function (t, e) { - t.index = e; - }); - } - drawScene(t, e) { - var i = this.getLayer(), - r = t || (i && i.getCanvas()), - a = r && r.getContext(), - n = this._getCanvasCache(), - s = n && n.scene, - o = r && r.isCache; - if (!this.isVisible() && !o) return this; - if (s) { - a.save(); - var h = this.getAbsoluteTransform(e).getMatrix(); - a.transform(h[0], h[1], h[2], h[3], h[4], h[5]), - this._drawCachedSceneCanvas(a), - a.restore(); - } else this._drawChildren('drawScene', r, e); - return this; - } - drawHit(t, e) { - if (!this.shouldDrawHit(e)) return this; - var i = this.getLayer(), - r = t || (i && i.hitCanvas), - a = r && r.getContext(), - n = this._getCanvasCache(); - if (n && n.hit) { - a.save(); - var s = this.getAbsoluteTransform(e).getMatrix(); - a.transform(s[0], s[1], s[2], s[3], s[4], s[5]), - this._drawCachedHitCanvas(a), - a.restore(); - } else this._drawChildren('drawHit', r, e); - return this; - } - _drawChildren(t, e, i) { - var r, - a = e && e.getContext(), - n = this.clipWidth(), - s = this.clipHeight(), - o = this.clipFunc(), - h = (n && s) || o; - const l = i === this; - if (h) { - a.save(); - var d = this.getAbsoluteTransform(i), - c = d.getMatrix(); - if ((a.transform(c[0], c[1], c[2], c[3], c[4], c[5]), a.beginPath(), o)) - o.call(this, a, this); - else { - var g = this.clipX(), - u = this.clipY(); - a.rect(g, u, n, s); - } - a.clip(), - (c = d.copy().invert().getMatrix()), - a.transform(c[0], c[1], c[2], c[3], c[4], c[5]); - } - var f = - !l && - 'source-over' !== this.globalCompositeOperation() && - 'drawScene' === t; - f && (a.save(), a._applyGlobalCompositeOperation(this)), - null === (r = this.children) || - void 0 === r || - r.forEach(function (r) { - r[t](e, i); - }), - f && a.restore(), - h && a.restore(); - } - getClientRect(t) { - var e, - i, - r, - a, - n, - s = (t = t || {}).skipTransform, - o = t.relativeTo, - h = { x: 1 / 0, y: 1 / 0, width: 0, height: 0 }, - l = this; - null === (e = this.children) || - void 0 === e || - e.forEach(function (e) { - if (e.visible()) { - var s = e.getClientRect({ - relativeTo: l, - skipShadow: t.skipShadow, - skipStroke: t.skipStroke, - }); - (0 === s.width && 0 === s.height) || - (void 0 === i - ? ((i = s.x), - (r = s.y), - (a = s.x + s.width), - (n = s.y + s.height)) - : ((i = Math.min(i, s.x)), - (r = Math.min(r, s.y)), - (a = Math.max(a, s.x + s.width)), - (n = Math.max(n, s.y + s.height)))); - } - }); - for (var d = this.find('Shape'), c = !1, g = 0; g < d.length; g++) { - if (d[g]._isVisible(this)) { - c = !0; - break; - } - } - return ( - (h = - c && void 0 !== i - ? { x: i, y: r, width: a - i, height: n - r } - : { x: 0, y: 0, width: 0, height: 0 }), - s ? h : this._transformedRect(h, o) - ); - } - } - S.addComponentsGetterSetter(H, 'clip', ['x', 'y', 'width', 'height']), - S.addGetterSetter(H, 'clipX', void 0, v()), - S.addGetterSetter(H, 'clipY', void 0, v()), - S.addGetterSetter(H, 'clipWidth', void 0, v()), - S.addGetterSetter(H, 'clipHeight', void 0, v()), - S.addGetterSetter(H, 'clipFunc'); - const Y = new Map(), - X = void 0 !== a._global.PointerEvent; - function j(t) { - return Y.get(t); - } - function U(t) { - return { evt: t, pointerId: t.pointerId }; - } - function q(t, e) { - return Y.get(t) === e; - } - function K(t, e) { - V(t); - e.getStage() && - (Y.set(t, e), - X && - e._fire('gotpointercapture', U(new PointerEvent('gotpointercapture')))); - } - function V(t, e) { - const i = Y.get(t); - if (!i) return; - const r = i.getStage(); - r && r.content, - Y.delete(t), - X && - i._fire( - 'lostpointercapture', - U(new PointerEvent('lostpointercapture')) - ); - } - var Q = [ - 'mouseenter', - 'mousedown', - 'mousemove', - 'mouseup', - 'mouseleave', - 'touchstart', - 'touchmove', - 'touchend', - 'mouseover', - 'wheel', - 'contextmenu', - 'pointerdown', - 'pointermove', - 'pointerup', - 'pointercancel', - 'lostpointercapture', - ], - J = Q.length; - function Z(t, e) { - t.content.addEventListener( - e, - function (i) { - t['_' + e](i); - }, - !1 - ); - } - const $ = []; - function tt(t = {}) { - return ( - (t.clipFunc || t.clipWidth || t.clipHeight) && - u.warn( - 'Stage does not support clipping. Please use clip for Layers or Groups.' - ), - t - ); - } - class et extends H { - constructor(t) { - super(tt(t)), - (this._pointerPositions = []), - (this._changedPointerPositions = []), - this._buildDOM(), - this._bindContentEvents(), - $.push(this), - this.on('widthChange.konva heightChange.konva', this._resizeDOM), - this.on('visibleChange.konva', this._checkVisibility), - this.on( - 'clipWidthChange.konva clipHeightChange.konva clipFuncChange.konva', - () => { - tt(this.attrs); - } - ), - this._checkVisibility(); - } - _validateAdd(t) { - const e = 'Layer' === t.getType(), - i = 'FastLayer' === t.getType(); - e || i || u.throw('You may only add layers to the stage.'); - } - _checkVisibility() { - if (!this.content) return; - const t = this.visible() ? '' : 'none'; - this.content.style.display = t; - } - setContainer(t) { - if ('string' == typeof t) { - if ('.' === t.charAt(0)) { - var e = t.slice(1); - t = document.getElementsByClassName(e)[0]; - } else { - var i; - (i = '#' !== t.charAt(0) ? t : t.slice(1)), - (t = document.getElementById(i)); - } - if (!t) throw 'Can not find container in document with id ' + i; - } - return ( - this._setAttr('container', t), - this.content && - (this.content.parentElement && - this.content.parentElement.removeChild(this.content), - t.appendChild(this.content)), - this - ); - } - shouldDrawHit() { - return !0; - } - clear() { - var t, - e = this.children, - i = e.length; - for (t = 0; t < i; t++) e[t].clear(); - return this; - } - clone(t) { - return ( - t || (t = {}), - (t.container = - 'undefined' != typeof document && document.createElement('div')), - H.prototype.clone.call(this, t) - ); - } - destroy() { - super.destroy(); - var t = this.content; - t && u._isInDocument(t) && this.container().removeChild(t); - var e = $.indexOf(this); - return e > -1 && $.splice(e, 1), this; - } - getPointerPosition() { - const t = this._pointerPositions[0] || this._changedPointerPositions[0]; - return t - ? { x: t.x, y: t.y } - : (u.warn( - 'Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);' - ), - null); - } - _getPointerById(t) { - return this._pointerPositions.find((e) => e.id === t); - } - getPointersPositions() { - return this._pointerPositions; - } - getStage() { - return this; - } - getContent() { - return this.content; - } - _toKonvaCanvas(t) { - ((t = t || {}).x = t.x || 0), - (t.y = t.y || 0), - (t.width = t.width || this.width()), - (t.height = t.height || this.height()); - var e = new M({ - width: t.width, - height: t.height, - pixelRatio: t.pixelRatio || 1, - }), - i = e.getContext()._context, - r = this.children; - return ( - (t.x || t.y) && i.translate(-1 * t.x, -1 * t.y), - r.forEach(function (e) { - if (e.isVisible()) { - var r = e._toKonvaCanvas(t); - i.drawImage( - r._canvas, - t.x, - t.y, - r.getWidth() / r.getPixelRatio(), - r.getHeight() / r.getPixelRatio() - ); - } - }), - e - ); - } - getIntersection(t, e) { - if (!t) return null; - var i, - r = this.children; - for (i = r.length - 1; i >= 0; i--) { - const a = r[i].getIntersection(t, e); - if (a) return a; - } - return null; - } - _resizeDOM() { - var t = this.width(), - e = this.height(); - this.content && - ((this.content.style.width = t + 'px'), - (this.content.style.height = e + 'px')), - this.bufferCanvas.setSize(t, e), - this.bufferHitCanvas.setSize(t, e), - this.children.forEach((i) => { - i.setSize({ width: t, height: e }), i.draw(); - }); - } - add(t, ...e) { - if (arguments.length > 1) { - for (var i = 0; i < arguments.length; i++) this.add(arguments[i]); - return this; - } - super.add(t); - var r = this.children.length; - return ( - r > 5 && - u.warn( - 'The stage has ' + - r + - ' layers. Recommended maximum number of layers is 3-5. Adding more layers into the stage may drop the performance. Rethink your tree structure, you can use Konva.Group.' - ), - t.setSize({ width: this.width(), height: this.height() }), - t.draw(), - a.isBrowser && this.content.appendChild(t.canvas._canvas), - this - ); - } - getParent() { - return null; - } - getLayer() { - return null; - } - hasPointerCapture(t) { - return q(t, this); - } - setPointerCapture(t) { - K(t, this); - } - releaseCapture(t) { - V(t); - } - getLayers() { - return this.children; - } - _bindContentEvents() { - if (a.isBrowser) for (var t = 0; t < J; t++) Z(this, Q[t]); - } - _mouseenter(t) { - this.setPointersPositions(t), - this._fire('mouseenter', { evt: t, target: this, currentTarget: this }); - } - _mouseover(t) { - this.setPointersPositions(t), - this._fire('contentMouseover', { evt: t }), - this._fire('mouseover', { evt: t, target: this, currentTarget: this }); - } - _mouseleave(t) { - var e; - this.setPointersPositions(t); - var i = ( - null === (e = this.targetShape) || void 0 === e - ? void 0 - : e.getStage() - ) - ? this.targetShape - : null, - r = !E.isDragging || a.hitOnDragEnabled; - i && r - ? (i._fireAndBubble('mouseout', { evt: t }), - i._fireAndBubble('mouseleave', { evt: t }), - this._fire('mouseleave', { - evt: t, - target: this, - currentTarget: this, - }), - (this.targetShape = null)) - : r && - (this._fire('mouseleave', { - evt: t, - target: this, - currentTarget: this, - }), - this._fire('mouseout', { - evt: t, - target: this, - currentTarget: this, - })), - (this.pointerPos = void 0), - (this._pointerPositions = []), - this._fire('contentMouseout', { evt: t }); - } - _mousemove(t) { - var e; - if (a.UA.ieMobile) return this._touchmove(t); - this.setPointersPositions(t); - var i = u._getFirstPointerId(t), - r = ( - null === (e = this.targetShape) || void 0 === e - ? void 0 - : e.getStage() - ) - ? this.targetShape - : null, - n = !E.isDragging || a.hitOnDragEnabled; - if (n) { - const e = this.getIntersection(this.getPointerPosition()); - if (e && e.isListening()) - n && r !== e - ? (r && - (r._fireAndBubble('mouseout', { evt: t, pointerId: i }, e), - r._fireAndBubble('mouseleave', { evt: t, pointerId: i }, e)), - e._fireAndBubble('mouseover', { evt: t, pointerId: i }, r), - e._fireAndBubble('mouseenter', { evt: t, pointerId: i }, r), - e._fireAndBubble('mousemove', { evt: t, pointerId: i }), - (this.targetShape = e)) - : e._fireAndBubble('mousemove', { evt: t, pointerId: i }); - else - r && - n && - (r._fireAndBubble('mouseout', { evt: t, pointerId: i }), - r._fireAndBubble('mouseleave', { evt: t, pointerId: i }), - this._fire('mouseover', { - evt: t, - target: this, - currentTarget: this, - pointerId: i, - }), - (this.targetShape = null)), - this._fire('mousemove', { - evt: t, - target: this, - currentTarget: this, - pointerId: i, - }); - this._fire('contentMousemove', { evt: t }); - } - t.cancelable && t.preventDefault(); - } - _mousedown(t) { - if (a.UA.ieMobile) return this._touchstart(t); - this.setPointersPositions(t); - var e = u._getFirstPointerId(t), - i = this.getIntersection(this.getPointerPosition()); - (E.justDragged = !1), - (a.listenClickTap = !0), - i && i.isListening() - ? ((this.clickStartShape = i), - i._fireAndBubble('mousedown', { evt: t, pointerId: e })) - : this._fire('mousedown', { - evt: t, - target: this, - currentTarget: this, - pointerId: e, - }), - this._fire('contentMousedown', { evt: t }); - } - _mouseup(t) { - if (a.UA.ieMobile) return this._touchend(t); - this.setPointersPositions(t); - var e = u._getFirstPointerId(t), - i = this.getIntersection(this.getPointerPosition()), - r = this.clickStartShape, - n = this.clickEndShape, - s = !1; - a.inDblClickWindow - ? ((s = !0), clearTimeout(this.dblTimeout)) - : E.justDragged || - ((a.inDblClickWindow = !0), clearTimeout(this.dblTimeout)), - (this.dblTimeout = setTimeout(function () { - a.inDblClickWindow = !1; - }, a.dblClickWindow)), - i && i.isListening() - ? ((this.clickEndShape = i), - i._fireAndBubble('mouseup', { evt: t, pointerId: e }), - a.listenClickTap && - r && - r._id === i._id && - (i._fireAndBubble('click', { evt: t, pointerId: e }), - s && - n && - n === i && - i._fireAndBubble('dblclick', { evt: t, pointerId: e }))) - : ((this.clickEndShape = null), - this._fire('mouseup', { - evt: t, - target: this, - currentTarget: this, - pointerId: e, - }), - a.listenClickTap && - this._fire('click', { - evt: t, - target: this, - currentTarget: this, - pointerId: e, - }), - s && - this._fire('dblclick', { - evt: t, - target: this, - currentTarget: this, - pointerId: e, - })), - this._fire('contentMouseup', { evt: t }), - a.listenClickTap && - (this._fire('contentClick', { evt: t }), - s && this._fire('contentDblclick', { evt: t })), - (a.listenClickTap = !1), - t.cancelable && t.preventDefault(); - } - _contextmenu(t) { - this.setPointersPositions(t); - var e = this.getIntersection(this.getPointerPosition()); - e && e.isListening() - ? e._fireAndBubble('contextmenu', { evt: t }) - : this._fire('contextmenu', { - evt: t, - target: this, - currentTarget: this, - }), - this._fire('contentContextmenu', { evt: t }); - } - _touchstart(t) { - this.setPointersPositions(t); - var e = !1; - this._changedPointerPositions.forEach((i) => { - var r = this.getIntersection(i); - (a.listenClickTap = !0), (E.justDragged = !1); - r && - r.isListening() && - (a.captureTouchEventsEnabled && r.setPointerCapture(i.id), - (this.tapStartShape = r), - r._fireAndBubble('touchstart', { evt: t, pointerId: i.id }, this), - (e = !0), - r.isListening() && - r.preventDefault() && - t.cancelable && - t.preventDefault()); - }), - e || - this._fire('touchstart', { - evt: t, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }), - this._fire('contentTouchstart', { evt: t }); - } - _touchmove(t) { - if ((this.setPointersPositions(t), !E.isDragging || a.hitOnDragEnabled)) { - var e = !1, - i = {}; - this._changedPointerPositions.forEach((r) => { - const a = j(r.id) || this.getIntersection(r); - a && - a.isListening() && - (i[a._id] || - ((i[a._id] = !0), - a._fireAndBubble('touchmove', { evt: t, pointerId: r.id }), - (e = !0), - a.isListening() && - a.preventDefault() && - t.cancelable && - t.preventDefault())); - }), - e || - this._fire('touchmove', { - evt: t, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }), - this._fire('contentTouchmove', { evt: t }); - } - E.isDragging && - E.node.preventDefault() && - t.cancelable && - t.preventDefault(); - } - _touchend(t) { - this.setPointersPositions(t); - var e = this.tapEndShape, - i = !1; - a.inDblClickWindow - ? ((i = !0), clearTimeout(this.dblTimeout)) - : E.justDragged || - ((a.inDblClickWindow = !0), clearTimeout(this.dblTimeout)), - (this.dblTimeout = setTimeout(function () { - a.inDblClickWindow = !1; - }, a.dblClickWindow)); - var r = !1, - n = {}, - s = !1, - o = !1; - this._changedPointerPositions.forEach((h) => { - var l = j(h.id) || this.getIntersection(h); - l && l.releaseCapture(h.id); - l && - l.isListening() && - (n[l._id] || - ((n[l._id] = !0), - (this.tapEndShape = l), - l._fireAndBubble('touchend', { evt: t, pointerId: h.id }), - (r = !0), - a.listenClickTap && - l === this.tapStartShape && - ((s = !0), - l._fireAndBubble('tap', { evt: t, pointerId: h.id }), - i && - e && - e === l && - ((o = !0), - l._fireAndBubble('dbltap', { evt: t, pointerId: h.id }))), - l.isListening() && - l.preventDefault() && - t.cancelable && - t.preventDefault())); - }), - r || - this._fire('touchend', { - evt: t, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }), - a.listenClickTap && - !s && - ((this.tapEndShape = null), - this._fire('tap', { - evt: t, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - })), - i && - !o && - this._fire('dbltap', { - evt: t, - target: this, - currentTarget: this, - pointerId: this._changedPointerPositions[0].id, - }), - this._fire('contentTouchend', { evt: t }), - a.listenClickTap && - (this._fire('contentTap', { evt: t }), - i && this._fire('contentDbltap', { evt: t })), - this.preventDefault() && t.cancelable && t.preventDefault(), - (a.listenClickTap = !1); - } - _wheel(t) { - this.setPointersPositions(t); - var e = this.getIntersection(this.getPointerPosition()); - e && e.isListening() - ? e._fireAndBubble('wheel', { evt: t }) - : this._fire('wheel', { evt: t, target: this, currentTarget: this }), - this._fire('contentWheel', { evt: t }); - } - _pointerdown(t) { - if (!a._pointerEventsEnabled) return; - this.setPointersPositions(t); - const e = - j(t.pointerId) || this.getIntersection(this.getPointerPosition()); - e && e._fireAndBubble('pointerdown', U(t)); - } - _pointermove(t) { - if (!a._pointerEventsEnabled) return; - this.setPointersPositions(t); - const e = - j(t.pointerId) || this.getIntersection(this.getPointerPosition()); - e && e._fireAndBubble('pointermove', U(t)); - } - _pointerup(t) { - if (!a._pointerEventsEnabled) return; - this.setPointersPositions(t); - const e = - j(t.pointerId) || this.getIntersection(this.getPointerPosition()); - e && e._fireAndBubble('pointerup', U(t)), V(t.pointerId); - } - _pointercancel(t) { - if (!a._pointerEventsEnabled) return; - this.setPointersPositions(t); - const e = - j(t.pointerId) || this.getIntersection(this.getPointerPosition()); - e && e._fireAndBubble('pointerup', U(t)), V(t.pointerId); - } - _lostpointercapture(t) { - V(t.pointerId); - } - setPointersPositions(t) { - var e = this._getContentPosition(), - i = null, - r = null; - void 0 !== (t = t || window.event).touches - ? ((this._pointerPositions = []), - (this._changedPointerPositions = []), - Array.prototype.forEach.call(t.touches, (t) => { - this._pointerPositions.push({ - id: t.identifier, - x: (t.clientX - e.left) / e.scaleX, - y: (t.clientY - e.top) / e.scaleY, - }); - }), - Array.prototype.forEach.call(t.changedTouches || t.touches, (t) => { - this._changedPointerPositions.push({ - id: t.identifier, - x: (t.clientX - e.left) / e.scaleX, - y: (t.clientY - e.top) / e.scaleY, - }); - })) - : ((i = (t.clientX - e.left) / e.scaleX), - (r = (t.clientY - e.top) / e.scaleY), - (this.pointerPos = { x: i, y: r }), - (this._pointerPositions = [ - { x: i, y: r, id: u._getFirstPointerId(t) }, - ]), - (this._changedPointerPositions = [ - { x: i, y: r, id: u._getFirstPointerId(t) }, - ])); - } - _setPointerPosition(t) { - u.warn( - 'Method _setPointerPosition is deprecated. Use "stage.setPointersPositions(event)" instead.' - ), - this.setPointersPositions(t); - } - _getContentPosition() { - if (!this.content || !this.content.getBoundingClientRect) - return { top: 0, left: 0, scaleX: 1, scaleY: 1 }; - var t = this.content.getBoundingClientRect(); - return { - top: t.top, - left: t.left, - scaleX: t.width / this.content.clientWidth || 1, - scaleY: t.height / this.content.clientHeight || 1, - }; - } - _buildDOM() { - if ( - ((this.bufferCanvas = new M({ - width: this.width(), - height: this.height(), - })), - (this.bufferHitCanvas = new G({ - pixelRatio: 1, - width: this.width(), - height: this.height(), - })), - a.isBrowser) - ) { - var t = this.container(); - if (!t) throw 'Stage has no container. A container is required.'; - (t.innerHTML = ''), - (this.content = document.createElement('div')), - (this.content.style.position = 'relative'), - (this.content.style.userSelect = 'none'), - (this.content.className = 'konvajs-content'), - this.content.setAttribute('role', 'presentation'), - t.appendChild(this.content), - this._resizeDOM(); - } - } - cache() { - return ( - u.warn( - 'Cache function is not allowed for stage. You may use cache only for layers, groups and shapes.' - ), - this - ); - } - clearCache() { - return this; - } - batchDraw() { - return ( - this.children.forEach(function (t) { - t.batchDraw(); - }), - this - ); - } - } - (et.prototype.nodeType = 'Stage'), s(et), S.addGetterSetter(et, 'container'); - let it; - function rt() { - return it || ((it = u.createCanvasElement().getContext('2d')), it); - } - const at = {}; - class nt extends z { - constructor(t) { - let e; - for (super(t); (e = u.getRandomColor()), !e || e in at; ); - (this.colorKey = e), (at[e] = this); - } - getContext() { - return this.getLayer().getContext(); - } - getCanvas() { - return this.getLayer().getCanvas(); - } - getSceneFunc() { - return this.attrs.sceneFunc || this._sceneFunc; - } - getHitFunc() { - return this.attrs.hitFunc || this._hitFunc; - } - hasShadow() { - return this._getCache('hasShadow', this._hasShadow); - } - _hasShadow() { - return ( - this.shadowEnabled() && - 0 !== this.shadowOpacity() && - !!( - this.shadowColor() || - this.shadowBlur() || - this.shadowOffsetX() || - this.shadowOffsetY() - ) - ); - } - _getFillPattern() { - return this._getCache('patternImage', this.__getFillPattern); - } - __getFillPattern() { - if (this.fillPatternImage()) { - const t = rt().createPattern( - this.fillPatternImage(), - this.fillPatternRepeat() || 'repeat' - ); - return ( - t && - t.setTransform && - t.setTransform({ - a: this.fillPatternScaleX(), - b: 0, - c: 0, - d: this.fillPatternScaleY(), - e: 0, - f: 0, - }), - t - ); - } - } - _getLinearGradient() { - return this._getCache('linearGradient', this.__getLinearGradient); - } - __getLinearGradient() { - var t = this.fillLinearGradientColorStops(); - if (t) { - for ( - var e = rt(), - i = this.fillLinearGradientStartPoint(), - r = this.fillLinearGradientEndPoint(), - a = e.createLinearGradient(i.x, i.y, r.x, r.y), - n = 0; - n < t.length; - n += 2 - ) - a.addColorStop(t[n], t[n + 1]); - return a; - } - } - _getRadialGradient() { - return this._getCache('radialGradient', this.__getRadialGradient); - } - __getRadialGradient() { - var t = this.fillRadialGradientColorStops(); - if (t) { - for ( - var e = rt(), - i = this.fillRadialGradientStartPoint(), - r = this.fillRadialGradientEndPoint(), - a = e.createRadialGradient( - i.x, - i.y, - this.fillRadialGradientStartRadius(), - r.x, - r.y, - this.fillRadialGradientEndRadius() - ), - n = 0; - n < t.length; - n += 2 - ) - a.addColorStop(t[n], t[n + 1]); - return a; - } - } - getShadowRGBA() { - return this._getCache('shadowRGBA', this._getShadowRGBA); - } - _getShadowRGBA() { - if (this.hasShadow()) { - var t = u.colorToRGBA(this.shadowColor()); - return ( - 'rgba(' + - t.r + - ',' + - t.g + - ',' + - t.b + - ',' + - t.a * (this.shadowOpacity() || 1) + - ')' - ); - } - } - hasFill() { - return this._calculate( - 'hasFill', - [ - 'fillEnabled', - 'fill', - 'fillPatternImage', - 'fillLinearGradientColorStops', - 'fillRadialGradientColorStops', - ], - () => - this.fillEnabled() && - !!( - this.fill() || - this.fillPatternImage() || - this.fillLinearGradientColorStops() || - this.fillRadialGradientColorStops() - ) - ); - } - hasStroke() { - return this._calculate( - 'hasStroke', - [ - 'strokeEnabled', - 'strokeWidth', - 'stroke', - 'strokeLinearGradientColorStops', - ], - () => - this.strokeEnabled() && - this.strokeWidth() && - !(!this.stroke() && !this.strokeLinearGradientColorStops()) - ); - } - hasHitStroke() { - const t = this.hitStrokeWidth(); - return 'auto' === t ? this.hasStroke() : this.strokeEnabled() && !!t; - } - intersects(t) { - var e = this.getStage().bufferHitCanvas; - return ( - e.getContext().clear(), - this.drawHit(e, null, !0), - e.context.getImageData(Math.round(t.x), Math.round(t.y), 1, 1).data[3] > - 0 - ); - } - destroy() { - return ( - z.prototype.destroy.call(this), - delete at[this.colorKey], - delete this.colorKey, - this - ); - } - _useBufferCanvas(t) { - var e; - if (!this.getStage()) return !1; - if (!(null === (e = this.attrs.perfectDrawEnabled) || void 0 === e || e)) - return !1; - const i = t || this.hasFill(), - r = this.hasStroke(), - a = 1 !== this.getAbsoluteOpacity(); - if (i && r && a) return !0; - const n = this.hasShadow(), - s = this.shadowForStrokeEnabled(); - return !!(i && r && n && s); - } - setStrokeHitEnabled(t) { - u.warn( - 'strokeHitEnabled property is deprecated. Please use hitStrokeWidth instead.' - ), - t ? this.hitStrokeWidth('auto') : this.hitStrokeWidth(0); - } - getStrokeHitEnabled() { - return 0 !== this.hitStrokeWidth(); - } - getSelfRect() { - var t = this.size(); - return { - x: this._centroid ? -t.width / 2 : 0, - y: this._centroid ? -t.height / 2 : 0, - width: t.width, - height: t.height, - }; - } - getClientRect(t = {}) { - const e = t.skipTransform, - i = t.relativeTo, - r = this.getSelfRect(), - a = (!t.skipStroke && this.hasStroke() && this.strokeWidth()) || 0, - n = r.width + a, - s = r.height + a, - o = !t.skipShadow && this.hasShadow(), - h = o ? this.shadowOffsetX() : 0, - l = o ? this.shadowOffsetY() : 0, - d = n + Math.abs(h), - c = s + Math.abs(l), - g = (o && this.shadowBlur()) || 0, - u = d + 2 * g, - f = c + 2 * g; - let p = 0; - Math.round(a / 2) !== a / 2 && (p = 1); - const v = { - width: u + p, - height: f + p, - x: -Math.round(a / 2 + g) + Math.min(h, 0) + r.x, - y: -Math.round(a / 2 + g) + Math.min(l, 0) + r.y, - }; - return e ? v : this._transformedRect(v, i); - } - drawScene(t, e) { - var i, - r, - a = this.getLayer(), - n = t || a.getCanvas(), - s = n.getContext(), - o = this._getCanvasCache(), - h = this.getSceneFunc(), - l = this.hasShadow(), - d = n.isCache, - c = n.isCache, - g = e === this; - if (!this.isVisible() && !d) return this; - if (o) { - s.save(); - var u = this.getAbsoluteTransform(e).getMatrix(); - return ( - s.transform(u[0], u[1], u[2], u[3], u[4], u[5]), - this._drawCachedSceneCanvas(s), - s.restore(), - this - ); - } - if (!h) return this; - if ((s.save(), this._useBufferCanvas() && !c)) { - (r = (i = this.getStage().bufferCanvas).getContext()).clear(), - r.save(), - r._applyLineJoin(this); - var f = this.getAbsoluteTransform(e).getMatrix(); - r.transform(f[0], f[1], f[2], f[3], f[4], f[5]), - h.call(this, r, this), - r.restore(); - var p = i.pixelRatio; - l && s._applyShadow(this), - s._applyOpacity(this), - s._applyGlobalCompositeOperation(this), - s.drawImage(i._canvas, 0, 0, i.width / p, i.height / p); - } else { - if ((s._applyLineJoin(this), !g)) { - f = this.getAbsoluteTransform(e).getMatrix(); - s.transform(f[0], f[1], f[2], f[3], f[4], f[5]), - s._applyOpacity(this), - s._applyGlobalCompositeOperation(this); - } - l && s._applyShadow(this), h.call(this, s, this); - } - return s.restore(), this; - } - drawHit(t, e, i = !1) { - if (!this.shouldDrawHit(e, i)) return this; - var r = this.getLayer(), - a = t || r.hitCanvas, - n = a && a.getContext(), - s = this.hitFunc() || this.sceneFunc(), - o = this._getCanvasCache(), - h = o && o.hit; - if ( - (this.colorKey || - u.warn( - 'Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. If you want to reuse shape you should call remove() instead of destroy()' - ), - h) - ) { - n.save(); - var l = this.getAbsoluteTransform(e).getMatrix(); - return ( - n.transform(l[0], l[1], l[2], l[3], l[4], l[5]), - this._drawCachedHitCanvas(n), - n.restore(), - this - ); - } - if (!s) return this; - n.save(), n._applyLineJoin(this); - if (!(this === e)) { - var d = this.getAbsoluteTransform(e).getMatrix(); - n.transform(d[0], d[1], d[2], d[3], d[4], d[5]); - } - return s.call(this, n, this), n.restore(), this; - } - drawHitFromCache(t = 0) { - var e, - i, - r, - a, - n, - s = this._getCanvasCache(), - o = this._getCachedSceneCanvas(), - h = s.hit, - l = h.getContext(), - d = h.getWidth(), - c = h.getHeight(); - l.clear(), l.drawImage(o._canvas, 0, 0, d, c); - try { - for ( - r = (i = (e = l.getImageData(0, 0, d, c)).data).length, - a = u._hexToRgb(this.colorKey), - n = 0; - n < r; - n += 4 - ) - i[n + 3] > t - ? ((i[n] = a.r), - (i[n + 1] = a.g), - (i[n + 2] = a.b), - (i[n + 3] = 255)) - : (i[n + 3] = 0); - l.putImageData(e, 0, 0); - } catch (t) { - u.error( - 'Unable to draw hit graph from cached scene canvas. ' + t.message - ); - } - return this; - } - hasPointerCapture(t) { - return q(t, this); - } - setPointerCapture(t) { - K(t, this); - } - releaseCapture(t) { - V(t); - } - } - (nt.prototype._fillFunc = function (t) { - t.fill(); - }), - (nt.prototype._strokeFunc = function (t) { - t.stroke(); - }), - (nt.prototype._fillFuncHit = function (t) { - t.fill(); - }), - (nt.prototype._strokeFuncHit = function (t) { - t.stroke(); - }), - (nt.prototype._centroid = !1), - (nt.prototype.nodeType = 'Shape'), - s(nt), - (nt.prototype.eventListeners = {}), - nt.prototype.on.call( - nt.prototype, - 'shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', - function () { - this._clearCache('hasShadow'); - } - ), - nt.prototype.on.call( - nt.prototype, - 'shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', - function () { - this._clearCache('shadowRGBA'); - } - ), - nt.prototype.on.call( - nt.prototype, - 'fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva fillPatternScaleXChange.konva fillPatternScaleYChange.konva', - function () { - this._clearCache('patternImage'); - } - ), - nt.prototype.on.call( - nt.prototype, - 'fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva', - function () { - this._clearCache('linearGradient'); - } - ), - nt.prototype.on.call( - nt.prototype, - 'fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva', - function () { - this._clearCache('radialGradient'); - } - ), - S.addGetterSetter(nt, 'stroke', void 0, x()), - S.addGetterSetter(nt, 'strokeWidth', 2, v()), - S.addGetterSetter(nt, 'fillAfterStrokeEnabled', !1), - S.addGetterSetter(nt, 'hitStrokeWidth', 'auto', _()), - S.addGetterSetter(nt, 'strokeHitEnabled', !0, b()), - S.addGetterSetter(nt, 'perfectDrawEnabled', !0, b()), - S.addGetterSetter(nt, 'shadowForStrokeEnabled', !0, b()), - S.addGetterSetter(nt, 'lineJoin'), - S.addGetterSetter(nt, 'lineCap'), - S.addGetterSetter(nt, 'sceneFunc'), - S.addGetterSetter(nt, 'hitFunc'), - S.addGetterSetter(nt, 'dash'), - S.addGetterSetter(nt, 'dashOffset', 0, v()), - S.addGetterSetter(nt, 'shadowColor', void 0, y()), - S.addGetterSetter(nt, 'shadowBlur', 0, v()), - S.addGetterSetter(nt, 'shadowOpacity', 1, v()), - S.addComponentsGetterSetter(nt, 'shadowOffset', ['x', 'y']), - S.addGetterSetter(nt, 'shadowOffsetX', 0, v()), - S.addGetterSetter(nt, 'shadowOffsetY', 0, v()), - S.addGetterSetter(nt, 'fillPatternImage'), - S.addGetterSetter(nt, 'fill', void 0, x()), - S.addGetterSetter(nt, 'fillPatternX', 0, v()), - S.addGetterSetter(nt, 'fillPatternY', 0, v()), - S.addGetterSetter(nt, 'fillLinearGradientColorStops'), - S.addGetterSetter(nt, 'strokeLinearGradientColorStops'), - S.addGetterSetter(nt, 'fillRadialGradientStartRadius', 0), - S.addGetterSetter(nt, 'fillRadialGradientEndRadius', 0), - S.addGetterSetter(nt, 'fillRadialGradientColorStops'), - S.addGetterSetter(nt, 'fillPatternRepeat', 'repeat'), - S.addGetterSetter(nt, 'fillEnabled', !0), - S.addGetterSetter(nt, 'strokeEnabled', !0), - S.addGetterSetter(nt, 'shadowEnabled', !0), - S.addGetterSetter(nt, 'dashEnabled', !0), - S.addGetterSetter(nt, 'strokeScaleEnabled', !0), - S.addGetterSetter(nt, 'fillPriority', 'color'), - S.addComponentsGetterSetter(nt, 'fillPatternOffset', ['x', 'y']), - S.addGetterSetter(nt, 'fillPatternOffsetX', 0, v()), - S.addGetterSetter(nt, 'fillPatternOffsetY', 0, v()), - S.addComponentsGetterSetter(nt, 'fillPatternScale', ['x', 'y']), - S.addGetterSetter(nt, 'fillPatternScaleX', 1, v()), - S.addGetterSetter(nt, 'fillPatternScaleY', 1, v()), - S.addComponentsGetterSetter(nt, 'fillLinearGradientStartPoint', ['x', 'y']), - S.addComponentsGetterSetter(nt, 'strokeLinearGradientStartPoint', [ - 'x', - 'y', - ]), - S.addGetterSetter(nt, 'fillLinearGradientStartPointX', 0), - S.addGetterSetter(nt, 'strokeLinearGradientStartPointX', 0), - S.addGetterSetter(nt, 'fillLinearGradientStartPointY', 0), - S.addGetterSetter(nt, 'strokeLinearGradientStartPointY', 0), - S.addComponentsGetterSetter(nt, 'fillLinearGradientEndPoint', ['x', 'y']), - S.addComponentsGetterSetter(nt, 'strokeLinearGradientEndPoint', ['x', 'y']), - S.addGetterSetter(nt, 'fillLinearGradientEndPointX', 0), - S.addGetterSetter(nt, 'strokeLinearGradientEndPointX', 0), - S.addGetterSetter(nt, 'fillLinearGradientEndPointY', 0), - S.addGetterSetter(nt, 'strokeLinearGradientEndPointY', 0), - S.addComponentsGetterSetter(nt, 'fillRadialGradientStartPoint', ['x', 'y']), - S.addGetterSetter(nt, 'fillRadialGradientStartPointX', 0), - S.addGetterSetter(nt, 'fillRadialGradientStartPointY', 0), - S.addComponentsGetterSetter(nt, 'fillRadialGradientEndPoint', ['x', 'y']), - S.addGetterSetter(nt, 'fillRadialGradientEndPointX', 0), - S.addGetterSetter(nt, 'fillRadialGradientEndPointY', 0), - S.addGetterSetter(nt, 'fillPatternRotation', 0), - S.backCompat(nt, { - dashArray: 'dash', - getDashArray: 'getDash', - setDashArray: 'getDash', - drawFunc: 'sceneFunc', - getDrawFunc: 'getSceneFunc', - setDrawFunc: 'setSceneFunc', - drawHitFunc: 'hitFunc', - getDrawHitFunc: 'getHitFunc', - setDrawHitFunc: 'setHitFunc', - }); - var st = [ - { x: 0, y: 0 }, - { x: -1, y: -1 }, - { x: 1, y: -1 }, - { x: 1, y: 1 }, - { x: -1, y: 1 }, - ], - ot = st.length; - class ht extends H { - constructor(t) { - super(t), - (this.canvas = new M()), - (this.hitCanvas = new G({ pixelRatio: 1 })), - (this._waitingForDraw = !1), - this.on('visibleChange.konva', this._checkVisibility), - this._checkVisibility(), - this.on('imageSmoothingEnabledChange.konva', this._setSmoothEnabled), - this._setSmoothEnabled(); - } - createPNGStream() { - return this.canvas._canvas.createPNGStream(); - } - getCanvas() { - return this.canvas; - } - getNativeCanvasElement() { - return this.canvas._canvas; - } - getHitCanvas() { - return this.hitCanvas; - } - getContext() { - return this.getCanvas().getContext(); - } - clear(t) { - return ( - this.getContext().clear(t), - this.getHitCanvas().getContext().clear(t), - this - ); - } - setZIndex(t) { - super.setZIndex(t); - var e = this.getStage(); - return ( - e && - (e.content.removeChild(this.getCanvas()._canvas), - t < e.children.length - 1 - ? e.content.insertBefore( - this.getCanvas()._canvas, - e.children[t + 1].getCanvas()._canvas - ) - : e.content.appendChild(this.getCanvas()._canvas)), - this - ); - } - moveToTop() { - z.prototype.moveToTop.call(this); - var t = this.getStage(); - return ( - t && - (t.content.removeChild(this.getCanvas()._canvas), - t.content.appendChild(this.getCanvas()._canvas)), - !0 - ); - } - moveUp() { - if (!z.prototype.moveUp.call(this)) return !1; - var t = this.getStage(); - return ( - !!t && - (t.content.removeChild(this.getCanvas()._canvas), - this.index < t.children.length - 1 - ? t.content.insertBefore( - this.getCanvas()._canvas, - t.children[this.index + 1].getCanvas()._canvas - ) - : t.content.appendChild(this.getCanvas()._canvas), - !0) - ); - } - moveDown() { - if (z.prototype.moveDown.call(this)) { - var t = this.getStage(); - if (t) { - var e = t.children; - t.content.removeChild(this.getCanvas()._canvas), - t.content.insertBefore( - this.getCanvas()._canvas, - e[this.index + 1].getCanvas()._canvas - ); - } - return !0; - } - return !1; - } - moveToBottom() { - if (z.prototype.moveToBottom.call(this)) { - var t = this.getStage(); - if (t) { - var e = t.children; - t.content.removeChild(this.getCanvas()._canvas), - t.content.insertBefore( - this.getCanvas()._canvas, - e[1].getCanvas()._canvas - ); - } - return !0; - } - return !1; - } - getLayer() { - return this; - } - remove() { - var t = this.getCanvas()._canvas; - return ( - z.prototype.remove.call(this), - t && t.parentNode && u._isInDocument(t) && t.parentNode.removeChild(t), - this - ); - } - getStage() { - return this.parent; - } - setSize({ width: t, height: e }) { - return ( - this.canvas.setSize(t, e), - this.hitCanvas.setSize(t, e), - this._setSmoothEnabled(), - this - ); - } - _validateAdd(t) { - var e = t.getType(); - 'Group' !== e && - 'Shape' !== e && - u.throw('You may only add groups and shapes to a layer.'); - } - _toKonvaCanvas(t) { - return ( - ((t = t || {}).width = t.width || this.getWidth()), - (t.height = t.height || this.getHeight()), - (t.x = void 0 !== t.x ? t.x : this.x()), - (t.y = void 0 !== t.y ? t.y : this.y()), - z.prototype._toKonvaCanvas.call(this, t) - ); - } - _checkVisibility() { - const t = this.visible(); - this.canvas._canvas.style.display = t ? 'block' : 'none'; - } - _setSmoothEnabled() { - this.getContext()._context.imageSmoothingEnabled = this.imageSmoothingEnabled(); - } - getWidth() { - if (this.parent) return this.parent.width(); - } - setWidth() { - u.warn( - 'Can not change width of layer. Use "stage.width(value)" function instead.' - ); - } - getHeight() { - if (this.parent) return this.parent.height(); - } - setHeight() { - u.warn( - 'Can not change height of layer. Use "stage.height(value)" function instead.' - ); - } - batchDraw() { - return ( - this._waitingForDraw || - ((this._waitingForDraw = !0), - u.requestAnimFrame(() => { - this.draw(), (this._waitingForDraw = !1); - })), - this - ); - } - getIntersection(t, e) { - if (!this.isListening() || !this.isVisible()) return null; - for (var i = 1, r = !1; ; ) { - for (let a = 0; a < ot; a++) { - const n = st[a], - s = this._getIntersection({ x: t.x + n.x * i, y: t.y + n.y * i }), - o = s.shape; - if (o && e) return o.findAncestor(e, !0); - if (o) return o; - if (((r = !!s.antialiased), !s.antialiased)) break; - } - if (!r) return null; - i += 1; - } - } - _getIntersection(t) { - const e = this.hitCanvas.pixelRatio, - i = this.hitCanvas.context.getImageData( - Math.round(t.x * e), - Math.round(t.y * e), - 1, - 1 - ).data, - r = i[3]; - if (255 === r) { - const t = u._rgbToHex(i[0], i[1], i[2]), - e = at['#' + t]; - return e ? { shape: e } : { antialiased: !0 }; - } - return r > 0 ? { antialiased: !0 } : {}; - } - drawScene(t, e) { - var i = this.getLayer(), - r = t || (i && i.getCanvas()); - return ( - this._fire('beforeDraw', { node: this }), - this.clearBeforeDraw() && r.getContext().clear(), - H.prototype.drawScene.call(this, r, e), - this._fire('draw', { node: this }), - this - ); - } - drawHit(t, e) { - var i = this.getLayer(), - r = t || (i && i.hitCanvas); - return ( - i && i.clearBeforeDraw() && i.getHitCanvas().getContext().clear(), - H.prototype.drawHit.call(this, r, e), - this - ); - } - enableHitGraph() { - return this.hitGraphEnabled(!0), this; - } - disableHitGraph() { - return this.hitGraphEnabled(!1), this; - } - setHitGraphEnabled(t) { - u.warn( - 'hitGraphEnabled method is deprecated. Please use layer.listening() instead.' - ), - this.listening(t); - } - getHitGraphEnabled(t) { - return ( - u.warn( - 'hitGraphEnabled method is deprecated. Please use layer.listening() instead.' - ), - this.listening() - ); - } - toggleHitCanvas() { - if (this.parent) { - var t = this.parent; - !!this.hitCanvas._canvas.parentNode - ? t.content.removeChild(this.hitCanvas._canvas) - : t.content.appendChild(this.hitCanvas._canvas); - } - } - } - (ht.prototype.nodeType = 'Layer'), - s(ht), - S.addGetterSetter(ht, 'imageSmoothingEnabled', !0), - S.addGetterSetter(ht, 'clearBeforeDraw', !0), - S.addGetterSetter(ht, 'hitGraphEnabled', !0, b()); - class lt extends ht { - constructor(t) { - super(t), - this.listening(!1), - u.warn( - 'Konva.Fast layer is deprecated. Please use "new Konva.Layer({ listening: false })" instead.' - ); - } - } - (lt.prototype.nodeType = 'FastLayer'), s(lt); - class dt extends H { - _validateAdd(t) { - var e = t.getType(); - 'Group' !== e && - 'Shape' !== e && - u.throw('You may only add groups and shapes to groups.'); - } - } - (dt.prototype.nodeType = 'Group'), s(dt); - var ct = - r.performance && r.performance.now - ? function () { - return r.performance.now(); - } - : function () { - return new Date().getTime(); - }; - class gt { - constructor(t, e) { - (this.id = gt.animIdCounter++), - (this.frame = { time: 0, timeDiff: 0, lastTime: ct(), frameRate: 0 }), - (this.func = t), - this.setLayers(e); - } - setLayers(t) { - var e = []; - return (e = t ? (t.length > 0 ? t : [t]) : []), (this.layers = e), this; - } - getLayers() { - return this.layers; - } - addLayer(t) { - var e, - i = this.layers, - r = i.length; - for (e = 0; e < r; e++) if (i[e]._id === t._id) return !1; - return this.layers.push(t), !0; - } - isRunning() { - var t, - e = gt.animations, - i = e.length; - for (t = 0; t < i; t++) if (e[t].id === this.id) return !0; - return !1; - } - start() { - return ( - this.stop(), - (this.frame.timeDiff = 0), - (this.frame.lastTime = ct()), - gt._addAnimation(this), - this - ); - } - stop() { - return gt._removeAnimation(this), this; - } - _updateFrameObject(t) { - (this.frame.timeDiff = t - this.frame.lastTime), - (this.frame.lastTime = t), - (this.frame.time += this.frame.timeDiff), - (this.frame.frameRate = 1e3 / this.frame.timeDiff); - } - static _addAnimation(t) { - this.animations.push(t), this._handleAnimation(); - } - static _removeAnimation(t) { - var e, - i = t.id, - r = this.animations, - a = r.length; - for (e = 0; e < a; e++) - if (r[e].id === i) { - this.animations.splice(e, 1); - break; - } - } - static _runFrames() { - var t, - e, - i, - r, - a, - n, - s, - o, - h = {}, - l = this.animations; - for (r = 0; r < l.length; r++) - if ( - ((e = (t = l[r]).layers), - (i = t.func), - t._updateFrameObject(ct()), - (n = e.length), - !i || !1 !== i.call(t, t.frame)) - ) - for (a = 0; a < n; a++) void 0 !== (s = e[a])._id && (h[s._id] = s); - for (o in h) h.hasOwnProperty(o) && h[o].draw(); - } - static _animationLoop() { - var t = gt; - t.animations.length - ? (t._runFrames(), u.requestAnimFrame(t._animationLoop)) - : (t.animRunning = !1); - } - static _handleAnimation() { - this.animRunning || - ((this.animRunning = !0), u.requestAnimFrame(this._animationLoop)); - } - } - (gt.animations = []), (gt.animIdCounter = 0), (gt.animRunning = !1); - var ut = { node: 1, duration: 1, easing: 1, onFinish: 1, yoyo: 1 }, - ft = 0, - pt = ['fill', 'stroke', 'shadowColor']; - class vt { - constructor(t, e, i, r, a, n, s) { - (this.prop = t), - (this.propFunc = e), - (this.begin = r), - (this._pos = r), - (this.duration = n), - (this._change = 0), - (this.prevPos = 0), - (this.yoyo = s), - (this._time = 0), - (this._position = 0), - (this._startTime = 0), - (this._finish = 0), - (this.func = i), - (this._change = a - this.begin), - this.pause(); - } - fire(t) { - var e = this[t]; - e && e(); - } - setTime(t) { - t > this.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()); - } - getTime() { - return this._time; - } - setPosition(t) { - (this.prevPos = this._pos), this.propFunc(t), (this._pos = t); - } - getPosition(t) { - return ( - void 0 === t && (t = this._time), - this.func(t, this.begin, this._change, this.duration) - ); - } - play() { - (this.state = 2), - (this._startTime = this.getTimer() - this._time), - this.onEnterFrame(), - this.fire('onPlay'); - } - reverse() { - (this.state = 3), - (this._time = this.duration - this._time), - (this._startTime = this.getTimer() - this._time), - this.onEnterFrame(), - this.fire('onReverse'); - } - seek(t) { - this.pause(), (this._time = t), this.update(), this.fire('onSeek'); - } - reset() { - this.pause(), (this._time = 0), this.update(), this.fire('onReset'); - } - finish() { - this.pause(), - (this._time = this.duration), - this.update(), - this.fire('onFinish'); - } - update() { - this.setPosition(this.getPosition(this._time)), this.fire('onUpdate'); - } - onEnterFrame() { - var t = this.getTimer() - this._startTime; - 2 === this.state - ? this.setTime(t) - : 3 === this.state && this.setTime(this.duration - t); - } - pause() { - (this.state = 1), this.fire('onPause'); - } - getTimer() { - return new Date().getTime(); - } - } - class mt { - constructor(t) { - var e, - i, - r = this, - n = t.node, - s = n._id, - o = t.easing || _t.Linear, - h = !!t.yoyo; - (e = void 0 === t.duration ? 0.3 : 0 === t.duration ? 0.001 : t.duration), - (this.node = n), - (this._id = ft++); - var l = n.getLayer() || (n instanceof a.Stage ? n.getLayers() : null); - for (i in (l || - u.error( - 'Tween constructor have `node` that is not in a layer. Please add node into layer first.' - ), - (this.anim = new gt(function () { - r.tween.onEnterFrame(); - }, l)), - (this.tween = new vt( - i, - function (t) { - r._tweenFunc(t); - }, - o, - 0, - 1, - 1e3 * e, - h - )), - this._addListeners(), - mt.attrs[s] || (mt.attrs[s] = {}), - mt.attrs[s][this._id] || (mt.attrs[s][this._id] = {}), - mt.tweens[s] || (mt.tweens[s] = {}), - t)) - void 0 === ut[i] && this._addAttr(i, t[i]); - this.reset(), - (this.onFinish = t.onFinish), - (this.onReset = t.onReset), - (this.onUpdate = t.onUpdate); - } - _addAttr(t, e) { - var i, - r, - a, - n, - s, - o, - h, - l, - d = this.node, - c = d._id; - if ( - ((a = mt.tweens[c][t]) && delete mt.attrs[c][a][t], - (i = d.getAttr(t)), - u._isArray(e)) - ) - if ( - ((r = []), - (s = Math.max(e.length, i.length)), - 'points' === t && - e.length !== i.length && - (e.length > i.length - ? ((h = i), (i = u._prepareArrayForTween(i, e, d.closed()))) - : ((o = e), (e = u._prepareArrayForTween(e, i, d.closed())))), - 0 === t.indexOf('fill')) - ) - for (n = 0; n < s; n++) - if (n % 2 == 0) r.push(e[n] - i[n]); - else { - var g = u.colorToRGBA(i[n]); - (l = u.colorToRGBA(e[n])), - (i[n] = g), - r.push({ - r: l.r - g.r, - g: l.g - g.g, - b: l.b - g.b, - a: l.a - g.a, - }); - } - else for (n = 0; n < s; n++) r.push(e[n] - i[n]); - else - -1 !== pt.indexOf(t) - ? ((i = u.colorToRGBA(i)), - (r = { - r: (l = u.colorToRGBA(e)).r - i.r, - g: l.g - i.g, - b: l.b - i.b, - a: l.a - i.a, - })) - : (r = e - i); - (mt.attrs[c][this._id][t] = { - start: i, - diff: r, - end: e, - trueEnd: o, - trueStart: h, - }), - (mt.tweens[c][t] = this._id); - } - _tweenFunc(t) { - var e, - i, - r, - a, - n, - s, - o, - h, - l = this.node, - d = mt.attrs[l._id][this._id]; - for (e in d) { - if (((r = (i = d[e]).start), (a = i.diff), (h = i.end), u._isArray(r))) - if ( - ((n = []), - (o = Math.max(r.length, h.length)), - 0 === e.indexOf('fill')) - ) - for (s = 0; s < o; s++) - s % 2 == 0 - ? n.push((r[s] || 0) + a[s] * t) - : n.push( - 'rgba(' + - Math.round(r[s].r + a[s].r * t) + - ',' + - Math.round(r[s].g + a[s].g * t) + - ',' + - Math.round(r[s].b + a[s].b * t) + - ',' + - (r[s].a + a[s].a * t) + - ')' - ); - else for (s = 0; s < o; s++) n.push((r[s] || 0) + a[s] * t); - else - n = - -1 !== pt.indexOf(e) - ? 'rgba(' + - Math.round(r.r + a.r * t) + - ',' + - Math.round(r.g + a.g * t) + - ',' + - Math.round(r.b + a.b * t) + - ',' + - (r.a + a.a * t) + - ')' - : r + a * t; - l.setAttr(e, n); - } - } - _addListeners() { - (this.tween.onPlay = () => { - this.anim.start(); - }), - (this.tween.onReverse = () => { - this.anim.start(); - }), - (this.tween.onPause = () => { - this.anim.stop(); - }), - (this.tween.onFinish = () => { - var t = this.node, - e = mt.attrs[t._id][this._id]; - e.points && e.points.trueEnd && t.setAttr('points', e.points.trueEnd), - this.onFinish && this.onFinish.call(this); - }), - (this.tween.onReset = () => { - var t = this.node, - e = mt.attrs[t._id][this._id]; - e.points && e.points.trueStart && t.points(e.points.trueStart), - this.onReset && this.onReset(); - }), - (this.tween.onUpdate = () => { - this.onUpdate && this.onUpdate.call(this); - }); - } - play() { - return this.tween.play(), this; - } - reverse() { - return this.tween.reverse(), this; - } - reset() { - return this.tween.reset(), this; - } - seek(t) { - return this.tween.seek(1e3 * t), this; - } - pause() { - return this.tween.pause(), this; - } - finish() { - return this.tween.finish(), this; - } - destroy() { - var t, - e = this.node._id, - i = this._id, - r = mt.tweens[e]; - for (t in (this.pause(), r)) delete mt.tweens[e][t]; - delete mt.attrs[e][i]; - } - } - (mt.attrs = {}), - (mt.tweens = {}), - (z.prototype.to = function (t) { - var e = t.onFinish; - (t.node = this), - (t.onFinish = function () { - this.destroy(), e && e(); - }), - new mt(t).play(); - }); - const _t = { - BackEaseIn(t, e, i, r) { - var a = 1.70158; - return i * (t /= r) * t * ((a + 1) * t - a) + e; - }, - BackEaseOut(t, e, i, r) { - var a = 1.70158; - return i * ((t = t / r - 1) * t * ((a + 1) * t + a) + 1) + e; - }, - BackEaseInOut(t, e, i, r) { - var a = 1.70158; - return (t /= r / 2) < 1 - ? (i / 2) * (t * t * ((1 + (a *= 1.525)) * t - a)) + e - : (i / 2) * ((t -= 2) * t * ((1 + (a *= 1.525)) * t + a) + 2) + e; - }, - ElasticEaseIn(t, e, i, r, a, n) { - var s = 0; - return 0 === t - ? e - : 1 == (t /= r) - ? e + i - : (n || (n = 0.3 * r), - !a || a < Math.abs(i) - ? ((a = i), (s = n / 4)) - : (s = (n / (2 * Math.PI)) * Math.asin(i / a)), - -a * - Math.pow(2, 10 * (t -= 1)) * - Math.sin(((t * r - s) * (2 * Math.PI)) / n) + - e); - }, - ElasticEaseOut(t, e, i, r, a, n) { - var s = 0; - return 0 === t - ? e - : 1 == (t /= r) - ? e + i - : (n || (n = 0.3 * r), - !a || a < Math.abs(i) - ? ((a = i), (s = n / 4)) - : (s = (n / (2 * Math.PI)) * Math.asin(i / a)), - a * - Math.pow(2, -10 * t) * - Math.sin(((t * r - s) * (2 * Math.PI)) / n) + - i + - e); - }, - ElasticEaseInOut(t, e, i, r, a, n) { - var s = 0; - return 0 === t - ? e - : 2 == (t /= r / 2) - ? e + i - : (n || (n = r * (0.3 * 1.5)), - !a || a < Math.abs(i) - ? ((a = i), (s = n / 4)) - : (s = (n / (2 * Math.PI)) * Math.asin(i / a)), - t < 1 - ? a * - Math.pow(2, 10 * (t -= 1)) * - Math.sin(((t * r - s) * (2 * Math.PI)) / n) * - -0.5 + - e - : a * - Math.pow(2, -10 * (t -= 1)) * - Math.sin(((t * r - s) * (2 * Math.PI)) / n) * - 0.5 + - i + - e); - }, - BounceEaseOut: (t, e, i, r) => - (t /= r) < 1 / 2.75 - ? i * (7.5625 * t * t) + e - : t < 2 / 2.75 - ? i * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + e - : t < 2.5 / 2.75 - ? i * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + e - : i * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + e, - BounceEaseIn: (t, e, i, r) => i - _t.BounceEaseOut(r - t, 0, i, r) + e, - BounceEaseInOut: (t, e, i, r) => - t < r / 2 - ? 0.5 * _t.BounceEaseIn(2 * t, 0, i, r) + e - : 0.5 * _t.BounceEaseOut(2 * t - r, 0, i, r) + 0.5 * i + e, - EaseIn: (t, e, i, r) => i * (t /= r) * t + e, - EaseOut: (t, e, i, r) => -i * (t /= r) * (t - 2) + e, - EaseInOut: (t, e, i, r) => - (t /= r / 2) < 1 - ? (i / 2) * t * t + e - : (-i / 2) * (--t * (t - 2) - 1) + e, - StrongEaseIn: (t, e, i, r) => i * (t /= r) * t * t * t * t + e, - StrongEaseOut: (t, e, i, r) => - i * ((t = t / r - 1) * t * t * t * t + 1) + e, - StrongEaseInOut: (t, e, i, r) => - (t /= r / 2) < 1 - ? (i / 2) * t * t * t * t * t + e - : (i / 2) * ((t -= 2) * t * t * t * t + 2) + e, - Linear: (t, e, i, r) => (i * t) / r + e, - }, - yt = u._assign(a, { - Util: u, - Transform: o, - Node: z, - ids: R, - names: L, - Container: H, - Stage: et, - stages: $, - Layer: ht, - FastLayer: lt, - Group: dt, - DD: E, - Shape: nt, - shapes: at, - Animation: gt, - Tween: mt, - Easings: _t, - Context: C, - Canvas: A, - }); - class xt extends nt { - _sceneFunc(t) { - var e = a.getAngle(this.angle()), - i = this.clockwise(); - t.beginPath(), - t.arc(0, 0, this.outerRadius(), 0, e, i), - t.arc(0, 0, this.innerRadius(), e, 0, !i), - t.closePath(), - t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.outerRadius(); - } - getHeight() { - return 2 * this.outerRadius(); - } - setWidth(t) { - this.outerRadius(t / 2); - } - setHeight(t) { - this.outerRadius(t / 2); - } - } - (xt.prototype._centroid = !0), - (xt.prototype.className = 'Arc'), - (xt.prototype._attrsAffectingSize = ['innerRadius', 'outerRadius']), - s(xt), - S.addGetterSetter(xt, 'innerRadius', 0, v()), - S.addGetterSetter(xt, 'outerRadius', 0, v()), - S.addGetterSetter(xt, 'angle', 0, v()), - S.addGetterSetter(xt, 'clockwise', !1, b()); - class bt extends nt { - constructor(t) { - super(t), - this.on( - 'pointsChange.konva tensionChange.konva closedChange.konva bezierChange.konva', - function () { - this._clearCache('tensionPoints'); - } - ); - } - _sceneFunc(t) { - var e, - i, - r, - a = this.points(), - n = a.length, - s = this.tension(), - o = this.closed(), - h = this.bezier(); - if (n) { - if ((t.beginPath(), t.moveTo(a[0], a[1]), 0 !== s && n > 4)) { - for ( - i = (e = this.getTensionPoints()).length, - r = o ? 0 : 4, - o || t.quadraticCurveTo(e[0], e[1], e[2], e[3]); - r < i - 2; - - ) - t.bezierCurveTo(e[r++], e[r++], e[r++], e[r++], e[r++], e[r++]); - o || t.quadraticCurveTo(e[i - 2], e[i - 1], a[n - 2], a[n - 1]); - } else if (h) - for (r = 2; r < n; ) - t.bezierCurveTo(a[r++], a[r++], a[r++], a[r++], a[r++], a[r++]); - else for (r = 2; r < n; r += 2) t.lineTo(a[r], a[r + 1]); - o ? (t.closePath(), t.fillStrokeShape(this)) : t.strokeShape(this); - } - } - getTensionPoints() { - return this._getCache('tensionPoints', this._getTensionPoints); - } - _getTensionPoints() { - return this.closed() - ? this._getTensionPointsClosed() - : u._expandPoints(this.points(), this.tension()); - } - _getTensionPointsClosed() { - var t = this.points(), - e = t.length, - i = this.tension(), - r = u._getControlPoints(t[e - 2], t[e - 1], t[0], t[1], t[2], t[3], i), - a = u._getControlPoints( - t[e - 4], - t[e - 3], - t[e - 2], - t[e - 1], - t[0], - t[1], - i - ), - n = u._expandPoints(t, i); - return [r[2], r[3]] - .concat(n) - .concat([ - a[0], - a[1], - t[e - 2], - t[e - 1], - a[2], - a[3], - r[0], - r[1], - t[0], - t[1], - ]); - } - getWidth() { - return this.getSelfRect().width; - } - getHeight() { - return this.getSelfRect().height; - } - getSelfRect() { - var t = this.points(); - if (t.length < 4) - return { x: t[0] || 0, y: t[1] || 0, width: 0, height: 0 }; - for ( - var e, - i, - r = (t = - 0 !== this.tension() - ? [ - t[0], - t[1], - ...this._getTensionPoints(), - t[t.length - 2], - t[t.length - 1], - ] - : this.points())[0], - a = t[0], - n = t[1], - s = t[1], - o = 0; - o < t.length / 2; - o++ - ) - (e = t[2 * o]), - (i = t[2 * o + 1]), - (r = Math.min(r, e)), - (a = Math.max(a, e)), - (n = Math.min(n, i)), - (s = Math.max(s, i)); - return { x: r, y: n, width: a - r, height: s - n }; - } - } - (bt.prototype.className = 'Line'), - (bt.prototype._attrsAffectingSize = ['points', 'bezier', 'tension']), - s(bt), - S.addGetterSetter(bt, 'closed', !1), - S.addGetterSetter(bt, 'bezier', !1), - S.addGetterSetter(bt, 'tension', 0, v()), - S.addGetterSetter( - bt, - 'points', - [], - (function () { - if (a.isUnminified) - return function (t, e) { - return ( - u._isArray(t) - ? t.forEach(function (t) { - u._isNumber(t) || - u.warn( - '"' + - e + - '" attribute has non numeric element ' + - t + - '. Make sure that all elements are numbers.' - ); - }) - : u.warn( - f(t) + - ' is a not valid value for "' + - e + - '" attribute. The value should be a array of numbers.' - ), - t - ); - }; - })() - ); - class St extends bt { - _sceneFunc(t) { - super._sceneFunc(t); - var e = 2 * Math.PI, - i = this.points(), - r = i, - a = 0 !== this.tension() && i.length > 4; - a && (r = this.getTensionPoints()); - var n, - s, - o = i.length; - a - ? ((n = i[o - 2] - (r[r.length - 2] + r[r.length - 4]) / 2), - (s = i[o - 1] - (r[r.length - 1] + r[r.length - 3]) / 2)) - : ((n = i[o - 2] - i[o - 4]), (s = i[o - 1] - i[o - 3])); - var h = (Math.atan2(s, n) + e) % e, - l = this.pointerLength(), - d = this.pointerWidth(); - t.save(), - t.beginPath(), - t.translate(i[o - 2], i[o - 1]), - t.rotate(h), - t.moveTo(0, 0), - t.lineTo(-l, d / 2), - t.lineTo(-l, -d / 2), - t.closePath(), - t.restore(), - this.pointerAtBeginning() && - (t.save(), - t.translate(i[0], i[1]), - a - ? ((n = (r[0] + r[2]) / 2 - i[0]), (s = (r[1] + r[3]) / 2 - i[1])) - : ((n = i[2] - i[0]), (s = i[3] - i[1])), - t.rotate((Math.atan2(-s, -n) + e) % e), - t.moveTo(0, 0), - t.lineTo(-l, d / 2), - t.lineTo(-l, -d / 2), - t.closePath(), - t.restore()); - var c = this.dashEnabled(); - c && ((this.attrs.dashEnabled = !1), t.setLineDash([])), - t.fillStrokeShape(this), - c && (this.attrs.dashEnabled = !0); - } - getSelfRect() { - const t = super.getSelfRect(), - e = this.pointerWidth() / 2; - return { - x: t.x - e, - y: t.y - e, - width: t.width + 2 * e, - height: t.height + 2 * e, - }; - } - } - (St.prototype.className = 'Arrow'), - s(St), - S.addGetterSetter(St, 'pointerLength', 10, v()), - S.addGetterSetter(St, 'pointerWidth', 10, v()), - S.addGetterSetter(St, 'pointerAtBeginning', !1); - class wt extends nt { - _sceneFunc(t) { - t.beginPath(), - t.arc(0, 0, this.attrs.radius || 0, 0, 2 * Math.PI, !1), - t.closePath(), - t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.radius(); - } - getHeight() { - return 2 * this.radius(); - } - setWidth(t) { - this.radius() !== t / 2 && this.radius(t / 2); - } - setHeight(t) { - this.radius() !== t / 2 && this.radius(t / 2); - } - } - (wt.prototype._centroid = !0), - (wt.prototype.className = 'Circle'), - (wt.prototype._attrsAffectingSize = ['radius']), - s(wt), - S.addGetterSetter(wt, 'radius', 0, v()); - class Ct extends nt { - _sceneFunc(t) { - var e = this.radiusX(), - i = this.radiusY(); - t.beginPath(), - t.save(), - e !== i && t.scale(1, i / e), - t.arc(0, 0, e, 0, 2 * Math.PI, !1), - t.restore(), - t.closePath(), - t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.radiusX(); - } - getHeight() { - return 2 * this.radiusY(); - } - setWidth(t) { - this.radiusX(t / 2); - } - setHeight(t) { - this.radiusY(t / 2); - } - } - (Ct.prototype.className = 'Ellipse'), - (Ct.prototype._centroid = !0), - (Ct.prototype._attrsAffectingSize = ['radiusX', 'radiusY']), - s(Ct), - S.addComponentsGetterSetter(Ct, 'radius', ['x', 'y']), - S.addGetterSetter(Ct, 'radiusX', 0, v()), - S.addGetterSetter(Ct, 'radiusY', 0, v()); - class Pt extends nt { - _useBufferCanvas() { - return super._useBufferCanvas(!0); - } - _sceneFunc(t) { - const e = this.getWidth(), - i = this.getHeight(), - r = this.attrs.image; - let a; - if (r) { - const t = this.attrs.cropWidth, - n = this.attrs.cropHeight; - a = - t && n - ? [r, this.cropX(), this.cropY(), t, n, 0, 0, e, i] - : [r, 0, 0, e, i]; - } - (this.hasFill() || this.hasStroke()) && - (t.beginPath(), - t.rect(0, 0, e, i), - t.closePath(), - t.fillStrokeShape(this)), - r && t.drawImage.apply(t, a); - } - _hitFunc(t) { - var e = this.width(), - i = this.height(); - t.beginPath(), t.rect(0, 0, e, i), t.closePath(), t.fillStrokeShape(this); - } - getWidth() { - var t, e; - return null !== (t = this.attrs.width) && void 0 !== t - ? t - : null === (e = this.image()) || void 0 === e - ? void 0 - : e.width; - } - getHeight() { - var t, e; - return null !== (t = this.attrs.height) && void 0 !== t - ? t - : null === (e = this.image()) || void 0 === e - ? void 0 - : e.height; - } - static fromURL(t, e) { - var i = u.createImageElement(); - (i.onload = function () { - var t = new Pt({ image: i }); - e(t); - }), - (i.crossOrigin = 'Anonymous'), - (i.src = t); - } - } - (Pt.prototype.className = 'Image'), - s(Pt), - S.addGetterSetter(Pt, 'image'), - S.addComponentsGetterSetter(Pt, 'crop', ['x', 'y', 'width', 'height']), - S.addGetterSetter(Pt, 'cropX', 0, v()), - S.addGetterSetter(Pt, 'cropY', 0, v()), - S.addGetterSetter(Pt, 'cropWidth', 0, v()), - S.addGetterSetter(Pt, 'cropHeight', 0, v()); - var kt = [ - 'fontFamily', - 'fontSize', - 'fontStyle', - 'padding', - 'lineHeight', - 'text', - 'width', - 'height', - ], - Tt = kt.length; - class At extends dt { - constructor(t) { - super(t), - this.on('add.konva', function (t) { - this._addListeners(t.child), this._sync(); - }); - } - getText() { - return this.find('Text')[0]; - } - getTag() { - return this.find('Tag')[0]; - } - _addListeners(t) { - var e, - i = this, - r = function () { - i._sync(); - }; - for (e = 0; e < Tt; e++) t.on(kt[e] + 'Change.konva', r); - } - getWidth() { - return this.getText().width(); - } - getHeight() { - return this.getText().height(); - } - _sync() { - var t, - e, - i, - r, - a, - n, - s, - o = this.getText(), - h = this.getTag(); - if (o && h) { - switch ( - ((t = o.width()), - (e = o.height()), - (i = h.pointerDirection()), - (r = h.pointerWidth()), - (s = h.pointerHeight()), - (a = 0), - (n = 0), - i) - ) { - case 'up': - (a = t / 2), (n = -1 * s); - break; - case 'right': - (a = t + r), (n = e / 2); - break; - case 'down': - (a = t / 2), (n = e + s); - break; - case 'left': - (a = -1 * r), (n = e / 2); - } - h.setAttrs({ x: -1 * a, y: -1 * n, width: t, height: e }), - o.setAttrs({ x: -1 * a, y: -1 * n }); - } - } - } - (At.prototype.className = 'Label'), s(At); - class Mt extends nt { - _sceneFunc(t) { - var e = this.width(), - i = this.height(), - r = this.pointerDirection(), - a = this.pointerWidth(), - n = this.pointerHeight(), - s = this.cornerRadius(); - let o = 0, - h = 0, - l = 0, - d = 0; - 'number' == typeof s - ? (o = h = l = d = Math.min(s, e / 2, i / 2)) - : ((o = Math.min(s[0] || 0, e / 2, i / 2)), - (h = Math.min(s[1] || 0, e / 2, i / 2)), - (d = Math.min(s[2] || 0, e / 2, i / 2)), - (l = Math.min(s[3] || 0, e / 2, i / 2))), - t.beginPath(), - t.moveTo(o, 0), - 'up' === r && - (t.lineTo((e - a) / 2, 0), - t.lineTo(e / 2, -1 * n), - t.lineTo((e + a) / 2, 0)), - t.lineTo(e - h, 0), - t.arc(e - h, h, h, (3 * Math.PI) / 2, 0, !1), - 'right' === r && - (t.lineTo(e, (i - n) / 2), - t.lineTo(e + a, i / 2), - t.lineTo(e, (i + n) / 2)), - t.lineTo(e, i - d), - t.arc(e - d, i - d, d, 0, Math.PI / 2, !1), - 'down' === r && - (t.lineTo((e + a) / 2, i), - t.lineTo(e / 2, i + n), - t.lineTo((e - a) / 2, i)), - t.lineTo(l, i), - t.arc(l, i - l, l, Math.PI / 2, Math.PI, !1), - 'left' === r && - (t.lineTo(0, (i + n) / 2), - t.lineTo(-1 * a, i / 2), - t.lineTo(0, (i - n) / 2)), - t.lineTo(0, o), - t.arc(o, o, o, Math.PI, (3 * Math.PI) / 2, !1), - t.closePath(), - t.fillStrokeShape(this); - } - getSelfRect() { - var t = 0, - e = 0, - i = this.pointerWidth(), - r = this.pointerHeight(), - a = this.pointerDirection(), - n = this.width(), - s = this.height(); - return ( - 'up' === a - ? ((e -= r), (s += r)) - : 'down' === a - ? (s += r) - : 'left' === a - ? ((t -= 1.5 * i), (n += i)) - : 'right' === a && (n += 1.5 * i), - { x: t, y: e, width: n, height: s } - ); - } - } - (Mt.prototype.className = 'Tag'), - s(Mt), - S.addGetterSetter(Mt, 'pointerDirection', 'none'), - S.addGetterSetter(Mt, 'pointerWidth', 0, v()), - S.addGetterSetter(Mt, 'pointerHeight', 0, v()), - S.addGetterSetter(Mt, 'cornerRadius', 0, m(4)); - class Gt extends nt { - constructor(t) { - super(t), - (this.dataArray = []), - (this.pathLength = 0), - (this.dataArray = Gt.parsePathData(this.data())), - (this.pathLength = 0); - for (var e = 0; e < this.dataArray.length; ++e) - this.pathLength += this.dataArray[e].pathLength; - this.on('dataChange.konva', function () { - (this.dataArray = Gt.parsePathData(this.data())), (this.pathLength = 0); - for (var t = 0; t < this.dataArray.length; ++t) - this.pathLength += this.dataArray[t].pathLength; - }); - } - _sceneFunc(t) { - var e = this.dataArray; - t.beginPath(); - for (var i = !1, r = 0; r < e.length; r++) { - var a = e[r].command, - n = e[r].points; - switch (a) { - case 'L': - t.lineTo(n[0], n[1]); - break; - case 'M': - t.moveTo(n[0], n[1]); - break; - case 'C': - t.bezierCurveTo(n[0], n[1], n[2], n[3], n[4], n[5]); - break; - case 'Q': - t.quadraticCurveTo(n[0], n[1], n[2], n[3]); - break; - case 'A': - var s = n[0], - o = n[1], - h = n[2], - l = n[3], - d = n[4], - c = n[5], - g = n[6], - u = n[7], - f = h > l ? h : l, - p = h > l ? 1 : h / l, - v = h > l ? l / h : 1; - t.translate(s, o), - t.rotate(g), - t.scale(p, v), - t.arc(0, 0, f, d, d + c, 1 - u), - t.scale(1 / p, 1 / v), - t.rotate(-g), - t.translate(-s, -o); - break; - case 'z': - (i = !0), t.closePath(); - } - } - i || this.hasFill() ? t.fillStrokeShape(this) : t.strokeShape(this); - } - getSelfRect() { - var t = []; - this.dataArray.forEach(function (e) { - if ('A' === e.command) { - var i = e.points[4], - r = e.points[5], - a = e.points[4] + r, - n = Math.PI / 180; - if ((Math.abs(i - a) < n && (n = Math.abs(i - a)), r < 0)) - for (let r = i - n; r > a; r -= n) { - const i = Gt.getPointOnEllipticalArc( - e.points[0], - e.points[1], - e.points[2], - e.points[3], - r, - 0 - ); - t.push(i.x, i.y); - } - else - for (let r = i + n; r < a; r += n) { - const i = Gt.getPointOnEllipticalArc( - e.points[0], - e.points[1], - e.points[2], - e.points[3], - r, - 0 - ); - t.push(i.x, i.y); - } - } else if ('C' === e.command) - for (let i = 0; i <= 1; i += 0.01) { - const r = Gt.getPointOnCubicBezier( - i, - e.start.x, - e.start.y, - e.points[0], - e.points[1], - e.points[2], - e.points[3], - e.points[4], - e.points[5] - ); - t.push(r.x, r.y); - } - else t = t.concat(e.points); - }); - for ( - var e, i, r = t[0], a = t[0], n = t[1], s = t[1], o = 0; - o < t.length / 2; - o++ - ) - (e = t[2 * o]), - (i = t[2 * o + 1]), - isNaN(e) || ((r = Math.min(r, e)), (a = Math.max(a, e))), - isNaN(i) || ((n = Math.min(n, i)), (s = Math.max(s, i))); - return { - x: Math.round(r), - y: Math.round(n), - width: Math.round(a - r), - height: Math.round(s - n), - }; - } - getLength() { - return this.pathLength; - } - getPointAtLength(t) { - var e, - i = 0, - r = this.dataArray.length; - if (!r) return null; - for (; i < r && t > this.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 < 0.01) - return { x: (e = this.dataArray[i].points.slice(0, 2))[0], y: e[1] }; - var a = this.dataArray[i], - n = a.points; - switch (a.command) { - case 'L': - return Gt.getPointOnLine(t, a.start.x, a.start.y, n[0], n[1]); - case 'C': - return Gt.getPointOnCubicBezier( - t / a.pathLength, - a.start.x, - a.start.y, - n[0], - n[1], - n[2], - n[3], - n[4], - n[5] - ); - case 'Q': - return Gt.getPointOnQuadraticBezier( - t / a.pathLength, - a.start.x, - a.start.y, - n[0], - n[1], - n[2], - n[3] - ); - case 'A': - var s = n[0], - o = n[1], - h = n[2], - l = n[3], - d = n[4], - c = n[5], - g = n[6]; - return ( - (d += (c * t) / a.pathLength), - Gt.getPointOnEllipticalArc(s, o, h, l, d, g) - ); - } - return null; - } - static getLineLength(t, e, i, r) { - return Math.sqrt((i - t) * (i - t) + (r - e) * (r - e)); - } - static getPointOnLine(t, e, i, r, a, n, s) { - void 0 === n && (n = e), void 0 === s && (s = i); - var o = (a - i) / (r - e + 1e-8), - h = Math.sqrt((t * t) / (1 + o * o)); - r < e && (h *= -1); - var l, - d = o * h; - if (r === e) l = { x: n, y: s + d }; - else if ((s - i) / (n - e + 1e-8) === o) l = { x: n + h, y: s + d }; - else { - var c, - g, - u = this.getLineLength(e, i, r, a), - f = (n - e) * (r - e) + (s - i) * (a - i); - (c = e + (f /= u * u) * (r - e)), (g = i + f * (a - i)); - var p = this.getLineLength(n, s, c, g), - v = Math.sqrt(t * t - p * p); - (h = Math.sqrt((v * v) / (1 + o * o))), - r < e && (h *= -1), - (l = { x: c + h, y: g + (d = o * h) }); - } - return l; - } - static getPointOnCubicBezier(t, e, i, r, a, n, s, o, h) { - function l(t) { - return t * t * t; - } - function d(t) { - return 3 * t * t * (1 - t); - } - function c(t) { - return 3 * t * (1 - t) * (1 - t); - } - function g(t) { - return (1 - t) * (1 - t) * (1 - t); - } - return { - x: o * l(t) + n * d(t) + r * c(t) + e * g(t), - y: h * l(t) + s * d(t) + a * c(t) + i * g(t), - }; - } - static getPointOnQuadraticBezier(t, e, i, r, a, n, s) { - function o(t) { - return t * t; - } - function h(t) { - return 2 * t * (1 - t); - } - function l(t) { - return (1 - t) * (1 - t); - } - return { - x: n * o(t) + r * h(t) + e * l(t), - y: s * o(t) + a * h(t) + i * l(t), - }; - } - static getPointOnEllipticalArc(t, e, i, r, a, n) { - var s = Math.cos(n), - o = Math.sin(n), - h = i * Math.cos(a), - l = r * Math.sin(a); - return { x: t + (h * s - l * o), y: e + (h * o + l * s) }; - } - static parsePathData(t) { - if (!t) return []; - var e = t, - i = [ - 'm', - 'M', - 'l', - 'L', - 'v', - 'V', - 'h', - 'H', - 'z', - 'Z', - 'c', - 'C', - 'q', - 'Q', - 't', - 'T', - 's', - 'S', - 'a', - 'A', - ]; - e = e.replace(new RegExp(' ', 'g'), ','); - for (var r = 0; r < i.length; r++) - e = e.replace(new RegExp(i[r], 'g'), '|' + i[r]); - var a, - n = e.split('|'), - s = [], - o = [], - h = 0, - l = 0, - d = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi; - for (r = 1; r < n.length; r++) { - var c = n[r], - g = c.charAt(0); - for (c = c.slice(1), o.length = 0; (a = d.exec(c)); ) o.push(a[0]); - for (var u = [], f = 0, p = o.length; f < p; f++) { - var v = parseFloat(o[f]); - isNaN(v) ? u.push(0) : u.push(v); - } - for (; u.length > 0 && !isNaN(u[0]); ) { - var m, - _, - y, - x, - b, - S, - w, - C, - P, - k, - T = null, - A = [], - M = h, - G = l; - switch (g) { - case 'l': - (h += u.shift()), (l += u.shift()), (T = 'L'), A.push(h, l); - break; - case 'L': - (h = u.shift()), (l = u.shift()), A.push(h, l); - break; - case 'm': - var E = u.shift(), - R = u.shift(); - if ( - ((h += E), - (l += R), - (T = 'M'), - s.length > 2 && 'z' === s[s.length - 1].command) - ) - for (var L = s.length - 2; L >= 0; L--) - if ('M' === s[L].command) { - (h = s[L].points[0] + E), (l = s[L].points[1] + R); - break; - } - A.push(h, l), (g = 'l'); - break; - case 'M': - (h = u.shift()), - (l = u.shift()), - (T = 'M'), - A.push(h, l), - (g = 'L'); - break; - case 'h': - (h += u.shift()), (T = 'L'), A.push(h, l); - break; - case 'H': - (h = u.shift()), (T = 'L'), A.push(h, l); - break; - case 'v': - (l += u.shift()), (T = 'L'), A.push(h, l); - break; - case 'V': - (l = u.shift()), (T = 'L'), A.push(h, l); - break; - case 'C': - A.push(u.shift(), u.shift(), u.shift(), u.shift()), - (h = u.shift()), - (l = u.shift()), - A.push(h, l); - break; - case 'c': - A.push( - h + u.shift(), - l + u.shift(), - h + u.shift(), - l + u.shift() - ), - (h += u.shift()), - (l += u.shift()), - (T = 'C'), - A.push(h, l); - break; - case 'S': - (_ = h), - (y = l), - 'C' === (m = s[s.length - 1]).command && - ((_ = h + (h - m.points[2])), (y = l + (l - m.points[3]))), - A.push(_, y, u.shift(), u.shift()), - (h = u.shift()), - (l = u.shift()), - (T = 'C'), - A.push(h, l); - break; - case 's': - (_ = h), - (y = l), - 'C' === (m = s[s.length - 1]).command && - ((_ = h + (h - m.points[2])), (y = l + (l - m.points[3]))), - A.push(_, y, h + u.shift(), l + u.shift()), - (h += u.shift()), - (l += u.shift()), - (T = 'C'), - A.push(h, l); - break; - case 'Q': - A.push(u.shift(), u.shift()), - (h = u.shift()), - (l = u.shift()), - A.push(h, l); - break; - case 'q': - A.push(h + u.shift(), l + u.shift()), - (h += u.shift()), - (l += u.shift()), - (T = 'Q'), - A.push(h, l); - break; - case 'T': - (_ = h), - (y = l), - 'Q' === (m = s[s.length - 1]).command && - ((_ = h + (h - m.points[0])), (y = l + (l - m.points[1]))), - (h = u.shift()), - (l = u.shift()), - (T = 'Q'), - A.push(_, y, h, l); - break; - case 't': - (_ = h), - (y = l), - 'Q' === (m = s[s.length - 1]).command && - ((_ = h + (h - m.points[0])), (y = l + (l - m.points[1]))), - (h += u.shift()), - (l += u.shift()), - (T = 'Q'), - A.push(_, y, h, l); - break; - case 'A': - (x = u.shift()), - (b = u.shift()), - (S = u.shift()), - (w = u.shift()), - (C = u.shift()), - (P = h), - (k = l), - (h = u.shift()), - (l = u.shift()), - (T = 'A'), - (A = this.convertEndpointToCenterParameterization( - P, - k, - h, - l, - w, - C, - x, - b, - S - )); - break; - case 'a': - (x = u.shift()), - (b = u.shift()), - (S = u.shift()), - (w = u.shift()), - (C = u.shift()), - (P = h), - (k = l), - (h += u.shift()), - (l += u.shift()), - (T = 'A'), - (A = this.convertEndpointToCenterParameterization( - P, - k, - h, - l, - w, - C, - x, - b, - S - )); - } - s.push({ - command: T || g, - points: A, - start: { x: M, y: G }, - pathLength: this.calcLength(M, G, T || g, A), - }); - } - ('z' !== g && 'Z' !== g) || - s.push({ command: 'z', points: [], start: void 0, pathLength: 0 }); - } - return s; - } - static calcLength(t, e, i, r) { - var a, - n, - s, - o, - h = Gt; - switch (i) { - case 'L': - return h.getLineLength(t, e, r[0], r[1]); - case 'C': - for ( - a = 0, - n = h.getPointOnCubicBezier( - 0, - t, - e, - r[0], - r[1], - r[2], - r[3], - r[4], - r[5] - ), - o = 0.01; - o <= 1; - o += 0.01 - ) - (s = h.getPointOnCubicBezier( - o, - t, - e, - r[0], - r[1], - r[2], - r[3], - r[4], - r[5] - )), - (a += h.getLineLength(n.x, n.y, s.x, s.y)), - (n = s); - return a; - case 'Q': - for ( - a = 0, - n = h.getPointOnQuadraticBezier(0, t, e, r[0], r[1], r[2], r[3]), - o = 0.01; - o <= 1; - o += 0.01 - ) - (s = h.getPointOnQuadraticBezier(o, t, e, r[0], r[1], r[2], r[3])), - (a += h.getLineLength(n.x, n.y, s.x, s.y)), - (n = s); - return a; - case 'A': - a = 0; - var l = r[4], - d = r[5], - c = r[4] + d, - g = Math.PI / 180; - if ( - (Math.abs(l - c) < g && (g = Math.abs(l - c)), - (n = h.getPointOnEllipticalArc(r[0], r[1], r[2], r[3], l, 0)), - d < 0) - ) - for (o = l - g; o > c; o -= g) - (s = h.getPointOnEllipticalArc(r[0], r[1], r[2], r[3], o, 0)), - (a += h.getLineLength(n.x, n.y, s.x, s.y)), - (n = s); - else - for (o = l + g; o < c; o += g) - (s = h.getPointOnEllipticalArc(r[0], r[1], r[2], r[3], o, 0)), - (a += h.getLineLength(n.x, n.y, s.x, s.y)), - (n = s); - return ( - (s = h.getPointOnEllipticalArc(r[0], r[1], r[2], r[3], c, 0)), - (a += h.getLineLength(n.x, n.y, s.x, s.y)) - ); - } - return 0; - } - static convertEndpointToCenterParameterization(t, e, i, r, a, n, s, o, h) { - var l = h * (Math.PI / 180), - d = (Math.cos(l) * (t - i)) / 2 + (Math.sin(l) * (e - r)) / 2, - c = (-1 * Math.sin(l) * (t - i)) / 2 + (Math.cos(l) * (e - r)) / 2, - g = (d * d) / (s * s) + (c * c) / (o * o); - g > 1 && ((s *= Math.sqrt(g)), (o *= Math.sqrt(g))); - var u = Math.sqrt( - (s * s * (o * o) - s * s * (c * c) - o * o * (d * d)) / - (s * s * (c * c) + o * o * (d * d)) - ); - a === n && (u *= -1), isNaN(u) && (u = 0); - var f = (u * s * c) / o, - p = (u * -o * d) / s, - v = (t + i) / 2 + Math.cos(l) * f - Math.sin(l) * p, - m = (e + r) / 2 + Math.sin(l) * f + Math.cos(l) * p, - _ = function (t) { - return Math.sqrt(t[0] * t[0] + t[1] * t[1]); - }, - y = function (t, e) { - return (t[0] * e[0] + t[1] * e[1]) / (_(t) * _(e)); - }, - x = function (t, e) { - return (t[0] * e[1] < t[1] * e[0] ? -1 : 1) * Math.acos(y(t, e)); - }, - b = x([1, 0], [(d - f) / s, (c - p) / o]), - S = [(d - f) / s, (c - p) / o], - w = [(-1 * d - f) / s, (-1 * c - p) / o], - C = x(S, w); - return ( - y(S, w) <= -1 && (C = Math.PI), - y(S, w) >= 1 && (C = 0), - 0 === n && C > 0 && (C -= 2 * Math.PI), - 1 === n && C < 0 && (C += 2 * Math.PI), - [v, m, s, o, b, C, l, n] - ); - } - } - (Gt.prototype.className = 'Path'), - (Gt.prototype._attrsAffectingSize = ['data']), - s(Gt), - S.addGetterSetter(Gt, 'data'); - class Et extends nt { - _sceneFunc(t) { - var e = this.cornerRadius(), - i = this.width(), - r = this.height(); - if ((t.beginPath(), e)) { - let a = 0, - n = 0, - s = 0, - o = 0; - 'number' == typeof e - ? (a = n = s = o = Math.min(e, i / 2, r / 2)) - : ((a = Math.min(e[0] || 0, i / 2, r / 2)), - (n = Math.min(e[1] || 0, i / 2, r / 2)), - (o = Math.min(e[2] || 0, i / 2, r / 2)), - (s = Math.min(e[3] || 0, i / 2, r / 2))), - t.moveTo(a, 0), - t.lineTo(i - n, 0), - t.arc(i - n, n, n, (3 * Math.PI) / 2, 0, !1), - t.lineTo(i, r - o), - t.arc(i - o, r - o, o, 0, Math.PI / 2, !1), - t.lineTo(s, r), - t.arc(s, r - s, s, Math.PI / 2, Math.PI, !1), - t.lineTo(0, a), - t.arc(a, a, a, Math.PI, (3 * Math.PI) / 2, !1); - } else t.rect(0, 0, i, r); - t.closePath(), t.fillStrokeShape(this); - } - } - (Et.prototype.className = 'Rect'), - s(Et), - S.addGetterSetter(Et, 'cornerRadius', 0, m(4)); - class Rt extends nt { - _sceneFunc(t) { - const e = this._getPoints(); - t.beginPath(), t.moveTo(e[0].x, e[0].y); - for (var i = 1; i < e.length; i++) t.lineTo(e[i].x, e[i].y); - t.closePath(), t.fillStrokeShape(this); - } - _getPoints() { - const t = this.attrs.sides, - e = this.attrs.radius || 0, - i = []; - for (var r = 0; r < t; r++) - i.push({ - x: e * Math.sin((2 * r * Math.PI) / t), - y: -1 * e * Math.cos((2 * r * Math.PI) / t), - }); - return i; - } - getSelfRect() { - const t = this._getPoints(); - var e = t[0].x, - i = t[0].y, - r = t[0].x, - a = t[0].y; - return ( - t.forEach((t) => { - (e = Math.min(e, t.x)), - (i = Math.max(i, t.x)), - (r = Math.min(r, t.y)), - (a = Math.max(a, t.y)); - }), - { x: e, y: r, width: i - e, height: a - r } - ); - } - getWidth() { - return 2 * this.radius(); - } - getHeight() { - return 2 * this.radius(); - } - setWidth(t) { - this.radius(t / 2); - } - setHeight(t) { - this.radius(t / 2); - } - } - (Rt.prototype.className = 'RegularPolygon'), - (Rt.prototype._centroid = !0), - (Rt.prototype._attrsAffectingSize = ['radius']), - s(Rt), - S.addGetterSetter(Rt, 'radius', 0, v()), - S.addGetterSetter(Rt, 'sides', 0, v()); - var Lt = 2 * Math.PI; - class Dt extends nt { - _sceneFunc(t) { - t.beginPath(), - t.arc(0, 0, this.innerRadius(), 0, Lt, !1), - t.moveTo(this.outerRadius(), 0), - t.arc(0, 0, this.outerRadius(), Lt, 0, !0), - t.closePath(), - t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.outerRadius(); - } - getHeight() { - return 2 * this.outerRadius(); - } - setWidth(t) { - this.outerRadius(t / 2); - } - setHeight(t) { - this.outerRadius(t / 2); - } - } - (Dt.prototype.className = 'Ring'), - (Dt.prototype._centroid = !0), - (Dt.prototype._attrsAffectingSize = ['innerRadius', 'outerRadius']), - s(Dt), - S.addGetterSetter(Dt, 'innerRadius', 0, v()), - S.addGetterSetter(Dt, 'outerRadius', 0, v()); - class It extends nt { - constructor(t) { - super(t), - (this._updated = !0), - (this.anim = new gt(() => { - var t = this._updated; - return (this._updated = !1), t; - })), - this.on('animationChange.konva', function () { - this.frameIndex(0); - }), - this.on('frameIndexChange.konva', function () { - this._updated = !0; - }), - this.on('frameRateChange.konva', function () { - this.anim.isRunning() && - (clearInterval(this.interval), this._setInterval()); - }); - } - _sceneFunc(t) { - var e = this.animation(), - i = this.frameIndex(), - r = 4 * i, - a = this.animations()[e], - n = this.frameOffsets(), - s = a[r + 0], - o = a[r + 1], - h = a[r + 2], - l = a[r + 3], - d = this.image(); - if ( - ((this.hasFill() || this.hasStroke()) && - (t.beginPath(), - t.rect(0, 0, h, l), - t.closePath(), - t.fillStrokeShape(this)), - d) - ) - if (n) { - var c = n[e], - g = 2 * i; - t.drawImage(d, s, o, h, l, c[g + 0], c[g + 1], h, l); - } else t.drawImage(d, s, o, h, l, 0, 0, h, l); - } - _hitFunc(t) { - var e = this.animation(), - i = this.frameIndex(), - r = 4 * i, - a = this.animations()[e], - n = this.frameOffsets(), - s = a[r + 2], - o = a[r + 3]; - if ((t.beginPath(), n)) { - var h = n[e], - l = 2 * i; - t.rect(h[l + 0], h[l + 1], s, o); - } else t.rect(0, 0, s, o); - t.closePath(), t.fillShape(this); - } - _useBufferCanvas() { - return super._useBufferCanvas(!0); - } - _setInterval() { - var t = this; - this.interval = setInterval(function () { - t._updateIndex(); - }, 1e3 / this.frameRate()); - } - start() { - if (!this.isRunning()) { - var t = this.getLayer(); - this.anim.setLayers(t), this._setInterval(), this.anim.start(); - } - } - stop() { - this.anim.stop(), clearInterval(this.interval); - } - isRunning() { - return this.anim.isRunning(); - } - _updateIndex() { - var t = this.frameIndex(), - e = this.animation(); - t < this.animations()[e].length / 4 - 1 - ? this.frameIndex(t + 1) - : this.frameIndex(0); - } - } - (It.prototype.className = 'Sprite'), - s(It), - S.addGetterSetter(It, 'animation'), - S.addGetterSetter(It, 'animations'), - S.addGetterSetter(It, 'frameOffsets'), - S.addGetterSetter(It, 'image'), - S.addGetterSetter(It, 'frameIndex', 0, v()), - S.addGetterSetter(It, 'frameRate', 17, v()), - S.backCompat(It, { - index: 'frameIndex', - getIndex: 'getFrameIndex', - setIndex: 'setFrameIndex', - }); - class Ot extends nt { - _sceneFunc(t) { - var e = this.innerRadius(), - i = this.outerRadius(), - r = this.numPoints(); - t.beginPath(), t.moveTo(0, 0 - i); - for (var a = 1; a < 2 * r; a++) { - var n = a % 2 == 0 ? i : e, - s = n * Math.sin((a * Math.PI) / r), - o = -1 * n * Math.cos((a * Math.PI) / r); - t.lineTo(s, o); - } - t.closePath(), t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.outerRadius(); - } - getHeight() { - return 2 * this.outerRadius(); - } - setWidth(t) { - this.outerRadius(t / 2); - } - setHeight(t) { - this.outerRadius(t / 2); - } - } - function Ft(t) { - return Array.from(t); - } - (Ot.prototype.className = 'Star'), - (Ot.prototype._centroid = !0), - (Ot.prototype._attrsAffectingSize = ['innerRadius', 'outerRadius']), - s(Ot), - S.addGetterSetter(Ot, 'numPoints', 5, v()), - S.addGetterSetter(Ot, 'innerRadius', 0, v()), - S.addGetterSetter(Ot, 'outerRadius', 0, v()); - var Bt, - Nt = [ - 'fontFamily', - 'fontSize', - 'fontStyle', - 'fontVariant', - 'padding', - 'align', - 'verticalAlign', - 'lineHeight', - 'text', - 'width', - 'height', - 'wrap', - 'ellipsis', - 'letterSpacing', - ], - zt = Nt.length; - function Wt() { - return Bt || (Bt = u.createCanvasElement().getContext('2d')); - } - class Ht extends nt { - constructor(t) { - super( - (function (t) { - return ( - (t = t || {}).fillLinearGradientColorStops || - t.fillRadialGradientColorStops || - t.fillPatternImage || - (t.fill = t.fill || 'black'), - t - ); - })(t) - ), - (this._partialTextX = 0), - (this._partialTextY = 0); - for (var e = 0; e < zt; e++) - this.on(Nt[e] + 'Change.konva', this._setTextData); - this._setTextData(); - } - _sceneFunc(t) { - var e = this.textArr, - i = e.length; - if (this.text()) { - var r, - a = this.padding(), - n = this.fontSize(), - s = this.lineHeight() * n, - o = this.verticalAlign(), - h = 0, - l = this.align(), - d = this.getWidth(), - c = this.letterSpacing(), - g = this.fill(), - u = this.textDecoration(), - f = -1 !== u.indexOf('underline'), - p = -1 !== u.indexOf('line-through'), - v = 0, - m = ((v = s / 2), 0), - _ = 0; - for ( - t.setAttr('font', this._getContextFont()), - t.setAttr('textBaseline', 'middle'), - t.setAttr('textAlign', 'left'), - 'middle' === o - ? (h = (this.getHeight() - i * s - 2 * a) / 2) - : 'bottom' === o && (h = this.getHeight() - i * s - 2 * a), - t.translate(a, h + a), - r = 0; - r < i; - r++ - ) { - (m = 0), (_ = 0); - var y, - x, - b, - S = e[r], - w = S.text, - C = S.width, - P = r !== i - 1; - if ( - (t.save(), - 'right' === l - ? (m += d - C - 2 * a) - : 'center' === l && (m += (d - C - 2 * a) / 2), - f && - (t.save(), - t.beginPath(), - t.moveTo(m, v + _ + Math.round(n / 2)), - (x = 0 === (y = w.split(' ').length - 1)), - (b = 'justify' === l && P && !x ? d - 2 * a : C), - t.lineTo(m + Math.round(b), v + _ + Math.round(n / 2)), - (t.lineWidth = n / 15), - (t.strokeStyle = g), - t.stroke(), - t.restore()), - p && - (t.save(), - t.beginPath(), - t.moveTo(m, v + _), - (x = 0 === (y = w.split(' ').length - 1)), - (b = 'justify' === l && P && !x ? d - 2 * a : C), - t.lineTo(m + Math.round(b), v + _), - (t.lineWidth = n / 15), - (t.strokeStyle = g), - t.stroke(), - t.restore()), - 0 !== c || 'justify' === l) - ) { - y = w.split(' ').length - 1; - for (var k = Ft(w), T = 0; T < k.length; T++) { - var A = k[T]; - ' ' === A && - r !== i - 1 && - 'justify' === l && - (m += (d - 2 * a - C) / y), - (this._partialTextX = m), - (this._partialTextY = v + _), - (this._partialText = A), - t.fillStrokeShape(this), - (m += this.measureSize(A).width + c); - } - } else - (this._partialTextX = m), - (this._partialTextY = v + _), - (this._partialText = w), - t.fillStrokeShape(this); - t.restore(), i > 1 && (v += s); - } - } - } - _hitFunc(t) { - var e = this.getWidth(), - i = this.getHeight(); - t.beginPath(), t.rect(0, 0, e, i), t.closePath(), t.fillStrokeShape(this); - } - setText(t) { - var e = u._isString(t) ? t : null == t ? '' : t + ''; - return this._setAttr('text', e), this; - } - getWidth() { - return 'auto' === this.attrs.width || void 0 === this.attrs.width - ? this.getTextWidth() + 2 * this.padding() - : this.attrs.width; - } - getHeight() { - return 'auto' === this.attrs.height || void 0 === this.attrs.height - ? this.fontSize() * this.textArr.length * this.lineHeight() + - 2 * this.padding() - : this.attrs.height; - } - getTextWidth() { - return this.textWidth; - } - getTextHeight() { - return ( - u.warn( - 'text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.' - ), - this.textHeight - ); - } - measureSize(t) { - var e, - i = Wt(), - r = this.fontSize(); - return ( - i.save(), - (i.font = this._getContextFont()), - (e = i.measureText(t)), - i.restore(), - { width: e.width, height: r } - ); - } - _getContextFont() { - return a.UA.isIE - ? this.fontStyle() + ' ' + this.fontSize() + 'px ' + this.fontFamily() - : this.fontStyle() + - ' ' + - this.fontVariant() + - ' ' + - this.fontSize() + - 'px ' + - this.fontFamily() - .split(',') - .map((t) => { - const e = (t = t.trim()).indexOf(' ') >= 0, - i = t.indexOf('"') >= 0 || t.indexOf("'") >= 0; - return e && !i && (t = `"${t}"`), t; - }) - .join(', '); - } - _addTextLine(t) { - 'justify' === this.align() && (t = t.trim()); - var e = this._getTextWidth(t); - return this.textArr.push({ text: t, width: e }); - } - _getTextWidth(t) { - var e = this.letterSpacing(), - i = t.length; - return Wt().measureText(t).width + (i ? e * (i - 1) : 0); - } - _setTextData() { - var t = this.text().split('\n'), - e = +this.fontSize(), - i = 0, - r = this.lineHeight() * e, - a = this.attrs.width, - n = this.attrs.height, - s = 'auto' !== a && void 0 !== a, - o = 'auto' !== n && void 0 !== n, - h = this.padding(), - l = a - 2 * h, - d = n - 2 * h, - c = 0, - g = this.wrap(), - u = 'none' !== g, - f = 'char' !== g && u, - p = this.ellipsis(); - (this.textArr = []), (Wt().font = this._getContextFont()); - for ( - var v = p ? this._getTextWidth('…') : 0, m = 0, _ = t.length; - m < _; - ++m - ) { - var y = t[m], - x = this._getTextWidth(y); - if (s && x > l) - for (; y.length > 0; ) { - for (var b = 0, S = y.length, w = '', C = 0; b < S; ) { - var P = (b + S) >>> 1, - k = y.slice(0, P + 1), - T = this._getTextWidth(k) + v; - T <= l ? ((b = P + 1), (w = k), (C = T)) : (S = P); - } - if (!w) break; - if (f) { - var A, - M = y[w.length]; - (A = - (' ' === M || '-' === M) && C <= l - ? w.length - : Math.max(w.lastIndexOf(' '), w.lastIndexOf('-')) + 1) > 0 && - ((b = A), (w = w.slice(0, b)), (C = this._getTextWidth(w))); - } - if ( - ((w = w.trimRight()), - this._addTextLine(w), - (i = Math.max(i, C)), - (c += r), - !u || (o && c + r > d)) - ) { - var G = this.textArr[this.textArr.length - 1]; - if (G) - if (p) - this._getTextWidth(G.text + '…') < l || - (G.text = G.text.slice(0, G.text.length - 3)), - this.textArr.splice(this.textArr.length - 1, 1), - this._addTextLine(G.text + '…'); - break; - } - if ( - (y = (y = y.slice(b)).trimLeft()).length > 0 && - (x = this._getTextWidth(y)) <= l - ) { - this._addTextLine(y), (c += r), (i = Math.max(i, x)); - break; - } - } - else this._addTextLine(y), (c += r), (i = Math.max(i, x)); - if (o && c + r > d) break; - } - (this.textHeight = e), (this.textWidth = i); - } - getStrokeScaleEnabled() { - return !0; - } - } - (Ht.prototype._fillFunc = function (t) { - t.fillText(this._partialText, this._partialTextX, this._partialTextY); - }), - (Ht.prototype._strokeFunc = function (t) { - t.strokeText(this._partialText, this._partialTextX, this._partialTextY); - }), - (Ht.prototype.className = 'Text'), - (Ht.prototype._attrsAffectingSize = [ - 'text', - 'fontSize', - 'padding', - 'wrap', - 'lineHeight', - 'letterSpacing', - ]), - s(Ht), - S.overWriteSetter(Ht, 'width', _()), - S.overWriteSetter(Ht, 'height', _()), - S.addGetterSetter(Ht, 'fontFamily', 'Arial'), - S.addGetterSetter(Ht, 'fontSize', 12, v()), - S.addGetterSetter(Ht, 'fontStyle', 'normal'), - S.addGetterSetter(Ht, 'fontVariant', 'normal'), - S.addGetterSetter(Ht, 'padding', 0, v()), - S.addGetterSetter(Ht, 'align', 'left'), - S.addGetterSetter(Ht, 'verticalAlign', 'top'), - S.addGetterSetter(Ht, 'lineHeight', 1, v()), - S.addGetterSetter(Ht, 'wrap', 'word'), - S.addGetterSetter(Ht, 'ellipsis', !1, b()), - S.addGetterSetter(Ht, 'letterSpacing', 0, v()), - S.addGetterSetter(Ht, 'text', '', y()), - S.addGetterSetter(Ht, 'textDecoration', ''); - function Yt(t) { - t.fillText(this.partialText, 0, 0); - } - function Xt(t) { - t.strokeText(this.partialText, 0, 0); - } - class jt extends nt { - constructor(t) { - super(t), - (this.dummyCanvas = u.createCanvasElement()), - (this.dataArray = []), - (this.dataArray = Gt.parsePathData(this.attrs.data)), - this.on('dataChange.konva', function () { - (this.dataArray = Gt.parsePathData(this.attrs.data)), - this._setTextData(); - }), - this.on( - 'textChange.konva alignChange.konva letterSpacingChange.konva kerningFuncChange.konva fontSizeChange.konva', - this._setTextData - ), - t && - t.getKerning && - (u.warn( - 'getKerning TextPath API is deprecated. Please use "kerningFunc" instead.' - ), - this.kerningFunc(t.getKerning)), - this._setTextData(); - } - _sceneFunc(t) { - t.setAttr('font', this._getContextFont()), - t.setAttr('textBaseline', this.textBaseline()), - t.setAttr('textAlign', 'left'), - t.save(); - var e = this.textDecoration(), - i = this.fill(), - r = this.fontSize(), - a = this.glyphInfo; - 'underline' === e && t.beginPath(); - for (var n = 0; n < a.length; n++) { - t.save(); - var s = a[n].p0; - t.translate(s.x, s.y), - t.rotate(a[n].rotation), - (this.partialText = a[n].text), - t.fillStrokeShape(this), - 'underline' === e && - (0 === n && t.moveTo(0, r / 2 + 1), t.lineTo(r, r / 2 + 1)), - t.restore(); - } - 'underline' === e && - ((t.strokeStyle = i), (t.lineWidth = r / 20), t.stroke()), - t.restore(); - } - _hitFunc(t) { - t.beginPath(); - var e = this.glyphInfo; - if (e.length >= 1) { - var i = e[0].p0; - t.moveTo(i.x, i.y); - } - for (var r = 0; r < e.length; r++) { - var a = e[r].p1; - t.lineTo(a.x, a.y); - } - t.setAttr('lineWidth', this.fontSize()), - t.setAttr('strokeStyle', this.colorKey), - t.stroke(); - } - getTextWidth() { - return this.textWidth; - } - getTextHeight() { - return ( - u.warn( - 'text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.' - ), - this.textHeight - ); - } - setText(t) { - return Ht.prototype.setText.call(this, t); - } - _getContextFont() { - return Ht.prototype._getContextFont.call(this); - } - _getTextSize(t) { - var e = this.dummyCanvas.getContext('2d'); - e.save(), (e.font = this._getContextFont()); - var i = e.measureText(t); - return ( - e.restore(), - { width: i.width, height: parseInt(this.attrs.fontSize, 10) } - ); - } - _setTextData() { - var t = this, - e = this._getTextSize(this.attrs.text), - i = this.letterSpacing(), - r = this.align(), - a = this.kerningFunc(); - (this.textWidth = e.width), (this.textHeight = e.height); - var n = Math.max( - this.textWidth + ((this.attrs.text || '').length - 1) * i, - 0 - ); - this.glyphInfo = []; - for (var s = 0, o = 0; o < t.dataArray.length; o++) - t.dataArray[o].pathLength > 0 && (s += t.dataArray[o].pathLength); - var h = 0; - 'center' === r && (h = Math.max(0, s / 2 - n / 2)), - 'right' === r && (h = Math.max(0, s - n)); - for ( - var l, - d, - c, - g = Ft(this.text()), - u = this.text().split(' ').length - 1, - f = -1, - p = 0, - v = function () { - p = 0; - for (var e = t.dataArray, i = f + 1; i < e.length; i++) { - if (e[i].pathLength > 0) return (f = i), e[i]; - 'M' === e[i].command && - (l = { x: e[i].points[0], y: e[i].points[1] }); - } - return {}; - }, - m = function (e) { - var a = t._getTextSize(e).width + i; - ' ' === e && 'justify' === r && (a += (s - n) / u); - var o = 0, - h = 0; - for (d = void 0; Math.abs(a - o) / a > 0.01 && h < 20; ) { - h++; - for (var g = o; void 0 === c; ) - (c = v()) && - g + c.pathLength < a && - ((g += c.pathLength), (c = void 0)); - if (c === {} || void 0 === l) return; - var f = !1; - switch (c.command) { - case 'L': - Gt.getLineLength(l.x, l.y, c.points[0], c.points[1]) > a - ? (d = Gt.getPointOnLine( - a, - l.x, - l.y, - c.points[0], - c.points[1], - l.x, - l.y - )) - : (c = void 0); - break; - case 'A': - var m = c.points[4], - _ = c.points[5], - y = c.points[4] + _; - 0 === p - ? (p = m + 1e-8) - : a > o - ? (p += ((Math.PI / 180) * _) / Math.abs(_)) - : (p -= ((Math.PI / 360) * _) / Math.abs(_)), - ((_ < 0 && p < y) || (_ >= 0 && p > y)) && - ((p = y), (f = !0)), - (d = Gt.getPointOnEllipticalArc( - c.points[0], - c.points[1], - c.points[2], - c.points[3], - p, - c.points[6] - )); - break; - case 'C': - 0 === p - ? (p = a > c.pathLength ? 1e-8 : a / c.pathLength) - : a > o - ? (p += (a - o) / c.pathLength / 2) - : (p = Math.max(p - (o - a) / c.pathLength / 2, 0)), - p > 1 && ((p = 1), (f = !0)), - (d = Gt.getPointOnCubicBezier( - p, - c.start.x, - c.start.y, - c.points[0], - c.points[1], - c.points[2], - c.points[3], - c.points[4], - c.points[5] - )); - break; - case 'Q': - 0 === p - ? (p = a / c.pathLength) - : a > o - ? (p += (a - o) / c.pathLength) - : (p -= (o - a) / c.pathLength), - p > 1 && ((p = 1), (f = !0)), - (d = Gt.getPointOnQuadraticBezier( - p, - c.start.x, - c.start.y, - c.points[0], - c.points[1], - c.points[2], - c.points[3] - )); - } - void 0 !== d && (o = Gt.getLineLength(l.x, l.y, d.x, d.y)), - f && ((f = !1), (c = void 0)); - } - }, - _ = h / (t._getTextSize('C').width + i) - 1, - y = 0; - y < _ && (m('C'), void 0 !== l && void 0 !== d); - y++ - ) - l = d; - for ( - var x = 0; - x < g.length && (m(g[x]), void 0 !== l && void 0 !== d); - x++ - ) { - var b = Gt.getLineLength(l.x, l.y, d.x, d.y), - S = 0; - if (a) - try { - S = a(g[x - 1], g[x]) * this.fontSize(); - } catch (t) { - S = 0; - } - (l.x += S), (d.x += S), (this.textWidth += S); - var w = Gt.getPointOnLine(S + b / 2, l.x, l.y, d.x, d.y), - C = Math.atan2(d.y - l.y, d.x - l.x); - this.glyphInfo.push({ - transposeX: w.x, - transposeY: w.y, - text: g[x], - rotation: C, - p0: l, - p1: d, - }), - (l = d); - } - } - getSelfRect() { - if (!this.glyphInfo.length) return { x: 0, y: 0, width: 0, height: 0 }; - var t = []; - this.glyphInfo.forEach(function (e) { - t.push(e.p0.x), t.push(e.p0.y), t.push(e.p1.x), t.push(e.p1.y); - }); - for ( - var e, - i, - r = t[0] || 0, - a = t[0] || 0, - n = t[1] || 0, - s = t[1] || 0, - o = 0; - o < t.length / 2; - o++ - ) - (e = t[2 * o]), - (i = t[2 * o + 1]), - (r = Math.min(r, e)), - (a = Math.max(a, e)), - (n = Math.min(n, i)), - (s = Math.max(s, i)); - var h = this.fontSize(); - return { - x: r - h / 2, - y: n - h / 2, - width: a - r + h, - height: s - n + h, - }; - } - } - (jt.prototype._fillFunc = Yt), - (jt.prototype._strokeFunc = Xt), - (jt.prototype._fillFuncHit = Yt), - (jt.prototype._strokeFuncHit = Xt), - (jt.prototype.className = 'TextPath'), - (jt.prototype._attrsAffectingSize = ['text', 'fontSize', 'data']), - s(jt), - S.addGetterSetter(jt, 'data'), - S.addGetterSetter(jt, 'fontFamily', 'Arial'), - S.addGetterSetter(jt, 'fontSize', 12, v()), - S.addGetterSetter(jt, 'fontStyle', 'normal'), - S.addGetterSetter(jt, 'align', 'left'), - S.addGetterSetter(jt, 'letterSpacing', 0, v()), - S.addGetterSetter(jt, 'textBaseline', 'middle'), - S.addGetterSetter(jt, 'fontVariant', 'normal'), - S.addGetterSetter(jt, 'text', ''), - S.addGetterSetter(jt, 'textDecoration', null), - S.addGetterSetter(jt, 'kerningFunc', null); - var Ut = [ - 'resizeEnabledChange', - 'rotateAnchorOffsetChange', - 'rotateEnabledChange', - 'enabledAnchorsChange', - 'anchorSizeChange', - 'borderEnabledChange', - 'borderStrokeChange', - 'borderStrokeWidthChange', - 'borderDashChange', - 'anchorStrokeChange', - 'anchorStrokeWidthChange', - 'anchorFillChange', - 'anchorCornerRadiusChange', - 'ignoreStrokeChange', - ] - .map((t) => t + '.tr-konva') - .join(' '), - qt = [ - 'widthChange', - 'heightChange', - 'scaleXChange', - 'scaleYChange', - 'skewXChange', - 'skewYChange', - 'rotationChange', - 'offsetXChange', - 'offsetYChange', - 'transformsEnabledChange', - 'strokeWidthChange', - ] - .map((t) => t + '.tr-konva') - .join(' '), - Kt = { - 'top-left': -45, - 'top-center': 0, - 'top-right': 45, - 'middle-right': -90, - 'middle-left': 90, - 'bottom-left': -135, - 'bottom-center': 180, - 'bottom-right': 135, - }; - const Vt = 'ontouchstart' in a._global; - var Qt = [ - 'top-left', - 'top-center', - 'top-right', - 'middle-right', - 'middle-left', - 'bottom-left', - 'bottom-center', - 'bottom-right', - ]; - function Jt(t, e, i) { - const r = i.x + (t.x - i.x) * Math.cos(e) - (t.y - i.y) * Math.sin(e), - a = i.y + (t.x - i.x) * Math.sin(e) + (t.y - i.y) * Math.cos(e); - return Object.assign(Object.assign({}, t), { - rotation: t.rotation + e, - x: r, - y: a, - }); - } - function Zt(t, e) { - return Jt( - t, - e, - (function (t) { - return { - x: - t.x + - (t.width / 2) * Math.cos(t.rotation) + - (t.height / 2) * Math.sin(-t.rotation), - y: - t.y + - (t.height / 2) * Math.cos(t.rotation) + - (t.width / 2) * Math.sin(t.rotation), - }; - })(t) - ); - } - class $t extends dt { - constructor(t) { - super(t), - (this._transforming = !1), - this._createElements(), - (this._handleMouseMove = this._handleMouseMove.bind(this)), - (this._handleMouseUp = this._handleMouseUp.bind(this)), - (this.update = this.update.bind(this)), - this.on(Ut, this.update), - this.getNode() && this.update(); - } - attachTo(t) { - return this.setNode(t), this; - } - setNode(t) { - return ( - u.warn( - 'tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.' - ), - this.setNodes([t]) - ); - } - getNode() { - return this._nodes && this._nodes[0]; - } - setNodes(t = []) { - return ( - this._nodes && this._nodes.length && this.detach(), - (this._nodes = t), - 1 === t.length - ? this.rotation(t[0].getAbsoluteRotation()) - : this.rotation(0), - this._nodes.forEach((t) => { - const e = t._attrsAffectingSize - .map((t) => t + 'Change.tr-konva') - .join(' '), - i = () => { - 1 === this.nodes().length && - this.rotation(this.nodes()[0].getAbsoluteRotation()), - this._resetTransformCache(), - this._transforming || this.isDragging() || this.update(); - }; - t.on(e, i), - t.on(qt, i), - t.on('_clearTransformCache.tr-konva', i), - t.on('xChange.tr-konva yChange.tr-konva', i), - this._proxyDrag(t); - }), - this._resetTransformCache(), - !!this.findOne('.top-left') && this.update(), - this - ); - } - _proxyDrag(t) { - let e; - t.on('dragstart.tr-konva', (i) => { - (e = t.getAbsolutePosition()), - this.isDragging() || - t === this.findOne('.back') || - this.startDrag(i, !1); - }), - t.on('dragmove.tr-konva', (i) => { - if (!e) return; - const r = t.getAbsolutePosition(), - a = r.x - e.x, - n = r.y - e.y; - this.nodes().forEach((e) => { - if (e === t) return; - if (e.isDragging()) return; - const r = e.getAbsolutePosition(); - e.setAbsolutePosition({ x: r.x + a, y: r.y + n }), e.startDrag(i); - }), - (e = null); - }); - } - getNodes() { - return this._nodes || []; - } - getActiveAnchor() { - return this._movingAnchorName; - } - detach() { - this._nodes && - this._nodes.forEach((t) => { - t.off('.tr-konva'); - }), - (this._nodes = []), - this._resetTransformCache(); - } - _resetTransformCache() { - this._clearCache('nodesRect'), - this._clearCache('transform'), - this._clearSelfAndDescendantCache('absoluteTransform'); - } - _getNodeRect() { - return this._getCache('nodesRect', this.__getNodeRect); - } - __getNodeShape(t, e = this.rotation(), i) { - var r = t.getClientRect({ - skipTransform: !0, - skipShadow: !0, - skipStroke: this.ignoreStroke(), - }), - n = t.getAbsoluteScale(i), - s = t.getAbsolutePosition(i), - o = r.x * n.x - t.offsetX() * n.x, - h = r.y * n.y - t.offsetY() * n.y; - const l = - (a.getAngle(t.getAbsoluteRotation()) + 2 * Math.PI) % (2 * Math.PI); - return Jt( - { - x: s.x + o * Math.cos(l) + h * Math.sin(-l), - y: s.y + h * Math.cos(l) + o * Math.sin(l), - width: r.width * n.x, - height: r.height * n.y, - rotation: l, - }, - -a.getAngle(e), - { x: 0, y: 0 } - ); - } - __getNodeRect() { - if (!this.getNode()) - return { x: -1e8, y: -1e8, width: 0, height: 0, rotation: 0 }; - const t = []; - this.nodes().map((e) => { - const i = e.getClientRect({ - skipTransform: !0, - skipShadow: !0, - skipStroke: this.ignoreStroke(), - }); - var r = [ - { x: i.x, y: i.y }, - { x: i.x + i.width, y: i.y }, - { x: i.x + i.width, y: i.y + i.height }, - { x: i.x, y: i.y + i.height }, - ], - a = e.getAbsoluteTransform(); - r.forEach(function (e) { - var i = a.point(e); - t.push(i); - }); - }); - const e = new o(); - var i, r, n, s; - e.rotate(-a.getAngle(this.rotation())), - t.forEach(function (t) { - var a = e.point(t); - void 0 === i && ((i = n = a.x), (r = s = a.y)), - (i = Math.min(i, a.x)), - (r = Math.min(r, a.y)), - (n = Math.max(n, a.x)), - (s = Math.max(s, a.y)); - }), - e.invert(); - const h = e.point({ x: i, y: r }); - return { - x: h.x, - y: h.y, - width: n - i, - height: s - r, - rotation: a.getAngle(this.rotation()), - }; - } - getX() { - return this._getNodeRect().x; - } - getY() { - return this._getNodeRect().y; - } - getWidth() { - return this._getNodeRect().width; - } - getHeight() { - return this._getNodeRect().height; - } - _createElements() { - this._createBack(), - Qt.forEach( - function (t) { - this._createAnchor(t); - }.bind(this) - ), - this._createAnchor('rotater'); - } - _createAnchor(t) { - var e = new Et({ - stroke: 'rgb(0, 161, 255)', - fill: 'white', - strokeWidth: 1, - name: t + ' _anchor', - dragDistance: 0, - draggable: !0, - hitStrokeWidth: Vt ? 10 : 'auto', - }), - i = this; - e.on('mousedown touchstart', function (t) { - i._handleMouseDown(t); - }), - e.on('dragstart', (t) => { - e.stopDrag(), (t.cancelBubble = !0); - }), - e.on('dragend', (t) => { - t.cancelBubble = !0; - }), - e.on('mouseenter', () => { - var i = a.getAngle(this.rotation()), - r = (function (t, e) { - if ('rotater' === t) return 'crosshair'; - e += u._degToRad(Kt[t] || 0); - var i = ((u._radToDeg(e) % 360) + 360) % 360; - return u._inRange(i, 337.5, 360) || u._inRange(i, 0, 22.5) - ? 'ns-resize' - : u._inRange(i, 22.5, 67.5) - ? 'nesw-resize' - : u._inRange(i, 67.5, 112.5) - ? 'ew-resize' - : u._inRange(i, 112.5, 157.5) - ? 'nwse-resize' - : u._inRange(i, 157.5, 202.5) - ? 'ns-resize' - : u._inRange(i, 202.5, 247.5) - ? 'nesw-resize' - : u._inRange(i, 247.5, 292.5) - ? 'ew-resize' - : u._inRange(i, 292.5, 337.5) - ? 'nwse-resize' - : (u.error( - 'Transformer has unknown angle for cursor detection: ' + i - ), - 'pointer'); - })(t, i); - (e.getStage().content.style.cursor = r), (this._cursorChange = !0); - }), - e.on('mouseout', () => { - (e.getStage().content.style.cursor = ''), (this._cursorChange = !1); - }), - this.add(e); - } - _createBack() { - var t = new nt({ - name: 'back', - width: 0, - height: 0, - draggable: !0, - sceneFunc(t) { - var e = this.getParent(), - i = e.padding(); - t.beginPath(), - t.rect(-i, -i, this.width() + 2 * i, this.height() + 2 * i), - t.moveTo(this.width() / 2, -i), - e.rotateEnabled() && - t.lineTo( - this.width() / 2, - -e.rotateAnchorOffset() * u._sign(this.height()) - i - ), - t.fillStrokeShape(this); - }, - hitFunc: (t, e) => { - if (this.shouldOverdrawWholeArea()) { - var i = this.padding(); - t.beginPath(), - t.rect(-i, -i, e.width() + 2 * i, e.height() + 2 * i), - t.fillStrokeShape(e); - } - }, - }); - this.add(t), - this._proxyDrag(t), - t.on('dragstart', (t) => { - t.cancelBubble = !0; - }), - t.on('dragmove', (t) => { - t.cancelBubble = !0; - }), - t.on('dragend', (t) => { - t.cancelBubble = !0; - }); - } - _handleMouseDown(t) { - this._movingAnchorName = t.target.name().split(' ')[0]; - var e = this._getNodeRect(), - i = e.width, - r = e.height, - a = Math.sqrt(Math.pow(i, 2) + Math.pow(r, 2)); - (this.sin = Math.abs(r / a)), - (this.cos = Math.abs(i / a)), - window.addEventListener('mousemove', this._handleMouseMove), - window.addEventListener('touchmove', this._handleMouseMove), - window.addEventListener('mouseup', this._handleMouseUp, !0), - window.addEventListener('touchend', this._handleMouseUp, !0), - (this._transforming = !0); - var n = t.target.getAbsolutePosition(), - s = t.target.getStage().getPointerPosition(); - (this._anchorDragOffset = { x: s.x - n.x, y: s.y - n.y }), - this._fire('transformstart', { evt: t, target: this.getNode() }), - this._nodes.forEach((e) => { - e._fire('transformstart', { evt: t, target: e }); - }); - } - _handleMouseMove(t) { - var e, - i, - r, - n = this.findOne('.' + this._movingAnchorName), - s = n.getStage(); - s.setPointersPositions(t); - const o = s.getPointerPosition(); - var h = { - x: o.x - this._anchorDragOffset.x, - y: o.y - this._anchorDragOffset.y, - }; - const l = n.getAbsolutePosition(); - n.setAbsolutePosition(h); - const d = n.getAbsolutePosition(); - if (l.x !== d.x || l.y !== d.y) - if ('rotater' !== this._movingAnchorName) { - var c = this.keepRatio() || t.shiftKey, - g = this.centeredScaling() || t.altKey; - if ('top-left' === this._movingAnchorName) { - if (c) { - var u = g - ? { x: this.width() / 2, y: this.height() / 2 } - : { - x: this.findOne('.bottom-right').x(), - y: this.findOne('.bottom-right').y(), - }; - r = Math.sqrt( - Math.pow(u.x - n.x(), 2) + Math.pow(u.y - n.y(), 2) - ); - var f = this.findOne('.top-left').x() > u.x ? -1 : 1, - p = this.findOne('.top-left').y() > u.y ? -1 : 1; - (e = r * this.cos * f), - (i = r * this.sin * p), - this.findOne('.top-left').x(u.x - e), - this.findOne('.top-left').y(u.y - i); - } - } else if ('top-center' === this._movingAnchorName) - this.findOne('.top-left').y(n.y()); - else if ('top-right' === this._movingAnchorName) { - if (c) { - u = g - ? { x: this.width() / 2, y: this.height() / 2 } - : { - x: this.findOne('.bottom-left').x(), - y: this.findOne('.bottom-left').y(), - }; - r = Math.sqrt( - Math.pow(n.x() - u.x, 2) + Math.pow(u.y - n.y(), 2) - ); - (f = this.findOne('.top-right').x() < u.x ? -1 : 1), - (p = this.findOne('.top-right').y() > u.y ? -1 : 1); - (e = r * this.cos * f), - (i = r * this.sin * p), - this.findOne('.top-right').x(u.x + e), - this.findOne('.top-right').y(u.y - i); - } - var v = n.position(); - this.findOne('.top-left').y(v.y), - this.findOne('.bottom-right').x(v.x); - } else if ('middle-left' === this._movingAnchorName) - this.findOne('.top-left').x(n.x()); - else if ('middle-right' === this._movingAnchorName) - this.findOne('.bottom-right').x(n.x()); - else if ('bottom-left' === this._movingAnchorName) { - if (c) { - u = g - ? { x: this.width() / 2, y: this.height() / 2 } - : { - x: this.findOne('.top-right').x(), - y: this.findOne('.top-right').y(), - }; - r = Math.sqrt( - Math.pow(u.x - n.x(), 2) + Math.pow(n.y() - u.y, 2) - ); - (f = u.x < n.x() ? -1 : 1), (p = n.y() < u.y ? -1 : 1); - (e = r * this.cos * f), - (i = r * this.sin * p), - n.x(u.x - e), - n.y(u.y + i); - } - (v = n.position()), - this.findOne('.top-left').x(v.x), - this.findOne('.bottom-right').y(v.y); - } else if ('bottom-center' === this._movingAnchorName) - this.findOne('.bottom-right').y(n.y()); - else if ('bottom-right' === this._movingAnchorName) { - if (c) { - u = g - ? { x: this.width() / 2, y: this.height() / 2 } - : { - x: this.findOne('.top-left').x(), - y: this.findOne('.top-left').y(), - }; - r = Math.sqrt( - Math.pow(n.x() - u.x, 2) + Math.pow(n.y() - u.y, 2) - ); - (f = this.findOne('.bottom-right').x() < u.x ? -1 : 1), - (p = this.findOne('.bottom-right').y() < u.y ? -1 : 1); - (e = r * this.cos * f), - (i = r * this.sin * p), - this.findOne('.bottom-right').x(u.x + e), - this.findOne('.bottom-right').y(u.y + i); - } - } else - console.error( - new Error( - 'Wrong position argument of selection resizer: ' + - this._movingAnchorName - ) - ); - if ((g = this.centeredScaling() || t.altKey)) { - var m = this.findOne('.top-left'), - _ = this.findOne('.bottom-right'), - y = m.x(), - x = m.y(), - b = this.getWidth() - _.x(), - S = this.getHeight() - _.y(); - _.move({ x: -y, y: -x }), m.move({ x: b, y: S }); - } - var w = this.findOne('.top-left').getAbsolutePosition(); - (e = w.x), (i = w.y); - var C = - this.findOne('.bottom-right').x() - this.findOne('.top-left').x(), - P = - this.findOne('.bottom-right').y() - this.findOne('.top-left').y(); - this._fitNodesInto( - { - x: e, - y: i, - width: C, - height: P, - rotation: a.getAngle(this.rotation()), - }, - t - ); - } else { - var k = this._getNodeRect(); - (e = n.x() - k.width / 2), (i = -n.y() + k.height / 2); - let r = Math.atan2(-i, e) + Math.PI / 2; - k.height < 0 && (r -= Math.PI); - const s = a.getAngle(this.rotation()) + r, - o = a.getAngle(this.rotationSnapTolerance()), - h = Zt( - k, - (function (t, e, i) { - let r = e; - for (let n = 0; n < t.length; n++) { - const s = a.getAngle(t[n]), - o = Math.abs(s - e) % (2 * Math.PI); - Math.min(o, 2 * Math.PI - o) < i && (r = s); - } - return r; - })(this.rotationSnaps(), s, o) - k.rotation - ); - this._fitNodesInto(h, t); - } - } - _handleMouseUp(t) { - this._removeEvents(t); - } - getAbsoluteTransform() { - return this.getTransform(); - } - _removeEvents(t) { - if (this._transforming) { - (this._transforming = !1), - window.removeEventListener('mousemove', this._handleMouseMove), - window.removeEventListener('touchmove', this._handleMouseMove), - window.removeEventListener('mouseup', this._handleMouseUp, !0), - window.removeEventListener('touchend', this._handleMouseUp, !0); - var e = this.getNode(); - this._fire('transformend', { evt: t, target: e }), - e && - this._nodes.forEach((e) => { - e._fire('transformend', { evt: t, target: e }); - }), - (this._movingAnchorName = null); - } - } - _fitNodesInto(t, e) { - var i = this._getNodeRect(); - if (u._inRange(t.width, 2 * -this.padding() - 1, 1)) - return void this.update(); - if (u._inRange(t.height, 2 * -this.padding() - 1, 1)) - return void this.update(); - var r = new o(); - if ( - (r.rotate(a.getAngle(this.rotation())), - this._movingAnchorName && - t.width < 0 && - this._movingAnchorName.indexOf('left') >= 0) - ) { - const e = r.point({ x: 2 * -this.padding(), y: 0 }); - (t.x += e.x), - (t.y += e.y), - (t.width += 2 * this.padding()), - (this._movingAnchorName = this._movingAnchorName.replace( - 'left', - 'right' - )), - (this._anchorDragOffset.x -= e.x), - (this._anchorDragOffset.y -= e.y); - } else if ( - this._movingAnchorName && - t.width < 0 && - this._movingAnchorName.indexOf('right') >= 0 - ) { - const e = r.point({ x: 2 * this.padding(), y: 0 }); - (this._movingAnchorName = this._movingAnchorName.replace( - 'right', - 'left' - )), - (this._anchorDragOffset.x -= e.x), - (this._anchorDragOffset.y -= e.y), - (t.width += 2 * this.padding()); - } - if ( - this._movingAnchorName && - t.height < 0 && - this._movingAnchorName.indexOf('top') >= 0 - ) { - const e = r.point({ x: 0, y: 2 * -this.padding() }); - (t.x += e.x), - (t.y += e.y), - (this._movingAnchorName = this._movingAnchorName.replace( - 'top', - 'bottom' - )), - (this._anchorDragOffset.x -= e.x), - (this._anchorDragOffset.y -= e.y), - (t.height += 2 * this.padding()); - } else if ( - this._movingAnchorName && - t.height < 0 && - this._movingAnchorName.indexOf('bottom') >= 0 - ) { - const e = r.point({ x: 0, y: 2 * this.padding() }); - (this._movingAnchorName = this._movingAnchorName.replace( - 'bottom', - 'top' - )), - (this._anchorDragOffset.x -= e.x), - (this._anchorDragOffset.y -= e.y), - (t.height += 2 * this.padding()); - } - if (this.boundBoxFunc()) { - const e = this.boundBoxFunc()(i, t); - e - ? (t = e) - : u.warn( - 'boundBoxFunc returned falsy. You should return new bound rect from it!' - ); - } - const n = new o(); - n.translate(i.x, i.y), - n.rotate(i.rotation), - n.scale(i.width / 1e7, i.height / 1e7); - const s = new o(); - s.translate(t.x, t.y), - s.rotate(t.rotation), - s.scale(t.width / 1e7, t.height / 1e7); - const h = s.multiply(n.invert()); - this._nodes.forEach((t) => { - var i; - const r = t.getParent().getAbsoluteTransform(), - a = t.getTransform().copy(); - a.translate(t.offsetX(), t.offsetY()); - const n = new o(); - n.multiply(r.copy().invert()).multiply(h).multiply(r).multiply(a); - const s = n.decompose(); - t.setAttrs(s), - this._fire('transform', { evt: e, target: t }), - t._fire('transform', { evt: e, target: t }), - null === (i = t.getLayer()) || void 0 === i || i.batchDraw(); - }), - this.rotation(u._getRotation(t.rotation)), - this._resetTransformCache(), - this.update(), - this.getLayer().batchDraw(); - } - forceUpdate() { - this._resetTransformCache(), this.update(); - } - _batchChangeChild(t, e) { - this.findOne(t).setAttrs(e); - } - update() { - var t, - e = this._getNodeRect(); - this.rotation(u._getRotation(e.rotation)); - var i = e.width, - r = e.height, - a = this.enabledAnchors(), - n = this.resizeEnabled(), - s = this.padding(), - o = this.anchorSize(); - this.find('._anchor').forEach((t) => { - t.setAttrs({ - width: o, - height: o, - offsetX: o / 2, - offsetY: o / 2, - stroke: this.anchorStroke(), - strokeWidth: this.anchorStrokeWidth(), - fill: this.anchorFill(), - cornerRadius: this.anchorCornerRadius(), - }); - }), - this._batchChangeChild('.top-left', { - x: 0, - y: 0, - offsetX: o / 2 + s, - offsetY: o / 2 + s, - visible: n && a.indexOf('top-left') >= 0, - }), - this._batchChangeChild('.top-center', { - x: i / 2, - y: 0, - offsetY: o / 2 + s, - visible: n && a.indexOf('top-center') >= 0, - }), - this._batchChangeChild('.top-right', { - x: i, - y: 0, - offsetX: o / 2 - s, - offsetY: o / 2 + s, - visible: n && a.indexOf('top-right') >= 0, - }), - this._batchChangeChild('.middle-left', { - x: 0, - y: r / 2, - offsetX: o / 2 + s, - visible: n && a.indexOf('middle-left') >= 0, - }), - this._batchChangeChild('.middle-right', { - x: i, - y: r / 2, - offsetX: o / 2 - s, - visible: n && a.indexOf('middle-right') >= 0, - }), - this._batchChangeChild('.bottom-left', { - x: 0, - y: r, - offsetX: o / 2 + s, - offsetY: o / 2 - s, - visible: n && a.indexOf('bottom-left') >= 0, - }), - this._batchChangeChild('.bottom-center', { - x: i / 2, - y: r, - offsetY: o / 2 - s, - visible: n && a.indexOf('bottom-center') >= 0, - }), - this._batchChangeChild('.bottom-right', { - x: i, - y: r, - offsetX: o / 2 - s, - offsetY: o / 2 - s, - visible: n && a.indexOf('bottom-right') >= 0, - }), - this._batchChangeChild('.rotater', { - x: i / 2, - y: -this.rotateAnchorOffset() * u._sign(r) - s, - visible: this.rotateEnabled(), - }), - this._batchChangeChild('.back', { - width: i, - height: r, - visible: this.borderEnabled(), - stroke: this.borderStroke(), - strokeWidth: this.borderStrokeWidth(), - dash: this.borderDash(), - x: 0, - y: 0, - }), - null === (t = this.getLayer()) || void 0 === t || t.batchDraw(); - } - isTransforming() { - return this._transforming; - } - stopTransform() { - if (this._transforming) { - this._removeEvents(); - var t = this.findOne('.' + this._movingAnchorName); - t && t.stopDrag(); - } - } - destroy() { - return ( - this.getStage() && - this._cursorChange && - (this.getStage().content.style.cursor = ''), - dt.prototype.destroy.call(this), - this.detach(), - this._removeEvents(), - this - ); - } - toObject() { - return z.prototype.toObject.call(this); - } - } - ($t.prototype.className = 'Transformer'), - s($t), - S.addGetterSetter($t, 'enabledAnchors', Qt, function (t) { - return ( - t instanceof Array || u.warn('enabledAnchors value should be an array'), - t instanceof Array && - t.forEach(function (t) { - -1 === Qt.indexOf(t) && - u.warn( - 'Unknown anchor name: ' + - t + - '. Available names are: ' + - Qt.join(', ') - ); - }), - t || [] - ); - }), - S.addGetterSetter($t, 'resizeEnabled', !0), - S.addGetterSetter($t, 'anchorSize', 10, v()), - S.addGetterSetter($t, 'rotateEnabled', !0), - S.addGetterSetter($t, 'rotationSnaps', []), - S.addGetterSetter($t, 'rotateAnchorOffset', 50, v()), - S.addGetterSetter($t, 'rotationSnapTolerance', 5, v()), - S.addGetterSetter($t, 'borderEnabled', !0), - S.addGetterSetter($t, 'anchorStroke', 'rgb(0, 161, 255)'), - S.addGetterSetter($t, 'anchorStrokeWidth', 1, v()), - S.addGetterSetter($t, 'anchorFill', 'white'), - S.addGetterSetter($t, 'anchorCornerRadius', 0, v()), - S.addGetterSetter($t, 'borderStroke', 'rgb(0, 161, 255)'), - S.addGetterSetter($t, 'borderStrokeWidth', 1, v()), - S.addGetterSetter($t, 'borderDash'), - S.addGetterSetter($t, 'keepRatio', !0), - S.addGetterSetter($t, 'centeredScaling', !1), - S.addGetterSetter($t, 'ignoreStroke', !1), - S.addGetterSetter($t, 'padding', 0, v()), - S.addGetterSetter($t, 'node'), - S.addGetterSetter($t, 'nodes'), - S.addGetterSetter($t, 'boundBoxFunc'), - S.addGetterSetter($t, 'shouldOverdrawWholeArea', !1), - S.backCompat($t, { - lineEnabled: 'borderEnabled', - rotateHandlerOffset: 'rotateAnchorOffset', - enabledHandlers: 'enabledAnchors', - }); - class te extends nt { - _sceneFunc(t) { - t.beginPath(), - t.arc( - 0, - 0, - this.radius(), - 0, - a.getAngle(this.angle()), - this.clockwise() - ), - t.lineTo(0, 0), - t.closePath(), - t.fillStrokeShape(this); - } - getWidth() { - return 2 * this.radius(); - } - getHeight() { - return 2 * this.radius(); - } - setWidth(t) { - this.radius(t / 2); - } - setHeight(t) { - this.radius(t / 2); - } - } - function ee() { - (this.r = 0), (this.g = 0), (this.b = 0), (this.a = 0), (this.next = null); - } - (te.prototype.className = 'Wedge'), - (te.prototype._centroid = !0), - (te.prototype._attrsAffectingSize = ['radius']), - s(te), - S.addGetterSetter(te, 'radius', 0, v()), - S.addGetterSetter(te, 'angle', 0, v()), - S.addGetterSetter(te, 'clockwise', !1), - S.backCompat(te, { - angleDeg: 'angle', - getAngleDeg: 'getAngle', - setAngleDeg: 'setAngle', - }); - var ie = [ - 512, - 512, - 456, - 512, - 328, - 456, - 335, - 512, - 405, - 328, - 271, - 456, - 388, - 335, - 292, - 512, - 454, - 405, - 364, - 328, - 298, - 271, - 496, - 456, - 420, - 388, - 360, - 335, - 312, - 292, - 273, - 512, - 482, - 454, - 428, - 405, - 383, - 364, - 345, - 328, - 312, - 298, - 284, - 271, - 259, - 496, - 475, - 456, - 437, - 420, - 404, - 388, - 374, - 360, - 347, - 335, - 323, - 312, - 302, - 292, - 282, - 273, - 265, - 512, - 497, - 482, - 468, - 454, - 441, - 428, - 417, - 405, - 394, - 383, - 373, - 364, - 354, - 345, - 337, - 328, - 320, - 312, - 305, - 298, - 291, - 284, - 278, - 271, - 265, - 259, - 507, - 496, - 485, - 475, - 465, - 456, - 446, - 437, - 428, - 420, - 412, - 404, - 396, - 388, - 381, - 374, - 367, - 360, - 354, - 347, - 341, - 335, - 329, - 323, - 318, - 312, - 307, - 302, - 297, - 292, - 287, - 282, - 278, - 273, - 269, - 265, - 261, - 512, - 505, - 497, - 489, - 482, - 475, - 468, - 461, - 454, - 447, - 441, - 435, - 428, - 422, - 417, - 411, - 405, - 399, - 394, - 389, - 383, - 378, - 373, - 368, - 364, - 359, - 354, - 350, - 345, - 341, - 337, - 332, - 328, - 324, - 320, - 316, - 312, - 309, - 305, - 301, - 298, - 294, - 291, - 287, - 284, - 281, - 278, - 274, - 271, - 268, - 265, - 262, - 259, - 257, - 507, - 501, - 496, - 491, - 485, - 480, - 475, - 470, - 465, - 460, - 456, - 451, - 446, - 442, - 437, - 433, - 428, - 424, - 420, - 416, - 412, - 408, - 404, - 400, - 396, - 392, - 388, - 385, - 381, - 377, - 374, - 370, - 367, - 363, - 360, - 357, - 354, - 350, - 347, - 344, - 341, - 338, - 335, - 332, - 329, - 326, - 323, - 320, - 318, - 315, - 312, - 310, - 307, - 304, - 302, - 299, - 297, - 294, - 292, - 289, - 287, - 285, - 282, - 280, - 278, - 275, - 273, - 271, - 269, - 267, - 265, - 263, - 261, - 259, - ], - re = [ - 9, - 11, - 12, - 13, - 13, - 14, - 14, - 15, - 15, - 15, - 15, - 16, - 16, - 16, - 16, - 17, - 17, - 17, - 17, - 17, - 17, - 17, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - ]; - S.addGetterSetter(z, 'blurRadius', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'brightness', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'contrast', 0, v(), S.afterSetFilter); - function ae(t, e, i, r, a) { - var n = i - e, - s = a - r; - return 0 === n ? r + s / 2 : 0 === s ? r : s * ((t - e) / n) + r; - } - S.addGetterSetter(z, 'embossStrength', 0.5, v(), S.afterSetFilter), - S.addGetterSetter(z, 'embossWhiteLevel', 0.5, v(), S.afterSetFilter), - S.addGetterSetter(z, 'embossDirection', 'top-left', null, S.afterSetFilter), - S.addGetterSetter(z, 'embossBlend', !1, null, S.afterSetFilter); - S.addGetterSetter(z, 'enhance', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'hue', 0, v(), S.afterSetFilter), - S.addGetterSetter(z, 'saturation', 0, v(), S.afterSetFilter), - S.addGetterSetter(z, 'luminance', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'hue', 0, v(), S.afterSetFilter), - S.addGetterSetter(z, 'saturation', 0, v(), S.afterSetFilter), - S.addGetterSetter(z, 'value', 0, v(), S.afterSetFilter); - function ne(t, e, i) { - var r = 4 * (i * t.width + e), - a = []; - return a.push(t.data[r++], t.data[r++], t.data[r++], t.data[r++]), a; - } - function se(t, e) { - return Math.sqrt( - Math.pow(t[0] - e[0], 2) + - Math.pow(t[1] - e[1], 2) + - Math.pow(t[2] - e[2], 2) - ); - } - S.addGetterSetter(z, 'kaleidoscopePower', 2, v(), S.afterSetFilter), - S.addGetterSetter(z, 'kaleidoscopeAngle', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'threshold', 0, v(), S.afterSetFilter); - S.addGetterSetter(z, 'noise', 0.2, v(), S.afterSetFilter); - S.addGetterSetter(z, 'pixelSize', 8, v(), S.afterSetFilter); - S.addGetterSetter(z, 'levels', 0.5, v(), S.afterSetFilter); - S.addGetterSetter(z, 'red', 0, function (t) { - return ( - (this._filterUpToDate = !1), t > 255 ? 255 : t < 0 ? 0 : Math.round(t) - ); - }), - S.addGetterSetter(z, 'green', 0, function (t) { - return ( - (this._filterUpToDate = !1), t > 255 ? 255 : t < 0 ? 0 : Math.round(t) - ); - }), - S.addGetterSetter(z, 'blue', 0, p, S.afterSetFilter); - S.addGetterSetter(z, 'red', 0, function (t) { - return ( - (this._filterUpToDate = !1), t > 255 ? 255 : t < 0 ? 0 : Math.round(t) - ); - }), - S.addGetterSetter(z, 'green', 0, function (t) { - return ( - (this._filterUpToDate = !1), t > 255 ? 255 : t < 0 ? 0 : Math.round(t) - ); - }), - S.addGetterSetter(z, 'blue', 0, p, S.afterSetFilter), - S.addGetterSetter(z, 'alpha', 1, function (t) { - return (this._filterUpToDate = !1), t > 1 ? 1 : t < 0 ? 0 : t; - }); - S.addGetterSetter(z, 'threshold', 0.5, v(), S.afterSetFilter); - return yt.Util._assign(yt, { - Arc: xt, - Arrow: St, - Circle: wt, - Ellipse: Ct, - Image: Pt, - Label: At, - Tag: Mt, - Line: bt, - Path: Gt, - Rect: Et, - RegularPolygon: Rt, - Ring: Dt, - Sprite: It, - Star: Ot, - Text: Ht, - TextPath: jt, - Transformer: $t, - Wedge: te, - Filters: { - Blur: function (t) { - var e = Math.round(this.blurRadius()); - e > 0 && - (function (t, e) { - var i, - r, - a, - n, - s, - o, - h, - l, - d, - c, - g, - u, - f, - p, - v, - m, - _, - y, - x, - b, - S, - w, - C, - P, - k = t.data, - T = t.width, - A = t.height, - M = e + e + 1, - G = T - 1, - E = A - 1, - R = e + 1, - L = (R * (R + 1)) / 2, - D = new ee(), - I = null, - O = D, - F = null, - B = null, - N = ie[e], - z = re[e]; - for (a = 1; a < M; a++) (O = O.next = new ee()), a === R && (I = O); - for (O.next = D, h = o = 0, r = 0; r < A; r++) { - for ( - m = _ = y = x = l = d = c = g = 0, - u = R * (b = k[o]), - f = R * (S = k[o + 1]), - p = R * (w = k[o + 2]), - v = R * (C = k[o + 3]), - l += L * b, - d += L * S, - c += L * w, - g += L * C, - O = D, - a = 0; - a < R; - a++ - ) - (O.r = b), (O.g = S), (O.b = w), (O.a = C), (O = O.next); - for (a = 1; a < R; a++) - (n = o + ((G < a ? G : a) << 2)), - (l += (O.r = b = k[n]) * (P = R - a)), - (d += (O.g = S = k[n + 1]) * P), - (c += (O.b = w = k[n + 2]) * P), - (g += (O.a = C = k[n + 3]) * P), - (m += b), - (_ += S), - (y += w), - (x += C), - (O = O.next); - for (F = D, B = I, i = 0; i < T; i++) - (k[o + 3] = C = (g * N) >> z), - 0 !== C - ? ((C = 255 / C), - (k[o] = ((l * N) >> z) * C), - (k[o + 1] = ((d * N) >> z) * C), - (k[o + 2] = ((c * N) >> z) * C)) - : (k[o] = k[o + 1] = k[o + 2] = 0), - (l -= u), - (d -= f), - (c -= p), - (g -= v), - (u -= F.r), - (f -= F.g), - (p -= F.b), - (v -= F.a), - (n = (h + ((n = i + e + 1) < G ? n : G)) << 2), - (l += m += F.r = k[n]), - (d += _ += F.g = k[n + 1]), - (c += y += F.b = k[n + 2]), - (g += x += F.a = k[n + 3]), - (F = F.next), - (u += b = B.r), - (f += S = B.g), - (p += w = B.b), - (v += C = B.a), - (m -= b), - (_ -= S), - (y -= w), - (x -= C), - (B = B.next), - (o += 4); - h += T; - } - for (i = 0; i < T; i++) { - for ( - _ = y = x = m = d = c = g = l = 0, - u = R * (b = k[(o = i << 2)]), - f = R * (S = k[o + 1]), - p = R * (w = k[o + 2]), - v = R * (C = k[o + 3]), - l += L * b, - d += L * S, - c += L * w, - g += L * C, - O = D, - a = 0; - a < R; - a++ - ) - (O.r = b), (O.g = S), (O.b = w), (O.a = C), (O = O.next); - for (s = T, a = 1; a <= e; a++) - (o = (s + i) << 2), - (l += (O.r = b = k[o]) * (P = R - a)), - (d += (O.g = S = k[o + 1]) * P), - (c += (O.b = w = k[o + 2]) * P), - (g += (O.a = C = k[o + 3]) * P), - (m += b), - (_ += S), - (y += w), - (x += C), - (O = O.next), - a < E && (s += T); - for (o = i, F = D, B = I, r = 0; r < A; r++) - (k[(n = o << 2) + 3] = C = (g * N) >> z), - C > 0 - ? ((C = 255 / C), - (k[n] = ((l * N) >> z) * C), - (k[n + 1] = ((d * N) >> z) * C), - (k[n + 2] = ((c * N) >> z) * C)) - : (k[n] = k[n + 1] = k[n + 2] = 0), - (l -= u), - (d -= f), - (c -= p), - (g -= v), - (u -= F.r), - (f -= F.g), - (p -= F.b), - (v -= F.a), - (n = (i + ((n = r + R) < E ? n : E) * T) << 2), - (l += m += F.r = k[n]), - (d += _ += F.g = k[n + 1]), - (c += y += F.b = k[n + 2]), - (g += x += F.a = k[n + 3]), - (F = F.next), - (u += b = B.r), - (f += S = B.g), - (p += w = B.b), - (v += C = B.a), - (m -= b), - (_ -= S), - (y -= w), - (x -= C), - (B = B.next), - (o += T); - } - })(t, e); - }, - Brighten: function (t) { - var e, - i = 255 * this.brightness(), - r = t.data, - a = r.length; - for (e = 0; e < a; e += 4) - (r[e] += i), (r[e + 1] += i), (r[e + 2] += i); - }, - Contrast: function (t) { - var e, - i = Math.pow((this.contrast() + 100) / 100, 2), - r = t.data, - a = r.length, - n = 150, - s = 150, - o = 150; - for (e = 0; e < a; e += 4) - (n = r[e]), - (s = r[e + 1]), - (o = r[e + 2]), - (n /= 255), - (n -= 0.5), - (n *= i), - (n += 0.5), - (s /= 255), - (s -= 0.5), - (s *= i), - (s += 0.5), - (o /= 255), - (o -= 0.5), - (o *= i), - (o += 0.5), - (n = (n *= 255) < 0 ? 0 : n > 255 ? 255 : n), - (s = (s *= 255) < 0 ? 0 : s > 255 ? 255 : s), - (o = (o *= 255) < 0 ? 0 : o > 255 ? 255 : o), - (r[e] = n), - (r[e + 1] = s), - (r[e + 2] = o); - }, - Emboss: function (t) { - var e = 10 * this.embossStrength(), - i = 255 * this.embossWhiteLevel(), - r = this.embossDirection(), - a = this.embossBlend(), - n = 0, - s = 0, - o = t.data, - h = t.width, - l = t.height, - d = 4 * h, - c = l; - switch (r) { - case 'top-left': - (n = -1), (s = -1); - break; - case 'top': - (n = -1), (s = 0); - break; - case 'top-right': - (n = -1), (s = 1); - break; - case 'right': - (n = 0), (s = 1); - break; - case 'bottom-right': - (n = 1), (s = 1); - break; - case 'bottom': - (n = 1), (s = 0); - break; - case 'bottom-left': - (n = 1), (s = -1); - break; - case 'left': - (n = 0), (s = -1); - break; - default: - u.error('Unknown emboss direction: ' + r); - } - do { - var g = (c - 1) * d, - f = n; - c + f < 1 && (f = 0), c + f > l && (f = 0); - var p = (c - 1 + f) * h * 4, - v = h; - do { - var m = g + 4 * (v - 1), - _ = s; - v + _ < 1 && (_ = 0), v + _ > h && (_ = 0); - var y = p + 4 * (v - 1 + _), - x = o[m] - o[y], - b = o[m + 1] - o[y + 1], - S = o[m + 2] - o[y + 2], - w = x, - C = w > 0 ? w : -w; - if ( - ((b > 0 ? b : -b) > C && (w = b), - (S > 0 ? S : -S) > C && (w = S), - (w *= e), - a) - ) { - var P = o[m] + w, - k = o[m + 1] + w, - T = o[m + 2] + w; - (o[m] = P > 255 ? 255 : P < 0 ? 0 : P), - (o[m + 1] = k > 255 ? 255 : k < 0 ? 0 : k), - (o[m + 2] = T > 255 ? 255 : T < 0 ? 0 : T); - } else { - var A = i - w; - A < 0 ? (A = 0) : A > 255 && (A = 255), - (o[m] = o[m + 1] = o[m + 2] = A); - } - } while (--v); - } while (--c); - }, - Enhance: function (t) { - var e, - i, - r, - a, - n = t.data, - s = n.length, - o = n[0], - h = o, - l = n[1], - d = l, - c = n[2], - g = c, - u = this.enhance(); - if (0 !== u) { - for (a = 0; a < s; a += 4) - (e = n[a + 0]) < o ? (o = e) : e > h && (h = e), - (i = n[a + 1]) < l ? (l = i) : i > d && (d = i), - (r = n[a + 2]) < c ? (c = r) : r > g && (g = r); - var f, p, v, m, _, y, x, b, S; - for ( - h === o && ((h = 255), (o = 0)), - d === l && ((d = 255), (l = 0)), - g === c && ((g = 255), (c = 0)), - u > 0 - ? ((p = h + u * (255 - h)), - (v = o - u * (o - 0)), - (_ = d + u * (255 - d)), - (y = l - u * (l - 0)), - (b = g + u * (255 - g)), - (S = c - u * (c - 0))) - : ((p = h + u * (h - (f = 0.5 * (h + o)))), - (v = o + u * (o - f)), - (_ = d + u * (d - (m = 0.5 * (d + l)))), - (y = l + u * (l - m)), - (b = g + u * (g - (x = 0.5 * (g + c)))), - (S = c + u * (c - x))), - a = 0; - a < s; - a += 4 - ) - (n[a + 0] = ae(n[a + 0], o, h, v, p)), - (n[a + 1] = ae(n[a + 1], l, d, y, _)), - (n[a + 2] = ae(n[a + 2], c, g, S, b)); - } - }, - Grayscale: function (t) { - var e, - i, - r = t.data, - a = r.length; - for (e = 0; e < a; e += 4) - (i = 0.34 * r[e] + 0.5 * r[e + 1] + 0.16 * r[e + 2]), - (r[e] = i), - (r[e + 1] = i), - (r[e + 2] = i); - }, - HSL: function (t) { - var e, - i, - r, - a, - n, - s = t.data, - o = s.length, - h = Math.pow(2, this.saturation()), - l = Math.abs(this.hue() + 360) % 360, - d = 127 * this.luminance(), - c = 1 * h * Math.cos((l * Math.PI) / 180), - g = 1 * h * Math.sin((l * Math.PI) / 180), - u = 0.299 + 0.701 * c + 0.167 * g, - f = 0.587 - 0.587 * c + 0.33 * g, - p = 0.114 - 0.114 * c - 0.497 * g, - v = 0.299 - 0.299 * c - 0.328 * g, - m = 0.587 + 0.413 * c + 0.035 * g, - _ = 0.114 - 0.114 * c + 0.293 * g, - y = 0.299 - 0.3 * c + 1.25 * g, - x = 0.587 - 0.586 * c - 1.05 * g, - b = 0.114 + 0.886 * c - 0.2 * g; - for (e = 0; e < o; e += 4) - (i = s[e + 0]), - (r = s[e + 1]), - (a = s[e + 2]), - (n = s[e + 3]), - (s[e + 0] = u * i + f * r + p * a + d), - (s[e + 1] = v * i + m * r + _ * a + d), - (s[e + 2] = y * i + x * r + b * a + d), - (s[e + 3] = n); - }, - HSV: function (t) { - var e, - i, - r, - a, - n, - s = t.data, - o = s.length, - h = Math.pow(2, this.value()), - l = Math.pow(2, this.saturation()), - d = Math.abs(this.hue() + 360) % 360, - c = h * l * Math.cos((d * Math.PI) / 180), - g = h * l * Math.sin((d * Math.PI) / 180), - u = 0.299 * h + 0.701 * c + 0.167 * g, - f = 0.587 * h - 0.587 * c + 0.33 * g, - p = 0.114 * h - 0.114 * c - 0.497 * g, - v = 0.299 * h - 0.299 * c - 0.328 * g, - m = 0.587 * h + 0.413 * c + 0.035 * g, - _ = 0.114 * h - 0.114 * c + 0.293 * g, - y = 0.299 * h - 0.3 * c + 1.25 * g, - x = 0.587 * h - 0.586 * c - 1.05 * g, - b = 0.114 * h + 0.886 * c - 0.2 * g; - for (e = 0; e < o; e += 4) - (i = s[e + 0]), - (r = s[e + 1]), - (a = s[e + 2]), - (n = s[e + 3]), - (s[e + 0] = u * i + f * r + p * a), - (s[e + 1] = v * i + m * r + _ * a), - (s[e + 2] = y * i + x * r + b * a), - (s[e + 3] = n); - }, - Invert: function (t) { - var e, - i = t.data, - r = i.length; - for (e = 0; e < r; e += 4) - (i[e] = 255 - i[e]), - (i[e + 1] = 255 - i[e + 1]), - (i[e + 2] = 255 - i[e + 2]); - }, - Kaleidoscope: function (t) { - var e, - i, - r, - a, - n, - s, - o, - h, - l, - d = t.width, - c = t.height, - g = Math.round(this.kaleidoscopePower()), - f = Math.round(this.kaleidoscopeAngle()), - p = Math.floor((d * (f % 360)) / 360); - if (!(g < 1)) { - var v = u.createCanvasElement(); - (v.width = d), (v.height = c); - var m = v.getContext('2d').getImageData(0, 0, d, c); - !(function (t, e, i) { - var r, - a, - n, - s, - o = t.data, - h = e.data, - l = t.width, - d = t.height, - c = i.polarCenterX || l / 2, - g = i.polarCenterY || d / 2, - u = 0, - f = 0, - p = 0, - v = 0, - m = Math.sqrt(c * c + g * g); - (a = l - c), - (n = d - g), - (m = (s = Math.sqrt(a * a + n * n)) > m ? s : m); - var _, - y, - x, - b, - S = d, - w = l, - C = ((360 / w) * Math.PI) / 180; - for (y = 0; y < w; y += 1) - for ( - x = Math.sin(y * C), b = Math.cos(y * C), _ = 0; - _ < S; - _ += 1 - ) - (a = Math.floor(c + ((m * _) / S) * b)), - (u = - o[ - (r = - 4 * ((n = Math.floor(g + ((m * _) / S) * x)) * l + a)) + - 0 - ]), - (f = o[r + 1]), - (p = o[r + 2]), - (v = o[r + 3]), - (h[(r = 4 * (y + _ * l)) + 0] = u), - (h[r + 1] = f), - (h[r + 2] = p), - (h[r + 3] = v); - })(t, m, { polarCenterX: d / 2, polarCenterY: c / 2 }); - for (var _ = d / Math.pow(2, g); _ <= 8; ) (_ *= 2), (g -= 1); - var y = (_ = Math.ceil(_)), - x = 0, - b = y, - S = 1; - for (p + _ > d && ((x = y), (b = 0), (S = -1)), i = 0; i < c; i += 1) - for (e = x; e !== b; e += S) - (h = 4 * (d * i + (Math.round(e + p) % d))), - (a = m.data[h + 0]), - (n = m.data[h + 1]), - (s = m.data[h + 2]), - (o = m.data[h + 3]), - (l = 4 * (d * i + e)), - (m.data[l + 0] = a), - (m.data[l + 1] = n), - (m.data[l + 2] = s), - (m.data[l + 3] = o); - for (i = 0; i < c; i += 1) - for (y = Math.floor(_), r = 0; r < g; r += 1) { - for (e = 0; e < y + 1; e += 1) - (h = 4 * (d * i + e)), - (a = m.data[h + 0]), - (n = m.data[h + 1]), - (s = m.data[h + 2]), - (o = m.data[h + 3]), - (l = 4 * (d * i + 2 * y - e - 1)), - (m.data[l + 0] = a), - (m.data[l + 1] = n), - (m.data[l + 2] = s), - (m.data[l + 3] = o); - y *= 2; - } - !(function (t, e, i) { - var r, - a, - n, - s, - o, - h, - l = t.data, - d = e.data, - c = t.width, - g = t.height, - u = i.polarCenterX || c / 2, - f = i.polarCenterY || g / 2, - p = 0, - v = 0, - m = 0, - _ = 0, - y = Math.sqrt(u * u + f * f); - (a = c - u), - (n = g - f), - (y = (h = Math.sqrt(a * a + n * n)) > y ? h : y); - var x, - b, - S, - w = g, - C = c, - P = i.polarRotation || 0; - for (a = 0; a < c; a += 1) - for (n = 0; n < g; n += 1) - (s = a - u), - (o = n - f), - (x = (Math.sqrt(s * s + o * o) * w) / y), - (b = - ((b = - ((180 * Math.atan2(o, s)) / Math.PI + 360 + P) % 360) * - C) / - 360), - (S = Math.floor(b)), - (p = l[(r = 4 * (Math.floor(x) * c + S)) + 0]), - (v = l[r + 1]), - (m = l[r + 2]), - (_ = l[r + 3]), - (d[(r = 4 * (n * c + a)) + 0] = p), - (d[r + 1] = v), - (d[r + 2] = m), - (d[r + 3] = _); - })(m, t, { polarRotation: 0 }); - } - }, - Mask: function (t) { - var e = (function (t, e) { - var i = ne(t, 0, 0), - r = ne(t, t.width - 1, 0), - a = ne(t, 0, t.height - 1), - n = ne(t, t.width - 1, t.height - 1), - s = e || 10; - if (se(i, r) < s && se(r, n) < s && se(n, a) < s && se(a, i) < s) { - for ( - var o = (function (t) { - for (var e = [0, 0, 0], i = 0; i < t.length; i++) - (e[0] += t[i][0]), (e[1] += t[i][1]), (e[2] += t[i][2]); - return ( - (e[0] /= t.length), - (e[1] /= t.length), - (e[2] /= t.length), - e - ); - })([r, i, n, a]), - h = [], - l = 0; - l < t.width * t.height; - l++ - ) { - var d = se(o, [ - t.data[4 * l], - t.data[4 * l + 1], - t.data[4 * l + 2], - ]); - h[l] = d < s ? 0 : 255; - } - return h; - } - })(t, this.threshold()); - return ( - e && - (function (t, e) { - for (var i = 0; i < t.width * t.height; i++) - t.data[4 * i + 3] = e[i]; - })( - t, - (e = (function (t, e, i) { - for ( - var r = [ - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - 1 / 9, - ], - a = Math.round(Math.sqrt(r.length)), - n = Math.floor(a / 2), - s = [], - o = 0; - o < i; - o++ - ) - for (var h = 0; h < e; h++) { - for (var l = o * e + h, d = 0, c = 0; c < a; c++) - for (var g = 0; g < a; g++) { - var u = o + c - n, - f = h + g - n; - if (u >= 0 && u < i && f >= 0 && f < e) { - var p = r[c * a + g]; - d += t[u * e + f] * p; - } - } - s[l] = d; - } - return s; - })( - (e = (function (t, e, i) { - for ( - var r = [1, 1, 1, 1, 1, 1, 1, 1, 1], - a = Math.round(Math.sqrt(r.length)), - n = Math.floor(a / 2), - s = [], - o = 0; - o < i; - o++ - ) - for (var h = 0; h < e; h++) { - for (var l = o * e + h, d = 0, c = 0; c < a; c++) - for (var g = 0; g < a; g++) { - var u = o + c - n, - f = h + g - n; - if (u >= 0 && u < i && f >= 0 && f < e) { - var p = r[c * a + g]; - d += t[u * e + f] * p; - } - } - s[l] = d >= 1020 ? 255 : 0; - } - return s; - })( - (e = (function (t, e, i) { - for ( - var r = [1, 1, 1, 1, 0, 1, 1, 1, 1], - a = Math.round(Math.sqrt(r.length)), - n = Math.floor(a / 2), - s = [], - o = 0; - o < i; - o++ - ) - for (var h = 0; h < e; h++) { - for (var l = o * e + h, d = 0, c = 0; c < a; c++) - for (var g = 0; g < a; g++) { - var u = o + c - n, - f = h + g - n; - if (u >= 0 && u < i && f >= 0 && f < e) { - var p = r[c * a + g]; - d += t[u * e + f] * p; - } - } - s[l] = 2040 === d ? 255 : 0; - } - return s; - })(e, t.width, t.height)), - t.width, - t.height - )), - t.width, - t.height - )) - ), - t - ); - }, - Noise: function (t) { - var e, - i = 255 * this.noise(), - r = t.data, - a = r.length, - n = i / 2; - for (e = 0; e < a; e += 4) - (r[e + 0] += n - 2 * n * Math.random()), - (r[e + 1] += n - 2 * n * Math.random()), - (r[e + 2] += n - 2 * n * Math.random()); - }, - Pixelate: function (t) { - var e, - i, - r, - a, - n, - s, - o, - h, - l, - d, - c, - g, - f, - p, - v = Math.ceil(this.pixelSize()), - m = t.width, - _ = t.height, - y = Math.ceil(m / v), - x = Math.ceil(_ / v), - b = t.data; - if (v <= 0) u.error('pixelSize value can not be <= 0'); - else - for (g = 0; g < y; g += 1) - for (f = 0; f < x; f += 1) { - for ( - a = 0, - n = 0, - s = 0, - o = 0, - l = (h = g * v) + v, - c = (d = f * v) + v, - p = 0, - e = h; - e < l; - e += 1 - ) - if (!(e >= m)) - for (i = d; i < c; i += 1) - i >= _ || - ((a += b[(r = 4 * (m * i + e)) + 0]), - (n += b[r + 1]), - (s += b[r + 2]), - (o += b[r + 3]), - (p += 1)); - for (a /= p, n /= p, s /= p, o /= p, e = h; e < l; e += 1) - if (!(e >= m)) - for (i = d; i < c; i += 1) - i >= _ || - ((b[(r = 4 * (m * i + e)) + 0] = a), - (b[r + 1] = n), - (b[r + 2] = s), - (b[r + 3] = o)); - } - }, - Posterize: function (t) { - var e, - i = Math.round(254 * this.levels()) + 1, - r = t.data, - a = r.length, - n = 255 / i; - for (e = 0; e < a; e += 1) r[e] = Math.floor(r[e] / n) * n; - }, - RGB: function (t) { - var e, - i, - r = t.data, - a = r.length, - n = this.red(), - s = this.green(), - o = this.blue(); - for (e = 0; e < a; e += 4) - (i = (0.34 * r[e] + 0.5 * r[e + 1] + 0.16 * r[e + 2]) / 255), - (r[e] = i * n), - (r[e + 1] = i * s), - (r[e + 2] = i * o), - (r[e + 3] = r[e + 3]); - }, - RGBA: function (t) { - var e, - i, - r = t.data, - a = r.length, - n = this.red(), - s = this.green(), - o = this.blue(), - h = this.alpha(); - for (e = 0; e < a; e += 4) - (i = 1 - h), - (r[e] = n * h + r[e] * i), - (r[e + 1] = s * h + r[e + 1] * i), - (r[e + 2] = o * h + r[e + 2] * i); - }, - Sepia: function (t) { - var e, - i, - r, - a, - n = t.data, - s = n.length; - for (e = 0; e < s; e += 4) - (i = n[e + 0]), - (r = n[e + 1]), - (a = n[e + 2]), - (n[e + 0] = Math.min(255, 0.393 * i + 0.769 * r + 0.189 * a)), - (n[e + 1] = Math.min(255, 0.349 * i + 0.686 * r + 0.168 * a)), - (n[e + 2] = Math.min(255, 0.272 * i + 0.534 * r + 0.131 * a)); - }, - Solarize: function (t) { - var e = t.data, - i = t.width, - r = 4 * i, - a = t.height; - do { - var n = (a - 1) * r, - s = i; - do { - var o = n + 4 * (s - 1), - h = e[o], - l = e[o + 1], - d = e[o + 2]; - h > 127 && (h = 255 - h), - l > 127 && (l = 255 - l), - d > 127 && (d = 255 - d), - (e[o] = h), - (e[o + 1] = l), - (e[o + 2] = d); - } while (--s); - } while (--a); - }, - Threshold: function (t) { - var e, - i = 255 * this.threshold(), - r = t.data, - a = r.length; - for (e = 0; e < a; e += 1) r[e] = r[e] < i ? 0 : 255; - }, - }, - }); -}); + */var t=Math.PI/180;const e=function(t){var e=t.indexOf("msie ");if(e>0)return parseInt(t.substring(e+5,t.indexOf(".",e)),10);if(t.indexOf("trident/")>0){var i=t.indexOf("rv:");return parseInt(t.substring(i+3,t.indexOf(".",i)),10)}var r=t.indexOf("edge/");return r>0&&parseInt(t.substring(r+5,t.indexOf(".",r)),10)},i=function(t){var i=t.toLowerCase(),r=/(chrome)[ /]([\w.]+)/.exec(i)||/(webkit)[ /]([\w.]+)/.exec(i)||/(opera)(?:.*version|)[ /]([\w.]+)/.exec(i)||/(msie) ([\w.]+)/.exec(i)||i.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(i)||[],a=!!t.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i),n=!!t.match(/IEMobile/i);return{browser:r[1]||"",version:r[2]||"0",isIE:e(i),mobile:a,ieMobile:n}},r="undefined"!=typeof global?global:"undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope?self:{},a={_global:r,version:"7.2.5",isBrowser:"undefined"!=typeof window&&("[object Window]"==={}.toString.call(window)||"[object global]"==={}.toString.call(window)),isUnminified:/param/.test(function(t){}.toString()),dblClickWindow:400,getAngle:e=>a.angleDeg?e*t:e,enableTrace:!1,_pointerEventsEnabled:!1,autoDrawEnabled:!0,hitOnDragEnabled:!1,captureTouchEventsEnabled:!1,listenClickTap:!1,inDblClickWindow:!1,pixelRatio:"undefined"!=typeof window&&window.devicePixelRatio||1,dragDistance:3,angleDeg:!0,showWarnings:!0,dragButtons:[0,1],isDragging:()=>a.DD.isDragging,isDragReady:()=>!!a.DD.node,UA:i(r.navigator&&r.navigator.userAgent||""),document:r.document,_injectGlobal(t){r.Konva=t},_parseUA:i},n=t=>{a[t.prototype.getClassName()]=t};a._injectGlobal(a);class s{constructor(t=[1,0,0,1,0,0]){this.dirty=!1,this.m=t&&t.slice()||[1,0,0,1,0,0]}reset(){this.m[0]=1,this.m[1]=0,this.m[2]=0,this.m[3]=1,this.m[4]=0,this.m[5]=0}copy(){return new s(this.m)}copyInto(t){t.m[0]=this.m[0],t.m[1]=this.m[1],t.m[2]=this.m[2],t.m[3]=this.m[3],t.m[4]=this.m[4],t.m[5]=this.m[5]}point(t){var e=this.m;return{x:e[0]*t.x+e[2]*t.y+e[4],y:e[1]*t.x+e[3]*t.y+e[5]}}translate(t,e){return this.m[4]+=this.m[0]*t+this.m[2]*e,this.m[5]+=this.m[1]*t+this.m[3]*e,this}scale(t,e){return this.m[0]*=t,this.m[1]*=t,this.m[2]*=e,this.m[3]*=e,this}rotate(t){var e=Math.cos(t),i=Math.sin(t),r=this.m[0]*e+this.m[2]*i,a=this.m[1]*e+this.m[3]*i,n=this.m[0]*-i+this.m[2]*e,s=this.m[1]*-i+this.m[3]*e;return this.m[0]=r,this.m[1]=a,this.m[2]=n,this.m[3]=s,this}getTranslation(){return{x:this.m[4],y:this.m[5]}}skew(t,e){var i=this.m[0]+this.m[2]*e,r=this.m[1]+this.m[3]*e,a=this.m[2]+this.m[0]*t,n=this.m[3]+this.m[1]*t;return this.m[0]=i,this.m[1]=r,this.m[2]=a,this.m[3]=n,this}multiply(t){var e=this.m[0]*t.m[0]+this.m[2]*t.m[1],i=this.m[1]*t.m[0]+this.m[3]*t.m[1],r=this.m[0]*t.m[2]+this.m[2]*t.m[3],a=this.m[1]*t.m[2]+this.m[3]*t.m[3],n=this.m[0]*t.m[4]+this.m[2]*t.m[5]+this.m[4],s=this.m[1]*t.m[4]+this.m[3]*t.m[5]+this.m[5];return this.m[0]=e,this.m[1]=i,this.m[2]=r,this.m[3]=a,this.m[4]=n,this.m[5]=s,this}invert(){var t=1/(this.m[0]*this.m[3]-this.m[1]*this.m[2]),e=this.m[3]*t,i=-this.m[1]*t,r=-this.m[2]*t,a=this.m[0]*t,n=t*(this.m[2]*this.m[5]-this.m[3]*this.m[4]),s=t*(this.m[1]*this.m[4]-this.m[0]*this.m[5]);return this.m[0]=e,this.m[1]=i,this.m[2]=r,this.m[3]=a,this.m[4]=n,this.m[5]=s,this}getMatrix(){return this.m}setAbsolutePosition(t,e){var i=this.m[0],r=this.m[1],a=this.m[2],n=this.m[3],s=this.m[4],o=(i*(e-this.m[5])-r*(t-s))/(i*n-r*a),h=(t-s-a*o)/i;return this.translate(h,o)}decompose(){var t=this.m[0],e=this.m[1],i=this.m[2],r=this.m[3],a=t*r-e*i;let n={x:this.m[4],y:this.m[5],rotation:0,scaleX:0,scaleY:0,skewX:0,skewY:0};if(0!=t||0!=e){var s=Math.sqrt(t*t+e*e);n.rotation=e>0?Math.acos(t/s):-Math.acos(t/s),n.scaleX=s,n.scaleY=a/s,n.skewX=(t*i+e*r)/a,n.skewY=0}else if(0!=i||0!=r){var o=Math.sqrt(i*i+r*r);n.rotation=Math.PI/2-(r>0?Math.acos(-i/o):-Math.acos(i/o)),n.scaleX=a/o,n.scaleY=o,n.skewX=0,n.skewY=(t*i+e*r)/a}return n.rotation=g._getRotation(n.rotation),n}}var o=Math.PI/180,h=180/Math.PI,l={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,132,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,255,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,203],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[119,128,144],slategrey:[119,128,144],snow:[255,255,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],transparent:[255,255,255,0],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,5]},d=/rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/,c=[];const g={_isElement:t=>!(!t||1!=t.nodeType),_isFunction:t=>!!(t&&t.constructor&&t.call&&t.apply),_isPlainObject:t=>!!t&&t.constructor===Object,_isArray:t=>"[object Array]"===Object.prototype.toString.call(t),_isNumber:t=>"[object Number]"===Object.prototype.toString.call(t)&&!isNaN(t)&&isFinite(t),_isString:t=>"[object String]"===Object.prototype.toString.call(t),_isBoolean:t=>"[object Boolean]"===Object.prototype.toString.call(t),isObject:t=>t instanceof Object,isValidSelector(t){if("string"!=typeof t)return!1;var e=t[0];return"#"===e||"."===e||e===e.toUpperCase()},_sign:t=>0===t||t>0?1:-1,requestAnimFrame(t){c.push(t);const e="undefined"!=typeof requestAnimationFrame&&requestAnimationFrame||function(t){setTimeout(t,60)};1===c.length&&e((function(){const t=c;c=[],t.forEach((function(t){t()}))}))},createCanvasElement(){var t=document.createElement("canvas");try{t.style=t.style||{}}catch(t){}return t},createImageElement:()=>document.createElement("img"),_isInDocument(t){for(;t=t.parentNode;)if(t==document)return!0;return!1},_simplifyArray(t){var e,i,r=[],a=t.length,n=g;for(e=0;e((1<<24)+(t<<16)+(e<<8)+i).toString(16).slice(1),_hexToRgb(t){t=t.replace("#","");var e=parseInt(t,16);return{r:e>>16&255,g:e>>8&255,b:255&e}},getRandomColor(){for(var t=(16777215*Math.random()<<0).toString(16);t.length<6;)t="0"+t;return"#"+t},get:(t,e)=>void 0===t?e:t,getRGB(t){var e;return t in l?{r:(e=l[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=d.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:t=>(t=t||"black",g._namedColorToRBA(t)||g._hex3ColorToRGBA(t)||g._hex6ColorToRGBA(t)||g._rgbColorToRGBA(t)||g._rgbaColorToRGBA(t)||g._hslColorToRGBA(t)),_namedColorToRBA(t){var e=l[t.toLowerCase()];return e?{r:e[0],g:e[1],b:e[2],a:1}:null},_rgbColorToRGBA(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(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(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(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(t){if(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)){const[e,...i]=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t),r=Number(i[0])/360,a=Number(i[1])/100,n=Number(i[2])/100;let s,o,h;if(0===a)return h=255*n,{r:Math.round(h),g:Math.round(h),b:Math.round(h),a:1};s=n<.5?n*(1+a):n+a-n*a;const l=2*n-s,d=[0,0,0];for(let t=0;t<3;t++)o=r+1/3*-(t-1),o<0&&o++,o>1&&o--,h=6*o<1?l+6*(s-l)*o:2*o<1?s:3*o<2?l+(s-l)*(2/3-o)*6:l,d[t]=255*h;return{r:Math.round(d[0]),g:Math.round(d[1]),b:Math.round(d[2]),a:1}}},haveIntersection:(t,e)=>!(e.x>t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heightt.slice(0),_degToRad:t=>t*o,_radToDeg:t=>t*h,_getRotation:t=>a.angleDeg?g._radToDeg(t):t,_capitalize:t=>t.charAt(0).toUpperCase()+t.slice(1),throw(t){throw new Error("Konva error: "+t)},error(t){console.error("Konva error: "+t)},warn(t){a.showWarnings&&console.warn("Konva warning: "+t)},extend(t,e){function i(){this.constructor=t}i.prototype=e.prototype;var r=t.prototype;for(var a in t.prototype=new i,r)r.hasOwnProperty(a)&&(t.prototype[a]=r[a]);t.__super__=e.prototype,t.super=e},_getControlPoints(t,e,i,r,a,n,s){var o=Math.sqrt(Math.pow(i-t,2)+Math.pow(r-e,2)),h=Math.sqrt(Math.pow(a-i,2)+Math.pow(n-r,2)),l=s*o/(o+h),d=s*h/(o+h);return[i-l*(a-t),r-l*(n-e),i+d*(a-t),r+d*(n-e)]},_expandPoints(t,e){var i,r,a=t.length,n=[];for(i=2;ie<=t&&t1?(s=i,o=r,h=(i-a)*(i-a)+(r-n)*(r-n)):h=((s=t+d*(i-t))-a)*(s-a)+((o=e+d*(r-e))-n)*(o-n)}return[s,o,h]},_getProjectionToLine(t,e,i){var r=g.cloneObject(t),a=Number.MAX_VALUE;return e.forEach((function(n,s){if(i||s!==e.length-1){var o=e[(s+1)%e.length],h=g._getProjectionToSegment(n.x,n.y,o.x,o.y,t.x,t.y),l=h[0],d=h[1],c=h[2];ce.length){var s=e;e=t,t=s}for(r=0;rt.touches?t.changedTouches[0].identifier:999};function u(t){return g._isString(t)?'"'+t+'"':"[object Number]"===Object.prototype.toString.call(t)||g._isBoolean(t)?t:Object.prototype.toString.call(t)}function f(t){return t>255?255:t<0?0:Math.round(t)}function p(){if(a.isUnminified)return function(t,e){return g._isNumber(t)||g.warn(u(t)+' is a not valid value for "'+e+'" attribute. The value should be a number.'),t}}function v(t){if(a.isUnminified)return function(e,i){let r=g._isNumber(e),a=g._isArray(e)&&e.length==t;return r||a||g.warn(u(e)+' is a not valid value for "'+i+'" attribute. The value should be a number or Array('+t+")"),e}}function m(){if(a.isUnminified)return function(t,e){return g._isNumber(t)||"auto"===t||g.warn(u(t)+' is a not valid value for "'+e+'" attribute. The value should be a number or "auto".'),t}}function _(){if(a.isUnminified)return function(t,e){return g._isString(t)||g.warn(u(t)+' is a not valid value for "'+e+'" attribute. The value should be a string.'),t}}function y(){if(a.isUnminified)return function(t,e){const i=g._isString(t),r="[object CanvasGradient]"===Object.prototype.toString.call(t)||t&&t.addColorStop;return i||r||g.warn(u(t)+' is a not valid value for "'+e+'" attribute. The value should be a string or a native gradient.'),t}}function x(){if(a.isUnminified)return function(t,e){return!0===t||!1===t||g.warn(u(t)+' is a not valid value for "'+e+'" attribute. The value should be a boolean.'),t}}const b={addGetterSetter(t,e,i,r,a){b.addGetter(t,e,i),b.addSetter(t,e,r,a),b.addOverloadedGetterSetter(t,e)},addGetter(t,e,i){var r="get"+g._capitalize(e);t.prototype[r]=t.prototype[r]||function(){var t=this.attrs[e];return void 0===t?i:t}},addSetter(t,e,i,r){var a="set"+g._capitalize(e);t.prototype[a]||b.overWriteSetter(t,e,i,r)},overWriteSetter(t,e,i,r){var a="set"+g._capitalize(e);t.prototype[a]=function(t){return i&&null!=t&&(t=i.call(this,t,e)),this._setAttr(e,t),r&&r.call(this),this}},addComponentsGetterSetter(t,e,i,r,n){var s,o,h=i.length,l=g._capitalize,d="get"+l(e),c="set"+l(e);t.prototype[d]=function(){var t={};for(s=0;s"number"==typeof t?Math.floor(t):t)),h+="("+n.join(",")+")")):(h+=r.property,t||(h+="="+r.val)),h+=";";return h}clearTrace(){this.traceArr=[]}_trace(t){var e=this.traceArr;e.push(t),e.length>=100&&e.shift()}reset(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)}getCanvas(){return this.canvas}clear(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)}_applyLineCap(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)}_applyOpacity(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)}_applyLineJoin(t){var e=t.attrs.lineJoin;e&&this.setAttr("lineJoin",e)}setAttr(t,e){this._context[t]=e}arc(t,e,i,r,a,n){this._context.arc(t,e,i,r,a,n)}arcTo(t,e,i,r,a){this._context.arcTo(t,e,i,r,a)}beginPath(){this._context.beginPath()}bezierCurveTo(t,e,i,r,a,n){this._context.bezierCurveTo(t,e,i,r,a,n)}clearRect(t,e,i,r){this._context.clearRect(t,e,i,r)}clip(){this._context.clip()}closePath(){this._context.closePath()}createImageData(t,e){var i=arguments;return 2===i.length?this._context.createImageData(t,e):1===i.length?this._context.createImageData(t):void 0}createLinearGradient(t,e,i,r){return this._context.createLinearGradient(t,e,i,r)}createPattern(t,e){return this._context.createPattern(t,e)}createRadialGradient(t,e,i,r,a,n){return this._context.createRadialGradient(t,e,i,r,a,n)}drawImage(t,e,i,r,a,n,s,o,h){var l=arguments,d=this._context;3===l.length?d.drawImage(t,e,i):5===l.length?d.drawImage(t,e,i,r,a):9===l.length&&d.drawImage(t,e,i,r,a,n,s,o,h)}ellipse(t,e,i,r,a,n,s,o){this._context.ellipse(t,e,i,r,a,n,s,o)}isPointInPath(t,e){return this._context.isPointInPath(t,e)}fill(){this._context.fill()}fillRect(t,e,i,r){this._context.fillRect(t,e,i,r)}strokeRect(t,e,i,r){this._context.strokeRect(t,e,i,r)}fillText(t,e,i){this._context.fillText(t,e,i)}measureText(t){return this._context.measureText(t)}getImageData(t,e,i,r){return this._context.getImageData(t,e,i,r)}lineTo(t,e){this._context.lineTo(t,e)}moveTo(t,e){this._context.moveTo(t,e)}rect(t,e,i,r){this._context.rect(t,e,i,r)}putImageData(t,e,i){this._context.putImageData(t,e,i)}quadraticCurveTo(t,e,i,r){this._context.quadraticCurveTo(t,e,i,r)}restore(){this._context.restore()}rotate(t){this._context.rotate(t)}save(){this._context.save()}scale(t,e){this._context.scale(t,e)}setLineDash(t){this._context.setLineDash?this._context.setLineDash(t):"mozDash"in this._context?this._context.mozDash=t:"webkitLineDash"in this._context&&(this._context.webkitLineDash=t)}getLineDash(){return this._context.getLineDash()}setTransform(t,e,i,r,a,n){this._context.setTransform(t,e,i,r,a,n)}stroke(){this._context.stroke()}strokeText(t,e,i,r){this._context.strokeText(t,e,i,r)}transform(t,e,i,r,a,n){this._context.transform(t,e,i,r,a,n)}translate(t,e){this._context.translate(t,e)}_enableTrace(){var t,e,i=this,r=S.length,a=this.setAttr,n=function(t){var r,a=i[t];i[t]=function(){return e=g._simplifyArray(Array.prototype.slice.call(arguments,0)),r=a.apply(i,arguments),i._trace({method:t,args:e}),r}};for(t=0;t{"dragging"===e.dragStatus&&(t=!0)}),t},justDragged:!1,get node(){var t;return G._dragElements.forEach(e=>{t=e.node}),t},_dragElements:new Map,_drag(t){const e=[];G._dragElements.forEach((i,r)=>{const{node:a}=i,n=a.getStage();n.setPointersPositions(t),void 0===i.pointerId&&(i.pointerId=g._getFirstPointerId(t));const s=n._changedPointerPositions.find(t=>t.id===i.pointerId);if(s){if("dragging"!==i.dragStatus){var o=a.dragDistance();if(Math.max(Math.abs(s.x-i.startPointerPos.x),Math.abs(s.y-i.startPointerPos.y)){e.fire("dragmove",{type:"dragmove",target:e,evt:t},!0)})},_endDragBefore(t){G._dragElements.forEach((e,i)=>{const{node:r}=e,n=r.getStage();t&&n.setPointersPositions(t);if(!n._changedPointerPositions.find(t=>t.id===e.pointerId))return;"dragging"!==e.dragStatus&&"stopped"!==e.dragStatus||(G.justDragged=!0,a.listenClickTap=!1,e.dragStatus="stopped");const s=e.node.getLayer()||e.node instanceof a.Stage&&e.node;s&&s.batchDraw()})},_endDragAfter(t){G._dragElements.forEach((e,i)=>{"stopped"===e.dragStatus&&e.node.fire("dragend",{type:"dragend",target:e.node,evt:t},!0),"dragging"!==e.dragStatus&&G._dragElements.delete(i)})}};a.isBrowser&&(window.addEventListener("mouseup",G._endDragBefore,!0),window.addEventListener("touchend",G._endDragBefore,!0),window.addEventListener("mousemove",G._drag),window.addEventListener("touchmove",G._drag),window.addEventListener("mouseup",G._endDragAfter,!1),window.addEventListener("touchend",G._endDragAfter,!1));const E={},R={},L=function(t,e){t&&E[t]===e&&delete E[t]},D=function(t,e){e&&(R[e]||(R[e]=[]),R[e].push(t))},I=function(t,e){if(t){var i=R[t];if(i){for(var r=0;rt+"Change.konva").join(" ");this.on(i,()=>{this._clearCache(t)}),this._attachedDepsListeners.set(t,!0)}return this._getCache(t,i)}_getCanvasCache(){return this._cache.get("canvas")}_clearSelfAndDescendantCache(t,e){this._clearCache(t),"absoluteTransform"===t&&this.fire("absoluteTransformChange")}clearCache(){return this._cache.delete("canvas"),this._clearSelfAndDescendantCache(),this._requestDraw(),this}cache(t){var e=t||{},i={};void 0!==e.x&&void 0!==e.y&&void 0!==e.width&&void 0!==e.height||(i=this.getClientRect({skipTransform:!0,relativeTo:this.getParent()}));var r=Math.ceil(e.width||i.width),a=Math.ceil(e.height||i.height),n=e.pixelRatio,s=void 0===e.x?i.x:e.x,o=void 0===e.y?i.y:e.y,h=e.offset||0,l=e.drawBorder||!1,d=e.hitCanvasPixelRatio||1;if(r&&a){s-=h,o-=h;var c=new A({pixelRatio:n,width:r+=2*h,height:a+=2*h}),u=new A({pixelRatio:n,width:0,height:0}),f=new M({pixelRatio:d,width:r,height:a}),p=c.getContext(),v=f.getContext();return f.isCache=!0,c.isCache=!0,this._cache.delete("canvas"),this._filterUpToDate=!1,!1===e.imageSmoothingEnabled&&(c.getContext()._context.imageSmoothingEnabled=!1,u.getContext()._context.imageSmoothingEnabled=!1),p.save(),v.save(),p.translate(-s,-o),v.translate(-s,-o),this._isUnderCache=!0,this._clearSelfAndDescendantCache("absoluteOpacity"),this._clearSelfAndDescendantCache("absoluteScale"),this.drawScene(c,this),this.drawHit(f,this),this._isUnderCache=!1,p.restore(),v.restore(),l&&(p.save(),p.beginPath(),p.rect(0,0,r,a),p.closePath(),p.setAttr("strokeStyle","red"),p.setAttr("lineWidth",5),p.stroke(),p.restore()),this._cache.set("canvas",{scene:c,filter:u,hit:f,x:s,y:o}),this._requestDraw(),this}g.error("Can not cache the node. Width or height of the node equals 0. Caching is skipped.")}isCached(){return this._cache.has("canvas")}getClientRect(t){throw new Error('abstract "getClientRect" method call')}_transformedRect(t,e){var i,r,a,n,s=[{x:t.x,y:t.y},{x:t.x+t.width,y:t.y},{x:t.x+t.width,y:t.y+t.height},{x:t.x,y:t.y+t.height}],o=this.getAbsoluteTransform(e);return s.forEach((function(t){var e=o.point(t);void 0===i&&(i=a=e.x,r=n=e.y),i=Math.min(i,e.x),r=Math.min(r,e.y),a=Math.max(a,e.x),n=Math.max(n,e.y)})),{x:i,y:r,width:a-i,height:n-r}}_drawCachedSceneCanvas(t){t.save(),t._applyOpacity(this),t._applyGlobalCompositeOperation(this);const e=this._getCanvasCache();t.translate(e.x,e.y);var i=this._getCachedSceneCanvas(),r=i.pixelRatio;t.drawImage(i._canvas,0,0,i.width/r,i.height/r),t.restore()}_drawCachedHitCanvas(t){var e=this._getCanvasCache(),i=e.hit;t.save(),t.translate(e.x,e.y),t.drawImage(i._canvas,0,0,i.width/i.pixelRatio,i.height/i.pixelRatio),t.restore()}_getCachedSceneCanvas(){var t,e,i,r,a=this.filters(),n=this._getCanvasCache(),s=n.scene,o=n.filter,h=o.getContext();if(a){if(!this._filterUpToDate){var l=s.pixelRatio;o.setSize(s.width/s.pixelRatio,s.height/s.pixelRatio);try{for(t=a.length,h.clear(),h.drawImage(s._canvas,0,0,s.getWidth()/l,s.getHeight()/l),e=h.getImageData(0,0,o.getWidth(),o.getHeight()),i=0;i{var e,i;if(!t)return this;for(e in t)"children"!==e&&(i="set"+g._capitalize(e),g._isFunction(this[i])?this[i](t[e]):this._setAttr(e,t[e]))}),this}isListening(){return this._getCache("listening",this._isListening)}_isListening(t){if(!this.listening())return!1;const e=this.getParent();return!e||e===t||this===t||e._isListening(t)}isVisible(){return this._getCache("visible",this._isVisible)}_isVisible(t){if(!this.visible())return!1;const e=this.getParent();return!e||e===t||this===t||e._isVisible(t)}shouldDrawHit(t,e=!1){if(t)return this._isVisible(t)&&this._isListening(t);var i=this.getLayer(),r=!1;G._dragElements.forEach(t=>{"dragging"===t.dragStatus&&("Stage"===t.node.nodeType||t.node.getLayer()===i)&&(r=!0)});var n=!e&&!a.hitOnDragEnabled&&r;return this.isListening()&&this.isVisible()&&!n}show(){return this.visible(!0),this}hide(){return this.visible(!1),this}getZIndex(){return this.index||0}getAbsoluteZIndex(){var t,e,i,r,a=this.getDepth(),n=this,s=0;return"Stage"!==n.nodeType&&function o(h){for(t=[],e=h.length,i=0;i0&&t[0].getDepth()<=a&&o(t)}(n.getStage().getChildren()),s}getDepth(){for(var t=0,e=this.parent;e;)t++,e=e.parent;return t}_batchTransformChanges(t){this._batchingTransformChange=!0,t(),this._batchingTransformChange=!1,this._needClearTransformCache&&(this._clearCache("transform"),this._clearSelfAndDescendantCache("absoluteTransform",!0)),this._needClearTransformCache=!1}setPosition(t){return this._batchTransformChanges(()=>{this.x(t.x),this.y(t.y)}),this}getPosition(){return{x:this.x(),y:this.y()}}getAbsolutePosition(t){let e=!1,i=this.parent;for(;i;){if(i.isCached()){e=!0;break}i=i.parent}e&&!t&&(t=!0);var r=this.getAbsoluteTransform(t).getMatrix(),a=new s,n=this.offset();return a.m=r.slice(),a.translate(n.x,n.y),a.getTranslation()}setAbsolutePosition(t){var e=this._clearTransform();this.attrs.x=e.x,this.attrs.y=e.y,delete e.x,delete e.y,this._clearCache("transform");var i=this._getAbsoluteTransform().copy();return i.invert(),i.translate(t.x,t.y),t={x:this.attrs.x+i.getTranslation().x,y:this.attrs.y+i.getTranslation().y},this._setTransform(e),this.setPosition({x:t.x,y:t.y}),this._clearCache("transform"),this._clearSelfAndDescendantCache("absoluteTransform"),this}_setTransform(t){var e;for(e in t)this.attrs[e]=t[e]}_clearTransform(){var t={x:this.x(),y:this.y(),rotation:this.rotation(),scaleX:this.scaleX(),scaleY:this.scaleY(),offsetX:this.offsetX(),offsetY:this.offsetY(),skewX:this.skewX(),skewY:this.skewY()};return this.attrs.x=0,this.attrs.y=0,this.attrs.rotation=0,this.attrs.scaleX=1,this.attrs.scaleY=1,this.attrs.offsetX=0,this.attrs.offsetY=0,this.attrs.skewX=0,this.attrs.skewY=0,t}move(t){var e=t.x,i=t.y,r=this.x(),a=this.y();return void 0!==e&&(r+=e),void 0!==i&&(a+=i),this.setPosition({x:r,y:a}),this}_eachAncestorReverse(t,e){var i,r,a=[],n=this.getParent();if(!e||e._id!==this._id){for(a.unshift(this);n&&(!e||n._id!==e._id);)a.unshift(n),n=n.parent;for(i=a.length,r=0;r0&&(this.parent.children.splice(t,1),this.parent.children.splice(t-1,0,this),this.parent._setChildrenIndices(),!0)}moveToBottom(){if(!this.parent)return g.warn("Node has no parent. moveToBottom function is ignored."),!1;var t=this.index;return t>0&&(this.parent.children.splice(t,1),this.parent.children.unshift(this),this.parent._setChildrenIndices(),!0)}setZIndex(t){if(!this.parent)return g.warn("Node has no parent. zIndex parameter is ignored."),this;(t<0||t>=this.parent.children.length)&&g.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}getAbsoluteOpacity(){return this._getCache("absoluteOpacity",this._getAbsoluteOpacity)}_getAbsoluteOpacity(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=e.getAbsoluteOpacity()),t}moveTo(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this}toObject(){var t,e,i,r,a={},n=this.getAttrs();for(t in a.attrs={},n)e=n[t],g.isObject(e)&&!g._isPlainObject(e)&&!g._isArray(e)||(i="function"==typeof this[t]&&this[t],delete n[t],r=i?i.call(this):null,n[t]=e,r!==e&&(a.attrs[t]=e));return a.className=this.getClassName(),g._prepareToStringify(a)}toJSON(){return JSON.stringify(this.toObject())}getParent(){return this.parent}findAncestors(t,e,i){var r=[];e&&this._isMatch(t)&&r.push(this);for(var a=this.parent;a;){if(a===i)return r;a._isMatch(t)&&r.push(a),a=a.parent}return r}isAncestorOf(t){return!1}findAncestor(t,e,i){return this.findAncestors(t,e,i)[0]}_isMatch(t){if(!t)return!1;if("function"==typeof t)return t(this);var e,i,r=t.replace(/ /g,"").split(","),a=r.length;for(e=0;e=0)&&!this.isDragging()){var e=!1;G._dragElements.forEach(t=>{this.isAncestorOf(t.node)&&(e=!0)}),e||this._createDragElement(t)}}))}_dragChange(){if(this.attrs.draggable)this._listenDrag();else{if(this._dragCleanup(),!this.getStage())return;const t=G._dragElements.get(this._id),e=t&&"dragging"===t.dragStatus,i=t&&"ready"===t.dragStatus;e?this.stopDrag():i&&G._dragElements.delete(this._id)}}_dragCleanup(){this.off("mousedown.konva"),this.off("touchstart.konva")}static create(t,e){return g._isString(t)&&(t=JSON.parse(t)),this._createNode(t,e)}static _createNode(t,e){var i,r,n,s=N.prototype.getClassName.call(t),o=t.children;e&&(t.attrs.container=e),a[s]||(g.warn('Can not find a node with class name "'+s+'". Fallback to "Shape".'),s="Shape");if(i=new(0,a[s])(t.attrs),o)for(r=o.length,n=0;n0}removeChildren(){return this.getChildren().forEach(t=>{t.parent=null,t.index=0,t.remove()}),this.children=[],this}destroyChildren(){return this.getChildren().forEach(t=>{t.parent=null,t.index=0,t.destroy()}),this.children=[],this}add(...t){if(arguments.length>1){for(var e=0;e0?e[0]:void 0}_generalFind(t,e){var i=[];return this._descendants(r=>{const a=r._isMatch(t);return a&&i.push(r),!(!a||!e)}),i}_descendants(t){let e=!1;const i=this.getChildren();for(const r of i){if(e=t(r),e)return!0;if(r.hasChildren()&&(e=r._descendants(t),e))return!0}return!1}toObject(){var t=N.prototype.toObject.call(this);return t.children=[],this.getChildren().forEach(e=>{t.children.push(e.toObject())}),t}isAncestorOf(t){for(var e=t.getParent();e;){if(e._id===this._id)return!0;e=e.getParent()}return!1}clone(t){var e=N.prototype.clone.call(this,t);return this.getChildren().forEach((function(t){e.add(t.clone())})),e}getAllIntersections(t){var e=[];return this.find("Shape").forEach((function(i){i.isVisible()&&i.intersects(t)&&e.push(i)})),e}_clearSelfAndDescendantCache(t,e){var i;super._clearSelfAndDescendantCache(t,e),this.isCached()||null===(i=this.children)||void 0===i||i.forEach((function(i){i._clearSelfAndDescendantCache(t,e)}))}_setChildrenIndices(){var t;null===(t=this.children)||void 0===t||t.forEach((function(t,e){t.index=e})),this._requestDraw()}drawScene(t,e){var i=this.getLayer(),r=t||i&&i.getCanvas(),a=r&&r.getContext(),n=this._getCanvasCache(),s=n&&n.scene,o=r&&r.isCache;if(!this.isVisible()&&!o)return this;if(s){a.save();var h=this.getAbsoluteTransform(e).getMatrix();a.transform(h[0],h[1],h[2],h[3],h[4],h[5]),this._drawCachedSceneCanvas(a),a.restore()}else this._drawChildren("drawScene",r,e);return this}drawHit(t,e){if(!this.shouldDrawHit(e))return this;var i=this.getLayer(),r=t||i&&i.hitCanvas,a=r&&r.getContext(),n=this._getCanvasCache();if(n&&n.hit){a.save();var s=this.getAbsoluteTransform(e).getMatrix();a.transform(s[0],s[1],s[2],s[3],s[4],s[5]),this._drawCachedHitCanvas(a),a.restore()}else this._drawChildren("drawHit",r,e);return this}_drawChildren(t,e,i){var r,a=e&&e.getContext(),n=this.clipWidth(),s=this.clipHeight(),o=this.clipFunc(),h=n&&s||o;const l=i===this;if(h){a.save();var d=this.getAbsoluteTransform(i),c=d.getMatrix();if(a.transform(c[0],c[1],c[2],c[3],c[4],c[5]),a.beginPath(),o)o.call(this,a,this);else{var g=this.clipX(),u=this.clipY();a.rect(g,u,n,s)}a.clip(),c=d.copy().invert().getMatrix(),a.transform(c[0],c[1],c[2],c[3],c[4],c[5])}var f=!l&&"source-over"!==this.globalCompositeOperation()&&"drawScene"===t;f&&(a.save(),a._applyGlobalCompositeOperation(this)),null===(r=this.children)||void 0===r||r.forEach((function(r){r[t](e,i)})),f&&a.restore(),h&&a.restore()}getClientRect(t){var e,i,r,a,n,s=(t=t||{}).skipTransform,o=t.relativeTo,h={x:1/0,y:1/0,width:0,height:0},l=this;null===(e=this.children)||void 0===e||e.forEach((function(e){if(e.visible()){var s=e.getClientRect({relativeTo:l,skipShadow:t.skipShadow,skipStroke:t.skipStroke});0===s.width&&0===s.height||(void 0===i?(i=s.x,r=s.y,a=s.x+s.width,n=s.y+s.height):(i=Math.min(i,s.x),r=Math.min(r,s.y),a=Math.max(a,s.x+s.width),n=Math.max(n,s.y+s.height)))}}));for(var d=this.find("Shape"),c=!1,g=0;g{$(this.attrs)}),this._checkVisibility()}_validateAdd(t){const e="Layer"===t.getType(),i="FastLayer"===t.getType();e||i||g.throw("You may only add layers to the stage.")}_checkVisibility(){if(!this.content)return;const t=this.visible()?"":"none";this.content.style.display=t}setContainer(t){if("string"==typeof t){if("."===t.charAt(0)){var e=t.slice(1);t=document.getElementsByClassName(e)[0]}else{var i;i="#"!==t.charAt(0)?t:t.slice(1),t=document.getElementById(i)}if(!t)throw"Can not find container in document with id "+i}return this._setAttr("container",t),this.content&&(this.content.parentElement&&this.content.parentElement.removeChild(this.content),t.appendChild(this.content)),this}shouldDrawHit(){return!0}clear(){var t,e=this.children,i=e.length;for(t=0;t-1&&Z.splice(e,1),this}getPointerPosition(){const t=this._pointerPositions[0]||this._changedPointerPositions[0];return t?{x:t.x,y:t.y}:(g.warn("Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);"),null)}_getPointerById(t){return this._pointerPositions.find(e=>e.id===t)}getPointersPositions(){return this._pointerPositions}getStage(){return this}getContent(){return this.content}_toKonvaCanvas(t){(t=t||{}).x=t.x||0,t.y=t.y||0,t.width=t.width||this.width(),t.height=t.height||this.height();var e=new A({width:t.width,height:t.height,pixelRatio:t.pixelRatio||1}),i=e.getContext()._context,r=this.children;return(t.x||t.y)&&i.translate(-1*t.x,-1*t.y),r.forEach((function(e){if(e.isVisible()){var r=e._toKonvaCanvas(t);i.drawImage(r._canvas,t.x,t.y,r.getWidth()/r.getPixelRatio(),r.getHeight()/r.getPixelRatio())}})),e}getIntersection(t,e){if(!t)return null;var i,r=this.children;for(i=r.length-1;i>=0;i--){const a=r[i].getIntersection(t,e);if(a)return a}return null}_resizeDOM(){var t=this.width(),e=this.height();this.content&&(this.content.style.width=t+"px",this.content.style.height=e+"px"),this.bufferCanvas.setSize(t,e),this.bufferHitCanvas.setSize(t,e),this.children.forEach(i=>{i.setSize({width:t,height:e}),i.draw()})}add(t,...e){if(arguments.length>1){for(var i=0;i5&&g.warn("The stage has "+r+" layers. Recommended maximum number of layers is 3-5. Adding more layers into the stage may drop the performance. Rethink your tree structure, you can use Konva.Group."),t.setSize({width:this.width(),height:this.height()}),t.draw(),a.isBrowser&&this.content.appendChild(t.canvas._canvas),this}getParent(){return null}getLayer(){return null}hasPointerCapture(t){return U(t,this)}setPointerCapture(t){q(t,this)}releaseCapture(t){K(t)}getLayers(){return this.children}_bindContentEvents(){if(a.isBrowser)for(var t=0;t{var r=this.getIntersection(i);a.listenClickTap=!0,G.justDragged=!1;r&&r.isListening()&&(a.captureTouchEventsEnabled&&r.setPointerCapture(i.id),this.tapStartShape=r,r._fireAndBubble("touchstart",{evt:t,pointerId:i.id},this),e=!0,r.isListening()&&r.preventDefault()&&t.cancelable&&t.preventDefault())}),e||this._fire("touchstart",{evt:t,target:this,currentTarget:this,pointerId:this._changedPointerPositions[0].id}),this._fire("contentTouchstart",{evt:t})}_touchmove(t){if(this.setPointersPositions(t),!G.isDragging||a.hitOnDragEnabled){var e=!1,i={};this._changedPointerPositions.forEach(r=>{const a=X(r.id)||this.getIntersection(r);a&&a.isListening()&&(i[a._id]||(i[a._id]=!0,a._fireAndBubble("touchmove",{evt:t,pointerId:r.id}),e=!0,a.isListening()&&a.preventDefault()&&t.cancelable&&t.preventDefault()))}),e||this._fire("touchmove",{evt:t,target:this,currentTarget:this,pointerId:this._changedPointerPositions[0].id}),this._fire("contentTouchmove",{evt:t})}G.isDragging&&G.node.preventDefault()&&t.cancelable&&t.preventDefault()}_touchend(t){this.setPointersPositions(t);var e=this.tapEndShape,i=!1;a.inDblClickWindow?(i=!0,clearTimeout(this.dblTimeout)):G.justDragged||(a.inDblClickWindow=!0,clearTimeout(this.dblTimeout)),this.dblTimeout=setTimeout((function(){a.inDblClickWindow=!1}),a.dblClickWindow);var r=!1,n={},s=!1,o=!1;this._changedPointerPositions.forEach(h=>{var l=X(h.id)||this.getIntersection(h);l&&l.releaseCapture(h.id);l&&l.isListening()&&(n[l._id]||(n[l._id]=!0,this.tapEndShape=l,l._fireAndBubble("touchend",{evt:t,pointerId:h.id}),r=!0,a.listenClickTap&&l===this.tapStartShape&&(s=!0,l._fireAndBubble("tap",{evt:t,pointerId:h.id}),i&&e&&e===l&&(o=!0,l._fireAndBubble("dbltap",{evt:t,pointerId:h.id}))),l.isListening()&&l.preventDefault()&&t.cancelable&&t.preventDefault()))}),r||this._fire("touchend",{evt:t,target:this,currentTarget:this,pointerId:this._changedPointerPositions[0].id}),a.listenClickTap&&!s&&(this.tapEndShape=null,this._fire("tap",{evt:t,target:this,currentTarget:this,pointerId:this._changedPointerPositions[0].id})),i&&!o&&this._fire("dbltap",{evt:t,target:this,currentTarget:this,pointerId:this._changedPointerPositions[0].id}),this._fire("contentTouchend",{evt:t}),a.listenClickTap&&(this._fire("contentTap",{evt:t}),i&&this._fire("contentDbltap",{evt:t})),this.preventDefault()&&t.cancelable&&t.preventDefault(),a.listenClickTap=!1}_wheel(t){this.setPointersPositions(t);var e=this.getIntersection(this.getPointerPosition());e&&e.isListening()?e._fireAndBubble("wheel",{evt:t}):this._fire("wheel",{evt:t,target:this,currentTarget:this}),this._fire("contentWheel",{evt:t})}_pointerdown(t){if(!a._pointerEventsEnabled)return;this.setPointersPositions(t);const e=X(t.pointerId)||this.getIntersection(this.getPointerPosition());e&&e._fireAndBubble("pointerdown",j(t))}_pointermove(t){if(!a._pointerEventsEnabled)return;this.setPointersPositions(t);const e=X(t.pointerId)||this.getIntersection(this.getPointerPosition());e&&e._fireAndBubble("pointermove",j(t))}_pointerup(t){if(!a._pointerEventsEnabled)return;this.setPointersPositions(t);const e=X(t.pointerId)||this.getIntersection(this.getPointerPosition());e&&e._fireAndBubble("pointerup",j(t)),K(t.pointerId)}_pointercancel(t){if(!a._pointerEventsEnabled)return;this.setPointersPositions(t);const e=X(t.pointerId)||this.getIntersection(this.getPointerPosition());e&&e._fireAndBubble("pointerup",j(t)),K(t.pointerId)}_lostpointercapture(t){K(t.pointerId)}setPointersPositions(t){var e=this._getContentPosition(),i=null,r=null;void 0!==(t=t||window.event).touches?(this._pointerPositions=[],this._changedPointerPositions=[],Array.prototype.forEach.call(t.touches,t=>{this._pointerPositions.push({id:t.identifier,x:(t.clientX-e.left)/e.scaleX,y:(t.clientY-e.top)/e.scaleY})}),Array.prototype.forEach.call(t.changedTouches||t.touches,t=>{this._changedPointerPositions.push({id:t.identifier,x:(t.clientX-e.left)/e.scaleX,y:(t.clientY-e.top)/e.scaleY})})):(i=(t.clientX-e.left)/e.scaleX,r=(t.clientY-e.top)/e.scaleY,this.pointerPos={x:i,y:r},this._pointerPositions=[{x:i,y:r,id:g._getFirstPointerId(t)}],this._changedPointerPositions=[{x:i,y:r,id:g._getFirstPointerId(t)}])}_setPointerPosition(t){g.warn('Method _setPointerPosition is deprecated. Use "stage.setPointersPositions(event)" instead.'),this.setPointersPositions(t)}_getContentPosition(){if(!this.content||!this.content.getBoundingClientRect)return{top:0,left:0,scaleX:1,scaleY:1};var t=this.content.getBoundingClientRect();return{top:t.top,left:t.left,scaleX:t.width/this.content.clientWidth||1,scaleY:t.height/this.content.clientHeight||1}}_buildDOM(){if(this.bufferCanvas=new A({width:this.width(),height:this.height()}),this.bufferHitCanvas=new M({pixelRatio:1,width:this.width(),height:this.height()}),a.isBrowser){var t=this.container();if(!t)throw"Stage has no container. A container is required.";t.innerHTML="",this.content=document.createElement("div"),this.content.style.position="relative",this.content.style.userSelect="none",this.content.className="konvajs-content",this.content.setAttribute("role","presentation"),t.appendChild(this.content),this._resizeDOM()}}cache(){return g.warn("Cache function is not allowed for stage. You may use cache only for layers, groups and shapes."),this}clearCache(){return this}batchDraw(){return this.getChildren().forEach((function(t){t.batchDraw()})),this}}tt.prototype.nodeType="Stage",n(tt),b.addGetterSetter(tt,"container");let et;function it(){return et||(et=g.createCanvasElement().getContext("2d"),et)}const rt={};class at extends N{constructor(t){let e;for(super(t);e=g.getRandomColor(),!e||e in rt;);this.colorKey=e,rt[e]=this}getContext(){return this.getLayer().getContext()}getCanvas(){return this.getLayer().getCanvas()}getSceneFunc(){return this.attrs.sceneFunc||this._sceneFunc}getHitFunc(){return this.attrs.hitFunc||this._hitFunc}hasShadow(){return this._getCache("hasShadow",this._hasShadow)}_hasShadow(){return this.shadowEnabled()&&0!==this.shadowOpacity()&&!!(this.shadowColor()||this.shadowBlur()||this.shadowOffsetX()||this.shadowOffsetY())}_getFillPattern(){return this._getCache("patternImage",this.__getFillPattern)}__getFillPattern(){if(this.fillPatternImage()){const t=it().createPattern(this.fillPatternImage(),this.fillPatternRepeat()||"repeat");return t&&t.setTransform&&t.setTransform({a:this.fillPatternScaleX(),b:0,c:0,d:this.fillPatternScaleY(),e:0,f:0}),t}}_getLinearGradient(){return this._getCache("linearGradient",this.__getLinearGradient)}__getLinearGradient(){var t=this.fillLinearGradientColorStops();if(t){for(var e=it(),i=this.fillLinearGradientStartPoint(),r=this.fillLinearGradientEndPoint(),a=e.createLinearGradient(i.x,i.y,r.x,r.y),n=0;nthis.fillEnabled()&&!!(this.fill()||this.fillPatternImage()||this.fillLinearGradientColorStops()||this.fillRadialGradientColorStops()))}hasStroke(){return this._calculate("hasStroke",["strokeEnabled","strokeWidth","stroke","strokeLinearGradientColorStops"],()=>this.strokeEnabled()&&this.strokeWidth()&&!(!this.stroke()&&!this.strokeLinearGradientColorStops()))}hasHitStroke(){const t=this.hitStrokeWidth();return"auto"===t?this.hasStroke():this.strokeEnabled()&&!!t}intersects(t){var e=this.getStage().bufferHitCanvas;return e.getContext().clear(),this.drawHit(e,null,!0),e.context.getImageData(Math.round(t.x),Math.round(t.y),1,1).data[3]>0}destroy(){return N.prototype.destroy.call(this),delete rt[this.colorKey],delete this.colorKey,this}_useBufferCanvas(t){var e;if(!this.getStage())return!1;if(!(null===(e=this.attrs.perfectDrawEnabled)||void 0===e||e))return!1;const i=t||this.hasFill(),r=this.hasStroke(),a=1!==this.getAbsoluteOpacity();if(i&&r&&a)return!0;const n=this.hasShadow(),s=this.shadowForStrokeEnabled();return!!(i&&r&&n&&s)}setStrokeHitEnabled(t){g.warn("strokeHitEnabled property is deprecated. Please use hitStrokeWidth instead."),t?this.hitStrokeWidth("auto"):this.hitStrokeWidth(0)}getStrokeHitEnabled(){return 0!==this.hitStrokeWidth()}getSelfRect(){var t=this.size();return{x:this._centroid?-t.width/2:0,y:this._centroid?-t.height/2:0,width:t.width,height:t.height}}getClientRect(t={}){const e=t.skipTransform,i=t.relativeTo,r=this.getSelfRect(),a=!t.skipStroke&&this.hasStroke()&&this.strokeWidth()||0,n=r.width+a,s=r.height+a,o=!t.skipShadow&&this.hasShadow(),h=o?this.shadowOffsetX():0,l=o?this.shadowOffsetY():0,d=n+Math.abs(h),c=s+Math.abs(l),g=o&&this.shadowBlur()||0,u=d+2*g,f=c+2*g;let p=0;Math.round(a/2)!==a/2&&(p=1);const v={width:u+p,height:f+p,x:-Math.round(a/2+g)+Math.min(h,0)+r.x,y:-Math.round(a/2+g)+Math.min(l,0)+r.y};return e?v:this._transformedRect(v,i)}drawScene(t,e){var i,r,a=this.getLayer(),n=t||a.getCanvas(),s=n.getContext(),o=this._getCanvasCache(),h=this.getSceneFunc(),l=this.hasShadow(),d=n.isCache,c=n.isCache,g=e===this;if(!this.isVisible()&&!d)return this;if(o){s.save();var u=this.getAbsoluteTransform(e).getMatrix();return s.transform(u[0],u[1],u[2],u[3],u[4],u[5]),this._drawCachedSceneCanvas(s),s.restore(),this}if(!h)return this;if(s.save(),this._useBufferCanvas()&&!c){(r=(i=this.getStage().bufferCanvas).getContext()).clear(),r.save(),r._applyLineJoin(this);var f=this.getAbsoluteTransform(e).getMatrix();r.transform(f[0],f[1],f[2],f[3],f[4],f[5]),h.call(this,r,this),r.restore();var p=i.pixelRatio;l&&s._applyShadow(this),s._applyOpacity(this),s._applyGlobalCompositeOperation(this),s.drawImage(i._canvas,0,0,i.width/p,i.height/p)}else{if(s._applyLineJoin(this),!g){f=this.getAbsoluteTransform(e).getMatrix();s.transform(f[0],f[1],f[2],f[3],f[4],f[5]),s._applyOpacity(this),s._applyGlobalCompositeOperation(this)}l&&s._applyShadow(this),h.call(this,s,this)}return s.restore(),this}drawHit(t,e,i=!1){if(!this.shouldDrawHit(e,i))return this;var r=this.getLayer(),a=t||r.hitCanvas,n=a&&a.getContext(),s=this.hitFunc()||this.sceneFunc(),o=this._getCanvasCache(),h=o&&o.hit;if(this.colorKey||g.warn("Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. If you want to reuse shape you should call remove() instead of destroy()"),h){n.save();var l=this.getAbsoluteTransform(e).getMatrix();return n.transform(l[0],l[1],l[2],l[3],l[4],l[5]),this._drawCachedHitCanvas(n),n.restore(),this}if(!s)return this;n.save(),n._applyLineJoin(this);if(!(this===e)){var d=this.getAbsoluteTransform(e).getMatrix();n.transform(d[0],d[1],d[2],d[3],d[4],d[5])}return s.call(this,n,this),n.restore(),this}drawHitFromCache(t=0){var e,i,r,a,n,s=this._getCanvasCache(),o=this._getCachedSceneCanvas(),h=s.hit,l=h.getContext(),d=h.getWidth(),c=h.getHeight();l.clear(),l.drawImage(o._canvas,0,0,d,c);try{for(r=(i=(e=l.getImageData(0,0,d,c)).data).length,a=g._hexToRgb(this.colorKey),n=0;nt?(i[n]=a.r,i[n+1]=a.g,i[n+2]=a.b,i[n+3]=255):i[n+3]=0;l.putImageData(e,0,0)}catch(t){g.error("Unable to draw hit graph from cached scene canvas. "+t.message)}return this}hasPointerCapture(t){return U(t,this)}setPointerCapture(t){q(t,this)}releaseCapture(t){K(t)}}at.prototype._fillFunc=function(t){t.fill()},at.prototype._strokeFunc=function(t){t.stroke()},at.prototype._fillFuncHit=function(t){t.fill()},at.prototype._strokeFuncHit=function(t){t.stroke()},at.prototype._centroid=!1,at.prototype.nodeType="Shape",n(at),at.prototype.eventListeners={},at.prototype.on.call(at.prototype,"shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva",(function(){this._clearCache("hasShadow")})),at.prototype.on.call(at.prototype,"shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva",(function(){this._clearCache("shadowRGBA")})),at.prototype.on.call(at.prototype,"fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva fillPatternScaleXChange.konva fillPatternScaleYChange.konva",(function(){this._clearCache("patternImage")})),at.prototype.on.call(at.prototype,"fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva",(function(){this._clearCache("linearGradient")})),at.prototype.on.call(at.prototype,"fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva",(function(){this._clearCache("radialGradient")})),b.addGetterSetter(at,"stroke",void 0,y()),b.addGetterSetter(at,"strokeWidth",2,p()),b.addGetterSetter(at,"fillAfterStrokeEnabled",!1),b.addGetterSetter(at,"hitStrokeWidth","auto",m()),b.addGetterSetter(at,"strokeHitEnabled",!0,x()),b.addGetterSetter(at,"perfectDrawEnabled",!0,x()),b.addGetterSetter(at,"shadowForStrokeEnabled",!0,x()),b.addGetterSetter(at,"lineJoin"),b.addGetterSetter(at,"lineCap"),b.addGetterSetter(at,"sceneFunc"),b.addGetterSetter(at,"hitFunc"),b.addGetterSetter(at,"dash"),b.addGetterSetter(at,"dashOffset",0,p()),b.addGetterSetter(at,"shadowColor",void 0,_()),b.addGetterSetter(at,"shadowBlur",0,p()),b.addGetterSetter(at,"shadowOpacity",1,p()),b.addComponentsGetterSetter(at,"shadowOffset",["x","y"]),b.addGetterSetter(at,"shadowOffsetX",0,p()),b.addGetterSetter(at,"shadowOffsetY",0,p()),b.addGetterSetter(at,"fillPatternImage"),b.addGetterSetter(at,"fill",void 0,y()),b.addGetterSetter(at,"fillPatternX",0,p()),b.addGetterSetter(at,"fillPatternY",0,p()),b.addGetterSetter(at,"fillLinearGradientColorStops"),b.addGetterSetter(at,"strokeLinearGradientColorStops"),b.addGetterSetter(at,"fillRadialGradientStartRadius",0),b.addGetterSetter(at,"fillRadialGradientEndRadius",0),b.addGetterSetter(at,"fillRadialGradientColorStops"),b.addGetterSetter(at,"fillPatternRepeat","repeat"),b.addGetterSetter(at,"fillEnabled",!0),b.addGetterSetter(at,"strokeEnabled",!0),b.addGetterSetter(at,"shadowEnabled",!0),b.addGetterSetter(at,"dashEnabled",!0),b.addGetterSetter(at,"strokeScaleEnabled",!0),b.addGetterSetter(at,"fillPriority","color"),b.addComponentsGetterSetter(at,"fillPatternOffset",["x","y"]),b.addGetterSetter(at,"fillPatternOffsetX",0,p()),b.addGetterSetter(at,"fillPatternOffsetY",0,p()),b.addComponentsGetterSetter(at,"fillPatternScale",["x","y"]),b.addGetterSetter(at,"fillPatternScaleX",1,p()),b.addGetterSetter(at,"fillPatternScaleY",1,p()),b.addComponentsGetterSetter(at,"fillLinearGradientStartPoint",["x","y"]),b.addComponentsGetterSetter(at,"strokeLinearGradientStartPoint",["x","y"]),b.addGetterSetter(at,"fillLinearGradientStartPointX",0),b.addGetterSetter(at,"strokeLinearGradientStartPointX",0),b.addGetterSetter(at,"fillLinearGradientStartPointY",0),b.addGetterSetter(at,"strokeLinearGradientStartPointY",0),b.addComponentsGetterSetter(at,"fillLinearGradientEndPoint",["x","y"]),b.addComponentsGetterSetter(at,"strokeLinearGradientEndPoint",["x","y"]),b.addGetterSetter(at,"fillLinearGradientEndPointX",0),b.addGetterSetter(at,"strokeLinearGradientEndPointX",0),b.addGetterSetter(at,"fillLinearGradientEndPointY",0),b.addGetterSetter(at,"strokeLinearGradientEndPointY",0),b.addComponentsGetterSetter(at,"fillRadialGradientStartPoint",["x","y"]),b.addGetterSetter(at,"fillRadialGradientStartPointX",0),b.addGetterSetter(at,"fillRadialGradientStartPointY",0),b.addComponentsGetterSetter(at,"fillRadialGradientEndPoint",["x","y"]),b.addGetterSetter(at,"fillRadialGradientEndPointX",0),b.addGetterSetter(at,"fillRadialGradientEndPointY",0),b.addGetterSetter(at,"fillPatternRotation",0),b.backCompat(at,{dashArray:"dash",getDashArray:"getDash",setDashArray:"getDash",drawFunc:"sceneFunc",getDrawFunc:"getSceneFunc",setDrawFunc:"setSceneFunc",drawHitFunc:"hitFunc",getDrawHitFunc:"getHitFunc",setDrawHitFunc:"setHitFunc"});var nt=[{x:0,y:0},{x:-1,y:-1},{x:1,y:-1},{x:1,y:1},{x:-1,y:1}],st=nt.length;class ot extends W{constructor(t){super(t),this.canvas=new A,this.hitCanvas=new M({pixelRatio:1}),this._waitingForDraw=!1,this.on("visibleChange.konva",this._checkVisibility),this._checkVisibility(),this.on("imageSmoothingEnabledChange.konva",this._setSmoothEnabled),this._setSmoothEnabled()}createPNGStream(){return this.canvas._canvas.createPNGStream()}getCanvas(){return this.canvas}getNativeCanvasElement(){return this.canvas._canvas}getHitCanvas(){return this.hitCanvas}getContext(){return this.getCanvas().getContext()}clear(t){return this.getContext().clear(t),this.getHitCanvas().getContext().clear(t),this}setZIndex(t){super.setZIndex(t);var e=this.getStage();return e&&e.content&&(e.content.removeChild(this.getNativeCanvasElement()),t{this.draw(),this._waitingForDraw=!1})),this}getIntersection(t,e){if(!this.isListening()||!this.isVisible())return null;for(var i=1,r=!1;;){for(let a=0;a0?{antialiased:!0}:{}}drawScene(t,e){var i=this.getLayer(),r=t||i&&i.getCanvas();return this._fire("beforeDraw",{node:this}),this.clearBeforeDraw()&&r.getContext().clear(),W.prototype.drawScene.call(this,r,e),this._fire("draw",{node:this}),this}drawHit(t,e){var i=this.getLayer(),r=t||i&&i.hitCanvas;return i&&i.clearBeforeDraw()&&i.getHitCanvas().getContext().clear(),W.prototype.drawHit.call(this,r,e),this}enableHitGraph(){return this.hitGraphEnabled(!0),this}disableHitGraph(){return this.hitGraphEnabled(!1),this}setHitGraphEnabled(t){g.warn("hitGraphEnabled method is deprecated. Please use layer.listening() instead."),this.listening(t)}getHitGraphEnabled(t){return g.warn("hitGraphEnabled method is deprecated. Please use layer.listening() instead."),this.listening()}toggleHitCanvas(){if(this.parent&&this.parent.content){var t=this.parent;!!this.hitCanvas._canvas.parentNode?t.content.removeChild(this.hitCanvas._canvas):t.content.appendChild(this.hitCanvas._canvas)}}}ot.prototype.nodeType="Layer",n(ot),b.addGetterSetter(ot,"imageSmoothingEnabled",!0),b.addGetterSetter(ot,"clearBeforeDraw",!0),b.addGetterSetter(ot,"hitGraphEnabled",!0,x());class ht extends ot{constructor(t){super(t),this.listening(!1),g.warn('Konva.Fast layer is deprecated. Please use "new Konva.Layer({ listening: false })" instead.')}}ht.prototype.nodeType="FastLayer",n(ht);class lt extends W{_validateAdd(t){var e=t.getType();"Group"!==e&&"Shape"!==e&&g.throw("You may only add groups and shapes to groups.")}}lt.prototype.nodeType="Group",n(lt);var dt=r.performance&&r.performance.now?function(){return r.performance.now()}:function(){return(new Date).getTime()};class ct{constructor(t,e){this.id=ct.animIdCounter++,this.frame={time:0,timeDiff:0,lastTime:dt(),frameRate:0},this.func=t,this.setLayers(e)}setLayers(t){var e=[];return e=t?t.length>0?t:[t]:[],this.layers=e,this}getLayers(){return this.layers}addLayer(t){var e,i=this.layers,r=i.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())}getTime(){return this._time}setPosition(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t}getPosition(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)}play(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")}reverse(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")}seek(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")}reset(){this.pause(),this._time=0,this.update(),this.fire("onReset")}finish(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")}update(){this.setPosition(this.getPosition(this._time)),this.fire("onUpdate")}onEnterFrame(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)}pause(){this.state=1,this.fire("onPause")}getTimer(){return(new Date).getTime()}}class vt{constructor(t){var e,i,r=this,n=t.node,s=n._id,o=t.easing||mt.Linear,h=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=n,this._id=ut++;var l=n.getLayer()||(n instanceof a.Stage?n.getLayers():null);for(i in l||g.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new ct((function(){r.tween.onEnterFrame()}),l),this.tween=new pt(i,(function(t){r._tweenFunc(t)}),o,0,1,1e3*e,h),this._addListeners(),vt.attrs[s]||(vt.attrs[s]={}),vt.attrs[s][this._id]||(vt.attrs[s][this._id]={}),vt.tweens[s]||(vt.tweens[s]={}),t)void 0===gt[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset,this.onUpdate=t.onUpdate}_addAttr(t,e){var i,r,a,n,s,o,h,l,d=this.node,c=d._id;if((a=vt.tweens[c][t])&&delete vt.attrs[c][a][t],i=d.getAttr(t),g._isArray(e))if(r=[],s=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=g._prepareArrayForTween(i,e,d.closed())):(o=e,e=g._prepareArrayForTween(e,i,d.closed()))),0===t.indexOf("fill"))for(n=0;n{this.anim.start()},this.tween.onReverse=()=>{this.anim.start()},this.tween.onPause=()=>{this.anim.stop()},this.tween.onFinish=()=>{var t=this.node,e=vt.attrs[t._id][this._id];e.points&&e.points.trueEnd&&t.setAttr("points",e.points.trueEnd),this.onFinish&&this.onFinish.call(this)},this.tween.onReset=()=>{var t=this.node,e=vt.attrs[t._id][this._id];e.points&&e.points.trueStart&&t.points(e.points.trueStart),this.onReset&&this.onReset()},this.tween.onUpdate=()=>{this.onUpdate&&this.onUpdate.call(this)}}play(){return this.tween.play(),this}reverse(){return this.tween.reverse(),this}reset(){return this.tween.reset(),this}seek(t){return this.tween.seek(1e3*t),this}pause(){return this.tween.pause(),this}finish(){return this.tween.finish(),this}destroy(){var t,e=this.node._id,i=this._id,r=vt.tweens[e];for(t in this.pause(),r)delete vt.tweens[e][t];delete vt.attrs[e][i]}}vt.attrs={},vt.tweens={},N.prototype.to=function(t){var e=t.onFinish;t.node=this,t.onFinish=function(){this.destroy(),e&&e()},new vt(t).play()};const mt={BackEaseIn(t,e,i,r){var a=1.70158;return i*(t/=r)*t*((a+1)*t-a)+e},BackEaseOut(t,e,i,r){var a=1.70158;return i*((t=t/r-1)*t*((a+1)*t+a)+1)+e},BackEaseInOut(t,e,i,r){var a=1.70158;return(t/=r/2)<1?i/2*(t*t*((1+(a*=1.525))*t-a))+e:i/2*((t-=2)*t*((1+(a*=1.525))*t+a)+2)+e},ElasticEaseIn(t,e,i,r,a,n){var s=0;return 0===t?e:1==(t/=r)?e+i:(n||(n=.3*r),!a||a(t/=r)<1/2.75?i*(7.5625*t*t)+e:t<2/2.75?i*(7.5625*(t-=1.5/2.75)*t+.75)+e:t<2.5/2.75?i*(7.5625*(t-=2.25/2.75)*t+.9375)+e:i*(7.5625*(t-=2.625/2.75)*t+.984375)+e,BounceEaseIn:(t,e,i,r)=>i-mt.BounceEaseOut(r-t,0,i,r)+e,BounceEaseInOut:(t,e,i,r)=>ti*(t/=r)*t+e,EaseOut:(t,e,i,r)=>-i*(t/=r)*(t-2)+e,EaseInOut:(t,e,i,r)=>(t/=r/2)<1?i/2*t*t+e:-i/2*(--t*(t-2)-1)+e,StrongEaseIn:(t,e,i,r)=>i*(t/=r)*t*t*t*t+e,StrongEaseOut:(t,e,i,r)=>i*((t=t/r-1)*t*t*t*t+1)+e,StrongEaseInOut:(t,e,i,r)=>(t/=r/2)<1?i/2*t*t*t*t*t+e:i/2*((t-=2)*t*t*t*t+2)+e,Linear:(t,e,i,r)=>i*t/r+e},_t=g._assign(a,{Util:g,Transform:s,Node:N,ids:E,names:R,Container:W,Stage:tt,stages:Z,Layer:ot,FastLayer:ht,Group:lt,DD:G,Shape:at,shapes:rt,Animation:ct,Tween:vt,Easings:mt,Context:w,Canvas:T});class yt extends at{_sceneFunc(t){var e=a.getAngle(this.angle()),i=this.clockwise();t.beginPath(),t.arc(0,0,this.outerRadius(),0,e,i),t.arc(0,0,this.innerRadius(),e,0,!i),t.closePath(),t.fillStrokeShape(this)}getWidth(){return 2*this.outerRadius()}getHeight(){return 2*this.outerRadius()}setWidth(t){this.outerRadius(t/2)}setHeight(t){this.outerRadius(t/2)}}yt.prototype._centroid=!0,yt.prototype.className="Arc",yt.prototype._attrsAffectingSize=["innerRadius","outerRadius"],n(yt),b.addGetterSetter(yt,"innerRadius",0,p()),b.addGetterSetter(yt,"outerRadius",0,p()),b.addGetterSetter(yt,"angle",0,p()),b.addGetterSetter(yt,"clockwise",!1,x());class xt extends at{constructor(t){super(t),this.on("pointsChange.konva tensionChange.konva closedChange.konva bezierChange.konva",(function(){this._clearCache("tensionPoints")}))}_sceneFunc(t){var e,i,r,a=this.points(),n=a.length,s=this.tension(),o=this.closed(),h=this.bezier();if(n){if(t.beginPath(),t.moveTo(a[0],a[1]),0!==s&&n>4){for(i=(e=this.getTensionPoints()).length,r=o?0:4,o||t.quadraticCurveTo(e[0],e[1],e[2],e[3]);r4;a&&(r=this.getTensionPoints());var n,s,o=i.length;a?(n=i[o-2]-(r[r.length-2]+r[r.length-4])/2,s=i[o-1]-(r[r.length-1]+r[r.length-3])/2):(n=i[o-2]-i[o-4],s=i[o-1]-i[o-3]);var h=(Math.atan2(s,n)+e)%e,l=this.pointerLength(),d=this.pointerWidth();this.pointerAtEnding()&&(t.save(),t.beginPath(),t.translate(i[o-2],i[o-1]),t.rotate(h),t.moveTo(0,0),t.lineTo(-l,d/2),t.lineTo(-l,-d/2),t.closePath(),t.restore()),this.pointerAtBeginning()&&(t.save(),t.translate(i[0],i[1]),a?(n=(r[0]+r[2])/2-i[0],s=(r[1]+r[3])/2-i[1]):(n=i[2]-i[0],s=i[3]-i[1]),t.rotate((Math.atan2(-s,-n)+e)%e),t.moveTo(0,0),t.lineTo(-l,d/2),t.lineTo(-l,-d/2),t.closePath(),t.restore());var c=this.dashEnabled();c&&(this.attrs.dashEnabled=!1,t.setLineDash([])),t.fillStrokeShape(this),c&&(this.attrs.dashEnabled=!0)}getSelfRect(){const t=super.getSelfRect(),e=this.pointerWidth()/2;return{x:t.x-e,y:t.y-e,width:t.width+2*e,height:t.height+2*e}}}bt.prototype.className="Arrow",n(bt),b.addGetterSetter(bt,"pointerLength",10,p()),b.addGetterSetter(bt,"pointerWidth",10,p()),b.addGetterSetter(bt,"pointerAtBeginning",!1),b.addGetterSetter(bt,"pointerAtEnding",!0);class St extends at{_sceneFunc(t){t.beginPath(),t.arc(0,0,this.attrs.radius||0,0,2*Math.PI,!1),t.closePath(),t.fillStrokeShape(this)}getWidth(){return 2*this.radius()}getHeight(){return 2*this.radius()}setWidth(t){this.radius()!==t/2&&this.radius(t/2)}setHeight(t){this.radius()!==t/2&&this.radius(t/2)}}St.prototype._centroid=!0,St.prototype.className="Circle",St.prototype._attrsAffectingSize=["radius"],n(St),b.addGetterSetter(St,"radius",0,p());class wt extends at{_sceneFunc(t){var e=this.radiusX(),i=this.radiusY();t.beginPath(),t.save(),e!==i&&t.scale(1,i/e),t.arc(0,0,e,0,2*Math.PI,!1),t.restore(),t.closePath(),t.fillStrokeShape(this)}getWidth(){return 2*this.radiusX()}getHeight(){return 2*this.radiusY()}setWidth(t){this.radiusX(t/2)}setHeight(t){this.radiusY(t/2)}}wt.prototype.className="Ellipse",wt.prototype._centroid=!0,wt.prototype._attrsAffectingSize=["radiusX","radiusY"],n(wt),b.addComponentsGetterSetter(wt,"radius",["x","y"]),b.addGetterSetter(wt,"radiusX",0,p()),b.addGetterSetter(wt,"radiusY",0,p());class Ct extends at{constructor(t){super(t),this.on("imageChange.konva",()=>{this._setImageLoad()}),this._setImageLoad()}_setImageLoad(){const t=this.image();t&&t.addEventListener&&t.addEventListener("load",()=>{this._requestDraw()})}_useBufferCanvas(){return super._useBufferCanvas(!0)}_sceneFunc(t){const e=this.getWidth(),i=this.getHeight(),r=this.attrs.image;let a;if(r){const t=this.attrs.cropWidth,n=this.attrs.cropHeight;a=t&&n?[r,this.cropX(),this.cropY(),t,n,0,0,e,i]:[r,0,0,e,i]}(this.hasFill()||this.hasStroke())&&(t.beginPath(),t.rect(0,0,e,i),t.closePath(),t.fillStrokeShape(this)),r&&t.drawImage.apply(t,a)}_hitFunc(t){var e=this.width(),i=this.height();t.beginPath(),t.rect(0,0,e,i),t.closePath(),t.fillStrokeShape(this)}getWidth(){var t,e;return null!==(t=this.attrs.width)&&void 0!==t?t:null===(e=this.image())||void 0===e?void 0:e.width}getHeight(){var t,e;return null!==(t=this.attrs.height)&&void 0!==t?t:null===(e=this.image())||void 0===e?void 0:e.height}static fromURL(t,e){var i=g.createImageElement();i.onload=function(){var t=new Ct({image:i});e(t)},i.crossOrigin="Anonymous",i.src=t}}Ct.prototype.className="Image",n(Ct),b.addGetterSetter(Ct,"image"),b.addComponentsGetterSetter(Ct,"crop",["x","y","width","height"]),b.addGetterSetter(Ct,"cropX",0,p()),b.addGetterSetter(Ct,"cropY",0,p()),b.addGetterSetter(Ct,"cropWidth",0,p()),b.addGetterSetter(Ct,"cropHeight",0,p());var Pt=["fontFamily","fontSize","fontStyle","padding","lineHeight","text","width","height"],kt=Pt.length;class Tt extends lt{constructor(t){super(t),this.on("add.konva",(function(t){this._addListeners(t.child),this._sync()}))}getText(){return this.find("Text")[0]}getTag(){return this.find("Tag")[0]}_addListeners(t){var e,i=this,r=function(){i._sync()};for(e=0;el?h:l,p=h>l?1:h/l,v=h>l?l/h:1;t.translate(s,o),t.rotate(g),t.scale(p,v),t.arc(0,0,f,d,d+c,1-u),t.scale(1/p,1/v),t.rotate(-g),t.translate(-s,-o);break;case"z":i=!0,t.closePath()}}i||this.hasFill()?t.fillStrokeShape(this):t.strokeShape(this)}getSelfRect(){var t=[];this.dataArray.forEach((function(e){if("A"===e.command){var i=e.points[4],r=e.points[5],a=e.points[4]+r,n=Math.PI/180;if(Math.abs(i-a)a;r-=n){const i=Mt.getPointOnEllipticalArc(e.points[0],e.points[1],e.points[2],e.points[3],r,0);t.push(i.x,i.y)}else for(let r=i+n;rthis.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 a=this.dataArray[i],n=a.points;switch(a.command){case"L":return Mt.getPointOnLine(t,a.start.x,a.start.y,n[0],n[1]);case"C":return Mt.getPointOnCubicBezier(t/a.pathLength,a.start.x,a.start.y,n[0],n[1],n[2],n[3],n[4],n[5]);case"Q":return Mt.getPointOnQuadraticBezier(t/a.pathLength,a.start.x,a.start.y,n[0],n[1],n[2],n[3]);case"A":var s=n[0],o=n[1],h=n[2],l=n[3],d=n[4],c=n[5],g=n[6];return d+=c*t/a.pathLength,Mt.getPointOnEllipticalArc(s,o,h,l,d,g)}return null}static getLineLength(t,e,i,r){return Math.sqrt((i-t)*(i-t)+(r-e)*(r-e))}static getPointOnLine(t,e,i,r,a,n,s){void 0===n&&(n=e),void 0===s&&(s=i);var o=(a-i)/(r-e+1e-8),h=Math.sqrt(t*t/(1+o*o));r0&&!isNaN(u[0]);){var m,_,y,x,b,S,w,C,P,k,T=null,A=[],M=h,G=l;switch(g){case"l":h+=u.shift(),l+=u.shift(),T="L",A.push(h,l);break;case"L":h=u.shift(),l=u.shift(),A.push(h,l);break;case"m":var E=u.shift(),R=u.shift();if(h+=E,l+=R,T="M",s.length>2&&"z"===s[s.length-1].command)for(var L=s.length-2;L>=0;L--)if("M"===s[L].command){h=s[L].points[0]+E,l=s[L].points[1]+R;break}A.push(h,l),g="l";break;case"M":h=u.shift(),l=u.shift(),T="M",A.push(h,l),g="L";break;case"h":h+=u.shift(),T="L",A.push(h,l);break;case"H":h=u.shift(),T="L",A.push(h,l);break;case"v":l+=u.shift(),T="L",A.push(h,l);break;case"V":l=u.shift(),T="L",A.push(h,l);break;case"C":A.push(u.shift(),u.shift(),u.shift(),u.shift()),h=u.shift(),l=u.shift(),A.push(h,l);break;case"c":A.push(h+u.shift(),l+u.shift(),h+u.shift(),l+u.shift()),h+=u.shift(),l+=u.shift(),T="C",A.push(h,l);break;case"S":_=h,y=l,"C"===(m=s[s.length-1]).command&&(_=h+(h-m.points[2]),y=l+(l-m.points[3])),A.push(_,y,u.shift(),u.shift()),h=u.shift(),l=u.shift(),T="C",A.push(h,l);break;case"s":_=h,y=l,"C"===(m=s[s.length-1]).command&&(_=h+(h-m.points[2]),y=l+(l-m.points[3])),A.push(_,y,h+u.shift(),l+u.shift()),h+=u.shift(),l+=u.shift(),T="C",A.push(h,l);break;case"Q":A.push(u.shift(),u.shift()),h=u.shift(),l=u.shift(),A.push(h,l);break;case"q":A.push(h+u.shift(),l+u.shift()),h+=u.shift(),l+=u.shift(),T="Q",A.push(h,l);break;case"T":_=h,y=l,"Q"===(m=s[s.length-1]).command&&(_=h+(h-m.points[0]),y=l+(l-m.points[1])),h=u.shift(),l=u.shift(),T="Q",A.push(_,y,h,l);break;case"t":_=h,y=l,"Q"===(m=s[s.length-1]).command&&(_=h+(h-m.points[0]),y=l+(l-m.points[1])),h+=u.shift(),l+=u.shift(),T="Q",A.push(_,y,h,l);break;case"A":x=u.shift(),b=u.shift(),S=u.shift(),w=u.shift(),C=u.shift(),P=h,k=l,h=u.shift(),l=u.shift(),T="A",A=this.convertEndpointToCenterParameterization(P,k,h,l,w,C,x,b,S);break;case"a":x=u.shift(),b=u.shift(),S=u.shift(),w=u.shift(),C=u.shift(),P=h,k=l,h+=u.shift(),l+=u.shift(),T="A",A=this.convertEndpointToCenterParameterization(P,k,h,l,w,C,x,b,S)}s.push({command:T||g,points:A,start:{x:M,y:G},pathLength:this.calcLength(M,G,T||g,A)})}"z"!==g&&"Z"!==g||s.push({command:"z",points:[],start:void 0,pathLength:0})}return s}static calcLength(t,e,i,r){var a,n,s,o,h=Mt;switch(i){case"L":return h.getLineLength(t,e,r[0],r[1]);case"C":for(a=0,n=h.getPointOnCubicBezier(0,t,e,r[0],r[1],r[2],r[3],r[4],r[5]),o=.01;o<=1;o+=.01)s=h.getPointOnCubicBezier(o,t,e,r[0],r[1],r[2],r[3],r[4],r[5]),a+=h.getLineLength(n.x,n.y,s.x,s.y),n=s;return a;case"Q":for(a=0,n=h.getPointOnQuadraticBezier(0,t,e,r[0],r[1],r[2],r[3]),o=.01;o<=1;o+=.01)s=h.getPointOnQuadraticBezier(o,t,e,r[0],r[1],r[2],r[3]),a+=h.getLineLength(n.x,n.y,s.x,s.y),n=s;return a;case"A":a=0;var l=r[4],d=r[5],c=r[4]+d,g=Math.PI/180;if(Math.abs(l-c)c;o-=g)s=h.getPointOnEllipticalArc(r[0],r[1],r[2],r[3],o,0),a+=h.getLineLength(n.x,n.y,s.x,s.y),n=s;else for(o=l+g;o1&&(s*=Math.sqrt(g),o*=Math.sqrt(g));var u=Math.sqrt((s*s*(o*o)-s*s*(c*c)-o*o*(d*d))/(s*s*(c*c)+o*o*(d*d)));a===n&&(u*=-1),isNaN(u)&&(u=0);var f=u*s*c/o,p=u*-o*d/s,v=(t+i)/2+Math.cos(l)*f-Math.sin(l)*p,m=(e+r)/2+Math.sin(l)*f+Math.cos(l)*p,_=function(t){return Math.sqrt(t[0]*t[0]+t[1]*t[1])},y=function(t,e){return(t[0]*e[0]+t[1]*e[1])/(_(t)*_(e))},x=function(t,e){return(t[0]*e[1]=1&&(C=0),0===n&&C>0&&(C-=2*Math.PI),1===n&&C<0&&(C+=2*Math.PI),[v,m,s,o,b,C,l,n]}}Mt.prototype.className="Path",Mt.prototype._attrsAffectingSize=["data"],n(Mt),b.addGetterSetter(Mt,"data");class Gt extends at{_sceneFunc(t){var e=this.cornerRadius(),i=this.width(),r=this.height();if(t.beginPath(),e){let a=0,n=0,s=0,o=0;"number"==typeof e?a=n=s=o=Math.min(e,i/2,r/2):(a=Math.min(e[0]||0,i/2,r/2),n=Math.min(e[1]||0,i/2,r/2),o=Math.min(e[2]||0,i/2,r/2),s=Math.min(e[3]||0,i/2,r/2)),t.moveTo(a,0),t.lineTo(i-n,0),t.arc(i-n,n,n,3*Math.PI/2,0,!1),t.lineTo(i,r-o),t.arc(i-o,r-o,o,0,Math.PI/2,!1),t.lineTo(s,r),t.arc(s,r-s,s,Math.PI/2,Math.PI,!1),t.lineTo(0,a),t.arc(a,a,a,Math.PI,3*Math.PI/2,!1)}else t.rect(0,0,i,r);t.closePath(),t.fillStrokeShape(this)}}Gt.prototype.className="Rect",n(Gt),b.addGetterSetter(Gt,"cornerRadius",0,v(4));class Et extends at{_sceneFunc(t){const e=this._getPoints();t.beginPath(),t.moveTo(e[0].x,e[0].y);for(var i=1;i{e=Math.min(e,t.x),i=Math.max(i,t.x),r=Math.min(r,t.y),a=Math.max(a,t.y)}),{x:e,y:r,width:i-e,height:a-r}}getWidth(){return 2*this.radius()}getHeight(){return 2*this.radius()}setWidth(t){this.radius(t/2)}setHeight(t){this.radius(t/2)}}Et.prototype.className="RegularPolygon",Et.prototype._centroid=!0,Et.prototype._attrsAffectingSize=["radius"],n(Et),b.addGetterSetter(Et,"radius",0,p()),b.addGetterSetter(Et,"sides",0,p());var Rt=2*Math.PI;class Lt extends at{_sceneFunc(t){t.beginPath(),t.arc(0,0,this.innerRadius(),0,Rt,!1),t.moveTo(this.outerRadius(),0),t.arc(0,0,this.outerRadius(),Rt,0,!0),t.closePath(),t.fillStrokeShape(this)}getWidth(){return 2*this.outerRadius()}getHeight(){return 2*this.outerRadius()}setWidth(t){this.outerRadius(t/2)}setHeight(t){this.outerRadius(t/2)}}Lt.prototype.className="Ring",Lt.prototype._centroid=!0,Lt.prototype._attrsAffectingSize=["innerRadius","outerRadius"],n(Lt),b.addGetterSetter(Lt,"innerRadius",0,p()),b.addGetterSetter(Lt,"outerRadius",0,p());class Dt extends at{constructor(t){super(t),this._updated=!0,this.anim=new ct(()=>{var t=this._updated;return this._updated=!1,t}),this.on("animationChange.konva",(function(){this.frameIndex(0)})),this.on("frameIndexChange.konva",(function(){this._updated=!0})),this.on("frameRateChange.konva",(function(){this.anim.isRunning()&&(clearInterval(this.interval),this._setInterval())}))}_sceneFunc(t){var e=this.animation(),i=this.frameIndex(),r=4*i,a=this.animations()[e],n=this.frameOffsets(),s=a[r+0],o=a[r+1],h=a[r+2],l=a[r+3],d=this.image();if((this.hasFill()||this.hasStroke())&&(t.beginPath(),t.rect(0,0,h,l),t.closePath(),t.fillStrokeShape(this)),d)if(n){var c=n[e],g=2*i;t.drawImage(d,s,o,h,l,c[g+0],c[g+1],h,l)}else t.drawImage(d,s,o,h,l,0,0,h,l)}_hitFunc(t){var e=this.animation(),i=this.frameIndex(),r=4*i,a=this.animations()[e],n=this.frameOffsets(),s=a[r+2],o=a[r+3];if(t.beginPath(),n){var h=n[e],l=2*i;t.rect(h[l+0],h[l+1],s,o)}else t.rect(0,0,s,o);t.closePath(),t.fillShape(this)}_useBufferCanvas(){return super._useBufferCanvas(!0)}_setInterval(){var t=this;this.interval=setInterval((function(){t._updateIndex()}),1e3/this.frameRate())}start(){if(!this.isRunning()){var t=this.getLayer();this.anim.setLayers(t),this._setInterval(),this.anim.start()}}stop(){this.anim.stop(),clearInterval(this.interval)}isRunning(){return this.anim.isRunning()}_updateIndex(){var t=this.frameIndex(),e=this.animation();t1&&(v+=s)}}}_hitFunc(t){var e=this.getWidth(),i=this.getHeight();t.beginPath(),t.rect(0,0,e,i),t.closePath(),t.fillStrokeShape(this)}setText(t){var e=g._isString(t)?t:null==t?"":t+"";return this._setAttr("text",e),this}getWidth(){return"auto"===this.attrs.width||void 0===this.attrs.width?this.getTextWidth()+2*this.padding():this.attrs.width}getHeight(){return"auto"===this.attrs.height||void 0===this.attrs.height?this.fontSize()*this.textArr.length*this.lineHeight()+2*this.padding():this.attrs.height}getTextWidth(){return this.textWidth}getTextHeight(){return g.warn("text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height."),this.textHeight}measureSize(t){var e,i=zt(),r=this.fontSize();return i.save(),i.font=this._getContextFont(),e=i.measureText(t),i.restore(),{width:e.width,height:r}}_getContextFont(){return a.UA.isIE?this.fontStyle()+" "+this.fontSize()+"px "+this.fontFamily():this.fontStyle()+" "+this.fontVariant()+" "+this.fontSize()+"px "+this.fontFamily().split(",").map(t=>{const e=(t=t.trim()).indexOf(" ")>=0,i=t.indexOf('"')>=0||t.indexOf("'")>=0;return e&&!i&&(t=`"${t}"`),t}).join(", ")}_addTextLine(t){"justify"===this.align()&&(t=t.trim());var e=this._getTextWidth(t);return this.textArr.push({text:t,width:e})}_getTextWidth(t){var e=this.letterSpacing(),i=t.length;return zt().measureText(t).width+(i?e*(i-1):0)}_setTextData(){var t=this.text().split("\n"),e=+this.fontSize(),i=0,r=this.lineHeight()*e,a=this.attrs.width,n=this.attrs.height,s="auto"!==a&&void 0!==a,o="auto"!==n&&void 0!==n,h=this.padding(),l=a-2*h,d=n-2*h,c=0,g=this.wrap(),u="none"!==g,f="char"!==g&&u,p=this.ellipsis();this.textArr=[],zt().font=this._getContextFont();for(var v=p?this._getTextWidth("…"):0,m=0,_=t.length;m<_;++m){var y=t[m],x=this._getTextWidth(y);if(s&&x>l)for(;y.length>0;){for(var b=0,S=y.length,w="",C=0;b>>1,k=y.slice(0,P+1),T=this._getTextWidth(k)+v;T<=l?(b=P+1,w=k,C=T):S=P}if(!w)break;if(f){var A,M=y[w.length];(A=(" "===M||"-"===M)&&C<=l?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)>0&&(b=A,w=w.slice(0,b),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=r,!u||o&&c+r>d){var G=this.textArr[this.textArr.length-1];if(G)if(p)this._getTextWidth(G.text+"…")0&&(x=this._getTextWidth(y))<=l){this._addTextLine(y),c+=r,i=Math.max(i,x);break}}else this._addTextLine(y),c+=r,i=Math.max(i,x);if(o&&c+r>d)break}this.textHeight=e,this.textWidth=i}getStrokeScaleEnabled(){return!0}}Wt.prototype._fillFunc=function(t){t.fillText(this._partialText,this._partialTextX,this._partialTextY)},Wt.prototype._strokeFunc=function(t){t.strokeText(this._partialText,this._partialTextX,this._partialTextY)},Wt.prototype.className="Text",Wt.prototype._attrsAffectingSize=["text","fontSize","padding","wrap","lineHeight","letterSpacing"],n(Wt),b.overWriteSetter(Wt,"width",m()),b.overWriteSetter(Wt,"height",m()),b.addGetterSetter(Wt,"fontFamily","Arial"),b.addGetterSetter(Wt,"fontSize",12,p()),b.addGetterSetter(Wt,"fontStyle","normal"),b.addGetterSetter(Wt,"fontVariant","normal"),b.addGetterSetter(Wt,"padding",0,p()),b.addGetterSetter(Wt,"align","left"),b.addGetterSetter(Wt,"verticalAlign","top"),b.addGetterSetter(Wt,"lineHeight",1,p()),b.addGetterSetter(Wt,"wrap","word"),b.addGetterSetter(Wt,"ellipsis",!1,x()),b.addGetterSetter(Wt,"letterSpacing",0,p()),b.addGetterSetter(Wt,"text","",_()),b.addGetterSetter(Wt,"textDecoration","");function Ht(t){t.fillText(this.partialText,0,0)}function Yt(t){t.strokeText(this.partialText,0,0)}class Xt extends at{constructor(t){super(t),this.dummyCanvas=g.createCanvasElement(),this.dataArray=[],this.dataArray=Mt.parsePathData(this.attrs.data),this.on("dataChange.konva",(function(){this.dataArray=Mt.parsePathData(this.attrs.data),this._setTextData()})),this.on("textChange.konva alignChange.konva letterSpacingChange.konva kerningFuncChange.konva fontSizeChange.konva",this._setTextData),t&&t.getKerning&&(g.warn('getKerning TextPath API is deprecated. Please use "kerningFunc" instead.'),this.kerningFunc(t.getKerning)),this._setTextData()}_sceneFunc(t){t.setAttr("font",this._getContextFont()),t.setAttr("textBaseline",this.textBaseline()),t.setAttr("textAlign","left"),t.save();var e=this.textDecoration(),i=this.fill(),r=this.fontSize(),a=this.glyphInfo;"underline"===e&&t.beginPath();for(var n=0;n=1){var i=e[0].p0;t.moveTo(i.x,i.y)}for(var r=0;r0&&(s+=t.dataArray[o].pathLength);var h=0;"center"===r&&(h=Math.max(0,s/2-n/2)),"right"===r&&(h=Math.max(0,s-n));for(var l,d,c,g=Ot(this.text()),u=this.text().split(" ").length-1,f=-1,p=0,v=function(){p=0;for(var e=t.dataArray,i=f+1;i0)return f=i,e[i];"M"===e[i].command&&(l={x:e[i].points[0],y:e[i].points[1]})}return{}},m=function(e){var a=t._getTextSize(e).width+i;" "===e&&"justify"===r&&(a+=(s-n)/u);var o=0,h=0;for(d=void 0;Math.abs(a-o)/a>.01&&h<20;){h++;for(var g=o;void 0===c;)(c=v())&&g+c.pathLengtha?d=Mt.getPointOnLine(a,l.x,l.y,c.points[0],c.points[1],l.x,l.y):c=void 0;break;case"A":var m=c.points[4],_=c.points[5],y=c.points[4]+_;0===p?p=m+1e-8:a>o?p+=Math.PI/180*_/Math.abs(_):p-=Math.PI/360*_/Math.abs(_),(_<0&&p=0&&p>y)&&(p=y,f=!0),d=Mt.getPointOnEllipticalArc(c.points[0],c.points[1],c.points[2],c.points[3],p,c.points[6]);break;case"C":0===p?p=a>c.pathLength?1e-8:a/c.pathLength:a>o?p+=(a-o)/c.pathLength/2:p=Math.max(p-(o-a)/c.pathLength/2,0),p>1&&(p=1,f=!0),d=Mt.getPointOnCubicBezier(p,c.start.x,c.start.y,c.points[0],c.points[1],c.points[2],c.points[3],c.points[4],c.points[5]);break;case"Q":0===p?p=a/c.pathLength:a>o?p+=(a-o)/c.pathLength:p-=(o-a)/c.pathLength,p>1&&(p=1,f=!0),d=Mt.getPointOnQuadraticBezier(p,c.start.x,c.start.y,c.points[0],c.points[1],c.points[2],c.points[3])}void 0!==d&&(o=Mt.getLineLength(l.x,l.y,d.x,d.y)),f&&(f=!1,c=void 0)}},_=h/(t._getTextSize("C").width+i)-1,y=0;y<_&&(m("C"),void 0!==l&&void 0!==d);y++)l=d;for(var x=0;xt+".tr-konva").join(" "),Ut=["widthChange","heightChange","scaleXChange","scaleYChange","skewXChange","skewYChange","rotationChange","offsetXChange","offsetYChange","transformsEnabledChange","strokeWidthChange"].map(t=>t+".tr-konva").join(" "),qt={"top-left":-45,"top-center":0,"top-right":45,"middle-right":-90,"middle-left":90,"bottom-left":-135,"bottom-center":180,"bottom-right":135};const Kt="ontouchstart"in a._global;var Vt=["top-left","top-center","top-right","middle-right","middle-left","bottom-left","bottom-center","bottom-right"];function Qt(t,e,i){const r=i.x+(t.x-i.x)*Math.cos(e)-(t.y-i.y)*Math.sin(e),a=i.y+(t.x-i.x)*Math.sin(e)+(t.y-i.y)*Math.cos(e);return Object.assign(Object.assign({},t),{rotation:t.rotation+e,x:r,y:a})}function Jt(t,e){return Qt(t,e,function(t){return{x:t.x+t.width/2*Math.cos(t.rotation)+t.height/2*Math.sin(-t.rotation),y:t.y+t.height/2*Math.cos(t.rotation)+t.width/2*Math.sin(t.rotation)}}(t))}class Zt extends lt{constructor(t){super(t),this._transforming=!1,this._createElements(),this._handleMouseMove=this._handleMouseMove.bind(this),this._handleMouseUp=this._handleMouseUp.bind(this),this.update=this.update.bind(this),this.on(jt,this.update),this.getNode()&&this.update()}attachTo(t){return this.setNode(t),this}setNode(t){return g.warn("tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead."),this.setNodes([t])}getNode(){return this._nodes&&this._nodes[0]}setNodes(t=[]){return this._nodes&&this._nodes.length&&this.detach(),this._nodes=t,1===t.length?this.rotation(t[0].getAbsoluteRotation()):this.rotation(0),this._nodes.forEach(t=>{const e=t._attrsAffectingSize.map(t=>t+"Change.tr-konva").join(" "),i=()=>{1===this.nodes().length&&this.rotation(this.nodes()[0].getAbsoluteRotation()),this._resetTransformCache(),this._transforming||this.isDragging()||this.update()};t.on(e,i),t.on(Ut,i),t.on("absoluteTransformChange.tr-konva",i),t.on("xChange.tr-konva yChange.tr-konva",i),this._proxyDrag(t)}),this._resetTransformCache(),!!this.findOne(".top-left")&&this.update(),this}_proxyDrag(t){let e;t.on("dragstart.tr-konva",i=>{e=t.getAbsolutePosition(),this.isDragging()||t===this.findOne(".back")||this.startDrag(i,!1)}),t.on("dragmove.tr-konva",i=>{if(!e)return;const r=t.getAbsolutePosition(),a=r.x-e.x,n=r.y-e.y;this.nodes().forEach(e=>{if(e===t)return;if(e.isDragging())return;const r=e.getAbsolutePosition();e.setAbsolutePosition({x:r.x+a,y:r.y+n}),e.startDrag(i)}),e=null})}getNodes(){return this._nodes||[]}getActiveAnchor(){return this._movingAnchorName}detach(){this._nodes&&this._nodes.forEach(t=>{t.off(".tr-konva")}),this._nodes=[],this._resetTransformCache()}_resetTransformCache(){this._clearCache("nodesRect"),this._clearCache("transform"),this._clearSelfAndDescendantCache("absoluteTransform")}_getNodeRect(){return this._getCache("nodesRect",this.__getNodeRect)}__getNodeShape(t,e=this.rotation(),i){var r=t.getClientRect({skipTransform:!0,skipShadow:!0,skipStroke:this.ignoreStroke()}),n=t.getAbsoluteScale(i),s=t.getAbsolutePosition(i),o=r.x*n.x-t.offsetX()*n.x,h=r.y*n.y-t.offsetY()*n.y;const l=(a.getAngle(t.getAbsoluteRotation())+2*Math.PI)%(2*Math.PI);return Qt({x:s.x+o*Math.cos(l)+h*Math.sin(-l),y:s.y+h*Math.cos(l)+o*Math.sin(l),width:r.width*n.x,height:r.height*n.y,rotation:l},-a.getAngle(e),{x:0,y:0})}__getNodeRect(){if(!this.getNode())return{x:-1e8,y:-1e8,width:0,height:0,rotation:0};const t=[];this.nodes().map(e=>{const i=e.getClientRect({skipTransform:!0,skipShadow:!0,skipStroke:this.ignoreStroke()});var r=[{x:i.x,y:i.y},{x:i.x+i.width,y:i.y},{x:i.x+i.width,y:i.y+i.height},{x:i.x,y:i.y+i.height}],a=e.getAbsoluteTransform();r.forEach((function(e){var i=a.point(e);t.push(i)}))});const e=new s;var i,r,n,o;e.rotate(-a.getAngle(this.rotation())),t.forEach((function(t){var a=e.point(t);void 0===i&&(i=n=a.x,r=o=a.y),i=Math.min(i,a.x),r=Math.min(r,a.y),n=Math.max(n,a.x),o=Math.max(o,a.y)})),e.invert();const h=e.point({x:i,y:r});return{x:h.x,y:h.y,width:n-i,height:o-r,rotation:a.getAngle(this.rotation())}}getX(){return this._getNodeRect().x}getY(){return this._getNodeRect().y}getWidth(){return this._getNodeRect().width}getHeight(){return this._getNodeRect().height}_createElements(){this._createBack(),Vt.forEach(function(t){this._createAnchor(t)}.bind(this)),this._createAnchor("rotater")}_createAnchor(t){var e=new Gt({stroke:"rgb(0, 161, 255)",fill:"white",strokeWidth:1,name:t+" _anchor",dragDistance:0,draggable:!0,hitStrokeWidth:Kt?10:"auto"}),i=this;e.on("mousedown touchstart",(function(t){i._handleMouseDown(t)})),e.on("dragstart",t=>{e.stopDrag(),t.cancelBubble=!0}),e.on("dragend",t=>{t.cancelBubble=!0}),e.on("mouseenter",()=>{var i=a.getAngle(this.rotation()),r=function(t,e){if("rotater"===t)return"crosshair";e+=g._degToRad(qt[t]||0);var i=(g._radToDeg(e)%360+360)%360;return g._inRange(i,337.5,360)||g._inRange(i,0,22.5)?"ns-resize":g._inRange(i,22.5,67.5)?"nesw-resize":g._inRange(i,67.5,112.5)?"ew-resize":g._inRange(i,112.5,157.5)?"nwse-resize":g._inRange(i,157.5,202.5)?"ns-resize":g._inRange(i,202.5,247.5)?"nesw-resize":g._inRange(i,247.5,292.5)?"ew-resize":g._inRange(i,292.5,337.5)?"nwse-resize":(g.error("Transformer has unknown angle for cursor detection: "+i),"pointer")}(t,i);e.getStage().content&&(e.getStage().content.style.cursor=r),this._cursorChange=!0}),e.on("mouseout",()=>{e.getStage().content&&(e.getStage().content.style.cursor=""),this._cursorChange=!1}),this.add(e)}_createBack(){var t=new at({name:"back",width:0,height:0,draggable:!0,sceneFunc(t){var e=this.getParent(),i=e.padding();t.beginPath(),t.rect(-i,-i,this.width()+2*i,this.height()+2*i),t.moveTo(this.width()/2,-i),e.rotateEnabled()&&t.lineTo(this.width()/2,-e.rotateAnchorOffset()*g._sign(this.height())-i),t.fillStrokeShape(this)},hitFunc:(t,e)=>{if(this.shouldOverdrawWholeArea()){var i=this.padding();t.beginPath(),t.rect(-i,-i,e.width()+2*i,e.height()+2*i),t.fillStrokeShape(e)}}});this.add(t),this._proxyDrag(t),t.on("dragstart",t=>{t.cancelBubble=!0}),t.on("dragmove",t=>{t.cancelBubble=!0}),t.on("dragend",t=>{t.cancelBubble=!0})}_handleMouseDown(t){this._movingAnchorName=t.target.name().split(" ")[0];var e=this._getNodeRect(),i=e.width,r=e.height,a=Math.sqrt(Math.pow(i,2)+Math.pow(r,2));this.sin=Math.abs(r/a),this.cos=Math.abs(i/a),"undefined"!=typeof window&&(window.addEventListener("mousemove",this._handleMouseMove),window.addEventListener("touchmove",this._handleMouseMove),window.addEventListener("mouseup",this._handleMouseUp,!0),window.addEventListener("touchend",this._handleMouseUp,!0)),this._transforming=!0;var n=t.target.getAbsolutePosition(),s=t.target.getStage().getPointerPosition();this._anchorDragOffset={x:s.x-n.x,y:s.y-n.y},this._fire("transformstart",{evt:t,target:this.getNode()}),this._nodes.forEach(e=>{e._fire("transformstart",{evt:t,target:e})})}_handleMouseMove(t){var e,i,r,n=this.findOne("."+this._movingAnchorName),s=n.getStage();s.setPointersPositions(t);const o=s.getPointerPosition();var h={x:o.x-this._anchorDragOffset.x,y:o.y-this._anchorDragOffset.y};const l=n.getAbsolutePosition();n.setAbsolutePosition(h);const d=n.getAbsolutePosition();if(l.x!==d.x||l.y!==d.y)if("rotater"!==this._movingAnchorName){var c=this.keepRatio()||t.shiftKey,g=this.centeredScaling()||t.altKey;if("top-left"===this._movingAnchorName){if(c){var u=g?{x:this.width()/2,y:this.height()/2}:{x:this.findOne(".bottom-right").x(),y:this.findOne(".bottom-right").y()};r=Math.sqrt(Math.pow(u.x-n.x(),2)+Math.pow(u.y-n.y(),2));var f=this.findOne(".top-left").x()>u.x?-1:1,p=this.findOne(".top-left").y()>u.y?-1:1;e=r*this.cos*f,i=r*this.sin*p,this.findOne(".top-left").x(u.x-e),this.findOne(".top-left").y(u.y-i)}}else if("top-center"===this._movingAnchorName)this.findOne(".top-left").y(n.y());else if("top-right"===this._movingAnchorName){if(c){u=g?{x:this.width()/2,y:this.height()/2}:{x:this.findOne(".bottom-left").x(),y:this.findOne(".bottom-left").y()};r=Math.sqrt(Math.pow(n.x()-u.x,2)+Math.pow(u.y-n.y(),2));f=this.findOne(".top-right").x()u.y?-1:1;e=r*this.cos*f,i=r*this.sin*p,this.findOne(".top-right").x(u.x+e),this.findOne(".top-right").y(u.y-i)}var v=n.position();this.findOne(".top-left").y(v.y),this.findOne(".bottom-right").x(v.x)}else if("middle-left"===this._movingAnchorName)this.findOne(".top-left").x(n.x());else if("middle-right"===this._movingAnchorName)this.findOne(".bottom-right").x(n.x());else if("bottom-left"===this._movingAnchorName){if(c){u=g?{x:this.width()/2,y:this.height()/2}:{x:this.findOne(".top-right").x(),y:this.findOne(".top-right").y()};r=Math.sqrt(Math.pow(u.x-n.x(),2)+Math.pow(n.y()-u.y,2));f=u.x{e._fire("transformend",{evt:t,target:e})}),this._movingAnchorName=null}}_fitNodesInto(t,e){var i=this._getNodeRect();if(g._inRange(t.width,2*-this.padding()-1,1))return void this.update();if(g._inRange(t.height,2*-this.padding()-1,1))return void this.update();var r=new s;if(r.rotate(a.getAngle(this.rotation())),this._movingAnchorName&&t.width<0&&this._movingAnchorName.indexOf("left")>=0){const e=r.point({x:2*-this.padding(),y:0});t.x+=e.x,t.y+=e.y,t.width+=2*this.padding(),this._movingAnchorName=this._movingAnchorName.replace("left","right"),this._anchorDragOffset.x-=e.x,this._anchorDragOffset.y-=e.y}else if(this._movingAnchorName&&t.width<0&&this._movingAnchorName.indexOf("right")>=0){const e=r.point({x:2*this.padding(),y:0});this._movingAnchorName=this._movingAnchorName.replace("right","left"),this._anchorDragOffset.x-=e.x,this._anchorDragOffset.y-=e.y,t.width+=2*this.padding()}if(this._movingAnchorName&&t.height<0&&this._movingAnchorName.indexOf("top")>=0){const e=r.point({x:0,y:2*-this.padding()});t.x+=e.x,t.y+=e.y,this._movingAnchorName=this._movingAnchorName.replace("top","bottom"),this._anchorDragOffset.x-=e.x,this._anchorDragOffset.y-=e.y,t.height+=2*this.padding()}else if(this._movingAnchorName&&t.height<0&&this._movingAnchorName.indexOf("bottom")>=0){const e=r.point({x:0,y:2*this.padding()});this._movingAnchorName=this._movingAnchorName.replace("bottom","top"),this._anchorDragOffset.x-=e.x,this._anchorDragOffset.y-=e.y,t.height+=2*this.padding()}if(this.boundBoxFunc()){const e=this.boundBoxFunc()(i,t);e?t=e:g.warn("boundBoxFunc returned falsy. You should return new bound rect from it!")}const n=new s;n.translate(i.x,i.y),n.rotate(i.rotation),n.scale(i.width/1e7,i.height/1e7);const o=new s;o.translate(t.x,t.y),o.rotate(t.rotation),o.scale(t.width/1e7,t.height/1e7);const h=o.multiply(n.invert());this._nodes.forEach(t=>{var i;const r=t.getParent().getAbsoluteTransform(),a=t.getTransform().copy();a.translate(t.offsetX(),t.offsetY());const n=new s;n.multiply(r.copy().invert()).multiply(h).multiply(r).multiply(a);const o=n.decompose();t.setAttrs(o),this._fire("transform",{evt:e,target:t}),t._fire("transform",{evt:e,target:t}),null===(i=t.getLayer())||void 0===i||i.batchDraw()}),this.rotation(g._getRotation(t.rotation)),this._resetTransformCache(),this.update(),this.getLayer().batchDraw()}forceUpdate(){this._resetTransformCache(),this.update()}_batchChangeChild(t,e){this.findOne(t).setAttrs(e)}update(){var t,e=this._getNodeRect();this.rotation(g._getRotation(e.rotation));var i=e.width,r=e.height,a=this.enabledAnchors(),n=this.resizeEnabled(),s=this.padding(),o=this.anchorSize();this.find("._anchor").forEach(t=>{t.setAttrs({width:o,height:o,offsetX:o/2,offsetY:o/2,stroke:this.anchorStroke(),strokeWidth:this.anchorStrokeWidth(),fill:this.anchorFill(),cornerRadius:this.anchorCornerRadius()})}),this._batchChangeChild(".top-left",{x:0,y:0,offsetX:o/2+s,offsetY:o/2+s,visible:n&&a.indexOf("top-left")>=0}),this._batchChangeChild(".top-center",{x:i/2,y:0,offsetY:o/2+s,visible:n&&a.indexOf("top-center")>=0}),this._batchChangeChild(".top-right",{x:i,y:0,offsetX:o/2-s,offsetY:o/2+s,visible:n&&a.indexOf("top-right")>=0}),this._batchChangeChild(".middle-left",{x:0,y:r/2,offsetX:o/2+s,visible:n&&a.indexOf("middle-left")>=0}),this._batchChangeChild(".middle-right",{x:i,y:r/2,offsetX:o/2-s,visible:n&&a.indexOf("middle-right")>=0}),this._batchChangeChild(".bottom-left",{x:0,y:r,offsetX:o/2+s,offsetY:o/2-s,visible:n&&a.indexOf("bottom-left")>=0}),this._batchChangeChild(".bottom-center",{x:i/2,y:r,offsetY:o/2-s,visible:n&&a.indexOf("bottom-center")>=0}),this._batchChangeChild(".bottom-right",{x:i,y:r,offsetX:o/2-s,offsetY:o/2-s,visible:n&&a.indexOf("bottom-right")>=0}),this._batchChangeChild(".rotater",{x:i/2,y:-this.rotateAnchorOffset()*g._sign(r)-s,visible:this.rotateEnabled()}),this._batchChangeChild(".back",{width:i,height:r,visible:this.borderEnabled(),stroke:this.borderStroke(),strokeWidth:this.borderStrokeWidth(),dash:this.borderDash(),x:0,y:0}),null===(t=this.getLayer())||void 0===t||t.batchDraw()}isTransforming(){return this._transforming}stopTransform(){if(this._transforming){this._removeEvents();var t=this.findOne("."+this._movingAnchorName);t&&t.stopDrag()}}destroy(){return this.getStage()&&this._cursorChange&&this.getStage().content&&(this.getStage().content.style.cursor=""),lt.prototype.destroy.call(this),this.detach(),this._removeEvents(),this}toObject(){return N.prototype.toObject.call(this)}}Zt.prototype.className="Transformer",n(Zt),b.addGetterSetter(Zt,"enabledAnchors",Vt,(function(t){return t instanceof Array||g.warn("enabledAnchors value should be an array"),t instanceof Array&&t.forEach((function(t){-1===Vt.indexOf(t)&&g.warn("Unknown anchor name: "+t+". Available names are: "+Vt.join(", "))})),t||[]})),b.addGetterSetter(Zt,"resizeEnabled",!0),b.addGetterSetter(Zt,"anchorSize",10,p()),b.addGetterSetter(Zt,"rotateEnabled",!0),b.addGetterSetter(Zt,"rotationSnaps",[]),b.addGetterSetter(Zt,"rotateAnchorOffset",50,p()),b.addGetterSetter(Zt,"rotationSnapTolerance",5,p()),b.addGetterSetter(Zt,"borderEnabled",!0),b.addGetterSetter(Zt,"anchorStroke","rgb(0, 161, 255)"),b.addGetterSetter(Zt,"anchorStrokeWidth",1,p()),b.addGetterSetter(Zt,"anchorFill","white"),b.addGetterSetter(Zt,"anchorCornerRadius",0,p()),b.addGetterSetter(Zt,"borderStroke","rgb(0, 161, 255)"),b.addGetterSetter(Zt,"borderStrokeWidth",1,p()),b.addGetterSetter(Zt,"borderDash"),b.addGetterSetter(Zt,"keepRatio",!0),b.addGetterSetter(Zt,"centeredScaling",!1),b.addGetterSetter(Zt,"ignoreStroke",!1),b.addGetterSetter(Zt,"padding",0,p()),b.addGetterSetter(Zt,"node"),b.addGetterSetter(Zt,"nodes"),b.addGetterSetter(Zt,"boundBoxFunc"),b.addGetterSetter(Zt,"shouldOverdrawWholeArea",!1),b.backCompat(Zt,{lineEnabled:"borderEnabled",rotateHandlerOffset:"rotateAnchorOffset",enabledHandlers:"enabledAnchors"});class $t extends at{_sceneFunc(t){t.beginPath(),t.arc(0,0,this.radius(),0,a.getAngle(this.angle()),this.clockwise()),t.lineTo(0,0),t.closePath(),t.fillStrokeShape(this)}getWidth(){return 2*this.radius()}getHeight(){return 2*this.radius()}setWidth(t){this.radius(t/2)}setHeight(t){this.radius(t/2)}}function te(){this.r=0,this.g=0,this.b=0,this.a=0,this.next=null}$t.prototype.className="Wedge",$t.prototype._centroid=!0,$t.prototype._attrsAffectingSize=["radius"],n($t),b.addGetterSetter($t,"radius",0,p()),b.addGetterSetter($t,"angle",0,p()),b.addGetterSetter($t,"clockwise",!1),b.backCompat($t,{angleDeg:"angle",getAngleDeg:"getAngle",setAngleDeg:"setAngle"});var ee=[512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259],ie=[9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24];b.addGetterSetter(N,"blurRadius",0,p(),b.afterSetFilter);b.addGetterSetter(N,"brightness",0,p(),b.afterSetFilter);b.addGetterSetter(N,"contrast",0,p(),b.afterSetFilter);function re(t,e,i,r,a){var n=i-e,s=a-r;return 0===n?r+s/2:0===s?r:s*((t-e)/n)+r}b.addGetterSetter(N,"embossStrength",.5,p(),b.afterSetFilter),b.addGetterSetter(N,"embossWhiteLevel",.5,p(),b.afterSetFilter),b.addGetterSetter(N,"embossDirection","top-left",null,b.afterSetFilter),b.addGetterSetter(N,"embossBlend",!1,null,b.afterSetFilter);b.addGetterSetter(N,"enhance",0,p(),b.afterSetFilter);b.addGetterSetter(N,"hue",0,p(),b.afterSetFilter),b.addGetterSetter(N,"saturation",0,p(),b.afterSetFilter),b.addGetterSetter(N,"luminance",0,p(),b.afterSetFilter);b.addGetterSetter(N,"hue",0,p(),b.afterSetFilter),b.addGetterSetter(N,"saturation",0,p(),b.afterSetFilter),b.addGetterSetter(N,"value",0,p(),b.afterSetFilter);function ae(t,e,i){var r=4*(i*t.width+e),a=[];return a.push(t.data[r++],t.data[r++],t.data[r++],t.data[r++]),a}function ne(t,e){return Math.sqrt(Math.pow(t[0]-e[0],2)+Math.pow(t[1]-e[1],2)+Math.pow(t[2]-e[2],2))}b.addGetterSetter(N,"kaleidoscopePower",2,p(),b.afterSetFilter),b.addGetterSetter(N,"kaleidoscopeAngle",0,p(),b.afterSetFilter);b.addGetterSetter(N,"threshold",0,p(),b.afterSetFilter);b.addGetterSetter(N,"noise",.2,p(),b.afterSetFilter);b.addGetterSetter(N,"pixelSize",8,p(),b.afterSetFilter);b.addGetterSetter(N,"levels",.5,p(),b.afterSetFilter);b.addGetterSetter(N,"red",0,(function(t){return this._filterUpToDate=!1,t>255?255:t<0?0:Math.round(t)})),b.addGetterSetter(N,"green",0,(function(t){return this._filterUpToDate=!1,t>255?255:t<0?0:Math.round(t)})),b.addGetterSetter(N,"blue",0,f,b.afterSetFilter);b.addGetterSetter(N,"red",0,(function(t){return this._filterUpToDate=!1,t>255?255:t<0?0:Math.round(t)})),b.addGetterSetter(N,"green",0,(function(t){return this._filterUpToDate=!1,t>255?255:t<0?0:Math.round(t)})),b.addGetterSetter(N,"blue",0,f,b.afterSetFilter),b.addGetterSetter(N,"alpha",1,(function(t){return this._filterUpToDate=!1,t>1?1:t<0?0:t}));b.addGetterSetter(N,"threshold",.5,p(),b.afterSetFilter);return _t.Util._assign(_t,{Arc:yt,Arrow:bt,Circle:St,Ellipse:wt,Image:Ct,Label:Tt,Tag:At,Line:xt,Path:Mt,Rect:Gt,RegularPolygon:Et,Ring:Lt,Sprite:Dt,Star:It,Text:Wt,TextPath:Xt,Transformer:Zt,Wedge:$t,Filters:{Blur:function(t){var e=Math.round(this.blurRadius());e>0&&function(t,e){var i,r,a,n,s,o,h,l,d,c,g,u,f,p,v,m,_,y,x,b,S,w,C,P,k=t.data,T=t.width,A=t.height,M=e+e+1,G=T-1,E=A-1,R=e+1,L=R*(R+1)/2,D=new te,I=null,O=D,F=null,B=null,N=ee[e],z=ie[e];for(a=1;a>z,0!==C?(C=255/C,k[o]=(l*N>>z)*C,k[o+1]=(d*N>>z)*C,k[o+2]=(c*N>>z)*C):k[o]=k[o+1]=k[o+2]=0,l-=u,d-=f,c-=p,g-=v,u-=F.r,f-=F.g,p-=F.b,v-=F.a,n=h+((n=i+e+1)>z,C>0?(C=255/C,k[n]=(l*N>>z)*C,k[n+1]=(d*N>>z)*C,k[n+2]=(c*N>>z)*C):k[n]=k[n+1]=k[n+2]=0,l-=u,d-=f,c-=p,g-=v,u-=F.r,f-=F.g,p-=F.b,v-=F.a,n=i+((n=r+R)255?255:n,s=(s*=255)<0?0:s>255?255:s,o=(o*=255)<0?0:o>255?255:o,r[e]=n,r[e+1]=s,r[e+2]=o},Emboss:function(t){var e=10*this.embossStrength(),i=255*this.embossWhiteLevel(),r=this.embossDirection(),a=this.embossBlend(),n=0,s=0,o=t.data,h=t.width,l=t.height,d=4*h,c=l;switch(r){case"top-left":n=-1,s=-1;break;case"top":n=-1,s=0;break;case"top-right":n=-1,s=1;break;case"right":n=0,s=1;break;case"bottom-right":n=1,s=1;break;case"bottom":n=1,s=0;break;case"bottom-left":n=1,s=-1;break;case"left":n=0,s=-1;break;default:g.error("Unknown emboss direction: "+r)}do{var u=(c-1)*d,f=n;c+f<1&&(f=0),c+f>l&&(f=0);var p=(c-1+f)*h*4,v=h;do{var m=u+4*(v-1),_=s;v+_<1&&(_=0),v+_>h&&(_=0);var y=p+4*(v-1+_),x=o[m]-o[y],b=o[m+1]-o[y+1],S=o[m+2]-o[y+2],w=x,C=w>0?w:-w;if((b>0?b:-b)>C&&(w=b),(S>0?S:-S)>C&&(w=S),w*=e,a){var P=o[m]+w,k=o[m+1]+w,T=o[m+2]+w;o[m]=P>255?255:P<0?0:P,o[m+1]=k>255?255:k<0?0:k,o[m+2]=T>255?255:T<0?0:T}else{var A=i-w;A<0?A=0:A>255&&(A=255),o[m]=o[m+1]=o[m+2]=A}}while(--v)}while(--c)},Enhance:function(t){var e,i,r,a,n=t.data,s=n.length,o=n[0],h=o,l=n[1],d=l,c=n[2],g=c,u=this.enhance();if(0!==u){for(a=0;ah&&(h=e),(i=n[a+1])d&&(d=i),(r=n[a+2])g&&(g=r);var f,p,v,m,_,y,x,b,S;for(h===o&&(h=255,o=0),d===l&&(d=255,l=0),g===c&&(g=255,c=0),u>0?(p=h+u*(255-h),v=o-u*(o-0),_=d+u*(255-d),y=l-u*(l-0),b=g+u*(255-g),S=c-u*(c-0)):(p=h+u*(h-(f=.5*(h+o))),v=o+u*(o-f),_=d+u*(d-(m=.5*(d+l))),y=l+u*(l-m),b=g+u*(g-(x=.5*(g+c))),S=c+u*(c-x)),a=0;am?s:m;var _,y,x,b,S=d,w=l,C=360/w*Math.PI/180;for(y=0;yd&&(x=y,b=0,S=-1),i=0;iy?h:y;var x,b,S,w=g,C=c,P=i.polarRotation||0;for(a=0;a=0&&u=0&&f=0&&u=0&&f=1020?255:0}return s}(e=function(t,e,i){for(var r=[1,1,1,1,0,1,1,1,1],a=Math.round(Math.sqrt(r.length)),n=Math.floor(a/2),s=[],o=0;o=0&&u=0&&f=m))for(i=d;i=_||(a+=b[(r=4*(m*i+e))+0],n+=b[r+1],s+=b[r+2],o+=b[r+3],p+=1);for(a/=p,n/=p,s/=p,o/=p,e=h;e=m))for(i=d;i=_||(b[(r=4*(m*i+e))+0]=a,b[r+1]=n,b[r+2]=s,b[r+3]=o)}},Posterize:function(t){var e,i=Math.round(254*this.levels())+1,r=t.data,a=r.length,n=255/i;for(e=0;e127&&(h=255-h),l>127&&(l=255-l),d>127&&(d=255-d),e[o]=h,e[o+1]=l,e[o+2]=d}while(--s)}while(--a)},Threshold:function(t){var e,i=255*this.threshold(),r=t.data,a=r.length;for(e=0;e number { if (glob.performance && glob.performance.now) { diff --git a/src/Canvas.ts b/src/Canvas.ts index 09c677ff..7ed53e22 100644 --- a/src/Canvas.ts +++ b/src/Canvas.ts @@ -1,8 +1,8 @@ -import { Util } from './Util'; -import { SceneContext, HitContext, Context } from './Context'; -import { Konva } from './Global'; -import { Factory } from './Factory'; -import { getNumberValidator } from './Validators'; +import { Util } from './Util.js'; +import { SceneContext, HitContext, Context } from './Context.js'; +import { Konva } from './Global.js'; +import { Factory } from './Factory.js'; +import { getNumberValidator } from './Validators.js'; // calculate pixel ratio var _pixelRatio; @@ -12,7 +12,7 @@ function getDevicePixelRatio() { } var canvas = Util.createCanvasElement(); var context = canvas.getContext('2d') as any; - _pixelRatio = (function() { + _pixelRatio = (function () { var devicePixelRatio = Konva._global.devicePixelRatio || 1, backingStoreRatio = context.webkitBackingStorePixelRatio || diff --git a/src/Container.ts b/src/Container.ts index f7b5c215..9f814c94 100644 --- a/src/Container.ts +++ b/src/Container.ts @@ -1,11 +1,10 @@ -import { Util } from './Util'; -import { Factory } from './Factory'; -import { Node, NodeConfig } from './Node'; -import { getNumberValidator } from './Validators'; +import { Factory } from './Factory.js'; +import { Node, NodeConfig } from './Node.js'; +import { getNumberValidator } from './Validators.js'; import { GetSet, IRect } from './types'; -import { Shape } from './Shape'; -import { HitCanvas, SceneCanvas } from './Canvas'; +import { Shape } from './Shape.js'; +import { HitCanvas, SceneCanvas } from './Canvas.js'; export interface ContainerConfig extends NodeConfig { clearBeforeDraw?: boolean; @@ -27,7 +26,7 @@ export interface ContainerConfig extends NodeConfig { * @@containerParams */ export abstract class Container< - ChildType extends Node + ChildType extends Node = Node > extends Node { children: Array | undefined = []; diff --git a/src/Context.ts b/src/Context.ts index b15a33ba..3a9a1bf3 100644 --- a/src/Context.ts +++ b/src/Context.ts @@ -1,7 +1,7 @@ -import { Util } from './Util'; -import { Konva } from './Global'; -import { Canvas } from './Canvas'; -import { Shape } from './Shape'; +import { Util } from './Util.js'; +import { Konva } from './Global.js'; +import { Canvas } from './Canvas.js'; +import { Shape } from './Shape.js'; var COMMA = ',', OPEN_PAREN = '(', diff --git a/src/Core.ts b/src/Core.ts index e6eecb92..10845f01 100644 --- a/src/Core.ts +++ b/src/Core.ts @@ -1,5 +1,5 @@ // enter file of limited Konva version with only core functions -export { Konva } from './_CoreInternals'; -import { Konva } from './_CoreInternals'; +export { Konva } from './_CoreInternals.js'; +import { Konva } from './_CoreInternals.js'; export default Konva; diff --git a/src/DragAndDrop.ts b/src/DragAndDrop.ts index 4b99d4ac..347d5d1f 100644 --- a/src/DragAndDrop.ts +++ b/src/DragAndDrop.ts @@ -1,7 +1,7 @@ -import { Konva } from './Global'; -import { Node } from './Node'; +import { Konva } from './Global.js'; +import { Node } from './Node.js'; import { Vector2d } from './types'; -import { Util } from './Util'; +import { Util } from './Util.js'; export const DD = { get isDragging() { diff --git a/src/Factory.ts b/src/Factory.ts index c62c5caa..4366dc26 100644 --- a/src/Factory.ts +++ b/src/Factory.ts @@ -1,5 +1,5 @@ -import { Util } from './Util'; -import { getComponentValidator } from './Validators'; +import { Util } from './Util.js'; +import { getComponentValidator } from './Validators.js'; var GET = 'get', SET = 'set'; diff --git a/src/FastLayer.ts b/src/FastLayer.ts index a7f59931..dd7028be 100644 --- a/src/FastLayer.ts +++ b/src/FastLayer.ts @@ -1,6 +1,6 @@ -import { Util } from './Util'; -import { Layer } from './Layer'; -import { _registerNode } from './Global'; +import { Util } from './Util.js'; +import { Layer } from './Layer.js'; +import { _registerNode } from './Global.js'; /** * FastLayer constructor. **DEPRECATED!** Please use `Konva.Layer({ listening: false})` instead. Layers are tied to their own canvas element and are used diff --git a/src/Global.ts b/src/Global.ts index 7c7b962f..02f9068a 100644 --- a/src/Global.ts +++ b/src/Global.ts @@ -24,57 +24,6 @@ function detectBrowser() { ); } -const _detectIE = function (ua) { - var msie = ua.indexOf('msie '); - if (msie > 0) { - // IE 10 or older => return version number - return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); - } - - var trident = ua.indexOf('trident/'); - if (trident > 0) { - // IE 11 => return version number - var rv = ua.indexOf('rv:'); - return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); - } - - var edge = ua.indexOf('edge/'); - if (edge > 0) { - // Edge (IE 12+) => return version number - return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); - } - - // other browser - return false; -}; - -export const _parseUA = function (userAgent) { - var ua = userAgent.toLowerCase(), - // jQuery UA regex - match = - /(chrome)[ /]([\w.]+)/.exec(ua) || - /(webkit)[ /]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ /]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - (ua.indexOf('compatible') < 0 && - /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)) || - [], - // adding mobile flag as well - mobile = !!userAgent.match( - /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i - ), - ieMobile = !!userAgent.match(/IEMobile/i); - - return { - browser: match[1] || '', - version: match[2] || '0', - isIE: _detectIE(ua), - // adding mobile flab - mobile: mobile, - ieMobile: ieMobile, // If this is true (i.e., WP8), then Konva touch events are executed instead of equivalent Konva mouse events - }; -}; - declare const WorkerGlobalScope: any; export const glob: any = @@ -90,9 +39,9 @@ export const Konva = { _global: glob, version: '@@version', isBrowser: detectBrowser(), - isUnminified: /param/.test(function (param) {}.toString()), + isUnminified: /param/.test(function (param: any) {}.toString()), dblClickWindow: 400, - getAngle(angle) { + getAngle(angle: number) { return Konva.angleDeg ? angle * PI_OVER_180 : angle; }, enableTrace: false, @@ -210,20 +159,15 @@ export const Konva = { return !!Konva['DD'].node; }, // user agent - UA: _parseUA((glob.navigator && glob.navigator.userAgent) || ''), document: glob.document, // insert Konva into global namespace (window) // it is required for npm packages _injectGlobal(Konva) { glob.Konva = Konva; }, - _parseUA, }; -export const _NODES_REGISTRY = {}; - -export const _registerNode = (NodeClass) => { - _NODES_REGISTRY[NodeClass.prototype.getClassName()] = NodeClass; +export const _registerNode = (NodeClass: any) => { Konva[NodeClass.prototype.getClassName()] = NodeClass; }; diff --git a/src/Group.ts b/src/Group.ts index 4ebb0bd5..5c65bc1d 100644 --- a/src/Group.ts +++ b/src/Group.ts @@ -1,8 +1,8 @@ -import { Util } from './Util'; -import { Container } from './Container'; -import { _registerNode } from './Global'; -import { Node } from './Node'; -import { Shape } from './Shape'; +import { Util } from './Util.js'; +import { Container } from './Container.js'; +import { _registerNode } from './Global.js'; +import { Node } from './Node.js'; +import { Shape } from './Shape.js'; /** * Group constructor. Groups are used to contain shapes or other groups. diff --git a/src/Layer.ts b/src/Layer.ts index d5e1eb5f..9cafdad2 100644 --- a/src/Layer.ts +++ b/src/Layer.ts @@ -1,15 +1,15 @@ -import { Util } from './Util'; -import { Container, ContainerConfig } from './Container'; -import { Node } from './Node'; -import { Factory } from './Factory'; -import { SceneCanvas, HitCanvas } from './Canvas'; -import { Stage } from './Stage'; -import { getBooleanValidator } from './Validators'; +import { Util } from './Util.js'; +import { Container, ContainerConfig } from './Container.js'; +import { Node } from './Node.js'; +import { Factory } from './Factory.js'; +import { SceneCanvas, HitCanvas } from './Canvas.js'; +import { Stage } from './Stage.js'; +import { getBooleanValidator } from './Validators.js'; import { GetSet, Vector2d } from './types'; -import { Group } from './Group'; -import { Shape, shapes } from './Shape'; -import { _registerNode } from './Global'; +import { Group } from './Group.js'; +import { Shape, shapes } from './Shape.js'; +import { _registerNode } from './Global.js'; export interface LayerConfig extends ContainerConfig { clearBeforeDraw?: boolean; diff --git a/src/Node.ts b/src/Node.ts index a5e88757..87eec11e 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,19 +1,19 @@ -import { Util, Transform } from './Util'; -import { Factory } from './Factory'; -import { SceneCanvas, HitCanvas, Canvas } from './Canvas'; -import { Konva, _NODES_REGISTRY } from './Global'; -import { Container } from './Container'; +import { Util, Transform } from './Util.js'; +import { Factory } from './Factory.js'; +import { SceneCanvas, HitCanvas, Canvas } from './Canvas.js'; +import { Konva } from './Global.js'; +import { Container } from './Container.js'; import { GetSet, Vector2d, IRect } from './types'; -import { DD } from './DragAndDrop'; +import { DD } from './DragAndDrop.js'; import { getNumberValidator, getStringValidator, getBooleanValidator, -} from './Validators'; -import { Stage } from './Stage'; -import { Context } from './Context'; -import { Shape } from './Shape'; -import { Layer } from './Layer'; +} from './Validators.js'; +import { Stage } from './Stage.js'; +import { Context } from './Context.js'; +import { Shape } from './Shape.js'; +import { Layer } from './Layer.js'; export const ids: any = {}; export const names: any = {}; @@ -227,10 +227,6 @@ export abstract class Node { return false; } - getChildren() { - return emptyChildren; - } - _clearCache(attr?: string) { // if we want to clear transform cache // we don't really need to remove it from the cache @@ -264,7 +260,7 @@ export abstract class Node { return cache; } - _calculate(name, deps, getter) { + _calculate(name: string, deps: Array, getter: Function) { // if we are trying to calculate function for the first time // we need to attach listeners for change events if (!this._attachedDepsListeners.get(name)) { @@ -285,7 +281,7 @@ export abstract class Node { * when the logic for a cached result depends on ancestor propagation, use this * method to clear self and children cache */ - _clearSelfAndDescendantCache(attr?: string, forceEvent?: boolean) { + _clearSelfAndDescendantCache(attr?: string) { this._clearCache(attr); // trigger clear cache, so transformer can use it if (attr === ABSOLUTE_TRANSFORM) { @@ -587,7 +583,7 @@ export abstract class Node { 0, 0, hitCanvas.width / hitCanvas.pixelRatio, - hitCanvas.height / hitCanvas.pixelRatio, + hitCanvas.height / hitCanvas.pixelRatio ); context.restore(); } @@ -1010,7 +1006,7 @@ export abstract class Node { isListening() { return this._getCache(LISTENING, this._isListening); } - _isListening(relativeTo?: Node) { + _isListening(relativeTo?: Node): boolean { const listening = this.listening(); if (!listening) { return false; @@ -1039,7 +1035,7 @@ export abstract class Node { isVisible() { return this._getCache(VISIBLE, this._isVisible); } - _isVisible(relativeTo) { + _isVisible(relativeTo?: Node): boolean { const visible = this.visible(); if (!visible) { return false; @@ -1171,7 +1167,7 @@ export abstract class Node { this._needClearTransformCache = false; } - setPosition(pos) { + setPosition(pos: Vector2d) { this._batchTransformChanges(() => { this.x(pos.x); this.y(pos.y); @@ -1199,7 +1195,7 @@ export abstract class Node { * // so stage transforms are ignored * node.getAbsolutePosition(stage) */ - getAbsolutePosition(top?) { + getAbsolutePosition(top?: Node) { let haveCachedParent = false; let parent = this.parent; while (parent) { @@ -1224,7 +1220,7 @@ export abstract class Node { return absoluteTransform.getTranslation(); } - setAbsolutePosition(pos) { + setAbsolutePosition(pos: Vector2d) { var origTrans = this._clearTransform(); // don't clear translation @@ -1300,7 +1296,7 @@ export abstract class Node { * y: 2 * }); */ - move(change) { + move(change: Vector2d) { var changeX = change.x, changeY = change.y, x = this.x(), @@ -1350,7 +1346,7 @@ export abstract class Node { * @param {Number} theta * @returns {Konva.Node} */ - rotate(theta) { + rotate(theta: number) { this.rotation(this.rotation() + theta); return this; } @@ -1479,7 +1475,7 @@ export abstract class Node { * // move node from current layer into layer2 * node.moveTo(layer2); */ - moveTo(newContainer) { + moveTo(newContainer: Container) { // do nothing if new container is already parent if (this.getParent() !== newContainer) { this._remove(); @@ -1557,7 +1553,7 @@ export abstract class Node { * // get one of the parent group * var parentGroups = node.findAncestors('Group'); */ - findAncestors(selector, includeSelf?, stopNode?) { + findAncestors(selector: string, includeSelf?: boolean, stopNode?: Container) { var res: Array = []; if (includeSelf && this._isMatch(selector)) { @@ -1575,7 +1571,7 @@ export abstract class Node { } return res; } - isAncestorOf(node) { + isAncestorOf(node: Node) { return false; } /** @@ -1590,11 +1586,11 @@ export abstract class Node { * // get one of the parent group * var group = node.findAncestors('.mygroup'); */ - findAncestor(selector?: string, includeSelf?: boolean, stopNode?: Node) { + findAncestor(selector?: string, includeSelf?: boolean, stopNode?: Container) { return this.findAncestors(selector, includeSelf, stopNode)[0]; } // is current node match passed selector? - _isMatch(selector) { + _isMatch(selector: string | Function) { if (!selector) { return false; } @@ -1687,7 +1683,7 @@ export abstract class Node { * // fire click event that bubbles * node.fire('click', null, true); */ - fire(eventType, evt: any = {}, bubble?) { + fire(eventType: string, evt: any = {}, bubble?: boolean) { evt.target = evt.target || this; // bubble if (bubble) { @@ -1768,7 +1764,7 @@ export abstract class Node { * // get absolute scale x * var scaleX = node.getAbsoluteScale().x; */ - getAbsoluteScale(top?) { + getAbsoluteScale(top?: Node) { // do not cache this calculations, // because it use cache transform // this is special logic for caching with some shapes with shadow @@ -1872,7 +1868,7 @@ export abstract class Node { * x: 5 * }); */ - clone(obj?) { + clone(obj?: any) { // instantiate new node var attrs = Util.cloneObject(this.attrs), key, @@ -2071,7 +2067,7 @@ export abstract class Node { getType() { return this.nodeType; } - getDragDistance() { + getDragDistance(): number { // compare with undefined because we need to track 0 value if (this.attrs.dragDistance !== undefined) { return this.attrs.dragDistance; @@ -2435,11 +2431,7 @@ export abstract class Node { this._lastPos.y !== newNodePos.y ) { this.setAbsolutePosition(newNodePos); - if (this.getLayer()) { - this.getLayer().batchDraw(); - } else if (this.getStage()) { - this.getStage().batchDraw(); - } + this._requestDraw(); } this._lastPos = newNodePos; @@ -2632,7 +2624,7 @@ export abstract class Node { obj.attrs.container = container; } - if (!_NODES_REGISTRY[className]) { + if (!Konva[className]) { Util.warn( 'Can not find a node with class name "' + className + @@ -2641,7 +2633,7 @@ export abstract class Node { className = 'Shape'; } - const Class = _NODES_REGISTRY[className]; + const Class = Konva[className]; no = new Class(obj.attrs); if (children) { diff --git a/src/PointerEvents.ts b/src/PointerEvents.ts index a3f3ffa3..26b69b06 100644 --- a/src/PointerEvents.ts +++ b/src/PointerEvents.ts @@ -1,8 +1,8 @@ -import { KonvaEventObject } from './Node'; -import { Konva } from './Global'; +import { KonvaEventObject } from './Node.js'; +import { Konva } from './Global.js'; -import { Shape } from './Shape'; -import { Stage } from './Stage'; +import { Shape } from './Shape.js'; +import { Stage } from './Stage.js'; const Captures = new Map(); @@ -21,7 +21,7 @@ export function getCapturedShape(pointerId: number) { export function createEvent(evt: PointerEvent): KonvaPointerEvent { return { evt, - pointerId: evt.pointerId + pointerId: evt.pointerId, } as any; } diff --git a/src/Shape.ts b/src/Shape.ts index 120bd0f0..aa476c12 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -1,20 +1,20 @@ -import { Util } from './Util'; -import { Factory } from './Factory'; -import { Node, NodeConfig } from './Node'; +import { Util } from './Util.js'; +import { Factory } from './Factory.js'; +import { Node, NodeConfig } from './Node.js'; import { getNumberValidator, getNumberOrAutoValidator, getStringValidator, getBooleanValidator, getStringOrGradientValidator, -} from './Validators'; +} from './Validators.js'; -import { Context, SceneContext } from './Context'; -import { _registerNode } from './Global'; -import * as PointerEvents from './PointerEvents'; +import { Context, SceneContext } from './Context.js'; +import { _registerNode } from './Global.js'; +import * as PointerEvents from './PointerEvents.js'; import { GetSet, Vector2d } from './types'; -import { HitCanvas, SceneCanvas } from './Canvas'; +import { HitCanvas, SceneCanvas } from './Canvas.js'; // hack from here https://stackoverflow.com/questions/52667959/what-is-the-purpose-of-bivariancehack-in-typescript-types/52668133#52668133 export type ShapeConfigHandler = { @@ -202,6 +202,7 @@ export class Shape< * @name Konva.Shape#getContext * @returns {Konva.Context} */ + // TODO: remove method getContext() { return this.getLayer().getContext(); } @@ -211,6 +212,7 @@ export class Shape< * @name Konva.Shape#getCanvas * @returns {Konva.Canvas} */ + // TODO: remove method getCanvas() { return this.getLayer().getCanvas(); } diff --git a/src/Stage.ts b/src/Stage.ts index 6b723047..6782a5c2 100644 --- a/src/Stage.ts +++ b/src/Stage.ts @@ -1,14 +1,14 @@ -import { Util } from './Util'; -import { Factory } from './Factory'; -import { Container, ContainerConfig } from './Container'; -import { Konva } from './Global'; -import { SceneCanvas, HitCanvas } from './Canvas'; +import { Util } from './Util.js'; +import { Factory } from './Factory.js'; +import { Container, ContainerConfig } from './Container.js'; +import { Konva } from './Global.js'; +import { SceneCanvas, HitCanvas } from './Canvas.js'; import { GetSet, Vector2d } from './types'; -import { Shape } from './Shape'; -import { Layer } from './Layer'; -import { DD } from './DragAndDrop'; -import { _registerNode } from './Global'; -import * as PointerEvents from './PointerEvents'; +import { Shape } from './Shape.js'; +import { Layer } from './Layer.js'; +import { DD } from './DragAndDrop.js'; +import { _registerNode } from './Global.js'; +import * as PointerEvents from './PointerEvents.js'; export interface StageConfig extends ContainerConfig { container: HTMLDivElement | string; @@ -464,10 +464,7 @@ export class Stage extends Container { this._fire(CONTENT_MOUSEOUT, { evt: evt }); } _mousemove(evt) { - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva.UA.ieMobile) { - return this._touchmove(evt); - } + this.setPointersPositions(evt); var pointerId = Util._getFirstPointerId(evt); var targetShape = this.targetShape?.getStage() ? this.targetShape : null; @@ -535,10 +532,6 @@ export class Stage extends Container { } } _mousedown(evt) { - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva.UA.ieMobile) { - return this._touchstart(evt); - } this.setPointersPositions(evt); var pointerId = Util._getFirstPointerId(evt); var shape = this.getIntersection(this.getPointerPosition()) as Shape; @@ -569,10 +562,6 @@ export class Stage extends Container { // } } _mouseup(evt) { - // workaround for mobile IE to force touch event when unhandled pointer event elevates into a mouse event - if (Konva.UA.ieMobile) { - return this._touchend(evt); - } this.setPointersPositions(evt); var pointerId = Util._getFirstPointerId(evt); var shape = this.getIntersection(this.getPointerPosition()) as Shape, diff --git a/src/Tween.ts b/src/Tween.ts index 813ee394..b82ca988 100644 --- a/src/Tween.ts +++ b/src/Tween.ts @@ -1,7 +1,7 @@ -import { Util } from './Util'; -import { Animation } from './Animation'; -import { Node, NodeConfig } from './Node'; -import { Konva } from './Global'; +import { Util } from './Util.js'; +import { Animation } from './Animation.js'; +import { Node, NodeConfig } from './Node.js'; +import { Konva } from './Global.js'; import { Line } from './shapes/Line'; var blacklist = { diff --git a/src/Util.ts b/src/Util.ts index d562f4dc..b2e4f07f 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -1,4 +1,4 @@ -import { Konva } from './Global'; +import { Konva } from './Global.js'; import { IRect, RGB, RGBA, Vector2d } from './types'; /* diff --git a/src/Validators.ts b/src/Validators.ts index a41e6537..fd3aca74 100644 --- a/src/Validators.ts +++ b/src/Validators.ts @@ -1,5 +1,5 @@ -import { Konva } from './Global'; -import { Util } from './Util'; +import { Konva } from './Global.js'; +import { Util } from './Util.js'; function _formatValue(val: any) { if (Util._isString(val)) { diff --git a/src/_CoreInternals.ts b/src/_CoreInternals.ts index 4a539eda..561a21ce 100644 --- a/src/_CoreInternals.ts +++ b/src/_CoreInternals.ts @@ -1,26 +1,26 @@ // what is core parts of Konva? -import { Konva as Global } from './Global'; +import { Konva as Global } from './Global.js'; -import { Util, Transform } from './Util'; -import { Node, ids, names } from './Node'; -import { Container } from './Container'; +import { Util, Transform } from './Util.js'; +import { Node, ids, names } from './Node.js'; +import { Container } from './Container.js'; -import { Stage, stages } from './Stage'; +import { Stage, stages } from './Stage.js'; -import { Layer } from './Layer'; -import { FastLayer } from './FastLayer'; +import { Layer } from './Layer.js'; +import { FastLayer } from './FastLayer.js'; -import { Group } from './Group'; +import { Group } from './Group.js'; -import { DD } from './DragAndDrop'; +import { DD } from './DragAndDrop.js'; -import { Shape, shapes } from './Shape'; +import { Shape, shapes } from './Shape.js'; -import { Animation } from './Animation'; -import { Tween, Easings } from './Tween'; +import { Animation } from './Animation.js'; +import { Tween, Easings } from './Tween.js'; -import { Context } from './Context'; -import { Canvas } from './Canvas'; +import { Context } from './Context.js'; +import { Canvas } from './Canvas.js'; export const Konva = Util._assign(Global, { Util, diff --git a/src/_FullInternals.ts b/src/_FullInternals.ts index d257f4cd..8384c812 100644 --- a/src/_FullInternals.ts +++ b/src/_FullInternals.ts @@ -1,46 +1,46 @@ // we need to import core of the Konva and then extend it with all additional objects -import { Konva as Core } from './_CoreInternals'; +import { Konva as Core } from './_CoreInternals.js'; // shapes -import { Arc } from './shapes/Arc'; -import { Arrow } from './shapes/Arrow'; -import { Circle } from './shapes/Circle'; -import { Ellipse } from './shapes/Ellipse'; -import { Image } from './shapes/Image'; -import { Label, Tag } from './shapes/Label'; -import { Line } from './shapes/Line'; -import { Path } from './shapes/Path'; -import { Rect } from './shapes/Rect'; -import { RegularPolygon } from './shapes/RegularPolygon'; -import { Ring } from './shapes/Ring'; -import { Sprite } from './shapes/Sprite'; -import { Star } from './shapes/Star'; -import { Text } from './shapes/Text'; -import { TextPath } from './shapes/TextPath'; -import { Transformer } from './shapes/Transformer'; -import { Wedge } from './shapes/Wedge'; +import { Arc } from './shapes/Arc.js'; +import { Arrow } from './shapes/Arrow.js'; +import { Circle } from './shapes/Circle.js'; +import { Ellipse } from './shapes/Ellipse.js'; +import { Image } from './shapes/Image.js'; +import { Label, Tag } from './shapes/Label.js'; +import { Line } from './shapes/Line.js'; +import { Path } from './shapes/Path.js'; +import { Rect } from './shapes/Rect.js'; +import { RegularPolygon } from './shapes/RegularPolygon.js'; +import { Ring } from './shapes/Ring.js'; +import { Sprite } from './shapes/Sprite.js'; +import { Star } from './shapes/Star.js'; +import { Text } from './shapes/Text.js'; +import { TextPath } from './shapes/TextPath.js'; +import { Transformer } from './shapes/Transformer.js'; +import { Wedge } from './shapes/Wedge.js'; // filters -import { Blur } from './filters/Blur'; -import { Brighten } from './filters/Brighten'; -import { Contrast } from './filters/Contrast'; -import { Emboss } from './filters/Emboss'; -import { Enhance } from './filters/Enhance'; -import { Grayscale } from './filters/Grayscale'; -import { HSL } from './filters/HSL'; -import { HSV } from './filters/HSV'; -import { Invert } from './filters/Invert'; -import { Kaleidoscope } from './filters/Kaleidoscope'; -import { Mask } from './filters/Mask'; -import { Noise } from './filters/Noise'; -import { Pixelate } from './filters/Pixelate'; -import { Posterize } from './filters/Posterize'; -import { RGB } from './filters/RGB'; -import { RGBA } from './filters/RGBA'; -import { Sepia } from './filters/Sepia'; -import { Solarize } from './filters/Solarize'; -import { Threshold } from './filters/Threshold'; +import { Blur } from './filters/Blur.js'; +import { Brighten } from './filters/Brighten.js'; +import { Contrast } from './filters/Contrast.js'; +import { Emboss } from './filters/Emboss.js'; +import { Enhance } from './filters/Enhance.js'; +import { Grayscale } from './filters/Grayscale.js'; +import { HSL } from './filters/HSL.js'; +import { HSV } from './filters/HSV.js'; +import { Invert } from './filters/Invert.js'; +import { Kaleidoscope } from './filters/Kaleidoscope.js'; +import { Mask } from './filters/Mask.js'; +import { Noise } from './filters/Noise.js'; +import { Pixelate } from './filters/Pixelate.js'; +import { Posterize } from './filters/Posterize.js'; +import { RGB } from './filters/RGB.js'; +import { RGBA } from './filters/RGBA.js'; +import { Sepia } from './filters/Sepia.js'; +import { Solarize } from './filters/Solarize.js'; +import { Threshold } from './filters/Threshold.js'; export const Konva = Core.Util._assign(Core, { Arc, diff --git a/src/filters/Blur.ts b/src/filters/Blur.ts index 203f6b26..44b9addd 100644 --- a/src/filters/Blur.ts +++ b/src/filters/Blur.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /* the Gauss filter master repo: https://github.com/pavelpower/kineticjsGaussFilter @@ -309,7 +309,7 @@ var mul_table = [ 265, 263, 261, - 259 + 259, ]; var shg_table = [ @@ -567,7 +567,7 @@ var shg_table = [ 24, 24, 24, - 24 + 24, ]; function filterGaussBlurRGBA(imageData, radius) { diff --git a/src/filters/Brighten.ts b/src/filters/Brighten.ts index 619f8f1a..198d35dd 100644 --- a/src/filters/Brighten.ts +++ b/src/filters/Brighten.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Brighten Filter. @@ -12,7 +12,7 @@ import { getNumberValidator } from '../Validators'; * node.filters([Konva.Filters.Brighten]); * node.brightness(0.8); */ -export const Brighten: Filter = function(imageData) { +export const Brighten: Filter = function (imageData) { var brightness = this.brightness() * 255, data = imageData.data, len = data.length, diff --git a/src/filters/Contrast.ts b/src/filters/Contrast.ts index b9533d0e..ee878315 100644 --- a/src/filters/Contrast.ts +++ b/src/filters/Contrast.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Contrast Filter. * @function @@ -12,7 +12,7 @@ import { getNumberValidator } from '../Validators'; * node.contrast(10); */ -export const Contrast: Filter = function(imageData) { +export const Contrast: Filter = function (imageData) { var adjust = Math.pow((this.contrast() + 100) / 100, 2); var data = imageData.data, diff --git a/src/filters/Emboss.ts b/src/filters/Emboss.ts index 42a6e996..f12ee491 100644 --- a/src/filters/Emboss.ts +++ b/src/filters/Emboss.ts @@ -1,7 +1,7 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { Util } from '../Util'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { Util } from '../Util.js'; +import { getNumberValidator } from '../Validators.js'; /** * Emboss Filter. * Pixastic Lib - Emboss filter - v0.1.0 @@ -18,7 +18,7 @@ import { getNumberValidator } from '../Validators'; * node.embossDirection('right'); * node.embossBlend(true); */ -export const Emboss: Filter = function(imageData) { +export const Emboss: Filter = function (imageData) { // pixastic strength is between 0 and 10. I want it between 0 and 1 // pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also, // a max value of greyLevel yields a white emboss, and the min value yields a black diff --git a/src/filters/Enhance.ts b/src/filters/Enhance.ts index 23180268..c12f3a73 100644 --- a/src/filters/Enhance.ts +++ b/src/filters/Enhance.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; function remap(fromValue, fromMin, fromMax, toMin, toMax) { // Compute the range of the data @@ -37,7 +37,7 @@ function remap(fromValue, fromMin, fromMax, toMin, toMax) { * node.filters([Konva.Filters.Enhance]); * node.enhance(0.4); */ -export const Enhance: Filter = function(imageData) { +export const Enhance: Filter = function (imageData) { var data = imageData.data, nSubPixels = data.length, rMin = data[0], diff --git a/src/filters/Grayscale.ts b/src/filters/Grayscale.ts index 0c4466ab..59be65b7 100644 --- a/src/filters/Grayscale.ts +++ b/src/filters/Grayscale.ts @@ -1,4 +1,4 @@ -import { Filter } from '../Node'; +import { Filter } from '../Node.js'; /** * Grayscale Filter @@ -9,7 +9,7 @@ import { Filter } from '../Node'; * node.cache(); * node.filters([Konva.Filters.Grayscale]); */ -export const Grayscale: Filter = function(imageData) { +export const Grayscale: Filter = function (imageData) { var data = imageData.data, len = data.length, i, diff --git a/src/filters/HSL.ts b/src/filters/HSL.ts index f3292da1..02f8a34f 100644 --- a/src/filters/HSL.ts +++ b/src/filters/HSL.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; Factory.addGetterSetter( Node, @@ -58,7 +58,7 @@ Factory.addGetterSetter( * image.luminance(0.2); */ -export const HSL: Filter = function(imageData) { +export const HSL: Filter = function (imageData) { var data = imageData.data, nPixels = data.length, v = 1, diff --git a/src/filters/HSV.ts b/src/filters/HSV.ts index 708d4ea9..c4836d8a 100644 --- a/src/filters/HSV.ts +++ b/src/filters/HSV.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * HSV Filter. Adjusts the hue, saturation and value @@ -14,7 +14,7 @@ import { getNumberValidator } from '../Validators'; * image.value(200); */ -export const HSV: Filter = function(imageData) { +export const HSV: Filter = function (imageData) { var data = imageData.data, nPixels = data.length, v = Math.pow(2, this.value()), diff --git a/src/filters/Invert.ts b/src/filters/Invert.ts index f9f339fe..fd4a6d60 100644 --- a/src/filters/Invert.ts +++ b/src/filters/Invert.ts @@ -1,4 +1,4 @@ -import { Filter } from '../Node'; +import { Filter } from '../Node.js'; /** * Invert Filter * @function @@ -8,7 +8,7 @@ import { Filter } from '../Node'; * node.cache(); * node.filters([Konva.Filters.Invert]); */ -export const Invert: Filter = function(imageData) { +export const Invert: Filter = function (imageData) { var data = imageData.data, len = data.length, i; diff --git a/src/filters/Kaleidoscope.ts b/src/filters/Kaleidoscope.ts index ce4676b1..73fd51ba 100644 --- a/src/filters/Kaleidoscope.ts +++ b/src/filters/Kaleidoscope.ts @@ -1,7 +1,7 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { Util } from '../Util'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { Util } from '../Util.js'; +import { getNumberValidator } from '../Validators.js'; /* * ToPolar Filter. Converts image data to polar coordinates. Performs @@ -19,7 +19,7 @@ import { getNumberValidator } from '../Validators'; * default is in the middle */ -var ToPolar = function(src, dst, opt) { +var ToPolar = function (src, dst, opt) { var srcPixels = src.data, dstPixels = dst.data, xSize = src.width, @@ -96,7 +96,7 @@ var ToPolar = function(src, dst, opt) { * 0 is no rotation, 360 degrees is a full rotation */ -var FromPolar = function(src, dst, opt) { +var FromPolar = function (src, dst, opt) { var srcPixels = src.data, dstPixels = dst.data, xSize = src.width, @@ -177,7 +177,7 @@ var FromPolar = function(src, dst, opt) { * node.kaleidoscopePower(3); * node.kaleidoscopeAngle(45); */ -export const Kaleidoscope: Filter = function(imageData) { +export const Kaleidoscope: Filter = function (imageData) { var xSize = imageData.width, ySize = imageData.height; @@ -201,7 +201,7 @@ export const Kaleidoscope: Filter = function(imageData) { // Convert thhe original to polar coordinates ToPolar(imageData, scratchData, { polarCenterX: xSize / 2, - polarCenterY: ySize / 2 + polarCenterY: ySize / 2, }); // Determine how big each section will be, if it's too small diff --git a/src/filters/Mask.ts b/src/filters/Mask.ts index 2c951b9e..d1bc3c67 100644 --- a/src/filters/Mask.ts +++ b/src/filters/Mask.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; function pixelAt(idata, x, y) { var idx = (y * idata.width + x) * 4; @@ -60,7 +60,7 @@ function backgroundMask(idata, threshold) { var d = rgbDistance(mean, [ idata.data[i * 4], idata.data[i * 4 + 1], - idata.data[i * 4 + 2] + idata.data[i * 4 + 2], ]); mask[i] = d < thres ? 0 : 255; } @@ -179,7 +179,7 @@ function smoothEdgeMask(mask, sw, sh) { * node.filters([Konva.Filters.Mask]); * node.threshold(200); */ -export const Mask: Filter = function(imageData) { +export const Mask: Filter = function (imageData) { // Detect pixels close to the background color var threshold = this.threshold(), mask = backgroundMask(imageData, threshold); diff --git a/src/filters/Noise.ts b/src/filters/Noise.ts index d11a2f56..9007a7fc 100644 --- a/src/filters/Noise.ts +++ b/src/filters/Noise.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Noise Filter. Randomly adds or substracts to the color channels @@ -14,7 +14,7 @@ import { getNumberValidator } from '../Validators'; * node.filters([Konva.Filters.Noise]); * node.noise(0.8); */ -export const Noise: Filter = function(imageData) { +export const Noise: Filter = function (imageData) { var amount = this.noise() * 255, data = imageData.data, nPixels = data.length, diff --git a/src/filters/Pixelate.ts b/src/filters/Pixelate.ts index e1633e2a..4a4b1b12 100644 --- a/src/filters/Pixelate.ts +++ b/src/filters/Pixelate.ts @@ -1,8 +1,8 @@ /*eslint-disable max-depth */ -import { Factory } from '../Factory'; -import { Util } from '../Util'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Util } from '../Util.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Pixelate Filter. Averages groups of pixels and redraws @@ -18,7 +18,7 @@ import { getNumberValidator } from '../Validators'; * node.pixelSize(10); */ -export const Pixelate: Filter = function(imageData) { +export const Pixelate: Filter = function (imageData) { var pixelSize = Math.ceil(this.pixelSize()), width = imageData.width, height = imageData.height, diff --git a/src/filters/Posterize.ts b/src/filters/Posterize.ts index a34e011d..8fb12073 100644 --- a/src/filters/Posterize.ts +++ b/src/filters/Posterize.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Posterize Filter. Adjusts the channels so that there are no more * than n different values for that channel. This is also applied @@ -16,7 +16,7 @@ import { getNumberValidator } from '../Validators'; * node.levels(0.8); // between 0 and 1 */ -export const Posterize: Filter = function(imageData) { +export const Posterize: Filter = function (imageData) { // level must be between 1 and 255 var levels = Math.round(this.levels() * 254) + 1, data = imageData.data, diff --git a/src/filters/RGB.ts b/src/filters/RGB.ts index 65010fb6..9de05ae5 100644 --- a/src/filters/RGB.ts +++ b/src/filters/RGB.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { RGBComponent } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { RGBComponent } from '../Validators.js'; /** * RGB Filter @@ -16,7 +16,7 @@ import { RGBComponent } from '../Validators'; * node.green(200); */ -export const RGB: Filter = function(imageData) { +export const RGB: Filter = function (imageData) { var data = imageData.data, nPixels = data.length, red = this.red(), @@ -35,7 +35,7 @@ export const RGB: Filter = function(imageData) { } }; -Factory.addGetterSetter(Node, 'red', 0, function(val) { +Factory.addGetterSetter(Node, 'red', 0, function (val) { this._filterUpToDate = false; if (val > 255) { return 255; @@ -54,7 +54,7 @@ Factory.addGetterSetter(Node, 'red', 0, function(val) { * @returns {Integer} */ -Factory.addGetterSetter(Node, 'green', 0, function(val) { +Factory.addGetterSetter(Node, 'green', 0, function (val) { this._filterUpToDate = false; if (val > 255) { return 255; diff --git a/src/filters/RGBA.ts b/src/filters/RGBA.ts index 55dc2a9b..324adb0a 100644 --- a/src/filters/RGBA.ts +++ b/src/filters/RGBA.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { RGBComponent } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { RGBComponent } from '../Validators.js'; /** * RGBA Filter @@ -17,7 +17,7 @@ import { RGBComponent } from '../Validators'; * node.alpha(0.3); */ -export const RGBA: Filter = function(imageData) { +export const RGBA: Filter = function (imageData) { var data = imageData.data, nPixels = data.length, red = this.red(), @@ -36,7 +36,7 @@ export const RGBA: Filter = function(imageData) { } }; -Factory.addGetterSetter(Node, 'red', 0, function(val) { +Factory.addGetterSetter(Node, 'red', 0, function (val) { this._filterUpToDate = false; if (val > 255) { return 255; @@ -55,7 +55,7 @@ Factory.addGetterSetter(Node, 'red', 0, function(val) { * @returns {Integer} */ -Factory.addGetterSetter(Node, 'green', 0, function(val) { +Factory.addGetterSetter(Node, 'green', 0, function (val) { this._filterUpToDate = false; if (val > 255) { return 255; @@ -84,7 +84,7 @@ Factory.addGetterSetter(Node, 'blue', 0, RGBComponent, Factory.afterSetFilter); * @returns {Integer} */ -Factory.addGetterSetter(Node, 'alpha', 1, function(val) { +Factory.addGetterSetter(Node, 'alpha', 1, function (val) { this._filterUpToDate = false; if (val > 1) { return 1; diff --git a/src/filters/Sepia.ts b/src/filters/Sepia.ts index 06514d06..849e76fd 100644 --- a/src/filters/Sepia.ts +++ b/src/filters/Sepia.ts @@ -1,4 +1,4 @@ -import { Filter } from '../Node'; +import { Filter } from '../Node.js'; // based on https://stackoverflow.com/questions/1061093/how-is-a-sepia-tone-created @@ -11,7 +11,7 @@ import { Filter } from '../Node'; * node.cache(); * node.filters([Konva.Filters.Sepia]); */ -export const Sepia: Filter = function(imageData) { +export const Sepia: Filter = function (imageData) { var data = imageData.data, nPixels = data.length, i, diff --git a/src/filters/Solarize.ts b/src/filters/Solarize.ts index 6d2f797a..f5a27816 100644 --- a/src/filters/Solarize.ts +++ b/src/filters/Solarize.ts @@ -1,4 +1,4 @@ -import { Filter } from '../Node'; +import { Filter } from '../Node.js'; /** * Solarize Filter * Pixastic Lib - Solarize filter - v0.1.0 @@ -13,7 +13,7 @@ import { Filter } from '../Node'; * node.filters([Konva.Filters.Solarize]); */ -export const Solarize: Filter = function(imageData) { +export const Solarize: Filter = function (imageData) { var data = imageData.data, w = imageData.width, h = imageData.height, diff --git a/src/filters/Threshold.ts b/src/filters/Threshold.ts index 471cbcfb..70b6152f 100644 --- a/src/filters/Threshold.ts +++ b/src/filters/Threshold.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Node, Filter } from '../Node'; -import { getNumberValidator } from '../Validators'; +import { Factory } from '../Factory.js'; +import { Node, Filter } from '../Node.js'; +import { getNumberValidator } from '../Validators.js'; /** * Threshold Filter. Pushes any value above the mid point to * the max and any value below the mid point to the min. @@ -16,7 +16,7 @@ import { getNumberValidator } from '../Validators'; * node.threshold(0.1); */ -export const Threshold: Filter = function(imageData) { +export const Threshold: Filter = function (imageData) { var level = this.threshold() * 255, data = imageData.data, len = data.length, diff --git a/src/index-node.ts b/src/index-node.ts index e5dfc134..a0b98bd3 100644 --- a/src/index-node.ts +++ b/src/index-node.ts @@ -1,5 +1,5 @@ // main entry for umd build for rollup -import { Konva } from './_FullInternals'; +import { Konva } from './_FullInternals.js'; import * as canvas from 'canvas'; const isNode = typeof global.document === 'undefined'; diff --git a/src/shapes/Arc.ts b/src/shapes/Arc.ts index ff65bfb2..721e10c4 100644 --- a/src/shapes/Arc.ts +++ b/src/shapes/Arc.ts @@ -1,9 +1,9 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Konva } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Konva } from '../Global.js'; import { GetSet } from '../types'; -import { getNumberValidator, getBooleanValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { getNumberValidator, getBooleanValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; export interface ArcConfig extends ShapeConfig { angle: number; diff --git a/src/shapes/Arrow.ts b/src/shapes/Arrow.ts index c78a99d7..9417d4ba 100644 --- a/src/shapes/Arrow.ts +++ b/src/shapes/Arrow.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Line, LineConfig } from './Line'; +import { Factory } from '../Factory.js'; +import { Line, LineConfig } from './Line.js'; import { GetSet } from '../types'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; export interface ArrowConfig extends LineConfig { points: number[]; diff --git a/src/shapes/Circle.ts b/src/shapes/Circle.ts index 9491ca3b..1bbb23a1 100644 --- a/src/shapes/Circle.ts +++ b/src/shapes/Circle.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; import { GetSet } from '../types'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; export interface CircleConfig extends ShapeConfig { radius?: number; diff --git a/src/shapes/Ellipse.ts b/src/shapes/Ellipse.ts index c410bbfa..67970fa6 100644 --- a/src/shapes/Ellipse.ts +++ b/src/shapes/Ellipse.ts @@ -1,7 +1,7 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet, Vector2d } from '../types'; diff --git a/src/shapes/Image.ts b/src/shapes/Image.ts index b0f4fb9e..b52b3141 100644 --- a/src/shapes/Image.ts +++ b/src/shapes/Image.ts @@ -1,11 +1,11 @@ -import { Util } from '../Util'; -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Util } from '../Util.js'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet, IRect } from '../types'; -import { Context } from '../Context'; +import { Context } from '../Context.js'; export interface ImageConfig extends ShapeConfig { image: CanvasImageSource | undefined; diff --git a/src/shapes/Label.ts b/src/shapes/Label.ts index d4c3128c..bcdf053c 100644 --- a/src/shapes/Label.ts +++ b/src/shapes/Label.ts @@ -1,15 +1,15 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Group } from '../Group'; -import { ContainerConfig } from '../Container'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Group } from '../Group.js'; +import { ContainerConfig } from '../Container.js'; import { getNumberOrArrayOfNumbersValidator, getNumberValidator, -} from '../Validators'; -import { _registerNode } from '../Global'; +} from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; -import { Text } from './Text'; +import { Text } from './Text.js'; export interface LabelConfig extends ContainerConfig {} diff --git a/src/shapes/Line.ts b/src/shapes/Line.ts index e686bcaa..b90c7c06 100644 --- a/src/shapes/Line.ts +++ b/src/shapes/Line.ts @@ -1,11 +1,11 @@ -import { Util } from '../Util'; -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { getNumberValidator, getNumberArrayValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Util } from '../Util.js'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { getNumberValidator, getNumberArrayValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; -import { Context } from '../Context'; +import { Context } from '../Context.js'; export interface LineConfig extends ShapeConfig { points?: number[]; diff --git a/src/shapes/Path.ts b/src/shapes/Path.ts index ecb2b507..3e7f2d61 100644 --- a/src/shapes/Path.ts +++ b/src/shapes/Path.ts @@ -1,6 +1,6 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; diff --git a/src/shapes/Rect.ts b/src/shapes/Rect.ts index 27549e7f..e8a9cb94 100644 --- a/src/shapes/Rect.ts +++ b/src/shapes/Rect.ts @@ -1,9 +1,9 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; -import { getNumberOrArrayOfNumbersValidator } from '../Validators'; +import { getNumberOrArrayOfNumbersValidator } from '../Validators.js'; export interface RectConfig extends ShapeConfig { cornerRadius?: number | number[]; } diff --git a/src/shapes/RegularPolygon.ts b/src/shapes/RegularPolygon.ts index 580a156f..29037fd8 100644 --- a/src/shapes/RegularPolygon.ts +++ b/src/shapes/RegularPolygon.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; import { GetSet } from '../types'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; export interface RegularPolygonConfig extends ShapeConfig { sides: number; diff --git a/src/shapes/Ring.ts b/src/shapes/Ring.ts index bf547f10..90b09f80 100644 --- a/src/shapes/Ring.ts +++ b/src/shapes/Ring.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; import { GetSet } from '../types'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; export interface RingConfig extends ShapeConfig { innerRadius: number; diff --git a/src/shapes/Sprite.ts b/src/shapes/Sprite.ts index 832615c6..9de4843d 100644 --- a/src/shapes/Sprite.ts +++ b/src/shapes/Sprite.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Animation } from '../Animation'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Animation } from '../Animation.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; diff --git a/src/shapes/Star.ts b/src/shapes/Star.ts index 4df5d97c..3dcc8283 100644 --- a/src/shapes/Star.ts +++ b/src/shapes/Star.ts @@ -1,7 +1,7 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; diff --git a/src/shapes/Text.ts b/src/shapes/Text.ts index 959afa8d..3e82c1a0 100644 --- a/src/shapes/Text.ts +++ b/src/shapes/Text.ts @@ -1,14 +1,14 @@ -import { Util } from '../Util'; -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Konva } from '../Global'; +import { Util } from '../Util.js'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Konva } from '../Global.js'; import { getNumberValidator, getStringValidator, getNumberOrAutoValidator, getBooleanValidator, -} from '../Validators'; -import { _registerNode } from '../Global'; +} from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; @@ -379,20 +379,6 @@ export class Text extends Shape { }; } _getContextFont() { - // IE don't want to work with usual font style - // bold was not working - // removing font variant will solve - // fix for: https://github.com/konvajs/konva/issues/94 - if (Konva.UA.isIE) { - return ( - this.fontStyle() + - SPACE + - this.fontSize() + - PX_SPACE + - this.fontFamily() - ); - } - return ( this.fontStyle() + SPACE + diff --git a/src/shapes/TextPath.ts b/src/shapes/TextPath.ts index 50818f4c..377a865f 100644 --- a/src/shapes/TextPath.ts +++ b/src/shapes/TextPath.ts @@ -1,10 +1,10 @@ -import { Util } from '../Util'; -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Path } from './Path'; -import { Text, stringToArray } from './Text'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Util } from '../Util.js'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Path } from './Path.js'; +import { Text, stringToArray } from './Text.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet, Vector2d } from '../types'; diff --git a/src/shapes/Transformer.ts b/src/shapes/Transformer.ts index a882b567..fdea4b22 100644 --- a/src/shapes/Transformer.ts +++ b/src/shapes/Transformer.ts @@ -1,13 +1,13 @@ -import { Util, Transform } from '../Util'; -import { Factory } from '../Factory'; -import { Node } from '../Node'; -import { Shape } from '../Shape'; -import { Rect } from './Rect'; -import { Group } from '../Group'; -import { ContainerConfig } from '../Container'; -import { Konva } from '../Global'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Util, Transform } from '../Util.js'; +import { Factory } from '../Factory.js'; +import { Node } from '../Node.js'; +import { Shape } from '../Shape.js'; +import { Rect } from './Rect.js'; +import { Group } from '../Group.js'; +import { ContainerConfig } from '../Container.js'; +import { Konva } from '../Global.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet, IRect, Vector2d } from '../types'; diff --git a/src/shapes/Wedge.ts b/src/shapes/Wedge.ts index 28b11792..30726c0c 100644 --- a/src/shapes/Wedge.ts +++ b/src/shapes/Wedge.ts @@ -1,8 +1,8 @@ -import { Factory } from '../Factory'; -import { Shape, ShapeConfig } from '../Shape'; -import { Konva } from '../Global'; -import { getNumberValidator } from '../Validators'; -import { _registerNode } from '../Global'; +import { Factory } from '../Factory.js'; +import { Shape, ShapeConfig } from '../Shape.js'; +import { Konva } from '../Global.js'; +import { getNumberValidator } from '../Validators.js'; +import { _registerNode } from '../Global.js'; import { GetSet } from '../types'; diff --git a/test.ts b/test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/test/import-test.js b/test/import-test.js index 1aaf56cd..84799e0b 100644 --- a/test/import-test.js +++ b/test/import-test.js @@ -1,29 +1,25 @@ -// TODO: restore -// function equal(val1, val2, message) { -// if (val1 !== val2) { -// throw new Error('Not passed: ' + message); -// } -// } +function equal(val1, val2, message) { + if (val1 !== val2) { + throw new Error('Not passed: ' + message); + } +} -// // try to import only core -// let { Konva } = require('../lib/Core'); +// try to import only core +import Konva from '../lib/Core.js'; -// // no external shapes +// no external shapes // equal(Konva.Rect, undefined, 'no external shapes'); -// let Rect = require('../lib/shapes/Rect').Rect; +import { Rect } from '../lib/shapes/Rect.js'; -// equal(Rect !== undefined, true, 'Rect is defined'); +equal(Rect !== undefined, true, 'Rect is defined'); -// equal(Konva.Rect, Rect, 'Rect is injected'); +equal(Konva.Rect, Rect, 'Rect is injected'); -// // now import from package.json -// const oldKonva = Konva; -// Konva = require('../'); +import Konva2 from '../lib/index-node.js'; -// equal(Konva.Rect, Rect, 'Same rects'); +equal(Konva2.Rect, Rect, 'Rect is injected'); -// // check global injection -// equal(global.Konva, Konva, 'injected'); +equal(Konva2, Konva, 'Same Konva'); -// equal(Konva, oldKonva, 'Full package is the same as core.'); +console.log('Import tests are passed.'); diff --git a/test/manual/Blur-test.ts b/test/manual/Blur-test.ts index 46bffcba..9bafa8e3 100644 --- a/test/manual/Blur-test.ts +++ b/test/manual/Blur-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Blur', function () { // ====================================================== diff --git a/test/manual/Brighten-test.ts b/test/manual/Brighten-test.ts index 8ba30fb1..06112211 100644 --- a/test/manual/Brighten-test.ts +++ b/test/manual/Brighten-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Brighten', function () { // ====================================================== diff --git a/test/manual/Contrast-test.ts b/test/manual/Contrast-test.ts index 45265482..0528af45 100644 --- a/test/manual/Contrast-test.ts +++ b/test/manual/Contrast-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Filter Contrast', function () { // ====================================================== diff --git a/test/manual/Emboss-test.ts b/test/manual/Emboss-test.ts index e3cdfe9f..841e44fe 100644 --- a/test/manual/Emboss-test.ts +++ b/test/manual/Emboss-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Emboss', function () { // ====================================================== diff --git a/test/manual/Enhance-test.ts b/test/manual/Enhance-test.ts index 77faf631..0f93f2b1 100644 --- a/test/manual/Enhance-test.ts +++ b/test/manual/Enhance-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Enhance', function () { // ====================================================== diff --git a/test/manual/Filter-test.ts b/test/manual/Filter-test.ts index 19c44ca2..a12af132 100644 --- a/test/manual/Filter-test.ts +++ b/test/manual/Filter-test.ts @@ -1,4 +1,4 @@ -import { addStage, Konva, cloneAndCompareLayer } from '../unit/utis'; +import { addStage, Konva, cloneAndCompareLayer } from '../unit/test-utils'; describe('Filter', function () { it('pixelRaio check', function () { diff --git a/test/manual/Grayscale-test.ts b/test/manual/Grayscale-test.ts index 8b5ec3ae..0b04baa0 100644 --- a/test/manual/Grayscale-test.ts +++ b/test/manual/Grayscale-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Grayscale', function () { // ====================================================== diff --git a/test/manual/HSL-test.ts b/test/manual/HSL-test.ts index f0848ab9..ea4fc340 100644 --- a/test/manual/HSL-test.ts +++ b/test/manual/HSL-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('HSL', function () { // ====================================================== diff --git a/test/manual/HSV-test.ts b/test/manual/HSV-test.ts index 896a27c9..69526617 100644 --- a/test/manual/HSV-test.ts +++ b/test/manual/HSV-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('HSV', function () { // ====================================================== diff --git a/test/manual/Invert-test.ts b/test/manual/Invert-test.ts index f08685dc..800cebf9 100644 --- a/test/manual/Invert-test.ts +++ b/test/manual/Invert-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Invert', function () { // ====================================================== diff --git a/test/manual/Kaleidoscope-test.ts b/test/manual/Kaleidoscope-test.ts index e98e7a42..ef400ac1 100644 --- a/test/manual/Kaleidoscope-test.ts +++ b/test/manual/Kaleidoscope-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Kaleidoscope', function () { // ====================================================== diff --git a/test/manual/Manual-test.ts b/test/manual/Manual-test.ts index 263aaad5..1a506a04 100644 --- a/test/manual/Manual-test.ts +++ b/test/manual/Manual-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Manual', function () { // ====================================================== diff --git a/test/manual/Mask-test.ts b/test/manual/Mask-test.ts index 03d96222..870c4f31 100644 --- a/test/manual/Mask-test.ts +++ b/test/manual/Mask-test.ts @@ -1,4 +1,4 @@ -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Mask', function () { // ====================================================== diff --git a/test/manual/Noise-test.ts b/test/manual/Noise-test.ts index e09c7334..c910a640 100644 --- a/test/manual/Noise-test.ts +++ b/test/manual/Noise-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Noise', function () { // ====================================================== diff --git a/test/manual/Pixelate-test.ts b/test/manual/Pixelate-test.ts index b68d3a71..cb22ea30 100644 --- a/test/manual/Pixelate-test.ts +++ b/test/manual/Pixelate-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Pixelate', function () { // ====================================================== diff --git a/test/manual/Posterize-test.ts b/test/manual/Posterize-test.ts index 057c7365..e83f14d4 100644 --- a/test/manual/Posterize-test.ts +++ b/test/manual/Posterize-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Posterize', function () { // ====================================================== diff --git a/test/manual/RGB-test.ts b/test/manual/RGB-test.ts index 2f2d5145..2fef7e74 100644 --- a/test/manual/RGB-test.ts +++ b/test/manual/RGB-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('RGB', function () { // ====================================================== diff --git a/test/manual/RGBA-test.ts b/test/manual/RGBA-test.ts index 71e29c9c..37c67133 100644 --- a/test/manual/RGBA-test.ts +++ b/test/manual/RGBA-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('RGBA', function () { // ====================================================== diff --git a/test/manual/Sepia-test.ts b/test/manual/Sepia-test.ts index 58f5f97a..e22a132a 100644 --- a/test/manual/Sepia-test.ts +++ b/test/manual/Sepia-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Filter Sepia', function () { // ====================================================== diff --git a/test/manual/Solarize-test.ts b/test/manual/Solarize-test.ts index 4858b6d2..a32faec0 100644 --- a/test/manual/Solarize-test.ts +++ b/test/manual/Solarize-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Solarize', function () { // ====================================================== diff --git a/test/manual/Threshold-test.ts b/test/manual/Threshold-test.ts index 3f59d773..df1d0701 100644 --- a/test/manual/Threshold-test.ts +++ b/test/manual/Threshold-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../unit/utis'; +import { addStage, Konva, loadImage } from '../unit/test-utils'; describe('Threshold', function () { // ====================================================== diff --git a/test/unit/Animation-test.ts b/test/unit/Animation-test.ts index 6e4b1862..856632e2 100644 --- a/test/unit/Animation-test.ts +++ b/test/unit/Animation-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Animation', function () { // ====================================================== diff --git a/test/unit/Arc-test.ts b/test/unit/Arc-test.ts index b1d9b100..51c5d298 100644 --- a/test/unit/Arc-test.ts +++ b/test/unit/Arc-test.ts @@ -1,6 +1,11 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; +import { + addStage, + Konva, + createCanvas, + compareLayerAndCanvas, +} from './test-utils'; describe('Arc', function () { // ====================================================== diff --git a/test/unit/Arrow-test.ts b/test/unit/Arrow-test.ts index 8fb65a48..831f3ced 100644 --- a/test/unit/Arrow-test.ts +++ b/test/unit/Arrow-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, cloneAndCompareLayer } from './utis'; +import { addStage, Konva, cloneAndCompareLayer } from './test-utils'; describe('Arrow', function () { // ====================================================== diff --git a/test/unit/AutoDraw-test.ts b/test/unit/AutoDraw-test.ts index b2b92da1..817f95ef 100644 --- a/test/unit/AutoDraw-test.ts +++ b/test/unit/AutoDraw-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { addStage, isNode, Konva } from './utis'; +import { addStage, isNode, Konva } from './test-utils'; describe('AutoDraw', function () { // ====================================================== diff --git a/test/unit/Blob-test.ts b/test/unit/Blob-test.ts index 382f2191..aa4315af 100644 --- a/test/unit/Blob-test.ts +++ b/test/unit/Blob-test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; import { Line } from '../../src/shapes/Line'; -import { addStage, Konva, cloneAndCompareLayer } from './utis'; +import { addStage, Konva, cloneAndCompareLayer } from './test-utils'; describe('Blob', function () { // ====================================================== diff --git a/test/unit/Canvas-test.ts b/test/unit/Canvas-test.ts index 99009b33..05fa37f9 100644 --- a/test/unit/Canvas-test.ts +++ b/test/unit/Canvas-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Canvas', function () { // ====================================================== diff --git a/test/unit/Circle-test.ts b/test/unit/Circle-test.ts index 28169bad..11c1c266 100644 --- a/test/unit/Circle-test.ts +++ b/test/unit/Circle-test.ts @@ -6,7 +6,7 @@ import { createCanvas, compareLayerAndCanvas, loadImage, -} from './utis'; +} from './test-utils'; describe('Circle', function () { // ====================================================== diff --git a/test/unit/Container-test.ts b/test/unit/Container-test.ts index 423f644f..f544197b 100644 --- a/test/unit/Container-test.ts +++ b/test/unit/Container-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { Shape } from '../../src/Shape'; -import { addStage, Konva, compareLayers } from './utis'; +import { Shape } from '../../src/Shape.js'; +import { addStage, Konva, compareLayers } from './test-utils'; describe('Container', function () { // ====================================================== diff --git a/test/unit/Context-test.ts b/test/unit/Context-test.ts index 9fe9f586..3c231326 100644 --- a/test/unit/Context-test.ts +++ b/test/unit/Context-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Context', function () { // ====================================================== diff --git a/test/unit/DragAndDrop-test.ts b/test/unit/DragAndDrop-test.ts index 6ba49a2e..d6616cce 100644 --- a/test/unit/DragAndDrop-test.ts +++ b/test/unit/DragAndDrop-test.ts @@ -8,7 +8,7 @@ import { simulateTouchStart, simulateTouchEnd, simulateTouchMove, -} from './utis'; +} from './test-utils'; describe('DragAndDrop', function () { // ====================================================== diff --git a/test/unit/DragAndDropEvents-test.ts b/test/unit/DragAndDropEvents-test.ts index 51d92e5b..8219e7d1 100644 --- a/test/unit/DragAndDropEvents-test.ts +++ b/test/unit/DragAndDropEvents-test.ts @@ -6,7 +6,7 @@ import { simulateMouseDown, simulateMouseMove, simulateMouseUp, -} from './utis'; +} from './test-utils'; describe('DragAndDropEvents', function () { // ====================================================== diff --git a/test/unit/Ellipse-test.ts b/test/unit/Ellipse-test.ts index 2b893df3..2411dc50 100644 --- a/test/unit/Ellipse-test.ts +++ b/test/unit/Ellipse-test.ts @@ -1,6 +1,11 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; +import { + addStage, + Konva, + createCanvas, + compareLayerAndCanvas, +} from './test-utils'; describe('Ellipse', function () { // ====================================================== diff --git a/test/unit/Global-test.ts b/test/unit/Global-test.ts index 3856bbdd..551542e4 100644 --- a/test/unit/Global-test.ts +++ b/test/unit/Global-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { Konva } from './utis'; +import { Konva } from './test-utils'; describe('Global', function () { // ====================================================== @@ -19,73 +19,4 @@ describe('Global', function () { // set angleDeg back to true for future tests Konva.angleDeg = true; }); - - // ====================================================== - it('UA tests', function () { - var ua; - - // Chrome 34.0.1847.137 m - ua = Konva._parseUA( - 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36' - ); - - assert.equal(ua.browser, 'chrome'); - assert.equal(ua.mobile, false); - assert.equal(ua.version, '34.0.1847.137'); - assert.equal(ua.ieMobile, false); - - // Internet Explorer 9 - ua = Konva._parseUA( - 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)' - ); - assert.equal(ua.browser, 'msie'); - assert.equal(ua.mobile, false); - assert.equal(ua.version, '9.0'); - assert.equal(ua.ieMobile, false); - - // Internet Explorer 10 - ua = Konva._parseUA( - 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)' - ); - assert.equal(ua.browser, 'msie'); - assert.equal(ua.mobile, false); - assert.equal(ua.version, '10.0'); - assert.equal(ua.ieMobile, false); - - // Internet Explorer 10 Mobile (Windows Phone 8) - ua = Konva._parseUA( - 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)' - ); - assert.equal(ua.browser, 'msie'); - assert.equal(ua.mobile, true); - assert.equal(ua.version, '10.0'); - assert.equal(ua.ieMobile, true); // <-- forces Konva mouse events to be Konva touch events instead - - // Internet Explorer 11 Mobile (Windows Phone 8.1) - ua = Konva._parseUA( - 'Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11; IEMobile/11.0; NOKIA; Lumia 928) like Gecko' - ); - assert.equal(ua.browser, 'mozilla'); - assert.equal(ua.mobile, true); - assert.equal(ua.version, '11'); - assert.equal(ua.ieMobile, true); // <-- forces Konva mouse events to be Konva touch events instead - - // Internet Explorer 11 on 64-bit Windows 8.1 with Update - ua = Konva._parseUA( - 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' - ); - assert.equal(ua.browser, 'mozilla'); - assert.equal(ua.mobile, false); - assert.equal(ua.version, '11.0'); - assert.equal(ua.ieMobile, false); - - // Windows 8.1 with Update HTML/JS appx - ua = Konva._parseUA( - 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; Tablet PC 2.0; MSAppHost/2.0; rv:11.0) like Gecko' - ); - assert.equal(ua.browser, 'mozilla'); - assert.equal(ua.mobile, false); - assert.equal(ua.version, '11.0'); - assert.equal(ua.ieMobile, false); - }); }); diff --git a/test/unit/Group-test.ts b/test/unit/Group-test.ts index ec75dfe9..4dc2c6b9 100644 --- a/test/unit/Group-test.ts +++ b/test/unit/Group-test.ts @@ -1,4 +1,4 @@ -import { addStage, cloneAndCompareLayer, Konva } from './utis'; +import { addStage, cloneAndCompareLayer, Konva } from './test-utils'; describe('Group', function () { // ====================================================== diff --git a/test/unit/Image-test.ts b/test/unit/Image-test.ts index f4560ce2..80f3356b 100644 --- a/test/unit/Image-test.ts +++ b/test/unit/Image-test.ts @@ -8,7 +8,7 @@ import { loadImage, isNode, isBrowser, -} from './utis'; +} from './test-utils'; describe('Image', function () { // ====================================================== diff --git a/test/unit/Label-test.ts b/test/unit/Label-test.ts index 2fc7a11a..854321b0 100644 --- a/test/unit/Label-test.ts +++ b/test/unit/Label-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, cloneAndCompareLayer, isBrowser } from './utis'; +import { addStage, Konva, cloneAndCompareLayer, isBrowser } from './test-utils'; describe('Label', function () { // ====================================================== diff --git a/test/unit/Layer-test.ts b/test/unit/Layer-test.ts index 3e75f1cc..07eb5fd4 100644 --- a/test/unit/Layer-test.ts +++ b/test/unit/Layer-test.ts @@ -9,7 +9,7 @@ import { Konva, loadImage, isNode, -} from './utis'; +} from './test-utils'; describe('Layer', function () { // ====================================================== diff --git a/test/unit/Line-test.ts b/test/unit/Line-test.ts index 653cc054..2efa2816 100644 --- a/test/unit/Line-test.ts +++ b/test/unit/Line-test.ts @@ -6,7 +6,7 @@ import { createCanvas, compareLayerAndCanvas, compareLayers, -} from './utis'; +} from './test-utils'; describe('Line', function () { // ====================================================== diff --git a/test/unit/MouseEvents-test.ts b/test/unit/MouseEvents-test.ts index 2088ec55..0bad634d 100644 --- a/test/unit/MouseEvents-test.ts +++ b/test/unit/MouseEvents-test.ts @@ -9,7 +9,7 @@ import { simulateTouchStart, simulateTouchEnd, isNode, -} from './utis'; +} from './test-utils'; describe('MouseEvents', function () { // ====================================================== diff --git a/test/unit/Node-cache-test.ts b/test/unit/Node-cache-test.ts index 56bafba5..2f37c6e4 100644 --- a/test/unit/Node-cache-test.ts +++ b/test/unit/Node-cache-test.ts @@ -8,7 +8,7 @@ import { createCanvas, loadImage, getPixelRatio, -} from './utis'; +} from './test-utils'; describe('Caching', function () { it('cache simple rectangle', function () { diff --git a/test/unit/Node-test.ts b/test/unit/Node-test.ts index 42b0cf40..174cfd2c 100644 --- a/test/unit/Node-test.ts +++ b/test/unit/Node-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { Shape } from '../../src/Shape'; +import { Shape } from '../../src/Shape.js'; import { addStage, @@ -12,7 +12,7 @@ import { loadImage, Konva, isBrowser, -} from './utis'; +} from './test-utils'; describe('Node', function () { // ====================================================== diff --git a/test/unit/Path-test.ts b/test/unit/Path-test.ts index b5f63a8c..b3c71c8b 100644 --- a/test/unit/Path-test.ts +++ b/test/unit/Path-test.ts @@ -10,7 +10,7 @@ import { compareLayerAndCanvas, cloneAndCompareLayer, isNode, -} from './utis'; +} from './test-utils'; describe('Path', function () { // ====================================================== diff --git a/test/unit/PointerEvents-test.ts b/test/unit/PointerEvents-test.ts index 60de8610..ae9e2e14 100644 --- a/test/unit/PointerEvents-test.ts +++ b/test/unit/PointerEvents-test.ts @@ -6,7 +6,7 @@ import { simulatePointerDown, simulatePointerMove, simulatePointerUp, -} from './utis'; +} from './test-utils'; // TODO: restore it! describe.skip('PointerEvents', function () { diff --git a/test/unit/Polygon-test.ts b/test/unit/Polygon-test.ts index 72378aa8..d1b6e576 100644 --- a/test/unit/Polygon-test.ts +++ b/test/unit/Polygon-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Polygon', function () { it('add polygon', function () { diff --git a/test/unit/Rect-test.ts b/test/unit/Rect-test.ts index 47b42597..308a6188 100644 --- a/test/unit/Rect-test.ts +++ b/test/unit/Rect-test.ts @@ -1,6 +1,11 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; +import { + addStage, + Konva, + createCanvas, + compareLayerAndCanvas, +} from './test-utils'; describe('Rect', function () { // ====================================================== diff --git a/test/unit/RegularPolygon-test.ts b/test/unit/RegularPolygon-test.ts index 51052535..21f59c02 100644 --- a/test/unit/RegularPolygon-test.ts +++ b/test/unit/RegularPolygon-test.ts @@ -5,7 +5,7 @@ import { Konva, cloneAndCompareLayer, assertAlmostEqual, -} from './utis'; +} from './test-utils'; describe('RegularPolygon', function () { // ====================================================== diff --git a/test/unit/Ring-test.ts b/test/unit/Ring-test.ts index fe78d6cb..7abe4f75 100644 --- a/test/unit/Ring-test.ts +++ b/test/unit/Ring-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, compareLayers } from './utis'; +import { addStage, Konva, compareLayers } from './test-utils'; describe('Ring', function () { // ====================================================== diff --git a/test/unit/Shape-test.ts b/test/unit/Shape-test.ts index 741759c9..ed896a19 100644 --- a/test/unit/Shape-test.ts +++ b/test/unit/Shape-test.ts @@ -12,7 +12,7 @@ import { compareLayers, loadImage, Konva, -} from './utis'; +} from './test-utils'; describe('Shape', function () { // ====================================================== diff --git a/test/unit/Spline-test.ts b/test/unit/Spline-test.ts index fc7252a9..8ec01420 100644 --- a/test/unit/Spline-test.ts +++ b/test/unit/Spline-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Spline', function () { // ====================================================== diff --git a/test/unit/Sprite-test.ts b/test/unit/Sprite-test.ts index 6596c342..9e8f3cfc 100644 --- a/test/unit/Sprite-test.ts +++ b/test/unit/Sprite-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from './utis'; +import { addStage, Konva, loadImage } from './test-utils'; describe('Sprite', function () { // ====================================================== diff --git a/test/unit/Stage-test.ts b/test/unit/Stage-test.ts index 7a1545a1..95778608 100644 --- a/test/unit/Stage-test.ts +++ b/test/unit/Stage-test.ts @@ -15,7 +15,7 @@ import { isNode, isBrowser, Konva, -} from './utis'; +} from './test-utils'; describe('Stage', function () { // ====================================================== diff --git a/test/unit/Star-test.ts b/test/unit/Star-test.ts index dd199739..d31236da 100644 --- a/test/unit/Star-test.ts +++ b/test/unit/Star-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, cloneAndCompareLayer } from './utis'; +import { addStage, Konva, cloneAndCompareLayer } from './test-utils'; describe('Star', function () { // ====================================================== diff --git a/test/unit/Text-test.ts b/test/unit/Text-test.ts index db57658b..6bc3a711 100644 --- a/test/unit/Text-test.ts +++ b/test/unit/Text-test.ts @@ -10,7 +10,7 @@ import { isBrowser, isNode, assertAlmostEqual, -} from './utis'; +} from './test-utils'; describe('Text', function () { // ====================================================== diff --git a/test/unit/TextPath-test.ts b/test/unit/TextPath-test.ts index 3eaa8cf1..50f1302a 100644 --- a/test/unit/TextPath-test.ts +++ b/test/unit/TextPath-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, cloneAndCompareLayer, isBrowser } from './utis'; +import { addStage, Konva, cloneAndCompareLayer, isBrowser } from './test-utils'; describe('TextPath', function () { // ====================================================== diff --git a/test/unit/TouchEvents-test.ts b/test/unit/TouchEvents-test.ts index abb2cb44..fb680589 100644 --- a/test/unit/TouchEvents-test.ts +++ b/test/unit/TouchEvents-test.ts @@ -6,7 +6,7 @@ import { simulateTouchStart, simulateTouchEnd, simulateTouchMove, -} from './utis'; +} from './test-utils'; describe.skip('TouchEvents', function () { // ====================================================== diff --git a/test/unit/Transformer-test.ts b/test/unit/Transformer-test.ts index 44b260cc..89f76af8 100644 --- a/test/unit/Transformer-test.ts +++ b/test/unit/Transformer-test.ts @@ -9,7 +9,7 @@ import { simulateMouseMove as sm, simulateMouseUp as su, assertAlmostEqual, -} from './utis'; +} from './test-utils'; function simulateMouseDown(tr, pos) { sd(tr.getStage(), pos); @@ -1411,7 +1411,6 @@ describe('Transformer', function () { assertAlmostEqual(rect.rotation(), -180); }); - it('slightly move for cache check (top-left anchor)', function () { var stage = addStage(); var layer = new Konva.Layer(); diff --git a/test/unit/Tween-test.ts b/test/unit/Tween-test.ts index 1854a883..838f1e13 100644 --- a/test/unit/Tween-test.ts +++ b/test/unit/Tween-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Tween', function () { // ====================================================== diff --git a/test/unit/Util-test.ts b/test/unit/Util-test.ts index a8f0a89d..65a208e3 100644 --- a/test/unit/Util-test.ts +++ b/test/unit/Util-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { Konva } from './utis'; +import { Konva } from './test-utils'; describe('Util', function () { it('get()', function () { diff --git a/test/unit/Wedge-test.ts b/test/unit/Wedge-test.ts index 00aab0ed..0b0c231d 100644 --- a/test/unit/Wedge-test.ts +++ b/test/unit/Wedge-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva } from './utis'; +import { addStage, Konva } from './test-utils'; describe('Wedge', function () { // ====================================================== diff --git a/test/unit/utis.ts b/test/unit/test-utils.ts similarity index 98% rename from test/unit/utis.ts rename to test/unit/test-utils.ts index 8e463164..cb6b130b 100644 --- a/test/unit/utis.ts +++ b/test/unit/test-utils.ts @@ -10,8 +10,8 @@ Konva.enableTrace = true; Konva.showWarnings = true; import { imagediff } from './imagediff'; -import { Layer } from '../../src/Layer'; -import { Stage } from '../../src/Stage'; +import { Layer } from '../../src/Layer.js'; +import { Stage } from '../../src/Stage.js'; // reset some data beforeEach(function () { @@ -157,8 +157,6 @@ export function showHit(layer) { getContainer().appendChild(canvas); } -Konva['UA'].mobile = false; - export function simulateMouseDown(stage, pos) { var top = isNode ? 0 : stage.content.getBoundingClientRect().top; diff --git a/tsconfig.json b/tsconfig.json index e50c968d..bb54187c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,9 @@ "noEmitOnError": true, "lib": ["ES2015", "dom"], "moduleResolution": "node", - "declaration": true + "declaration": true, + "noImplicitAny": true, + // "strict": true }, "include": ["./src/*.ts"] }