TODO: Besides splitting this out from previous commit, should really avoid markdown field in favor of modifying jsdoc to report wherever it lays out "prettyprint"; still probably missing some one-liners; see https://github.com/google/code-prettify; update builds to confirm new stackblur is working; add below to CHANGES; add back for eslint-plugin-jsdoc once merged (though need new version `^3.9.1`); move any linting changes to other linting branch

- Refactoring (minor): Add favicon to canvas demo
- Linting (ESLint Markdown JavaScript): Add `eslint-plugin-markdown` with
  slightly loosened config (`no-undef` and `padded-blocks` off and
  `no-unused-vars` as a warning)
- Linting (ESLint JSDoc code comments): Add `eslint-plugin-jsdoc` and apply to
    JSDoc code comments
- Linting (ESLint): Completely avoid unescaped tabs in files
- Docs (Linting): Add linting info file
- npm: Rename `copy-deps` script to `copy`
- Refactoring: Add stackblur-canvas as a dependency and copy it in (until such time as we can do so for canvg)
master
Brett Zamir 2018-10-31 03:41:22 +08:00
parent afa5576ed1
commit 901c9547fe
17 changed files with 413 additions and 327 deletions

View File

@ -6,18 +6,37 @@
"parserOptions": { "parserOptions": {
"sourceType": "module" "sourceType": "module"
}, },
"plugins": ["compat", "qunit", "testcafe"], "plugins": ["compat", "qunit", "testcafe", "jsdoc", "markdown"],
"env": { "env": {
"node": false, "node": false,
"browser": true "browser": true
}, },
"settings": { "settings": {
"polyfills": ["url", "promises", "fetch", "queryselector"] "polyfills": ["url", "promises", "fetch", "queryselector"],
"jsdoc": {
"additionalTagNames": {
"customTags": []
},
"tagNamePreference": {
"arg": "param",
"return": "returns"
},
"allowOverrideWithoutParam": true,
"allowImplementsWithoutParam": true,
"allowAugmentsExtendsWithoutParam": true
}
}, },
"overrides": [{
"files": ["**/*.md"],
"rules": {
"no-undef": ["off"],
"no-unused-vars": ["warn"],
"padded-blocks": ["off"]
}
}],
"rules": { "rules": {
"semi": [2, "always"], "semi": [2, "always"],
"indent": ["error", 2, {"outerIIFEBody": 0}], "indent": ["error", 2, {"outerIIFEBody": 0}],
"no-tabs": 0,
"object-property-newline": 0, "object-property-newline": 0,
"one-var": 0, "one-var": 0,
"no-var": 2, "no-var": 2,
@ -25,6 +44,23 @@
"no-extra-semi": 2, "no-extra-semi": 2,
"quote-props": [2, "as-needed"], "quote-props": [2, "as-needed"],
"object-curly-spacing": ["error", "never"], "object-curly-spacing": ["error", "never"],
"jsdoc/check-param-names": 1,
"jsdoc/check-tag-names": 1,
"jsdoc/check-types": 1,
"jsdoc/newline-after-description": 0,
"jsdoc/require-description": 0,
"jsdoc/require-description-complete-sentence": 0,
"jsdoc/require-example": 0,
"jsdoc/require-hyphen-before-param-description": 0,
"jsdoc/require-param-description": 0,
"jsdoc/require-param": 1,
"jsdoc/require-param-name": 1,
"jsdoc/require-param-type": 1,
"jsdoc/require-returns-description": 0,
"jsdoc/require-returns-type": 1,
"jsdoc/no-undefined-types": ["off"],
"jsdoc/valid-types": ["error"],
"valid-jsdoc": ["off", { "valid-jsdoc": ["off", {
"prefer": { "prefer": {
"arg": "param", "arg": "param",

View File

@ -2,13 +2,26 @@
## 3.2.0 ## 3.2.0
- Refactoring: Avoid unnecessary addEventListener `false`; change internal - Refactoring: Avoid unnecessary `addEventListener` `false`; change internal
jPicker function to class (used with `new`) jPicker function to class (used with `new`)
- Linting (ESLint): Add `valid-jsdoc` rule and make fixes; but turn off for - Linting (ESLint): Add `valid-jsdoc` rule and make fixes, but turn off for
now due to <https://github.com/eslint/eslint/issues/11036> and now due to <https://github.com/eslint/doctrine/issues/221> and
<https://github.com/eslint/eslint/issues/11037> <https://github.com/eslint/doctrine/issues/222>
- Linting (ESLint compat): Add eslint-plugin-compat to get browser support - Linting (ESLint compat): Add `eslint-plugin-compat` to get browser support
warnings warnings
- Linting (ESLint Markdown JavaScript): Add `eslint-plugin-markdown` with
slightly loosened config (`no-undef` and `padded-blocks` off and
`no-unused-vars` as a warning)
- Linting (ESLint JSDoc code comments): Add `eslint-plugin-jsdoc` and apply to
JSDoc code comments though disable `jsdoc/valid-types` rule for now due to <https://github.com/Kuniwak/jsdoctypeparser/issues/47> and disable rule
`jsdoc/require-param` due to
<https://github.com/gajus/eslint-plugin-jsdoc/issues/100>; also of
possible interest: <https://github.com/AtomLinter/linter-eslint/issues/1192>,
<https://github.com/gajus/eslint-plugin-jsdoc/issues/103>,
<https://github.com/eslint/eslint-plugin-markdown/issues/109>,
<https://github.com/gajus/eslint-plugin-jsdoc/issues/101>,
<https://github.com/gajus/eslint-plugin-jsdoc/issues/99>,
<https://github.com/eslint/eslint/issues/11043>
- Docs (README): Indicate minimal polyfills needed for older browsers - Docs (README): Indicate minimal polyfills needed for older browsers
(IE <= 11, IE Mobile, Opera Mini, Blackberry Browser <= 10, (IE <= 11, IE Mobile, Opera Mini, Blackberry Browser <= 10,
Android Browser 4.4.3-4.4.4) Android Browser 4.4.3-4.4.4)

View File

@ -6,6 +6,7 @@
<script src="../editor/jquery.min.js"></script> <script src="../editor/jquery.min.js"></script>
<script src="../editor/jquery-ui/jquery-ui-1.8.17.custom.min.js"></script> <script src="../editor/jquery-ui/jquery-ui-1.8.17.custom.min.js"></script>
<style> #svgroot { overflow: hidden; } </style> <style> #svgroot { overflow: hidden; } </style>
<link rel="shortcut icon" type="image/x-icon" href="../editor/images/logo.png" />
</head> </head>
<body> <body>

29
docs/Linting.md Normal file
View File

@ -0,0 +1,29 @@
## Command line
```
npm run eslint
```
This will query both JavaScript files and will query JavaScript within
Markdown files. It will also check for some JSDoc issues.
## JSDoc
To check for JSDoc issues, besides the eslint script, one may run the
following to find any overly generic types in use (types should be as
specific as possible):
```
npm run types-doc
```
See also [ReleaseInstructions](./ReleaseInstructions.md).
## Atom usage
If using the Atom package `linter-eslint`, one may add `source.gfm` to the
"List of scopes to run ESLint on..." setting to get reporting of JavaScript
errors in Markdown.
One may also add `source.embedded.js` though configuration comments
and skip directives (not currently in use) don't seem to work there.

View File

@ -4,6 +4,8 @@
module.exports = { module.exports = {
plugins: ['plugins/markdown'], plugins: ['plugins/markdown'],
markdown: { markdown: {
// tags: ['examples']
/*
// "The highlighter function should escape the code block's contents and wrap them in <pre><code> tags" // "The highlighter function should escape the code block's contents and wrap them in <pre><code> tags"
highlight (code, language) { highlight (code, language) {
function ret () { function ret () {
@ -11,6 +13,8 @@ module.exports = {
return '<pre><code>' + code + ' in this language: ' + language + '</code></pre>'; return '<pre><code>' + code + ' in this language: ' + language + '</code></pre>';
} }
if (language !== 'js') { // E.g., we have one URL in some tutorial Markdown if (language !== 'js') { // E.g., we have one URL in some tutorial Markdown
// Seems to be only for full triple-backticked fences
// console.log('lll', code);
return ret(); return ret();
} }
@ -48,8 +52,8 @@ module.exports = {
console.log('\n' + code); console.log('\n' + code);
return ret(); return ret();
}, }
tags: [] */
}, },
recurseDepth: 10, recurseDepth: 10,
source: { source: {
@ -69,15 +73,15 @@ module.exports = {
}, },
templates: { templates: {
cleverLinks: true, cleverLinks: true,
monospaceLinks: false, monospaceLinks: false /* ,
default: { default: {
layoutFile: 'docs/layout.tmpl' layoutFile: 'docs/layout.tmpl'
} } */
}, },
opts: { opts: {
recurse: true, recurse: true,
verbose: true, verbose: true,
destination: 'docs/jsdoc', // destination: 'docs/jsdoc',
tutorials: 'docs/tutorials' tutorials: 'docs/tutorials'
} }
}; };

View File

@ -132,8 +132,10 @@ const crect = rect.cloneNode(false);
const retValue = (!crect.getAttribute('x').includes(',')); const retValue = (!crect.getAttribute('x').includes(','));
if (!retValue) { if (!retValue) {
// Todo: i18nize or remove // Todo: i18nize or remove
$.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' + $.alert(
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.'); 'NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' +
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.'
);
} }
return retValue; return retValue;
}()); }());
@ -152,13 +154,13 @@ rxform.appendItem(t1);
const r1 = rxform.getItem(0); const r1 = rxform.getItem(0);
// Todo: Do frame-independent instance checking // Todo: Do frame-independent instance checking
return r1 instanceof SVGTransform && t1 instanceof SVGTransform && return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
r1.type === t1.type && r1.angle === t1.angle && r1.type === t1.type && r1.angle === t1.angle &&
r1.matrix.a === t1.matrix.a && r1.matrix.a === t1.matrix.a &&
r1.matrix.b === t1.matrix.b && r1.matrix.b === t1.matrix.b &&
r1.matrix.c === t1.matrix.c && r1.matrix.c === t1.matrix.c &&
r1.matrix.d === t1.matrix.d && r1.matrix.d === t1.matrix.d &&
r1.matrix.e === t1.matrix.e && r1.matrix.e === t1.matrix.e &&
r1.matrix.f === t1.matrix.f; r1.matrix.f === t1.matrix.f;
}()); }());
// Public API // Public API

View File

@ -9,7 +9,7 @@
*/ */
import RGBColor from './rgbcolor.js'; import RGBColor from './rgbcolor.js';
import {canvasRGBA} from './StackBlur.js'; import {canvasRGBA} from '../external/stackblur-canvas/dist/stackblur-es.js';
let canvasRGBA_ = canvasRGBA; let canvasRGBA_ = canvasRGBA;
@ -57,7 +57,7 @@ export const setStackBlurCanvasRGBA = (cb) => {
* with `<canvas>` elements. * with `<canvas>` elements.
* @function module:canvg.canvg * @function module:canvg.canvg
* @param {HTMLCanvasElement|string} target canvas element or the id of a canvas element * @param {HTMLCanvasElement|string} target canvas element or the id of a canvas element
* @param {string|XMLDocument} s: svg string, url to svg file, or xml document * @param {string|XMLDocument} s - svg string, url to svg file, or xml document
* @param {module:canvg.CanvgOptions} [opts] Optional hash of options * @param {module:canvg.CanvgOptions} [opts] Optional hash of options
* @returns {Promise} All the function after the first render is completed with dom * @returns {Promise} All the function after the first render is completed with dom
*/ */

View File

@ -49,11 +49,10 @@ export default {
/** /**
* This function sets the content of element elt to the input XML. * This function sets the content of element elt to the input XML.
* @param {string} xmlString - The XML text * @param {string} xmlString - The XML text
* @param {Element} elt - the parent element to append to
* @returns {boolean} This function returns false if the set was unsuccessful, true otherwise. * @returns {boolean} This function returns false if the set was unsuccessful, true otherwise.
*/ */
function setForeignString (xmlString) { function setForeignString (xmlString) {
const elt = selElems[0]; const elt = selElems[0]; // The parent `Element` to append to
try { try {
// convert string into XML document // convert string into XML document
const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>'); const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');

View File

@ -1,80 +1,44 @@
/** /**
* StackBlur - a fast almost Gaussian Blur For Canvas * StackBlur - a fast almost Gaussian Blur For Canvas
*
In case you find this class useful - especially in commercial projects - * In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account * I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de * mario@quasimondo.de
*
Or support me on flattr: * Or support me on flattr:
https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript * {@link https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript}
* @module StackBlur * @module StackBlur
* @version 0.5 * @version 0.5
* @author Mario Klingemann * @author Mario Klingemann
Contact: mario@quasimondo.com * Contact: mario@quasimondo.com
Website: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html * Website: {@link http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html}
Twitter: @quasimondo * Twitter: @quasimondo
*
* @copyright (c) 2010 Mario Klingemann * @copyright (c) 2010 Mario Klingemann
*
Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without * files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, * restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell * copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the * copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following * Software is furnished to do so, subject to the following
conditions: * conditions:
*
The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
*
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
const mulTable = [512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];
const mulTable = [ const shgTable = [9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24];
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];
const shgTable = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24];
/** /**
* @param {string|HTMLImageElement} img * @param {string|HTMLImageElement} img
* @param {string|HTMLCanvasElement} canvas * @param {string|HTMLCanvasElement} canvas
@ -82,19 +46,23 @@ const shgTable = [
* @param {boolean} blurAlphaChannel * @param {boolean} blurAlphaChannel
* @returns {undefined} * @returns {undefined}
*/ */
function processImage (img, canvas, radius, blurAlphaChannel) {
function processImage(img, canvas, radius, blurAlphaChannel) {
if (typeof img === 'string') { if (typeof img === 'string') {
img = document.getElementById(img); img = document.getElementById(img);
} }
if (!img || !('naturalWidth' in img)) { if (!img || !('naturalWidth' in img)) {
return; return;
} }
const w = img.naturalWidth; const w = img.naturalWidth;
const h = img.naturalHeight; const h = img.naturalHeight;
if (typeof canvas === 'string') { if (typeof canvas === 'string') {
canvas = document.getElementById(canvas); canvas = document.getElementById(canvas);
} }
if (!canvas || !('getContext' in canvas)) { if (!canvas || !('getContext' in canvas)) {
return; return;
} }
@ -103,12 +71,13 @@ function processImage (img, canvas, radius, blurAlphaChannel) {
canvas.style.height = h + 'px'; canvas.style.height = h + 'px';
canvas.width = w; canvas.width = w;
canvas.height = h; canvas.height = h;
const context = canvas.getContext('2d'); const context = canvas.getContext('2d');
context.clearRect(0, 0, w, h); context.clearRect(0, 0, w, h);
context.drawImage(img, 0, 0); context.drawImage(img, 0, 0);
if (isNaN(radius) || radius < 1) { return; } if (isNaN(radius) || radius < 1) {
return;
}
if (blurAlphaChannel) { if (blurAlphaChannel) {
processCanvasRGBA(canvas, 0, 0, w, h, radius); processCanvasRGBA(canvas, 0, 0, w, h, radius);
@ -116,7 +85,6 @@ function processImage (img, canvas, radius, blurAlphaChannel) {
processCanvasRGB(canvas, 0, 0, w, h, radius); processCanvasRGB(canvas, 0, 0, w, h, radius);
} }
} }
/** /**
* @param {string|HTMLCanvasElement} canvas * @param {string|HTMLCanvasElement} canvas
* @param {Integer} topX * @param {Integer} topX
@ -126,10 +94,13 @@ function processImage (img, canvas, radius, blurAlphaChannel) {
* @throws {Error} * @throws {Error}
* @returns {ImageData} See {@link https://html.spec.whatwg.org/multipage/canvas.html#imagedata} * @returns {ImageData} See {@link https://html.spec.whatwg.org/multipage/canvas.html#imagedata}
*/ */
function getImageDataFromCanvas (canvas, topX, topY, width, height) {
function getImageDataFromCanvas(canvas, topX, topY, width, height) {
if (typeof canvas === 'string') { if (typeof canvas === 'string') {
canvas = document.getElementById(canvas); canvas = document.getElementById(canvas);
} }
if (!canvas || !('getContext' in canvas)) { if (!canvas || !('getContext' in canvas)) {
return; return;
} }
@ -142,7 +113,6 @@ function getImageDataFromCanvas (canvas, topX, topY, width, height) {
throw new Error('unable to access image data: ' + e); throw new Error('unable to access image data: ' + e);
} }
} }
/** /**
* @param {HTMLCanvasElement} canvas * @param {HTMLCanvasElement} canvas
* @param {Integer} topX * @param {Integer} topX
@ -152,17 +122,18 @@ function getImageDataFromCanvas (canvas, topX, topY, width, height) {
* @param {Float} radius * @param {Float} radius
* @returns {undefined} * @returns {undefined}
*/ */
function processCanvasRGBA (canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) { return; }
function processCanvasRGBA(canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) {
return;
}
radius |= 0; radius |= 0;
let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height); let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);
imageData = processImageDataRGBA(imageData, topX, topY, width, height, radius); imageData = processImageDataRGBA(imageData, topX, topY, width, height, radius);
canvas.getContext('2d').putImageData(imageData, topX, topY); canvas.getContext('2d').putImageData(imageData, topX, topY);
} }
/** /**
* @param {ImageData} imageData * @param {ImageData} imageData
* @param {Integer} topX * @param {Integer} topX
@ -172,52 +143,46 @@ function processCanvasRGBA (canvas, topX, topY, width, height, radius) {
* @param {Float} radius * @param {Float} radius
* @returns {ImageData} * @returns {ImageData}
*/ */
function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
function processImageDataRGBA(imageData, topX, topY, width, height, radius) {
const pixels = imageData.data; const pixels = imageData.data;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum, aSum, rOutSum, gOutSum, bOutSum, aOutSum, rInSum, gInSum, bInSum, aInSum, pr, pg, pb, pa, rbs;
const div = radius + radius + 1; // const w4 = width << 2;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum, aSum,
rOutSum, gOutSum, bOutSum, aOutSum,
rInSum, gInSum, bInSum, aInSum,
pr, pg, pb, pa, rbs;
const div = radius + radius + 1;
// const w4 = width << 2;
const widthMinus1 = width - 1; const widthMinus1 = width - 1;
const heightMinus1 = height - 1; const heightMinus1 = height - 1;
const radiusPlus1 = radius + 1; const radiusPlus1 = radius + 1;
const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
const stackStart = new BlurStack(); const stackStart = new BlurStack();
let stack = stackStart; let stack = stackStart;
let stackEnd; let stackEnd;
for (i = 1; i < div; i++) { for (i = 1; i < div; i++) {
stack = stack.next = new BlurStack(); stack = stack.next = new BlurStack();
if (i === radiusPlus1) { if (i === radiusPlus1) {
stackEnd = stack; stackEnd = stack;
} }
} }
stack.next = stackStart; stack.next = stackStart;
let stackIn = null; let stackIn = null;
let stackOut = null; let stackOut = null;
yw = yi = 0; yw = yi = 0;
const mulSum = mulTable[radius]; const mulSum = mulTable[radius];
const shgSum = shgTable[radius]; const shgSum = shgTable[radius];
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
rInSum = gInSum = bInSum = aInSum = rSum = gSum = bSum = aSum = 0; rInSum = gInSum = bInSum = aInSum = rSum = gSum = bSum = aSum = 0;
rOutSum = radiusPlus1 * (pr = pixels[yi]); rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
aOutSum = radiusPlus1 * (pa = pixels[yi + 3]); aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);
rSum += sumFactor * pr; rSum += sumFactor * pr;
gSum += sumFactor * pg; gSum += sumFactor * pg;
bSum += sumFactor * pb; bSum += sumFactor * pb;
aSum += sumFactor * pa; aSum += sumFactor * pa;
stack = stackStart; stack = stackStart;
for (i = 0; i < radiusPlus1; i++) { for (i = 0; i < radiusPlus1; i++) {
@ -230,28 +195,28 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
for (i = 1; i < radiusPlus1; i++) { for (i = 1; i < radiusPlus1; i++) {
p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
rSum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[p + 1])) * rbs; gSum += (stack.g = pg = pixels[p + 1]) * rbs;
bSum += (stack.b = (pb = pixels[p + 2])) * rbs; bSum += (stack.b = pb = pixels[p + 2]) * rbs;
aSum += (stack.a = (pa = pixels[p + 3])) * rbs; aSum += (stack.a = pa = pixels[p + 3]) * rbs;
rInSum += pr; rInSum += pr;
gInSum += pg; gInSum += pg;
bInSum += pb; bInSum += pb;
aInSum += pa; aInSum += pa;
stack = stack.next; stack = stack.next;
} }
stackIn = stackStart; stackIn = stackStart;
stackOut = stackEnd; stackOut = stackEnd;
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
pixels[yi + 3] = pa = (aSum * mulSum) >> shgSum; pixels[yi + 3] = pa = aSum * mulSum >> shgSum;
if (pa !== 0) { if (pa !== 0) {
pa = 255 / pa; pa = 255 / pa;
pixels[yi] = ((rSum * mulSum) >> shgSum) * pa; pixels[yi] = (rSum * mulSum >> shgSum) * pa;
pixels[yi + 1] = ((gSum * mulSum) >> shgSum) * pa; pixels[yi + 1] = (gSum * mulSum >> shgSum) * pa;
pixels[yi + 2] = ((bSum * mulSum) >> shgSum) * pa; pixels[yi + 2] = (bSum * mulSum >> shgSum) * pa;
} else { } else {
pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0; pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0;
} }
@ -260,57 +225,46 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
gSum -= gOutSum; gSum -= gOutSum;
bSum -= bOutSum; bSum -= bOutSum;
aSum -= aOutSum; aSum -= aOutSum;
rOutSum -= stackIn.r; rOutSum -= stackIn.r;
gOutSum -= stackIn.g; gOutSum -= stackIn.g;
bOutSum -= stackIn.b; bOutSum -= stackIn.b;
aOutSum -= stackIn.a; aOutSum -= stackIn.a;
p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;
p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; rInSum += stackIn.r = pixels[p];
gInSum += stackIn.g = pixels[p + 1];
rInSum += (stackIn.r = pixels[p]); bInSum += stackIn.b = pixels[p + 2];
gInSum += (stackIn.g = pixels[p + 1]); aInSum += stackIn.a = pixels[p + 3];
bInSum += (stackIn.b = pixels[p + 2]);
aInSum += (stackIn.a = pixels[p + 3]);
rSum += rInSum; rSum += rInSum;
gSum += gInSum; gSum += gInSum;
bSum += bInSum; bSum += bInSum;
aSum += aInSum; aSum += aInSum;
stackIn = stackIn.next; stackIn = stackIn.next;
rOutSum += pr = stackOut.r;
rOutSum += (pr = stackOut.r); gOutSum += pg = stackOut.g;
gOutSum += (pg = stackOut.g); bOutSum += pb = stackOut.b;
bOutSum += (pb = stackOut.b); aOutSum += pa = stackOut.a;
aOutSum += (pa = stackOut.a);
rInSum -= pr; rInSum -= pr;
gInSum -= pg; gInSum -= pg;
bInSum -= pb; bInSum -= pb;
aInSum -= pa; aInSum -= pa;
stackOut = stackOut.next; stackOut = stackOut.next;
yi += 4; yi += 4;
} }
yw += width; yw += width;
} }
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
gInSum = bInSum = aInSum = rInSum = gSum = bSum = aSum = rSum = 0; gInSum = bInSum = aInSum = rInSum = gSum = bSum = aSum = rSum = 0;
yi = x << 2; yi = x << 2;
rOutSum = radiusPlus1 * (pr = pixels[yi]); rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
aOutSum = radiusPlus1 * (pa = pixels[yi + 3]); aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);
rSum += sumFactor * pr; rSum += sumFactor * pr;
gSum += sumFactor * pg; gSum += sumFactor * pg;
bSum += sumFactor * pb; bSum += sumFactor * pb;
aSum += sumFactor * pa; aSum += sumFactor * pa;
stack = stackStart; stack = stackStart;
for (i = 0; i < radiusPlus1; i++) { for (i = 0; i < radiusPlus1; i++) {
@ -324,18 +278,15 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
yp = width; yp = width;
for (i = 1; i <= radius; i++) { for (i = 1; i <= radius; i++) {
yi = (yp + x) << 2; yi = yp + x << 2;
rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);
rSum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); gSum += (stack.g = pg = pixels[yi + 1]) * rbs;
gSum += (stack.g = (pg = pixels[yi + 1])) * rbs; bSum += (stack.b = pb = pixels[yi + 2]) * rbs;
bSum += (stack.b = (pb = pixels[yi + 2])) * rbs; aSum += (stack.a = pa = pixels[yi + 3]) * rbs;
aSum += (stack.a = (pa = pixels[yi + 3])) * rbs;
rInSum += pr; rInSum += pr;
gInSum += pg; gInSum += pg;
bInSum += pb; bInSum += pb;
aInSum += pa; aInSum += pa;
stack = stack.next; stack = stack.next;
if (i < heightMinus1) { if (i < heightMinus1) {
@ -346,14 +297,16 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
yi = x; yi = x;
stackIn = stackStart; stackIn = stackStart;
stackOut = stackEnd; stackOut = stackEnd;
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
p = yi << 2; p = yi << 2;
pixels[p + 3] = pa = (aSum * mulSum) >> shgSum; pixels[p + 3] = pa = aSum * mulSum >> shgSum;
if (pa > 0) { if (pa > 0) {
pa = 255 / pa; pa = 255 / pa;
pixels[p] = ((rSum * mulSum) >> shgSum) * pa; pixels[p] = (rSum * mulSum >> shgSum) * pa;
pixels[p + 1] = ((gSum * mulSum) >> shgSum) * pa; pixels[p + 1] = (gSum * mulSum >> shgSum) * pa;
pixels[p + 2] = ((bSum * mulSum) >> shgSum) * pa; pixels[p + 2] = (bSum * mulSum >> shgSum) * pa;
} else { } else {
pixels[p] = pixels[p + 1] = pixels[p + 2] = 0; pixels[p] = pixels[p + 1] = pixels[p + 2] = 0;
} }
@ -362,39 +315,31 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
gSum -= gOutSum; gSum -= gOutSum;
bSum -= bOutSum; bSum -= bOutSum;
aSum -= aOutSum; aSum -= aOutSum;
rOutSum -= stackIn.r; rOutSum -= stackIn.r;
gOutSum -= stackIn.g; gOutSum -= stackIn.g;
bOutSum -= stackIn.b; bOutSum -= stackIn.b;
aOutSum -= stackIn.a; aOutSum -= stackIn.a;
p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;
p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; rSum += rInSum += stackIn.r = pixels[p];
gSum += gInSum += stackIn.g = pixels[p + 1];
rSum += (rInSum += (stackIn.r = pixels[p])); bSum += bInSum += stackIn.b = pixels[p + 2];
gSum += (gInSum += (stackIn.g = pixels[p + 1])); aSum += aInSum += stackIn.a = pixels[p + 3];
bSum += (bInSum += (stackIn.b = pixels[p + 2]));
aSum += (aInSum += (stackIn.a = pixels[p + 3]));
stackIn = stackIn.next; stackIn = stackIn.next;
rOutSum += pr = stackOut.r;
rOutSum += (pr = stackOut.r); gOutSum += pg = stackOut.g;
gOutSum += (pg = stackOut.g); bOutSum += pb = stackOut.b;
bOutSum += (pb = stackOut.b); aOutSum += pa = stackOut.a;
aOutSum += (pa = stackOut.a);
rInSum -= pr; rInSum -= pr;
gInSum -= pg; gInSum -= pg;
bInSum -= pb; bInSum -= pb;
aInSum -= pa; aInSum -= pa;
stackOut = stackOut.next; stackOut = stackOut.next;
yi += width; yi += width;
} }
} }
return imageData; return imageData;
} }
/** /**
* @param {HTMLCanvasElement} canvas * @param {HTMLCanvasElement} canvas
* @param {Integer} topX * @param {Integer} topX
@ -404,16 +349,18 @@ function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
* @param {Float} radius * @param {Float} radius
* @returns {undefined} * @returns {undefined}
*/ */
function processCanvasRGB (canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) { return; }
radius |= 0;
function processCanvasRGB(canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) {
return;
}
radius |= 0;
let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height); let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);
imageData = processImageDataRGB(imageData, topX, topY, width, height, radius); imageData = processImageDataRGB(imageData, topX, topY, width, height, radius);
canvas.getContext('2d').putImageData(imageData, topX, topY); canvas.getContext('2d').putImageData(imageData, topX, topY);
} }
/** /**
* @param {ImageData} imageData * @param {ImageData} imageData
* @param {Integer} topX * @param {Integer} topX
@ -423,50 +370,44 @@ function processCanvasRGB (canvas, topX, topY, width, height, radius) {
* @param {Float} radius * @param {Float} radius
* @returns {ImageData} * @returns {ImageData}
*/ */
function processImageDataRGB (imageData, topX, topY, width, height, radius) {
function processImageDataRGB(imageData, topX, topY, width, height, radius) {
const pixels = imageData.data; const pixels = imageData.data;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum, rOutSum, gOutSum, bOutSum, rInSum, gInSum, bInSum, pr, pg, pb, rbs;
const div = radius + radius + 1; // const w4 = width << 2;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum,
rOutSum, gOutSum, bOutSum,
rInSum, gInSum, bInSum,
pr, pg, pb, rbs;
const div = radius + radius + 1;
// const w4 = width << 2;
const widthMinus1 = width - 1; const widthMinus1 = width - 1;
const heightMinus1 = height - 1; const heightMinus1 = height - 1;
const radiusPlus1 = radius + 1; const radiusPlus1 = radius + 1;
const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
const stackStart = new BlurStack(); const stackStart = new BlurStack();
let stack = stackStart; let stack = stackStart;
let stackEnd; let stackEnd;
for (i = 1; i < div; i++) { for (i = 1; i < div; i++) {
stack = stack.next = new BlurStack(); stack = stack.next = new BlurStack();
if (i === radiusPlus1) { if (i === radiusPlus1) {
stackEnd = stack; stackEnd = stack;
} }
} }
stack.next = stackStart; stack.next = stackStart;
let stackIn = null; let stackIn = null;
let stackOut = null; let stackOut = null;
yw = yi = 0; yw = yi = 0;
const mulSum = mulTable[radius]; const mulSum = mulTable[radius];
const shgSum = shgTable[radius]; const shgSum = shgTable[radius];
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
rInSum = gInSum = bInSum = rSum = gSum = bSum = 0; rInSum = gInSum = bInSum = rSum = gSum = bSum = 0;
rOutSum = radiusPlus1 * (pr = pixels[yi]); rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
rSum += sumFactor * pr; rSum += sumFactor * pr;
gSum += sumFactor * pg; gSum += sumFactor * pg;
bSum += sumFactor * pb; bSum += sumFactor * pb;
stack = stackStart; stack = stackStart;
for (i = 0; i < radiusPlus1; i++) { for (i = 0; i < radiusPlus1; i++) {
@ -478,71 +419,58 @@ function processImageDataRGB (imageData, topX, topY, width, height, radius) {
for (i = 1; i < radiusPlus1; i++) { for (i = 1; i < radiusPlus1; i++) {
p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
rSum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[p + 1])) * rbs; gSum += (stack.g = pg = pixels[p + 1]) * rbs;
bSum += (stack.b = (pb = pixels[p + 2])) * rbs; bSum += (stack.b = pb = pixels[p + 2]) * rbs;
rInSum += pr; rInSum += pr;
gInSum += pg; gInSum += pg;
bInSum += pb; bInSum += pb;
stack = stack.next; stack = stack.next;
} }
stackIn = stackStart; stackIn = stackStart;
stackOut = stackEnd; stackOut = stackEnd;
for (x = 0; x < width; x++) {
pixels[yi] = (rSum * mulSum) >> shgSum;
pixels[yi + 1] = (gSum * mulSum) >> shgSum;
pixels[yi + 2] = (bSum * mulSum) >> shgSum;
for (x = 0; x < width; x++) {
pixels[yi] = rSum * mulSum >> shgSum;
pixels[yi + 1] = gSum * mulSum >> shgSum;
pixels[yi + 2] = bSum * mulSum >> shgSum;
rSum -= rOutSum; rSum -= rOutSum;
gSum -= gOutSum; gSum -= gOutSum;
bSum -= bOutSum; bSum -= bOutSum;
rOutSum -= stackIn.r; rOutSum -= stackIn.r;
gOutSum -= stackIn.g; gOutSum -= stackIn.g;
bOutSum -= stackIn.b; bOutSum -= stackIn.b;
p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;
p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; rInSum += stackIn.r = pixels[p];
gInSum += stackIn.g = pixels[p + 1];
rInSum += (stackIn.r = pixels[p]); bInSum += stackIn.b = pixels[p + 2];
gInSum += (stackIn.g = pixels[p + 1]);
bInSum += (stackIn.b = pixels[p + 2]);
rSum += rInSum; rSum += rInSum;
gSum += gInSum; gSum += gInSum;
bSum += bInSum; bSum += bInSum;
stackIn = stackIn.next; stackIn = stackIn.next;
rOutSum += pr = stackOut.r;
rOutSum += (pr = stackOut.r); gOutSum += pg = stackOut.g;
gOutSum += (pg = stackOut.g); bOutSum += pb = stackOut.b;
bOutSum += (pb = stackOut.b);
rInSum -= pr; rInSum -= pr;
gInSum -= pg; gInSum -= pg;
bInSum -= pb; bInSum -= pb;
stackOut = stackOut.next; stackOut = stackOut.next;
yi += 4; yi += 4;
} }
yw += width; yw += width;
} }
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
gInSum = bInSum = rInSum = gSum = bSum = rSum = 0; gInSum = bInSum = rInSum = gSum = bSum = rSum = 0;
yi = x << 2; yi = x << 2;
rOutSum = radiusPlus1 * (pr = pixels[yi]); rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
rSum += sumFactor * pr; rSum += sumFactor * pr;
gSum += sumFactor * pg; gSum += sumFactor * pg;
bSum += sumFactor * pb; bSum += sumFactor * pb;
stack = stackStart; stack = stackStart;
for (i = 0; i < radiusPlus1; i++) { for (i = 0; i < radiusPlus1; i++) {
@ -555,16 +483,13 @@ function processImageDataRGB (imageData, topX, topY, width, height, radius) {
yp = width; yp = width;
for (i = 1; i <= radius; i++) { for (i = 1; i <= radius; i++) {
yi = (yp + x) << 2; yi = yp + x << 2;
rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);
rSum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); gSum += (stack.g = pg = pixels[yi + 1]) * rbs;
gSum += (stack.g = (pg = pixels[yi + 1])) * rbs; bSum += (stack.b = pb = pixels[yi + 2]) * rbs;
bSum += (stack.b = (pb = pixels[yi + 2])) * rbs;
rInSum += pr; rInSum += pr;
gInSum += pg; gInSum += pg;
bInSum += pb; bInSum += pb;
stack = stack.next; stack = stack.next;
if (i < heightMinus1) { if (i < heightMinus1) {
@ -575,82 +500,50 @@ function processImageDataRGB (imageData, topX, topY, width, height, radius) {
yi = x; yi = x;
stackIn = stackStart; stackIn = stackStart;
stackOut = stackEnd; stackOut = stackEnd;
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
p = yi << 2; p = yi << 2;
pixels[p] = (rSum * mulSum) >> shgSum; pixels[p] = rSum * mulSum >> shgSum;
pixels[p + 1] = (gSum * mulSum) >> shgSum; pixels[p + 1] = gSum * mulSum >> shgSum;
pixels[p + 2] = (bSum * mulSum) >> shgSum; pixels[p + 2] = bSum * mulSum >> shgSum;
rSum -= rOutSum; rSum -= rOutSum;
gSum -= gOutSum; gSum -= gOutSum;
bSum -= bOutSum; bSum -= bOutSum;
rOutSum -= stackIn.r; rOutSum -= stackIn.r;
gOutSum -= stackIn.g; gOutSum -= stackIn.g;
bOutSum -= stackIn.b; bOutSum -= stackIn.b;
p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;
p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; rSum += rInSum += stackIn.r = pixels[p];
gSum += gInSum += stackIn.g = pixels[p + 1];
rSum += (rInSum += (stackIn.r = pixels[p])); bSum += bInSum += stackIn.b = pixels[p + 2];
gSum += (gInSum += (stackIn.g = pixels[p + 1]));
bSum += (bInSum += (stackIn.b = pixels[p + 2]));
stackIn = stackIn.next; stackIn = stackIn.next;
rOutSum += pr = stackOut.r;
rOutSum += (pr = stackOut.r); gOutSum += pg = stackOut.g;
gOutSum += (pg = stackOut.g); bOutSum += pb = stackOut.b;
bOutSum += (pb = stackOut.b);
rInSum -= pr; rInSum -= pr;
gInSum -= pg; gInSum -= pg;
bInSum -= pb; bInSum -= pb;
stackOut = stackOut.next; stackOut = stackOut.next;
yi += width; yi += width;
} }
} }
return imageData; return imageData;
} }
/** /**
* *
*/ */
export class BlurStack {
constructor () {
class BlurStack {
constructor() {
this.r = 0; this.r = 0;
this.g = 0; this.g = 0;
this.b = 0; this.b = 0;
this.a = 0; this.a = 0;
this.next = null; this.next = null;
} }
} }
export { export { BlurStack, processImage as image, processCanvasRGBA as canvasRGBA, processCanvasRGB as canvasRGB, processImageDataRGBA as imageDataRGBA, processImageDataRGB as imageDataRGB };
/**
* @class module:StackBlur.image
* @see module:StackBlur~processImage
*/
processImage as image,
/**
* @class module:StackBlur.canvasRGBA
* @see module:StackBlur~processCanvasRGBA
*/
processCanvasRGBA as canvasRGBA,
/**
* @class module:StackBlur.canvasRGB
* @see module:StackBlur~processCanvasRGB
*/
processCanvasRGB as canvasRGB,
/**
* @class module:StackBlur.imageDataRGBA
* @see module:StackBlur~processImageDataRGBA
*/
processImageDataRGBA as imageDataRGBA,
/**
* @class module:StackBlur.imageDataRGB
* @see module:StackBlur~processImageDataRGB
*/
processImageDataRGB as imageDataRGB
};

View File

@ -185,7 +185,6 @@ class Layer {
/** /**
* Remove this layer's group from the DOM. No more functions on group can be called after this. * Remove this layer's group from the DOM. No more functions on group can be called after this.
* @param {SVGGElement} children - The children to append to this layer.
* @returns {SVGGElement} The layer SVG group that was just removed. * @returns {SVGGElement} The layer SVG group that was just removed.
*/ */
removeGroup () { removeGroup () {

View File

@ -324,15 +324,17 @@ function loadSvgString (str, callback) {
/** /**
* @function module:SVGEditor~getImportLocale * @function module:SVGEditor~getImportLocale
* @param {string} defaultLang * @param {PlainObject} defaults
* @param {string} defaultName * @param {string} defaults.defaultLang
* @param {string} defaults.defaultName
* @returns {module:SVGEditor~ImportLocale} * @returns {module:SVGEditor~ImportLocale}
*/ */
function getImportLocale ({defaultLang, defaultName}) { function getImportLocale ({defaultLang, defaultName}) {
/** /**
* @function module:SVGEditor~ImportLocale * @function module:SVGEditor~ImportLocale
* @param {string} [name] Defaults to `defaultName` of {@link module:SVGEditor~getImportLocale} * @param {PlainObject} localeInfo
* @param {string} [lang=defaultLang] Defaults to `defaultLang` of {@link module:SVGEditor~getImportLocale} * @param {string} [localeInfo.name] Defaults to `defaultName` of {@link module:SVGEditor~getImportLocale}
* @param {string} [localeInfo.lang=defaultLang] Defaults to `defaultLang` of {@link module:SVGEditor~getImportLocale}
* @returns {Promise} Resolves to {@link module:locale.LocaleStrings} * @returns {Promise} Resolves to {@link module:locale.LocaleStrings}
*/ */
return async function importLocale ({name = defaultName, lang = defaultLang} = {}) { return async function importLocale ({name = defaultName, lang = defaultLang} = {}) {
@ -2771,7 +2773,7 @@ editor.init = function () {
const allHolders = {}; const allHolders = {};
/** /**
* @param {GenericObject.<string, module:SVGEditor.ToolButton>} holders Key is a selector * @param {PlainObject.<string, module:SVGEditor.ToolButton>} holders Key is a selector
* @returns {undefined} * @returns {undefined}
*/ */
const setupFlyouts = function (holders) { const setupFlyouts = function (holders) {
@ -3440,8 +3442,9 @@ editor.init = function () {
'updateCanvas', 'updateCanvas',
/** /**
* @param {external:Window} win * @param {external:Window} win
* @param {false} center * @param {PlainObject} centerInfo
* @param {module:math.XYObject} newCtr * @param {false} centerInfo.center
* @param {module:math.XYObject} centerInfo.newCtr
* @listens module:svgcanvas.SvgCanvas#event:updateCanvas * @listens module:svgcanvas.SvgCanvas#event:updateCanvas
* @returns {undefined} * @returns {undefined}
*/ */
@ -6042,8 +6045,9 @@ editor.ready(() => {
let extensionsAdded = false; let extensionsAdded = false;
const messageQueue = []; const messageQueue = [];
/** /**
* @param {Any} data * @param {PlainObject} info
* @param {string} origin * @param {Any} info.data
* @param {string} info.origin
* @fires module:svgcanvas.SvgCanvas#event:message * @fires module:svgcanvas.SvgCanvas#event:message
* @returns {undefined} * @returns {undefined}
*/ */

View File

@ -814,8 +814,9 @@ pathModule.init(
return rubberBox; return rubberBox;
}, },
/** /**
* @param {boolean} closedSubpath * @param {PlainObject} ptsInfo
* @param {SVGCircleElement[]} grips * @param {boolean} ptsInfo.closedSubpath
* @param {SVGCircleElement[]} ptsInfo.grips
* @fires module:svgcanvas.SvgCanvas#event:pointsAdded * @fires module:svgcanvas.SvgCanvas#event:pointsAdded
* @fires module:svgcanvas.SvgCanvas#event:selected * @fires module:svgcanvas.SvgCanvas#event:selected
* @returns {undefined} * @returns {undefined}
@ -828,8 +829,9 @@ pathModule.init(
call('selected', grips); call('selected', grips);
}, },
/** /**
* @param {ChangeElementCommand} cmd * @param {PlainObject} changes
* @param {SVGPathElement} elem * @param {ChangeElementCommand} changes.cmd
* @param {SVGPathElement} changes.elem
* @fires module:svgcanvas.SvgCanvas#event:changed * @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {undefined} * @returns {undefined}
*/ */
@ -3809,7 +3811,7 @@ this.save = function (opts) {
}; };
/** /**
* @typedef {GenericObject} module:svgcanvas.IssuesAndCodes * @typedef {PlainObject} module:svgcanvas.IssuesAndCodes
* @property {string[]} issueCodes The locale-independent code names * @property {string[]} issueCodes The locale-independent code names
* @property {string[]} issues The localized descriptions * @property {string[]} issues The localized descriptions
*/ */

View File

@ -1346,6 +1346,7 @@ export const copyElem = function (el, getNextId) {
/** /**
* Overwrite methods for unit testing. * Overwrite methods for unit testing.
* @function module:utilities.mock * @function module:utilities.mock
* @param {PlainObject} mockMethods
* @returns {undefined} * @returns {undefined}
*/ */
export const mock = ({ export const mock = ({

122
package-lock.json generated
View File

@ -1131,7 +1131,7 @@
}, },
"async": { "async": {
"version": "0.2.6", "version": "0.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz", "resolved": "http://registry.npmjs.org/async/-/async-0.2.6.tgz",
"integrity": "sha1-rT83PZJJrjJIgVZVgryQ4VKrvWg=", "integrity": "sha1-rT83PZJJrjJIgVZVgryQ4VKrvWg=",
"dev": true "dev": true
}, },
@ -1883,7 +1883,7 @@
}, },
"regjsgen": { "regjsgen": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
"integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
"dev": true "dev": true
}, },
@ -2901,6 +2901,15 @@
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
"dev": true "dev": true
}, },
"comment-parser": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.5.0.tgz",
"integrity": "sha512-sNM+U6+Kme4WDxjVJ+1N92BQm5SC0RbFD4TLXLJ+hThX3crW1q+7ObjUhylMYAjR/rWdB+7ZNLPjujVbGruHGQ==",
"dev": true,
"requires": {
"readable-stream": "^2.0.4"
}
},
"component-emitter": { "component-emitter": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
@ -3686,6 +3695,85 @@
} }
} }
}, },
"eslint-plugin-jsdoc": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-3.9.1.tgz",
"integrity": "sha512-kSQ62uraDa9QSv/5YncMZoKLScqrq7kt4lGGokH7Iyuqqzo2rZhERdrkPELLdnX4jWwkh+gYFZBt0PVIseKH1g==",
"dev": true,
"requires": {
"comment-parser": "^0.5.0",
"jsdoctypeparser": "^2.0.0-alpha-8",
"lodash": "^4.17.11"
}
},
"eslint-plugin-markdown": {
"version": "1.0.0-rc.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.0-rc.0.tgz",
"integrity": "sha512-28Ioje4p8QAmpxDL91jR4rU+x6+UEx6IW/b+nVnXuS7CMCuOttQl+8BGSu04bm0+8ibOlNsvt5QXc7D847oOkw==",
"dev": true,
"requires": {
"object-assign": "^4.0.1",
"remark-parse": "^5.0.0",
"unified": "^6.1.2"
},
"dependencies": {
"remark-parse": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz",
"integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==",
"dev": true,
"requires": {
"collapse-white-space": "^1.0.2",
"is-alphabetical": "^1.0.0",
"is-decimal": "^1.0.0",
"is-whitespace-character": "^1.0.0",
"is-word-character": "^1.0.0",
"markdown-escapes": "^1.0.0",
"parse-entities": "^1.1.0",
"repeat-string": "^1.5.4",
"state-toggle": "^1.0.0",
"trim": "0.0.1",
"trim-trailing-lines": "^1.0.0",
"unherit": "^1.0.4",
"unist-util-remove-position": "^1.0.0",
"vfile-location": "^2.0.0",
"xtend": "^4.0.1"
}
},
"unified": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
"integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
"dev": true,
"requires": {
"bail": "^1.0.0",
"extend": "^3.0.0",
"is-plain-obj": "^1.1.0",
"trough": "^1.0.0",
"vfile": "^2.0.0",
"x-is-string": "^0.1.0"
}
},
"vfile": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
"integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
"dev": true,
"requires": {
"is-buffer": "^1.1.4",
"replace-ext": "1.0.0",
"unist-util-stringify-position": "^1.0.0",
"vfile-message": "^1.0.0"
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
"dev": true
}
}
},
"eslint-plugin-node": { "eslint-plugin-node": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-8.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-8.0.0.tgz",
@ -5948,6 +6036,12 @@
"underscore": "~1.8.3" "underscore": "~1.8.3"
} }
}, },
"jsdoctypeparser": {
"version": "2.0.0-alpha-8",
"resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-2.0.0-alpha-8.tgz",
"integrity": "sha1-uvE3+44qVYgQrc8Z0tKi9oDpCl8=",
"dev": true
},
"jsdom": { "jsdom": {
"version": "13.0.0", "version": "13.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-13.0.0.tgz", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-13.0.0.tgz",
@ -8887,6 +8981,12 @@
"tweetnacl": "~0.14.0" "tweetnacl": "~0.14.0"
} }
}, },
"stackblur-canvas": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.0.0.tgz",
"integrity": "sha512-660gH1SpjeKyfUYnne9nuIya7CDGds6NdIrxzOToSgaSlOqbh7UYGP9VlxlQ8IX7af/nPuAHLkN03l84OesX7Q==",
"dev": true
},
"stackframe": { "stackframe": {
"version": "0.3.1", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
@ -9240,7 +9340,7 @@
"dependencies": { "dependencies": {
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true "dev": true
} }
@ -9428,7 +9528,7 @@
}, },
"core-js": { "core-js": {
"version": "1.2.7", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
"dev": true "dev": true
} }
@ -9555,7 +9655,7 @@
}, },
"core-js": { "core-js": {
"version": "1.2.7", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
"dev": true "dev": true
}, },
@ -9584,37 +9684,37 @@
}, },
"testcafe-reporter-json": { "testcafe-reporter-json": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/testcafe-reporter-json/-/testcafe-reporter-json-2.1.0.tgz", "resolved": "http://registry.npmjs.org/testcafe-reporter-json/-/testcafe-reporter-json-2.1.0.tgz",
"integrity": "sha1-gLm1pt/y7h3h+R4mcHBsFHLmQAY=", "integrity": "sha1-gLm1pt/y7h3h+R4mcHBsFHLmQAY=",
"dev": true "dev": true
}, },
"testcafe-reporter-list": { "testcafe-reporter-list": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.1.0.tgz", "resolved": "http://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.1.0.tgz",
"integrity": "sha1-n6ifcbl9Pf5ktDAtXiJ97mmuxrk=", "integrity": "sha1-n6ifcbl9Pf5ktDAtXiJ97mmuxrk=",
"dev": true "dev": true
}, },
"testcafe-reporter-minimal": { "testcafe-reporter-minimal": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.1.0.tgz", "resolved": "http://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.1.0.tgz",
"integrity": "sha1-Z28DVHY0FDxurzq1KGgnOkvr9CE=", "integrity": "sha1-Z28DVHY0FDxurzq1KGgnOkvr9CE=",
"dev": true "dev": true
}, },
"testcafe-reporter-spec": { "testcafe-reporter-spec": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/testcafe-reporter-spec/-/testcafe-reporter-spec-2.1.1.tgz", "resolved": "http://registry.npmjs.org/testcafe-reporter-spec/-/testcafe-reporter-spec-2.1.1.tgz",
"integrity": "sha1-gVb87Q9RMkhlWa1WC8gGdkaSdew=", "integrity": "sha1-gVb87Q9RMkhlWa1WC8gGdkaSdew=",
"dev": true "dev": true
}, },
"testcafe-reporter-xunit": { "testcafe-reporter-xunit": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz", "resolved": "http://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz",
"integrity": "sha1-5tZsVyzhWvJmcGrw/WELKoQd1EM=", "integrity": "sha1-5tZsVyzhWvJmcGrw/WELKoQd1EM=",
"dev": true "dev": true
}, },
"text-encoding": { "text-encoding": {
"version": "0.6.4", "version": "0.6.4",
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", "resolved": "http://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
"integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
"dev": true "dev": true
}, },

View File

@ -18,9 +18,9 @@
"build-doc": "rm -rf docs/jsdoc/*;jsdoc --pedantic -c docs/jsdoc-config.js editor", "build-doc": "rm -rf docs/jsdoc/*;jsdoc --pedantic -c docs/jsdoc-config.js editor",
"build-html": "node build-html.js", "build-html": "node build-html.js",
"compress-images": "imageoptim 'chrome-app/*.png' && imageoptim 'editor/extensions/*.png' && imageoptim 'editor/spinbtn/*.png' && imageoptim 'editor/jgraduate/images/*.{png,gif}' && imageoptim 'editor/images/*.png'", "compress-images": "imageoptim 'chrome-app/*.png' && imageoptim 'editor/extensions/*.png' && imageoptim 'editor/spinbtn/*.png' && imageoptim 'editor/jgraduate/images/*.{png,gif}' && imageoptim 'editor/images/*.png'",
"copy-deps": "cp node_modules/load-stylesheets/dist/index-es.js editor/external/load-stylesheets/index-es.js && cp node_modules/@babel/polyfill/dist/polyfill.min.js editor/external/@babel/polyfill/polyfill.min.js && cp node_modules/@babel/polyfill/dist/polyfill.js editor/external/@babel/polyfill/polyfill.js && cp node_modules/jamilih/dist/jml-es.js editor/external/jamilih/jml-es.js && cp node_modules/query-result/esm/index.js editor/external/query-result/esm/index.js && cp node_modules/qr-manipulation/dist/index-es.js editor/external/qr-manipulation/dist/index-es.js", "copy": "cp node_modules/load-stylesheets/dist/index-es.js editor/external/load-stylesheets/index-es.js && cp node_modules/@babel/polyfill/dist/polyfill.min.js editor/external/@babel/polyfill/polyfill.min.js && cp node_modules/@babel/polyfill/dist/polyfill.js editor/external/@babel/polyfill/polyfill.js && cp node_modules/jamilih/dist/jml-es.js editor/external/jamilih/jml-es.js && cp node_modules/query-result/esm/index.js editor/external/query-result/esm/index.js && cp node_modules/qr-manipulation/dist/index-es.js editor/external/qr-manipulation/dist/index-es.js && cp node_modules/stackblur-canvas/dist/stackblur-es.js editor/external/stackblur-canvas/dist/stackblur-es.js",
"remark": "remark -q -f .", "remark": "remark -q -f .",
"eslint": "eslint .", "eslint": "eslint --ext js,md .",
"rollup": "rollup -c", "rollup": "rollup -c",
"start-embedded": "echo \"Open file to http://localhost:8000/editor/embedapi.html\" && static -p 8000 | static -p 8001 -H '{\"Access-Control-Allow-Origin\": \"*\"}'", "start-embedded": "echo \"Open file to http://localhost:8000/editor/embedapi.html\" && static -p 8000 | static -p 8001 -H '{\"Access-Control-Allow-Origin\": \"*\"}'",
"start": "echo \"Open file to http://localhost:8000/test/all_tests.html\" && static -p 8000", "start": "echo \"Open file to http://localhost:8000/test/all_tests.html\" && static -p 8000",
@ -83,6 +83,8 @@
"eslint-config-standard": "12.0.0", "eslint-config-standard": "12.0.0",
"eslint-plugin-compat": "2.6.3", "eslint-plugin-compat": "2.6.3",
"eslint-plugin-import": "2.14.0", "eslint-plugin-import": "2.14.0",
"eslint-plugin-jsdoc": "https://github.com/brettz9/eslint-plugin-jsdoc#origin/ArrayPattern",
"eslint-plugin-markdown": "^1.0.0-rc.0",
"eslint-plugin-node": "8.0.0", "eslint-plugin-node": "8.0.0",
"eslint-plugin-promise": "4.0.1", "eslint-plugin-promise": "4.0.1",
"eslint-plugin-qunit": "^4.0.0", "eslint-plugin-qunit": "^4.0.0",
@ -111,6 +113,7 @@
"rollup-plugin-terser": "^3.0.0", "rollup-plugin-terser": "^3.0.0",
"sinon": "^7.1.1", "sinon": "^7.1.1",
"sinon-test": "^2.4.0", "sinon-test": "^2.4.0",
"stackblur-canvas": "^2.0.0",
"testcafe": "^0.23.0" "testcafe": "^0.23.0"
} }
} }

View File

@ -15,7 +15,7 @@ QUnit.test('Test sanitizeSvg() strips ws from style attr', function (assert) {
assert.expect(2); assert.expect(2);
const rect = document.createElementNS(NS.SVG, 'rect'); const rect = document.createElementNS(NS.SVG, 'rect');
rect.setAttribute('style', 'stroke: blue ; stroke-width : 40;'); rect.setAttribute('style', 'stroke: blue ;\t\tstroke-width :\t\t40;');
// sanitizeSvg() requires the node to have a parent and a document. // sanitizeSvg() requires the node to have a parent and a document.
svg.append(rect); svg.append(rect);
sanitize.sanitizeSvg(rect); sanitize.sanitizeSvg(rect);

View File

@ -89,27 +89,27 @@ const mockPathActions = {
// Chrome // Chrome
// Before Optimization // Before Optimization
// Pass1 svgCanvas.getStrokedBBox total ms 4,218, ave ms 41.0, min/max 37 51 // Pass1 svgCanvas.getStrokedBBox total ms 4,218, ave ms 41.0, min/max 37 51
// Pass2 svgCanvas.getStrokedBBox total ms 4,458, ave ms 43.3, min/max 32 63 // Pass2 svgCanvas.getStrokedBBox total ms 4,458, ave ms 43.3, min/max 32 63
// Optimized Code // Optimized Code
// Pass1 svgCanvas.getStrokedBBox total ms 1,112, ave ms 10.8, min/max 9 20 // Pass1 svgCanvas.getStrokedBBox total ms 1,112, ave ms 10.8, min/max 9 20
// Pass2 svgCanvas.getStrokedBBox total ms 34, ave ms 0.3, min/max 0 20 // Pass2 svgCanvas.getStrokedBBox total ms 34, ave ms 0.3, min/max 0 20
// Firefox // Firefox
// Before Optimization // Before Optimization
// Pass1 svgCanvas.getStrokedBBox total ms 3,794, ave ms 36.8, min/max 33 48 // Pass1 svgCanvas.getStrokedBBox total ms 3,794, ave ms 36.8, min/max 33 48
// Pass2 svgCanvas.getStrokedBBox total ms 4,049, ave ms 39.3, min/max 28 53 // Pass2 svgCanvas.getStrokedBBox total ms 4,049, ave ms 39.3, min/max 28 53
// Optimized Code // Optimized Code
// Pass1 svgCanvas.getStrokedBBox total ms 104, ave ms 1.0, min/max 0 23 // Pass1 svgCanvas.getStrokedBBox total ms 104, ave ms 1.0, min/max 0 23
// Pass2 svgCanvas.getStrokedBBox total ms 71, ave ms 0.7, min/max 0 23 // Pass2 svgCanvas.getStrokedBBox total ms 71, ave ms 0.7, min/max 0 23
// Safari // Safari
// Before Optimization // Before Optimization
// Pass1 svgCanvas.getStrokedBBox total ms 4,840, ave ms 47.0, min/max 45 62 // Pass1 svgCanvas.getStrokedBBox total ms 4,840, ave ms 47.0, min/max 45 62
// Pass2 svgCanvas.getStrokedBBox total ms 4,849, ave ms 47.1, min/max 34 62 // Pass2 svgCanvas.getStrokedBBox total ms 4,849, ave ms 47.1, min/max 34 62
// Optimized Code // Optimized Code
// Pass1 svgCanvas.getStrokedBBox total ms 42, ave ms 0.4, min/max 0 23 // Pass1 svgCanvas.getStrokedBBox total ms 42, ave ms 0.4, min/max 0 23
// Pass2 svgCanvas.getStrokedBBox total ms 17, ave ms 0.2, min/max 0 23 // Pass2 svgCanvas.getStrokedBBox total ms 17, ave ms 0.2, min/max 0 23
QUnit.test('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function (assert) { QUnit.test('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function (assert) {
const done = assert.async(); const done = assert.async();