From 59956fe9441fcd7fa373bd2cbe3c9c86a07c3183 Mon Sep 17 00:00:00 2001 From: Anton Lavrenov Date: Mon, 3 May 2021 17:09:18 -0500 Subject: [PATCH] refactor tests --- .eslintrc | 218 --- .gitignore | 1 - bower.json | 30 - konva.js | 1464 ++--------------- package.json | 12 +- src/Node.ts | 1 + src/shapes/Circle.ts | 2 +- test/assets/Ghostscript_Tiger.svg | 725 -------- test/assets/bamoon.jpg | Bin 27342 -> 0 bytes test/assets/cropped-darth.jpg | Bin 23636 -> 0 bytes test/assets/cropped-darth.png | Bin 17257 -> 0 bytes test/assets/rabbit.png | Bin 198914 -> 0 bytes test/ifame.html | 1 + test/lib/imagediff.js | 391 ----- test/lib/stats.js | 105 -- test/manual-tests.html | 70 + .../{unit-new/filters => manual}/Blur-test.ts | 20 +- .../filters => manual}/Brighten-test.ts | 2 +- .../filters => manual}/Contrast-test.ts | 2 +- .../filters => manual}/Emboss-test.ts | 2 +- .../filters => manual}/Enhance-test.ts | 2 +- .../filters => manual}/Filter-test.ts | 2 +- .../filters => manual}/Grayscale-test.ts | 2 +- test/{unit-new/filters => manual}/HSL-test.ts | 2 +- test/{unit-new/filters => manual}/HSV-test.ts | 2 +- .../filters => manual}/Invert-test.ts | 2 +- .../filters => manual}/Kaleidoscope-test.ts | 2 +- .../manual/{manual-test.js => Manual-test.ts} | 32 +- .../{unit-new/filters => manual}/Mask-test.ts | 2 +- .../filters => manual}/Noise-test.ts | 2 +- .../filters => manual}/Pixelate-test.ts | 2 +- .../filters => manual}/Posterize-test.ts | 2 +- test/{unit-new/filters => manual}/RGB-test.ts | 2 +- .../{unit-new/filters => manual}/RGBA-test.ts | 2 +- .../filters => manual}/Sepia-test.ts | 2 +- .../filters => manual}/Solarize-test.ts | 2 +- .../filters => manual}/Threshold-test.ts | 2 +- test/memLeakTest.html | 59 - test/memory/build-destroy-star.html | 64 - test/memory/build-destroy-text.html | 60 - test/node-runner.js | 123 -- test/parcel-runner.html | 37 - test/parcel-runner.ts | 34 - test/performance/bunnies.html | 9 +- test/performance/common/random-squares.js | 104 -- test/performance/random-squares-dev.html | 23 - test/performance/rotate-cached-star.html | 64 - test/runner.html | 191 --- test/sandbox.html | 196 +++ test/sandbox2.html | 58 - test/setStats.js | 29 - test/test.html | 50 - test/tsconfig.json | 10 +- test/unit-tests.html | 112 ++ test/{unit-new => unit}/Animation-test.ts | 0 test/{unit-new/shapes => unit}/Arc-test.ts | 2 +- test/{unit-new/shapes => unit}/Arrow-test.ts | 2 +- test/{unit-new/shapes => unit}/Blob-test.ts | 4 +- test/{unit-new => unit}/Canvas-test.ts | 0 test/{unit-new/shapes => unit}/Circle-test.ts | 2 +- test/{unit-new => unit}/Container-test.ts | 0 test/{unit-new => unit}/Context-test.ts | 0 test/{unit-new => unit}/DragAndDrop-test.ts | 0 .../DragAndDropEvents-test.ts} | 140 +- .../{unit-new/shapes => unit}/Ellipse-test.ts | 2 +- test/{unit-new => unit}/Global-test.ts | 0 test/{unit-new => unit}/Group-test.ts | 0 test/{unit-new/shapes => unit}/Image-test.ts | 2 +- test/{unit-new/shapes => unit}/Label-test.ts | 23 +- test/{unit-new => unit}/Layer-test.ts | 0 test/{unit-new/shapes => unit}/Line-test.ts | 2 +- .../MouseEvents-test.ts} | 381 ++--- test/{unit-new => unit}/Node-cache-test.ts | 0 test/{unit-new => unit}/Node-test.ts | 2 +- test/{unit-new/shapes => unit}/Path-test.ts | 26 +- .../PointerEvents-test.ts} | 94 +- .../{unit-new/shapes => unit}/Polygon-test.ts | 2 +- test/{unit-new/shapes => unit}/Rect-test.ts | 2 +- .../shapes => unit}/RegularPolygon-test.ts | 11 +- test/{unit-new/shapes => unit}/Ring-test.ts | 2 +- test/{unit-new => unit}/Shape-test.ts | 2 +- test/{unit-new/shapes => unit}/Spline-test.ts | 2 +- test/{unit-new/shapes => unit}/Sprite-test.ts | 2 +- test/{unit-new => unit}/Stage-test.ts | 0 test/{unit-new/shapes => unit}/Star-test.ts | 2 +- test/{unit-new/shapes => unit}/Text-test.ts | 90 +- .../shapes => unit}/TextPath-test.ts | 8 +- .../TouchEvents-test.ts} | 176 +- .../shapes => unit}/Transformer-test.ts | 610 ++++--- test/{unit-new => unit}/Tween-test.ts | 0 test/{unit-new => unit}/Util-test.ts | 0 test/{unit-new/shapes => unit}/Wedge-test.ts | 2 +- test/{unit-new => unit}/imagediff.ts | 0 test/{unit-new => unit}/utis.ts | 65 +- test/worker.js | 193 --- 95 files changed, 1318 insertions(+), 4866 deletions(-) delete mode 100644 .eslintrc delete mode 100644 bower.json delete mode 100644 test/assets/Ghostscript_Tiger.svg delete mode 100644 test/assets/bamoon.jpg delete mode 100644 test/assets/cropped-darth.jpg delete mode 100644 test/assets/cropped-darth.png delete mode 100644 test/assets/rabbit.png delete mode 100644 test/lib/imagediff.js delete mode 100644 test/lib/stats.js create mode 100644 test/manual-tests.html rename test/{unit-new/filters => manual}/Blur-test.ts (94%) rename test/{unit-new/filters => manual}/Brighten-test.ts (98%) rename test/{unit-new/filters => manual}/Contrast-test.ts (97%) rename test/{unit-new/filters => manual}/Emboss-test.ts (97%) rename test/{unit-new/filters => manual}/Enhance-test.ts (96%) rename test/{unit-new/filters => manual}/Filter-test.ts (88%) rename test/{unit-new/filters => manual}/Grayscale-test.ts (96%) rename test/{unit-new/filters => manual}/HSL-test.ts (97%) rename test/{unit-new/filters => manual}/HSV-test.ts (98%) rename test/{unit-new/filters => manual}/Invert-test.ts (96%) rename test/{unit-new/filters => manual}/Kaleidoscope-test.ts (97%) rename test/manual/{manual-test.js => Manual-test.ts} (92%) rename test/{unit-new/filters => manual}/Mask-test.ts (92%) rename test/{unit-new/filters => manual}/Noise-test.ts (93%) rename test/{unit-new/filters => manual}/Pixelate-test.ts (93%) rename test/{unit-new/filters => manual}/Posterize-test.ts (93%) rename test/{unit-new/filters => manual}/RGB-test.ts (97%) rename test/{unit-new/filters => manual}/RGBA-test.ts (96%) rename test/{unit-new/filters => manual}/Sepia-test.ts (96%) rename test/{unit-new/filters => manual}/Solarize-test.ts (91%) rename test/{unit-new/filters => manual}/Threshold-test.ts (93%) delete mode 100644 test/memLeakTest.html delete mode 100644 test/memory/build-destroy-star.html delete mode 100644 test/memory/build-destroy-text.html delete mode 100644 test/node-runner.js delete mode 100644 test/parcel-runner.html delete mode 100644 test/parcel-runner.ts delete mode 100644 test/performance/common/random-squares.js delete mode 100644 test/performance/random-squares-dev.html delete mode 100644 test/performance/rotate-cached-star.html delete mode 100644 test/runner.html create mode 100644 test/sandbox.html delete mode 100644 test/sandbox2.html delete mode 100644 test/setStats.js delete mode 100644 test/test.html create mode 100644 test/unit-tests.html rename test/{unit-new => unit}/Animation-test.ts (100%) rename test/{unit-new/shapes => unit}/Arc-test.ts (99%) rename test/{unit-new/shapes => unit}/Arrow-test.ts (98%) rename test/{unit-new/shapes => unit}/Blob-test.ts (96%) rename test/{unit-new => unit}/Canvas-test.ts (100%) rename test/{unit-new/shapes => unit}/Circle-test.ts (99%) rename test/{unit-new => unit}/Container-test.ts (100%) rename test/{unit-new => unit}/Context-test.ts (100%) rename test/{unit-new => unit}/DragAndDrop-test.ts (100%) rename test/{functional/DragAndDropEvents-test.js => unit/DragAndDropEvents-test.ts} (79%) rename test/{unit-new/shapes => unit}/Ellipse-test.ts (99%) rename test/{unit-new => unit}/Global-test.ts (100%) rename test/{unit-new => unit}/Group-test.ts (100%) rename test/{unit-new/shapes => unit}/Image-test.ts (99%) rename test/{unit-new/shapes => unit}/Label-test.ts (83%) rename test/{unit-new => unit}/Layer-test.ts (100%) rename test/{unit-new/shapes => unit}/Line-test.ts (99%) rename test/{functional/MouseEvents-test.js => unit/MouseEvents-test.ts} (87%) rename test/{unit-new => unit}/Node-cache-test.ts (100%) rename test/{unit-new => unit}/Node-test.ts (99%) rename test/{unit-new/shapes => unit}/Path-test.ts (98%) rename test/{functional/PointerEvents-test.js => unit/PointerEvents-test.ts} (78%) rename test/{unit-new/shapes => unit}/Polygon-test.ts (91%) rename test/{unit-new/shapes => unit}/Rect-test.ts (99%) rename test/{unit-new/shapes => unit}/RegularPolygon-test.ts (95%) rename test/{unit-new/shapes => unit}/Ring-test.ts (97%) rename test/{unit-new => unit}/Shape-test.ts (99%) rename test/{unit-new/shapes => unit}/Spline-test.ts (98%) rename test/{unit-new/shapes => unit}/Sprite-test.ts (99%) rename test/{unit-new => unit}/Stage-test.ts (100%) rename test/{unit-new/shapes => unit}/Star-test.ts (97%) rename test/{unit-new/shapes => unit}/Text-test.ts (89%) rename test/{unit-new/shapes => unit}/TextPath-test.ts (99%) rename test/{functional/TouchEvents-test.js => unit/TouchEvents-test.ts} (80%) rename test/{unit-new/shapes => unit}/Transformer-test.ts (85%) rename test/{unit-new => unit}/Tween-test.ts (100%) rename test/{unit-new => unit}/Util-test.ts (100%) rename test/{unit-new/shapes => unit}/Wedge-test.ts (97%) rename test/{unit-new => unit}/imagediff.ts (100%) rename test/{unit-new => unit}/utis.ts (86%) delete mode 100644 test/worker.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 1fe78c9a..00000000 --- a/.eslintrc +++ /dev/null @@ -1,218 +0,0 @@ -{ - "extends": "eslint:recommended", - "env": { - "browser": true, - "node": true - }, - "rules": { - "no-alert": 0, - "no-array-constructor": 2, - "no-bitwise": 0, - "no-caller": 2, - "no-catch-shadow": 2, - "comma-dangle": 2, - "no-underscore-dangle": 0, - "no-cond-assign": 2, - "no-console": 0, - "no-constant-condition": 0, - "no-continue": 0, - "no-control-regex": 2, - "no-debugger": 2, - "no-delete-var": 2, - "no-div-regex": 0, - "no-dupe-keys": 2, - "no-dupe-args": 2, - "no-duplicate-case": 2, - "no-else-return": 0, - "no-empty": 2, - "no-empty-class": 0, - "no-empty-character-class": 2, - "no-labels": 2, - "no-eq-null": 2, - "no-eval": 2, - "no-ex-assign": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-extra-boolean-cast": 2, - "no-extra-parens": 0, - "no-extra-semi": 2, - "no-fallthrough": 2, - "no-floating-decimal": 0, - "no-func-assign": 2, - "no-implied-eval": 2, - "no-inline-comments": 0, - "no-inner-declarations": [2, "functions"], - "no-invalid-regexp": 2, - "no-irregular-whitespace": 2, - "no-iterator": 2, - "no-label-var": 2, - "no-lone-blocks": 2, - "no-lonely-if": 0, - "no-loop-func": 2, - "no-mixed-requires": [1, false], - "no-mixed-spaces-and-tabs": [2, false], - "linebreak-style": [1, "unix"], - "no-multi-spaces": 2, - "no-multi-str": 2, - "no-multiple-empty-lines": [ - 1, - { - "max": 3 - } - ], - "no-native-reassign": 2, - "no-negated-in-lhs": 2, - "no-nested-ternary": 0, - "no-new": 2, - "no-new-func": 2, - "no-new-object": 2, - "no-new-require": 0, - "no-new-wrappers": 2, - "no-obj-calls": 2, - "no-octal": 2, - "no-octal-escape": 2, - "no-param-reassign": 0, - "no-path-concat": 0, - "no-plusplus": 0, - "no-process-env": 0, - "no-process-exit": 2, - "no-proto": 2, - "no-redeclare": 2, - "no-regex-spaces": 2, - "no-reserved-keys": 0, - "no-restricted-modules": 0, - "no-return-assign": 0, - "no-script-url": 2, - "no-self-compare": 0, - "no-sequences": 2, - "no-shadow": 2, - "no-shadow-restricted-names": 2, - "no-spaced-func": 2, - "no-sparse-arrays": 2, - "no-sync": 0, - "no-ternary": 0, - "no-trailing-spaces": 2, - "no-throw-literal": 1, - "no-undef": 2, - "no-undef-init": 2, - "no-undefined": 0, - "no-unneeded-ternary": 2, - "no-unreachable": 2, - "no-unused-expressions": 2, - "no-unused-vars": [ - 2, - { - "vars": "all", - "args": "after-used" - } - ], - "no-use-before-define": 2, - "no-void": 0, - "no-var": 0, - "prefer-const": 0, - "no-warning-comments": [ - 0, - { - "terms": ["todo", "fixme", "xxx"], - "location": "start" - } - ], - "no-with": 2, - "accessor-pairs": 0, - "block-scoped-var": 0, - "brace-style": [0, "1tbs"], - "camelcase": 0, - "comma-spacing": 2, - "comma-style": 0, - "complexity": [1, 15], - "computed-property-spacing": [0, "never"], - "consistent-return": 1, - "consistent-this": [0, "that"], - "curly": [2, "all"], - "default-case": 0, - "dot-location": 0, - "dot-notation": [ - 2, - { - "allowKeywords": true - } - ], - "eol-last": 0, - "eqeqeq": 2, - "func-names": 0, - "func-style": [1, "declaration"], - "generator-star": 0, - "generator-star-spacing": 0, - "guard-for-in": 1, - "handle-callback-err": 2, - "indent": 0, - "key-spacing": [ - 2, - { - "beforeColon": false, - "afterColon": true - } - ], - "lines-around-comment": 0, - "max-depth": [2, 5], - "max-len": [2, 320, 4], - "max-nested-callbacks": [2, 2], - "max-params": [1, 8], - "max-statements": [1, 260], - "new-cap": 0, - "new-parens": 2, - "newline-after-var": 0, - "object-curly-spacing": [0, "never"], - "object-shorthand": 0, - "one-var": 0, - "operator-assignment": [0, "always"], - "operator-linebreak": 0, - "padded-blocks": 0, - "quote-props": 0, - "quotes": [2, "single"], - "radix": 0, - "semi": 2, - "semi-spacing": [ - 2, - { - "before": false, - "after": true - } - ], - "sort-vars": 0, - "space-after-function-name": [0, "never"], - "space-after-keywords": [0, "always"], - "space-before-blocks": [0, "always"], - "space-before-function-paren": [0, "always"], - "space-before-function-parentheses": [0, "always"], - "space-in-brackets": [0, "never"], - "space-in-parens": [0, "never"], - "space-infix-ops": 2, - "keyword-spacing": 0, - "space-unary-ops": [ - 2, - { - "words": true, - "nonwords": false - } - ], - "spaced-comment": 0, - "spaced-line-comment": [0, "always"], - "strict": [0, "function"], - "use-isnan": 2, - "valid-jsdoc": 0, - "valid-typeof": 2, - "vars-on-top": 0, - "wrap-iife": 0, - "wrap-regex": 0, - "yoda": [2, "never"] - }, - "globals": { - "Konva": false, - "define": false, - "test": false, - "assert": false, - "addStage": false, - "suite": false - } -} diff --git a/.gitignore b/.gitignore index 023152ef..cf6ec68d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ docs homedocs jsdoc-template api -test/sandbox.html package-lock.json lib src_old diff --git a/bower.json b/bower.json deleted file mode 100644 index cc97733e..00000000 --- a/bower.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "konva", - "authors": [ - "Anton Lavrenov", "Eric Rowell" - ], - "homepage": "http://konvajs.org", - "description": "Konva is an HTML5 Canvas JavaScript framework that enables high performance animations, transitions, node nesting, layering, filtering, caching, event handling for desktop and mobile applications, and much more.", - "keywords": [ - "canvas", - "animations", - "graphic", - "html5" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "test", - "resources", - "src", - "*.yml", - ".jshitrc", - ".npmignore", - "package.json", - ".travis.yml", - ".gitignore", - "Gruntfile.js", - "gulpfile.js" - ], - "main": "konva.min.js" -} diff --git a/konva.js b/konva.js index 7c95f76d..9683e320 100644 --- a/konva.js +++ b/konva.js @@ -5,10 +5,10 @@ }(this, (function () { 'use strict'; /* - * Konva JavaScript Framework v7.2.5 + * Konva JavaScript Framework v@@version * http://konvajs.org/ * Licensed under the MIT - * Date: Thu Apr 29 2021 + * Date: @@date * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) @@ -76,7 +76,7 @@ : {}; const Konva$2 = { _global: glob, - version: '7.2.5', + version: '@@version', isBrowser: detectBrowser(), isUnminified: /param/.test(function (param) { }.toString()), dblClickWindow: 400, @@ -1202,7 +1202,9 @@ Util.warn(_formatValue(val) + ' is a not valid value for "' + attr + - '" attribute. The value should be a number or Array(' + noOfElements + ')'); + '" attribute. The value should be a number or Array(' + + noOfElements + + ')'); } return val; }; @@ -1240,7 +1242,8 @@ if (Konva$2.isUnminified) { return function (val, attr) { const isString = Util._isString(val); - const isGradient = Object.prototype.toString.call(val) === '[object CanvasGradient]'; + 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 "' + @@ -1556,7 +1559,7 @@ this.strokeShape(shape); } } - getTrace(relaxed) { + getTrace(relaxed, rounded) { var traceArr = this.traceArr, len = traceArr.length, str = '', n, trace, method, args; for (n = 0; n < len; n++) { trace = traceArr[n]; @@ -1573,6 +1576,9 @@ 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; } } @@ -2516,26 +2522,7 @@ * @constructor * @memberof Konva * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams */ class Node { constructor(config) { @@ -2618,8 +2605,8 @@ _clearSelfAndDescendantCache(attr, forceEvent) { this._clearCache(attr); // trigger clear cache, so transformer can use it - if (forceEvent && attr === ABSOLUTE_TRANSFORM) { - this.fire('_clearTransformCache'); + if (attr === ABSOLUTE_TRANSFORM) { + this.fire('absoluteTransformChange'); } } /** @@ -5158,33 +5145,8 @@ * @augments Konva.Node * @abstract * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams */ class Container extends Node { constructor() { @@ -5803,26 +5765,7 @@ * @augments Konva.Container * @param {Object} config * @param {String|Element} config.container Container selector or DOM element - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams * @example * var stage = new Konva.Stage({ * width: 500, @@ -6716,80 +6659,8 @@ * @memberof Konva * @augments Konva.Node * @param {Object} config - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var customShape = new Konva.Shape({ * x: 5, @@ -8300,33 +8171,8 @@ * @param {Object} config * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want * to clear the canvas before each layer draw. The default value is true. - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams * @example * var layer = new Konva.Layer(); * stage.add(layer); @@ -8410,13 +8256,13 @@ setZIndex(index) { super.setZIndex(index); var stage = this.getStage(); - if (stage) { - stage.content.removeChild(this.getCanvas()._canvas); + if (stage && stage.content) { + stage.content.removeChild(this.getCanvasElement()); if (index < stage.children.length - 1) { - stage.content.insertBefore(this.getCanvas()._canvas, stage.children[index + 1].getCanvas()._canvas); + stage.content.insertBefore(this.getCanvasElement(), stage.children[index + 1].getCanvas()._canvas); } else { - stage.content.appendChild(this.getCanvas()._canvas); + stage.content.appendChild(this.getCanvasElement()); } } return this; @@ -8424,9 +8270,9 @@ moveToTop() { Node.prototype.moveToTop.call(this); var stage = this.getStage(); - if (stage) { - stage.content.removeChild(this.getCanvas()._canvas); - stage.content.appendChild(this.getCanvas()._canvas); + if (stage && stage.content) { + stage.content.removeChild(this.getCanvasElement()); + stage.content.appendChild(this.getCanvasElement()); } return true; } @@ -8436,15 +8282,15 @@ return false; } var stage = this.getStage(); - if (!stage) { + if (!stage || !stage.content) { return false; } - stage.content.removeChild(this.getCanvas()._canvas); + stage.content.removeChild(this.getCanvasElement()); if (this.index < stage.children.length - 1) { - stage.content.insertBefore(this.getCanvas()._canvas, stage.children[this.index + 1].getCanvas()._canvas); + stage.content.insertBefore(this.getCanvasElement(), stage.children[this.index + 1].getCanvas()._canvas); } else { - stage.content.appendChild(this.getCanvas()._canvas); + stage.content.appendChild(this.getCanvasElement()); } return true; } @@ -8454,8 +8300,10 @@ var stage = this.getStage(); if (stage) { var children = stage.children; - stage.content.removeChild(this.getCanvas()._canvas); - stage.content.insertBefore(this.getCanvas()._canvas, children[this.index + 1].getCanvas()._canvas); + if (stage.content) { + stage.content.removeChild(this.getCanvasElement()); + stage.content.insertBefore(this.getCanvasElement(), children[this.index + 1].getCanvas()._canvas); + } } return true; } @@ -8467,8 +8315,10 @@ var stage = this.getStage(); if (stage) { var children = stage.children; - stage.content.removeChild(this.getCanvas()._canvas); - stage.content.insertBefore(this.getCanvas()._canvas, children[1].getCanvas()._canvas); + if (stage.content) { + stage.content.removeChild(this.getCanvasElement()); + stage.content.insertBefore(this.getCanvasElement(), children[1].getCanvas()._canvas); + } } return true; } @@ -8478,7 +8328,7 @@ return this; } remove() { - var _canvas = this.getCanvas()._canvas; + var _canvas = this.getCanvasElement(); Node.prototype.remove.call(this); if (_canvas && _canvas.parentNode && Util._isInDocument(_canvas)) { _canvas.parentNode.removeChild(_canvas); @@ -8708,7 +8558,7 @@ * @method */ toggleHitCanvas() { - if (!this.parent) { + if (!this.parent || !this.parent['content']) { return; } var parent = this.parent; @@ -8787,13 +8637,7 @@ * @constructor * @memberof Konva * @augments Konva.Layer - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@containerParams * @example * var layer = new Konva.FastLayer(); */ @@ -8813,33 +8657,8 @@ * @memberof Konva * @augments Konva.Container * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] - * * @param {Object} [config.clip] set clip - * @param {Number} [config.clipX] set clip x - * @param {Number} [config.clipY] set clip y - * @param {Number} [config.clipWidth] set clip width - * @param {Number} [config.clipHeight] set clip height - * @param {Function} [config.clipFunc] set clip func - + * @@nodeParams + * @@containerParams * @example * var group = new Konva.Group(); */ @@ -9806,80 +9625,8 @@ * @param {Number} config.innerRadius * @param {Number} config.outerRadius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // draw a Arc that's pointing downwards * var arc = new Konva.Arc({ @@ -9991,80 +9738,8 @@ * The default is 0 * @param {Boolean} [config.closed] defines whether or not the line shape is closed, creating a polygon or blob * @param {Boolean} [config.bezier] if no tension is provided but bezier=true, we draw the line as a bezier using the passed points - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var line = new Konva.Line({ * x: 100, @@ -10283,80 +9958,8 @@ * @param {Number} config.pointerLength Arrow pointer length. Default value is 10. * @param {Number} config.pointerWidth Arrow pointer width. Default value is 10. * @param {Boolean} config.pointerAtBeginning Do we need to draw pointer on both sides?. Default false. - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var line = new Konva.Line({ * points: [73, 70, 340, 23, 450, 60, 500, 20], @@ -10496,80 +10099,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Number} config.radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // create circle * var circle = new Konva.Circle({ @@ -10629,80 +10160,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Object} config.radius defines x and y radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var ellipse = new Konva.Ellipse({ * radius : { @@ -10799,80 +10258,8 @@ * @param {Object} config * @param {Image} config.image * @param {Object} [config.crop] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var imageObj = new Image(); * imageObj.onload = function() { @@ -11079,26 +10466,7 @@ * @constructor * @memberof Konva * @param {Object} config - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@nodeParams * @example * // create label * var label = new Konva.Label({ @@ -11359,80 +10727,8 @@ * @augments Konva.Shape * @param {Object} config * @param {String} config.data SVG data string - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var path = new Konva.Path({ * x: 240, @@ -12177,80 +11473,8 @@ * @augments Konva.Shape * @param {Object} config * @param {Number} [config.cornerRadius] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var rect = new Konva.Rect({ * width: 100, @@ -12325,80 +11549,8 @@ * @param {Object} config * @param {Number} config.sides * @param {Number} config.radius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var hexagon = new Konva.RegularPolygon({ * x: 100, @@ -12508,80 +11660,8 @@ * @param {Number} config.innerRadius * @param {Number} config.outerRadius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var ring = new Konva.Ring({ * innerRadius: 40, @@ -12657,80 +11737,8 @@ * @param {Integer} [config.frameIndex] animation frame index * @param {Image} config.image image object * @param {Integer} [config.frameRate] animation frame rate - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var imageObj = new Image(); * imageObj.onload = function() { @@ -13022,80 +12030,8 @@ * @param {Integer} config.numPoints * @param {Number} config.innerRadius * @param {Number} config.outerRadius - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var star = new Konva.Star({ * x: 100, @@ -13266,80 +12202,8 @@ * @param {Number} [config.lineHeight] default is 1 * @param {String} [config.wrap] can be "word", "char", or "none". Default is word * @param {Boolean} [config.ellipsis] can be true or false. Default is false. if Konva.Text config is set to wrap="none" and ellipsis=true, then it will add "..." to the end - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var text = new Konva.Text({ * x: 10, @@ -13942,80 +12806,8 @@ * @param {String} config.data SVG data string * @param {Function} config.getKerning a getter for kerning values for the specified characters * @param {Function} config.kerningFunc a getter for kerning values for the specified characters - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * var kerningPairs = { * 'A': { @@ -14796,7 +13588,7 @@ }; node.on(additionalEvents, onChange); node.on(TRANSFORM_CHANGE_STR, onChange); - node.on(`_clearTransformCache.${EVENTS_NAME}`, onChange); + node.on(`absoluteTransformChange.${EVENTS_NAME}`, onChange); node.on(`xChange.${EVENTS_NAME} yChange.${EVENTS_NAME}`, onChange); this._proxyDrag(node); }); @@ -15017,11 +13809,13 @@ anchor.on('mouseenter', () => { var rad = Konva$2.getAngle(this.rotation()); var cursor = getCursor(name, rad); - anchor.getStage().content.style.cursor = cursor; + anchor.getStage().content && + (anchor.getStage().content.style.cursor = cursor); this._cursorChange = true; }); anchor.on('mouseout', () => { - anchor.getStage().content.style.cursor = ''; + anchor.getStage().content && + (anchor.getStage().content.style.cursor = ''); this._cursorChange = false; }); this.add(anchor); @@ -15076,10 +13870,12 @@ var hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); this.sin = Math.abs(height / hypotenuse); this.cos = Math.abs(width / hypotenuse); - window.addEventListener('mousemove', this._handleMouseMove); - window.addEventListener('touchmove', this._handleMouseMove); - window.addEventListener('mouseup', this._handleMouseUp, true); - window.addEventListener('touchend', this._handleMouseUp, true); + 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(); @@ -15274,10 +14070,12 @@ _removeEvents(e) { if (this._transforming) { this._transforming = false; - window.removeEventListener('mousemove', this._handleMouseMove); - window.removeEventListener('touchmove', this._handleMouseMove); - window.removeEventListener('mouseup', this._handleMouseUp, true); - window.removeEventListener('touchend', this._handleMouseUp, true); + 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) { @@ -15541,7 +14339,7 @@ } destroy() { if (this.getStage() && this._cursorChange) { - this.getStage().content.style.cursor = ''; + this.getStage().content && (this.getStage().content.style.cursor = ''); } Group.prototype.destroy.call(this); this.detach(); @@ -15896,80 +14694,8 @@ * @param {Number} config.angle in degrees * @param {Number} config.radius * @param {Boolean} [config.clockwise] - * @param {String} [config.fill] fill color - * @param {Image} [config.fillPatternImage] fill pattern image - * @param {Number} [config.fillPatternX] - * @param {Number} [config.fillPatternY] - * @param {Object} [config.fillPatternOffset] object with x and y component - * @param {Number} [config.fillPatternOffsetX] - * @param {Number} [config.fillPatternOffsetY] - * @param {Object} [config.fillPatternScale] object with x and y component - * @param {Number} [config.fillPatternScaleX] - * @param {Number} [config.fillPatternScaleY] - * @param {Number} [config.fillPatternRotation] - * @param {String} [config.fillPatternRepeat] can be "repeat", "repeat-x", "repeat-y", or "no-repeat". The default is "no-repeat" - * @param {Object} [config.fillLinearGradientStartPoint] object with x and y component - * @param {Number} [config.fillLinearGradientStartPointX] - * @param {Number} [config.fillLinearGradientStartPointY] - * @param {Object} [config.fillLinearGradientEndPoint] object with x and y component - * @param {Number} [config.fillLinearGradientEndPointX] - * @param {Number} [config.fillLinearGradientEndPointY] - * @param {Array} [config.fillLinearGradientColorStops] array of color stops - * @param {Object} [config.fillRadialGradientStartPoint] object with x and y component - * @param {Number} [config.fillRadialGradientStartPointX] - * @param {Number} [config.fillRadialGradientStartPointY] - * @param {Object} [config.fillRadialGradientEndPoint] object with x and y component - * @param {Number} [config.fillRadialGradientEndPointX] - * @param {Number} [config.fillRadialGradientEndPointY] - * @param {Number} [config.fillRadialGradientStartRadius] - * @param {Number} [config.fillRadialGradientEndRadius] - * @param {Array} [config.fillRadialGradientColorStops] array of color stops - * @param {Boolean} [config.fillEnabled] flag which enables or disables the fill. The default value is true - * @param {String} [config.fillPriority] can be color, linear-gradient, radial-graident, or pattern. The default value is color. The fillPriority property makes it really easy to toggle between different fill types. For example, if you want to toggle between a fill color style and a fill pattern style, simply set the fill property and the fillPattern properties, and then use setFillPriority('color') to render the shape with a color fill, or use setFillPriority('pattern') to render the shape with the pattern fill configuration - * @param {String} [config.stroke] stroke color - * @param {Number} [config.strokeWidth] stroke width - * @param {Boolean} [config.fillAfterStrokeEnabled]. Should we draw fill AFTER stroke? Default is false. - * @param {Number} [config.hitStrokeWidth] size of the stroke on hit canvas. The default is "auto" - equals to strokeWidth - * @param {Boolean} [config.strokeHitEnabled] flag which enables or disables stroke hit region. The default is true - * @param {Boolean} [config.perfectDrawEnabled] flag which enables or disables using buffer canvas. The default is true - * @param {Boolean} [config.shadowForStrokeEnabled] flag which enables or disables shadow for stroke. The default is true - * @param {Boolean} [config.strokeScaleEnabled] flag which enables or disables stroke scale. The default is true - * @param {Boolean} [config.strokeEnabled] flag which enables or disables the stroke. The default value is true - * @param {String} [config.lineJoin] can be miter, round, or bevel. The default - * is miter - * @param {String} [config.lineCap] can be butt, round, or square. The default - * is butt - * @param {String} [config.shadowColor] - * @param {Number} [config.shadowBlur] - * @param {Object} [config.shadowOffset] object with x and y component - * @param {Number} [config.shadowOffsetX] - * @param {Number} [config.shadowOffsetY] - * @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number - * between 0 and 1 - * @param {Boolean} [config.shadowEnabled] flag which enables or disables the shadow. The default value is true - * @param {Array} [config.dash] - * @param {Boolean} [config.dashEnabled] flag which enables or disables the dashArray. The default value is true - - * @param {Number} [config.x] - * @param {Number} [config.y] - * @param {Number} [config.width] - * @param {Number} [config.height] - * @param {Boolean} [config.visible] - * @param {Boolean} [config.listening] whether or not the node is listening for events - * @param {String} [config.id] unique id - * @param {String} [config.name] non-unique name - * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1 - * @param {Object} [config.scale] set scale - * @param {Number} [config.scaleX] set scale x - * @param {Number} [config.scaleY] set scale y - * @param {Number} [config.rotation] rotation in degrees - * @param {Object} [config.offset] offset from center point and rotation point - * @param {Number} [config.offsetX] set offset x - * @param {Number} [config.offsetY] set offset y - * @param {Boolean} [config.draggable] makes the node draggable. When stages are draggable, you can drag and drop - * the entire stage by dragging any portion of the stage - * @param {Number} [config.dragDistance] - * @param {Function} [config.dragBoundFunc] + * @@shapeParams + * @@nodeParams * @example * // draw a wedge that's pointing downwards * var wedge = new Konva.Wedge({ diff --git a/package.json b/package.json index 4bdeb22b..a9093fec 100644 --- a/package.json +++ b/package.json @@ -15,16 +15,14 @@ "browser": "./lib/index.js", "typings": "./types/index-types.d.ts", "scripts": { - "start": "npm run watch & gulp", + "start": "npm run test:watch", "lint": "gulp lint", "build": "npm run compile && gulp build", "full-build": "npm run build && npm t", - "test": "node ./test/import-test.js && npm run test:build && mocha-headless-chrome -f ./test-build/parcel-runner.html -a disable-web-security && npm run test:types", - "test:node": "env TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha -r ts-node/register test/unit-new/**/*.ts", - "test:node:watch": "env TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha -r ts-node/register test/**/*.ts", - "test:types": "tsc -p ./test/ --noEmit", - "test:build": "parcel build ./test/parcel-runner.html --dist-dir test-build --target none --public-url ./ --no-source-maps", - "test:watch": "rm -rf ./parcel-cache && parcel serve ./test/parcel-runner.html", + "test": "node ./test/import-test.js && npm run test:build && mocha-headless-chrome -f ./test-build/unit-tests.html -a disable-web-security && npm run test:types", + "test:node": "env TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha -r ts-node/register test/unit/**/*.ts", + "test:build": "parcel build ./test/unit-tests.html --dist-dir test-build --target none --public-url ./ --no-source-maps", + "test:watch": "rm -rf ./parcel-cache && parcel serve ./test/unit-tests.html ./test/manual-tests.html ./test/performance/bunnies.html", "prettier": "prettier --write \"src/**/*.js\" \"test/**/*.js\" --single-quote", "tsc": "tsc --removeComments", "rollup": "rollup -c", diff --git a/src/Node.ts b/src/Node.ts index 3f03e365..275aa36d 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -169,6 +169,7 @@ type NodeEventMap = GlobalEventHandlersEventMap & { }; export interface KonvaEventObject { + type: string; target: Shape | Stage; evt: EventType; currentTarget: Node; diff --git a/src/shapes/Circle.ts b/src/shapes/Circle.ts index 538b7b91..9491ca3b 100644 --- a/src/shapes/Circle.ts +++ b/src/shapes/Circle.ts @@ -5,7 +5,7 @@ import { getNumberValidator } from '../Validators'; import { _registerNode } from '../Global'; export interface CircleConfig extends ShapeConfig { - radius: number; + radius?: number; } /** diff --git a/test/assets/Ghostscript_Tiger.svg b/test/assets/Ghostscript_Tiger.svg deleted file mode 100644 index 671e556f..00000000 --- a/test/assets/Ghostscript_Tiger.svg +++ /dev/null @@ -1,725 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/assets/bamoon.jpg b/test/assets/bamoon.jpg deleted file mode 100644 index 210a19c07911405d377ddf8d869609f05241851f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27342 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 diff --git a/test/assets/cropped-darth.jpg b/test/assets/cropped-darth.jpg deleted file mode 100644 index 39972190456c96260b9de2bac8dc3bd652925a0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23636 zcmeHvXINBC(&!m-Mxufw$%5pJ1j!&Ek_8lmVSpjbz%b-6iVBh?Ck2t51q1{X3@9in zIfLX33P_Ik490hNzukSl``lmmZJ+5=T~%FOUEQbY>N@RF|Is+fbv19e9RTR+0(<}f z5CMb`Y5*66AmBd$!U*6W!vJ6dIsFTEgz*00!2x+h05Atwz#j@CdJNNo@VyW?fcK+r zHu!7@D00CE&xxN;C0nEojP0@m5{-0sK)SN27)l6=u$jUUwn#5`KvY;nR8~YpR!o>p zR76%nL{?ZF0B|2de(UxS=a+oPhq%9BZLkq+B7orj;3fF89}t$`{eW=)*$*7ZPZ-`T|fKmjK%vSiYkn;5I-;L_|bPL`FU>u_+I$O970Y?N=`w3f`Z}%Ed>PyEjFW|{a%IY zzY%cs0-z!Sv;jw42s?m71;M3)9F2gTBs^+@D1utzLyi-uFgD==5F9*w0zx8U5>jyR z|4M`aIJiHFCjbZ@1Q!Pn2cM9D2p^YB3?x$F;+>%u!B^6^reSxxDM~;alUc6J!AWQE z(nd@i71W_Z$Q5h2GQJ9Rm!N-Caf@3u&d65nRTf(EWT){2Y_0P4>n@MUZ|Xep*>|2K zG<8p{=TyDvncgt5^9)YRt$y1(vni!vYVQ@2lvmT-H@igz;NXDT;vMTmNPsVKtil-) zYCKQ_H+C9)(VH=}SPfnpbgYPR+Ki)uVpR<3pzh+UTm)DJ2)QL*b%IJ{owQXmmPErQ zeyQ+3Yrykcg`+`$4EMNADnJqVW_MR??D8_pL`lPAF33jGg3KiqSwV%A%%L}my{>SqL=w>_MkDWK=yF>&3hU#H|`TL zU!=TewZxE(JAd9%T&*Z)`a?s=J-PU1^M#KmhLdiH1GKZH9wn8VMbL?RW6UH~E6zim zl|r?_5e9$*G7sh464lT#pUBifKzQLfzq%t=~8uH-4K)I z9u?q0p5*87YxGt%vDWX0rOYijG8M*1#w6>`sN(&X{{^pm<9_6v<# z3l9W8JS%RjoHE%WsB||cav0e;oT9khv0ErFzRM}E$CN~`Z!6wJ=G%nf8J>`Ed3KlioWw*WrM}_x$Eyloxi0e^Q>NIo=-Tx$b9MwrOT`4zVe}))Ye}R zt9u0xKR0EZhqZ756I84t;7B}mI&hf#F!$W%^ZnMS3%T5{B;UDGL^gb-OMAiYcX1B$ zmd@08qfB^EGAXh4k^P{#WT}^XINJk4;+J=eNduG`=h837r^8;V6HX))Z@>8{V67o+OGHp*_cB&`jrfwB8?b9JV$&+hA}YwWCAU}X7JFU81DSJh zZP7>C>WP~p#asLrwe1&%)@vlJ8y1~8{KB(B`5(?<%w(TSk5-=jR7QD1qHEy^{ew}h zMzt?n8~~J&yLaY3%2q7Gn;oOd?n&Txli-703&#a%MIfhL)@5n8H8OY)-&AtOZx6+k zmz3f`EBoFz=cN2I<7=*yJm0P^yuuWEk{tmh(t2&>Z+fqGE}l=KoH+vKgC7Z%2qY2Q zm$Mq@U!1fYEs<%+3F@nziW}dLIs(+LFE5!i_HpR#PcIN8r7Gzq0Tq6 zF7-KH+@LI=pBM|UfNX|H%l18uT7e$!76cf6n)me37AmvuugX7bk>cx+ z%uwydl1Q5%KiBZKfMvtMh?T_XN?Y`^;yhGXU9rriWNt0JqpokwNrvt&Oy`wLO>AQ( z3kwqVn_)JggP#JU(bFRIwV3H z4q62YYV=&S3~M#-o0R+PJlw?=Ipq1iDPUdn@t&e)2mS{FV%)^{Z}KuejU7-J*6(2? ztaxw6OXsK`$Rg&}#M+pyzIb!@5;xtw6xS6>)1uuruMNMlbzk4}1$7+}US`!v+IJ~- z6_$%=7D9}h=AWx@f2c`aD8JVST&mA@t^G85KiPfc3jIu~A5(OR3$sgE;l~l)!6B>V z(^~{fXuWwV_lBDF8IK4=UhwSh)1KNAL3=OvrHo(NFpfDh>kpGxh*Hzis28ndWN~S!PYY6wovMa;USUi^ZdwVd{C2JR$k=hj_ z5QSww*6%!)0a5{GzxAX3Lq9!NG#rU=2kF#UP8C-);-^?p2OHF{f`Pre?yrIh3Ze45 zfI$B)=-4>B|Ds&7M|=J%sJS?+{wjdo{4H7;>SV8H;|K-Y|8BsamcefA0Rvk$Hd~~J z%?0Ebws@R0P>6rRDLel&pEAnU$QXfE=P+=_j>NB|>}<>SukZ%$&gf(OWpC#TSAMaR zc*3A)Budp9ZH?{0v67eVFT4L7G%So|2A{_Rsspq8F6JMaH3B_{f7PrZ)cHI9G75UZ z?0d7=(ZgLnhED+3!6(+o`SCm+S?*&R#c_U|Dc<-o=H$mktUu#@%*pVp%yKOC+i{ur zI0rMx@k{}I9c&``IRpUCG4IAPRud4ivjZv4U=DgHV1oR>WTvG4!iXN@&B6R9kHj%X z;5X)2<~CRc09ODw`j-iJ4om)*q@({E+OaLLq5;tFgB+Kzz94YyNqv7?gpbQOkndEi z-q^li$NShCctppTA8!)Q1rQDXepnsrQ~oK75nII71GDeez!m|}!2tkA@J9|n0Th4) zt>6m409!x+{8@t-G~fVIf4l}D^gI2D!%Fz+JO1MMli?@whpN~j!owN6T41|OV1x8P z*t-A2I|oIJfHds10k9L*8HupR!q|kJ(0`Vd(MXpc>Ym6v8oZcJHw$ccN1qF z>}vt}OFQ_-G!TtlZwQYITB?7@CbUN(JzW2SB0!?x_He|Hw~b8A5G!5p7zfHAxAs6I zHDCxB${G!`1rdOekL%C%l;k@z7K5c|x!ALTkN?;G$Mrxt|FIB*En!M1vFRpYWvM5Ig)M`|*3rixmctfj=C@m1Fq(`%8NaW2f-< z_Z7B!%wBY&Tc z{Czs|Kb(#n@4U`{`zQdw`lt}>mWmQk0v#75U;{caY`|sEc|n3M3=(iZhFn1oy8pnz z2B-jrfCL~2V7-s;z9`;zkBJbB@Ex~vG){qbK%-q{g@h39g4WnroFEkGBIIrDDkLH( zECk3Ydb?UfonUA-8yM&*$g_W~Z)9hK+sd<>O6Usfx~jk&;F`WDn4#|_BdD(vRK}KF zQGrd)Th`mf)dhyOX7hG&M!3s*%d;N~mjz)gT8N$Pm<8=5&wd;+W4oeznN0m z3JXAmB}LdI#RWygg=NHL&ar`EKw%*fQ6XU|0TE$Y2`O1&5w;(R9c&F{YbR@g?f=HCTkcf7VC~y^8{P@cZ1-L^$dgzVD3l{ z6cncB2}7VcepYw=894pdB7TvNNAqVTTj(!tSJ0t4Hjgb-2<8lP0cE>`yduZ?xyq`b zVAkOIj1hP?^K+nnALIQcREw4UgC7PS=fLFIv9VhL5fK3~VWXe1TLEEdSz+Ptth(Sd zum#V3{yS!*E!@uMzhTwYmDNJHqpcB8n3k$MJE)W(9BwNsE-o%2p(G+Ar7WhbCMqH# zEv6(Ut*RsiVkO07RMd}k0_&ttnWc(T`*<+_q7ikOH zP>h}JH(pCcxRUpY(RO_WTc8|HnD-|4!>4#)LXpBkW<| z>M6vI?S~L{o%uc#LjO2QzsLROd{P4EGi(XoBntxS6%O zY@nyErK5K2@RDijz!69sFs$YRMzFEF+bd?~Y=ob{uo^KK=L20>YpA=cuAw?M2oHce zUpDL(7z_VMpwqnB`#rwbC7^kkjqNAlzkE_bT~S~t8*&-s7qbO@K@h$T!p>f3S1cYI z4WYGh!ooP%I0!8YR1kzuVPX64@VR52@9+gIZ0mvm17|o`on38RY_V_?2;cSezy{QC zbwD`S6AtqN;cgJ-boOw8gD^IZOX~u&27`Qf*hmW}8U_WUmw3V;OolQtPyt~%@H1U9 z`#)ftKVUQ%*#db16{M@rajb`p7kZWrbb+PWG+|!OFf>}=GU(P@qijK^+r`xy;R68Q z`;4sxQ2&#Aag6?+{afN6eE$x_j_r5)H~r%=gV2BYjr(2mHxBs-j0S@-bKHBsaW*Lc zP;&N*A@Rz>kmE78NlpdC>ZEBu$h3f434k|hZ|uF z$2xj!aKv96$Uh|fFRT3_0SkVg*C0TXeF)H62?8hDXaU^i4*(twDS&%59i%{hjhha! z33$i_0H&<7-{(CDgY@J4FBwiWSj2IMABUR(6$2wSs0YgPI}0B6fe(IZK?%?T4B)ru z8~`sE{}%uK?LZl%I5H*Mn z!~kLjxel?1ARrzPf5Ri=Os=nP7lr)&LYkR_&GZ%EEhynMWBye7OZym7o0yhD6)d?tK;d|7-g{44nO_+I$I_=)(r_*M9C@O$v5 z@iz$w269t6Oj_J5{VM26PXhsh=Pa`i3*7th&qX8iS~$35OWdB66+D$68jKG6K50G z5w{Uf6Yr5wk?@enlNgaWlH4RoCMhL(Lo!VAjg*v>om7TYpA=4dgEX1+F=-3wIOz@< zH5nh73fWaM53(q-JhB&L17zRG$;r9NFOZv)qsgPl3&>xSe{QvQo>RLFYz%4)P7E;&H4Gz+c#M3E`ix$T>5Oj}mrm23K7Sf|I_z}C=|LtO zCO#$uCO@VurVmUT%q+|r%&yES%&(c3Sm;?UusE{Bvox^Gv(m6Cu)y#_U1tW$YsyBplKlb{z2>uQ*mXSvhq%{W*&` z2f2v3q`4fplDL|=wzzq?O}Rt3Yq;llPVs2*`0^C-4D*unD)PGVKH}{@OK?{Dtkc;C zXWRL3_$2ro_|o{=_;L6p`QiKz_&d(wpOZOj|bDCK;?xhuBwJ=nCd4rYBgiERJG6Q?CSRFMd~XW5*mIQ zFEsHrwKZcj`?Q#~pjri5D;K3M23%~?Cet?5PSu{!;nP9s)al~rUet}#9lpeM32~`L z575)ni_;sq%yZf8a=ku*{$>3%{TTxh1Al{NLmERX!$QMNBW0s#qakBnV-Mq3CX^;u zO$to5OjS)|O~-*Mv){m?=Y_x3d+pIuUph?h0+Y7eww(~G~SS)PTPTnro zZq8obKF)sLLD3=6VF|7RPlc~KYC2{(ZaL{Wv@d5V>4;sYOsDoDfY&7Nj?_ z!@xSRm9-tJE83+lq34Dd&z}&`6-_W>`f0N{<)6I`T!a=b? z>$gmA)!k;kedG4z9gRCh!4$!$;J%RaAsKh^?!xbW3Ka`Y2|Wz64SOFh9G)1y9|4Vc zA1M-<9C;LF7xgJxGCKVp!9B#i-WbK0{8*}3-`L4G-MH#_w)n94^#rSgcZuSO8A&8b z9!X=#I>}E{I8*MW?58@U_M|DNmEC8$A9{c5f$f9N^b6^w8O#~s8M_bR5BoDUGOHhP zKT6CZ$nwmZ$u`Mu&XLY3$Ysn8&ppUP$L{up@d@pz&9dUB`b4Tu<&-(Nu+1L#lnMS85z;#-5rz?Wnz2 z`>O7IT~)ncecrP(&(faLJ&$f6X}H~R)acu|@xt}R(o6f7ldr5^4ZXhdy1Plg>C+qS zH!W|~-@a~EYHnGw6QlC9MrBtBGql=xWnN%B*5n^fD=cA56N4!Mqo zPQ}ibU8-GgyS2JodoJ~K^cwf}_g(E9>$mNn8*m<29rPUB8@e%!KO8o4VkGf1)8|K{ zXGhD%B*&hQtB!w|Fq{~ggibC_xlip+-<~0#Nt|V!EtnIXdp55=-@ah6FumxyxVIF% zOtpOf3-6aFUoU+9uySQ(dKI;Lv=;G=;alFi`1-4j%Nw6JT{ic&!nPT<^LM0ons-fi zXZO7J3HOr^&K}eqY99_Cxqx3b{=R{A0o)6Gzk&7re$#)Igg8VH zVt|D71b_p<1@BR zwB0ukJ{eg}t&8Ah&E5g-=;`I{<9jDKYAsubxm*H zHn+Tc-`&&O*FP{gH9a#sH@~pHvAMOqvkP_~duI#}7atD~kAMK*1yq>|yfcO`LIAMS zDCrZ5TGP4_Dc|IXp)<&|p%)`A=X}|rf?7E_9wZK49Xkb8U42x+Ex}+UsbNO)02-H!#1$CwtM{(Kjr$uA66eG+-hq?dGv;V1;b7;b*TSu* zXP3~@WMdY%4ovNdpL?+{-*b44?tuETCey;?MReSVE9C?o*@^S-`0HEr_0hGA*(5>_ zqjO3E<*lsHX#KPINHPSUk=^p3Pp;>C;r778h7)yyGz*zQ#%a-RmnxQZ3F*{OB zJ7}xQ`1RI%#j%Oik4hy|novD)oT-4M>4W087Xq`tUB|G09@d5F!_-Z`<$v2j2bpKRS+Z>6OvHx8b@LRFA_ru`1m?>+qyV0ds2d026`>26cL#M*p{B^};*^f;}| zMKPv@LY9RVQnfQKlx}EKg@^dHtQlS+!)LV|w3wtZ8M(I;LuB)PPfI4XuuKlnQJc6# z?Aa9MG)=jdn2|Gy8s9g$NbsmdpMgm@_N>E5)^!iK%0WP()5s^)D{0ptFFTz!(Zg^j z+$RmZZ2Px?pr-#=axo?oZdQ;0_ zF;|%3=6=5))!>)?Vdulxo-2bfy5gAo74c;0~uTf@bKq<8kv&)x|maqSGjl7#OA};45V5(!J!3$^8SpGVLS4Z#k=+ zt27;Ool_f9Jh^A_CALzgXK&_F6yeQSu9wEzOs!Lq3_P(6^jF3`5$K@TY2jD*WQM>9 zw0H2d&4(vntS0t%l{{*1RFKNW5-B`c%Tu@T@HhH$>GepOXTY8IDx>cBQ&%mCTuuoO zgzbn)xP?Yu?Rc%CykXE|+%3D^uUTQ$^@63zuXKp(^EC5FZXaX+n-iBKryknIEl|#O zaFy(PZoZ(6$>rf`kJ~>2-gR7QyIxp*=*}OWTP(G|mO9GxAmv%~sCts`wIC_-$%Zncd@F|9s zZD6)*jsUs?=;9H;d<2*-909C7hYDZI_7z)mo@0*MyP}1H!p>ZdDf)&RV5_=;%C0<# zx5I#cQxcqtkfqPp>4GA{dY^N4YCe)sYR=oKBdO>oxnJ?xRMjTYVSbXDqeo?$a?+sd zZC%g4<2$?B>5%m;^=n2SWmQ|OV{mH9Gz+i2NgYbrr-xErlN1sOxoD_lp?XL>KNaQ! zv3GN-cOp@8qI=9X8sDi2buH}YQOwxc4eVbmxaatCGX3_Kd8!V?2L*Ey68zGUG$>{5 zT3@pPBOJAJ(NiMswHAq*p59afDV*d4b(3qrbBPa+@8Mn8?BghsZ^*T2f~@7woldVm zLyYgX-DBUyvu`os5m6dW*MklvW*rk~ZjW{*owusBi8S)@*_eJ3eM^R;09~KO1Eiix zqJQKL51Pp5j2(+}Wl3u>nV6kNzT+4wsk@4o>8(sD0CauJ)0NMumtlS%Ac~P)|3U1G~m(wMIt0-(dj_GFxtN%H=+LWh4F_54|trIpNhb7Z_PHd zX0+uM3LHF}&v6{oN#N6FavD#UvphTSDToWUW^lSt)Xg=pu`k1sea2-_hPRTOBb+Z| z$`Rgk+G#MMS2XVp_YKofjsvUNIatn4##$q@P7HLfEMRhe{Lb0=d3Z$w5l0xixI?71 z!3jQq@Fd4>hNmTTMoRWgYvqX;CGF#jaU7u>-Y*Rl5?QVCo|JvC zcxk}-OlCr^@%j-Ubg8+~PU86R`7$1}^bxb+o~u16 zd`q89Ih`s}_zHXYHY9pB#45GU)Y{uz36Dl7O;kA90F#^PF$s?Mq)qpk*=ii$2%y)y z-{h(*-^s1N7EidAxOVz2PQQp%+2nvrzie!yLd3ZR_V{#;?6%RGjkH7gw(=uDSkY>? zvF8xEuh1~idmvP>c+}BtSI=y~sFlr?@QCk2q#v(xdtqI9-NJ$LJ|?A3~Jh~HFafck@#(I2miTMr+W0iN6@8whXm2-a{RSWId z(AvG#nr%wkXDr`6S9&qmIl?6A_m39v{Td z&n1{pw+82_U_4KzxjXNAaD52CR8hrWtR_0k85e5U`Qb{Gpf}UtVb7Nv#f62A`A_zI z>z-b(n&>YZ=$PBC-+v}L%5})OpSh!=)qkGf8QLJ!`~+2Bk3^hF(U}=VPCswnw=HxXirTAtN^Y>w}*oPPA-iyN-tNf_@`^79;*V8n@ zAd~sF{vk=KCn>bgMF)(NbhWm2J(~SCm^OYO^YtKNwdl_UMODdqj-;Gm*+#~>%tS3!RK5A zHDqEk3p3NN#%JDz)@^)ubEO6=xk^FbwzFMD%v{G8|M!eof$ok+YS^eY&KzM`%1c z{2;6I2so#p>XI6ez878gcrPlXbkhx0~k89j4 z32gBkV&eVhUq>^pM`^3n%p2#qmQfw*tZVeW)6$c}G%>0=8s)DJsa~j8zj!gWu43*a zcp?~`bLZf`a+mt4i$oC-zGw@%i?yMJ4L+Z|yK>)~KZCdFE4Xk=?+m}WN~?E9_?@Lhns8i`m1n>2^%!5ipsJ$$Ne1ruYH;gN!LVnA{J@ zTs__O{=S|zdVlw*v)lLFa|zGSZ>JO{M7D%q&=N$zRT!*KQ);nrjfZkt_U>Qp!IdXk zpATc)G0Y<`=#?4ScwAKU_;P!1@3@#55eumr(W;Y#uvDr|h6gN8E23gJ0FzhW6eH{@ z=u{Xo+eP!r)&Od`VE;(#=^X!RTD33ZpaXB=!@>@6;c(@MPUfZh}N)ia&g}rRqfmA=OH*>*w36)?S5Xxcbp@; z;QjLc$1_27K^bRAjG><~=RB?T^+a2Up7JUY#w<0aND&E+g|RiY$m>zIhOksU8PIdk z{>XCA^ajA%rnnklDYf?L@Cqxfg8BZn&jBBYSkGt}ZF=^M)CY$U*YJF{;CJbOt@NM6 z^KpP>g(&Ll#xd}{k6j5(*ymcGpP3@$NqyV-j^zs_wIfY%r_=Oo$Cn|P*VB>0>{qfPhdQq$lv84_R70kET8Pa{G-g_MZX6+;+ERm?i)(p-!mnn1yUoRrB z_tz#K!Y7;puk|3b@INHH*s*EMFpM}HL_Hb=*Pq4sAPf-=$t#PxWG1KPO*HKiWkfyn z%>G;7q|63c1QWRR${z9SDwr5bajSC>O-}x1#_Q&@Kf{vcs;?!FZxyqbzae*X zb0g6Z^E5n#yAvf(@Jg+q8+QT+Lv?tK9krI?1W#>wp+#NQ%A3^9K^7~_{r-mK#Ms{1 z1QQvY)cMT0Pk1ZcG^>U?yX&Llw+>}nj{qDGOj_Iqrde@U<6v^+?8&wr^mL$o^lqa< z<55@VZ1Eyrp-88VlX^k98FBu*`^oEgaGao^sTMOLwgd0O^bal@`VgcnMo}S#LE|nI zH+p&Dr2-Q&V%-oK^?WGp{K*HgOp`PG9N9Vf#lyx=2lEYNQ=R>F)(rFS&_z>)%uMZ} z{RQ*x1o#@9e*LJWU;YF#UU>P*4s*TDp!CuwG4ieCO&!mPT=T1MC+bptjZhr1 zjFG;?)!9`qr0~l756r^|Bv_No9jS_$c3HBvc8dd2*>NQJt2g7FZC!+el4Z5I!Um_G zt1Pxv8Eyxu-i?Sj{G4{LIuUpI2!NK{3*Bh%`~DqH z32A{U7Qu?F^7%8565~H%o|9^+kaudwt7Mn;4e0b{EehPy8TK}vJ+zFZdSa&YO4veg z$G^>3zx_dIzaO+L-%;}I+DN~5`Cf9aAQ?AQLPbMcU+ZpW{#rl@XM3kMuVbW6aq+o6 zwjd$ey_g21pUEZxf*SwhRWoxnOdZLR=e(#U|b9Zh|Ri0xfPEv$f}7Uy>9ttj7E!=Z9{9snQhip$?$DQXxX&!LQh9@awHPkWcV#JlA?K++Q3 zI21;LZ#=pG)HJhix9{6>yDn3b_ebH-u}(TgjrlZd?+7}2Qcx&4MOx&3KJ z0M)P`KE-&L4@XW;K~N(@YVJy9_hnG45=RNC$jMtMtUA)uG!krg=@d%i04F3ehr1HF{ANCte^S4{8pQ)&*s3w{YOCy4@ zIxx?6GI)LIxRs|T_aFGaSx)%4So(-pjF{@zch@6zzDd)Hs+mR#ZSg)p~d5 z2&md^oVMEU>%;!xuF+U$0zJdJ&*g`fjYr+xr?*)YPd}?L_RfW$l@efP@s$ocb(?OG z<7(Kc>`toa6v1;B$TT(s(o`6|vnBD}yA&_US&KNPdc@@`sC!y9A>*EY`m~t(bTwt0 z?<}8#T}d!s7(-SfE2&RrL9m0RfE*p{tUEIAiPV{RacMNnfu1Rs{6IeB?lv; zXT6#oJa3DO`we;7uFB{Q|FA)2Ed$*Y`j((sY zl~q)xvoKX5K(ik|f9qKeoqU3M?8!C5iOmn!7gSwCZ)eGdmP2%J;Oj0U7XoTM*R)(; z#a}1Xx-UXo)(ZY7C1Hzpp9>dtdm@j3+g)C7H*=PCj3o(C{RshOuf2cmn$_l+2vD$0Neflz7A7*afHY+;dc{B9J6iPzu ziL-OvnJCi$Nq6^G2awI>oT>-+b=Ye(+X_wcmgnhbpMUlH5YGMesh;~K#_4ge!_c;( zJKKu;%?*~$>2=7kA*pGk)qddoMQ6cT3Q{QUooRt)^+&F#N9@S-R$|W4f5Z}7-SvKm*+!#{sBj@UT=!MHyZ!VK8 z`*GmdRI%_d-fd|fIt;vB@vY|k#hb9v8C9I*IQ@eMwugoT3wrlPKZ;GN`%STI4ojrC zj1Lbvam0S6s?$nqLEQI`Y4{Xm7Z&DiAXC}DAnT*(VtoDSctG;GQ1a}#Dn8n-ZrA;S zcH_@8Ydc(a1YU?8N^0q@hiyB}ZIxX+3HvWHY`*X<58Mu%A3+)06&0)-_1MGiYu9Cw zly|*73zs@k5X?@e5yeGXIF{%+K(DPiV9j?)*Ud^e0429uJ2juXN}nPeQQ z-%s7%sd;uRyQsuFJD4Qp>_BRG%aVB^yLap(>AOS-WydM2!BP6_>t?(P7`gS(6ZdKK z+g-Fdo};PdK783AUXU{N6gu5sK86z1-I>ksNJwd4nCwbWuv%D~SD8Vs9%kfV+KvFL z?Y^!d4~38eOAJ!ifdxEy>gn#4E+}L?_o&;@g26H|m_C+It9&Owf?GO%hmS=7MGwpy zvk${-Dy^u+h#hIT9Ax{&CFYoSm}`>tmk+vdQoZLFC`8RNO=5b9tKKnXehj_v{w2ca zFhdWHxCx^bM-;v%o-2p)@$prxS9Eu4Svb~7>#AvM$yI1jMY7{hc_kB#MX;TG3{XDY zjOB)MI-7Fc34p&oxU#>i&40JMrY&=*&i~^;{Y`GZx6+S=&sIN#>c~T`+^{7-bWtyJ z5^N`(F~aRqcv6aSSO_!A|1gr!TxL3Z=gkxk_>yjER2K|Z1n2qfZw2R`k(V$HE{t~B zh**`-@laC}8qzQ`Vs9uSzLc)_c&USac#IbCO{ZnC&)Nh}8$t#&c(bx{}`N?L@HhyCU&hkCi+bvhDqOH+exUrvhCAmh& z&&R}RMm_H-0mPeGatZ>!T7G@=e(~e-yOXW0uP7OEMIMlz(lt-s!Dn)My*xLJwqJ|h z$y-Auan%OOuOq%J9fX8_swOD%7{8>zWb2cdlT)0*($(8*$TRX9Ulq2_PtM6AwB+59 z7i^273$zUjv$++$BYTUBoM~p5gE4N~)jeY^@EU5qZTi~UP|aS(nRY+1f(kRs4{tP{ z78MDH$lS^fN)30krC>d8sBp3J47~#7crE@)tZnyF?*)w->Oofg=~$&3#1i9IqrsIx zFfG;02GPXTOu4q6z1%i!v1XNBKWgKDeMvW3>E>6Kt~f`na>*vYG^+T#(nrHPDUYu- z*0X>a;;)c?OcG|-bT(dif_%#{k`~FJDAGX(>>WVM4e`t+fe{_-a&dv z8Tj9Rt$FWgt*GpTVuYSG`rFj4W$YcS;hq>m5?6VBmXf+=P%n`6X{Pg`96H{0dtQ0F z(KTi23~i#^!<2_t5JuMsZ6bIHAIKfJcWt@_O%D#=yw$w9q0IV$c}?J((6rF#8z%SG zQTa@x?v++@BlMavV(D2cjmd?z3lqFko#;55?5pO7U%_t_dVx0chx?I4dEXZLN+v9? zQd3ejcLzK-t=5$7)W>;Mm(z|Vn{dYS{XicN_;Y=x$*E4nB z2{@UdWhtC>gANJ%J||!ADx+IpRLDHA*dGmF&nVkRA1LbWoF6hms`Mxdfjj8l?(=19 zt_qUQ0`7QmOnj~qh+;JtTM_;qo17?|8Y?;(hk=*1lB{}mEt+_;TR#5JWmiry^Gl`6 z)RdXSM2N|9J(|y7s4RZ`kr@VIp>>!tw)J75`gjk{Jr%y^sM!=!AAL!|_<}iAkMHud zNo%|6!fJVG5C_G>heBy8qxvUdJvO8)8r+{-p{#|FQ=Ax%j(|Z{yqGx42q`4KeAZLV zwU$>|r*U7i^-;s$bZDFwyZyYI4X=POqXpPAL%&B%$5s{ft>wseV*nXEk1DP}A=YZe zaoHn)fo~zVAotpvwJq7vu+R?u!mOGaV|@4NC}tO~{a7h0Gk?EBi{yUMy*-+Q*2yhB zH-z)Y04Ddhq6TA&d~WNV8pLK9eQLKND6R|-&W>s#Cu-}iufF|=yu{N2?dr^^EK7%Q z5~HrPYMojcBW&@n14gR(tFLaK)3f|?ZJ<9q z=Dm&N!NoVH?F^*nm38GCQR;T*wEgtQ8A?j6YeEN<-x8O7%gY$(5%lNHF*BGZNgSWU z*ehjVzLrKUDb7CVI!H-7AJtFteBnhpC#9e8nEE5lzY-Op~@n|$LB?7D2HND z!g<>}J7f`%FgT*e_zI`Ot&Ggqrm-zgXy&%Lk_KZR>$!FB^I6X}+fW!;q3H(|t0#=# zMGW}y*VWWA@af~Z!xn^hjKdt!sNK|9Cdb`v824e9E?nSlOeu{vwFBX9d2b1)*tRUd z>4V$Xc5AlROcWzp2Mv5!;F<(zYz_~yww{pd$+HgE_d7I+(!{>*%*F)N6ks?wL-=hta zbC%1p!VfCz$c;j^FYeuBhdWZ;Q`5O;pmy#vbvAhcw3t{<(&+AZ)k&($uzVgSjc^M`4#y8{B>&+WiXd? zY8ca7m3(|&4_9m-`gGO$Nvw1`rO=b~@Tp3l83Jz7QyWJBB}GKvb&Q0+i_k}ZNqa}c z5io%vb*zWFc&bl|EDfvreb()Z>@Qy~?on6#ni=gwLdxm**wNf9tQ>fZgq2rl)NwDg z3dUyR=eg*mpDw zdNIPb_w#+(zVK;9+l^+|&9_iLXIZ%fI*Q4?;`He>o`~G+vUiB94VSVwQcL$7W($;< z-e$EQe?m@Jvw3$)h3sS$qr6H;iK4w$jZ8^i%wW&i!@$tbsPsrD&OObXsFW!??b3U5 z)oL*+3=AeFvr2Zv>!6A3YMjVW@zsYPFd^B(^$Ep6x6yCI>V|RcI){hxyTymW^{IUK zP%-bxEC)~C?(`9$XLX>rN4cR`^m(*HHWpG#xW<0?Zga?G>!RHj7{H$U$OD- zHhjNv;4nZmP)u+7ux&@y?rSS1hrACn$%qMU$e0+cntS3K_*(BvK+X~H!D(ZAIZ*z~ zmxS17eBQkot@5Iy1C%vuU_5xB%kJY^z*L>$bJi8=(j#C*vHFk$L#VjIkx|pQGvxN@ z2ngR32unyzJ)6H$;_YMF+Lt4F1Ptk}_GyeyHn+9veVgna9PxdQ8IA5@X`HY^P8|Vx zfvj7Xir^ie>JNp!B42c=Nt97O_E*46&An#9!8mOnU_upGGjja5(J$oEsW4yZGtO2w zRyS@UXFK+iKwn|cO3y2N{Gf4xnFHCpiita@(a-Ffx@Pr8sAR)o&0?MqJRV?W#B|T^ zV;*l-9pb(Y(Taw=1%p(kZN)U+{_R61B~FK4U-!3W4h5{Lz+PFsO&f~#2oK3f8t6LF z_14j0eEQlo^@0^Ar+|{;)P~9J;OL?N58tW)MU8DtbTvZpiJbJIV#wM;^XlqYpdf3; zj<0srv(UWe0Oe7qvM-88QXSLl2hSToWvxFRbTklQD$BwYC^rlm5wdOyc!zD#NtCU# z^IeFEuIaqPMmXzE8~1b5ldD4=PUc6zz%C~Gx$ZTm!!oPso=AmjoF`Y0fYXQJyNV}| r0Pn7^DmV9h(LNq&86aBZunU}MS(wiOm3x7L;L(ujZbJa(XyE?<|5~Sj diff --git a/test/assets/cropped-darth.png b/test/assets/cropped-darth.png deleted file mode 100644 index 7d2cb003b3125d5f75d0b5660a8a12518d999aea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17257 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�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 z zMO<{o=MI%5AIwR@HE!MBkBo@pAA;G?qSV`bj9UE2OLkel!dx+U8tvs`OY&6GDiVI9jWj}xsWa` zCe;3Z>0(xvtolF8of+W!v#zRfVh;h=OhX0?`1~CH-GIjSEQZ(QCoU_&xL0I}mFA!2S zWFiDxB1Qpgrf=a(>$-jBMYe(Xzgu; zq^XI8+_Vy59@3l?9|bKvSW6!m|Z5hIk)+#_Kc>89K!o4rs1<~u>%P19bmW+X6mYp zE+y#Ixa7wzN0ZJT|Ni~7#cQ)>1KZodVdcgs0Fuw{KR()>)#JMR%+{CFd&q1G%hO)_BiE|I09KwQg30WHVC5iH?m??YYy;{soP6`Z@TkGO6cauex4hARyLEBk z)=2_06Bm!J0YQz@lo0ObciB3qDyf!aF2%c!$&HV@P6-)x5w#qsbgO)(e|%_(RGByE z1QP5D`9`Ahi6?eYuy<_vq*r#@;xZ;DRcyHlK~o>}g#k;Fx)>z5w%zFbZvxqPgPbRu zo){kb%83&5e9XGe9C@VxU8U`r57ke0hCAQAOTJh!fPzuldMcTMI-=E`^lr8DW%Y8& zFfI<5#>xXPoc+j`9L30C70}X4{svo6XWs5R+mkO3Nip|xyhND6PdJxAvm!u-&tH}S z^gow>M5F}*twJ+C9`9p2jA-M4jK|Ay8oly8np9@5=syWNFmq6p!~c`8FM*V%i%CM? z;`|$HhdR-;9lPvne6HXIZipN2If|*~cUw7i5_1z}MwPb%o<#zdOj!~LpXXic@7g4IRcH71JHm{Kq=X|=99-gtf zj6oX4aWlZpn;x1g=M2cAC-ucKnyT0vw+J$E*NEuHdhh%VdKcXkYnko^!rN@zrRyYbzMhUPu~P9 z9&^{vXl)aumTb9q+sz|*vMN1@{=0o48@}%f39#;CF^!2KT>K!YJo;q=rI>$2{NegK zzlJj3brU?XwlhXW`8)3e)r(>z>LCz{OY^D}pB#sIPj2tIDQ`}aV`M}@c;|tF(3o#C z)tpqNTh?3xuqDW;0W$$4S^gzz~nn<7wAWrtH0=qFcepqguPxmlwcsLs&Itt1=iYtr_%t#kd4EPBFt# zv0_z>P7;P(LEtMXnX-CalQG)xOH5Dsvkme$Ur;KS@$1foc7XBt`qLxNIW6Q#Q%LMW z{SLI^ysf)$ZUOAm!gB`&PiM~U?w?le!RT|Vb}IR~RXbid3kA{AE!Sp<|FZK$IzoG@ z3H71IBu+4@{PA7q`a0|`7Rt?3h8Df>QNtb5NJA~vQLB-8i6vt);v&XU!O)*w zH0Eud*R=Px+!B=w60cw(U*13!HA4p=jQ`e`^aCYaqIGumj+Iy8JP`pfTG7!!j9=GV9Y zOIdK~kF?Qw;}MTDyQQEl*6YfmZQ7RUKNm+OJEfVk zR+D%OX&f8J`-MOR82^}`id=i~|8@b4@EWSma?I-P0ruopa(iyGtf1nD5&FbD6AkVM--kt&VP?<{&m_bHVqLPY!7(?^t-+`U1gAncHu zzyaTJz5Cc74L9TwD%o@DW%9giP=sB?=-HZ~2xjj6M+l^2kJz)K5U`nmEH_KU;idbP zBYvk)0A>Im(@C%_qpI3`yJ2OF-*a6$7mKe$zi03-+(KO_ILNs#c-_Ih!0*`RApPC|)!-N=NiP%otZu-I~FcZ9!WYy`>ym zfpPBhcdhMC+gQWfuVI8D6elW%J!u5MWPHHARV(-roHLFyH=*g8f~Ouq%0yG!Mf|NU z15f(&TEE`T#)QB`U0F3N!{BIl_Lw|6`G-?L-eg7;Y|^IBGH$Av$@wY&=d(!z zc)bJ{n!?t9VD)0JzMA4~UMR+nkF~fv4%4vsuFp)02{Z1Q64ly8t-V_QbL5qY8!oua zi}o@{=x7EYkO7!QqfsEsD6e_4QBc;gZ=4Ivx{<$Crd)Y9bij#aSLFTiAwdw!wtY*# zg5jX9m9rz+G@{t3WFf@(dDY%BEq>s)eJy&n@2##n@_z&M3wlX4S|=PHB)UsClD?`P zz&Zg{ZfB<-Dv}0CuD(F>Q^r^B`^g$^j2GO?1orX8cY`n4%FaDH7_}-^K3%fC2%MRa z_yZQ_pRo@H-Tg)4U!H4nmJ+3s#2`&GSfvTDPnev3J=w07EkmJd(X3CC{#F;2khu3Z zp?)J*ooI`zQwE@6KJXG1FqEj#Q zbGgo(Juov2r+vMi(^Gv$f?zdi#AzjWssU&lqfNQ&R=ORJ`J*%#J}ADjZ2X~zvgbhv zb1GqFiZgg_U|A8h)56g^$ z`ylE6u!@wMvZp9=T-yj|S+2H9w4Jrrq5yq>-|o5BnDOe^60S(P;{Hny!%6|8QYQ

nRH8-B5&Zgwx&;e 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 DerjnG diff --git a/test/ifame.html b/test/ifame.html index 26cf5f15..386c0d7c 100644 --- a/test/ifame.html +++ b/test/ifame.html @@ -7,6 +7,7 @@ + diff --git a/test/lib/imagediff.js b/test/lib/imagediff.js deleted file mode 100644 index 800b8cea..00000000 --- a/test/lib/imagediff.js +++ /dev/null @@ -1,391 +0,0 @@ -// js-imagediff 1.0.3 -// (c) 2011-2012 Carl Sutherland, Humble Software -// Distributed under the MIT License -// For original source and documentation visit: -// http://www.github.com/HumbleSoftware/js-imagediff - -(function (name, definition) { - var root = this; - if (typeof module !== 'undefined') { - try { - var Canvas = require('canvas'); - } catch (e) { - throw new Error( - e.message + - '\n' + - 'Please see https://github.com/HumbleSoftware/js-imagediff#cannot-find-module-canvas\n' - ); - } - module.exports = definition(root, name, Canvas); - } else if (typeof define === 'function' && typeof define.amd === 'object') { - define(definition); - } else { - root[name] = definition(root, name); - } -})('imagediff', function (root, name, Canvas) { - var TYPE_ARRAY = /\[object Array\]/i, - TYPE_CANVAS = /\[object (Canvas|HTMLCanvasElement)\]/i, - TYPE_CONTEXT = /\[object CanvasRenderingContext2D\]/i, - TYPE_IMAGE = /\[object (Image|HTMLImageElement)\]/i, - TYPE_IMAGE_DATA = /\[object ImageData\]/i, - UNDEFINED = 'undefined', - canvas = getCanvas(), - context = canvas.getContext('2d'), - previous = root[name], - imagediff, - jasmine; - - // Creation - function getCanvas(width, height) { - var canvas = Canvas ? new Canvas() : document.createElement('canvas'); - if (width) canvas.width = width; - if (height) canvas.height = height; - return canvas; - } - function getImageData(width, height) { - canvas.width = width; - canvas.height = height; - context.clearRect(0, 0, width, height); - return context.createImageData(width, height); - } - - // Type Checking - function isImage(object) { - return isType(object, TYPE_IMAGE); - } - function isCanvas(object) { - return isType(object, TYPE_CANVAS); - } - function isContext(object) { - return isType(object, TYPE_CONTEXT); - } - function isImageData(object) { - return !!( - object && - isType(object, TYPE_IMAGE_DATA) && - typeof object.width !== UNDEFINED && - typeof object.height !== UNDEFINED && - typeof object.data !== UNDEFINED - ); - } - function isImageType(object) { - return ( - isImage(object) || - isCanvas(object) || - isContext(object) || - isImageData(object) - ); - } - function isType(object, type) { - return ( - typeof object === 'object' && - !!Object.prototype.toString.apply(object).match(type) - ); - } - - // Type Conversion - function copyImageData(imageData) { - var height = imageData.height, - width = imageData.width, - data = imageData.data, - newImageData, - newData, - i; - - canvas.width = width; - canvas.height = height; - newImageData = context.getImageData(0, 0, width, height); - newData = newImageData.data; - - for (i = imageData.data.length; i--; ) { - newData[i] = data[i]; - } - - return newImageData; - } - function toImageData(object) { - if (isImage(object)) { - return toImageDataFromImage(object); - } - if (isCanvas(object)) { - return toImageDataFromCanvas(object); - } - if (isContext(object)) { - return toImageDataFromContext(object); - } - if (isImageData(object)) { - return object; - } - } - function toImageDataFromImage(image) { - var height = image.height, - width = image.width; - canvas.width = width; - canvas.height = height; - context.clearRect(0, 0, width, height); - context.drawImage(image, 0, 0); - return context.getImageData(0, 0, width, height); - } - function toImageDataFromCanvas(canvas) { - var height = canvas.height, - width = canvas.width, - context = canvas.getContext('2d'); - return context.getImageData(0, 0, width, height); - } - function toImageDataFromContext(context) { - var canvas = context.canvas, - height = canvas.height, - width = canvas.width; - return context.getImageData(0, 0, width, height); - } - function toCanvas(object) { - var data = toImageData(object), - canvas = getCanvas(data.width, data.height), - context = canvas.getContext('2d'); - - context.putImageData(data, 0, 0); - return canvas; - } - - // ImageData Equality Operators - function equalWidth(a, b) { - return a.width === b.width; - } - function equalHeight(a, b) { - return a.height === b.height; - } - function equalDimensions(a, b) { - return equalHeight(a, b) && equalWidth(a, b); - } - function equal(a, b, tolerance) { - var aData = a.data, - bData = b.data, - length = aData.length, - i; - - tolerance = tolerance || 0; - - if (!equalDimensions(a, b)) return false; - for (i = length; i--; ) { - if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) { - console.log('Difference', Math.abs(aData[i] - bData[i])); - return false; - } - } - - return true; - } - - // Diff - function diff(a, b, options) { - return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b, options); - } - function diffEqual(a, b, options) { - var height = a.height, - width = a.width, - c = getImageData(width, height), // c = a - b - aData = a.data, - bData = b.data, - cData = c.data, - length = cData.length, - row, - column, - i, - j, - k, - v; - - for (i = 0; i < length; i += 4) { - cData[i] = Math.abs(aData[i] - bData[i]); - cData[i + 1] = Math.abs(aData[i + 1] - bData[i + 1]); - cData[i + 2] = Math.abs(aData[i + 2] - bData[i + 2]); - cData[i + 3] = Math.abs(255 - Math.abs(aData[i + 3] - bData[i + 3])); - } - - return c; - } - function diffUnequal(a, b, options) { - var height = Math.max(a.height, b.height), - width = Math.max(a.width, b.width), - c = getImageData(width, height), // c = a - b - aData = a.data, - bData = b.data, - cData = c.data, - align = options && options.align, - rowOffset, - columnOffset, - row, - column, - i, - j, - k, - v; - - for (i = cData.length - 1; i > 0; i = i - 4) { - cData[i] = 255; - } - - // Add First Image - offsets(a); - for (row = a.height; row--; ) { - for (column = a.width; column--; ) { - i = 4 * ((row + rowOffset) * width + (column + columnOffset)); - j = 4 * (row * a.width + column); - cData[i + 0] = aData[j + 0]; // r - cData[i + 1] = aData[j + 1]; // g - cData[i + 2] = aData[j + 2]; // b - // cData[i+3] = aData[j+3]; // a - } - } - - // Subtract Second Image - offsets(b); - for (row = b.height; row--; ) { - for (column = b.width; column--; ) { - i = 4 * ((row + rowOffset) * width + (column + columnOffset)); - j = 4 * (row * b.width + column); - cData[i + 0] = Math.abs(cData[i + 0] - bData[j + 0]); // r - cData[i + 1] = Math.abs(cData[i + 1] - bData[j + 1]); // g - cData[i + 2] = Math.abs(cData[i + 2] - bData[j + 2]); // b - } - } - - // Helpers - function offsets(imageData) { - if (align === 'top') { - rowOffset = 0; - columnOffset = 0; - } else { - rowOffset = Math.floor((height - imageData.height) / 2); - columnOffset = Math.floor((width - imageData.width) / 2); - } - } - - return c; - } - - // Validation - function checkType() { - var i; - for (i = 0; i < arguments.length; i++) { - if (!isImageType(arguments[i])) { - throw { - name: 'ImageTypeError', - message: 'Submitted object was not an image.', - }; - } - } - } - - // Jasmine Matchers - function get(element, content) { - element = document.createElement(element); - if (element && content) { - element.innerHTML = content; - } - return element; - } - - jasmine = { - toBeImageData: function () { - return imagediff.isImageData(this.actual); - }, - - toImageDiffEqual: function (expected, tolerance) { - if (typeof document !== UNDEFINED) { - this.message = function () { - var div = get('div'), - a = get('div', '
Actual:
'), - b = get('div', '
Expected:
'), - c = get('div', '
Diff:
'), - diff = imagediff.diff(this.actual, expected), - canvas = getCanvas(), - context; - - canvas.height = diff.height; - canvas.width = diff.width; - - div.style.overflow = 'hidden'; - a.style.float = 'left'; - b.style.float = 'left'; - c.style.float = 'left'; - - context = canvas.getContext('2d'); - context.putImageData(diff, 0, 0); - - a.appendChild(toCanvas(this.actual)); - b.appendChild(toCanvas(expected)); - c.appendChild(canvas); - - div.appendChild(a); - div.appendChild(b); - div.appendChild(c); - - return [div, 'Expected not to be equal.']; - }; - } - - return imagediff.equal(this.actual, expected, tolerance); - }, - }; - - // Image Output - function imageDataToPNG(imageData, outputFile, callback) { - var canvas = toCanvas(imageData), - base64Data, - decodedImage; - - callback = callback || Function; - - base64Data = canvas.toDataURL().replace(/^data:image\/\w+;base64,/, ''); - decodedImage = new Buffer(base64Data, 'base64'); - require('fs').writeFile(outputFile, decodedImage, callback); - } - - // Definition - imagediff = { - createCanvas: getCanvas, - createImageData: getImageData, - - isImage: isImage, - isCanvas: isCanvas, - isContext: isContext, - isImageData: isImageData, - isImageType: isImageType, - - toImageData: function (object) { - checkType(object); - if (isImageData(object)) { - return copyImageData(object); - } - return toImageData(object); - }, - - equal: function (a, b, tolerance) { - checkType(a, b); - a = toImageData(a); - b = toImageData(b); - return equal(a, b, tolerance); - }, - diff: function (a, b, options) { - checkType(a, b); - a = toImageData(a); - b = toImageData(b); - return diff(a, b, options); - }, - - jasmine: jasmine, - - // Compatibility - noConflict: function () { - root[name] = previous; - return imagediff; - }, - }; - - if (typeof module !== 'undefined') { - imagediff.imageDataToPNG = imageDataToPNG; - } - - return imagediff; -}); diff --git a/test/lib/stats.js b/test/lib/stats.js deleted file mode 100644 index 3002e162..00000000 --- a/test/lib/stats.js +++ /dev/null @@ -1,105 +0,0 @@ -// stats.js - http://github.com/mrdoob/stats.js -var Stats = function () { - var l = Date.now(), - m = l, - g = 0, - n = Infinity, - o = 0, - h = 0, - p = Infinity, - q = 0, - r = 0, - s = 0, - f = document.createElement('div'); - f.id = 'stats'; - f.addEventListener( - 'mousedown', - function (b) { - b.preventDefault(); - t(++s % 2); - }, - !1 - ); - f.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; - var a = document.createElement('div'); - a.id = 'fps'; - a.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; - f.appendChild(a); - var i = document.createElement('div'); - i.id = 'fpsText'; - i.style.cssText = - 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; - i.innerHTML = 'FPS'; - a.appendChild(i); - var c = document.createElement('div'); - c.id = 'fpsGraph'; - c.style.cssText = - 'position:relative;width:74px;height:30px;background-color:#0ff'; - for (a.appendChild(c); 74 > c.children.length; ) { - var j = document.createElement('span'); - j.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; - c.appendChild(j); - } - var d = document.createElement('div'); - d.id = 'ms'; - d.style.cssText = - 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; - f.appendChild(d); - var k = document.createElement('div'); - k.id = 'msText'; - k.style.cssText = - 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; - k.innerHTML = 'MS'; - d.appendChild(k); - var e = document.createElement('div'); - e.id = 'msGraph'; - e.style.cssText = - 'position:relative;width:74px;height:30px;background-color:#0f0'; - for (d.appendChild(e); 74 > e.children.length; ) - (j = document.createElement('span')), - (j.style.cssText = - 'width:1px;height:30px;float:left;background-color:#131'), - e.appendChild(j); - var t = function (b) { - s = b; - switch (s) { - case 0: - a.style.display = 'block'; - d.style.display = 'none'; - break; - case 1: - (a.style.display = 'none'), (d.style.display = 'block'); - } - }; - return { - REVISION: 11, - domElement: f, - setMode: t, - begin: function () { - l = Date.now(); - }, - end: function () { - var b = Date.now(); - g = b - l; - n = Math.min(n, g); - o = Math.max(o, g); - k.textContent = g + ' MS (' + n + '-' + o + ')'; - var a = Math.min(30, 30 - 30 * (g / 200)); - e.appendChild(e.firstChild).style.height = a + 'px'; - r++; - b > m + 1e3 && - ((h = Math.round((1e3 * r) / (b - m))), - (p = Math.min(p, h)), - (q = Math.max(q, h)), - (i.textContent = h + ' FPS (' + p + '-' + q + ')'), - (a = Math.min(30, 30 - 30 * (h / 100))), - (c.appendChild(c.firstChild).style.height = a + 'px'), - (m = b), - (r = 0)); - return b; - }, - update: function () { - l = this.end(); - }, - }; -}; diff --git a/test/manual-tests.html b/test/manual-tests.html new file mode 100644 index 00000000..06b519af --- /dev/null +++ b/test/manual-tests.html @@ -0,0 +1,70 @@ + + +
+ + + + + + + + + + +
+ + + + + diff --git a/test/unit-new/filters/Blur-test.ts b/test/manual/Blur-test.ts similarity index 94% rename from test/unit-new/filters/Blur-test.ts rename to test/manual/Blur-test.ts index c266ad80..46bffcba 100644 --- a/test/unit-new/filters/Blur-test.ts +++ b/test/manual/Blur-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Blur', function () { // ====================================================== @@ -88,26 +88,14 @@ describe('Blur', function () { layer.add(group); stage.add(layer); - group.cache({ - x: -150, - y: -150, - width: 300, - height: 300, - }); + group.cache(); - group.offset({ - x: 150, - y: 150, - }); + group.offset(); group.filters([Konva.Filters.Blur]); group.blurRadius(20); layer.draw(); - - //document.body.appendChild(group._getCanvasCache().hit._canvas); - - //showHit(layer); }); // ====================================================== @@ -240,7 +228,7 @@ describe('Blur', function () { var tween = new Konva.Tween({ node: darth, - duration: 2.0, + duration: 1, blurRadius: 0, easing: Konva.Easings.EaseInOut, }); diff --git a/test/unit-new/filters/Brighten-test.ts b/test/manual/Brighten-test.ts similarity index 98% rename from test/unit-new/filters/Brighten-test.ts rename to test/manual/Brighten-test.ts index 5f28249f..8ba30fb1 100644 --- a/test/unit-new/filters/Brighten-test.ts +++ b/test/manual/Brighten-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Brighten', function () { // ====================================================== diff --git a/test/unit-new/filters/Contrast-test.ts b/test/manual/Contrast-test.ts similarity index 97% rename from test/unit-new/filters/Contrast-test.ts rename to test/manual/Contrast-test.ts index 14744f85..45265482 100644 --- a/test/unit-new/filters/Contrast-test.ts +++ b/test/manual/Contrast-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Filter Contrast', function () { // ====================================================== diff --git a/test/unit-new/filters/Emboss-test.ts b/test/manual/Emboss-test.ts similarity index 97% rename from test/unit-new/filters/Emboss-test.ts rename to test/manual/Emboss-test.ts index 25d2e72c..e3cdfe9f 100644 --- a/test/unit-new/filters/Emboss-test.ts +++ b/test/manual/Emboss-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Emboss', function () { // ====================================================== diff --git a/test/unit-new/filters/Enhance-test.ts b/test/manual/Enhance-test.ts similarity index 96% rename from test/unit-new/filters/Enhance-test.ts rename to test/manual/Enhance-test.ts index 766ba764..77faf631 100644 --- a/test/unit-new/filters/Enhance-test.ts +++ b/test/manual/Enhance-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Enhance', function () { // ====================================================== diff --git a/test/unit-new/filters/Filter-test.ts b/test/manual/Filter-test.ts similarity index 88% rename from test/unit-new/filters/Filter-test.ts rename to test/manual/Filter-test.ts index 793245dd..19c44ca2 100644 --- a/test/unit-new/filters/Filter-test.ts +++ b/test/manual/Filter-test.ts @@ -1,4 +1,4 @@ -import { addStage, Konva, cloneAndCompareLayer } from '../utis'; +import { addStage, Konva, cloneAndCompareLayer } from '../unit/utis'; describe('Filter', function () { it('pixelRaio check', function () { diff --git a/test/unit-new/filters/Grayscale-test.ts b/test/manual/Grayscale-test.ts similarity index 96% rename from test/unit-new/filters/Grayscale-test.ts rename to test/manual/Grayscale-test.ts index 4b298659..8b5ec3ae 100644 --- a/test/unit-new/filters/Grayscale-test.ts +++ b/test/manual/Grayscale-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Grayscale', function () { // ====================================================== diff --git a/test/unit-new/filters/HSL-test.ts b/test/manual/HSL-test.ts similarity index 97% rename from test/unit-new/filters/HSL-test.ts rename to test/manual/HSL-test.ts index b96d71ab..f0848ab9 100644 --- a/test/unit-new/filters/HSL-test.ts +++ b/test/manual/HSL-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('HSL', function () { // ====================================================== diff --git a/test/unit-new/filters/HSV-test.ts b/test/manual/HSV-test.ts similarity index 98% rename from test/unit-new/filters/HSV-test.ts rename to test/manual/HSV-test.ts index 0375f5ca..896a27c9 100644 --- a/test/unit-new/filters/HSV-test.ts +++ b/test/manual/HSV-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('HSV', function () { // ====================================================== diff --git a/test/unit-new/filters/Invert-test.ts b/test/manual/Invert-test.ts similarity index 96% rename from test/unit-new/filters/Invert-test.ts rename to test/manual/Invert-test.ts index 5205a346..f08685dc 100644 --- a/test/unit-new/filters/Invert-test.ts +++ b/test/manual/Invert-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Invert', function () { // ====================================================== diff --git a/test/unit-new/filters/Kaleidoscope-test.ts b/test/manual/Kaleidoscope-test.ts similarity index 97% rename from test/unit-new/filters/Kaleidoscope-test.ts rename to test/manual/Kaleidoscope-test.ts index 07dbef92..e98e7a42 100644 --- a/test/unit-new/filters/Kaleidoscope-test.ts +++ b/test/manual/Kaleidoscope-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Kaleidoscope', function () { // ====================================================== diff --git a/test/manual/manual-test.js b/test/manual/Manual-test.ts similarity index 92% rename from test/manual/manual-test.js rename to test/manual/Manual-test.ts index 3b599a6d..263aaad5 100644 --- a/test/manual/manual-test.js +++ b/test/manual/Manual-test.ts @@ -1,6 +1,10 @@ -suite('Manual', function () { +import { assert } from 'chai'; + +import { addStage, Konva, loadImage } from '../unit/utis'; + +describe('Manual', function () { // ====================================================== - test('oscillation animation', function () { + it('oscillation animation', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -33,7 +37,7 @@ suite('Manual', function () { var centerX = stage.width() / 2; var anim = new Konva.Animation(function (frame) { - hexagon.setX( + hexagon.x( amplitude * Math.sin((new Date().getTime() * 2 * Math.PI) / period) + centerX ); @@ -43,7 +47,7 @@ suite('Manual', function () { }); // ====================================================== - test('rotation animation', function () { + it('rotation animation', function () { var stage = addStage(); var layer = new Konva.Layer(); var rect; @@ -76,7 +80,7 @@ suite('Manual', function () { }); // ====================================================== - test('tween node', function () { + it('tween node', function () { var stage = addStage(); var layer = new Konva.Layer(); var rect = new Konva.Rect({ @@ -108,7 +112,7 @@ suite('Manual', function () { }); // ====================================================== - test('tween spline', function () { + it('tween spline', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -147,7 +151,7 @@ suite('Manual', function () { }); // ====================================================== - test('blur and tween spline', function () { + it('blur and tween spline', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -201,7 +205,7 @@ suite('Manual', function () { tween.play(); }); - test('Make sure that all texts are inside rectangles.', function () { + it('Make sure that all texts are inside rectangles.', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -243,7 +247,7 @@ suite('Manual', function () { stage.add(layer); }); - test('change hit graph ratio', function () { + it('change hit graph ratio', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -280,19 +284,19 @@ suite('Manual', function () { }); }); - test('tween color', function () { + it('tween color', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ x: 100, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', stroke: 'blue', strokeWidth: 4, - shadowOffsetX: 10, + shadowOffx: 10, shadowOffsetY: 10, shadowColor: 'black', }); @@ -317,7 +321,7 @@ suite('Manual', function () { }); // ====================================================== - test('create image hit region with pixelRatio, look at hit, test hit with mouseover', function (done) { + it('create image hit region with pixelRatio, look at hit, test hit with mouseover', function (done) { var imageObj = new Image(); Konva.pixelRatio = 2; @@ -357,7 +361,7 @@ suite('Manual', function () { }); // ====================================================== - test('image hit region with alpha threshold, mouseover circle', function (done) { + it('image hit region with alpha threshold, mouseover circle', function (done) { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); diff --git a/test/unit-new/filters/Mask-test.ts b/test/manual/Mask-test.ts similarity index 92% rename from test/unit-new/filters/Mask-test.ts rename to test/manual/Mask-test.ts index d56679a2..03d96222 100644 --- a/test/unit-new/filters/Mask-test.ts +++ b/test/manual/Mask-test.ts @@ -1,4 +1,4 @@ -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Mask', function () { // ====================================================== diff --git a/test/unit-new/filters/Noise-test.ts b/test/manual/Noise-test.ts similarity index 93% rename from test/unit-new/filters/Noise-test.ts rename to test/manual/Noise-test.ts index 75ef0439..e09c7334 100644 --- a/test/unit-new/filters/Noise-test.ts +++ b/test/manual/Noise-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Noise', function () { // ====================================================== diff --git a/test/unit-new/filters/Pixelate-test.ts b/test/manual/Pixelate-test.ts similarity index 93% rename from test/unit-new/filters/Pixelate-test.ts rename to test/manual/Pixelate-test.ts index 65c5cc34..b68d3a71 100644 --- a/test/unit-new/filters/Pixelate-test.ts +++ b/test/manual/Pixelate-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Pixelate', function () { // ====================================================== diff --git a/test/unit-new/filters/Posterize-test.ts b/test/manual/Posterize-test.ts similarity index 93% rename from test/unit-new/filters/Posterize-test.ts rename to test/manual/Posterize-test.ts index dfe28102..057c7365 100644 --- a/test/unit-new/filters/Posterize-test.ts +++ b/test/manual/Posterize-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Posterize', function () { // ====================================================== diff --git a/test/unit-new/filters/RGB-test.ts b/test/manual/RGB-test.ts similarity index 97% rename from test/unit-new/filters/RGB-test.ts rename to test/manual/RGB-test.ts index f2d65cb4..2f2d5145 100644 --- a/test/unit-new/filters/RGB-test.ts +++ b/test/manual/RGB-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('RGB', function () { // ====================================================== diff --git a/test/unit-new/filters/RGBA-test.ts b/test/manual/RGBA-test.ts similarity index 96% rename from test/unit-new/filters/RGBA-test.ts rename to test/manual/RGBA-test.ts index 9ac90e72..71e29c9c 100644 --- a/test/unit-new/filters/RGBA-test.ts +++ b/test/manual/RGBA-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('RGBA', function () { // ====================================================== diff --git a/test/unit-new/filters/Sepia-test.ts b/test/manual/Sepia-test.ts similarity index 96% rename from test/unit-new/filters/Sepia-test.ts rename to test/manual/Sepia-test.ts index 82f3a0e0..58f5f97a 100644 --- a/test/unit-new/filters/Sepia-test.ts +++ b/test/manual/Sepia-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Filter Sepia', function () { // ====================================================== diff --git a/test/unit-new/filters/Solarize-test.ts b/test/manual/Solarize-test.ts similarity index 91% rename from test/unit-new/filters/Solarize-test.ts rename to test/manual/Solarize-test.ts index 43a4a618..4858b6d2 100644 --- a/test/unit-new/filters/Solarize-test.ts +++ b/test/manual/Solarize-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Solarize', function () { // ====================================================== diff --git a/test/unit-new/filters/Threshold-test.ts b/test/manual/Threshold-test.ts similarity index 93% rename from test/unit-new/filters/Threshold-test.ts rename to test/manual/Threshold-test.ts index b4b8b903..3f59d773 100644 --- a/test/unit-new/filters/Threshold-test.ts +++ b/test/manual/Threshold-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, loadImage } from '../utis'; +import { addStage, Konva, loadImage } from '../unit/utis'; describe('Threshold', function () { // ====================================================== diff --git a/test/memLeakTest.html b/test/memLeakTest.html deleted file mode 100644 index 26ff4f56..00000000 --- a/test/memLeakTest.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - KonvaJS Memory leak test - - - - Check memory before tests. Open console. Run "run()". See memory after. -
- - - - diff --git a/test/memory/build-destroy-star.html b/test/memory/build-destroy-star.html deleted file mode 100644 index 7bb5e4e0..00000000 --- a/test/memory/build-destroy-star.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - -
- - - - - - - \ No newline at end of file diff --git a/test/memory/build-destroy-text.html b/test/memory/build-destroy-text.html deleted file mode 100644 index ec82a9b4..00000000 --- a/test/memory/build-destroy-text.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - -
- - - - - - - \ No newline at end of file diff --git a/test/node-runner.js b/test/node-runner.js deleted file mode 100644 index 2591088c..00000000 --- a/test/node-runner.js +++ /dev/null @@ -1,123 +0,0 @@ -var fs = require('fs'), - Konva = require('../dist/konva-dev'); - -global.Konva = Konva; -Konva.enableTrace = true; - -// Config MINIMAL test environment -global.suite = function (title, func) { - console.log('Suite : ' + title); - func(); -}; - -global.test = function (title, func) { - try { - console.log('Run test: ' + title); - func(function () {}); - } catch (e) { - console.log('Error at ' + title, e); - throw e; - } -}; -test.skip = function () {}; -global.assert = function (condtion, message) { - if (!condtion) { - throw 'assert throw:' + message; - } -}; -global.assert.equal = function (left, right) { - if (left !== right) { - } -}; -global.assert.notEqual = function (left, right) { - if (left === right) { - throw 'assert throw'; - } -}; - -global.addStage = function () { - return new Konva.Stage({ - width: 578, - height: 200, - }); -}; - -// Some utils for testing -global.konvaContainer = Konva.document.createElement('div'); -Konva.document.body.appendChild(konvaContainer); -global.showHit = global.addContainer = function () {}; -global.Image = Konva._nodeCanvas.Image; -Image.prototype.style = {}; -eval(fs.readFileSync('./test/assets/tiger.js') + ''); -eval(fs.readFileSync('./test/assets/worldMap.js') + ''); -global.tiger = tiger; -global.worldMap = worldMap; - -// now load all tests -require('./unit/Global-test.js'); -require('./unit/Node-test.js'); -require('./unit/Global-test.js'); -require('./unit/Util-test.js'); -require('./unit/Canvas-test.js'); -require('./unit/Node-test.js'); -require('./unit/Container-test.js'); -require('./unit/Stage-test.js'); -require('./unit/Layer-test.js'); -require('./unit/Shape-test.js'); -require('./unit/Collection-test.js'); - -// shapes --> -require('./unit/shapes/Rect-test.js'); -require('./unit/shapes/Circle-test.js'); -require('./unit/shapes/Image-test.js'); -require('./unit/shapes/Line-test.js'); -require('./unit/shapes/Text-test.js'); -require('./unit/shapes/Blob-test.js'); -require('./unit/shapes/Ellipse-test.js'); -require('./unit/shapes/Polygon-test.js'); -require('./unit/shapes/Spline-test.js'); -require('./unit/shapes/Sprite-test.js'); -require('./unit/shapes/Wedge-test.js'); -require('./unit/shapes/Arc-test.js'); -require('./unit/shapes/Ring-test.js'); - -// // extensions --> -require('./unit/Animation-test.js'); -require('./unit/DragAndDrop-test.js'); -require('./unit/Tween-test.js'); - -// // plugins --> -require('./unit/plugins/Label-test.js'); -require('./unit/plugins/Star-test.js'); -require('./unit/plugins/RegularPolygon-test.js'); -require('./unit/plugins/Path-test.js'); -require('./unit/plugins/TextPath-test.js'); - -// // filters --> -require('./unit/filters/Blur-test.js'); -require('./unit/filters/Brighten-test.js'); -require('./unit/filters/RGB-test.js'); -require('./unit/filters/HSV-test.js'); -require('./unit/filters/HSL-test.js'); -require('./unit/filters/Invert-test.js'); -require('./unit/filters/Mask-test.js'); -require('./unit/filters/Grayscale-test.js'); -require('./unit/filters/Enhance-test.js'); -require('./unit/filters/Pixelate-test.js'); -require('./unit/filters/Noise-test.js'); -require('./unit/filters/Threshold-test.js'); -require('./unit/filters/Posterize-test.js'); -require('./unit/filters/Sepia-test.js'); -require('./unit/filters/Contrast-test.js'); -require('./unit/filters/Emboss-test.js'); -require('./unit/filters/Solarize-test.js'); -require('./unit/filters/Kaleidoscope-test.js'); - -// //=============== functional tests ================--> - -require('./functional/MouseEvents-test.js'); -require('./functional/TouchEvents-test.js'); -//require('./functional/DragAndDropEvents-test.js'); disabled because of simplest test configuration - -// //=============== manual tests ================--> -// require('./manual/manual-test.js'); disabled because of unlimited animation diff --git a/test/parcel-runner.html b/test/parcel-runner.html deleted file mode 100644 index 1fbd14d1..00000000 --- a/test/parcel-runner.html +++ /dev/null @@ -1,37 +0,0 @@ - - -
- - - - - - - - - -
- - - - - diff --git a/test/parcel-runner.ts b/test/parcel-runner.ts deleted file mode 100644 index bfa96d9c..00000000 --- a/test/parcel-runner.ts +++ /dev/null @@ -1,34 +0,0 @@ -import './unit-new/Animation-test.ts'; -import './unit-new/Canvas-test.ts'; -import './unit-new/Container-test.ts'; -import './unit-new/Context-test.ts'; -import './unit-new/DragAndDrop-test.ts'; -import './unit-new/Global-test.ts'; -import './unit-new/Group-test.ts'; -import './unit-new/Layer-test.ts'; -import './unit-new/Util-test.ts'; -import './unit-new/Stage-test.ts'; -import './unit-new/Shape-test.ts'; -import './unit-new/Node-test.ts'; -import './unit-new/Node-cache-test.ts'; - -import './unit-new/shapes/Rect-test.ts'; -import './unit-new/shapes/Circle-test.ts'; -import './unit-new/shapes/Image-test.ts'; -import './unit-new/shapes/Line-test.ts'; -import './unit-new/shapes/Text-test.ts'; -import './unit-new/shapes/Blob-test.ts'; -import './unit-new/shapes/Ellipse-test.ts'; -import './unit-new/shapes/Polygon-test.ts'; -import './unit-new/shapes/Spline-test.ts'; -import './unit-new/shapes/Sprite-test.ts'; -import './unit-new/shapes/Wedge-test.ts'; -import './unit-new/shapes/Arc-test.ts'; -import './unit-new/shapes/Ring-test.ts'; -import './unit-new/shapes/Label-test.ts'; -import './unit-new/shapes/Star-test.ts'; -import './unit-new/shapes/RegularPolygon-test.ts'; -import './unit-new/shapes/Path-test.ts'; -import './unit-new/shapes/TextPath-test.ts'; -import './unit-new/shapes/Arrow-test.ts'; -import './unit-new/shapes/Transformer-test.ts'; diff --git a/test/performance/bunnies.html b/test/performance/bunnies.html index 01294e82..0215b18f 100644 --- a/test/performance/bunnies.html +++ b/test/performance/bunnies.html @@ -10,10 +10,13 @@
- - + + + + - - - - - - \ No newline at end of file diff --git a/test/performance/rotate-cached-star.html b/test/performance/rotate-cached-star.html deleted file mode 100644 index 07ee9a75..00000000 --- a/test/performance/rotate-cached-star.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - -
- - - - - - - - \ No newline at end of file diff --git a/test/runner.html b/test/runner.html deleted file mode 100644 index eb7c8c1a..00000000 --- a/test/runner.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - KonvaJS Mocha Tests - - - - - -

KonvaJS Test

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/sandbox.html b/test/sandbox.html new file mode 100644 index 00000000..54efb808 --- /dev/null +++ b/test/sandbox.html @@ -0,0 +1,196 @@ + + + + + KonvaJS Sandbox + + + + + + + + + + + Some text +
+ + + + diff --git a/test/sandbox2.html b/test/sandbox2.html deleted file mode 100644 index 0caa9810..00000000 --- a/test/sandbox2.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - Konva Offscreen Canvas Demo - - - - - - - - diff --git a/test/setStats.js b/test/setStats.js deleted file mode 100644 index 454cba0c..00000000 --- a/test/setStats.js +++ /dev/null @@ -1,29 +0,0 @@ -window.requestAnimFrame = (function (callback) { - return ( - window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { - window.setTimeout(callback, 1000 / 30); - } - ); -})(); - -stats = new Stats(); -stats.setMode(0); -stats.domElement.style.position = 'fixed'; -stats.domElement.style.left = '0px'; -stats.domElement.style.top = '0px'; -document.body.appendChild(stats.domElement); - -function setStats() { - stats.begin(); - requestAnimFrame(function () { - stats.end(); - setStats(); - }); -} - -setStats(); diff --git a/test/test.html b/test/test.html deleted file mode 100644 index 8a9e6e6c..00000000 --- a/test/test.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - -
- - - - - diff --git a/test/tsconfig.json b/test/tsconfig.json index 819141e6..19e85afc 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "strict": true + "outDir": "lib", + "target": "ES2015", + "noEmitOnError": true, + "moduleResolution": "node", + "lib": ["ES2015", "dom"] }, - "files": ["../types/index-types.d.ts"] -} \ No newline at end of file + "include": ["../src/*.ts"] +} diff --git a/test/unit-tests.html b/test/unit-tests.html new file mode 100644 index 00000000..64bf00c0 --- /dev/null +++ b/test/unit-tests.html @@ -0,0 +1,112 @@ + + +
+ + + + + + + + + + + +
+ + + + + diff --git a/test/unit-new/Animation-test.ts b/test/unit/Animation-test.ts similarity index 100% rename from test/unit-new/Animation-test.ts rename to test/unit/Animation-test.ts diff --git a/test/unit-new/shapes/Arc-test.ts b/test/unit/Arc-test.ts similarity index 99% rename from test/unit-new/shapes/Arc-test.ts rename to test/unit/Arc-test.ts index fb7c7b2b..b1d9b100 100644 --- a/test/unit-new/shapes/Arc-test.ts +++ b/test/unit/Arc-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from '../utis'; +import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; describe('Arc', function () { // ====================================================== diff --git a/test/unit-new/shapes/Arrow-test.ts b/test/unit/Arrow-test.ts similarity index 98% rename from test/unit-new/shapes/Arrow-test.ts rename to test/unit/Arrow-test.ts index dd2a8690..8fb65a48 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Arrow', function () { // ====================================================== diff --git a/test/unit-new/shapes/Blob-test.ts b/test/unit/Blob-test.ts similarity index 96% rename from test/unit-new/shapes/Blob-test.ts rename to test/unit/Blob-test.ts index 9cf685ec..382f2191 100644 --- a/test/unit-new/shapes/Blob-test.ts +++ b/test/unit/Blob-test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; -import { Line } from '../../../src/shapes/Line'; +import { Line } from '../../src/shapes/Line'; -import { addStage, Konva, cloneAndCompareLayer } from '../utis'; +import { addStage, Konva, cloneAndCompareLayer } from './utis'; describe('Blob', function () { // ====================================================== diff --git a/test/unit-new/Canvas-test.ts b/test/unit/Canvas-test.ts similarity index 100% rename from test/unit-new/Canvas-test.ts rename to test/unit/Canvas-test.ts diff --git a/test/unit-new/shapes/Circle-test.ts b/test/unit/Circle-test.ts similarity index 99% rename from test/unit-new/shapes/Circle-test.ts rename to test/unit/Circle-test.ts index e0f6d23d..28169bad 100644 --- a/test/unit-new/shapes/Circle-test.ts +++ b/test/unit/Circle-test.ts @@ -6,7 +6,7 @@ import { createCanvas, compareLayerAndCanvas, loadImage, -} from '../utis'; +} from './utis'; describe('Circle', function () { // ====================================================== diff --git a/test/unit-new/Container-test.ts b/test/unit/Container-test.ts similarity index 100% rename from test/unit-new/Container-test.ts rename to test/unit/Container-test.ts diff --git a/test/unit-new/Context-test.ts b/test/unit/Context-test.ts similarity index 100% rename from test/unit-new/Context-test.ts rename to test/unit/Context-test.ts diff --git a/test/unit-new/DragAndDrop-test.ts b/test/unit/DragAndDrop-test.ts similarity index 100% rename from test/unit-new/DragAndDrop-test.ts rename to test/unit/DragAndDrop-test.ts diff --git a/test/functional/DragAndDropEvents-test.js b/test/unit/DragAndDropEvents-test.ts similarity index 79% rename from test/functional/DragAndDropEvents-test.js rename to test/unit/DragAndDropEvents-test.ts index c9f45ffc..c65a4aee 100644 --- a/test/functional/DragAndDropEvents-test.js +++ b/test/unit/DragAndDropEvents-test.ts @@ -1,6 +1,16 @@ -suite('DragAndDropEvents', function () { +import { assert } from 'chai'; + +import { + addStage, + Konva, + simulateMouseDown, + simulateMouseMove, + simulateMouseUp, +} from './utis'; + +describe('DragAndDropEvents', function () { // ====================================================== - test('test dragstart, dragmove, dragend', function (done) { + it('test dragstart, dragmove, dragend', function (done) { var stage = addStage(); var layer = new Konva.Layer(); @@ -17,7 +27,7 @@ suite('DragAndDropEvents', function () { var circle = new Konva.Circle({ x: 380, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, strokeWidth: 4, fill: 'red', @@ -34,7 +44,6 @@ suite('DragAndDropEvents', function () { var dragStart = false; var dragMove = false; var dragEnd = false; - var mouseup = false; var events = []; circle.on('dragstart', function () { @@ -60,7 +69,7 @@ suite('DragAndDropEvents', function () { /* * simulate drag and drop */ - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 380, y: 98, }); @@ -72,7 +81,7 @@ suite('DragAndDropEvents', function () { assert(Konva.isDragReady(), ' isDragReady()) should be true 6'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 385, y: 98, }); @@ -84,7 +93,7 @@ suite('DragAndDropEvents', function () { //assert.equal(dragMove, 'dragmove event was not triggered'); assert(!dragEnd, 'dragend event should not have been triggered 10'); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 385, y: 98, }); @@ -105,19 +114,17 @@ suite('DragAndDropEvents', function () { //console.log(greenCircle.getPosition()); //console.log(circle.getPosition()); - assert.equal(greenCircle.getX(), 40, 'green circle x should be 40'); - assert.equal(greenCircle.getY(), 40, 'green circle y should be 40'); - assert.equal(circle.getX(), 385, 'circle x should be 100'); - assert.equal(circle.getY(), 100, 'circle y should be 100'); - - showHit(layer); + assert.equal(greenCircle.x(), 40, 'green circle x should be 40'); + assert.equal(greenCircle.y(), 40, 'green circle y should be 40'); + assert.equal(circle.x(), 385, 'circle x should be 100'); + assert.equal(circle.y(), 100, 'circle y should be 100'); done(); }, 20); }); // ====================================================== - test('destroy shape while dragging', function (done) { + it('destroy shape while dragging', function (done) { var stage = addStage(); var layer = new Konva.Layer(); @@ -133,7 +140,7 @@ suite('DragAndDropEvents', function () { var circle = new Konva.Circle({ x: 380, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, strokeWidth: 4, fill: 'red', @@ -153,15 +160,10 @@ suite('DragAndDropEvents', function () { dragEnd = true; }); - circle.on('mouseup', function () { - //console.log('mouseup'); - events.push('mouseup'); - }); - assert(!Konva.isDragging(), ' isDragging() should be false'); assert(!Konva.isDragReady(), ' isDragReady()) should be false'); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 380, y: 98, }); @@ -169,7 +171,7 @@ suite('DragAndDropEvents', function () { assert(!circle.isDragging(), 'circle should not be dragging'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 100, y: 98, }); @@ -193,7 +195,7 @@ suite('DragAndDropEvents', function () { }); // ====================================================== - test('click should not occur after drag and drop', function (done) { + it('click should not occur after drag and drop', function (done) { var stage = addStage(); var layer = new Konva.Layer(); @@ -221,18 +223,18 @@ suite('DragAndDropEvents', function () { //console.log('dblclick'); }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 40, y: 40, }); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -244,7 +246,7 @@ suite('DragAndDropEvents', function () { }); // ====================================================== - test('drag and drop distance', function (done) { + it('drag and drop distance', function (done) { var stage = addStage(); var layer = new Konva.Layer(); @@ -263,23 +265,23 @@ suite('DragAndDropEvents', function () { circle.dragDistance(4); var top = stage.content.getBoundingClientRect().top; - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 40, y: 40, }); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 40, y: 42, }); assert(!circle.isDragging(), 'still not dragging'); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 40, y: 45, }); assert(circle.isDragging(), 'now circle is dragging'); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 41, y: 45, }); @@ -289,7 +291,7 @@ suite('DragAndDropEvents', function () { }); // ====================================================== - test('cancel drag and drop by setting draggable to false', function (done) { + it('cancel drag and drop by setting draggable to false', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -330,18 +332,18 @@ suite('DragAndDropEvents', function () { /* * simulate drag and drop */ - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 380, y: 100, }); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -353,7 +355,7 @@ suite('DragAndDropEvents', function () { }); // ====================================================== - test('drag and drop layer', function (done) { + it('drag and drop layer', function (done) { var stage = addStage(); var layer = new Konva.Layer({ sceneFunc: function () { @@ -370,15 +372,15 @@ suite('DragAndDropEvents', function () { }); var circle1 = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', }); var circle2 = new Konva.Circle({ x: 400, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, fill: 'green', }); @@ -393,42 +395,34 @@ suite('DragAndDropEvents', function () { /* * simulate drag and drop */ - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 399, y: 96, }); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 210, y: 109, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 210, y: 109, }); //console.log(layer.getPosition()) - assert.equal(layer.getX(), -189, 'layer x should be -189'); - assert.equal(layer.getY(), 13, 'layer y should be 13'); + assert.equal(layer.x(), -189, 'layer x should be -189'); + assert.equal(layer.y(), 13, 'layer y should be 13'); done(); }, 20); }); // ====================================================== - test('drag and drop stage', function (done) { - var container = document.createElement('div'), - stage = new Konva.Stage({ - container: container, - width: 578, - height: 200, - draggable: true, - }); - - konvaContainer.appendChild(container); + it('drag and drop stage', function (done) { + var stage = addStage({ draggable: true }); //stage.setDraggable(true); @@ -444,38 +438,36 @@ suite('DragAndDropEvents', function () { layer.add(circle); stage.add(layer); - var top = stage.content.getBoundingClientRect().top; - - assert.equal(stage.getX(), 0); - assert.equal(stage.getY(), 0); + assert.equal(stage.x(), 0); + assert.equal(stage.y(), 0); /* * simulate drag and drop */ - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 0, y: 100, }); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 300, y: 110, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 300, y: 110, }); - assert.equal(stage.getX(), 300); - assert.equal(stage.getY(), 10); + assert.equal(stage.x(), 300); + assert.equal(stage.y(), 10); done(); }, 20); }); - test('click should not start drag&drop', function () { + it('click should not start drag&drop', function () { var stage = addStage(); var layer = new Konva.Layer({ draggable: true, @@ -514,8 +506,8 @@ suite('DragAndDropEvents', function () { circle.on('click', function () { click += 1; }); - stage.simulateMouseDown({ x: 70, y: 70 }); - stage.simulateMouseUp({ x: 70, y: 70 }); + simulateMouseDown(stage, { x: 70, y: 70 }); + simulateMouseUp(stage, { x: 70, y: 70 }); assert.equal(click, 1, 'click triggered'); assert.equal(dragstart, 0, 'dragstart not triggered'); @@ -523,7 +515,7 @@ suite('DragAndDropEvents', function () { assert.equal(dragend, 0, 'dragend not triggered'); }); - test('drag&drop should not fire click', function () { + it('drag&drop should not fire click', function () { var stage = addStage(); var layer = new Konva.Layer({ draggable: true, @@ -562,9 +554,9 @@ suite('DragAndDropEvents', function () { circle.on('click', function () { click += 1; }); - stage.simulateMouseDown({ x: 70, y: 70 }); - stage.simulateMouseMove({ x: 80, y: 80 }); - stage.simulateMouseUp({ x: 80, y: 80 }); + simulateMouseDown(stage, { x: 70, y: 70 }); + simulateMouseMove(stage, { x: 80, y: 80 }); + simulateMouseUp(stage, { x: 80, y: 80 }); assert.equal(click, 0, 'click triggered'); assert.equal(dragstart, 1, 'dragstart not triggered'); @@ -572,7 +564,7 @@ suite('DragAndDropEvents', function () { assert.equal(dragend, 1, 'dragend not triggered'); }); - test('drag events should not trigger on a click even if we stop drag on dragstart', function () { + it('drag events should not trigger on a click even if we stop drag on dragstart', function () { var stage = addStage(); var layer = new Konva.Layer({ draggable: true, @@ -612,9 +604,9 @@ suite('DragAndDropEvents', function () { circle.on('click', function () { click += 1; }); - stage.simulateMouseDown({ x: 70, y: 70 }); - stage.simulateMouseMove({ x: 75, y: 75 }); - stage.simulateMouseUp({ x: 75, y: 75 }); + simulateMouseDown(stage, { x: 70, y: 70 }); + simulateMouseMove(stage, { x: 75, y: 75 }); + simulateMouseUp(stage, { x: 75, y: 75 }); assert.equal(click, 0, 'click triggered'); assert.equal(dragstart, 1, 'dragstart triggered'); diff --git a/test/unit-new/shapes/Ellipse-test.ts b/test/unit/Ellipse-test.ts similarity index 99% rename from test/unit-new/shapes/Ellipse-test.ts rename to test/unit/Ellipse-test.ts index 679e315d..2b893df3 100644 --- a/test/unit-new/shapes/Ellipse-test.ts +++ b/test/unit/Ellipse-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from '../utis'; +import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; describe('Ellipse', function () { // ====================================================== diff --git a/test/unit-new/Global-test.ts b/test/unit/Global-test.ts similarity index 100% rename from test/unit-new/Global-test.ts rename to test/unit/Global-test.ts diff --git a/test/unit-new/Group-test.ts b/test/unit/Group-test.ts similarity index 100% rename from test/unit-new/Group-test.ts rename to test/unit/Group-test.ts diff --git a/test/unit-new/shapes/Image-test.ts b/test/unit/Image-test.ts similarity index 99% rename from test/unit-new/shapes/Image-test.ts rename to test/unit/Image-test.ts index bebbb444..f4560ce2 100644 --- a/test/unit-new/shapes/Image-test.ts +++ b/test/unit/Image-test.ts @@ -8,7 +8,7 @@ import { loadImage, isNode, isBrowser, -} from '../utis'; +} from './utis'; describe('Image', function () { // ====================================================== diff --git a/test/unit-new/shapes/Label-test.ts b/test/unit/Label-test.ts similarity index 83% rename from test/unit-new/shapes/Label-test.ts rename to test/unit/Label-test.ts index d7e5cc26..d6359158 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Label', function () { // ====================================================== @@ -79,19 +79,12 @@ describe('Label', function () { layer.add(label); stage.add(layer); - var trace = layer.getContext().getTrace(); + var trace = layer.getContext().getTrace(false, true); - if (isBrowser) { - assert.equal( - trace, - 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,-63.965,120);shadowColor=rgba(0,0,0,0.2);shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;beginPath();moveTo(5,0);lineTo(153.965,0);lineTo(163.965,-20);lineTo(173.965,0);lineTo(322.93,0);arc(322.93,5,5,4.712,0,false);lineTo(327.93,55);arc(322.93,55,5,0,1.571,false);lineTo(5,60);arc(5,55,5,1.571,3.142,false);lineTo(0,5);arc(5,5,5,3.142,4.712,false);closePath();fillStyle=#bbb;fill();restore();save();transform(1,0,0,1,-63.965,120);font=normal normal 50px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=green;fillText(Hello big world,0,30);restore();restore();' - ); - } else { - assert.equal( - trace, - 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,-64.5,120);shadowColor=rgba(0,0,0,0.2);shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;beginPath();moveTo(5,0);lineTo(154.5,0);lineTo(164.5,-20);lineTo(174.5,0);lineTo(324,0);arc(324,5,5,4.712,0,false);lineTo(329,55);arc(324,55,5,0,1.571,false);lineTo(5,60);arc(5,55,5,1.571,3.142,false);lineTo(0,5);arc(5,5,5,3.142,4.712,false);closePath();fillStyle=#bbb;fill();restore();save();transform(1,0,0,1,-64.5,120);font=normal normal 50px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=green;fillText(Hello big world,0,30);restore();restore();' - ); - } + assert.equal( + trace, + 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,-64,120);shadowColor=rgba(0,0,0,0.2);shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;beginPath();moveTo(5,0);lineTo(153,0);lineTo(163,-20);lineTo(173,0);lineTo(322,0);arc(322,5,5,4,0,false);lineTo(327,55);arc(322,55,5,0,1,false);lineTo(5,60);arc(5,55,5,1,3,false);lineTo(0,5);arc(5,5,5,3,4,false);closePath();fillStyle=#bbb;fill();restore();save();transform(1,0,0,1,-64,120);font=normal normal 50px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=green;fillText(Hello big world,0,30);restore();restore();' + ); }); it('find label class', function () { @@ -125,7 +118,7 @@ describe('Label', function () { }); // caching doesn't give exactly the same result. WHY? - it.skip('cache label', function () { + it('cache label', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -260,7 +253,7 @@ describe('Label', function () { stage.add(layer); - cloneAndCompareLayer(layer, 250); + cloneAndCompareLayer(layer, 250, 100); }); it('tag should list text size changes', function () { diff --git a/test/unit-new/Layer-test.ts b/test/unit/Layer-test.ts similarity index 100% rename from test/unit-new/Layer-test.ts rename to test/unit/Layer-test.ts diff --git a/test/unit-new/shapes/Line-test.ts b/test/unit/Line-test.ts similarity index 99% rename from test/unit-new/shapes/Line-test.ts rename to test/unit/Line-test.ts index c24ba3a7..653cc054 100644 --- a/test/unit-new/shapes/Line-test.ts +++ b/test/unit/Line-test.ts @@ -6,7 +6,7 @@ import { createCanvas, compareLayerAndCanvas, compareLayers, -} from '../utis'; +} from './utis'; describe('Line', function () { // ====================================================== diff --git a/test/functional/MouseEvents-test.js b/test/unit/MouseEvents-test.ts similarity index 87% rename from test/functional/MouseEvents-test.js rename to test/unit/MouseEvents-test.ts index e5903591..1af15b19 100644 --- a/test/functional/MouseEvents-test.js +++ b/test/unit/MouseEvents-test.ts @@ -1,6 +1,18 @@ -suite('MouseEvents', function () { +import { assert } from 'chai'; + +import { + addStage, + Konva, + simulateMouseDown, + simulateMouseMove, + simulateMouseUp, + simulateTouchStart, + simulateTouchEnd, +} from './utis'; + +describe('MouseEvents', function () { // ====================================================== - test('stage content mouse events', function (done) { + it('stage content mouse events', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -16,9 +28,15 @@ suite('MouseEvents', function () { layer.add(circle); stage.add(layer); - var circleMousedown = (circleMouseup = stageContentMousedown = stageContentMouseup = stageContentMousemove = stageContentMouseout = stageContentMouseover = stageContentClick = stageContentDblClick = 0); - - var top = stage.content.getBoundingClientRect().top; + var circleMousedown = 0; + var circleMouseup = 0; + var stageContentMousedown = 0; + var stageContentMouseup = 0; + var stageContentMousemove = 0; + var stageContentMouseout = 0; + var stageContentMouseover = 0; + var stageContentClick = 0; + var stageContentDblClick = 0; circle.on('mousedown', function () { circleMousedown++; @@ -58,12 +76,12 @@ suite('MouseEvents', function () { stageContentDblClick++; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -74,11 +92,11 @@ suite('MouseEvents', function () { assert.equal(stageContentMouseup, 1); assert.equal(stageContentClick, 1); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 1, y: 1, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 1, y: 1, }); @@ -87,11 +105,11 @@ suite('MouseEvents', function () { assert.equal(stageContentMouseup, 2); // trigger double click - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 1, y: 1, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 1, y: 1, }); @@ -101,7 +119,7 @@ suite('MouseEvents', function () { //assert.equal(stageContentDblClick, 1); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 200, y: 1, }); @@ -127,16 +145,14 @@ suite('MouseEvents', function () { }); // ====================================================== - test('remove shape with onclick', function () { + it('remove shape with onclick', function () { var stage = addStage(); - var top = stage.content.getBoundingClientRect().top; - var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'green', stroke: 'black', @@ -157,12 +173,12 @@ suite('MouseEvents', function () { setTimeout(remove, 0); }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 291, y: 112, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 291, y: 112, }); @@ -170,7 +186,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test listening true/false with clicks', function () { + it('test listening true/false with clicks', function () { var stage = addStage(); var top = stage.content.getBoundingClientRect().top; @@ -178,8 +194,8 @@ suite('MouseEvents', function () { var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'green', stroke: 'black', @@ -197,23 +213,23 @@ suite('MouseEvents', function () { stage.add(layer); // ----------------------------------- - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 291, y: 112, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 291, y: 112, }); assert.equal(clickCount, 1, 'should be 1 click'); // ----------------------------------- - circle.setListening(false); - stage.simulateMouseDown({ + circle.listening(false); + simulateMouseDown(stage, { x: 291, y: 112, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 291, y: 112, }); @@ -224,12 +240,12 @@ suite('MouseEvents', function () { ); // ----------------------------------- - circle.setListening(true); - stage.simulateMouseDown({ + circle.listening(true); + simulateMouseDown(stage, { x: 291, y: 112, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 291, y: 112, }); @@ -237,7 +253,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('click mapping', function () { + it('click mapping', function () { var stage = addStage(); var layer = new Konva.Layer({ sceneFunc: function () { @@ -253,15 +269,15 @@ suite('MouseEvents', function () { }); var redCircle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', }); var greenCircle = new Konva.Circle({ x: 400, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, fill: 'green', }); @@ -283,17 +299,14 @@ suite('MouseEvents', function () { layer.add(greenCircle); stage.add(layer); - var top = stage.content.getBoundingClientRect().top; - - showHit(layer); // mousedown and mouseup on red circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 284, y: 113, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 284, y: 113, }); @@ -302,12 +315,12 @@ suite('MouseEvents', function () { assert.equal(greenClicks, 0, 'green circle should have 0 clicks'); // mousedown and mouseup on green circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 397, y: 108, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 397, y: 108, }); @@ -316,12 +329,12 @@ suite('MouseEvents', function () { assert.equal(greenClicks, 1, 'green circle should have 1 click'); // mousedown red circle and mouseup on green circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 284, y: 113, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 397, y: 108, }); @@ -331,7 +344,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('text events', function () { + it('text events', function () { var stage = addStage(); var layer = new Konva.Layer(); var text = new Konva.Text({ @@ -354,14 +367,12 @@ suite('MouseEvents', function () { layer.add(text); stage.add(layer); - showHit(layer); - - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 300, y: 120, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 300, y: 120, }); @@ -374,14 +385,14 @@ suite('MouseEvents', function () { }); // ====================================================== - test('modify fill stroke and stroke width on hover with circle', function (done) { + it('modify fill stroke and stroke width on hover with circle', function (done) { var stage = addStage(); var layer = new Konva.Layer({ throttle: 999, }); var circle = new Konva.Circle({ x: 380, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, strokeWidth: 4, fill: 'red', @@ -389,17 +400,17 @@ suite('MouseEvents', function () { }); circle.on('mouseover', function () { - this.setFill('yellow'); - this.setStroke('purple'); - this.setStrokeWidth(20); + this.fill('yellow'); + this.stroke('purple'); + this.strokeWidth(20); //console.log('mouseover') layer.draw(); }); circle.on('mouseout', function () { - this.setFill('red'); - this.setStroke('black'); - this.setStrokeWidth(4); + this.fill('red'); + this.stroke('black'); + this.strokeWidth(4); //console.log('mouseout') layer.draw(); }); @@ -409,47 +420,39 @@ suite('MouseEvents', function () { var top = stage.content.getBoundingClientRect().top; - assert.equal(circle.getFill(), 'red', 'circle fill should be red'); - assert.equal(circle.getStroke(), 'black', 'circle stroke should be black'); + assert.equal(circle.fill(), 'red', 'circle fill should be red'); + assert.equal(circle.stroke(), 'black', 'circle stroke should be black'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 377, y: 101, }); - assert.equal(circle.getFill(), 'yellow', 'circle fill should be yellow'); - assert.equal( - circle.getStroke(), - 'purple', - 'circle stroke should be purple' - ); + assert.equal(circle.fill(), 'yellow', 'circle fill should be yellow'); + assert.equal(circle.stroke(), 'purple', 'circle stroke should be purple'); setTimeout(function () { // move mouse back out of circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 157, y: 138, }); - assert.equal(circle.getFill(), 'red', 'circle fill should be red'); - assert.equal( - circle.getStroke(), - 'black', - 'circle stroke should be black' - ); + assert.equal(circle.fill(), 'red', 'circle fill should be red'); + assert.equal(circle.stroke(), 'black', 'circle stroke should be black'); done(); }, 20); }, 20); }); // ====================================================== - test('mousedown mouseup mouseover mouseout mousemove click dblclick', function (done) { + it('mousedown mouseup mouseover mouseout mousemove click dblclick', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', stroke: 'black', @@ -507,7 +510,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse to center of circle to trigger mouseover - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 290, y: 100, }); @@ -522,7 +525,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse again inside circle to trigger mousemove - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 290, y: 100, }); @@ -536,7 +539,7 @@ suite('MouseEvents', function () { assert(!mouseout, '2) mouseout should be false'); // mousedown inside circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 290, y: 100, }); @@ -550,7 +553,7 @@ suite('MouseEvents', function () { assert(!mouseout, '3) mouseout should be false'); // mouseup inside circle - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 290, y: 100, }); @@ -564,7 +567,7 @@ suite('MouseEvents', function () { assert(!mouseout, '4) mouseout should be false'); // mousedown inside circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 290, y: 100, }); @@ -578,7 +581,7 @@ suite('MouseEvents', function () { assert(!mouseout, '5) mouseout should be false'); // mouseup inside circle to trigger double click - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 290, y: 100, }); @@ -593,7 +596,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse outside of circle to trigger mouseout - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 0, y: 100, }); @@ -612,14 +615,14 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test group mousedown events', function () { + it('test group mousedown events', function () { var stage = addStage(); var layer = new Konva.Layer(); var group = new Konva.Group(); var redCircle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 80, strokeWidth: 4, fill: 'red', @@ -628,8 +631,8 @@ suite('MouseEvents', function () { }); var greenCircle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 40, strokeWidth: 4, fill: 'green', @@ -656,7 +659,7 @@ suite('MouseEvents', function () { greenCircleMousedowns++; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 285, y: 100, }); @@ -664,7 +667,7 @@ suite('MouseEvents', function () { assert.equal(groupMousedowns, 1, 'groupMousedowns should be 1'); assert.equal(greenCircleMousedowns, 1, 'greenCircleMousedowns should be 1'); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 332, y: 139, }); @@ -672,7 +675,7 @@ suite('MouseEvents', function () { assert.equal(groupMousedowns, 2, 'groupMousedowns should be 2'); assert.equal(greenCircleMousedowns, 1, 'greenCircleMousedowns should be 1'); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 285, y: 92, }); @@ -680,7 +683,7 @@ suite('MouseEvents', function () { assert.equal(groupMousedowns, 3, 'groupMousedowns should be 3'); assert.equal(greenCircleMousedowns, 2, 'greenCircleMousedowns should be 2'); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 221, y: 146, }); @@ -690,7 +693,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test mousedown events with antialiasing', function () { + it('test mousedown events with antialiasing', function () { var stage = addStage(); var layer = new Konva.Layer(); var group = new Konva.Group(); @@ -720,14 +723,14 @@ suite('MouseEvents', function () { layer.draw(); var top = stage.content.getBoundingClientRect().top; - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 135, y: 30, }); assert.equal(groupMousedowns, 1, 'groupMousedowns should be 1'); }); - test('test mousemove events with antialiasing', function () { + it('test mousemove events with antialiasing', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -764,7 +767,7 @@ suite('MouseEvents', function () { var top = stage.content.getBoundingClientRect().top; // move mouse slowly for (var i = 99; i < 129; i++) { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: i, y: 135, }); @@ -773,7 +776,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('group mouseenter events', function (done) { + it('group mouseenter events', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var group = new Konva.Group({ @@ -788,8 +791,8 @@ suite('MouseEvents', function () { var groupMouseleaves = 0; var redCircle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 80, strokeWidth: 4, fill: 'red', @@ -798,8 +801,8 @@ suite('MouseEvents', function () { }); var greenCircle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 40, strokeWidth: 4, fill: 'green', @@ -847,7 +850,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse outside of circles - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 177, y: 146, }); @@ -861,7 +864,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse inside of red circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 236, y: 145, }); @@ -877,7 +880,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse inside of green circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 284, y: 118, }); @@ -892,7 +895,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse back to red circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 345, y: 105, }); @@ -906,7 +909,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse outside of circles - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 177, y: 146, }); @@ -931,7 +934,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test mouseleave with multiple groups', function () { + it('test mouseleave with multiple groups', function () { var stage = addStage(); var layer = new Konva.Layer({ id: 'layer', @@ -1007,7 +1010,7 @@ suite('MouseEvents', function () { var top = stage.content.getBoundingClientRect().top; - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); @@ -1043,7 +1046,7 @@ suite('MouseEvents', function () { 'move1 : group2 mouseout should not trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 50, y: 50, }); @@ -1079,7 +1082,7 @@ suite('MouseEvents', function () { 'move2 : group2 mouseout should not trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); @@ -1111,7 +1114,7 @@ suite('MouseEvents', function () { assert.equal(groupMouseout, 2, 'move3 : group mouseout should trigger'); assert.equal(group2Mouseout, 1, 'move3 : group2 mouseout should trigger'); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 50, y: 50, }); @@ -1146,7 +1149,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test mouseleave with multiple groups 2', function () { + it('test mouseleave with multiple groups 2', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1235,7 +1238,7 @@ suite('MouseEvents', function () { var top = stage.content.getBoundingClientRect().top; - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); @@ -1246,7 +1249,7 @@ suite('MouseEvents', function () { 'move1 : group1 mouseenter should trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 60, y: 60, }); @@ -1266,7 +1269,7 @@ suite('MouseEvents', function () { 'move2 : group1 mouseleave should trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); @@ -1289,7 +1292,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test mouseleave and mouseenter on deep nesting', function () { + it('test mouseleave and mouseenter on deep nesting', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1348,7 +1351,7 @@ suite('MouseEvents', function () { mouseleave += 1; }); // move to big circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 20, y: 20, }); @@ -1356,7 +1359,7 @@ suite('MouseEvents', function () { assert.equal(mouseleave, 0, 'no leave on first move'); // move to small inner circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 50, y: 50, }); @@ -1364,7 +1367,7 @@ suite('MouseEvents', function () { assert.equal(mouseleave, 0, 'no leave on second move'); // move to big circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 20, y: 20, }); @@ -1372,7 +1375,7 @@ suite('MouseEvents', function () { assert.equal(mouseleave, 0, 'no leave on third move'); // move out of group - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 0, y: 0, }); @@ -1381,7 +1384,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test dblclick to a wrong target', function () { + it('test dblclick to a wrong target', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1420,21 +1423,21 @@ suite('MouseEvents', function () { rightRectDblClick++; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 50, y: 50, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 50, y: 50, }); assert.equal(leftRectSingleClick, 1, 'leftRect trigger a click'); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 150, y: 50, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 150, y: 50, }); @@ -1443,7 +1446,7 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test mouseleave + mouseenter with deep nesting', function () { + it('test mouseleave + mouseenter with deep nesting', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1547,7 +1550,7 @@ suite('MouseEvents', function () { rightRectMouseout += 1; }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 50, y: 50, }); @@ -1558,7 +1561,7 @@ suite('MouseEvents', function () { 'move1 : leftRectMouseenter mouseenter should trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 150, y: 50, }); @@ -1584,7 +1587,7 @@ suite('MouseEvents', function () { 'move2 : rightGrandParentGroup mouseenter should trigger' ); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 50, y: 50, }); @@ -1613,12 +1616,12 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test event bubbling', function () { + it('test event bubbling', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ x: 380, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, strokeWidth: 4, fill: 'red', @@ -1670,11 +1673,11 @@ suite('MouseEvents', function () { e.push('stage'); }); // click on circle - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 374, y: 114, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 374, y: 114, }); @@ -1688,12 +1691,12 @@ suite('MouseEvents', function () { }); // ====================================================== - test('test custom circle hit function', function (done) { + it('test custom circle hit function', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ x: 380, - y: stage.getHeight() / 2, + y: stage.height() / 2, radius: 70, strokeWidth: 4, fill: 'red', @@ -1728,7 +1731,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse far outside circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 113, y: 112, }); @@ -1737,7 +1740,7 @@ suite('MouseEvents', function () { assert.equal(mouseovers, 0, '1) mouseovers should be 0'); assert.equal(mouseouts, 0, '1) mouseouts should be 0'); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 286, y: 118, }); @@ -1746,7 +1749,7 @@ suite('MouseEvents', function () { assert.equal(mouseouts, 0, '2)mouseouts should be 0'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 113, y: 112, }); @@ -1754,8 +1757,6 @@ suite('MouseEvents', function () { assert.equal(mouseovers, 1, '3) mouseovers should be 1'); assert.equal(mouseouts, 1, '3) mouseouts should be 1'); - showHit(layer); - // set drawBufferFunc with setter circle.hitFunc(function (context) { @@ -1771,7 +1772,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move mouse far outside circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 113, y: 112, }); @@ -1780,7 +1781,7 @@ suite('MouseEvents', function () { assert.equal(mouseouts, 1, '4) mouseouts should be 1'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 286, y: 118, }); @@ -1789,7 +1790,7 @@ suite('MouseEvents', function () { assert.equal(mouseouts, 1, '5) mouseouts should be 1'); setTimeout(function () { - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 321, y: 112, }); @@ -1799,7 +1800,7 @@ suite('MouseEvents', function () { setTimeout(function () { // move to center of circle - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 375, y: 112, }); @@ -1817,7 +1818,7 @@ suite('MouseEvents', function () { }, 20); }); - test('change ratio for hit graph', function () { + it('change ratio for hit graph', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -1853,7 +1854,7 @@ suite('MouseEvents', function () { assert.equal(shape, circle); }); - test('double click after click should trigger event', function (done) { + it('double click after click should trigger event', function (done) { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1892,11 +1893,11 @@ suite('MouseEvents', function () { smallDblClicks += 1; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 10, y: 10, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 10, y: 10, }); @@ -1906,11 +1907,11 @@ suite('MouseEvents', function () { assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); setTimeout(function () { - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -1920,11 +1921,11 @@ suite('MouseEvents', function () { assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); setTimeout(function () { - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -1938,7 +1939,7 @@ suite('MouseEvents', function () { }); }); - test('click on stage and second click on shape should not trigger double click (check after dblclick)', function (done) { + it('click on stage and second click on shape should not trigger double click (check after dblclick)', function (done) { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -1958,19 +1959,19 @@ suite('MouseEvents', function () { var bigDblClicks = 0; // make dblclick - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -1983,11 +1984,11 @@ suite('MouseEvents', function () { bigDblClicks += 1; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 10, y: 10, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 10, y: 10, }); @@ -1995,11 +1996,11 @@ suite('MouseEvents', function () { assert.equal(bigClicks, 0); assert.equal(bigDblClicks, 0); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -2010,7 +2011,7 @@ suite('MouseEvents', function () { done(); }); - test('double click after drag should trigger event', function (done) { + it('double click after drag should trigger event', function (done) { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2050,15 +2051,15 @@ suite('MouseEvents', function () { smallDblClicks += 1; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 10, y: 10, }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 15, y: 15, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 15, y: 15, }); @@ -2068,11 +2069,11 @@ suite('MouseEvents', function () { assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); setTimeout(function () { - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -2082,11 +2083,11 @@ suite('MouseEvents', function () { assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); setTimeout(function () { - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 100, y: 100, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 100, y: 100, }); @@ -2100,7 +2101,7 @@ suite('MouseEvents', function () { }); }); - test('test mouseenter on empty stage', function () { + it('test mouseenter on empty stage', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2122,7 +2123,7 @@ suite('MouseEvents', function () { assert.equal(mouseenterCount, 1, 'mouseenterCount should be 1'); }); - test('test mouseleave on empty stage', function () { + it('test mouseleave on empty stage', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2144,7 +2145,7 @@ suite('MouseEvents', function () { assert.equal(mouseleave, 1, 'mouseleave should be 1'); }); - test('test mouseleave from the shape', function () { + it('test mouseleave from the shape', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2189,7 +2190,7 @@ suite('MouseEvents', function () { }); // move into a circle - stage.simulateMouseMove({ x: 200, y: 5 }); + simulateMouseMove(stage, { x: 200, y: 5 }); var top = stage.content.getBoundingClientRect().top; var evt = { @@ -2208,7 +2209,7 @@ suite('MouseEvents', function () { assert.equal(mouseout, 1, 'mouseout should be 1'); }); - test('should not trigger mouseenter on stage when we go to the shape from empty space', function () { + it('should not trigger mouseenter on stage when we go to the shape from empty space', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2228,12 +2229,12 @@ suite('MouseEvents', function () { mouseenter += 1; }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 100, y: 100, }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 25, y: 25, }); @@ -2241,7 +2242,7 @@ suite('MouseEvents', function () { assert.equal(mouseenter, 0, 'mouseenter should be 1'); }); - test('should not trigger mouseleave after shape destroy', function () { + it('should not trigger mouseleave after shape destroy', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2273,14 +2274,14 @@ suite('MouseEvents', function () { mouseleave += 1; }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); rect.destroy(); layer.draw(); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 20, y: 20, }); @@ -2288,7 +2289,7 @@ suite('MouseEvents', function () { assert.equal(mouseleave, 0); }); - test('should not trigger mouseenter on stage twice when we go to the shape directly', function () { + it('should not trigger mouseenter on stage twice when we go to the shape directly', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -2316,7 +2317,7 @@ suite('MouseEvents', function () { stage._mouseenter(evt); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 10, y: 10, }); @@ -2326,7 +2327,7 @@ suite('MouseEvents', function () { assert.equal(mouseenter, 1, 'mouseenter should be 1'); }); - test('should trigger mouse events if we set Konva.hitOnDragEnabled = true', function () { + it('should trigger mouse events if we set Konva.hitOnDragEnabled = true', function () { Konva.hitOnDragEnabled = true; var stage = addStage(); var layer = new Konva.Layer(); @@ -2347,20 +2348,20 @@ suite('MouseEvents', function () { mousemove += 1; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 10, y: 10, }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 20, y: 20, }); - stage.simulateMouseMove({ + simulateMouseMove(stage, { x: 30, y: 30, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 30, y: 30, }); @@ -2369,7 +2370,7 @@ suite('MouseEvents', function () { Konva.hitOnDragEnabled = false; }); - test('test scaled with CSS stage', function () { + it('test scaled with CSS stage', function () { var stage = addStage(); stage.container().style.transform = 'scale(0.5)'; @@ -2392,12 +2393,12 @@ suite('MouseEvents', function () { clicks += 1; }); - stage.simulateMouseDown({ + simulateMouseDown(stage, { x: 40, y: 40, }); - stage.simulateMouseUp({ + simulateMouseUp(stage, { x: 40, y: 40, }); @@ -2407,11 +2408,11 @@ suite('MouseEvents', function () { assert.deepEqual(stage.getPointerPosition(), { x: 80, y: 80 }); // try touch too - stage.simulateTouchStart({ + simulateTouchStart(stage, { x: 30, y: 30, }); - stage.simulateTouchEnd({ + simulateTouchEnd(stage, { x: 30, y: 30, }); diff --git a/test/unit-new/Node-cache-test.ts b/test/unit/Node-cache-test.ts similarity index 100% rename from test/unit-new/Node-cache-test.ts rename to test/unit/Node-cache-test.ts diff --git a/test/unit-new/Node-test.ts b/test/unit/Node-test.ts similarity index 99% rename from test/unit-new/Node-test.ts rename to test/unit/Node-test.ts index fd87a6c1..82a9db41 100644 --- a/test/unit-new/Node-test.ts +++ b/test/unit/Node-test.ts @@ -342,7 +342,7 @@ describe.skip('Node', function () { ); layer2.add(image); layer2.draw(); - compareLayers(layer, layer2, 50); + compareLayers(layer, layer2, 150); Konva.pixelRatio = oldRatio; done(); }); diff --git a/test/unit-new/shapes/Path-test.ts b/test/unit/Path-test.ts similarity index 98% rename from test/unit-new/shapes/Path-test.ts rename to test/unit/Path-test.ts index ca093fc2..b5f63a8c 100644 --- a/test/unit-new/shapes/Path-test.ts +++ b/test/unit/Path-test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; -import worldMap from '../../assets/worldMap'; -import tiger from '../../assets/tiger'; +import worldMap from '../assets/worldMap'; +import tiger from '../assets/tiger'; import { addStage, @@ -10,7 +10,7 @@ import { compareLayerAndCanvas, cloneAndCompareLayer, isNode, -} from '../utis'; +} from './utis'; describe('Path', function () { // ====================================================== @@ -738,7 +738,7 @@ describe('Path', function () { start, 0 ); - c = 'M ' + p1.x.toString() + ' ' + p1.y.toString(); + c = 'M ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); if ( dTheta < 0 // clockwise @@ -752,7 +752,7 @@ describe('Path', function () { t, 0 ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); } } else { // counter-clockwise @@ -765,7 +765,7 @@ describe('Path', function () { t, 0 ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); } } p1 = Konva.Path.getPointOnEllipticalArc( @@ -776,7 +776,7 @@ describe('Path', function () { end, 0 ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); var testpath = new Konva.Path({ stroke: 'black', @@ -789,7 +789,7 @@ describe('Path', function () { assert.equal( c, - 'M 50 100 63.39745962155612 75.00000000000001 99.99999999999996 56.698729810778076 149.99999999999997 50 200 56.69872981077807 236.60254037844388 75.00000000000001 250 100.00000000000003 236.60254037844382 125.00000000000004 199.9999999999999 143.30127018922195 150.00000000000003 150' + 'M 50.00 100.00 63.40 75.00 100.00 56.70 150.00 50.00 200.00 56.70 236.60 75.00 250.00 100.00 236.60 125.00 200.00 143.30 150.00 150.00' ); }); @@ -938,7 +938,7 @@ describe('Path', function () { start, psi ); - c = 'M ' + p1.x.toString() + ' ' + p1.y.toString(); + c = 'M ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); if ( dTheta < 0 // clockwise @@ -952,7 +952,7 @@ describe('Path', function () { t, psi ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); } } else { // counter-clockwise @@ -965,7 +965,7 @@ describe('Path', function () { t, psi ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); } } p1 = Konva.Path.getPointOnEllipticalArc( @@ -976,7 +976,7 @@ describe('Path', function () { end, psi ); - c += ' ' + p1.x.toString() + ' ' + p1.y.toString(); + c += ' ' + p1.x.toFixed(2) + ' ' + p1.y.toFixed(2); var testpath = new Konva.Path({ stroke: 'black', @@ -989,7 +989,7 @@ describe('Path', function () { assert.equal( c, - 'M 250 99.99999999999999 209.63024270137728 69.46654531272594 162.9710386647049 50.769536422212866 122.52468393108823 48.91882176155127 99.12874658818252 64.41029882948584 99.0521491531885 93.09303885609827 122.31541584695515 127.28152481454595 150 150' + 'M 250.00 100.00 209.63 69.47 162.97 50.77 122.52 48.92 99.13 64.41 99.05 93.09 122.32 127.28 150.00 150.00' ); }); diff --git a/test/functional/PointerEvents-test.js b/test/unit/PointerEvents-test.ts similarity index 78% rename from test/functional/PointerEvents-test.js rename to test/unit/PointerEvents-test.ts index b3e42096..60de8610 100644 --- a/test/functional/PointerEvents-test.js +++ b/test/unit/PointerEvents-test.ts @@ -1,14 +1,23 @@ -/* eslint-disable max-nested-callbacks */ -// TODO: repair it -suite.skip('PointerEvents', function () { +import { assert } from 'chai'; + +import { + addStage, + Konva, + simulatePointerDown, + simulatePointerMove, + simulatePointerUp, +} from './utis'; + +// TODO: restore it! +describe.skip('PointerEvents', function () { Konva._pointerEventsEnabled = true; // ====================================================== - test('pointerdown pointerup pointermove', function (done) { + it('pointerdown pointerup pointermove', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', stroke: 'black', @@ -38,12 +47,10 @@ suite.skip('PointerEvents', function () { layer.add(circle); stage.add(layer); - var top = stage.content.getBoundingClientRect().top; - // touchstart circle - stage._pointerdown({ - clientX: 289, - clientY: 100 + top, + simulatePointerDown(stage, { + x: 289, + y: 100, pointerId: 1, preventDefault: function () {}, }); @@ -53,7 +60,7 @@ suite.skip('PointerEvents', function () { assert(!pointerup, '1) pointerup should be false'); // pointerup circle - stage._pointerup({ + simulatePointerUp(stage, { touches: [], preventDefault: function () {}, }); @@ -63,11 +70,11 @@ suite.skip('PointerEvents', function () { assert(pointerup, '2) pointerup should be true'); // pointerdown circle - stage._pointerdown({ + simulatePointerDown(stage, { touches: [ { - clientX: 289, - clientY: 100 + top, + x: 289, + y: 100, }, ], preventDefault: function () {}, @@ -78,7 +85,7 @@ suite.skip('PointerEvents', function () { assert(pointerup, '3) pointerup should be true'); // pointerup circle to triger dbltap - stage._pointerup({ + simulatePointerUp(stage, { touches: [], preventDefault: function () {}, }); @@ -92,11 +99,11 @@ suite.skip('PointerEvents', function () { setTimeout(function () { // pointermove circle - stage._pointermove({ + simulatePointerMove(stage, { touches: [ { - clientX: 290, - clientY: 100 + top, + x: 290, + y: 100, }, ], preventDefault: function () {}, @@ -111,12 +118,12 @@ suite.skip('PointerEvents', function () { }); // ====================================================== - test('pointer capture', function (done) { + it('pointer capture', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', stroke: 'black', @@ -124,7 +131,7 @@ suite.skip('PointerEvents', function () { }); var circle2 = new Konva.Circle({ - x: stage.getWidth() / 2, + x: stage.width() / 2, y: 20, radius: 20, fill: 'red', @@ -145,16 +152,19 @@ suite.skip('PointerEvents', function () { circle.on('pointerdown', function (event) { downCount++; - this.setPointerCapture(event.pointerId); + this.setPointerCapture(event['pointerId']); }); circle.on('pointerup', function (evt) { - assert(this.hasPointerCapture(evt.pointerId), 'circle released capture'); + assert( + this.hasPointerCapture(evt['pointerId']), + 'circle released capture' + ); pointerup = true; }); circle.on('pointermove', function (evt) { - assert(this.hasPointerCapture(evt.pointerId), 'circle has capture'); + assert(this.hasPointerCapture(evt['pointerId']), 'circle has capture'); pointermove = true; }); @@ -165,9 +175,9 @@ suite.skip('PointerEvents', function () { var top = stage.content.getBoundingClientRect().top; // on circle 2 to confirm it works - stage._pointerdown({ - clientX: 289, - clientY: 10 + top, + simulatePointerDown(stage, { + x: 289, + y: 10 + top, pointerId: 0, preventDefault: function () {}, }); @@ -178,9 +188,9 @@ suite.skip('PointerEvents', function () { assert(!pointerup, '6) pointerup should be false'); // on circle with capture - stage._pointerdown({ - clientX: 289, - clientY: 100 + top, + simulatePointerDown(stage, { + x: 289, + y: 100 + top, pointerId: 1, preventDefault: function () {}, }); @@ -191,9 +201,9 @@ suite.skip('PointerEvents', function () { assert(!pointerup, '7) pointerup should be true'); // second pointerdown - stage._pointerdown({ - clientX: 289, - clientY: 10 + top, + simulatePointerDown(stage, { + x: 289, + y: 10 + top, pointerId: 1, preventDefault: function () {}, }); @@ -205,9 +215,9 @@ suite.skip('PointerEvents', function () { setTimeout(function () { // pointermove over circle 2 - stage._pointermove({ - clientX: 290, - clientY: 10 + top, + simulatePointerMove(stage, { + x: 290, + y: 10 + top, pointerId: 1, preventDefault: function () {}, }); @@ -215,14 +225,14 @@ suite.skip('PointerEvents', function () { assert(otherDownCount === 1, '9) otherDownCount should be 1'); assert(pointermove, '9) pointermove should be true'); - stage._pointerup({ + simulatePointerUp(stage, { pointerId: 1, preventDefault: function () {}, }); - stage._pointerdown({ - clientX: 289, - clientY: 10 + top, + simulatePointerDown(stage, { + x: 289, + y: 10 + top, pointerId: 1, preventDefault: function () {}, }); diff --git a/test/unit-new/shapes/Polygon-test.ts b/test/unit/Polygon-test.ts similarity index 91% rename from test/unit-new/shapes/Polygon-test.ts rename to test/unit/Polygon-test.ts index 0c76340a..72378aa8 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Polygon', function () { it('add polygon', function () { diff --git a/test/unit-new/shapes/Rect-test.ts b/test/unit/Rect-test.ts similarity index 99% rename from test/unit-new/shapes/Rect-test.ts rename to test/unit/Rect-test.ts index 58da17a3..47b42597 100644 --- a/test/unit-new/shapes/Rect-test.ts +++ b/test/unit/Rect-test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { addStage, Konva, createCanvas, compareLayerAndCanvas } from '../utis'; +import { addStage, Konva, createCanvas, compareLayerAndCanvas } from './utis'; describe('Rect', function () { // ====================================================== diff --git a/test/unit-new/shapes/RegularPolygon-test.ts b/test/unit/RegularPolygon-test.ts similarity index 95% rename from test/unit-new/shapes/RegularPolygon-test.ts rename to test/unit/RegularPolygon-test.ts index ebf1a661..51052535 100644 --- a/test/unit-new/shapes/RegularPolygon-test.ts +++ b/test/unit/RegularPolygon-test.ts @@ -1,6 +1,11 @@ import { assert } from 'chai'; -import { addStage, Konva, cloneAndCompareLayer } from '../utis'; +import { + addStage, + Konva, + cloneAndCompareLayer, + assertAlmostEqual, +} from './utis'; describe('RegularPolygon', function () { // ====================================================== @@ -198,7 +203,7 @@ describe('RegularPolygon', function () { var box = poly.getClientRect(); - assert.equal(box.width, 92.60254037844388); - assert.equal(box.height, 81.00000000000003); + assertAlmostEqual(box.width, 92.60254037844388); + assertAlmostEqual(box.height, 81.00000000000003); }); }); diff --git a/test/unit-new/shapes/Ring-test.ts b/test/unit/Ring-test.ts similarity index 97% rename from test/unit-new/shapes/Ring-test.ts rename to test/unit/Ring-test.ts index 5cf35353..fe78d6cb 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Ring', function () { // ====================================================== diff --git a/test/unit-new/Shape-test.ts b/test/unit/Shape-test.ts similarity index 99% rename from test/unit-new/Shape-test.ts rename to test/unit/Shape-test.ts index 81364131..741759c9 100644 --- a/test/unit-new/Shape-test.ts +++ b/test/unit/Shape-test.ts @@ -1131,7 +1131,7 @@ describe('Shape', function () { ); }); - it.skip('hitStrokeWidth', function () { + it('hitStrokeWidth', function () { var stage = addStage(); var layer = new Konva.Layer(); diff --git a/test/unit-new/shapes/Spline-test.ts b/test/unit/Spline-test.ts similarity index 98% rename from test/unit-new/shapes/Spline-test.ts rename to test/unit/Spline-test.ts index 64eb3369..fc7252a9 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Spline', function () { // ====================================================== diff --git a/test/unit-new/shapes/Sprite-test.ts b/test/unit/Sprite-test.ts similarity index 99% rename from test/unit-new/shapes/Sprite-test.ts rename to test/unit/Sprite-test.ts index 8a3a4df0..6596c342 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Sprite', function () { // ====================================================== diff --git a/test/unit-new/Stage-test.ts b/test/unit/Stage-test.ts similarity index 100% rename from test/unit-new/Stage-test.ts rename to test/unit/Stage-test.ts diff --git a/test/unit-new/shapes/Star-test.ts b/test/unit/Star-test.ts similarity index 97% rename from test/unit-new/shapes/Star-test.ts rename to test/unit/Star-test.ts index 06f804ff..dd199739 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Star', function () { // ====================================================== diff --git a/test/unit-new/shapes/Text-test.ts b/test/unit/Text-test.ts similarity index 89% rename from test/unit-new/shapes/Text-test.ts rename to test/unit/Text-test.ts index 6e15104e..55db039a 100644 --- a/test/unit-new/shapes/Text-test.ts +++ b/test/unit/Text-test.ts @@ -9,7 +9,8 @@ import { loadImage, isBrowser, isNode, -} from '../utis'; + assertAlmostEqual, +} from './utis'; describe('Text', function () { // ====================================================== @@ -150,7 +151,7 @@ describe('Text', function () { context.fillStyle = 'black'; context.fillText('Hello World!', 10, 10 + 25); - compareLayerAndCanvas(layer, canvas, 254); + compareLayerAndCanvas(layer, canvas, 254, 200); }); it('check emoji with letterSpacing', function () { @@ -207,10 +208,10 @@ describe('Text', function () { var layer2 = new Konva.Layer(); layer2.getCanvas().setPixelRatio(1); - layer2.add(text1.clone().cache({ pixelRatio: 4 })); + layer2.add(text1.clone().cache({ pixelRatio: 3 })); stage.add(layer1, layer2); - compareLayers(layer1, layer2, 220); + compareLayers(layer1, layer2, 250, 100); }); it('text cache with fill and shadow and some scale', function () { @@ -675,13 +676,13 @@ describe('Text', function () { if (isBrowser) { assert.equal( - layer.getContext().getTrace(), - "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);shadowColor=rgba(255,0,0,0.5);shadowBlur=1;shadowOffsetX=10;shadowOffsetY=10;font=normal normal 16px Calibri;textBaseline=middle;textAlign=left;translate(20,20);save();fillStyle=#555;fillText(HEADING,133.563,8);restore();save();fillStyle=#555;fillText(,170,24);restore();save();fillStyle=#555;fillText(All the world's a stage, and all the men and women,6.602,40);restore();save();fillStyle=#555;fillText(merely players. They have their exits and their,21.168,56);restore();save();fillStyle=#555;fillText(entrances; And one man in his time plays many,18.035,72);restore();save();fillStyle=#555;fillText(parts.,152.449,88);restore();restore();" + layer.getContext().getTrace(false, true), + "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);shadowColor=rgba(255,0,0,0.5);shadowBlur=1;shadowOffsetX=10;shadowOffsetY=10;font=normal normal 16px Calibri;textBaseline=middle;textAlign=left;translate(20,20);save();fillStyle=#555;fillText(HEADING,133,8);restore();save();fillStyle=#555;fillText(,170,24);restore();save();fillStyle=#555;fillText(All the world's a stage, and all the men and women,6,40);restore();save();fillStyle=#555;fillText(merely players. They have their exits and their,21,56);restore();save();fillStyle=#555;fillText(entrances; And one man in his time plays many,18,72);restore();save();fillStyle=#555;fillText(parts.,152,88);restore();restore();" ); } else { assert.equal( - layer.getContext().getTrace(), - "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);shadowColor=rgba(255,0,0,0.5);shadowBlur=1;shadowOffsetX=10;shadowOffsetY=10;font=normal normal 16px Calibri;textBaseline=middle;textAlign=left;translate(20,20);save();fillStyle=#555;fillText(HEADING,133,8);restore();save();fillStyle=#555;fillText(,170,24);restore();save();fillStyle=#555;fillText(All the world's a stage, and all the men and,18.5,40);restore();save();fillStyle=#555;fillText(women merely players. They have their exits,12.5,56);restore();save();fillStyle=#555;fillText(and their entrances; And one man in his time,13,72);restore();save();fillStyle=#555;fillText(plays many parts.,108,88);restore();restore();" + layer.getContext().getTrace(false, true), + "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);shadowColor=rgba(255,0,0,0.5);shadowBlur=1;shadowOffsetX=10;shadowOffsetY=10;font=normal normal 16px Calibri;textBaseline=middle;textAlign=left;translate(20,20);save();fillStyle=#555;fillText(HEADING,133,8);restore();save();fillStyle=#555;fillText(,170,24);restore();save();fillStyle=#555;fillText(All the world's a stage, and all the men and,18,40);restore();save();fillStyle=#555;fillText(women merely players. They have their exits,12,56);restore();save();fillStyle=#555;fillText(and their entrances; And one man in his time,13,72);restore();save();fillStyle=#555;fillText(plays many parts.,108,88);restore();restore();" ); } }); @@ -705,17 +706,10 @@ describe('Text', function () { layer.add(text); stage.add(layer); - if (isBrowser) { - var trace = - 'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 80px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();save();beginPath();moveTo(0,80);lineTo(189,80);stroke();restore();fillStyle=red;fillText(h,0,40);fillStyle=red;fillText(e,49.492,40);fillStyle=red;fillText(l,98.984,40);fillStyle=red;fillText(l,121.758,40);fillStyle=red;fillText(o,144.531,40);restore();save();save();beginPath();moveTo(0,160);lineTo(211,160);stroke();restore();fillStyle=red;fillText(w,0,120);fillStyle=red;fillText(o,62.773,120);fillStyle=red;fillText(r,112.266,120);fillStyle=red;fillText(l,143.906,120);fillStyle=red;fillText(d,166.68,120);restore();restore();'; - - assert.equal(layer.getContext().getTrace(), trace); - } else { - var trace = - 'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 80px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();save();beginPath();moveTo(0,80);lineTo(188,80);stroke();restore();fillStyle=red;fillText(h,0,40);fillStyle=red;fillText(e,49,40);fillStyle=red;fillText(l,98,40);fillStyle=red;fillText(l,121,40);fillStyle=red;fillText(o,144,40);restore();save();save();beginPath();moveTo(0,160);lineTo(211,160);stroke();restore();fillStyle=red;fillText(w,0,120);fillStyle=red;fillText(o,63,120);fillStyle=red;fillText(r,112,120);fillStyle=red;fillText(l,144,120);fillStyle=red;fillText(d,167,120);restore();restore();'; - - assert.equal(layer.getContext().getTrace(), trace); - } + assert.equal( + layer.getContext().getTrace(true), + 'clearRect();save();transform();font;textBaseline;textAlign;translate();save();save();beginPath();moveTo();lineTo();stroke();restore();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();restore();save();save();beginPath();moveTo();lineTo();stroke();restore();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();fillStyle;fillText();restore();restore();' + ); }); // ====================================================== @@ -882,17 +876,10 @@ describe('Text', function () { layer.add(text); stage.add(layer); - if (isBrowser) { - var trace = - 'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);beginPath();rect(0,0,200,100);closePath();lineWidth=2;strokeStyle=black;stroke();restore();save();transform(1,0,0,1,10,10);font=normal normal 16px Arial;textBaseline=middle;textAlign=left;translate(10,42);save();fillStyle=#555;fillText(Some awesome text,17.523,8);restore();restore();'; - - assert.equal(layer.getContext().getTrace(), trace); - } else { - var trace = - 'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);beginPath();rect(0,0,200,100);closePath();lineWidth=2;strokeStyle=black;stroke();restore();save();transform(1,0,0,1,10,10);font=normal normal 16px Arial;textBaseline=middle;textAlign=left;translate(10,42);save();fillStyle=#555;fillText(Some awesome text,18,8);restore();restore();'; - - assert.equal(layer.getContext().getTrace(), trace); - } + assert.equal( + layer.getContext().getTrace(false, true), + 'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);beginPath();rect(0,0,200,100);closePath();lineWidth=2;strokeStyle=black;stroke();restore();save();transform(1,0,0,1,10,10);font=normal normal 16px Arial;textBaseline=middle;textAlign=left;translate(10,42);save();fillStyle=#555;fillText(Some awesome text,17,8);restore();restore();' + ); }); it('get text width', function () { @@ -977,17 +964,10 @@ describe('Text', function () { layer.draw(); - if (isBrowser) { - assert.almostEqual(Math.round(text1.width()), 1725); - assert.almostEqual(Math.round(text2.width()), 2613); - assert.almostEqual(Math.round(text3.width()), 2005); - assert.almostEqual(Math.round(text4.width()), 1932); - } else { - assert.almostEqual(Math.round(text1.width()), 1745); - assert.almostEqual(Math.round(text2.width()), 2633); - assert.almostEqual(Math.round(text3.width()), 1995); - assert.almostEqual(Math.round(text4.width()), 1981); - } + assert.equal(Math.abs(Math.round(text1.width()) - 1725) < 4, true); + assert.equal(Math.abs(Math.round(text2.width()) - 2613) < 4, true); + assert.equal(Math.abs(Math.round(text3.width()) - 2005) < 4, true); + assert.equal(Math.abs(Math.round(text4.width()) - 1932) < 4, true); }); it('default text color should be black', function () { @@ -1270,34 +1250,6 @@ describe('Text', function () { layer.draw(); }); - it.skip('we should be able to clip underline by group', function () { - var stage = addStage(); - var layer = new Konva.Layer(); - stage.add(layer); - - var group = new Konva.Group({ - clipX: 10, - clipY: 10, - clipWidth: 100, - clipHeight: 27, - }); - layer.add(group); - - var text = new Konva.Text({ - x: 10, - y: 10, - width: 100, - text: 'Hello World', - textDecoration: 'underline', - fontSize: 40, - }); - group.add(text); - - layer.draw(); - - throw 1; - }); - it('image gradient for text', function (done) { const oldRatio = Konva.pixelRatio; Konva.pixelRatio = 1; diff --git a/test/unit-new/shapes/TextPath-test.ts b/test/unit/TextPath-test.ts similarity index 99% rename from test/unit-new/shapes/TextPath-test.ts rename to test/unit/TextPath-test.ts index 930053a0..3eaa8cf1 100644 --- a/test/unit-new/shapes/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 './utis'; describe('TextPath', function () { // ====================================================== @@ -52,7 +52,7 @@ describe('TextPath', function () { }); // ====================================================== - it.skip('Find Next Segment when Arc is in Path', function () { + it('Find Next Segment when Arc is in Path', function () { var stage = addStage(); var layer = new Konva.Layer(); @@ -82,9 +82,7 @@ describe('TextPath', function () { stage.add(layer); var trace = layer.getContext().getTrace(); - console.log(trace); assert.equal(trace.indexOf('NaN') === -1, true, 'No NaNs'); - throw ''; }); // ====================================================== @@ -308,7 +306,7 @@ describe('TextPath', function () { layer.add(textpath); stage.add(layer); - cloneAndCompareLayer(layer, 200); + cloneAndCompareLayer(layer, 200, 30); }); it('Text path with align', function () { diff --git a/test/functional/TouchEvents-test.js b/test/unit/TouchEvents-test.ts similarity index 80% rename from test/functional/TouchEvents-test.js rename to test/unit/TouchEvents-test.ts index f78b7693..760be522 100644 --- a/test/functional/TouchEvents-test.js +++ b/test/unit/TouchEvents-test.ts @@ -1,6 +1,16 @@ -suite('TouchEvents', function () { +import { assert } from 'chai'; + +import { + addStage, + Konva, + simulateTouchStart, + simulateTouchEnd, + simulateTouchMove, +} from './utis'; + +describe('TouchEvents', function () { // ====================================================== - test('stage content touch events', function () { + it('stage content touch events', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -16,9 +26,13 @@ suite('TouchEvents', function () { layer.add(circle); stage.add(layer); - var circleTouchstart = (circleTouchend = stageContentTouchstart = stageContentTouchend = stageContentTouchmove = stageContentTap = stageContentDbltap = 0); - - var top = stage.content.getBoundingClientRect().top; + var circleTouchstart = 0; + var circleTouchend = 0; + var stageContentTouchstart = 0; + var stageContentTouchend = 0; + var stageContentTouchmove = 0; + var stageContentTap = 0; + var stageContentDbltap = 0; circle.on('touchstart', function () { circleTouchstart++; @@ -48,31 +62,31 @@ suite('TouchEvents', function () { stageContentDbltap++; }); - stage.simulateTouchStart([{ x: 100, y: 100, id: 0 }]); + simulateTouchStart(stage, [{ x: 100, y: 100, id: 0 }]); - stage.simulateTouchEnd([], [{ x: 100, y: 100, id: 0 }]); - assert.equal(circleTouchstart, 1, 1); - assert.equal(circleTouchend, 1, 2); - assert.equal(stageContentTouchstart, 1, 3); - assert.equal(stageContentTouchend, 1, 4); - assert.equal(stageContentDbltap, 0, 5); + simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); + assert.equal(circleTouchstart, 1, '1'); + assert.equal(circleTouchend, 1, '2'); + assert.equal(stageContentTouchstart, 1, '3'); + assert.equal(stageContentTouchend, 1, '4'); + assert.equal(stageContentDbltap, 0, '5'); - stage.simulateTouchStart([{ x: 1, y: 1, id: 0 }]); + simulateTouchStart(stage, [{ x: 1, y: 1, id: 0 }]); - stage.simulateTouchEnd([], [{ x: 1, y: 1, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 1, y: 1, id: 0 }]); - assert.equal(stageContentTouchstart, 2, 6); - assert.equal(stageContentTouchend, 2, 7); - assert.equal(stageContentDbltap, 1, 8); + assert.equal(stageContentTouchstart, 2, '6'); + assert.equal(stageContentTouchend, 2, '7'); + assert.equal(stageContentDbltap, 1, '8'); }); // ====================================================== - test('touchstart touchend touchmove tap dbltap', function (done) { + it('touchstart touchend touchmove tap dbltap', function (done) { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ - x: stage.getWidth() / 2, - y: stage.getHeight() / 2, + x: stage.width() / 2, + y: stage.height() / 2, radius: 70, fill: 'red', stroke: 'black', @@ -125,7 +139,7 @@ suite('TouchEvents', function () { Konva.inDblClickWindow = false; // touchstart circle - stage.simulateTouchStart([{ x: 289, y: 100, id: 0 }]); + simulateTouchStart(stage, [{ x: 289, y: 100, id: 0 }]); assert(touchstart, '8) touchstart should be true'); assert(!touchmove, '8) touchmove should be false'); @@ -134,7 +148,7 @@ suite('TouchEvents', function () { assert(!dbltap, '8) dbltap should be false'); // touchend circle - stage.simulateTouchEnd([], [{ x: 289, y: 100, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 289, y: 100, id: 0 }]); // end drag is tied to document mouseup and touchend event // which can't be simulated. call _endDrag manually //Konva.DD._endDrag(); @@ -146,7 +160,7 @@ suite('TouchEvents', function () { assert(!dbltap, '9) dbltap should be false'); // touchstart circle - stage.simulateTouchStart([{ x: 289, y: 100, id: 0 }]); + simulateTouchStart(stage, [{ x: 289, y: 100, id: 0 }]); assert(touchstart, '10) touchstart should be true'); assert(!touchmove, '10) touchmove should be false'); @@ -155,7 +169,7 @@ suite('TouchEvents', function () { assert(!dbltap, '10) dbltap should be false'); // touchend circle to triger dbltap - stage.simulateTouchEnd([], [{ x: 289, y: 100, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 289, y: 100, id: 0 }]); // end drag is tied to document mouseup and touchend event // which can't be simulated. call _endDrag manually //Konva.DD._endDrag(); @@ -168,7 +182,7 @@ suite('TouchEvents', function () { setTimeout(function () { // touchmove circle - stage.simulateTouchMove([], [{ x: 289, y: 100, id: 0 }]); + simulateTouchMove(stage, [], [{ x: 289, y: 100, id: 0 }]); assert(touchstart, '12) touchstart should be true'); assert(touchmove, '12) touchmove should be true'); @@ -180,7 +194,7 @@ suite('TouchEvents', function () { }, 17); }); - test('tap on stage and second tap on shape should not trigger double tap (check after dbltap)', function (done) { + it('tap on stage and second tap on shape should not trigger double tap (check after dbltap)', function (done) { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -200,19 +214,19 @@ suite('TouchEvents', function () { var bigDblClicks = 0; // make dblclick - stage.simulateTouchStart({ + simulateTouchStart(stage, { x: 100, y: 100, }); - stage.simulateTouchEnd({ + simulateTouchEnd(stage, { x: 100, y: 100, }); - stage.simulateTouchStart({ + simulateTouchStart(stage, { x: 100, y: 100, }); - stage.simulateTouchEnd({ + simulateTouchEnd(stage, { x: 100, y: 100, }); @@ -225,11 +239,11 @@ suite('TouchEvents', function () { bigDblClicks += 1; }); - stage.simulateTouchStart({ + simulateTouchStart(stage, { x: 10, y: 10, }); - stage.simulateTouchEnd({ + simulateTouchEnd(stage, { x: 10, y: 10, }); @@ -237,11 +251,11 @@ suite('TouchEvents', function () { assert.equal(bigClicks, 0); assert.equal(bigDblClicks, 0); - stage.simulateTouchStart({ + simulateTouchStart(stage, { x: 100, y: 100, }); - stage.simulateTouchEnd({ + simulateTouchEnd(stage, { x: 100, y: 100, }); @@ -253,7 +267,7 @@ suite('TouchEvents', function () { }); // test for https://github.com/konvajs/konva/issues/156 - test('touchstart out of shape, then touch end inside shape', function () { + it('touchstart out of shape, then touch end inside shape', function () { var stage = addStage(); var layer = new Konva.Layer(); var circle = new Konva.Circle({ @@ -269,7 +283,9 @@ suite('TouchEvents', function () { layer.add(circle); stage.add(layer); - var circleTouchend = (stageContentTouchstart = stageContentTouchend = 0); + var circleTouchend = 0; + var stageContentTouchstart = 0; + var stageContentTouchend = 0; var top = stage.content.getBoundingClientRect().top; @@ -285,15 +301,15 @@ suite('TouchEvents', function () { stageContentTouchend++; }); - stage.simulateTouchStart([{ x: 1, y: 1, id: 0 }]); - stage.simulateTouchEnd([], [{ x: 100, y: 100, id: 0 }]); + simulateTouchStart(stage, [{ x: 1, y: 1, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); assert.equal(stageContentTouchstart, 1); assert.equal(stageContentTouchend, 1); assert.equal(circleTouchend, 1); }); - test('tap on one shape, then fast tap on another shape should no trigger double tap', function () { + it('tap on one shape, then fast tap on another shape should no trigger double tap', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -338,8 +354,8 @@ suite('TouchEvents', function () { circle2DoubleTap++; }); - stage.simulateTouchStart({ x: 100, y: 100 }); - stage.simulateTouchEnd({ x: 100, y: 100 }); + simulateTouchStart(stage, { x: 100, y: 100 }); + simulateTouchEnd(stage, { x: 100, y: 100 }); assert.equal(circle1Tap, 1, 'should trigger tap on first circle'); assert.equal(circle2Tap, 0, 'should NOT trigger tap on second circle'); @@ -349,8 +365,8 @@ suite('TouchEvents', function () { 'should NOT trigger dbltap on second circle' ); - stage.simulateTouchStart({ x: 200, y: 100 }); - stage.simulateTouchEnd({ x: 200, y: 100 }); + simulateTouchStart(stage, { x: 200, y: 100 }); + simulateTouchEnd(stage, { x: 200, y: 100 }); assert.equal(circle1Tap, 1, 'should trigger tap on first circle'); assert.equal(circle2Tap, 1, 'should trigger tap on second circle'); @@ -361,7 +377,7 @@ suite('TouchEvents', function () { ); }); - test('multitouch - register all touches', function () { + it('multitouch - register all touches', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -425,7 +441,8 @@ suite('TouchEvents', function () { }); // start with one touch - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); @@ -434,7 +451,8 @@ suite('TouchEvents', function () { assert.equal(touchStart, 1, 'trigger first touch start on circle'); // make second touch - stage.simulateTouchStart( + simulateTouchStart( + stage, [ { x: 100, y: 100, id: 0 }, { x: 210, y: 100, id: 1 }, @@ -455,7 +473,8 @@ suite('TouchEvents', function () { // now try to make two touches at the same time // TODO: should we trigger touch end first? - stage.simulateTouchStart( + simulateTouchStart( + stage, [ { x: 100, y: 100, id: 0 }, { x: 210, y: 100, id: 1 }, @@ -481,7 +500,8 @@ suite('TouchEvents', function () { ]); // move one finger - stage.simulateTouchMove( + simulateTouchMove( + stage, [ { x: 100, y: 100, id: 0 }, { x: 220, y: 100, id: 1 }, @@ -492,7 +512,8 @@ suite('TouchEvents', function () { assert.equal(stageTouchMove, 1, 'should trigger touch move on stage'); // move two fingers - stage.simulateTouchMove( + simulateTouchMove( + stage, [ { x: 100, y: 100, id: 0 }, { x: 220, y: 100, id: 1 }, @@ -509,7 +530,8 @@ suite('TouchEvents', function () { 'should trigger two more touchmoves on stage' ); - stage.simulateTouchEnd( + simulateTouchEnd( + stage, [], [ { x: 100, y: 100, id: 0 }, @@ -520,7 +542,8 @@ suite('TouchEvents', function () { assert.equal(stageTouchEnd, 1); // try two touch ends on both shapes - stage.simulateTouchEnd( + simulateTouchEnd( + stage, [], [ { x: 100, y: 100, id: 0 }, @@ -534,7 +557,7 @@ suite('TouchEvents', function () { assert.equal(stageTouchEnd, 3); }); - test('can capture touch events', function () { + it('can capture touch events', function () { Konva.captureTouchEventsEnabled = true; var stage = addStage(); var layer = new Konva.Layer(); @@ -567,20 +590,23 @@ suite('TouchEvents', function () { touchEnd++; }); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); // go out of circle - stage.simulateTouchMove( + simulateTouchMove( + stage, [{ x: 180, y: 100, id: 0 }], [{ x: 180, y: 100, id: 0 }] ); assert.equal(touchMove, 1, 'first touchmove'); // add another finger - stage.simulateTouchStart( + simulateTouchStart( + stage, [ { x: 180, y: 100, id: 0 }, { x: 100, y: 100, id: 1 }, @@ -589,7 +615,8 @@ suite('TouchEvents', function () { ); // move all out - stage.simulateTouchMove( + simulateTouchMove( + stage, [ { x: 185, y: 100, id: 0 }, { x: 190, y: 100, id: 1 }, @@ -603,7 +630,8 @@ suite('TouchEvents', function () { assert.equal(touchMove, 2, 'second touchmove'); // remove fingers - stage.simulateTouchEnd( + simulateTouchEnd( + stage, [], [ { x: 185, y: 100, id: 0 }, @@ -620,7 +648,7 @@ suite('TouchEvents', function () { Konva.captureTouchEventsEnabled = false; }); - test('tap and double tap should trigger just once on stage', function () { + it('tap and double tap should trigger just once on stage', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -650,27 +678,29 @@ suite('TouchEvents', function () { dbltap += 1; }); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); - stage.simulateTouchEnd([], [{ x: 100, y: 100, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); assert.equal(tap, 1, 'tap triggered'); assert.equal(dbltap, 0, 'no dbltap triggered'); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); - stage.simulateTouchEnd([], [{ x: 100, y: 100, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); assert.equal(tap, 2, 'tap triggered'); assert.equal(dbltap, 1, 'no dbltap triggered'); }); - test('drag and second tap should not trigger dbltap', function () { + it('drag and second tap should not trigger dbltap', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -705,34 +735,37 @@ suite('TouchEvents', function () { dragmove += 1; }); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); - stage.simulateTouchMove( + simulateTouchMove( + stage, [{ x: 150, y: 150, id: 0 }], [{ x: 150, y: 150, id: 0 }] ); - stage.simulateTouchEnd([], [{ x: 150, y: 150, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 150, y: 150, id: 0 }]); assert.equal(tap, 0, 'no tap triggered'); assert.equal(dbltap, 0, 'no dbltap triggered'); assert.equal(dragmove, 1, 'dragmove triggered'); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 150, y: 150, id: 0 }], [{ x: 150, y: 150, id: 0 }] ); - stage.simulateTouchEnd([], [{ x: 150, y: 150, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 150, y: 150, id: 0 }]); assert.equal(tap, 1, 'tap triggered'); assert.equal(dbltap, 0, 'no dbltap triggered'); }); - test('tap should give pointer position', function () { + it('tap should give pointer position', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); @@ -764,12 +797,13 @@ suite('TouchEvents', function () { click += 1; }); - stage.simulateTouchStart( + simulateTouchStart( + stage, [{ x: 100, y: 100, id: 0 }], [{ x: 100, y: 100, id: 0 }] ); - stage.simulateTouchEnd([], [{ x: 100, y: 100, id: 0 }]); + simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); assert.equal(tap, 1, 'tap triggered'); assert.equal(click, 0, 'no click triggered'); diff --git a/test/unit-new/shapes/Transformer-test.ts b/test/unit/Transformer-test.ts similarity index 85% rename from test/unit-new/shapes/Transformer-test.ts rename to test/unit/Transformer-test.ts index d68dbe5f..44b260cc 100644 --- a/test/unit-new/shapes/Transformer-test.ts +++ b/test/unit/Transformer-test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import { Transformer } from '../../../src/shapes/Transformer'; +import { Transformer } from '../../src/shapes/Transformer'; import { addStage, @@ -8,7 +8,8 @@ import { simulateMouseDown as sd, simulateMouseMove as sm, simulateMouseUp as su, -} from '../utis'; + assertAlmostEqual, +} from './utis'; function simulateMouseDown(tr, pos) { sd(tr.getStage(), pos); @@ -36,16 +37,6 @@ function simulateMouseUp(tr: Transformer, pos = { x: 0, y: 0 }) { } describe('Transformer', function () { - function isClose(a, b) { - return Math.abs(a - b) < 0.000001; - } - - assert.almostEqual = function (val1, val2) { - if (!isClose(val1, val2)) { - throw new Error('Expected ' + val1 + ' to be almost equal to ' + val2); - } - }; - // ====================================================== it('init transformer on simple rectangle', function () { var stage = addStage(); @@ -223,11 +214,11 @@ describe('Transformer', function () { rotation: Konva.getAngle(45), }); - assert.almostEqual(rect.x(), 50); - assert.almostEqual(rect.y(), 50); - assert.almostEqual(tr.width(), 100); - assert.almostEqual(tr.height(), 150); - assert.almostEqual(tr.rotation(), rect.rotation()); + assertAlmostEqual(rect.x(), 50); + assertAlmostEqual(rect.y(), 50); + assertAlmostEqual(tr.width(), 100); + assertAlmostEqual(tr.height(), 150); + assertAlmostEqual(tr.rotation(), rect.rotation()); }); it('transformer should follow rotation on single node', function () { @@ -292,11 +283,11 @@ describe('Transformer', function () { rotation: 0, }); - assert.almostEqual(rect.x(), 0); - assert.almostEqual(rect.y(), 0); - assert.almostEqual(tr.width(), 100); - assert.almostEqual(tr.height(), 150); - assert.almostEqual(rect.rotation(), -45); + assertAlmostEqual(rect.x(), 0); + assertAlmostEqual(rect.y(), 0); + assertAlmostEqual(tr.width(), 100); + assertAlmostEqual(tr.height(), 150); + assertAlmostEqual(rect.rotation(), -45); }); it('transformer should follow rotation on single node inside group', function () { @@ -329,7 +320,7 @@ describe('Transformer', function () { rect.rotation(45); layer.draw(); - assert.equal(isClose(tr.rotation(), 90), true); + assertAlmostEqual(tr.rotation(), 90); }); it('try to fit simple rotated rectangle - 2', function () { @@ -362,12 +353,12 @@ describe('Transformer', function () { rotation: 0, }); - assert.almostEqual(rect.x(), 40); - assert.almostEqual(rect.y(), 40); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.height(), 200); - assert.almostEqual(rect.scaleY(), 0.5); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 40); + assertAlmostEqual(rect.y(), 40); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.height(), 200); + assertAlmostEqual(rect.scaleY(), 0.5); + assertAlmostEqual(rect.rotation(), 0); }); it('rotate around center', function () { @@ -400,12 +391,12 @@ describe('Transformer', function () { rotation: 0, }); - assert.almostEqual(rect.x(), 40); - assert.almostEqual(rect.y(), 40); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.height(), 200); - assert.almostEqual(rect.scaleY(), 0.5); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 40); + assertAlmostEqual(rect.y(), 40); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.height(), 200); + assertAlmostEqual(rect.scaleY(), 0.5); + assertAlmostEqual(rect.rotation(), 0); }); it('change transform of parent', function () { @@ -516,7 +507,7 @@ describe('Transformer', function () { assert.equal(tr.width(), 50); assert.equal(tr.height(), 50); assert.equal(tr.rotation(), rect.rotation()); - assert.almostEqual(rect.skewX(), 0.2); + assertAlmostEqual(rect.skewX(), 0.2); }); it('try to resize in draggable stage', function () { @@ -620,13 +611,13 @@ describe('Transformer', function () { tr._fitNodesInto(box); - assert.almostEqual(rect.x(), 100); - assert.almostEqual(rect.y(), 0); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.scaleY(), -1); - assert.almostEqual(rect.rotation(), -180); + assertAlmostEqual(rect.x(), 100); + assertAlmostEqual(rect.y(), 0); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.scaleY(), -1); + assertAlmostEqual(rect.rotation(), -180); layer.draw(); }); @@ -665,11 +656,11 @@ describe('Transformer', function () { rotation: 0, }); - assert.almostEqual(rect.x(), 20); - assert.almostEqual(rect.y(), 20); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.scaleX(), 2); + assertAlmostEqual(rect.x(), 20); + assertAlmostEqual(rect.y(), 20); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.scaleX(), 2); }); it('listen shape changes', function () { @@ -768,11 +759,11 @@ describe('Transformer', function () { rotation: 0, }); - assert.almostEqual(rect.x(), 100); - assert.almostEqual(rect.y(), 70); - assert.almostEqual(rect.width() * rect.scaleX(), 100); - assert.almostEqual(rect.height() * rect.scaleY(), 100); - assert.almostEqual(rect.rotation(), rect.rotation()); + assertAlmostEqual(rect.x(), 100); + assertAlmostEqual(rect.y(), 70); + assertAlmostEqual(rect.width() * rect.scaleX(), 100); + assertAlmostEqual(rect.height() * rect.scaleY(), 100); + assertAlmostEqual(rect.rotation(), rect.rotation()); }); it('add transformer for transformed rect with offset', function () { @@ -838,17 +829,17 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual(rect.x(), 100); - assert.almostEqual(rect.y(), 50); - assert.almostEqual(rect.width() * rect.scaleX(), 200); - assert.almostEqual(rect.height() * rect.scaleY(), 100); - assert.almostEqual(rect.rotation(), rect.rotation()); + assertAlmostEqual(rect.x(), 100); + assertAlmostEqual(rect.y(), 50); + assertAlmostEqual(rect.width() * rect.scaleX(), 200); + assertAlmostEqual(rect.height() * rect.scaleY(), 100); + assertAlmostEqual(rect.rotation(), rect.rotation()); - assert.almostEqual(tr.x(), 0); - assert.almostEqual(tr.y(), 0); - assert.almostEqual(tr.width(), 200); - assert.almostEqual(tr.height(), 100); - assert.almostEqual(rect.rotation(), rect.rotation()); + assertAlmostEqual(tr.x(), 0); + assertAlmostEqual(tr.y(), 0); + assertAlmostEqual(tr.width(), 200); + assertAlmostEqual(tr.height(), 100); + assertAlmostEqual(rect.rotation(), rect.rotation()); }); it('add transformer for circle', function () { @@ -944,16 +935,16 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual(circle.x(), 40); - assert.almostEqual(circle.y(), 40); - assert.almostEqual(circle.width() * circle.scaleX(), 80); - assert.almostEqual(circle.height() * circle.scaleY(), 80); - assert.almostEqual(circle.rotation(), 90); + assertAlmostEqual(circle.x(), 40); + assertAlmostEqual(circle.y(), 40); + assertAlmostEqual(circle.width() * circle.scaleX(), 80); + assertAlmostEqual(circle.height() * circle.scaleY(), 80); + assertAlmostEqual(circle.rotation(), 90); - assert.almostEqual(tr.x(), 80); - assert.almostEqual(tr.y(), 0); - assert.almostEqual(tr.width(), 80); - assert.almostEqual(tr.height(), 80); + assertAlmostEqual(tr.x(), 80); + assertAlmostEqual(tr.y(), 0); + assertAlmostEqual(tr.width(), 80); + assertAlmostEqual(tr.height(), 80); }); it('add transformer for transformed circle', function () { @@ -1106,16 +1097,16 @@ describe('Transformer', function () { var rect = group.getClientRect(); - assert.almostEqual(group.x(), 50); - assert.almostEqual(group.y(), 50); - assert.almostEqual(rect.width, 100); - assert.almostEqual(rect.height, 100); - assert.almostEqual(group.rotation(), 90); + assertAlmostEqual(group.x(), 50); + assertAlmostEqual(group.y(), 50); + assertAlmostEqual(rect.width, 100); + assertAlmostEqual(rect.height, 100); + assertAlmostEqual(group.rotation(), 90); - assert.almostEqual(tr.x(), 100); - assert.almostEqual(tr.y(), 0); - assert.almostEqual(tr.width(), 100); - assert.almostEqual(tr.height(), 100); + assertAlmostEqual(tr.x(), 100); + assertAlmostEqual(tr.y(), 0); + assertAlmostEqual(tr.width(), 100); + assertAlmostEqual(tr.height(), 100); }); it('add transformer to another group', function () { @@ -1208,15 +1199,15 @@ describe('Transformer', function () { var rect = group.getClientRect(); - assert.almostEqual(group.x(), 100); - assert.almostEqual(group.y(), 50); - assert.almostEqual(rect.width, 200); - assert.almostEqual(rect.height, 100); + assertAlmostEqual(group.x(), 100); + assertAlmostEqual(group.y(), 50); + assertAlmostEqual(rect.width, 200); + assertAlmostEqual(rect.height, 100); - assert.almostEqual(tr.x(), 0); - assert.almostEqual(tr.y(), 0); - assert.almostEqual(tr.width(), 200); - assert.almostEqual(tr.height(), 100); + assertAlmostEqual(tr.x(), 0); + assertAlmostEqual(tr.y(), 0); + assertAlmostEqual(tr.width(), 200); + assertAlmostEqual(tr.height(), 100); }); it('toJSON should not save attached node and children', function () { @@ -1370,12 +1361,12 @@ describe('Transformer', function () { y: 150, }); - assert.almostEqual(rect.x(), 80); - assert.almostEqual(rect.y(), 30); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.5); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.x(), 80); + assertAlmostEqual(rect.y(), 30); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.5); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.scaleY(), 1); }); it('keep ratio should allow negative scaling', function () { @@ -1415,36 +1406,11 @@ describe('Transformer', function () { y: pos.y + 100, }); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.scaleY(), 1); - assert.almostEqual(rect.rotation(), -180); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.rotation(), -180); }); - it.skip('visual test', function (done) { - var stage = addStage(); - var layer = new Konva.Layer(); - stage.add(layer); - var src = 'assets/darth-vader.jpg'; - Konva.Image.fromURL(src, function (image) { - image.setAttrs({ - draggable: true, - scaleX: 0.5, - scaleY: 0.5, - shadowColor: 'black', - // shadowBlur: 10, - shadowOffset: { x: 10, y: 10 }, - }); - layer.add(image); - var tr = new Konva.Transformer({ - nodes: [image], - }); - layer.add(tr); - layer.draw(); - - throw 1; - done(); - }); - }); it('slightly move for cache check (top-left anchor)', function () { var stage = addStage(); @@ -1469,7 +1435,7 @@ describe('Transformer', function () { layer.draw(); var anchor = tr.findOne('.top-left'); - assert.almostEqual(anchor.getAbsolutePosition().x, 20); + assertAlmostEqual(anchor.getAbsolutePosition().x, 20); simulateMouseDown(tr, { x: 20, @@ -1484,8 +1450,8 @@ describe('Transformer', function () { simulateMouseUp(tr); layer.draw(); - assert.almostEqual(rect.x(), 20); - assert.almostEqual(rect.y(), 20); + assertAlmostEqual(rect.x(), 20); + assertAlmostEqual(rect.y(), 20); }); it('rotation snaps', function () { @@ -1552,24 +1518,24 @@ describe('Transformer', function () { x: 0, y: 199, }); - assert.almostEqual(rect.rotation(), -90); + assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 50, }); - assert.almostEqual(rect.rotation(), -90); + assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 45, }); - assert.almostEqual(rect.rotation(), -90); + assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 1, }); - assert.almostEqual(rect.rotation(), -90); + assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 1, @@ -1613,25 +1579,25 @@ describe('Transformer', function () { y: 60, }); - assert.almostEqual(rect.x(), 115); - assert.almostEqual(rect.y(), 10); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.05); - assert.almostEqual(rect.scaleY(), -1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), -180); + assertAlmostEqual(rect.x(), 115); + assertAlmostEqual(rect.y(), 10); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.05); + assertAlmostEqual(rect.scaleY(), -1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), -180); simulateMouseMove(tr, { x: 125, y: 60, }); - assert.almostEqual(rect.x(), 115); - assert.almostEqual(rect.y(), 10); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.scaleY(), -1); + assertAlmostEqual(rect.x(), 115); + assertAlmostEqual(rect.y(), 10); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.scaleY(), -1); // switch again simulateMouseMove(tr, { @@ -1639,12 +1605,12 @@ describe('Transformer', function () { y: 60, }); - assert.almostEqual(rect.x(), 100); - assert.almostEqual(rect.y(), 10); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleY(), 1); - assert.almostEqual(rect.scaleX(), 0.1); - assert.almostEqual(rect.height(), 100); + assertAlmostEqual(rect.x(), 100); + assertAlmostEqual(rect.y(), 10); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.scaleX(), 0.1); + assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); @@ -1682,24 +1648,24 @@ describe('Transformer', function () { y: 125, }); - assert.almostEqual(rect.x(), 10); - assert.almostEqual(rect.y(), 115); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleY(), -0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 10); + assertAlmostEqual(rect.y(), 115); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleY(), -0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 0); simulateMouseMove(tr, { x: 60, y: 125, }); - assert.almostEqual(rect.x(), 10); - assert.almostEqual(rect.y(), 115); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleY(), -0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 10); + assertAlmostEqual(rect.y(), 115); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleY(), -0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 0); // switch again simulateMouseMove(tr, { @@ -1707,13 +1673,13 @@ describe('Transformer', function () { y: 90, }); - assert.almostEqual(rect.x(), 10); - assert.almostEqual(rect.y(), 100); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.scaleY(), 0.1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 10); + assertAlmostEqual(rect.y(), 100); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.scaleY(), 0.1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 0); simulateMouseUp(tr); }); @@ -1751,13 +1717,13 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual(rect.x(), 150); - assert.almostEqual(rect.y(), 50); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.5); - assert.almostEqual(rect.scaleY(), -0.5); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), -180); + assertAlmostEqual(rect.x(), 150); + assertAlmostEqual(rect.y(), 50); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.5); + assertAlmostEqual(rect.scaleY(), -0.5); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), -180); simulateMouseMove(tr, { x: 98, @@ -1802,12 +1768,12 @@ describe('Transformer', function () { y: 0, }); - assert.almostEqual(rect.x(), 0); - assert.almostEqual(rect.y(), 0); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleY(), 1); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.height(), 100); + assertAlmostEqual(rect.x(), 0); + assertAlmostEqual(rect.y(), 0); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); @@ -1845,12 +1811,12 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual(rect.x(), 0); - assert.almostEqual(rect.y(), 200); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.x(), 0); + assertAlmostEqual(rect.y(), 200); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 0); simulateMouseMove(tr, { x: 0, @@ -1859,13 +1825,13 @@ describe('Transformer', function () { layer.draw(); simulateMouseUp(tr); - assert.almostEqual(rect.x(), 0); - assert.almostEqual(rect.y(), 0); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 0); - assert.almostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.x(), 0); + assertAlmostEqual(rect.y(), 0); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 0); + assertAlmostEqual(rect.scaleY(), 1); }); it('switch scaling with padding for rotated - x', function () { @@ -1902,25 +1868,25 @@ describe('Transformer', function () { y: 125, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y(), 115); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.05); - assert.almostEqual(rect.scaleY(), -1); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), -90); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y(), 115); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.05); + assertAlmostEqual(rect.scaleY(), -1); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 60, y: 125, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y(), 115); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.scaleY(), -1); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y(), 115); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.scaleY(), -1); layer.draw(); @@ -1930,13 +1896,13 @@ describe('Transformer', function () { y: 90, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y(), 100); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 0.1); - assert.almostEqual(rect.scaleY(), 1); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y(), 100); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 0.1); + assertAlmostEqual(rect.scaleY(), 1); - assert.almostEqual(rect.height(), 100); + assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); @@ -1975,26 +1941,26 @@ describe('Transformer', function () { y: 60, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y(), 10); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.scaleY(), -0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 90); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y(), 10); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.scaleY(), -0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 90); simulateMouseMove(tr, { x: 125, y: 60, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y(), 10); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.scaleY(), -0.05); - assert.almostEqual(rect.height(), 100); - assert.almostEqual(rect.rotation(), 90); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y(), 10); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.scaleY(), -0.05); + assertAlmostEqual(rect.height(), 100); + assertAlmostEqual(rect.rotation(), 90); // switch again simulateMouseMove(tr, { @@ -2002,12 +1968,12 @@ describe('Transformer', function () { y: 60, }); - assert.almostEqual(rect.x(), 110); - assert.almostEqual(rect.y() - 120 < 0.001, true); - assert.almostEqual(rect.width(), 100); - assert.almostEqual(rect.scaleX(), 1); - assert.almostEqual(rect.scaleY(), 0.1); - assert.almostEqual(rect.height(), 100); + assertAlmostEqual(rect.x(), 110); + assertAlmostEqual(rect.y() - 120 < 0.001, true); + assertAlmostEqual(rect.width(), 100); + assertAlmostEqual(rect.scaleX(), 1); + assertAlmostEqual(rect.scaleY(), 0.1); + assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); @@ -2901,16 +2867,8 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual( - rect.width() * rect.scaleX(), - test.expectedWidth, - test.name + ' width check' - ); - assert.almostEqual( - rect.height() * rect.scaleY(), - test.expectedHeight, - test.name + ' height check' - ); + assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); + assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); @@ -2965,16 +2923,8 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual( - rect.width() * rect.scaleX(), - test.expectedWidth, - test.name + ' width check' - ); - assert.almostEqual( - rect.height() * rect.scaleY(), - test.expectedHeight, - test.name + ' height check' - ); + assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); + assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); @@ -3028,16 +2978,8 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual( - rect.width() * rect.scaleX(), - test.expectedWidth, - test.name + ' width check' - ); - assert.almostEqual( - rect.height() * rect.scaleY(), - test.expectedHeight, - test.name + ' height check' - ); + assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); + assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); @@ -3099,26 +3041,26 @@ describe('Transformer', function () { simulateMouseDown(tr, start); simulateMouseMove(tr, end); var box = rect.getClientRect(); - assert.almostEqual(box.x, 0); - assert.almostEqual(box.y, 0); - assert.almostEqual(box.width, 200); - assert.almostEqual(box.height, 100); + assertAlmostEqual(box.x, 0); + assertAlmostEqual(box.y, 0); + assertAlmostEqual(box.width, 200); + assertAlmostEqual(box.height, 100); // make extra move on end simulateMouseMove(tr, end); var box = rect.getClientRect(); - assert.almostEqual(box.x, 0); - assert.almostEqual(box.y, 0); - assert.almostEqual(box.width, 200); - assert.almostEqual(box.height, 100); + assertAlmostEqual(box.x, 0); + assertAlmostEqual(box.y, 0); + assertAlmostEqual(box.width, 200); + assertAlmostEqual(box.height, 100); // move back simulateMouseMove(tr, start); simulateMouseUp(tr); - assert.almostEqual(box.x, 0); - assert.almostEqual(box.y, 0); - assert.almostEqual(box.width, 200); - assert.almostEqual(box.height, 100); + assertAlmostEqual(box.x, 0); + assertAlmostEqual(box.y, 0); + assertAlmostEqual(box.width, 200); + assertAlmostEqual(box.height, 100); }); }); @@ -3763,7 +3705,7 @@ describe('Transformer', function () { // should not throw error rect2.width(100); - assert(tr2.width(), 200); + assertAlmostEqual(tr2.width(), 100); stage.draw(); }); @@ -3824,7 +3766,7 @@ describe('Transformer', function () { y: 50, }); - assert.almostEqual(rect.width() * rect.scaleX(), 200); + assertAlmostEqual(rect.width() * rect.scaleX(), 200); }); it('rotate several nodes', function () { @@ -3869,17 +3811,17 @@ describe('Transformer', function () { layer.draw(); - assert.almostEqual(rect1.x(), 100); - assert.almostEqual(rect1.y(), 0); - assert.almostEqual(rect1.width() + rect2.width(), 100); - assert.almostEqual(rect1.height() + rect2.width(), 100); - assert.almostEqual(rect1.rotation(), 90); + assertAlmostEqual(rect1.x(), 100); + assertAlmostEqual(rect1.y(), 0); + assertAlmostEqual(rect1.width() + rect2.width(), 100); + assertAlmostEqual(rect1.height() + rect2.width(), 100); + assertAlmostEqual(rect1.rotation(), 90); - assert.almostEqual(rect2.x(), 50); - assert.almostEqual(rect2.y(), 50); - assert.almostEqual(rect2.width() + rect2.width(), 100); - assert.almostEqual(rect2.height() + rect2.width(), 100); - assert.almostEqual(tr.rotation(), 90); + assertAlmostEqual(rect2.x(), 50); + assertAlmostEqual(rect2.y(), 50); + assertAlmostEqual(rect2.width() + rect2.width(), 100); + assertAlmostEqual(rect2.height() + rect2.width(), 100); + assertAlmostEqual(tr.rotation(), 90); tr._fitNodesInto({ x: 100, @@ -3889,11 +3831,11 @@ describe('Transformer', function () { rotation: Konva.getAngle(180), }); - assert.almostEqual(tr.x(), rect1.x()); - assert.almostEqual(tr.y(), rect1.y()); - assert.almostEqual(tr.width(), rect1.width() + rect2.width()); - assert.almostEqual(tr.height(), rect1.height() + rect2.width()); - assert.almostEqual(tr.rotation(), 180); + assertAlmostEqual(tr.x(), rect1.x()); + assertAlmostEqual(tr.y(), rect1.y()); + assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); + assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); + assertAlmostEqual(tr.rotation(), 180); }); it('events on several nodes', function () { @@ -4015,17 +3957,17 @@ describe('Transformer', function () { layer.draw(); - assert.almostEqual(rect1.x(), 100); - assert.almostEqual(rect1.y(), 41.421356237309496); - assert.almostEqual(rect1.width() + rect2.width(), 100); - assert.almostEqual(rect1.height() + rect2.width(), 100); - assert.almostEqual(rect1.rotation(), 132.45339125826706); + assertAlmostEqual(rect1.x(), 100); + assertAlmostEqual(rect1.y(), 41.421356237309496); + assertAlmostEqual(rect1.width() + rect2.width(), 100); + assertAlmostEqual(rect1.height() + rect2.width(), 100); + assertAlmostEqual(rect1.rotation(), 132.45339125826706); - assert.almostEqual(rect2.x(), 46.41016151377549); - assert.almostEqual(rect2.y(), 100); - assert.almostEqual(rect2.width() + rect2.width(), 100); - assert.almostEqual(rect2.height() + rect2.width(), 100); - assert.almostEqual(tr.rotation(), 90); + assertAlmostEqual(rect2.x(), 46.41016151377549); + assertAlmostEqual(rect2.y(), 100); + assertAlmostEqual(rect2.width() + rect2.width(), 100); + assertAlmostEqual(rect2.height() + rect2.width(), 100); + assertAlmostEqual(tr.rotation(), 90); tr._fitNodesInto({ x: 100, @@ -4035,8 +3977,8 @@ describe('Transformer', function () { rotation: Konva.getAngle(180), }); - assert.almostEqual(tr.x(), 100); - assert.almostEqual(tr.y(), 100); + assertAlmostEqual(tr.x(), 100); + assertAlmostEqual(tr.y(), 100); }); it('drag several nodes', function () { @@ -4368,20 +4310,20 @@ describe('Transformer', function () { rotation: Konva.getAngle(90), }); - assert.almostEqual(tr.x(), rect1.x()); - assert.almostEqual(tr.y(), rect1.y()); - assert.almostEqual(tr.width(), rect1.width() + rect2.width()); - assert.almostEqual(tr.height(), rect1.height() + rect2.width()); - assert.almostEqual(tr.rotation(), 90); + assertAlmostEqual(tr.x(), rect1.x()); + assertAlmostEqual(tr.y(), rect1.y()); + assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); + assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); + assertAlmostEqual(tr.rotation(), 90); layer.draw(); tr.nodes([rect1, rect2]); - assert.almostEqual(tr.x(), 0); - assert.almostEqual(tr.y(), 0); - assert.almostEqual(tr.width(), rect1.width() + rect2.width()); - assert.almostEqual(tr.height(), rect1.height() + rect2.width()); - assert.almostEqual(tr.rotation(), 0); + assertAlmostEqual(tr.x(), 0); + assertAlmostEqual(tr.y(), 0); + assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); + assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); + assertAlmostEqual(tr.rotation(), 0); }); it('rotate several nodes inside different parents', function () { @@ -4441,23 +4383,23 @@ describe('Transformer', function () { var newBox = tr._getNodeRect(); - assert.almostEqual(box.x, newBox.x); - assert.almostEqual(box.y, newBox.y); - assert.almostEqual(box.width, newBox.width); - assert.almostEqual(box.height, newBox.height); - assert.almostEqual(box.rotation, newBox.rotation); + assertAlmostEqual(box.x, newBox.x); + assertAlmostEqual(box.y, newBox.y); + assertAlmostEqual(box.width, newBox.width); + assertAlmostEqual(box.height, newBox.height); + assertAlmostEqual(box.rotation, newBox.rotation); - assert.almostEqual(rect1.x(), 0); - assert.almostEqual(rect1.y(), 0); - assert.almostEqual(rect1.width(), 50); - assert.almostEqual(rect1.height(), 50); - assert.almostEqual(rect1.rotation(), 0); + assertAlmostEqual(rect1.x(), 0); + assertAlmostEqual(rect1.y(), 0); + assertAlmostEqual(rect1.width(), 50); + assertAlmostEqual(rect1.height(), 50); + assertAlmostEqual(rect1.rotation(), 0); - assert.almostEqual(rect2.x(), 0); - assert.almostEqual(rect2.y(), 50); - assert.almostEqual(rect2.width(), 25); - assert.almostEqual(rect2.height(), 50); - assert.almostEqual(rect2.rotation(), 0); + assertAlmostEqual(rect2.x(), 0); + assertAlmostEqual(rect2.y(), 50); + assertAlmostEqual(rect2.width(), 25); + assertAlmostEqual(rect2.height(), 50); + assertAlmostEqual(rect2.rotation(), 0); }); it('can attach transformer into several nodes and fit into negative scale', function () { @@ -4508,11 +4450,11 @@ describe('Transformer', function () { }); layer.draw(); - assert.almostEqual(Math.round(tr.x()), 0); - assert.almostEqual(Math.round(tr.y()), 0); - assert.almostEqual(tr.width(), rect1.width() + rect2.width()); - assert.almostEqual(tr.height(), rect1.height() + rect2.height()); - assert.almostEqual(tr.rotation(), 0); + assertAlmostEqual(Math.round(tr.x()), 0); + assertAlmostEqual(Math.round(tr.y()), 0); + assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); + assertAlmostEqual(tr.height(), rect1.height() + rect2.height()); + assertAlmostEqual(tr.rotation(), 0); }); it('boundBoxFox should work in absolute coordinates', function () { diff --git a/test/unit-new/Tween-test.ts b/test/unit/Tween-test.ts similarity index 100% rename from test/unit-new/Tween-test.ts rename to test/unit/Tween-test.ts diff --git a/test/unit-new/Util-test.ts b/test/unit/Util-test.ts similarity index 100% rename from test/unit-new/Util-test.ts rename to test/unit/Util-test.ts diff --git a/test/unit-new/shapes/Wedge-test.ts b/test/unit/Wedge-test.ts similarity index 97% rename from test/unit-new/shapes/Wedge-test.ts rename to test/unit/Wedge-test.ts index 28800228..00aab0ed 100644 --- a/test/unit-new/shapes/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 './utis'; describe('Wedge', function () { // ====================================================== diff --git a/test/unit-new/imagediff.ts b/test/unit/imagediff.ts similarity index 100% rename from test/unit-new/imagediff.ts rename to test/unit/imagediff.ts diff --git a/test/unit-new/utis.ts b/test/unit/utis.ts similarity index 86% rename from test/unit-new/utis.ts rename to test/unit/utis.ts index a523f2bb..b29f361a 100644 --- a/test/unit-new/utis.ts +++ b/test/unit/utis.ts @@ -11,6 +11,7 @@ Konva.showWarnings = true; import { imagediff } from './imagediff'; import { Layer } from '../../src/Layer'; +import { Stage } from '../../src/Stage'; export const isNode = typeof global.document === 'undefined'; export const isBrowser = !isNode; @@ -46,19 +47,6 @@ export function addStage(attrs?) { return stage; } -beforeEach(function () { - Konva.inDblClickWindow = false; - - if ( - !( - this.currentTest.body.indexOf('assert') !== -1 || - this.currentTest.body.toLowerCase().indexOf('compare') !== -1 - ) - ) { - console.error('Found test without asserts: ' + this.currentTest.title); - } -}); - export function loadImage(url, callback) { const isBase64 = url.indexOf('base64') >= 0; if (isNode && !isBase64) { @@ -129,15 +117,15 @@ export function compareLayerAndCanvas(layer: Layer, canvas, tol?, secondTol?) { compareCanvases(layer.getCanvasElement(), canvas, tol, secondTol); } -export function cloneAndCompareLayer(layer: Layer, tol?) { +export function cloneAndCompareLayer(layer: Layer, tol?, secondTol?) { var layer2 = layer.clone(); layer.getStage().add(layer2); layer2.hide(); - compareLayers(layer, layer2, tol); + compareLayers(layer, layer2, tol, secondTol); } -export function compareLayers(layer1: Layer, layer2: Layer, tol?) { - compareLayerAndCanvas(layer1, layer2.getCanvasElement(), tol); +export function compareLayers(layer1: Layer, layer2: Layer, tol?, secondTol?) { + compareLayerAndCanvas(layer1, layer2.getCanvasElement(), tol, secondTol); } export function createCanvas() { @@ -160,24 +148,6 @@ export function showHit(layer) { Konva.UA.mobile = false; -afterEach(function () { - var isFailed = this.currentTest.state == 'failed'; - var isManual = this.currentTest.parent.title === 'Manual'; - - Konva.stages.forEach(function (stage) { - clearTimeout(stage.dblTimeout); - }); - - if (!isFailed && !isManual) { - Konva.stages.forEach(function (stage) { - stage.destroy(); - }); - if (Konva.DD._dragElements.size) { - throw 'Why drag elements are not cleaned?'; - } - } -}); - export function simulateMouseDown(stage, pos) { var top = isNode ? 0 : stage.content.getBoundingClientRect().top; @@ -324,17 +294,17 @@ export function simulateTouchEnd(stage, pos, changed?) { Konva.DD._endDragAfter(evt); } -export function simulatePointerDown(stage, pos) { +export function simulatePointerDown(stage: Stage, pos) { var top = isNode ? 0 : stage.content.getBoundingClientRect().top; - stage._mousedown({ + stage._pointerdown({ clientX: pos.x, clientY: pos.y + top, button: pos.button || 0, pointerId: pos.pointerId || 1, - }); + } as any); } -export function simulatePointerMove(stage, pos) { +export function simulatePointerMove(stage: Stage, pos) { var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var evt = { clientX: pos.x, @@ -343,11 +313,12 @@ export function simulatePointerMove(stage, pos) { pointerId: pos.pointerId || 1, }; - stage._mousemove(evt); + stage._pointermove(evt as any); Konva.DD._drag(evt); } -export function simulatePointerUp(stage, pos) { +export function simulatePointerUp(stage: Stage, pos) { + debugger; var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var evt = { clientX: pos.x, @@ -357,6 +328,16 @@ export function simulatePointerUp(stage, pos) { }; Konva.DD._endDragBefore(evt); - stage._mouseup(evt); + stage._pointerup(evt as any); Konva.DD._endDragAfter(evt); } + +function isClose(a, b) { + return Math.abs(a - b) < 0.000001; +} + +export const assertAlmostEqual = function (val1, val2) { + if (!isClose(val1, val2)) { + throw new Error('Expected ' + val1 + ' to be almost equal to ' + val2); + } +}; diff --git a/test/worker.js b/test/worker.js deleted file mode 100644 index 4a46d60e..00000000 --- a/test/worker.js +++ /dev/null @@ -1,193 +0,0 @@ -importScripts('../../konva.js'); - -Konva.Util.createCanvasElement = () => { - const canvas = new OffscreenCanvas(1, 1); - canvas.style = {}; - return canvas; -}; - -var stage = new Konva.Stage({ - width: 200, - height: 200, -}); - -var layer = new Konva.Layer(); -stage.add(layer); - -var topGroup = new Konva.Group(); -layer.add(topGroup); - -var counter = new Konva.Text({ - x: 5, - y: 35, -}); -topGroup.add(counter); - -var button = new Konva.Label({ - x: 5, - y: 5, - opacity: 0.75, -}); -topGroup.add(button); - -button.add( - new Konva.Tag({ - fill: 'black', - }) -); - -button.add( - new Konva.Text({ - text: 'Push me to add bunnies', - fontFamily: 'Calibri', - fontSize: 18, - padding: 5, - fill: 'white', - }) -); - -var circle = new Konva.Circle({ - x: stage.width() / 2, - y: stage.height() / 2, - radius: 20, - fill: 'red', - draggable: true, -}); -topGroup.add(circle); -layer.draw(); - -onmessage = function (evt) { - if (evt.data.canvas) { - var canvas = evt.data.canvas; - stage.setSize({ - width: canvas.width, - height: canvas.height, - }); - const ctx = canvas.getContext('2d'); - setInterval(() => { - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(layer.getCanvas()._canvas, 0, 0); - }, 16); - } - if (evt.data.eventName === 'mouseup') { - Konva.DD._endDragBefore(evt.data.event); - } - if (evt.data.eventName === 'touchend') { - Konva.DD._endDragBefore(evt.data.event); - } - if (evt.data.eventName === 'mousemove') { - Konva.DD._drag(evt.data.event); - } - if (evt.data.eventName === 'touchmove') { - Konva.DD._drag(evt.data.event); - } - if (evt.data.eventName === 'mouseup') { - Konva.DD._endDragAfter(evt.data.event); - } - if (evt.data.eventName === 'touchend') { - Konva.DD._endDragAfter(evt.data.event); - } - - if (evt.data.eventName) { - stage['_' + evt.data.eventName](evt.data.event); - } -}; - -function requestAnimationFrame(cb) { - setTimeout(cb, 16); -} -async function runBunnies() { - var bunnys = []; - var gravity = 0.75; - - var startBunnyCount = 100; - var isAdding = false; - var count = 0; - var amount = 10; - const imgBlob = await fetch('./assets/bunny.png').then((r) => r.blob()); - const img = await createImageBitmap(imgBlob); - - button.on('mousedown', function () { - isAdding = true; - }); - - button.on('mouseup', function () { - isAdding = false; - }); - - for (var i = 0; i < startBunnyCount; i++) { - var bunny = new Konva.Image({ - image: img, - transformsEnabled: 'position', - x: 10, - y: 10, - listening: false, - }); - - bunny.speedX = Math.random() * 10; - bunny.speedY = Math.random() * 10 - 5; - - bunnys.push(bunny); - counter.text('Bunnies number: ' + bunnys.length); - layer.add(bunny); - } - topGroup.moveToTop(); - layer.draw(); - - function update() { - var maxX = stage.width() - 10; - var minX = 0; - var maxY = stage.height() - 10; - var minY = 0; - if (isAdding) { - // add 10 at a time :) - - for (var i = 0; i < amount; i++) { - var bunny = new Konva.Image({ - image: img, - transformsEnabled: 'position', - x: 0, - y: 0, - listening: false, - }); - bunny.speedX = Math.random() * 10; - bunny.speedY = Math.random() * 10 - 5; - bunnys.push(bunny); - layer.add(bunny); - counter.text('Bunnies number: ' + bunnys.length); - count++; - } - topGroup.moveToTop(); - } - - for (var i = 0; i < bunnys.length; i++) { - var bunny = bunnys[i]; - bunny.setX(bunny.getX() + bunny.speedX); - bunny.setY(bunny.getY() + bunny.speedY); - bunny.speedY += gravity; - if (bunny.getX() > maxX - img.width) { - bunny.speedX *= -1; - bunny.setX(maxX - img.width); - } else if (bunny.getX() < minX) { - bunny.speedX *= -1; - bunny.setX(minX); - } - - if (bunny.getY() > maxY - img.height) { - bunny.speedY *= -0.85; - bunny.setY(maxY - img.height); - if (Math.random() > 0.5) { - bunny.speedY -= Math.random() * 6; - } - } else if (bunny.getY() < minY) { - bunny.speedY = 0; - bunny.setY(minY); - } - } - layer.drawScene(); - requestAnimationFrame(update); - } - update(); -} - -runBunnies();