diff --git a/.travis.yml b/.travis.yml index 0954607e..036ee4f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,12 @@ language: node_js # Follow https://github.com/nodejs/LTS to decide when to remove a version node_js: -- 9 +# Stable version is temporarily disabled due to a bug in resemblejs package with +# node v12 (https://github.com/orgs/paperjs/teams/contributors/discussions/12). +# - stable +# - 11 +- 10 - 8 -# 6.13 and 6.14 causing unreasonable errors in SymbolDefinition.initialize. -# https://travis-ci.org/paperjs/paper.js/jobs/434854796 -# To avoid these versions, we specify version to 6.12 as temporary solution. -# See https://github.com/paperjs/paper.js/issues/1523 -- 6.12 sudo: false env: matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b5b5ff..7df06fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,83 @@ # Change Log +## `0.12.3` + +### Fixed + +- Fix regression in `Color` change propagation (#1672, #1674). +- SVG Export: Fix viewport size of exported `Symbol` (#1668). +- Handle non-invertible matrices in `Item#contains()` (#1651). +- Improve documentation for `Item#clipMask` (#1673). +- Improve TypeScript definitions (#1659, #1663, #1664, #1667) + +### Added + +- Add documentation for `Item#internalBounds`. + +## `0.12.2` + +### Fixed + +- Fix drawing with compound-paths as clip-items (#1361). +- Fix drawing of path selection with small handle size (#1327). +- Do not ignore `Group#clipItem.matrix` in `Group#internalBounds` (#1427). +- Correctly calculate bounds with nested empty items (#1467). +- Fix color change propagation on groups (#1152). +- Fix `Path#arcTo()` where `from` and `to` points are equal (#1613). +- Improve `new Raster(size[, position])` constructor (#1621). +- SVG Export: Fix error when `Item#matrix` is not invertible (#1580). +- SVG Export: Include missing viewBox attribute (#1576). +- SVG Import: Use correct default values for gradients (#1632, #1660). +- SVG Import: Add basic `` support (#1597). +- JSON Import: Prevent `Item#insert()` method from being overridden (#1392). +- PaperScript: Fix issues with increment/decrement operators (#1450, #1611). + +## `0.12.1` + +### Added + +- Add TypeScript definition, automatically generated from JSDoc comments + (#1612). +- Support `new Raster(size[, position])` constructor. +- Expose `Raster#context` accessor. +- Implement `Raster#clear()` method to clear associated canvas context. +- Node.js: Add support for Node.js v11 and v12. + +### Fixed + +- Fix parsing of CSS colors with spaces in parentheses (#1629). +- Improve `Color.random()` documentation. +- Fix `Tween#then()` documentation. + +### Removed + +- Node.js: Remove support for Node.js v6. + +## `0.12.0` + +### News + +Another release, another new member on the team: Please welcome +[@arnoson](https://github.com/arnoson), who has worked hard on the all new +animation support, exposed through the `Tween` class and its various methods on +the `Item` class, see below for details: + +### Added + +- Add new `Tween` class and related methods on `Item`, to animate and + interpolate their various properties, including colors, sub-properties, etc.: + `Item#tween(from, to, options)`, `Item#tween(to, options)`, + `Item#tween(options)`, `Item#tweenFrom(from, options)`, + `Item#tweenTo(to, options)` + +### Fixed + +- Only draw Raster if image is not empty (#1320). +- Emit mousedrag events on correct items when covered by other items (#1465). +- Fix drawing issues of bounds and position with `Group#selectedColor` (#1571). +- Fix `Item.once()` to actually only emit event once. +- Various documentation fixes and improvements (#1399). + ## `0.11.8` ### News @@ -59,6 +137,7 @@ the fixes and additions from the past two weeks: ## `0.11.5` ### Fixed + - Fix `Curve#isSelected()` to correctly reflect the state of `#handle1` (#1378). - Key Events: Fix auto-filling issue on Chrome (#1358, #1365). - Boolean: Check that overlaps are on the right path (#1321). @@ -71,38 +150,42 @@ the fixes and additions from the past two weeks: ## `0.11.4` ### Changed + - Node.js: Add support for v8, and keep testing v4, v6, v7 in Travis CI. ## `0.11.3` ### Fixed -- Mouse Events: Fix item-based `doubleclick` events (#1316). +- Mouse Events: Fix item-based `doubleclick` events (#1316). - Overhaul the caching of bounds and matrix decomposition, improving reliability of `Item#rotation` and `#scaling` and fixing situations caused by wrongly caching `Item#position` and `#bounds` values. - - Prevent consumed properties in object literal constructors from being set on the instance. ### Changed + - Make all functions and accessors enumerable on all Paper.js classes. ## `0.11.2` ### Fixed + - PaperScript: Fix a parsing error in math operations without white-space (#1314). ## `0.11.1` ### Fixed + - Bring back deactivation of Node.js modules on browsers. This has most probably broken Webpack bundling in `0.11.0`. ## `0.11.0` ### Changed + - Separate `paper` module on NPM into: `paper`, `paper-jsdom` and `paper-jsdom-canvas` (#1252): - `paper` is the main library, and can be used directly in a browser @@ -115,12 +198,14 @@ the fixes and additions from the past two weeks: [jsdom](https://github.com/tmpvar/jsdom). ### Added + - PaperScript: Support newer, external versions of Acorn.js for PaperScript parsing, opening the doors to ES 2015 (#1183, #1275). - Hit Tests: Implement `options.position` to hit `Item#position` (#1249). - Split `Item#copyTo()` into `#addTo()` and `#copyTo()`. ### Fixed + - Intersections: Bring back special handling of curve end-points (#1284). - Intersections: Correctly handle `Item#applyMatrix = false` (#1289). - Boolean: Bring back on-path winding handling (#1281). @@ -154,6 +239,7 @@ the fixes and additions from the past two weeks: ## `0.10.3` ### Changed + - Node.js: Support v7, and keep testing v4 up to v7 in Travis CI. - Node.js: Loosely couple Node.js / Electron code to `Canvas` module, and treat its absence like a headless web worker context in the browser (#1103). @@ -178,6 +264,7 @@ the fixes and additions from the past two weeks: `#reorient()` (#973). ### Added + - Implement `Path#divideAt(location)`, in analogy to `Curve#divideAt(location)`. - Add `PathItem#compare()` as a way to compare the geometry of two paths to see if they describe the same shape, handling cases where paths start in different @@ -196,6 +283,7 @@ the fixes and additions from the past two weeks: (#1004, #1177). ### Fixed + - Many improvements to boolean operations: - Improve performance of boolean operations when there no actual crossings between the paths, but paths may be contained within each other. @@ -236,17 +324,20 @@ the fixes and additions from the past two weeks: (#632). ### Removed + - Remove `Numerical.TOLERANCE = 1e-6` as there is no internal use for it anymore. ## `0.10.2` ### Fixed + - Get published version to work correctly in Bower again. ## `0.10.1` ### Fixed + - Correct a few issues with documentation and NPM publishing that slipped through in the `0.10.0` release. @@ -284,6 +375,7 @@ Thank you all for using Paper.js, submitting bugs and ideas, and all those that contribute to the code. ### Changed + - Significant overhaul and improvements of boolean path operations `PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()`: - Improve handling of self-intersecting paths and non-zero fill-rules. @@ -300,7 +392,7 @@ contribute to the code. - `Curve#getParameterAt(offset)` → `#getTimeAt(offset)` - `Curve#getParameterOf(point)` → `getTimeOf(point)` - `Curve#getPointAt(time, true)` → `#getPointAtTime(time)` - - `Curve#getTangentAt(time, true)` → `#getTangenttTime(time)` + - `Curve#getTangentAt(time, true)` → `#getTangentAtTime(time)` - `Curve#getNormalAt(time, true)` → `#getNormalAtTime(time)` - `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)` - `CurveLocation#parameter` → `#time` @@ -360,6 +452,7 @@ contribute to the code. `Color` (#1043). ### Added + - Use unified code-base for browsers, Node.js, Electron, and anything in-between, and enable npm install for browser use (#739). - Start using automatic code testing and deployment of prebuilt versions through @@ -424,6 +517,7 @@ contribute to the code. - Add `Raster#loaded` to reflect the loading state of its image. ### Fixed + - Fix calculations of `Item#strokeBounds` for all possible combinations of `Item#strokeScaling` and `Item#applyMatrix` for `Path`, `Shape` and `SymbolItem`, along with correct handling of such strokes in Item#hitTest() @@ -502,10 +596,11 @@ contribute to the code. `Numerical.solveCubic()` for edge-cases (#1085). ### Removed + - Canvas attributes "resize" and "data-paper-resize" no longer cause paper to resize the canvas when the viewport size changes; Additional CSS styles are required since `0.9.22`, e.g.: - + ```css /* Scale canvas with resize attribute to full size */ canvas[resize] { @@ -520,6 +615,7 @@ contribute to the code. It is replaced by `Project#addLayer()` and `Project#insertLayer()`. ### Deprecated + - `#windingRule` on `Item` and `Style` → `#fillRule` - `Curve#getNormalAt(time, true)` → `#getNormalAtTime(true)` - `Curve#divide()` → `#divideAt(offset)` / `#divideAtTime(time)` @@ -527,7 +623,7 @@ contribute to the code. - `Curve#getParameterAt(offset)` → `#getTimeAt(offset)` - `Curve#getParameterOf(point)` → `getTimeOf(point)` - `Curve#getPointAt(time, true)` → `#getPointAtTime(time)` -- `Curve#getTangentAt(time, true)` → `#getTangenttTime(time)` +- `Curve#getTangentAt(time, true)` → `#getTangentAtTime(time)` - `Curve#getNormalAt(time, true)` → `#getNormalAtTime(time)` - `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)` - `CurveLocation#parameter` → `#time` diff --git a/LICENSE.txt b/LICENSE.txt index 28c2e83f..6b6c439e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ -Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey -http://scratchdisk.com/ & http://jonathanpuckey.com/ +Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey +http://scratchdisk.com/ & https://puckey.studio/ All rights reserved. The MIT License (MIT) diff --git a/README.md b/README.md index 70ee71e5..97f720a1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ If you want to work with Paper.js, simply download the latest "stable" version from [http://paperjs.org/download/](http://paperjs.org/download/) - Website: +- Questions: - Discussion forum: - Mainline source code: - Twitter: [@paperjs](https://twitter.com/paperjs) diff --git a/examples/Node.js/Raster.js b/examples/Node.js/Raster.js index e3a28d68..0309ae03 100644 --- a/examples/Node.js/Raster.js +++ b/examples/Node.js/Raster.js @@ -24,7 +24,7 @@ raster.onLoad = function() { var fs = require('fs'); var svg = new paper.XMLSerializer().serializeToString(project.exportSVG()); - fs.writeFile(path.resolve('./out.svg'),svg, function (err) { + fs.writeFile(path.resolve('./out.svg'), svg, function (err) { if (err) throw err; console.log('Saved!'); }); diff --git a/examples/Node.js/SvgExport.js b/examples/Node.js/SvgExport.js index a0ae8365..5d9c236a 100644 --- a/examples/Node.js/SvgExport.js +++ b/examples/Node.js/SvgExport.js @@ -45,7 +45,7 @@ with (paper) { var svg = project.exportSVG({ asString: true }); console.log(svg); - fs.writeFile(path.resolve('./out.svg'),svg, function (err) { + fs.writeFile(path.resolve('./out.svg'), svg, function (err) { if (err) throw err; console.log('Saved!'); }); diff --git a/gulp/jsdoc b/gulp/jsdoc index 2533ac8e..6c10a800 160000 --- a/gulp/jsdoc +++ b/gulp/jsdoc @@ -1 +1 @@ -Subproject commit 2533ac8e1863262f3c28cd29bc940c6d2ecdf147 +Subproject commit 6c10a800e2acafdb50b8493c6a67e5cbeec91f10 diff --git a/gulp/tasks/build.js b/gulp/tasks/build.js index ba2397e7..48ee18ca 100644 --- a/gulp/tasks/build.js +++ b/gulp/tasks/build.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/tasks/dist.js b/gulp/tasks/dist.js index 17ba87bd..e69e861c 100644 --- a/gulp/tasks/dist.js +++ b/gulp/tasks/dist.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -22,6 +22,7 @@ gulp.task('zip', ['clean:zip', 'dist'], function() { gulp.src([ 'dist/paper-full*.js', 'dist/paper-core*.js', + 'dist/paper.d.ts', 'dist/node/**/*', 'LICENSE.txt', 'examples/**/*', diff --git a/gulp/tasks/docs.js b/gulp/tasks/docs.js index 01953df9..6e20068d 100644 --- a/gulp/tasks/docs.js +++ b/gulp/tasks/docs.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -14,14 +14,15 @@ var gulp = require('gulp'), del = require('del'), rename = require('gulp-rename'), shell = require('gulp-shell'), - options = require('../utils/options.js'); + options = require('../utils/options.js'), + run = require('run-sequence'); var docOptions = { local: 'docs', // Generates the offline docs server: 'serverdocs' // Generates the website templates for the online docs }; -gulp.task('docs', ['docs:local', 'build:full'], function() { +gulp.task('docs', ['docs:local', 'docs:typescript', 'build:full'], function() { return gulp.src('dist/paper-full.js') .pipe(rename({ basename: 'paper' })) .pipe(gulp.dest('dist/docs/assets/js/')); @@ -32,15 +33,58 @@ Object.keys(docOptions).forEach(function(name) { var mode = docOptions[name]; return gulp.src('src') .pipe(shell( - ['java -cp jsrun.jar:lib/* JsRun app/run.js', - ' -c=conf/', name, '.conf ', - ' -D="renderMode:', mode, '" ', - ' -D="version:', options.version, '"'].join(''), + [ + 'java -cp jsrun.jar:lib/* JsRun app/run.js', + ' -c=conf/', name, '.conf ', + ' -D="renderMode:', mode, '" ', + ' -D="version:', options.version, '"' + ].join(''), { cwd: 'gulp/jsdoc' }) - ) + ); }); gulp.task('clean:docs:' + name, function() { - return del([ 'dist/' + docOptions[name] + '/**' ]); + return del(['dist/' + docOptions[name] + '/**']); }); }); + +// The goal of the typescript task is to automatically generate a type +// definition for the library. +gulp.task('docs:typescript', function(callback) { + run( + 'docs:typescript:clean:before', + 'docs:typescript:build', + 'docs:typescript:clean:after', + callback + ); +}); +// First clean eventually existing type definition... +gulp.task('docs:typescript:clean:before', function() { + return del('dist/paper.d.ts'); +}); +// ...then build the definition... +gulp.task('docs:typescript:build', function() { + // First parse JSDoc comments and store parsed data in a temporary file... + return gulp.src('src') + .pipe(shell( + [ + 'java -cp jsrun.jar:lib/* JsRun app/run.js', + ' -c=conf/typescript.conf ', + ' -D="file:../../gulp/typescript/typescript-definition-data.json"', + ' -D="version:', options.version, '"', + ' -D="date:', options.date, '"' + ].join(''), + { cwd: 'gulp/jsdoc' }) + ) + // ...then generate definition from parsed data... + .pipe(shell('node gulp/typescript/typescript-definition-generator.js')) + // ...finally test the definition by compiling a typescript file. + .pipe(shell('node node_modules/typescript/bin/tsc --project gulp/typescript')); +}); +// ...finally remove all unneeded temporary files that were used for building. +gulp.task('docs:typescript:clean:after', function() { + return del([ + 'gulp/typescript/typescript-definition-data.json', + 'gulp/typescript/typescript-definition-test.js' + ]); +}); diff --git a/gulp/tasks/jshint.js b/gulp/tasks/jshint.js index 382f9154..987c96f4 100644 --- a/gulp/tasks/jshint.js +++ b/gulp/tasks/jshint.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/tasks/load.js b/gulp/tasks/load.js index 1d301aab..d985e74a 100644 --- a/gulp/tasks/load.js +++ b/gulp/tasks/load.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/tasks/minify.js b/gulp/tasks/minify.js index b55318bc..28d1b1aa 100644 --- a/gulp/tasks/minify.js +++ b/gulp/tasks/minify.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/tasks/publish.js b/gulp/tasks/publish.js index d1b07c37..25d37a00 100644 --- a/gulp/tasks/publish.js +++ b/gulp/tasks/publish.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -32,20 +32,21 @@ var packages = ['paper-jsdom', 'paper-jsdom-canvas'], end_with_newline: true }; -gulp.task('publish', function() { +gulp.task('publish', function(callback) { if (options.branch !== 'develop') { throw new Error('Publishing is only allowed on the develop branch.'); } // publish:website comes before publish:release, so paperjs.zip file is gone // before npm publish: - return run( + run( 'publish:json', 'publish:dist', 'publish:packages', 'publish:commit', 'publish:website', 'publish:release', - 'publish:load' + 'publish:load', + callback ); }); @@ -108,11 +109,12 @@ packages.forEach(function(name) { }); }); -gulp.task('publish:website', function() { +gulp.task('publish:website', function(callback) { if (fs.lstatSync(sitePath).isDirectory()) { - return run( + run( 'publish:website:build', - 'publish:website:push' + 'publish:website:push', + callback ); } }); diff --git a/gulp/tasks/test.js b/gulp/tasks/test.js index 1982e46c..1ec61697 100644 --- a/gulp/tasks/test.js +++ b/gulp/tasks/test.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/tasks/watch.js b/gulp/tasks/watch.js index 5864e895..28a4dbdd 100644 --- a/gulp/tasks/watch.js +++ b/gulp/tasks/watch.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/typescript/tsconfig.json b/gulp/typescript/tsconfig.json new file mode 100644 index 00000000..7fbc4091 --- /dev/null +++ b/gulp/typescript/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ES5", + "strictNullChecks": true + }, + "files" : [ + "typescript-definition-test.ts" + ] +} diff --git a/gulp/typescript/typescript-definition-generator.js b/gulp/typescript/typescript-definition-generator.js new file mode 100644 index 00000000..7a8df070 --- /dev/null +++ b/gulp/typescript/typescript-definition-generator.js @@ -0,0 +1,339 @@ +/** + * This script generates a type definition by taking JSDoc roughly parsed data, + * formatting it and passing it to a mustache template. + */ + +const fs = require('fs'); +const mustache = require('mustache'); + +// Retrieve JSDoc data. +const data = JSON.parse(fs.readFileSync(__dirname + '/typescript-definition-data.json', 'utf8')); +const classes = data.classes; + +// Format classes. +classes.forEach(cls => { + // Format class. + // Store name as `className` and not simply `name`, to avoid name conflict + // in static constructors block. + cls.className = cls._name; + // Store closest parent if there is one. + cls.extends = cls.inheritsFrom && cls.inheritsFrom.length > 0 + ? cls.inheritsFrom[0] + : null; + // Store comment using class tag as description. + cls.comment = formatComment(cls.comment, 'class'); + + // Build a filter for deprecated or inherited methods or properties. + const filter = it => !it.deprecated && it.memberOf == cls.alias && !it.isNamespace; + + // Format properties. + cls.properties = cls.properties + .filter(filter) + .map(it => ({ + name: it._name, + type: formatType(it.type, { isProperty: true, isSettableProperty: !it.readOnly }), + static: formatStatic(it.isStatic), + readOnly: formatReadOnly(it.readOnly), + comment: formatComment(it.comment) + })); + + // Format methods. + const methods = cls.methods + .filter(filter) + .map(it => { + const name = formatMethodName(it._name); + const isStaticConstructor = it.isStatic && it.isConstructor; + return { + name: name, + // Constructors don't need return type. + type: !it.isConstructor + ? formatType(getMethodReturnType(it), { isMethodReturnType: true }) + : '', + static: formatStatic(it.isStatic), + // This flag is only used below to filter methods. + isStaticConstructor: isStaticConstructor, + comment: formatComment(it.comment, 'desc', it.isConstructor), + params: it._params + ? it._params + // Filter internal parameters (starting with underscore). + .filter(it => !/^_/.test(it.name)) + .map(it => formatParameter(it, isStaticConstructor && cls)) + .join(', ') + : '' + }; + }) + .sort(sortMethods); + + // Divide methods in 2 parts: static constructors and other. Because static + // constructors need a special syntax in type definition. + cls.methods = []; + cls.staticConstructors = []; + methods.forEach(method => { + if (method.isStaticConstructor) { + // Group static constructors by method name. + let staticConstructors = cls.staticConstructors.find(it => it.name === method.name); + if (!staticConstructors) { + staticConstructors = { + name: method.name, + constructors: [] + }; + cls.staticConstructors.push(staticConstructors); + } + staticConstructors.constructors.push(method); + } else { + cls.methods.push(method); + } + }); + // Store a conveniance flag to check whether class has static constructors. + cls.hasStaticConstructors = cls.staticConstructors.length > 0; +}); + +// PaperScope class needs to be handled slightly differently because it "owns" +// all the other classes as properties. Eg. we can do `new paperScope.Path()`. +// So we add a `classesPointers` property that the template will use. +const paperScopeClass = classes.find(_ => _.className === 'PaperScope'); +paperScopeClass.classesPointers = classes.filter(_ => _.className !== 'PaperScope').map(_ => ({ name: _.className })); + +// Since paper.js module is at the same time a PaperScope instance, we need to +// duplicate PaperScope instance properties and methods in the module scope. +// For that, we expose a special variable to the template. +const paperInstance = { ...paperScopeClass }; +// We filter static properties and methods for module scope. +paperInstance.properties = paperInstance.properties.filter(_ => !_.static); +paperInstance.methods = paperInstance.methods.filter(_ => !_.static && _.name !== 'constructor'); + +// Format data trough a mustache template. +// Prepare data for the template. +const context = { + paperInstance: paperInstance, + classes: classes, + version: data.version, + date: data.date, + // {{#doc}} blocks are used in template to automatically generate a JSDoc + // comment with a custom indent. + doc: () => formatJSDoc +}; +// Retrieve template content. +const template = fs.readFileSync(__dirname + '/typescript-definition-template.mustache', 'utf8'); +// Render template. +const output = mustache.render(template, context); +// Write output in a file. +fs.writeFileSync(__dirname + '/../../dist/paper.d.ts', output, 'utf8'); + + +// +// METHODS +// + +function formatReadOnly(isReadOnly) { + return isReadOnly ? 'readonly ' : null; +} + +function formatStatic(isStatic) { + return isStatic ? 'static ' : null; +} + +function formatType(type, options) { + return ': ' + parseType(type, options); +} + +function parseType(type, options) { + // Always return a type even if input type is empty. In that case, return + // `void` for method return type and `any` for the rest. + if (!type) { + return options.isMethodReturnType ? 'void' : 'any'; + } + // Prefer `any[]` over `Array` to be more consistent with other types. + if (type === 'Array') { + return 'any[]'; + } + // Handle any type: `*` => `any` + type = type.replace('*', 'any'); + // Check if type is a "rest" type (meaning that an infinite number of + // parameter of this type can be passed). In that case, we need to remove + // `...` prefix and add `[]` as a suffix: + // - `...Type` => `Type[]` + // - `...(TypeA|TypeB)` => `(TypeA|TypeB)[]` + const isRestType = type.startsWith('...'); + if (isRestType) { + type = type.replace(/^\.\.\./, ''); + } + // Handle multiple types possibility by splitting on `|` then re-joining + // back parsed types. + type = type.split('|').map(splittedType => { + // Get type without array suffix `[]` for easier matching. + const singleType = splittedType.replace(/(\[\])+$/, ''); + // Handle eventual type conflict in static constructors block. For + // example, in `Path.Rectangle(rectangle: Rectangle)` method, + // `rectangle` parameter type must be mapped to `paper.Rectangle` as it + // is declared inside a `Path` namespace and would otherwise be wrongly + // assumed as being the type of `Path.Rectangle` class. + if (options.staticConstructorClass && options.staticConstructorClass.methods.find(it => it.isStatic && it.isConstructor && formatMethodName(it._name) === singleType) + ) { + return 'paper.' + splittedType; + } + // Convert primitive types to their lowercase equivalent to suit + // typescript best practices. + if (['Number', 'String', 'Boolean', 'Object'].indexOf(singleType) >= 0) { + splittedType = splittedType.toLowerCase(); + } + // Properties `object` type need to be turned into `any` to avoid + // errors when reading object properties. Eg. if `property` is of type + // `object`, `property.key` access is forbidden. + if (options.isProperty && splittedType === 'object') { + return 'any'; + } + return splittedType; + }).join(' | '); + if (isRestType) { + type += '[]'; + } + + // We declare settable properties as nullable to be compatible with + // TypeScript `strictNullChecks` option (#1664). + if (options.isSettableProperty && type !== 'any') { + type += ' | null'; + } + + return type; +} + +function formatMethodName(methodName) { + // Overloaded methods were parsed as `method^0`, `method^1`... here, we + // turn them back to `method` as typescript allow overloading. + methodName = methodName.replace(/\^[0-9]+$/, ''); + // Real contructors are called `initialize` in the library. + methodName = methodName.replace(/^initialize$/, 'constructor'); + return methodName; +} + +function formatParameter(param, staticConstructorClass) { + let content = ''; + // Handle rest parameter pattern `...Type`. Parameter name needs to be + // prefixed with `...` as in ES6. E.g. `...parameter: type[]`. + if (param.type.match(/^\.\.\.(.+)$/)) { + content += '...'; + } + content += formatParameterName(param.name); + // Optional parameters are formatted as: `parameter?: type`. + if (param.isOptional) { + content += '?'; + } + content += formatType(param.type, { staticConstructorClass }); + return content; +} + +function formatParameterName(parameterName) { + // Avoid usage of reserved keyword as parameter name. + // E.g. `function` => `callback`. + if (parameterName === 'function') { + return 'callback'; + } + return parameterName; +} + +function formatComment(comment, descriptionTagName = 'desc', skipReturn = false) { + const tags = comment.tags; + let content = ''; + + // Retrieve description tag. + const descriptionTag = tags.find(it => it.title === descriptionTagName); + if (descriptionTag) { + // Don't display group titles. + content += descriptionTag.desc.replace(/\{@grouptitle .+?\}/g, '').trim(); + } + + // Preserve some of the JSDoc tags that can be usefull even in type + // definition. Format their values to make sure that only informations + // that make sense are kept. E.g. method parameters types are already + // provided in the signature... + content += formatCommentTags(tags, 'see'); + content += formatCommentTags(tags, 'option'); + content += formatCommentTags(tags, 'param', it => it.name + ' - ' + it.desc); + + if (!skipReturn) { + content += formatCommentTags(tags, 'return', it => it.desc.trim().replace(/^\{|\}$/g, '').replace(/@([a-zA-Z]+)/, '$1')); + } + + // Make sure links are followable (e.g. by IDEs) by removing parameters. + // {@link Class#method(param)} => {@link Class#method} + content = content.replace(/(\{@link [^\}]+?)\(.*?\)(\})/g, '$1$2'); + + content = content.trim(); + return content; +} + +function formatCommentTags(tags, tagName, formatter) { + let content = ''; + // Default formatter simply outputs description. + formatter = formatter || (it => it.desc); + // Only keep tags that have a description. + tags = tags.filter(it => it.desc && it.title === tagName); + if (tags.length > 0) { + content += '\n'; + // Display tag as it was in original JSDoc, followed by formatted value. + tags.forEach(it => content += '\n@' + tagName + ' ' + formatter(it)); + } + return content; +} + +/** + * This outputs a JSDoc comment indented at the given offset and including the + * parsed comment for current mustache block. + * @param {Number} offset the number of spaces to use for indentation + * @param {Function} render the mustache render method + * @return {string} the formatted JSDoc comment + */ +function formatJSDoc(offset, render) { + // First render current block comment. Use `{{&}}` syntax to make sure + // special characters are not escaped. + let content = render('{{&comment}}'); + if (!content) { + return ''; + } + + // Build indentation. + offset = parseInt(offset); + if (offset > 0) { + offset++; + } + const indentation = new Array(offset).join(' '); + + // Prefix each line with the indentation. + content = content.split('\n') + .map(_ => indentation + ' * ' + _) + .join('\n'); + + // Wrap content in JSDoc delimiters: `/**` and `*/`. + return '/** \n' + content + '\n' + indentation + ' */'; +} + +function getMethodReturnType(method) { + return method.returnType || method.returns.length > 0 && method.returns[0].type; +} + +function sortMethods(methodA, methodB) { + // This places constructors before other methods as it is a best practice. + // This also place constructors with only one object parameter after other + // constructors to avoid type inference errors due to constructors + // overloading order. E.g. if `constructor(object: object)` is defined + // before `constructor(instance: Class)`, calling `constructor(instance)` + // will always be mapped to `contructor(object: object)`, since everything + // is an object in JavaScript. This is problematic because most of Paper.js + // classes have a constructor accepting an object. + const aIsContructor = methodA.name === 'constructor'; + const bIsContructor = methodB.name === 'constructor'; + if (aIsContructor && bIsContructor) { + if (methodA.params === 'object: object') { + return 1; + } + if (methodB.params === 'object: object') { + return -1; + } + } else if (aIsContructor) { + return -1; + } else if (bIsContructor) { + return 1; + } + return 0; +} diff --git a/gulp/typescript/typescript-definition-template.mustache b/gulp/typescript/typescript-definition-template.mustache new file mode 100644 index 00000000..3de46bcc --- /dev/null +++ b/gulp/typescript/typescript-definition-template.mustache @@ -0,0 +1,70 @@ +/*! + * Paper.js v{{version}} - The Swiss Army Knife of Vector Graphics Scripting. + * http://paperjs.org/ + * + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + * + * Date: {{date}} + * + * This is an auto-generated type definition. + */ + +declare module paper { + {{#paperInstance}} + {{#properties}} + {{#doc}}4{{/doc}} + let {{name}}{{type}} + + {{/properties}} + + {{#methods}} + {{#doc}}4{{/doc}} + function {{name}}({{params}}){{type}} + + {{/methods}} + {{/paperInstance}} + + {{#classes}} + + {{#doc}}4{{/doc}} + class {{className}} {{#extends}}extends {{extends}}{{/extends}} { + {{#properties}} + {{#doc}}8{{/doc}} + {{static}}{{readOnly}}{{name}}{{type}} + + {{/properties}} + {{#classesPointers}} + {{name}}: typeof {{name}} + {{/classesPointers}} + + {{#methods}} + {{#doc}}8{{/doc}} + {{static}}{{name}}({{params}}){{type}} + + {{/methods}} + } + {{#hasStaticConstructors}} + namespace {{className}} { + {{#staticConstructors}} + + class {{name}} extends {{className}} { + {{#constructors}} + {{#doc}}12{{/doc}} + constructor({{params}}) + + {{/constructors}} + } + {{/staticConstructors}} + } + {{/hasStaticConstructors}} + {{/classes}} +} + +declare module 'paper' { + export = paper +} diff --git a/gulp/typescript/typescript-definition-test.ts b/gulp/typescript/typescript-definition-test.ts new file mode 100644 index 00000000..0d0cead4 --- /dev/null +++ b/gulp/typescript/typescript-definition-test.ts @@ -0,0 +1,1206 @@ +/// + +/** + * This file is used as a way to test auto-generated typescript definition + * validity. For now, this only check that calling methods as they are defined + * in online documentation does not throw error in typescript compilation. + * + * Todo: add more advanced type checking by using either: + * - typescript compiler check: `let result:type = methodCall()` + * - dedicated testing library like: https://github.com/Microsoft/dtslint + */ + +import * as paper from 'paper'; + + +// +// Utility variables +// + +let point = {} as paper.Point; +let size = {} as paper.Size; +let rectangle = {} as paper.Rectangle; +let matrix = {} as paper.Matrix; +let project = {} as paper.Project; +let item = {} as paper.Item; +let layer = {} as paper.Layer; +let group = {} as paper.Group; +let shape = {} as paper.Shape; +let raster = {} as paper.Raster; +let pathItem = {} as paper.PathItem; +let path = {} as paper.Path; +let compoundPath = {} as paper.CompoundPath; +let segment = {} as paper.Segment; +let curve = {} as paper.Curve; +let curveLocation = {} as paper.CurveLocation; +let symbolDefinition = {} as paper.SymbolDefinition; +let symbolItem = {} as paper.SymbolItem; +let style = {} as paper.Style; +let color = {} as paper.Color; +let gradient = {} as paper.Gradient; +let gradientStop = {} as paper.GradientStop; +let textItem = {} as paper.TextItem; +let pointText = {} as paper.PointText; +let view = {} as paper.View; +let event = {} as paper.Event; +let mouseEvent = {} as paper.MouseEvent; +let tool = {} as paper.Tool; +let toolEvent = {} as paper.ToolEvent; +let keyEvent = {} as paper.KeyEvent; +let paperScope = {} as paper.PaperScope; +let callback = {} as () => {}; +let hitResult = {} as paper.HitResult; +let object = {} as object; + + +// +// Classes +// + +// +// Point +// + +new paper.Point(0, 0); +new paper.Point([ 0, 0 ]); +new paper.Point({ x: 0, y: 0 }); +new paper.Point(size); +new paper.Point(point); +point.x; +point.y; +point.length; +point.angle; +point.angleInRadians; +point.quadrant; +point.selected; +point.set(0, 0); +point.set([ 0, 0 ]); +point.set({ x: 0, y: 0 }); +point.set(size); +point.set(point); +point.equals(point); +point.clone(); +point.toString(); +point.getAngle(point); +point.getAngleInRadians(point); +point.getDirectedAngle(point); +point.getDistance(point, true); +point.normalize(); +point.normalize(0); +point.rotate(0, point); +point.transform(matrix); +point.isInside(rectangle); +point.isClose(point, 0); +point.isCollinear(point); +point.isOrthogonal(point); +point.isZero(); +point.isNaN(); +point.isInQuadrant(0); +point.dot(point); +point.cross(point); +point.project(point); +point.round(); +point.ceil(); +point.floor(); +point.abs(); +point.add(0); +point.add(point); +point.subtract(0); +point.subtract(point); +point.multiply(0); +point.multiply(point); +point.divide(0); +point.divide(point); +point.modulo(0); +point.modulo(point); +paper.Point.min(point, point); +paper.Point.max(point, point); +paper.Point.random(); + + +// +// Size +// + + +new paper.Size(0, 0); +new paper.Size([ 0, 0 ]); +new paper.Size({ width: 0, height: 0 }); +new paper.Size(size); +new paper.Size(point); +size.width; +size.height; +size.set(0, 0); +size.set([ 0, 0 ]); +size.set({ x: 0, y: 0 }); +size.set(size); +size.set(point); +size.equals(size); +size.clone(); +size.toString(); +size.isZero(); +size.isNaN(); +size.round(); +size.ceil(); +size.floor(); +size.abs(); +size.add(0); +size.add(size); +size.subtract(0); +size.subtract(size); +size.multiply(0); +size.multiply(size); +size.divide(0); +size.divide(size); +size.modulo(0); +size.modulo(size); +paper.Size.min(size, size); +paper.Size.max(size, size); +paper.Size.random(); + + +// +// Rectangle +// + + +new paper.Rectangle(point, size); +new paper.Rectangle({ point: point, size: size }); +new paper.Rectangle(0, 0, 0, 0); +new paper.Rectangle(point, point); +new paper.Rectangle(rectangle); +rectangle.x; +rectangle.y; +rectangle.width; +rectangle.height; +rectangle.point; +rectangle.size; +rectangle.left; +rectangle.top; +rectangle.right; +rectangle.bottom; +rectangle.center; +rectangle.topLeft; +rectangle.topRight; +rectangle.bottomLeft; +rectangle.bottomRight; +rectangle.leftCenter; +rectangle.topCenter; +rectangle.rightCenter; +rectangle.bottomCenter; +rectangle.area; +rectangle.selected; +rectangle.set(point, size); +rectangle.set({ point: point, size: size }); +rectangle.set(0, 0, 0, 0); +rectangle.set(point, point); +rectangle.set(rectangle); +rectangle.clone(); +rectangle.equals(rectangle); +rectangle.toString(); +rectangle.isEmpty(); +rectangle.contains(point); +rectangle.contains(rectangle); +rectangle.intersects(rectangle); +rectangle.intersects(rectangle, 0); +rectangle.intersect(rectangle); +rectangle.unite(rectangle); +rectangle.include(point); +rectangle.expand(0); +rectangle.expand(0, 0); +rectangle.scale(0); +rectangle.scale(0, 0); + + +// +// Matrix +// + +new paper.Matrix(); +new paper.Matrix(0, 0, 0, 0, 0, 0); +new paper.Matrix([ 0, 0, 0, 0, 0, 0 ]); +new paper.Matrix(matrix); +matrix.a; +matrix.b; +matrix.c; +matrix.d; +matrix.tx; +matrix.ty; +matrix.values; +matrix.translation; +matrix.scaling; +matrix.rotation; +matrix.set(0, 0, 0, 0, 0, 0); +matrix.set([ 0, 0, 0, 0, 0, 0 ]); +matrix.set(matrix); +matrix.clone(); +matrix.equals(matrix); +matrix.toString(); +matrix.reset(); +matrix.apply(); +matrix.apply(true); +matrix.translate(point); +matrix.translate(0, 0); +matrix.scale(0); +matrix.scale(0, point); +matrix.scale(0, 0); +matrix.scale(0, 0, point); +matrix.rotate(0, point); +matrix.rotate(0, 0, 0); +matrix.shear(point); +matrix.shear(point, point); +matrix.shear(0, 0); +matrix.shear(0, 0, point); +matrix.skew(point); +matrix.skew(point, point); +matrix.skew(0, 0); +matrix.skew(0, 0, point); +matrix.append(matrix); +matrix.prepend(matrix); +matrix.appended(matrix); +matrix.prepended(matrix); +matrix.invert(); +matrix.inverted(); +matrix.isIdentity(); +matrix.isInvertible(); +matrix.isSingular(); +matrix.transform(point); +matrix.transform([ 0, 0 ], [ 0, 0 ], 0); +matrix.inverseTransform(point); +matrix.decompose(); +matrix.applyToContext({} as CanvasRenderingContext2D); + + +// +// Project +// + +new paper.Project({} as HTMLCanvasElement); +new paper.Project(''); +new paper.Project(size); +project.view; +project.currentStyle; +project.index; +project.layers; +project.activeLayer; +project.symbolDefinitions; +project.selectedItems; +project.activate(); +project.clear(); +project.isEmpty(); +project.remove(); +project.selectAll(); +project.deselectAll(); +project.addLayer(layer); +project.insertLayer(0, layer); +project.hitTest(point); +project.hitTest(point, {}); +project.hitTestAll(point); +project.hitTestAll(point, {}); +project.getItems({}); +project.getItems(callback); +project.getItem({}); +project.getItem(callback); +project.exportJSON(); +project.exportJSON({}); +project.importJSON(''); +project.exportSVG(); +project.exportSVG({}); +project.importSVG(''); +project.importSVG({} as SVGElement); +project.importSVG('', {}); +project.importSVG('', callback); + + +// +// Item +// + +item.id; +item.className; +item.name; +item.style; +item.locked; +item.visible; +item.blendMode; +item.opacity; +item.selected; +item.clipMask; +item.data; +item.position; +item.pivot; +item.bounds; +item.strokeBounds; +item.handleBounds; +item.rotation; +item.scaling; +item.matrix; +item.globalMatrix; +item.viewMatrix; +item.applyMatrix; +item.project; +item.view; +item.layer; +item.parent; +item.children; +item.firstChild; +item.lastChild; +item.nextSibling; +item.previousSibling; +item.index; +item.strokeColor; +item.strokeWidth; +item.strokeCap; +item.strokeJoin; +item.dashOffset; +item.strokeScaling; +item.dashArray; +item.miterLimit; +item.fillColor; +item.fillColor && item.fillColor.red; +item.fillRule; +item.shadowColor; +item.shadowBlur; +item.shadowOffset; +item.selectedColor; +item.onFrame; +item.onMouseDown; +item.onMouseDrag; +item.onMouseUp; +item.onClick; +item.onDoubleClick; +item.onMouseMove; +item.onMouseEnter; +item.onMouseLeave; +item.set({}); +item.clone(); +item.clone({}); +item.copyContent(item); +item.copyAttributes(item, true); +item.rasterize(); +item.rasterize(0); +item.rasterize(0, true); +item.contains(point); +item.isInside(rectangle); +item.intersects(item); +item.hitTest(point); +item.hitTest(point, {}); +item.hitTestAll(point); +item.hitTestAll(point, {}); +item.matches({}); +item.matches(callback); +item.matches(name, {}); +item.getItems({}); +item.getItems(callback); +item.getItem({}); +item.getItem(callback); +item.exportJSON(); +item.exportJSON({}); +item.importJSON(''); +item.exportSVG(); +item.exportSVG({}); +item.importSVG(''); +item.importSVG({} as SVGElement); +item.importSVG('', {}); +item.importSVG('', callback); +item.addChild(item); +item.insertChild(0, item); +item.addChildren([ item ]); +item.insertChildren(0, [ item ]); +item.insertAbove(item); +item.insertBelow(item); +item.sendToBack(); +item.bringToFront(); +item.addTo(group); +item.copyTo(group); +item.reduce({}); +item.remove(); +item.replaceWith(item); +item.removeChildren(); +item.removeChildren(0); +item.removeChildren(0, 0); +item.reverseChildren(); +item.isEmpty(); +item.hasFill(); +item.hasStroke(); +item.hasShadow(); +item.hasChildren(); +item.isInserted(); +item.isAbove(item); +item.isBelow(item); +item.isParent(item); +item.isChild(item); +item.isDescendant(item); +item.isAncestor(item); +item.isSibling(item); +item.isGroupedWith(item); +item.translate(point); +item.rotate(0); +item.rotate(0, point); +item.scale(0); +item.scale(0, point); +item.scale(0, 0); +item.scale(0, 0, point); +item.shear(point); +item.shear(point, point); +item.shear(0, 0); +item.shear(0, 0, point); +item.skew(point); +item.skew(point, point); +item.skew(0, 0); +item.skew(0, 0, point); +item.transform(matrix); +item.globalToLocal(point); +item.localToGlobal(point); +item.parentToLocal(point); +item.localToParent(point); +item.fitBounds(rectangle); +item.fitBounds(rectangle, true); +item.on('', callback); +item.on({}); +item.off('', callback); +item.off({}); +item.emit('', event); +item.responds(''); +item.removeOn({}); +item.removeOnMove(); +item.removeOnDown(); +item.removeOnDrag(); +item.removeOnUp(); + + +// +// Layer +// + +new paper.Layer([ item ]); +new paper.Layer({}); +layer.activate(); + + +// +// Group +// + +new paper.Group([ item ]); +new paper.Group({}); +group.clipped; + + +// +// Shape +// + +new paper.Shape.Circle(point, 0); +new paper.Shape.Circle({}); +new paper.Shape.Rectangle(rectangle); +new paper.Shape.Rectangle(rectangle, size); +new paper.Shape.Rectangle(point, size); +new paper.Shape.Rectangle(point, point); +new paper.Shape.Rectangle({}); +new paper.Shape.Ellipse(rectangle); +new paper.Shape.Ellipse({}); +shape.type; +shape.size; +shape.radius; +shape.toPath(); +shape.toPath(true); + + +// +// Raster +// + +new paper.Raster(); +new paper.Raster({} as HTMLImageElement); +new paper.Raster({} as HTMLCanvasElement); +new paper.Raster(''); +new paper.Raster('', point); +raster.size; +raster.width; +raster.height; +raster.loaded; +raster.resolution; +raster.image; +raster.canvas; +raster.context; +raster.source; +raster.crossOrigin; +raster.smoothing; +raster.onLoad; +raster.onLoad = () => {}; +raster.onLoad = null; +raster.onError; +raster.getSubCanvas(rectangle); +raster.getSubRaster(rectangle); +raster.toDataURL(); +raster.drawImage({} as HTMLImageElement, point); +raster.getAverageColor(path); +raster.getAverageColor(rectangle); +raster.getAverageColor(point); +raster.getPixel(0, 0); +raster.getPixel(point); +raster.setPixel(0, 0, color); +raster.setPixel(point, color); +raster.createImageData(size); +raster.getImageData(rectangle); +raster.setImageData({} as ImageData, point); + + +// +// HitResult +// + +hitResult.type; +hitResult.name; +hitResult.item; +hitResult.location; +hitResult.color; +hitResult.segment; +hitResult.point; + + +// +// PathItem +// + +pathItem.interiorPoint; +pathItem.clockwise; +pathItem.pathData; +pathItem.unite(path); +pathItem.unite(path, {}); +pathItem.intersect(path); +pathItem.intersect(path, {}); +pathItem.subtract(path); +pathItem.subtract(path, {}); +pathItem.exclude(path); +pathItem.exclude(path, {}); +pathItem.divide(path); +pathItem.divide(path, {}); +pathItem.reorient(); +pathItem.reorient(true); +pathItem.reorient(true, true); +pathItem.getIntersections(path); +pathItem.getIntersections(path, callback); +pathItem.getCrossings(path); +pathItem.getNearestLocation(point); +pathItem.getNearestPoint(point); +pathItem.reverse(); +pathItem.flatten(); +pathItem.flatten(0); +pathItem.smooth(); +pathItem.smooth({}); +pathItem.simplify(); +pathItem.simplify(0); +pathItem.interpolate(path, path, 0); +pathItem.compare(path); +pathItem.moveTo(point); +pathItem.lineTo(point); +pathItem.arcTo(point, point); +pathItem.arcTo(point); +pathItem.arcTo(point, true); +pathItem.curveTo(point, point); +pathItem.curveTo(point, point, 0); +pathItem.cubicCurveTo(point, point, point); +pathItem.quadraticCurveTo(point, point); +pathItem.closePath(); +pathItem.moveBy(point); +pathItem.lineBy(point); +pathItem.arcBy(point, point); +pathItem.arcBy(point); +pathItem.arcBy(point, true); +pathItem.curveBy(point, point); +pathItem.curveBy(point, point, 0); +pathItem.cubicCurveBy(point, point, point); +pathItem.quadraticCurveBy(point, point); +paper.PathItem.create(''); +paper.PathItem.create([ [ 0 ] ]); +paper.PathItem.create({}); + + +// +// Path +// + +new paper.Path(); +new paper.Path([ segment ]); +new paper.Path(object); +new paper.Path(''); +new paper.Path.Line(point, point); +new paper.Path.Line(object); +new paper.Path.Circle(point, 0); +new paper.Path.Circle(object); +new paper.Path.Rectangle(rectangle); +new paper.Path.Rectangle(rectangle, size); +new paper.Path.Rectangle(point, size); +new paper.Path.Rectangle(point, point); +new paper.Path.Rectangle(object); +new paper.Path.Ellipse(rectangle); +new paper.Path.Ellipse(object); +new paper.Path.Arc(point, point, point); +new paper.Path.Arc(object); +new paper.Path.RegularPolygon(point, 0, 0); +new paper.Path.RegularPolygon(object); +new paper.Path.Star(point, 0, 0, 0); +new paper.Path.Star(object); +path.segments; +path.firstSegment; +path.lastSegment; +path.curves; +path.firstCurve; +path.lastCurve; +path.closed; +path.length; +path.area; +path.fullySelected; +path.add(segment); +path.add(point); +path.add([0,0]); +path.add(segment, point, [0,0]); +path.insert(0, segment); +path.addSegments([ segment ]); +path.insertSegments(0, [ segment ]); +path.removeSegment(0); +path.removeSegments(); +path.removeSegments(0); +path.removeSegments(0, 0); +path.hasHandles(); +path.clearHandles(); +path.divideAt(curveLocation); +path.splitAt(curveLocation); +path.join(path); +path.join(path, 0); +path.reduce(object); +path.toShape(); +path.toShape(true); +path.getLocationOf(point); +path.getOffsetOf(point); +path.getLocationAt(0); +path.getPointAt(0); +path.getTangentAt(0); +path.getNormalAt(0); +path.getWeightedTangentAt(0); +path.getWeightedNormalAt(0); +path.getCurvatureAt(0); +path.getOffsetsWithTangent(point); + + +// +// CompoundPath +// + +new paper.CompoundPath(object); +new paper.CompoundPath(''); +compoundPath.closed; +compoundPath.firstSegment; +compoundPath.lastSegment; +compoundPath.curves; +compoundPath.firstCurve; +compoundPath.lastCurve; +compoundPath.area; +compoundPath.length; + + +// +// Segment +// + +new paper.Segment(); +new paper.Segment(point); +new paper.Segment(point, point); +new paper.Segment(point, point, point); +new paper.Segment(object); +segment.point; +segment.handleIn; +segment.handleOut; +segment.selected; +segment.index; +segment.path; +segment.curve; +segment.location; +segment.next; +segment.previous; +segment.hasHandles(); +segment.isSmooth(); +segment.clearHandles(); +segment.smooth(); +segment.smooth(object); +segment.isFirst(); +segment.isLast(); +segment.reverse(); +segment.reversed(); +segment.remove(); +segment.toString(); +segment.transform(matrix); +segment.interpolate(segment, segment, 0); + + +// +// Curve +// + +new paper.Curve(segment, segment); +new paper.Curve(point, point, point, point); +curve.point1; +curve.point2; +curve.handle1; +curve.handle2; +curve.segment1; +curve.segment2; +curve.path; +curve.index; +curve.next; +curve.previous; +curve.selected; +curve.values; +curve.points; +curve.length; +curve.area; +curve.bounds; +curve.strokeBounds; +curve.handleBounds; +curve.clone(); +curve.toString(); +curve.classify(); +curve.remove(); +curve.isFirst(); +curve.isLast(); +curve.getPart(0, 0); +curve.divideAt(curveLocation); +curve.divideAtTime(0); +curve.splitAt(curveLocation); +curve.splitAtTime(0); +curve.reversed(); +curve.clearHandles(); +curve.hasHandles(); +curve.hasLength(); +curve.hasLength(0); +curve.isStraight(); +curve.isLinear(); +curve.isCollinear(curve); +curve.isHorizontal(); +curve.isVertical(); +curve.getLocationAt(0); +curve.getLocationAtTime(0); +curve.getTimeAt(0); +curve.getTimeAt(0, 0); +curve.getTimesWithTangent(point); +curve.getOffsetAtTime(0); +curve.getLocationOf(point); +curve.getOffsetOf(point); +curve.getTimeOf(point); +curve.getNearestLocation(point); +curve.getNearestPoint(point); +curve.getPointAt(curveLocation); +curve.getTangentAt(curveLocation); +curve.getNormalAt(curveLocation); +curve.getWeightedTangentAt(curveLocation); +curve.getWeightedNormalAt(curveLocation); +curve.getCurvatureAt(curveLocation); +curve.getPointAtTime(0); +curve.getTangentAtTime(0); +curve.getNormalAtTime(0); +curve.getWeightedTangentAtTime(0); +curve.getWeightedNormalAtTime(0); +curve.getCurvatureAtTime(0); +curve.getIntersections(curve); + + +// +// CurveLocation +// + +new paper.CurveLocation(curve, 0); +new paper.CurveLocation(curve, 0, point); +curveLocation.segment; +curveLocation.curve; +curveLocation.path; +curveLocation.index; +curveLocation.time; +curveLocation.point; +curveLocation.offset; +curveLocation.curveOffset; +curveLocation.intersection; +curveLocation.tangent; +curveLocation.normal; +curveLocation.curvature; +curveLocation.distance; +curveLocation.equals(curveLocation); +curveLocation.toString(); +curveLocation.isTouching(); +curveLocation.isCrossing(); +curveLocation.hasOverlap(); + + +// +// SymbolDefinition +// + +new paper.SymbolDefinition(item); +new paper.SymbolDefinition(item, true); +symbolDefinition.project; +symbolDefinition.item; +symbolDefinition.place(); +symbolDefinition.place(point); +symbolDefinition.clone(); +symbolDefinition.equals(symbolDefinition); + + +// +// SymbolItem +// + +new paper.SymbolItem(symbolDefinition); +new paper.SymbolItem(item); +new paper.SymbolItem(symbolDefinition, point); +symbolItem.definition; + + +// +// Style +// + +new paper.Style(object); +style.view; +style.strokeColor; +style.strokeWidth; +style.strokeCap; +style.strokeJoin; +style.strokeScaling; +style.dashOffset; +style.dashArray; +style.miterLimit; +style.fillColor; +style.fillRule; +style.shadowColor; +style.shadowBlur; +style.shadowOffset; +style.selectedColor; +style.fontFamily; +style.fontWeight; +style.fontSize; +style.leading; +style.justification; + + +// +// Color +// + +new paper.Color(0, 0, 0); +new paper.Color(0, 0, 0, 0); +new paper.Color(0); +new paper.Color(0, 0); +new paper.Color(object); +new paper.Color(''); +new paper.Color(gradient, point, point); +new paper.Color(gradient, point, point, point); +color.type; +color.components; +color.alpha; +color.red; +color.green; +color.blue; +color.gray; +color.hue; +color.saturation; +color.brightness; +color.lightness; +color.gradient; +color.highlight; +color.set(0, 0, 0); +color.set(0, 0, 0, 0); +color.set(0); +color.set(0, 0); +color.set(object); +color.set(color); +color.set(gradient, point, point); +color.set(gradient, point, point, point); +color.convert(''); +color.hasAlpha(); +color.equals(color); +color.clone(); +color.toString(); +color.toCSS(true); +color.transform(matrix); +color.add(0); +color.add(color); +color.subtract(0); +color.subtract(color); +color.multiply(0); +color.multiply(color); +color.divide(0); +color.divide(color); +paper.Color.random(); + + +// +// Gradient +// + +gradient.stops; +gradient.radial; +gradient.clone(); +gradient.equals(gradient); + + +// +// GradientStop +// + +new paper.GradientStop(); +new paper.GradientStop(color); +new paper.GradientStop(color, 0); +gradientStop.offset; +gradientStop.color; +gradientStop.clone(); + + +// +// TextItem +// + +textItem.content; +textItem.fontFamily; +textItem.fontWeight; +textItem.fontSize; +textItem.leading; +textItem.justification; + + +// +// PointText +// + +new paper.PointText(point); +new paper.PointText(object); +pointText.point; + + +// +// View +// + +view.autoUpdate; +view.element; +view.pixelRatio; +view.resolution; +view.viewSize; +view.bounds; +view.size; +view.center; +view.zoom; +view.rotation; +view.scaling; +view.matrix; +view.onFrame; +view.onResize; +view.onMouseDown; +view.onMouseDrag; +view.onMouseUp; +view.onClick; +view.onDoubleClick; +view.onMouseMove; +view.onMouseEnter; +view.onMouseLeave; +view.remove(); +view.update(); +view.requestUpdate(); +view.play(); +view.pause(); +view.isVisible(); +view.isInserted(); +view.translate(point); +view.rotate(0); +view.rotate(0, point); +view.scale(0); +view.scale(0, point); +view.scale(0, 0); +view.scale(0, 0, point); +view.shear(point); +view.shear(point, point); +view.shear(0, 0); +view.shear(0, 0, point); +view.skew(point); +view.skew(point, point); +view.skew(0, 0); +view.skew(0, 0, point); +view.transform(matrix); +view.projectToView(point); +view.viewToProject(point); +view.getEventPoint(event); +view.on('', callback); +view.on(object); +view.off('', callback); +view.off(object); +view.emit('', event); +view.responds(''); + + +// +// Event +// + +event.timeStamp; +event.modifiers; +event.modifiers.shift; +event.preventDefault(); +event.stopPropagation(); +event.stop(); + + +// +// MouseEvent +// + +mouseEvent.type; +mouseEvent.point; +mouseEvent.target; +mouseEvent.currentTarget; +mouseEvent.delta; +mouseEvent.toString(); + + +// +// Tool +// + +tool.minDistance; +tool.maxDistance; +tool.fixedDistance; +tool.onMouseDown; +tool.onMouseDrag; +tool.onMouseMove; +tool.onMouseUp; +tool.onKeyDown; +tool.onKeyUp; +tool.activate(); +tool.remove(); +tool.on('', callback); +tool.on(object); +tool.off('', callback); +tool.off(object); +tool.emit('', event); +tool.responds(''); + + +// +// ToolEvent +// + +toolEvent.type; +toolEvent.point; +toolEvent.lastPoint; +toolEvent.downPoint; +toolEvent.middlePoint; +toolEvent.delta; +toolEvent.count; +toolEvent.item; +toolEvent.toString(); + + +// +// Key +// + +paper.Key.modifiers; +paper.Key.isDown(''); + + +// +// KeyEvent +// + +keyEvent.type; +keyEvent.character; +keyEvent.key; +keyEvent.toString(); + + +// +// PaperScope +// + +new paper.PaperScope(); +paperScope.version; +paperScope.settings; +paperScope.settings = null; +paperScope.project; +paperScope.projects; +paperScope.view; +paperScope.tool; +paperScope.tools; +paperScope.execute(''); +paperScope.execute('', object); +paperScope.install(object); +paperScope.setup(''); +paperScope.setup({} as HTMLCanvasElement); +paperScope.setup(size); +paperScope.activate(); +paper.PaperScope.get(0); +new paperScope.Color(''); +new paperScope.CompoundPath(''); +new paperScope.Curve(segment, segment); +new paperScope.CurveLocation(curve, 0); +new paperScope.Event(); +new paperScope.Gradient(); +new paperScope.GradientStop(); +new paperScope.Group(); +new paperScope.HitResult(); +new paperScope.Item(); +new paperScope.Key(); +new paperScope.KeyEvent(); +new paperScope.Layer(); +new paperScope.Matrix(); +new paperScope.MouseEvent(); +new paperScope.PaperScript(); +new paperScope.Path(); +new paperScope.PathItem(); +new paperScope.Point(0, 0); +new paperScope.PointText(point); +new paperScope.Project(size); +new paperScope.Raster(); +new paperScope.Rectangle(point, size); +new paperScope.Segment(); +new paperScope.Shape(); +new paperScope.Size(0,0); +new paperScope.Style(object); +new paperScope.SymbolDefinition(item); +new paperScope.SymbolItem(symbolDefinition); +new paperScope.TextItem(); +new paperScope.Tool(); +new paperScope.ToolEvent(); +new paperScope.Tween(object, object, object, 0); +new paperScope.View(); + + +// +// Global PaperScope instance +// + +paper.version; +paper.settings; +paper.project; +paper.projects; +paper.view; +paper.tool; +paper.tools; +paper.execute(''); +paper.execute('', object); +paper.install(object); +paper.setup(''); +paper.setup({} as HTMLCanvasElement); +paper.setup(size); +paper.activate(); + + +// +// PaperScript +// + +paper.PaperScript.compile(''); +paper.PaperScript.compile('', object); +paper.PaperScript.execute('', paperScope); +paper.PaperScript.execute('', paperScope, object); +paper.PaperScript.load(); +paper.PaperScript.load({} as HTMLScriptElement); diff --git a/gulp/utils/error.js b/gulp/utils/error.js index cfd92c58..b61b9a82 100644 --- a/gulp/utils/error.js +++ b/gulp/utils/error.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/gulp/utils/options.js b/gulp/utils/options.js index b9e4a414..09b48cc4 100644 --- a/gulp/utils/options.js +++ b/gulp/utils/options.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -24,9 +24,10 @@ options.date = git('log -1 --pretty=format:%ad'); options.branch = git('rev-parse --abbrev-ref HEAD'); // If a specific branch is requested, quit without errors if we don't match. -if (argv.branch && argv.branch !== options.branch) { - console.log('Branch "' + options.branch + '" does not match "' + - argv.branch + '". There is nothing to do here.'); +var ensureBranch = argv['ensure-branch']; +if (ensureBranch && ensureBranch !== options.branch) { + console.log('Branch "' + options.branch + '" does not match requested "' + + ensureBranch + '". There is nothing to do here.'); process.exit(0); } diff --git a/gulpfile.js b/gulpfile.js index 0e6e6fc3..ecb7f8d1 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/package.json b/package.json index b7951e6a..e157fdcc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@scratch/paper", - "version": "0.11.8", + "version": "0.12.3", "description": "The Swiss Army Knife of Vector Graphics Scripting", "license": "MIT", "homepage": "http://paperjs.org", @@ -9,11 +9,13 @@ "url": "https://github.com/paperjs/paper.js" }, "bugs": "https://github.com/paperjs/paper.js/issues", - "contributors": ["Jürg Lehni (http://scratchdisk.com)", "Jonathan Puckey (http://studiomoniker.com)"], + "contributors": [ + "Jürg Lehni (http://scratchdisk.com)", + "Jonathan Puckey (http://studiomoniker.com)" + ], "main": "dist/paper-full.js", + "types": "dist/paper.d.ts", "scripts": { - "precommit": "gulp jshint --branch develop", - "prepush": "gulp test --branch develop", "build": "gulp build", "dist": "gulp dist", "zip": "gulp zip", @@ -22,44 +24,22 @@ "jshint": "gulp jshint", "test": "gulp test" }, - "files": ["AUTHORS.md", "CHANGELOG.md", "dist/", "examples/", "LICENSE.txt", "README.md"], + "files": [ + "AUTHORS.md", + "CHANGELOG.md", + "dist/", + "examples/", + "LICENSE.txt", + "README.md" + ], "engines": { - "node": ">=4.0.0" + "node": ">=8.0.0" }, - "devDependencies": { - "acorn": "~0.5.0", - "canvas-prebuilt": "^2.0.0-alpha.14", - "del": "^2.2.1", - "gulp": "^3.9.1", - "gulp-cached": "^1.1.0", - "gulp-git-streamed": "^2.8.1", - "gulp-jshint": "^2.0.0", - "gulp-json-editor": "^2.2.1", - "gulp-prepro": "^2.4.0", - "gulp-qunits": "^2.1.1", - "gulp-rename": "^1.2.2", - "gulp-shell": "^0.5.2", - "gulp-symlink": "^2.1.4", - "gulp-uglify": "^1.5.4", - "gulp-uncomment": "^0.3.0", - "gulp-util": "^3.0.7", - "gulp-webserver": "^0.9.1", - "gulp-whitespace": "^0.1.0", - "gulp-zip": "^3.2.0", - "husky": "^0.11.4", - "jsdom": "^9.4.0", - "jshint": "^2.9.2", - "jshint-summary": "^0.4.0", - "merge-stream": "^1.0.0", - "minimist": "^1.2.0", - "prepro": "^2.4.0", - "qunitjs": "^1.23.0", - "require-dir": "^0.3.0", - "resemblejs": "^2.2.1", - "run-sequence": "^1.2.2", - "source-map-support": "^0.4.0", - "stats.js": "0.16.0", - "straps": "^3.0.1" + "husky": { + "hooks": { + "pre-commit": "gulp jshint --ensure-branch develop", + "pre-push": "gulp test --ensure-branch develop" + } }, "browser": { "canvas": false, @@ -69,5 +49,58 @@ "./dist/node/self.js": false, "./dist/node/extend.js": false }, - "keywords": ["vector", "graphic", "graphics", "2d", "geometry", "bezier", "curve", "curves", "path", "paths", "canvas", "svg", "paper", "paper.js", "paperjs"] + "devDependencies": { + "acorn": "~0.5.0", + "canvas": "^2.6.0", + "del": "^4.1.0", + "gulp": "^3.9.1", + "gulp-cached": "^1.1.0", + "gulp-git-streamed": "^2.8.1", + "gulp-jshint": "^2.1.0", + "gulp-json-editor": "^2.5.2", + "gulp-prepro": "^2.4.0", + "gulp-qunits": "^2.1.2", + "gulp-rename": "^1.4.0", + "gulp-shell": "^0.7.0", + "gulp-symlink": "^2.1.4", + "gulp-uglify": "^1.5.4", + "gulp-uncomment": "^0.3.0", + "gulp-util": "^3.0.7", + "gulp-webserver": "^0.9.1", + "gulp-whitespace": "^0.1.0", + "gulp-zip": "^3.2.0", + "husky": "^2.3.0", + "jsdom": "^15.1.1", + "jshint": "^2.10.2", + "jshint-summary": "^0.4.0", + "merge-stream": "^2.0.0", + "minimist": "^1.2.0", + "mustache": "^3.0.1", + "prepro": "^2.4.0", + "qunitjs": "^1.23.0", + "require-dir": "^1.2.0", + "resemblejs": "^3.2.3", + "run-sequence": "^2.2.1", + "source-map-support": "^0.5.12", + "stats.js": "0.17.0", + "straps": "^3.0.1", + "typescript": "^3.1.6" + }, + "keywords": [ + "vector", + "graphic", + "graphics", + "2d", + "geometry", + "bezier", + "curve", + "curves", + "path", + "paths", + "canvas", + "svg", + "paper", + "paper.js", + "paperjs" + ] } diff --git a/packages/paper-jsdom b/packages/paper-jsdom index f601084f..0fb6283f 160000 --- a/packages/paper-jsdom +++ b/packages/paper-jsdom @@ -1 +1 @@ -Subproject commit f601084fc319734d0bf47da700d6b6bff95260ba +Subproject commit 0fb6283f0955b8ee92fc9ac8838f167ea4a965d2 diff --git a/packages/paper-jsdom-canvas b/packages/paper-jsdom-canvas index a07b7d14..1e276564 160000 --- a/packages/paper-jsdom-canvas +++ b/packages/paper-jsdom-canvas @@ -1 +1 @@ -Subproject commit a07b7d149f02e980dfd837cd595f5000a9d5e052 +Subproject commit 1e276564106e5a29a6e00115c7e703cfc1fc2b09 diff --git a/src/anim/Tween.js b/src/anim/Tween.js new file mode 100644 index 00000000..790fee86 --- /dev/null +++ b/src/anim/Tween.js @@ -0,0 +1,398 @@ +/* + * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. + * http://paperjs.org/ + * + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +/** + * @name Tween + * + * @class Allows tweening `Object` properties between two states for a given + * duration. To tween properties on Paper.js {@link Item} instances, + * {@link Item#tween(from, to, options)} can be used, which returns created + * tween instance. + * + * @see Item#tween(from, to, options) + * @see Item#tween(to, options) + * @see Item#tween(options) + * @see Item#tweenTo(to, options) + * @see Item#tweenFrom(from, options) + */ +var Tween = Base.extend(Emitter, /** @lends Tween# */{ + _class: 'Tween', + + statics: { + easings: { + // no easing, no acceleration + linear: function(t) { + return t; + }, + + // accelerating from zero velocity + easeInQuad: function(t) { + return t * t; + }, + + // decelerating to zero velocity + easeOutQuad: function(t) { + return t * (2 - t); + }, + + // acceleration until halfway, then deceleration + easeInOutQuad: function(t) { + return t < 0.5 + ? 2 * t * t + : -1 + 2 * (2 - t) * t; + }, + + // accelerating from zero velocity + easeInCubic: function(t) { + return t * t * t; + }, + + // decelerating to zero velocity + easeOutCubic: function(t) { + return --t * t * t + 1; + }, + + // acceleration until halfway, then deceleration + easeInOutCubic: function(t) { + return t < 0.5 + ? 4 * t * t * t + : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + }, + + // accelerating from zero velocity + easeInQuart: function(t) { + return t * t * t * t; + }, + + // decelerating to zero velocity + easeOutQuart: function(t) { + return 1 - (--t) * t * t * t; + }, + + // acceleration until halfway, then deceleration + easeInOutQuart: function(t) { + return t < 0.5 + ? 8 * t * t * t * t + : 1 - 8 * (--t) * t * t * t; + }, + + // accelerating from zero velocity + easeInQuint: function(t) { + return t * t * t * t * t; + }, + + // decelerating to zero velocity + easeOutQuint: function(t) { + return 1 + --t * t * t * t * t; + }, + + // acceleration until halfway, then deceleration + easeInOutQuint: function(t) { + return t < 0.5 + ? 16 * t * t * t * t * t + : 1 + 16 * (--t) * t * t * t * t; + } + } + }, + + /** + * Creates a new tween. + * + * @param {Object} object the object to tween the properties on + * @param {Object} from the state at the start of the tweening + * @param {Object} to the state at the end of the tweening + * @param {Number} duration the duration of the tweening + * @param {String|Function} [easing='linear'] the type of the easing + * function or the easing function + * @param {Boolean} [start=true] whether to start tweening automatically + * @return {Tween} the newly created tween + */ + initialize: function Tween(object, from, to, duration, easing, start) { + this.object = object; + var type = typeof easing; + var isFunction = type === 'function'; + this.type = isFunction + ? type + : type === 'string' + ? easing + : 'linear'; + this.easing = isFunction ? easing : Tween.easings[this.type]; + this.duration = duration; + this.running = false; + + this._then = null; + this._startTime = null; + var state = from || to; + this._keys = state ? Object.keys(state) : []; + this._parsedKeys = this._parseKeys(this._keys); + this._from = state && this._getState(from); + this._to = state && this._getState(to); + if (start !== false) { + this.start(); + } + }, + + /** + * Set a function that will be executed when the tween completes. + * @param {Function} function the function to execute when the tween + * completes + * @return {Tween} + * + * @example {@paperscript} + * // Tweens chaining: + * var circle = new Path.Circle({ + * center: view.center, + * radius: 40, + * fillColor: 'blue' + * }); + * // Tween color from blue to red. + * var tween = circle.tweenTo({ fillColor: 'red' }, 2000); + * // When the first tween completes... + * tween.then(function() { + * // ...tween color back to blue. + * circle.tweenTo({ fillColor: 'blue' }, 2000); + * }); + */ + then: function(then) { + this._then = then; + return this; + }, + + /** + * Start tweening. + * @return {Tween} + * + * @example {@paperscript} + * // Manually start tweening. + * var circle = new Path.Circle({ + * center: view.center, + * radius: 40, + * fillColor: 'blue' + * }); + * var tween = circle.tweenTo( + * { fillColor: 'red' }, + * { duration: 2000, start: false } + * ); + * tween.start(); + */ + start: function() { + this._startTime = null; + this.running = true; + return this; + }, + + /** + * Stop tweening. + * @return {Tween} + * + * @example {@paperscript} + * // Stop a tween before it completes. + * var circle = new Path.Circle({ + * center: view.center, + * radius: 40, + * fillColor: 'blue' + * }); + * // Start tweening from blue to red for 2 seconds. + * var tween = circle.tweenTo({ fillColor: 'red' }, 2000); + * // After 1 second... + * setTimeout(function(){ + * // ...stop tweening. + * tween.stop(); + * }, 1000); + */ + stop: function() { + this.running = false; + return this; + }, + + // DOCS: Document Tween#update(progress) + update: function(progress) { + if (this.running) { + if (progress > 1) { + // always finish the animation + progress = 1; + this.running = false; + } + + var factor = this.easing(progress), + keys = this._keys, + getValue = function(value) { + return typeof value === 'function' + ? value(factor, progress) + : value; + }; + for (var i = 0, l = keys && keys.length; i < l; i++) { + var key = keys[i], + from = getValue(this._from[key]), + to = getValue(this._to[key]), + // Some paper objects have math functions (e.g.: Point, + // Color) which can directly be used to do the tweening. + value = (from && to && from.__add && to.__add) + ? to.__subtract(from).__multiply(factor).__add(from) + : ((to - from) * factor) + from; + this._setProperty(this._parsedKeys[key], value); + } + + if (!this.running && this._then) { + // TODO Look into what should be returned. + this._then(this.object); + } + if (this.responds('update')) { + this.emit('update', new Base({ + progress: progress, + factor: factor + })); + } + } + return this; + }, + + /** + * {@grouptitle Event Handlers} + * + * The function to be called when the tween is updated. It receives an + * object as its sole argument, containing the current progress of the + * tweening and the factor calculated by the easing function. + * + * @name Tween#onUpdate + * @property + * @type Function + * + * @example {@paperscript} + * // Display tween progression values: + * var circle = new Path.Circle({ + * center: view.center, + * radius: 40, + * fillColor: 'blue' + * }); + * var tween = circle.tweenTo( + * { fillColor: 'red' }, + * { + * duration: 2000, + * easing: 'easeInCubic' + * } + * ); + * var progressText = new PointText(view.center + [60, -10]); + * var factorText = new PointText(view.center + [60, 10]); + * + * // Install event using onUpdate() property: + * tween.onUpdate = function(event) { + * progressText.content = 'progress: ' + event.progress.toFixed(2); + * }; + * + * // Install event using on('update') method: + * tween.on('update', function(event) { + * factorText.content = 'factor: ' + event.factor.toFixed(2); + * }); + */ + _events: { + onUpdate: {} + }, + + _handleFrame: function(time) { + var startTime = this._startTime, + progress = startTime + ? (time - startTime) / this.duration + : 0; + if (!startTime) { + this._startTime = time; + } + this.update(progress); + }, + + _getState: function(state) { + var keys = this._keys, + result = {}; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i], + path = this._parsedKeys[key], + current = this._getProperty(path), + value; + if (state) { + var resolved = this._resolveValue(current, state[key]); + // Temporarily set the resolved value, so we can retrieve the + // coerced value from paper's internal magic. + this._setProperty(path, resolved); + value = this._getProperty(path); + // Clone the value if possible to prevent future changes. + value = value && value.clone ? value.clone() : value; + this._setProperty(path, current); + } else { + // We want to get the current state at the time of the call, so + // we have to clone if possible to prevent future changes. + value = current && current.clone ? current.clone() : current; + } + result[key] = value; + } + return result; + }, + + _resolveValue: function(current, value) { + if (value) { + if (Array.isArray(value) && value.length === 2) { + var operator = value[0]; + return ( + operator && + operator.match && + // We're (unnecessarily) escaping '*/' here to not confuse + // the ol' JSDoc parser... + operator.match(/^[+\-\*\/]=/) + ) + ? this._calculate(current, operator[0], value[1]) + : value; + } else if (typeof value === 'string') { + var match = value.match(/^[+\-*/]=(.*)/); + if (match) { + var parsed = JSON.parse(match[1].replace( + /(['"])?([a-zA-Z0-9_]+)(['"])?:/g, + '"$2": ' + )); + return this._calculate(current, value[0], parsed); + } + } + } + return value; + }, + + _calculate: function(left, operator, right) { + return paper.PaperScript.calculateBinary(left, operator, right); + }, + + _parseKeys: function(keys) { + var parsed = {}; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i], + path = key + // Convert from JS property access notation to JSON pointer: + .replace(/\.([^.]*)/g, '/$1') + // Expand array property access notation ([]) + .replace(/\[['"]?([^'"\]]*)['"]?\]/g, '/$1'); + parsed[key] = path.split('/'); + } + return parsed; + }, + + _getProperty: function(path, offset) { + var obj = this.object; + for (var i = 0, l = path.length - (offset || 0); i < l && obj; i++) { + obj = obj[path[i]]; + } + return obj; + }, + + _setProperty: function(path, value) { + var dest = this._getProperty(path, 1); + if (dest) { + dest[path[path.length - 1]] = value; + } + } +}); diff --git a/src/basic/Line.js b/src/basic/Line.js index fc08eb71..84893fd8 100644 --- a/src/basic/Line.js +++ b/src/basic/Line.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -12,8 +12,8 @@ /** * @name Line - * * @class The Line object represents.. + * @private */ var Line = Base.extend(/** @lends Line# */{ _class: 'Line', diff --git a/src/basic/Matrix.js b/src/basic/Matrix.js index 32d4d75c..5ac409ab 100644 --- a/src/basic/Matrix.js +++ b/src/basic/Matrix.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -104,6 +104,8 @@ var Matrix = Base.extend(/** @lends Matrix# */{ * also work for calls of `set()`. * * @function + * @param {...*} values + * @return {Point} */ set: '#initialize', @@ -183,7 +185,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{ * Attempts to apply the matrix to the content of item that it belongs to, * meaning its transformation is baked into the item's content or children. * - * @param {Boolean} recursively controls whether to apply transformations + * @param {Boolean} [recursively=true] controls whether to apply transformations * recursively on children * @return {Boolean} {@true if the matrix was applied} */ @@ -449,7 +451,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{ /** * Returns a new matrix as the result of prepending the specified matrix * to this matrix. This is the equivalent of multiplying - * `(specified matrix) s* (this matrix)`. + * `(specified matrix) * (this matrix)`. * * @param {Matrix} matrix the matrix to prepend * @return {Matrix} the newly created matrix @@ -498,15 +500,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{ }, /** - * @deprecated use use {@link #append(matrix)} instead. + * @deprecated use {@link #append(matrix)} instead. */ concatenate: '#append', /** - * @deprecated use use {@link #prepend(matrix)} instead. + * @deprecated use {@link #prepend(matrix)} instead. */ preConcatenate: '#prepend', /** - * @deprecated use use {@link #appended(matrix)} instead. + * @deprecated use {@link #appended(matrix)} instead. */ chain: '#appended', @@ -644,6 +646,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{ * Inverse transforms a point and returns the result. * * @param {Point} point the point to be transformed + * @return {Point} */ inverseTransform: function(/* point */) { return this._inverseTransform(Point.read(arguments)); diff --git a/src/basic/Point.js b/src/basic/Point.js index e9b260dd..9765162a 100644 --- a/src/basic/Point.js +++ b/src/basic/Point.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -170,6 +170,8 @@ var Point = Base.extend(/** @lends Point# */{ * for calls of `set()`. * * @function + * @param {...*} values + * @return {Point} */ set: '#initialize', @@ -768,7 +770,7 @@ var Point = Base.extend(/** @lends Point# */{ * * @param {Number} quadrant the quadrant to check against * @return {Boolean} {@true if either x or y are not a number} - * @see #getQuadrant() + * @see #quadrant */ isInQuadrant: function(q) { // Map quadrant to x & y coordinate pairs and multiply with coordinates, diff --git a/src/basic/Rectangle.js b/src/basic/Rectangle.js index 0a2cae29..09a388aa 100644 --- a/src/basic/Rectangle.js +++ b/src/basic/Rectangle.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -73,7 +73,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ * Creates a new rectangle object from the passed rectangle object. * * @name Rectangle#initialize - * @param {Rectangle} rt + * @param {Rectangle} rectangle */ initialize: function Rectangle(arg0, arg1, arg2, arg3) { var type = typeof arg0, @@ -159,6 +159,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ * constructors also work for calls of `set()`. * * @function + * @param {...*} values + * @return {Rectangle} */ set: '#initialize', @@ -201,6 +203,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ /** * Returns a copy of the rectangle. + * @return {Rectangle} */ clone: function() { return new Rectangle(this.x, this.y, this.width, this.height); @@ -772,6 +775,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ * Rectangle#contains(point)} returns `false` for that point. * * @param {Point} point + * @return {Rectangle} the smallest rectangle that contains both the + * original rectangle and the specified point */ include: function(/* point */) { var point = Point.read(arguments); @@ -783,17 +788,18 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ }, /** - * Expands the rectangle by the specified amount in horizontal and - * vertical directions. + * Returns a new rectangle expanded by the specified amount in horizontal + * and vertical directions. * * @name Rectangle#expand * @function * @param {Number|Size|Point} amount the amount to expand the rectangle in * both directions + * @return {Rectangle} the expanded rectangle */ /** - * Expands the rectangle by the specified amounts in horizontal and - * vertical directions. + * Returns a new rectangle expanded by the specified amounts in horizontal + * and vertical directions. * * @name Rectangle#expand * @function @@ -801,6 +807,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ * direction * @param {Number} ver the amount to expand the rectangle in vertical * direction + * @return {Rectangle} the expanded rectangle */ expand: function(/* amount */) { var amount = Size.read(arguments), @@ -811,21 +818,23 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{ }, /** - * Scales the rectangle by the specified amount from its center. + * Returns a new rectangle scaled by the specified amount from its center. * * @name Rectangle#scale * @function * @param {Number} amount + * @return {Rectangle} the scaled rectangle */ /** - * Scales the rectangle in horizontal direction by the specified `hor` - * amount and in vertical direction by the specified `ver` amount from its - * center. + * Returns a new rectangle scaled in horizontal direction by the specified + * `hor` amount and in vertical direction by the specified `ver` amount + * from its center. * * @name Rectangle#scale * @function * @param {Number} hor * @param {Number} ver + * @return {Rectangle} the scaled rectangle */ scale: function(hor, ver) { return this.expand(this.width * hor - this.width, diff --git a/src/basic/Size.js b/src/basic/Size.js index af10e6b5..ba2e3f0b 100644 --- a/src/basic/Size.js +++ b/src/basic/Size.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -130,6 +130,8 @@ var Size = Base.extend(/** @lends Size# */{ * for calls of `set()`. * * @function + * @param {...*} values + * @return {Size} */ set: '#initialize', @@ -158,7 +160,7 @@ var Size = Base.extend(/** @lends Size# */{ * Checks whether the width and height of the size are equal to those of the * supplied size. * - * @param {Size} + * @param {Size} size the size to compare to * @return {Boolean} * * @example @@ -176,6 +178,7 @@ var Size = Base.extend(/** @lends Size# */{ /** * Returns a copy of the size. + * @return {Size} */ clone: function() { return new Size(this.width, this.height); diff --git a/src/canvas/BlendMode.js b/src/canvas/BlendMode.js index d3342bd8..ac9ea7d3 100644 --- a/src/canvas/BlendMode.js +++ b/src/canvas/BlendMode.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/canvas/CanvasProvider.js b/src/canvas/CanvasProvider.js index dd9ced59..3ac0aac0 100644 --- a/src/canvas/CanvasProvider.js +++ b/src/canvas/CanvasProvider.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/canvas/ProxyContext.js b/src/canvas/ProxyContext.js index b709bbde..5a403b48 100644 --- a/src/canvas/ProxyContext.js +++ b/src/canvas/ProxyContext.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/constants.js b/src/constants.js index b360edf0..0c84dbcf 100644 --- a/src/constants.js +++ b/src/constants.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/core/Base.js b/src/core/Base.js index 834c940f..52d963af 100644 --- a/src/core/Base.js +++ b/src/core/Base.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -558,8 +558,16 @@ statics: /** @lends Base */{ if (args.length === 1 && obj instanceof Item && (useTarget || !(obj instanceof Layer))) { var arg = args[0]; - if (Base.isPlainObject(arg)) + if (Base.isPlainObject(arg)) { arg.insert = false; + // When using target, make sure the `item.insert()` + // method is not overridden with the `arg.insert` + // property that was just set. Pass an exclude + // object to the call of `obj.set()` below (#1392). + if (useTarget) { + args = args.concat([{ insert: true }]); + } + } } // When reusing an object, initialize it through #set() // instead of the constructor function: diff --git a/src/core/Emitter.js b/src/core/Emitter.js index 0ad43233..0e9724d1 100644 --- a/src/core/Emitter.js +++ b/src/core/Emitter.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -68,9 +68,9 @@ var Emitter = { }, once: function(type, func) { - return this.on(type, function() { + return this.on(type, function handler() { func.apply(this, arguments); - this.off(type, func); + this.off(type, handler); }); }, diff --git a/src/core/PaperScope.js b/src/core/PaperScope.js index e60b834b..2d4f9670 100644 --- a/src/core/PaperScope.js +++ b/src/core/PaperScope.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -87,7 +87,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{ // here: { chrome: true, webkit: false }, Mozilla missing is the // only difference to jQuery.browser user.replace( - /(opera|chrome|safari|webkit|firefox|msie|trident|atom|node)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g, + /(opera|chrome|safari|webkit|firefox|msie|trident|atom|node|jsdom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g, function(match, n, v1, v2, rv) { // Do not set additional browsers once chrome is detected. if (!agent.chrome) { @@ -95,7 +95,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{ /^(node|trident)$/.test(n) ? rv : v1; agent.version = v; agent.versionNumber = parseFloat(v); - n = n === 'trident' ? 'msie' : n; + n = { trident: 'msie', jsdom: 'node' }[n] || n; agent.name = n; agent[n] = true; } @@ -112,6 +112,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{ * The version of Paper.js, as a string. * * @type String + * @readonly */ version: /*#=*/__options.version, @@ -200,7 +201,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{ * mapping, in case the code that's passed in has already been mingled. * * @param {String} code the PaperScript code - * @param {Object} [option] the compilation options + * @param {Object} [options] the compilation options */ execute: function(code, options) { /*#*/ if (__options.paperScript) { diff --git a/src/core/PaperScopeItem.js b/src/core/PaperScopeItem.js index f03b8904..8aa31a8b 100644 --- a/src/core/PaperScopeItem.js +++ b/src/core/PaperScopeItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/core/PaperScript.js b/src/core/PaperScript.js index 152ded69..ca1f393e 100644 --- a/src/core/PaperScript.js +++ b/src/core/PaperScript.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -127,7 +127,7 @@ Base.exports.PaperScript = function() { * mapping, in case the code that's passed in has already been mingled. * * @param {String} code the PaperScript code - * @param {Object} [option] the compilation options + * @param {Object} [options] the compilation options * @return {Object} an object holding the compiled PaperScript translated * into JavaScript code along with source-maps and other information. */ @@ -177,7 +177,7 @@ Base.exports.PaperScript = function() { var start = getOffset(node.range[0]), end = getOffset(node.range[1]), insert = 0; - // Sort insertions by their offset, so getOffest() can do its thing + // Sort insertions by their offset, so getOffset() can do its thing for (var i = insertions.length - 1; i >= 0; i--) { if (start > insertions[i][0]) { insert = i + 1; @@ -256,12 +256,19 @@ Base.exports.PaperScript = function() { exp = '__$__(' + arg + ', "' + node.operator[0] + '", 1)', str = arg + ' = ' + exp; - // If this is not a prefixed update expression - // (++a, --a), assign the old value before updating it. - if (!node.prefix - && (parentType === 'AssignmentExpression' - || parentType === 'VariableDeclarator')) { - // Handle special issue #691 where the old value is + if (node.prefix) { + // A prefixed update expression (++a / --a), + // wrap expression in paranthesis. See #1611 + str = '(' + str + ')'; + } else if ( + // A suffixed update expression (a++, a--), + // assign the old value before updating it. + // See #691, #1450 + parentType === 'AssignmentExpression' || + parentType === 'VariableDeclarator' || + parentType === 'BinaryExpression' + ) { + // Handle special case where the old value is // assigned to itself, and the expression is just // executed after, e.g.: `var x = ***; x = x++;` if (getCode(parent.left || parent.id) === arg) @@ -323,7 +330,7 @@ Base.exports.PaperScript = function() { // Source-map support: // Encodes a Variable Length Quantity as a Base64 string. - // See: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps + // See: https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/ function encodeVLQ(value) { var res = '', base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; @@ -441,8 +448,8 @@ Base.exports.PaperScript = function() { * * @param {String} code the PaperScript code * @param {PaperScope} scope the scope for which the code is executed - * @param {Object} [option] the compilation options - * @return the exports defined in the executed code + * @param {Object} [options] the compilation options + * @return {Object} the exports defined in the executed code */ function execute(code, scope, options) { // Set currently active scope. @@ -484,7 +491,7 @@ Base.exports.PaperScript = function() { } } } - expose({ __$__: __$__, $__: $__, paper: scope, view: view, tool: tool }, + expose({ __$__: __$__, $__: $__, paper: scope, tool: tool }, true); expose(scope); // Add a fake `module.exports` object so PaperScripts can export things. @@ -657,7 +664,9 @@ Base.exports.PaperScript = function() { compile: compile, execute: execute, load: load, - parse: parse + parse: parse, + calculateBinary: __$__, + calculateUnary: $__ }; // Pass on `this` as the binding object, so we can reference Acorn both in // development and in the built library. diff --git a/src/docs/global.js b/src/docs/global.js index 4d8c8a82..29de23d9 100644 --- a/src/docs/global.js +++ b/src/docs/global.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -39,7 +39,7 @@ * * The project for which the PaperScript is executed. * - * Note that when working with mulitple projects, this does not necessarily + * Note that when working with multiple projects, this does not necessarily * reflect the currently active project. For this, use * {@link PaperScope#project} instead. * @@ -57,19 +57,20 @@ /** * The reference to the project's view. * - * Note that when working with mulitple projects, this does not necessarily + * Note that when working with multiple projects, this does not necessarily * reflect the view of the currently active project. For this, use * {@link PaperScope#view} instead. * * @name view * @type View + * @readonly */ /** * The reference to the tool object which is automatically created when global * tool event handlers are defined. * - * Note that when working with mulitple tools, this does not necessarily + * Note that when working with multiple tools, this does not necessarily * reflect the currently active tool. For this, use {@link PaperScope#tool} * instead. * diff --git a/src/dom/DomElement.js b/src/dom/DomElement.js index 035f6cab..6b92c895 100644 --- a/src/dom/DomElement.js +++ b/src/dom/DomElement.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/dom/DomEvent.js b/src/dom/DomEvent.js index c6786006..56ac214f 100644 --- a/src/dom/DomEvent.js +++ b/src/dom/DomEvent.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/event/Event.js b/src/event/Event.js index 5beca73c..297282e0 100644 --- a/src/event/Event.js +++ b/src/event/Event.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/event/Key.js b/src/event/Key.js index c8746429..be425b42 100644 --- a/src/event/Key.js +++ b/src/event/Key.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/event/KeyEvent.js b/src/event/KeyEvent.js index c20af658..b19539db 100644 --- a/src/event/KeyEvent.js +++ b/src/event/KeyEvent.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/event/MouseEvent.js b/src/event/MouseEvent.js index 93859adb..6700cba3 100644 --- a/src/event/MouseEvent.js +++ b/src/event/MouseEvent.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/export.js b/src/export.js index 0ac7f578..dc4d5d9e 100644 --- a/src/export.js +++ b/src/export.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/init.js b/src/init.js index 3e726c91..58d76e46 100644 --- a/src/init.js +++ b/src/init.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/ChangeFlag.js b/src/item/ChangeFlag.js index fd1aaede..4592c2c1 100644 --- a/src/item/ChangeFlag.js +++ b/src/item/ChangeFlag.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/Group.js b/src/item/Group.js index f9e36070..c3bd085c 100644 --- a/src/item/Group.js +++ b/src/item/Group.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -171,8 +171,7 @@ var Group = Item.extend(/** @lends Group# */{ _getBounds: function _getBounds(matrix, options) { var clipItem = this._getClipItem(); return clipItem - ? clipItem._getCachedBounds( - matrix && matrix.appended(clipItem._matrix), + ? clipItem._getCachedBounds(clipItem._matrix.prepended(matrix), Base.set({}, options, { stroke: false })) : _getBounds.base.call(this, matrix, options); }, diff --git a/src/item/HitResult.js b/src/item/HitResult.js index 460ee4b0..ee804160 100644 --- a/src/item/HitResult.js +++ b/src/item/HitResult.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/Item.js b/src/item/Item.js index 6e2dfc63..5ba11339 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -658,8 +658,8 @@ new function() { // Injection scope for various item event handlers /** * Specifies whether the item defines a clip mask. This can only be set on - * paths, compound paths, and text frame objects, and only if the item is - * already contained within a clipping group. + * paths and compound paths, and only if the item is already contained + * within a clipping group. * * @bean * @type Boolean @@ -1075,7 +1075,9 @@ new function() { // Injection scope for various item event handlers options = options || {}; for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; - if (item._visible && !item.isEmpty()) { + // Item is handled if it is visible and not recursively empty. + // This avoid errors with nested empty groups (#1467). + if (item._visible && !item.isEmpty(true)) { // Pass true for noInternal, since even when getting // internal bounds for this item, we need to apply the // matrices to its children. @@ -1120,6 +1122,17 @@ new function() { // Injection scope for various item event handlers * @type Rectangle */ + /** + * The bounding rectangle of the item without any matrix transformations. + * + * Typical use case would be drawing a frame around the object where you + * want to draw something of the same size, position, rotation, and scaling, + * like a selection frame. + * + * @name Item#internalBounds + * @type Rectangle + */ + /** * The rough bounding rectangle of the item that is sure to include all of * the drawing, including stroke width. @@ -1805,11 +1818,15 @@ new function() { // Injection scope for various item event handlers * } * * @param {Point} point the point to check for + * @return {Boolean} */ contains: function(/* point */) { // See CompoundPath#_contains() for the reason for !! - return !!this._contains( - this._matrix._inverseTransform(Point.read(arguments))); + var matrix = this._matrix; + return ( + matrix.isInvertible() && + !!this._contains(matrix._inverseTransform(Point.read(arguments))) + ); }, _contains: function(point) { @@ -2353,6 +2370,7 @@ new function() { // Injection scope for hit-test functions shared with project * items can have children. * * @param {String} json the JSON data to import from + * @return {Item} */ importJSON: function(json) { // Try importing into `this`. If another item is returned, try adding @@ -2388,7 +2406,8 @@ new function() { // Injection scope for hit-test functions shared with project * kept as a link to their external URL. * * @param {Object} [options] the export options - * @return {SVGElement} the item converted to an SVG node + * @return {SVGElement|String} the item converted to an SVG node or a + * `String` depending on `option.asString` value */ /** @@ -2772,6 +2791,7 @@ new function() { // Injection scope for hit-test functions shared with project * Replaces this item with the provided new item which will takes its place * in the project hierarchy instead. * + * @param {Item} item the item that will replace this item * @return {Boolean} {@true if the item was replaced} */ replaceWith: function(item) { @@ -2840,11 +2860,23 @@ new function() { // Injection scope for hit-test functions shared with project * no children, a {@link TextItem} with no text content and a {@link Path} * with no segments all are considered empty. * + * @param {Boolean} [recursively=false] whether an item with children should be + * considered empty if all its descendants are empty * @return Boolean */ - isEmpty: function() { + isEmpty: function(recursively) { var children = this._children; - return !children || !children.length; + var numChildren = children ? children.length : 0; + if (recursively) { + // In recursive check, item is empty if all its children are empty. + for (var i = 0; i < numChildren; i++) { + if (!children[i].isEmpty(recursively)) { + return false; + } + } + return true; + } + return !numChildren; }, /** @@ -3194,7 +3226,7 @@ new function() { // Injection scope for hit-test functions shared with project * * @name Item#dashArray * @property - * @type Array + * @type Number[] * @default [] */ @@ -4417,8 +4449,10 @@ new function() { // Injection scope for hit-test functions shared with project this._draw(ctx, param, viewMatrix, strokeMatrix); ctx.restore(); matrices.pop(); - if (param.clip && !param.dontFinish) - ctx.clip(); + if (param.clip && !param.dontFinish) { + // Pass fill-rule to handle clipping with compound-paths (#1361). + ctx.clip(this.getFillRule()); + } // If a temporary canvas was created, composite it onto the main canvas: if (!direct) { // Use BlendMode.process even for processing normal blendMode with @@ -4672,4 +4706,176 @@ new function() { // Injection scope for hit-test functions shared with project } return this; } -})); +}), /** @lends Item# */{ + /** + * {@grouptitle Tweening Functions} + * + * Tween item between two states. + * + * @name Item#tween + * + * @option options.duration {Number} the duration of the tweening + * @option [options.easing='linear'] {Function|String} an easing function or the type + * of the easing: {@values 'linear' 'easeInQuad' 'easeOutQuad' + * 'easeInOutQuad' 'easeInCubic' 'easeOutCubic' 'easeInOutCubic' + * 'easeInQuart' 'easeOutQuart' 'easeInOutQuart' 'easeInQuint' + * 'easeOutQuint' 'easeInOutQuint'} + * @option [options.start=true] {Boolean} whether to start tweening automatically + * + * @function + * @param {Object} from the state at the start of the tweening + * @param {Object} to the state at the end of the tweening + * @param {Object|Number} options the options or the duration + * @return {Tween} + * + * @example {@paperscript height=100} + * // Tween fillColor: + * var path = new Path.Circle({ + * radius: view.bounds.height * 0.4, + * center: view.center + * }); + * path.tween( + * { fillColor: 'blue' }, + * { fillColor: 'red' }, + * 3000 + * ); + * @example {@paperscript height=100} + * // Tween rotation: + * var path = new Shape.Rectangle({ + * fillColor: 'red', + * center: [50, view.center.y], + * size: [60, 60] + * }); + * path.tween({ + * rotation: 180, + * 'position.x': view.bounds.width - 50, + * 'fillColor.hue': '+= 90' + * }, { + * easing: 'easeInOutCubic', + * duration: 2000 + * }); + */ + /** + * Tween item to a state. + * + * @name Item#tween + * + * @function + * @param {Object} to the state at the end of the tweening + * @param {Object|Number} options the options or the duration + * @return {Tween} + * + * @example {@paperscript height=200} + * // Tween a nested property with relative values + * var path = new Path.Rectangle({ + * size: [100, 100], + * position: view.center, + * fillColor: 'red', + * }); + * + * var delta = { x: path.bounds.width / 2, y: 0 }; + * + * path.tween({ + * 'segments[1].point': ['+=', delta], + * 'segments[2].point.x': '-= 50' + * }, 3000); + * + * @see Item#tween(from, to, options) + */ + /** + * Tween item. + * + * @name Item#tween + * + * @function + * @param {Object|Number} options the options or the duration + * @return {Tween} + * + * @see Item#tween(from, to, options) + * + * @example {@paperscript height=100} + * // Start an empty tween and just use the update callback: + * var path = new Path.Circle({ + * fillColor: 'blue', + * radius: view.bounds.height * 0.4, + * center: view.center, + * }); + * var pathFrom = path.clone({ insert: false }) + * var pathTo = new Path.Rectangle({ + * position: view.center, + * rectangle: path.bounds, + * insert: false + * }); + * path.tween(2000).onUpdate = function(event) { + * path.interpolate(pathFrom, pathTo, event.factor) + * }; + */ + tween: function(from, to, options) { + if (!options) { + // If there are only two or one arguments, shift arguments to the + // left by one (omit `from`): + options = to; + to = from; + from = null; + if (!options) { + options = to; + to = null; + } + } + var easing = options && options.easing, + start = options && options.start, + duration = options != null && ( + typeof options === 'number' ? options : options.duration + ), + tween = new Tween(this, from, to, duration, easing, start); + function onFrame(event) { + tween._handleFrame(event.time * 1000); + if (!tween.running) { + this.off('frame', onFrame); + } + } + if (duration) { + this.on('frame', onFrame); + } + return tween; + }, + + /** + * + * Tween item to a state. + * + * @function + * @param {Object} to the state at the end of the tweening + * @param {Object|Number} options the options or the duration + * @return {Tween} + * + * @see Item#tween(to, options) + */ + tweenTo: function(to, options) { + return this.tween(null, to, options); + }, + + /** + * + * Tween item from a state to its state before the tweening. + * + * @function + * @param {Object} from the state at the start of the tweening + * @param {Object|Number} options the options or the duration + * @return {Tween} + * + * @see Item#tween(from, to, options) + * + * @example {@paperscript height=100} + * // Tween fillColor from red to the path's initial fillColor: + * var path = new Path.Circle({ + * fillColor: 'blue', + * radius: view.bounds.height * 0.4, + * center: view.center + * }); + * path.tweenFrom({ fillColor: 'red' }, { duration: 1000 }); + */ + tweenFrom: function(from, options) { + return this.tween(from, null, options); + } +}); diff --git a/src/item/ItemSelection.js b/src/item/ItemSelection.js index 94d75180..4b928e4c 100644 --- a/src/item/ItemSelection.js +++ b/src/item/ItemSelection.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/Layer.js b/src/item/Layer.js index 5650f505..5229b1cb 100644 --- a/src/item/Layer.js +++ b/src/item/Layer.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/Project.js b/src/item/Project.js index 8a7ad5c4..8d69d55e 100644 --- a/src/item/Project.js +++ b/src/item/Project.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -133,7 +133,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ /** * Checks whether the project has any content or not. * - * @return Boolean + * @return {Boolean} */ isEmpty: function() { return !this._children.length; @@ -348,7 +348,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ * {@link #layers} list. * * @param {Number} index the index at which to insert the layer - * @param {Item} item the item to be inserted in the project + * @param {Layer} layer the layer to be inserted in the project * @return {Layer} the added layer, or `null` if adding was not possible */ insertLayer: function(index, layer) { @@ -745,6 +745,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ * {@link Project#clear()} to do so. * * @param {String} json the JSON data to import from + * @return {Item} the imported item */ importJSON: function(json) { this.activate(); @@ -781,7 +782,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ * kept as a link to their external URL. * * @param {Object} [options] the export options - * @return {SVGElement} the project converted to an SVG node + * @return {SVGElement|String} the project converted to an SVG node or a + * `String` depending on `option.asString` value */ /** diff --git a/src/item/Raster.js b/src/item/Raster.js index c7a6cd39..b90b6060 100644 --- a/src/item/Raster.js +++ b/src/item/Raster.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -18,6 +18,7 @@ * @extends Item */ var Raster = Item.extend(/** @lends Raster# */{ +}, /** @lends Raster# */{ _class: 'Raster', _applyMatrix: false, _canApplyMatrix: false, @@ -31,15 +32,19 @@ var Raster = Item.extend(/** @lends Raster# */{ // Prioritize `crossOrigin` over `source`: _prioritize: ['crossOrigin'], _smoothing: false, + // Enforce creation of beans, as bean getters have hidden parameters. + // See #getContext(_change) below. + beans: true, // TODO: Implement type, width, height. // TODO: Have SymbolItem & Raster inherit from a shared class? /** * Creates a new raster item from the passed argument, and places it in the - * active layer. `object` can either be a DOM Image, a Canvas, or a string + * active layer. `source` can either be a DOM Image, a Canvas, or a string * describing the URL to load the image from, or the ID of a DOM element to * get the image from (either a DOM Image or a Canvas). * + * @name Raster#initialize * @param {HTMLImageElement|HTMLCanvasElement|String} [source] the source of * the raster * @param {Point} [position] the center position at which the raster item is @@ -77,22 +82,64 @@ var Raster = Item.extend(/** @lends Raster# */{ * raster.scale(0.5); * raster.rotate(10); */ - initialize: function Raster(object, position) { - // Support two forms of item initialization: Passing one object literal - // describing all the different properties to be set, or an image - // (object) and a point where it should be placed (point). + /** + * Creates a new empty raster of the given size, and places it in the + * active layer. + * + * @name Raster#initialize + * @param {Size} size the size of the raster + * @param {Point} [position] the center position at which the raster item is + * placed + * + * @example {@paperscript height=150} + * // Creating an empty raster and fill it with random pixels: + * var width = 100; + * var height = 100; + * + * // Create an empty raster placed at view center. + * var raster = new Raster(new Size(width, height), view.center); + * + * // For all of its pixels... + * for (var i = 0; i < width; i++) { + * for (var j = 0; j < height; j++) { + * // ...set a random color. + * raster.setPixel(i, j, Color.random()); + * } + * } + */ + initialize: function Raster(source, position) { + // Support three forms of item initialization: + // - One object literal describing all the different properties. + // - An image (Image|Canvas|String) and an optional position (Point). + // - A size (Size) describing the canvas that will be created and an + // optional position (Point). // If _initialize can set properties through object literal, we're done. - // Otherwise we need to check the type of object: - if (!this._initialize(object, - position !== undefined && Point.read(arguments, 1))) { - // object can be an image, canvas, URL or DOM-ID: - var image = typeof object === 'string' - ? document.getElementById(object) : object; + // Otherwise we need to check the type of object: var image, + if (!this._initialize(source, + position !== undefined && Point.read(arguments))) { + var image, + type = typeof source, + object = type === 'string' + ? document.getElementById(source) + : type === 'object' + ? source + : null; + if (object && object !== Item.NO_INSERT) { + if (object.getContent || object.naturalHeight != null) { + image = object; + } else if (object) { + // See if the arguments describe the raster size: + var size = Size.read(arguments); + if (!size.isZero()) { + image = CanvasProvider.getCanvas(size); + } + } + } if (image) { // #setImage() handles both canvas and image types. this.setImage(image); } else { - this.setSource(object); + this.setSource(source); } } if (!this._size) { @@ -305,7 +352,7 @@ var Raster = Item.extend(/** @lends Raster# */{ * case `null` is returned instead. * * @bean - * @type HTMLCanvasELement + * @type HTMLCanvasElement */ getCanvas: function() { if (!this._canvas) { @@ -330,15 +377,15 @@ var Raster = Item.extend(/** @lends Raster# */{ * The Canvas 2D drawing context of the raster. * * @bean - * @type Context + * @type CanvasRenderingContext2D */ - getContext: function(modify) { + getContext: function(_change) { if (!this._context) this._context = this.getCanvas().getContext('2d'); // Support a hidden parameter that indicates if the context will be used - // to modify the Raster object. We can notify such changes ahead since + // to change the Raster object. We can notify such changes ahead since // they are only used afterwards for redrawing. - if (modify) { + if (_change) { // Also set _image to null since the Raster stops representing it. // NOTE: This should theoretically be in our own _changed() handler // for ChangeFlag.PIXELS, but since it's only happening in one place @@ -386,7 +433,11 @@ var Raster = Item.extend(/** @lends Raster# */{ crossOrigin = this._crossOrigin; if (crossOrigin) image.crossOrigin = crossOrigin; - image.src = src; + // Prevent setting image source to `null`, as this isn't supported by + // browsers, and it would actually throw exceptions in JSDOM. + // TODO: Look into fixing this bug in JSDOM. + if (src) + image.src = src; this.setImage(image); }, @@ -463,7 +514,7 @@ var Raster = Item.extend(/** @lends Raster# */{ * @param {Rectangle} rect the boundaries of the sub image in pixel * coordinates * - * @return {HTMLCanvasELement} the sub image as a Canvas object + * @return {HTMLCanvasElement} the sub image as a Canvas object */ getSubCanvas: function(/* rect */) { var rect = Rectangle.read(arguments), @@ -519,7 +570,7 @@ var Raster = Item.extend(/** @lends Raster# */{ /** * Draws an image on the raster. * - * @param {HTMLImageELement|HTMLCanvasELement} image + * @param {HTMLImageElement|HTMLCanvasElement} image * @param {Point} point the offset of the image as a point in pixel * coordinates */ @@ -614,8 +665,8 @@ var Raster = Item.extend(/** @lends Raster# */{ * * @name Raster#getPixel * @function - * @param x the x offset of the pixel in pixel coordinates - * @param y the y offset of the pixel in pixel coordinates + * @param {Number} x the x offset of the pixel in pixel coordinates + * @param {Number} y the y offset of the pixel in pixel coordinates * @return {Color} the color of the pixel */ /** @@ -623,7 +674,8 @@ var Raster = Item.extend(/** @lends Raster# */{ * * @name Raster#getPixel * @function - * @param point the offset of the pixel as a point in pixel coordinates + * @param {Point} point the offset of the pixel as a point in pixel + * coordinates * @return {Color} the color of the pixel */ getPixel: function(/* point */) { @@ -639,17 +691,18 @@ var Raster = Item.extend(/** @lends Raster# */{ * * @name Raster#setPixel * @function - * @param x the x offset of the pixel in pixel coordinates - * @param y the y offset of the pixel in pixel coordinates - * @param color the color that the pixel will be set to + * @param {Number} x the x offset of the pixel in pixel coordinates + * @param {Number} y the y offset of the pixel in pixel coordinates + * @param {Color} color the color that the pixel will be set to */ /** * Sets the color of the specified pixel to the specified color. * * @name Raster#setPixel * @function - * @param point the offset of the pixel as a point in pixel coordinates - * @param color the color that the pixel will be set to + * @param {Point} point the offset of the pixel as a point in pixel + * coordinates + * @param {Color} color the color that the pixel will be set to */ setPixel: function(/* point, color */) { var point = Point.read(arguments), @@ -666,6 +719,14 @@ var Raster = Item.extend(/** @lends Raster# */{ ctx.putImageData(imageData, point.x, point.y); }, + /** + * Clears the image, if it is backed by a canvas. + */ + clear: function() { + var size = this._size; + this.getContext(true).clearRect(0, 0, size.width + 1, size.height + 1); + }, + // DOCS: document Raster#createImageData /** * {@grouptitle Image Data} @@ -761,7 +822,8 @@ var Raster = Item.extend(/** @lends Raster# */{ _draw: function(ctx, param, viewMatrix) { var element = this.getElement(); - if (element) { + // Only draw if image is not empty (#1320). + if (element && element.width > 0 && element.height > 0) { // Handle opacity for Rasters separately from the rest, since // Rasters never draw a stroke. See Item#draw(). ctx.globalAlpha = this._opacity; diff --git a/src/item/Shape.js b/src/item/Shape.js index 184362a9..fed35b8e 100644 --- a/src/item/Shape.js +++ b/src/item/Shape.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/item/SymbolDefinition.js b/src/item/SymbolDefinition.js index 9e79b27d..3e907fb2 100644 --- a/src/item/SymbolDefinition.js +++ b/src/item/SymbolDefinition.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -140,7 +140,7 @@ var SymbolDefinition = Base.extend(/** @lends SymbolDefinition# */{ /** * Returns a copy of the symbol. * - * @return {Symbol} + * @return {SymbolDefinition} */ clone: function() { return new SymbolDefinition(this._item.clone(false)); @@ -149,7 +149,7 @@ var SymbolDefinition = Base.extend(/** @lends SymbolDefinition# */{ /** * Checks whether the symbol's definition is equal to the supplied symbol. * - * @param {Symbol} symbol + * @param {SymbolDefinition} symbol * @return {Boolean} {@true if they are equal} */ equals: function(symbol) { diff --git a/src/item/SymbolItem.js b/src/item/SymbolItem.js index 3e78646c..437789f2 100644 --- a/src/item/SymbolItem.js +++ b/src/item/SymbolItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -31,7 +31,9 @@ var SymbolItem = Item.extend(/** @lends SymbolItem# */{ /** * Creates a new symbol item. * - * @param {Symbol} definition the symbol definition to place + * @name SymbolItem#initialize + * @param {SymbolDefinition|Item} definition the definition to place or an + * item to place as a symbol * @param {Point} [point] the center point of the placed symbol * * @example {@paperscript split=true height=240} diff --git a/src/load.js b/src/load.js index 59e08c7c..d1f4dd7b 100644 --- a/src/load.js +++ b/src/load.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -38,11 +38,10 @@ if (typeof window === 'object') { } else { // Some native javascript classes have name collisions with Paper.js // classes. Store them to be able to use them later in tests. - NativeClasses = { - Event: Event, - MouseEvent: MouseEvent + this.nativeClasses = { + Event: window.Event, + MouseEvent: window.MouseEvent }; - include('options.js'); // Load constants.js, required by the on-the-fly preprocessing: include('constants.js'); diff --git a/src/net/Http.js b/src/net/Http.js index 012f6b92..0e9b867f 100644 --- a/src/net/Http.js +++ b/src/net/Http.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/node/canvas.js b/src/node/canvas.js index fcb96540..335f3873 100644 --- a/src/node/canvas.js +++ b/src/node/canvas.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -18,7 +18,7 @@ module.exports = function(self, requireName) { var Canvas; try { - Canvas = require('canvas'); + Canvas = require('canvas').Canvas; } catch(error) { // Remove `self.window`, so we still have the global `self` reference, // but no `window` object: diff --git a/src/node/extend.js b/src/node/extend.js index d2e1ef66..a950e4b3 100644 --- a/src/node/extend.js +++ b/src/node/extend.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/node/self.js b/src/node/self.js index b6e47d8f..2ec77404 100644 --- a/src/node/self.js +++ b/src/node/self.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -37,15 +37,13 @@ try { if (jsdom) { // Create our document and window objects through jsdom. /* global document:true, window:true */ - var document = jsdom.jsdom('', { + var document = new jsdom.JSDOM('', { // Use the current working directory as the document's origin, so // requests to local files work correctly with CORS. url: 'file://' + process.cwd() + '/', - features: { - FetchExternalResources: ['img', 'script'] - } + resources: 'usable' }); - self = document.defaultView; + self = document.window; require('./canvas.js')(self, requireName); require('./xml.js')(self); } else { diff --git a/src/node/xml.js b/src/node/xml.js index 2a02ae7e..74087246 100644 --- a/src/node/xml.js +++ b/src/node/xml.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/options.js b/src/options.js index 5ec47207..603cd7ca 100644 --- a/src/options.js +++ b/src/options.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -17,7 +17,7 @@ // The paper.js version. // NOTE: Adjust value here before calling `gulp publish`, which then updates and // publishes the various JSON package files automatically. -var version = '0.11.8'; +var version = '0.12.3'; // If this file is loaded in the browser, we're in load.js mode. var load = typeof window === 'object'; diff --git a/src/paper.js b/src/paper.js index f2c6d327..fc00e683 100644 --- a/src/paper.js +++ b/src/paper.js @@ -2,8 +2,8 @@ * Paper.js v*#=*__options.version - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -15,7 +15,7 @@ * * Straps.js - Class inheritance library with support for bean-style accessors * - * Copyright (c) 2006 - 2016 Juerg Lehni + * Copyright (c) 2006 - 2019 Juerg Lehni * http://scratchdisk.com/ * * Distributed under the MIT license. @@ -23,7 +23,7 @@ *** * * Acorn.js - * http://marijnhaverbeke.nl/acorn/ + * https://marijnhaverbeke.nl/acorn/ * * Acorn is a tiny, fast JavaScript parser written in JavaScript, * created by Marijn Haverbeke and released under an MIT license. @@ -102,6 +102,8 @@ var paper = function(self, undefined) { /*#*/ include('tool/ToolEvent.js'); /*#*/ include('tool/Tool.js'); +/*#*/ include('anim/Tween.js'); + /*#*/ include('net/Http.js'); /*#*/ include('canvas/CanvasProvider.js'); diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index 115af3a9..d47b90b4 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -161,7 +161,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{ * * @bean * @type Boolean - * @see Path#isClosed() + * @see Path#closed */ isClosed: function() { var children = this._children; @@ -193,7 +193,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{ /** * The last Segment contained within the compound-path, a short-cut to - * calling {@link Path#lastChild} on {@link Item#lastChild}. + * calling {@link Path#lastSegment} on {@link Item#lastChild}. * * @bean * @type Segment diff --git a/src/path/Curve.js b/src/path/Curve.js index 1c5b6714..26798499 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -1476,7 +1476,7 @@ new function() { // Scope for methods that require private functions // 2: normal, 1st derivative // 3: curvature, 1st derivative & 2nd derivative // Prevent tangents and normals of length 0: - // http://stackoverflow.com/questions/10506868/ + // https://stackoverflow.com/questions/10506868/ if (t < tMin) { x = cx; y = cy; @@ -1698,7 +1698,7 @@ new function() { // Scope for methods that require private functions * Peaks are locations sharing some qualities of curvature extrema but * are cheaper to compute. They fulfill their purpose here quite well. * See: - * http://math.stackexchange.com/questions/1954845/bezier-curvature-extrema + * https://math.stackexchange.com/questions/1954845/bezier-curvature-extrema * * @param {Number[]} v the curve values array * @return {Number[]} the roots of all found peaks diff --git a/src/path/CurveLocation.js b/src/path/CurveLocation.js index cd878d45..19b31dc9 100644 --- a/src/path/CurveLocation.js +++ b/src/path/CurveLocation.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -147,7 +147,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{ * The path that this locations is situated on. * * @bean - * @type Item + * @type Path */ getPath: function() { var curve = this.getCurve(); @@ -159,7 +159,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{ * it is part of a {@link Path} item. * * @bean - * @type Index + * @type Number */ getIndex: function() { var curve = this.getCurve(); @@ -284,7 +284,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{ * @bean * @type Number * @see Curve#getNearestLocation(point) - * @see Path#getNearestLocation(point) + * @see PathItem#getNearestLocation(point) */ getDistance: function() { return this._distance; diff --git a/src/path/Path.Constructors.js b/src/path/Path.Constructors.js index 3cc23b9d..ea92ee16 100644 --- a/src/path/Path.Constructors.js +++ b/src/path/Path.Constructors.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/path/Path.js b/src/path/Path.js index e188bee4..820f8d23 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -75,7 +75,6 @@ var Path = PathItem.extend(/** @lends Path# */{ * Creates a new path item from SVG path-data and places it at the top of * the active layer. * - * @param * @name Path#initialize * @param {String} pathData the SVG path-data that describes the geometry * of this path @@ -484,9 +483,11 @@ var Path = PathItem.extend(/** @lends Path# */{ * Adds one or more segments to the end of the {@link #segments} array of * this path. * - * @param {Segment|Point} segment the segment or point to be added. - * @return {Segment} the added segment. This is not necessarily the same - * object, e.g. if the segment to be added already belongs to another path + * @param {...(Segment|Point|Number[])} segment the segment or point to be + * added. + * @return {Segment|Segment[]} the added segment(s). This is not necessarily + * the same object, e.g. if the segment to be added already belongs to + * another path. * * @example {@paperscript} * // Adding segments to a path using point objects: @@ -1215,6 +1216,8 @@ var Path = PathItem.extend(/** @lends Path# */{ /** * Reduces the path by removing curves that have a length of 0, * and unnecessary segments between two collinear flat curves. + * + * @return {Path} the reduced path */ reduce: function(options) { var curves = this.getCurves(), @@ -2172,11 +2175,13 @@ new function() { // Scope for drawing // SegmentPoint objects maybe seem a bit tedious but is worth the benefit in // performance. - function drawHandles(ctx, segments, matrix, size, isFullySelected) { - if (size === 0) { - return; - } + function drawHandles(ctx, segments, matrix, size) { + // Only draw if size is not null or negative. + if (size <= 0) return; + var half = size / 2, + miniSize = size - 2, + miniHalf = half - 1, coords = new Array(6), pX, pY; @@ -2470,9 +2475,10 @@ new function() { // PostScript-style drawing commands // #2: arcTo(through, to) through = to; to = Point.read(arguments); - } else { + } else if (!from.equals(to)) { // #3: arcTo(to, radius, rotation, clockwise, large) - // Drawing arcs in SVG style: + // Draw arc in SVG style, but only if `from` and `to` are not + // equal (#1613). var radius = Size.read(arguments), isZero = Numerical.isZero; // If rx = 0 or ry = 0 then this arc is treated as a @@ -2481,7 +2487,7 @@ new function() { // PostScript-style drawing commands if (isZero(radius.width) || isZero(radius.height)) return this.lineTo(to); // See for an explanation of the following calculations: - // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + // https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes var rotation = Base.read(arguments), clockwise = !!Base.read(arguments), large = !!Base.read(arguments), @@ -2568,47 +2574,49 @@ new function() { // PostScript-style drawing commands extent += extent < 0 ? 360 : -360; } } - var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON, - ext = abs(extent), - // Calculate the amount of segments required to approximate over - // `extend` degrees (extend / 90), but prevent ceil() from - // rounding up small imprecisions by subtracting epsilon first. - count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90), - inc = extent / count, - half = inc * Math.PI / 360, - z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), - segments = []; - for (var i = 0; i <= count; i++) { - // Explicitly use to point for last segment, since depending - // on values the calculation adds imprecision: - var pt = to, - out = null; - if (i < count) { - out = vector.rotate(90).multiply(z); - if (matrix) { - pt = matrix._transformPoint(vector); - out = matrix._transformPoint(vector.add(out)) - .subtract(pt); + if (extent) { + var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON, + ext = abs(extent), + // Calculate amount of segments required to approximate over + // `extend` degrees (extend / 90), but prevent ceil() from + // rounding up small imprecisions by subtracting epsilon. + count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90), + inc = extent / count, + half = inc * Math.PI / 360, + z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), + segments = []; + for (var i = 0; i <= count; i++) { + // Explicitly use to point for last segment, since depending + // on values the calculation adds imprecision: + var pt = to, + out = null; + if (i < count) { + out = vector.rotate(90).multiply(z); + if (matrix) { + pt = matrix._transformPoint(vector); + out = matrix._transformPoint(vector.add(out)) + .subtract(pt); + } else { + pt = center.add(vector); + } + } + if (!i) { + // Modify startSegment + current.setHandleOut(out); } else { - pt = center.add(vector); + // Add new Segment + var _in = vector.rotate(-90).multiply(z); + if (matrix) { + _in = matrix._transformPoint(vector.add(_in)) + .subtract(pt); + } + segments.push(new Segment(pt, _in, out)); } + vector = vector.rotate(inc); } - if (!i) { - // Modify startSegment - current.setHandleOut(out); - } else { - // Add new Segment - var _in = vector.rotate(-90).multiply(z); - if (matrix) { - _in = matrix._transformPoint(vector.add(_in)) - .subtract(pt); - } - segments.push(new Segment(pt, _in, out)); - } - vector = vector.rotate(inc); + // Add all segments at once at the end for higher performance + this._add(segments); } - // Add all segments at once at the end for higher performance - this._add(segments); }, lineBy: function(/* to */) { @@ -2846,8 +2854,9 @@ statics: { normal1 = curve1.getNormalAtTime(1).multiply(radius) .transform(strokeMatrix), normal2 = curve2.getNormalAtTime(0).multiply(radius) - .transform(strokeMatrix); - if (normal1.getDirectedAngle(normal2) < 0) { + .transform(strokeMatrix), + angle = normal1.getDirectedAngle(normal2); + if (angle < 0 || angle >= 180) { normal1 = normal1.negate(); normal2 = normal2.negate(); } diff --git a/src/path/PathFitter.js b/src/path/PathFitter.js index b9d10300..27361e69 100644 --- a/src/path/PathFitter.js +++ b/src/path/PathFitter.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/path/PathFlattener.js b/src/path/PathFlattener.js index 1df208a4..2f7899d1 100644 --- a/src/path/PathFlattener.js +++ b/src/path/PathFlattener.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index f4f098e4..018555aa 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -25,7 +25,7 @@ * @author Harikrishnan Gopalakrishnan * @author Jan Boesenberg * @author Juerg Lehni - * http://hkrish.com/playground/paperjs/booleanStudy.html + * https://hkrish.com/playground/paperjs/booleanStudy.html */ PathItem.inject(new function() { var min = Math.min, @@ -1125,7 +1125,7 @@ PathItem.inject(new function() { /** * Splits the geometry of this path along the geometry of the specified * path returns the result as a new group item. This is equivalent to - * calling {@link #subtract(path)} and {@link #subtract(path)} and + * calling {@link #subtract(path)} and {@link #intersect(path)} and * putting the results into a new group. * * @option [options.insert=true] {Boolean} whether the resulting item @@ -1156,7 +1156,7 @@ PathItem.inject(new function() { * amount of resulting paths allows so, otherwise a new path / * compound-path is created, replacing the current one. * - * @return {PahtItem} the resulting path item + * @return {PathItem} the resulting path item */ resolveCrossings: function() { var children = this._children, @@ -1278,7 +1278,7 @@ PathItem.inject(new function() { * @param {Boolean} [clockwise] if provided, the orientation of the root * paths will be set to the orientation specified by `clockwise`, * otherwise the orientation of the largest root child is used. - * @return {PahtItem} a reference to the item itself, reoriented + * @return {PathItem} a reference to the item itself, reoriented */ reorient: function(nonZero, clockwise) { var children = this._children; diff --git a/src/path/PathItem.js b/src/path/PathItem.js index ed9037c1..e7ff2d17 100644 --- a/src/path/PathItem.js +++ b/src/path/PathItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -102,8 +102,8 @@ var PathItem = Item.extend(/** @lends PathItem# */{ * * @bean * @type Boolean - * @see Path#getArea() - * @see CompoundPath#getArea() + * @see Path#area + * @see CompoundPath#area */ isClockwise: function() { return this.getArea() >= 0; @@ -345,6 +345,8 @@ var PathItem = Item.extend(/** @lends PathItem# */{ * crossing each other, as opposed to simply touching. * * @param {PathItem} path the other item to find the crossings with + * @return {CurveLocation[]} the locations of all crossings between the + * paths * @see #getIntersections(path) */ getCrossings: function(path) { diff --git a/src/path/Segment.js b/src/path/Segment.js index 298065ec..4fa11d0f 100644 --- a/src/path/Segment.js +++ b/src/path/Segment.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -234,8 +234,8 @@ var Segment = Base.extend(/** @lends Segment# */{ * Checks if the segment has any curve handles set. * * @return {Boolean} {@true if the segment has handles set} - * @see Segment#getHandleIn() - * @see Segment#getHandleOut() + * @see Segment#handleIn + * @see Segment#handleOut * @see Curve#hasHandles() * @see Path#hasHandles() */ @@ -554,6 +554,9 @@ var Segment = Base.extend(/** @lends Segment# */{ return this._path ? !!this._path.removeSegment(this._index) : false; }, + /** + * @return {Segment} + */ clone: function() { return new Segment(this._point, this._handleIn, this._handleOut); }, diff --git a/src/path/SegmentPoint.js b/src/path/SegmentPoint.js index 2289bda0..a6bf3428 100644 --- a/src/path/SegmentPoint.js +++ b/src/path/SegmentPoint.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/path/SegmentSelection.js b/src/path/SegmentSelection.js index 559ef294..abe4af55 100644 --- a/src/path/SegmentSelection.js +++ b/src/path/SegmentSelection.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/style/Color.js b/src/style/Color.js index 05f4691f..6cf4d737 100644 --- a/src/style/Color.js +++ b/src/style/Color.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -80,7 +80,7 @@ var Color = Base.extend(new function() { } else if (match = string.match(/^(rgb|hsl)a?\((.*)\)$/)) { // RGB / RGBA or HSL / HSLA type = match[1]; - components = match[2].split(/[,\s]+/g); + components = match[2].trim().split(/[,\s]+/g); var isHSL = type === 'hsl'; for (var i = 0, l = Math.min(components.length, 4); i < l; i++) { var component = components[i]; @@ -691,6 +691,8 @@ var Color = Base.extend(new function() { * constructors also work for calls of `set()`. * * @function + * @param {...*} values + * @return {Color} */ set: '#initialize', @@ -709,8 +711,13 @@ var Color = Base.extend(new function() { */ _changed: function() { this._canvasStyle = null; - if (this._owner) - this._owner._changed(/*#=*/Change.STYLE); + if (this._owner) { + if (this._setter) { + this._owner[this._setter](this); + } else { + this._owner._changed(/*#=*/Change.STYLE); + } + } }, /** @@ -729,7 +736,7 @@ var Color = Base.extend(new function() { }, /** - * Converts the color another type. + * Converts the color to another type. * * @param {String} type the color type to convert to. Possible values: * {@values 'rgb', 'gray', 'hsb', 'hsl'} @@ -1183,9 +1190,35 @@ var Color = Base.extend(new function() { // Export for backward compatibility code below. _types: types, + /** + * Returns a color object with random {@link #red}, {@link #green} + * and {@link #blue} values between `0` and `1`. + * + * @return {Color} the newly created color object + * @static + * + * @example {@paperscript} + * var circle = new Path.Circle(view.center, 50); + * // Set a random color as circle fill color. + * circle.fillColor = Color.random(); + */ random: function() { var random = Math.random; return new Color(random(), random(), random()); + }, + + _setOwner: function(color, owner, setter) { + if (color) { + // Clone color if owner changes: + if (color._owner && owner && color._owner !== owner) { + color = color.clone(); + } + if (!color._owner ^ !owner) { + color._owner = owner || null; + color._setter = setter || null; + } + } + return color; } } }); diff --git a/src/style/Gradient.js b/src/style/Gradient.js index 4fd6b6ea..512a835b 100644 --- a/src/style/Gradient.js +++ b/src/style/Gradient.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/style/GradientStop.js b/src/style/GradientStop.js index 96e78464..b1d2d427 100644 --- a/src/style/GradientStop.js +++ b/src/style/GradientStop.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -175,12 +175,10 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{ }, setColor: function(/* color */) { - // Make sure newly set colors are cloned, since they can only have - // one owner. - var color = Color.read(arguments, 0, { clone: true }); - if (color) - color._owner = this; - this._color = color; + // Clear old color owner before setting new one: + Color._setOwner(this._color, null); + this._color = Color._setOwner(Color.read(arguments, 0), this, + 'setColor'); this._changed(); }, diff --git a/src/style/Style.js b/src/style/Style.js index f8e10280..b30e090a 100644 --- a/src/style/Style.js +++ b/src/style/Style.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -162,29 +162,35 @@ var Style = Base.extend(new function() { // raw value is stored, and conversion only happens in the getter. fields[set] = function(value) { var owner = this._owner, - children = owner && owner._children; + children = owner && owner._children, + applyToChildren = children && children.length > 0 + && !(owner instanceof CompoundPath); // Only unify styles on children of Groups, excluding CompoundPaths. - if (children && children.length > 0 - && !(owner instanceof CompoundPath)) { + if (applyToChildren) { for (var i = 0, l = children.length; i < l; i++) children[i]._style[set](value); - } else if (key in this._defaults) { + } + // Always store selectedColor in item _values to make sure that + // group selected bounds and position color is coherent whether it + // has children or not when the value is set. + if ((key === 'selectedColor' || !applyToChildren) + && key in this._defaults) { var old = this._values[key]; if (old !== value) { if (isColor) { // The old value may be a native string or other color // description that wasn't coerced to a color object yet - if (old && old._owner !== undefined) { - old._owner = undefined; + if (old) { + Color._setOwner(old, null); old._canvasStyle = null; } if (value && value.constructor === Color) { - // Clone color if it already has an owner. // NOTE: If value is not a Color, it is only // converted and cloned in the getter further down. - if (value._owner) - value = value.clone(); - value._owner = owner; + value = Color._setOwner(value, owner, + // Only provide a color-setter if the style + // is to be applied to the children: + applyToChildren && set); } } // NOTE: We do not convert the values to Colors in the @@ -201,29 +207,13 @@ var Style = Base.extend(new function() { fields[get] = function(_dontMerge) { var owner = this._owner, children = owner && owner._children, + applyToChildren = children && children.length > 0 + && !(owner instanceof CompoundPath), value; // If the owner has children, walk through all of them and see if // they all have the same style. - // If true is passed for _dontMerge, don't merge children styles - if (key in this._defaults && (!children || !children.length - || _dontMerge || owner instanceof CompoundPath)) { - var value = this._values[key]; - if (value === undefined) { - value = this._defaults[key]; - if (value && value.clone) - value = value.clone(); - } else { - var ctor = isColor ? Color : isPoint ? Point : null; - if (ctor && !(value && value.constructor === ctor)) { - // Convert to a Color / Point, and stored result of the - // conversion. - this._values[key] = value = ctor.read([value], 0, - { readNull: true, clone: true }); - if (value && isColor) - value._owner = owner; - } - } - } else if (children) { + // If true is passed for _dontMerge, don't merge children styles. + if (applyToChildren && !_dontMerge) { for (var i = 0, l = children.length; i < l; i++) { var childValue = children[i]._style[get](); if (!i) { @@ -234,6 +224,30 @@ var Style = Base.extend(new function() { return undefined; } } + } else if (key in this._defaults) { + var value = this._values[key]; + if (value === undefined) { + value = this._defaults[key]; + // Clone defaults if available: + if (value && value.clone) { + value = value.clone(); + } + } else { + var ctor = isColor ? Color : isPoint ? Point : null; + if (ctor && !(value && value.constructor === ctor)) { + // Convert to a Color / Point, and stored result of the + // conversion. + this._values[key] = value = ctor.read([value], 0, + { readNull: true, clone: true }); + } + } + } + if (value && isColor) { + // Color._setOwner() may clone the color if it already has a + // different owner (e.g. resulting from `childValue` above). + // Only provide a color-setter if the style is to be applied to + // the children: + value = Color._setOwner(value, owner, applyToChildren && set); } return value; }; @@ -530,7 +544,7 @@ var Style = Base.extend(new function() { * * @name Style#dashArray * @property - * @type Array + * @type Number[] * @default [] */ diff --git a/src/svg/SvgElement.js b/src/svg/SvgElement.js index df34143c..f345dc50 100644 --- a/src/svg/SvgElement.js +++ b/src/svg/SvgElement.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/svg/SvgExport.js b/src/svg/SvgExport.js index 672f2f8f..f6b16d12 100644 --- a/src/svg/SvgExport.js +++ b/src/svg/SvgExport.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -29,11 +29,16 @@ new function() { // in rotate(). To do so, SVG requries us to inverse transform the // translation point by the matrix itself, since they are provided // in local coordinates. - matrix = matrix._shiftless(); - var point = matrix._inverseTransform(trans); + var point; + if (matrix.isInvertible()) { + matrix = matrix._shiftless(); + point = matrix._inverseTransform(trans); + trans = null; + } else { + point = new Point(); + } attrs[center ? 'cx' : 'x'] = point.x; attrs[center ? 'cy' : 'y'] = point.y; - trans = null; } if (!matrix.isIdentity()) { // See if we can decompose the matrix and can formulate it as a @@ -177,7 +182,7 @@ new function() { definition = item._definition, node = getDefinition(definition, 'symbol'), definitionItem = definition._item, - bounds = definitionItem.getBounds(); + bounds = definitionItem.getStrokeBounds(); if (!node) { node = SvgElement.create('symbol', { viewBox: formatter.rectangle(bounds) @@ -450,7 +455,7 @@ new function() { if (rect) { attrs.width = rect.width; attrs.height = rect.height; - if (rect.x || rect.y) + if (rect.x || rect.x === 0 || rect.y || rect.y === 0) attrs.viewBox = formatter.rectangle(rect); } var node = SvgElement.create('svg', attrs, formatter), diff --git a/src/svg/SvgImport.js b/src/svg/SvgImport.js index 9b97668b..9fcf6101 100644 --- a/src/svg/SvgImport.js +++ b/src/svg/SvgImport.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -22,11 +22,12 @@ new function() { var definitions = {}, rootSize; - function getValue(node, name, isString, allowNull, allowPercent) { + function getValue(node, name, isString, allowNull, allowPercent, + defaultValue) { // Interpret value as number. Never return NaN, but 0 instead. // If the value is a sequence of numbers, parseFloat will // return the first occurring number, which is enough for now. - var value = SvgElement.get(node, name), + var value = SvgElement.get(node, name) || defaultValue, res = value == null ? allowNull ? null @@ -43,9 +44,9 @@ new function() { : res; } - function getPoint(node, x, y, allowNull, allowPercent) { - x = getValue(node, x || 'x', false, allowNull, allowPercent); - y = getValue(node, y || 'y', false, allowNull, allowPercent); + function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) { + x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX); + y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY); return allowNull && (x == null || y == null) ? null : new Point(x, y); } @@ -168,13 +169,16 @@ new function() { 'userSpaceOnUse'; // Allow percentages in all values if scaleToBounds is true: if (radial) { - origin = getPoint(node, 'cx', 'cy', false, scaleToBounds); + origin = getPoint(node, 'cx', 'cy', false, scaleToBounds, + '50%', '50%'); destination = origin.add( - getValue(node, 'r', false, false, scaleToBounds), 0); + getValue(node, 'r', false, false, scaleToBounds, '50%'), 0); highlight = getPoint(node, 'fx', 'fy', true, scaleToBounds); } else { - origin = getPoint(node, 'x1', 'y1', false, scaleToBounds); - destination = getPoint(node, 'x2', 'y2', false, scaleToBounds); + origin = getPoint(node, 'x1', 'y1', false, scaleToBounds, + '0%', '0%'); + destination = getPoint(node, 'x2', 'y2', false, scaleToBounds, + '100%', '0%'); } var color = applyAttributes( new Color(gradient, origin, destination, highlight), node); @@ -196,23 +200,23 @@ new function() { return importNode(child, options, isRoot); } }, - // http://www.w3.org/TR/SVG/struct.html#Groups + // https://www.w3.org/TR/SVG/struct.html#Groups g: importGroup, - // http://www.w3.org/TR/SVG/struct.html#NewDocument + // https://www.w3.org/TR/SVG/struct.html#NewDocument svg: importGroup, clippath: importGroup, - // http://www.w3.org/TR/SVG/shapes.html#PolygonElement + // https://www.w3.org/TR/SVG/shapes.html#PolygonElement polygon: importPoly, - // http://www.w3.org/TR/SVG/shapes.html#PolylineElement + // https://www.w3.org/TR/SVG/shapes.html#PolylineElement polyline: importPoly, - // http://www.w3.org/TR/SVG/paths.html + // https://www.w3.org/TR/SVG/paths.html path: importPath, - // http://www.w3.org/TR/SVG/pservers.html#LinearGradients + // https://www.w3.org/TR/SVG/pservers.html#LinearGradients lineargradient: importGradient, - // http://www.w3.org/TR/SVG/pservers.html#RadialGradients + // https://www.w3.org/TR/SVG/pservers.html#RadialGradients radialgradient: importGradient, - // http://www.w3.org/TR/SVG/struct.html#ImageElement + // https://www.w3.org/TR/SVG/struct.html#ImageElement image: function (node) { var raster = new Raster(getValue(node, 'href', true)); raster.on('load', function() { @@ -228,17 +232,17 @@ new function() { return raster; }, - // http://www.w3.org/TR/SVG/struct.html#SymbolElement + // https://www.w3.org/TR/SVG/struct.html#SymbolElement symbol: function(node, type, options, isRoot) { return new SymbolDefinition( // Pass true for dontCenter: importGroup(node, type, options, isRoot), true); }, - // http://www.w3.org/TR/SVG/struct.html#DefsElement + // https://www.w3.org/TR/SVG/struct.html#DefsElement defs: importGroup, - // http://www.w3.org/TR/SVG/struct.html#UseElement + // https://www.w3.org/TR/SVG/struct.html#UseElement use: function(node) { // Note the namespaced xlink:href attribute is just called href // as a property on node. @@ -258,14 +262,14 @@ new function() { : null; }, - // http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement + // https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement circle: function(node) { return new Shape.Circle( getPoint(node, 'cx', 'cy'), getValue(node, 'r')); }, - // http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement + // https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement ellipse: function(node) { // We only use object literal notation where the default one is not // supported (e.g. center / radius fo Shape.Ellipse). @@ -275,7 +279,7 @@ new function() { }); }, - // http://www.w3.org/TR/SVG/shapes.html#RectElement + // https://www.w3.org/TR/SVG/shapes.html#RectElement rect: function(node) { return new Shape.Rectangle(new Rectangle( getPoint(node), @@ -283,7 +287,7 @@ new function() { ), getSize(node, 'rx', 'ry')); }, - // http://www.w3.org/TR/SVG/shapes.html#LineElement + // https://www.w3.org/TR/SVG/shapes.html#LineElement line: function(node) { return new Path.Line( getPoint(node, 'x1', 'y1'), @@ -345,7 +349,11 @@ new function() { text.setContent(lines.join('\n')); return text; } - } + }, + + // https://www.w3.org/TR/SVG/struct.html#SwitchElement + // Conditional attributes are ignored and all children are rendered. + switch: importGroup }; // Attributes and Styles @@ -356,7 +364,7 @@ new function() { function applyTransform(item, value, name, node) { if (item.transform) { - // http://www.w3.org/TR/SVG/types.html#DataTypeTransformList + // https://www.w3.org/TR/SVG/types.html#DataTypeTransformList // Parse SVG transform string. First we split at /)\s*/, to separate // commands var transforms = (node.getAttribute(name) || '').split(/\)\s*/g), @@ -399,8 +407,8 @@ new function() { } function applyOpacity(item, value, name) { - // http://www.w3.org/TR/SVG/painting.html#FillOpacityProperty - // http://www.w3.org/TR/SVG/painting.html#StrokeOpacityProperty + // https://www.w3.org/TR/SVG/painting.html#FillOpacityProperty + // https://www.w3.org/TR/SVG/painting.html#StrokeOpacityProperty var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor', color = item[key] && item[key](); if (color) @@ -442,7 +450,7 @@ new function() { }, 'clip-path': function(item, value) { - // http://www.w3.org/TR/SVG/masking.html#ClipPathProperty + // https://www.w3.org/TR/SVG/masking.html#ClipPathProperty var clip = getDefinition(value); if (clip) { clip = clip.clone(); @@ -474,20 +482,20 @@ new function() { }, 'stop-color': function(item, value) { - // http://www.w3.org/TR/SVG/pservers.html#StopColorProperty + // https://www.w3.org/TR/SVG/pservers.html#StopColorProperty if (item.setColor) item.setColor(value); }, 'stop-opacity': function(item, value) { - // http://www.w3.org/TR/SVG/pservers.html#StopOpacityProperty + // https://www.w3.org/TR/SVG/pservers.html#StopOpacityProperty // NOTE: It is important that this is applied after stop-color! if (item._color) item._color.setAlpha(parseFloat(value)); }, offset: function(item, value) { - // http://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute + // https://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute if (item.setOffset) { var percent = value.match(/(.*)%$/); item.setOffset(percent ? percent[1] / 100 : parseFloat(value)); @@ -495,7 +503,7 @@ new function() { }, viewBox: function(item, value, name, node, styles) { - // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute + // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute // TODO: implement preserveAspectRatio attribute // viewBox will be applied both to the group that's created for the // content in SymbolDefinition#item, and the SymbolItem itself. diff --git a/src/svg/SvgStyles.js b/src/svg/SvgStyles.js index af1827e2..9d8bab08 100644 --- a/src/svg/SvgStyles.js +++ b/src/svg/SvgStyles.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/text/PointText.js b/src/text/PointText.js index 762a8288..ccc1fd8e 100644 --- a/src/text/PointText.js +++ b/src/text/PointText.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/text/TextItem.js b/src/text/TextItem.js index b6d56bfe..11cc315d 100644 --- a/src/text/TextItem.js +++ b/src/text/TextItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/tool/Tool.js b/src/tool/Tool.js index e3c409e1..69699f09 100644 --- a/src/tool/Tool.js +++ b/src/tool/Tool.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/tool/ToolEvent.js b/src/tool/ToolEvent.js index 128de506..b9747459 100644 --- a/src/tool/ToolEvent.js +++ b/src/tool/ToolEvent.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/util/Formatter.js b/src/util/Formatter.js index 2b73c5ba..58fded28 100644 --- a/src/util/Formatter.js +++ b/src/util/Formatter.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/util/Numerical.js b/src/util/Numerical.js index b2b3adfd..54d4c5db 100644 --- a/src/util/Numerical.js +++ b/src/util/Numerical.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/util/UID.js b/src/util/UID.js index 9aac04c0..0c315f26 100644 --- a/src/util/UID.js +++ b/src/util/UID.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/src/view/CanvasView.js b/src/view/CanvasView.js index 3afdfa68..85eecfb3 100644 --- a/src/view/CanvasView.js +++ b/src/view/CanvasView.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -49,7 +49,7 @@ var CanvasView = View.extend(/** @lends CanvasView# */{ this._pixelRatio = 1; if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) { // Hi-DPI Canvas support based on: - // http://www.html5rocks.com/en/tutorials/canvas/hidpi/ + // https://www.html5rocks.com/en/tutorials/canvas/hidpi/ var deviceRatio = window.devicePixelRatio || 1, backingStoreRatio = DomElement.getPrefixed(ctx, 'backingStorePixelRatio') || 1; @@ -88,6 +88,10 @@ var CanvasView = View.extend(/** @lends CanvasView# */{ } }, + getContext: function() { + return this._context; + }, + /** * Converts the provide size in any of the units allowed in the browser to * pixels. @@ -124,7 +128,7 @@ var CanvasView = View.extend(/** @lends CanvasView# */{ /** * Updates the view if there are changes. Note that when using built-in - * event hanlders for interaction, animation and load events, this method is + * event handlers for interaction, animation and load events, this method is * invoked for you automatically at the end. * * @return {Boolean} {@true if the view was updated} diff --git a/src/view/View.js b/src/view/View.js index 281670f1..13291df6 100644 --- a/src/view/View.js +++ b/src/view/View.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -522,7 +522,7 @@ var View = Base.extend(Emitter, /** @lends View# */{ * * @bean * @type Number - * @see #getScaling() + * @see #scaling */ getZoom: function() { var scaling = this._decompose().scaling; @@ -559,7 +559,7 @@ var View = Base.extend(Emitter, /** @lends View# */{ * * @bean * @type Point - * @see #getZoom() + * @see #zoom */ getScaling: function() { var scaling = this._decompose().scaling; @@ -1496,7 +1496,7 @@ new function() { // Injection scope for event handling on the browser updateFocus: updateFocus, /** - * Clear all events handling state informations. Made for testing + * Clear all events handling state information. Made for testing * purpose, to have a way to start with a fresh state before each * test. * @private diff --git a/test/assets/gradients-3.svg b/test/assets/gradients-3.svg new file mode 100644 index 00000000..854ccf5a --- /dev/null +++ b/test/assets/gradients-3.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/test/assets/gradients-4.svg b/test/assets/gradients-4.svg new file mode 100644 index 00000000..98fc5380 --- /dev/null +++ b/test/assets/gradients-4.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/helpers.js b/test/helpers.js index 4ccc68ba..28e8be91 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -2,19 +2,21 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * * All rights reserved. */ -var isNode = typeof global === 'object', - isPhantom = typeof window === 'object' && !!window.callPhantom, +// We call our variable `isNodeContext` because resemble.js exposes a global +// `isNode` function which would override it and break node check. +var isNodeContext = typeof global === 'object', + isPhantomContext = typeof window === 'object' && !!window.callPhantom, scope; -if (isNode) { +if (isNodeContext) { scope = global; // Resemble.js needs the Image constructor global. global.Image = paper.window.Image; @@ -35,14 +37,11 @@ if (isNode) { } // Some native javascript classes have name collisions with Paper.js classes. -// If they have not already been stored in src/load.js, we dot it now. -if (!isNode && typeof NativeClasses === 'undefined') -{ - NativeClasses = { - Event: Event, - MouseEvent: MouseEvent - }; -} +// If they have not already been stored in `src/load.js`, do it now: +var nativeClasses = this.nativeClasses || { + Event: this.Event || {}, + MouseEvent: this.MouseEvent || {} +}; // The unit-tests expect the paper classes to be global. paper.install(scope); @@ -107,7 +106,7 @@ var equals = function(actual, expected, message, options) { || type === 'boolean' && 'Boolean' || type === 'undefined' && 'Undefined' || Array.isArray(expected) && 'Array' - || expected instanceof window.Element && 'Element' // handle DOM Elements + || expected instanceof window.Element && 'Element' // DOM Elements || (cls = expected && expected._class) // check _class 2nd last || type === 'object' && 'Object'; // Object as catch-all var comparator = type && comparators[type]; @@ -161,6 +160,81 @@ var compareProperties = function(actual, expected, properties, message, options) } }; +/** + * Compare 2 image data with resemble.js library. + * When comparison fails, expected, actual and compared images are displayed. + * @param {ImageData} imageData1 the expected image data + * @param {ImageData} imageData2 the actual image data + * @param {number} tolerance + * @param {string} diffDetail text displayed when comparison fails + */ +var compareImageData = function(imageData1, imageData2, tolerance, diffDetail) { + /** + * Build an image element from a given image data. + * @param {ImageData} imageData + * @return {HTMLImageElement} + */ + function image(imageData) { + var canvas = document.createElement('canvas'); + canvas.width = imageData.width; + canvas.height = imageData.height; + canvas.getContext('2d').putImageData(imageData, 0, 0); + var image = new Image(); + image.src = canvas.toDataURL(); + canvas.remove(); + return image; + } + + tolerance = (tolerance || 1e-4) * 100; + + var id = QUnit.config.current.testId, + index = QUnit.config.current.assertions.length + 1, + result; + // Compare image-data using resemble.js: + resemble.compare( + imageData1, + imageData2, + { + output: { + errorColor: { red: 255, green: 51, blue: 0 }, + errorType: 'flat', + transparency: 1 + }, + ignore: ['antialiasing'] + }, + // When working with imageData, this call is synchronous: + function (error, data) { + if (error) { + console.error(error); + } else { + result = data; + } + } + ) + // Compare with tolerance in percentage... + var fixed = tolerance < 1 ? ((1 / tolerance) + '').length - 1 : 0, + identical = result ? 100 - result.misMatchPercentage : 0, + ok = Math.abs(100 - identical) <= tolerance, + text = identical.toFixed(fixed) + '% identical', + detail = text; + if (!ok && diffDetail) { + detail += diffDetail; + } + QUnit.push(ok, text, (100).toFixed(fixed) + '% identical'); + if (!ok && result && !isNodeContext) { + // Get the right entry for this unit test and assertion, and + // replace the results with images + var entry = document.getElementById('qunit-test-output-' + id) + .querySelector('li:nth-child(' + (index) + ')'), + bounds = result.diffBounds; + entry.querySelector('.test-expected td').appendChild(image(imageData1)); + entry.querySelector('.test-actual td').appendChild(image(imageData2)); + entry.querySelector('.test-diff td').innerHTML = '
' + detail
+            + '

' + + ''; + } +}; + var comparePixels = function(actual, expected, message, options) { function rasterize(item, group, resolution) { var raster = null; @@ -178,11 +252,6 @@ var comparePixels = function(actual, expected, message, options) { return raster; } - function getImageTag(raster) { - return ''; - } - if (!expected) { return QUnit.strictEqual(actual, expected, message, options); } else if (!actual) { @@ -197,12 +266,12 @@ var comparePixels = function(actual, expected, message, options) { // bounds of both items before rasterizing. var resolution = options.resolution || 72, actualBounds = actual.strokeBounds, - expecedBounds = expected.strokeBounds, + expectedBounds = expected.strokeBounds, bounds = actualBounds.isEmpty() - ? expecedBounds - : expecedBounds.isEmpty() + ? expectedBounds + : expectedBounds.isEmpty() ? actualBounds - : actualBounds.unite(expecedBounds); + : actualBounds.unite(expectedBounds); if (bounds.isEmpty()) { QUnit.equal('empty', 'empty', message); return; @@ -220,53 +289,20 @@ var comparePixels = function(actual, expected, message, options) { expectedRaster = rasterize(expected, group, resolution); if (!actualRaster || !expectedRaster) { QUnit.push(false, null, null, 'Unable to compare rasterized items: ' + - (!actualRaster ? 'actual' : 'expected') + ' item is null', - QUnit.stack(2)); + (!actualRaster ? 'actual' : 'expected') + ' item is null', + QUnit.stack(2)); } else { - // Use resemble.js to compare the two rasterized items. - var id = QUnit.config.current.testId, - index = QUnit.config.current.assertions.length + 1, - result; - if (!resemble._setup) { - resemble._setup = true; - resemble.outputSettings({ - errorColor: { red: 255, green: 51, blue: 0 }, - errorType: 'flat', - transparency: 1 - }); - } - resemble(actualRaster.getImageData()) - .compareTo(expectedRaster.getImageData()) - .ignoreAntialiasing() - // When working with imageData, this call is synchronous: - .onComplete(function(data) { result = data; }); - // Compare with tolerance in percentage... - var tolerance = (options.tolerance || 1e-4) * 100, - fixed = tolerance < 1 ? ((1 / tolerance) + '').length - 1 : 0, - identical = result ? 100 - result.misMatchPercentage : 0, - ok = Math.abs(100 - identical) <= tolerance, - text = identical.toFixed(fixed) + '% identical', - detail = text; - if (!ok && - actual instanceof PathItem && expected instanceof PathItem) { - detail += '\nExpected:\n' + expected.pathData + - '\nActual:\n' + actual.pathData; - } - QUnit.push(ok, text, (100).toFixed(fixed) + '% identical', message); - if (!ok && result && !isNode) { - // Get the right entry for this unit test and assertion, and - // replace the results with images - var entry = document.getElementById('qunit-test-output-' + id) - .querySelector('li:nth-child(' + (index) + ')'), - bounds = result.diffBounds; - entry.querySelector('.test-expected td').innerHTML = - getImageTag(expectedRaster); - entry.querySelector('.test-actual td').innerHTML = - getImageTag(actualRaster); - entry.querySelector('.test-diff td').innerHTML = '
' + detail
-                    + '

' - + ''; - } + // Compare the two rasterized items. + var detail = actual instanceof PathItem && expected instanceof PathItem + ? '\nExpected:\n' + expected.pathData + + '\nActual:\n' + actual.pathData + : ''; + compareImageData( + actualRaster.getImageData(), + expectedRaster.getImageData(), + options.tolerance, + detail + ); } }; @@ -304,6 +340,41 @@ var compareItem = function(actual, expected, message, options, properties) { } }; +/** + * Run each callback in a separated canvas context and compare both outputs. + * This can be used to do selection drawing tests as it is not possible with + * comparePixels() method which relies on the item.rasterize() method which + * ignores selection. + * @param {number} width the width of the canvas + * @param {number} height the height of the canvas + * @param {function} expectedCallback the function producing the expected result + * @param {function} actualCallback the function producing the actual result + * @param {number} tolerance between 0 and 1 + */ +var compareCanvas = function(width, height, expected, actual, tolerance) { + function getImageData(width, height, callback) { + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var project = new Project(canvas); + var view = project.view; + callback(); + view.update(); + var imageData = view.context.getImageData(0, 0, width, height); + project.remove(); + canvas.remove(); + return imageData; + } + + compareImageData( + getImageData(width, height, expected), + getImageData(width, height, actual), + tolerance + ); + + currentProject.activate(); +}; + // A list of comparator functions, based on `expected` type. See equals() for // an explanation of how the type is determined. var comparators = { @@ -385,7 +456,7 @@ var comparators = { equals(actual.components, expected.components, message + ' (#components)', options); } else { - QUnit.strictEqual(actual, expected, message); + QUnit.push(expected.equals(actual), actual, expected, message); } }, @@ -597,8 +668,8 @@ var MouseEventPolyfill = function(type, params) { ); return mouseEvent; }; -MouseEventPolyfill.prototype = typeof NativeClasses !== 'undefined' - && NativeClasses.Event.prototype || Event.prototype; + +MouseEventPolyfill.prototype = nativeClasses.Event.prototype; var triggerMouseEvent = function(type, point, target) { // Depending on event type, events have to be triggered on different @@ -606,21 +677,16 @@ var triggerMouseEvent = function(type, point, target) { // and `docEvents` in View.js). And we cannot rely on the fact that event // will bubble from canvas to document, since the canvas used in tests is // not inserted in DOM. - target = target || (type === 'mousedown' ? view._element : document); - + target = target || (type === 'mousedown' ? view.element : document); // If `gulp load` was run, there is a name collision between paper Event / // MouseEvent and native javascript classes. In this case, we need to use - // native classes stored in global NativeClasses object instead. - var constructor = typeof NativeClasses !== 'undefined' - && NativeClasses.MouseEvent || MouseEvent; - + // native classes stored in the nativeClasses object instead. // MouseEvent class does not exist in PhantomJS, so in that case, we need to - // use a polyfill method. - if (typeof constructor !== 'function') { - constructor = MouseEventPolyfill; - } - - var event = new constructor(type, { + // use a polyfill method, see: https://stackoverflow.com/questions/42929639 + var MouseEvent = typeof nativeClasses.MouseEvent === 'function' + ? nativeClasses.MouseEvent + : MouseEventPolyfill; + var event = new MouseEvent(type, { bubbles: true, cancelable: true, composed: true, diff --git a/test/load.js b/test/load.js index ed1cf72e..0769f330 100644 --- a/test/load.js +++ b/test/load.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Color.js b/test/tests/Color.js index 32f0cf9d..363cdcc8 100644 --- a/test/tests/Color.js +++ b/test/tests/Color.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -81,6 +81,9 @@ test('Creating Colors', function() { equals(new Color('rgba(255, 0, 0, 0.5)'), new Color(1, 0, 0, 0.5), 'Color from rgba() string'); + equals(new Color('rgba( 255, 0, 0, 0.5 )'), new Color(1, 0, 0, 0.5), + 'Color from rgba() string 2nd test'); + equals(new Color('hsl(180deg, 20%, 40%)'), new Color({ hue: 180, saturation: 0.2, lightness: 0.4 }), 'Color from hsl() string'); @@ -299,3 +302,11 @@ test('Gradients with applyMatrix', function() { comparePixels(path, shape); }); + +test('Modifying group.strokeColor for multiple children', function() { + var item = new Group(new Path(), new Path()); + item.strokeColor = 'red'; + var strokeColor = item.strokeColor; + item.strokeColor.hue = 50; + equals(function() { return item.strokeColor !== undefined; }, true); +}); diff --git a/test/tests/CompoundPath.js b/test/tests/CompoundPath.js index adc0224d..2bad91e4 100644 --- a/test/tests/CompoundPath.js +++ b/test/tests/CompoundPath.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Curve.js b/test/tests/Curve.js index 6a4b6c4a..82ea945f 100644 --- a/test/tests/Curve.js +++ b/test/tests/Curve.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/CurveLocation.js b/test/tests/CurveLocation.js index fa3b06c2..816a7337 100644 --- a/test/tests/CurveLocation.js +++ b/test/tests/CurveLocation.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Emitter.js b/test/tests/Emitter.js index 9e55136b..2bbfdc98 100644 --- a/test/tests/Emitter.js +++ b/test/tests/Emitter.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Group.js b/test/tests/Group.js index 3f542204..e1e47153 100644 --- a/test/tests/Group.js +++ b/test/tests/Group.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -134,4 +134,58 @@ test('group.addChildren()', function() { group.addChildren(children); equals(group.children.length, 2, 'adding the same item twice should only add it once.'); -}) +}); + +test('group.setSelectedColor() with selected bound and position', function() { + // Working: Set selected color first then add child. + var group1 = new Group(); + group1.bounds.selected = true; + group1.position.selected = true; + group1.selectedColor = 'black'; + group1.addChild(new Path.Circle([50, 50], 40)); + // Failing: Add child first then set selected color. + var group2 = new Group(); + group2.bounds.selected = true; + group2.position.selected = true; + group2.addChild(new Path.Circle([50, 50], 40)); + group2.selectedColor = 'black'; + comparePixels(group1, group2); +}); + +test('Group#isEmpty(recursively)', function() { + var group = new Group(); + equals(true, group.isEmpty()); + equals(true, group.isEmpty(true)); + var group = new Group(new Group()); + equals(false, group.isEmpty()); + equals(true, group.isEmpty(true)); + var group = new Group(new Path()); + equals(false, group.isEmpty()); + equals(true, group.isEmpty(true)); + var group = new Group(new PointText()); + equals(false, group.isEmpty()); + equals(true, group.isEmpty(true)); +}); + +test( + 'group.internalBounds with clip item without clip.applyMatrix = false', + function() { + var point = new Point(100, 100); + var translation = new Point(100, 100); + var item = new Path.Circle({ + center: point, + radius: 50, + fillColor: 'orange' + }); + var clip = new Path.Rectangle({ + from: point.subtract(translation), + to: point.add(translation) + }); + clip.applyMatrix = false; + clip.translate(translation); + var group = new Group(clip, item); + group.clipped = true; + var expected = new Rectangle(point, point.add(translation.multiply(2))); + equals(group.internalBounds, expected); + } +); diff --git a/test/tests/HitResult.js b/test/tests/HitResult.js index 5ca489f7..e9926815 100644 --- a/test/tests/HitResult.js +++ b/test/tests/HitResult.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Interactions.js b/test/tests/Interactions.js index f606fb78..299d564b 100644 --- a/test/tests/Interactions.js +++ b/test/tests/Interactions.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Item.js b/test/tests/Item.js index fa226b93..0f751996 100644 --- a/test/tests/Item.js +++ b/test/tests/Item.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -945,3 +945,33 @@ test('Children global matrices are cleared after parent transformation', functio group.translate(100, 0); equals(item.localToGlobal(item.getPointAt(0)), new Point(100, 100)); }); + +test('Item#rasterize() with empty bounds', function() { + new Path.Line([0, 0], [100, 0]).rasterize(); + view.update(); + expect(0); +}); + +test('Item#draw() with CompoundPath as clip item', function() { + function createdClippedGroup(invertedOrder) { + var compound = new CompoundPath({ + children: [ + new Path.Circle(new Point(50, 50), 50), + new Path.Circle(new Point(100, 50), 50) + ], + fillRule: 'evenodd' + }); + + var rectangle = new Shape.Rectangle(new Point(0, 0), new Point(150, 50)); + + var group = new Group(); + group.children = invertedOrder + ? [compound, rectangle] + : [rectangle, compound]; + group.fillColor = 'black'; + group.clipped = true; + return group; + }; + + comparePixels(createdClippedGroup(true), createdClippedGroup(false)); +}); diff --git a/test/tests/Item_Bounds.js b/test/tests/Item_Bounds.js index f0b8ae03..3e9417d9 100644 --- a/test/tests/Item_Bounds.js +++ b/test/tests/Item_Bounds.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -722,7 +722,7 @@ test('path.strokeBounds with applyMatrix disabled', function() { testHitResult(); }); -test('TEST', function() { +test('path.strokeBounds with applyMatrix enabled', function() { var path = new Path.Rectangle({ applyMatrix: false, point: [10, 10], diff --git a/test/tests/Item_Cloning.js b/test/tests/Item_Cloning.js index 762701d0..723a2a20 100644 --- a/test/tests/Item_Cloning.js +++ b/test/tests/Item_Cloning.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Item_Getting.js b/test/tests/Item_Getting.js index 120d0500..d561572f 100644 --- a/test/tests/Item_Getting.js +++ b/test/tests/Item_Getting.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Item_Order.js b/test/tests/Item_Order.js index b99814ef..2d0adb2b 100644 --- a/test/tests/Item_Order.js +++ b/test/tests/Item_Order.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/JSON.js b/test/tests/JSON.js index 1c2fe5af..656d63d2 100644 --- a/test/tests/JSON.js +++ b/test/tests/JSON.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -256,3 +256,10 @@ test('Path#importJSON()', function() { equals(function() { return layer.firstChild === path; }, true); equals(function() { return path.parent === layer; }, true); }); + +test('Item#importJSON() does not override Item#insert()', function() { + var path = new Path(); + equals(typeof path.insert, 'function'); + path.importJSON(path.exportJSON()); + equals(typeof path.insert, 'function'); +}); diff --git a/test/tests/Layer.js b/test/tests/Layer.js index c4d2a188..947f0ab4 100644 --- a/test/tests/Layer.js +++ b/test/tests/Layer.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -139,3 +139,9 @@ test('#remove() with named layers', function(){ equals(removeCount, 2, 'project.layers[name].remove(); should be called twice'); }); + +test('#bounds with nested empty items', function() { + var item = new Path.Rectangle(new Point(10,10), new Size(10)); + new Group(new Group()); + equals(item.bounds, project.activeLayer.bounds); +}); diff --git a/test/tests/Matrix.js b/test/tests/Matrix.js index 6046eaf8..ec499e4a 100644 --- a/test/tests/Matrix.js +++ b/test/tests/Matrix.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Numerical.js b/test/tests/Numerical.js index 01a5cb08..4bf3040f 100644 --- a/test/tests/Numerical.js +++ b/test/tests/Numerical.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/PaperScript.js b/test/tests/PaperScript.js new file mode 100644 index 00000000..1f2510c9 --- /dev/null +++ b/test/tests/PaperScript.js @@ -0,0 +1,48 @@ +/* + * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. + * http://paperjs.org/ + * + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +QUnit.module('PaperScript'); + +function executeCode(code, expected) { + try { + equals(PaperScript.execute(code, paper), expected, code); + } catch (err) { + ok(false, err + ''); + } +} + +test('PaperScript with prefix decrement operators', function() { + executeCode( + 'var j = 0; for (var i = 10; i > 0; i--) { j++ }; module.exports = j', + 10 + ); + executeCode( + 'var x = 1; var y = 4 * --x; y; module.exports = x + " " + y', + '0 0' + ); +}); + +test('PaperScript with suffix increment operators', function() { + executeCode( + 'var j = 0; for (var i = 0; i < 10; ++i) { j++ }; module.exports = j', + 10 + ); + // #691 + executeCode( + 'var x = 1; x = x++; module.exports = x', + 1 + ); + executeCode( + 'var x = 1; var y = 4 * x++; y; module.exports = x + " " + y', + '2 4' + ); +}); diff --git a/test/tests/Path.js b/test/tests/Path.js index d985fe7b..47678d73 100644 --- a/test/tests/Path.js +++ b/test/tests/Path.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -645,3 +645,11 @@ test('Path#arcTo(through, to) is on through point side (#1477)', function() { path.arcTo(p2, p3); equals(true, path.segments[1].point.x > p1.x); }); + +test('Path#arcTo(to, radius, rotation, clockwise, large) when from and to are equal (#1613)', function(){ + var point = new Point(10,10); + var path = new Path(); + path.moveTo(point); + path.arcTo(point, new Size(10), 0, true, true); + expect(0); +}); diff --git a/test/tests/PathItem.js b/test/tests/PathItem.js index 2ac17864..e92c4a1e 100644 --- a/test/tests/PathItem.js +++ b/test/tests/PathItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/PathItem_Contains.js b/test/tests/PathItem_Contains.js index 30367955..4a07f48e 100644 --- a/test/tests/PathItem_Contains.js +++ b/test/tests/PathItem_Contains.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -394,4 +394,10 @@ test('Path#contains() with Path#interiorPoint: #854, #1064', function() { } }); - +test('IPathtem#contains() with non-invertible matrices (#1651)', function() { + var path = new Path({ + matrix: new Matrix(0, 0, 0, 0, 0, 0) + }); + equals(path.contains(path.position), false, + 'A path with a non-invertible matrix cannot contain its position'); +}); diff --git a/test/tests/Path_Boolean.js b/test/tests/Path_Boolean.js index ed9061f8..c965ee89 100644 --- a/test/tests/Path_Boolean.js +++ b/test/tests/Path_Boolean.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -219,7 +219,6 @@ test('#784', function() { 'M265.13434,453.46566l-0.03434,0.03434c0,0 -49.1,-14.5 -36.6,-36.6c7.48073,-13.22593 39.10093,-1.6319 63.28843,9.81157l16.18604,-16.18604c-8.05354,-21.53223 -15.90287,-47.40397 -10.27447,-54.42553c9.77623,-12.51358 31.40373,30.40618 32.36674,32.33326l0.03326,-0.03326c0,0.1 65,49.8 65,65c0,15.2 -33.8,65 -65,65c-30.62393,0 -63.75273,-62.62185 -64.96566,-64.93434z'); }); - test('#784#issuecomment-144653463', function() { var path1 = new Path({ segments: [ @@ -1202,4 +1201,4 @@ test('#1513', function () { var path2 = PathItem.create('M200,100c55.22847,0 100,44.77153 100,100h-200c0,-55.22847 44.77153,-100 100,-100z'); var result = 'M100,100h200v100c0,-55.22847 -44.77153,-100 -100,-100c-55.22847,0 -100,44.77153 -100,100z'; compareBoolean(path1.subtract(path2), result); -}); \ No newline at end of file +}); diff --git a/test/tests/Path_Constructors.js b/test/tests/Path_Constructors.js index 220f0ca4..e4eaa33f 100644 --- a/test/tests/Path_Constructors.js +++ b/test/tests/Path_Constructors.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Path_Intersections.js b/test/tests/Path_Intersections.js index 3d079706..6e69ec65 100644 --- a/test/tests/Path_Intersections.js +++ b/test/tests/Path_Intersections.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Point.js b/test/tests/Point.js index 41a5d1e6..46a415d6 100644 --- a/test/tests/Point.js +++ b/test/tests/Point.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Project.js b/test/tests/Project.js index ca970d01..31da0956 100644 --- a/test/tests/Project.js +++ b/test/tests/Project.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Raster.js b/test/tests/Raster.js index 883dff1a..32f56fbf 100644 --- a/test/tests/Raster.js +++ b/test/tests/Raster.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -206,3 +206,31 @@ test('Raster#setSmoothing setting does not impact canvas context', function(asse done(); }; }); + +test('new Raster(size[, position])', function() { + // Size only. + var raster = new Raster(new Size(100, 100)); + equals(raster.position, new Point(0, 0)); + equals(raster.bounds, new Rectangle(-50, -50, 100, 100)); + + var raster = new Raster({size:new Size(100, 100)}); + equals(raster.position, new Point(0, 0)); + equals(raster.bounds, new Rectangle(-50, -50, 100, 100)); + + var raster = new Raster({width:100, height:100}); + equals(raster.position, new Point(0, 0)); + equals(raster.bounds, new Rectangle(-50, -50, 100, 100)); + + // Size and position. + var raster = new Raster(new Size(100, 100), new Point(100, 100)); + equals(raster.position, new Point(100, 100)); + equals(raster.bounds, new Rectangle(50, 50, 100, 100)); + + var raster = new Raster({size:new Size(100, 100), position:new Point(100, 100)}); + equals(raster.position, new Point(100, 100)); + equals(raster.bounds, new Rectangle(50, 50, 100, 100)); + + var raster = new Raster({width:100, height:100, position:new Point(100, 100)}); + equals(raster.position, new Point(100, 100)); + equals(raster.bounds, new Rectangle(50, 50, 100, 100)); +}); diff --git a/test/tests/Rectangle.js b/test/tests/Rectangle.js index af17a14d..70de44ca 100644 --- a/test/tests/Rectangle.js +++ b/test/tests/Rectangle.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Segment.js b/test/tests/Segment.js index 3a2107af..29bb0434 100644 --- a/test/tests/Segment.js +++ b/test/tests/Segment.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Shape.js b/test/tests/Shape.js index cc5b59fd..3380e92f 100644 --- a/test/tests/Shape.js +++ b/test/tests/Shape.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Size.js b/test/tests/Size.js index df21a771..14f3ac61 100644 --- a/test/tests/Size.js +++ b/test/tests/Size.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/Style.js b/test/tests/Style.js index b0d84183..f930592b 100644 --- a/test/tests/Style.js +++ b/test/tests/Style.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/SvgExport.js b/test/tests/SvgExport.js index a68f6cd3..a9b2ca62 100644 --- a/test/tests/SvgExport.js +++ b/test/tests/SvgExport.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -113,7 +113,13 @@ test('Export SVG path at precision 0', function() { equals(path.exportSVG({ precision: 0 }).getAttribute('d'), 'M0,2l1,1'); }); -if (!isNode) { +test('Export SVG viewbox attribute with top left at origin', function() { + var path = new Path.Rectangle(new Point(10, 10), new Size(80)); + var rectangle = new Rectangle(new Point(0, 0), new Size(100)); + equals(project.exportSVG({ bounds: rectangle }).getAttribute('viewBox'), '0,0,100,100'); +}); + +if (!isNodeContext) { // JSDom does not have SVG rendering, so we can't test there. test('Export transformed shapes', function(assert) { var rect = new Shape.Rectangle({ @@ -149,6 +155,17 @@ if (!isNode) { compareSVG(assert.async(), svg, project.activeLayer); }); + test('Export not invertible item.matrix', function(assert) { + var rect = new Shape.Rectangle({ + point: [100, 100], + size: [100, 100], + fillColor: 'red', + matrix: [1, 1, 1, 1, 1, 1] + }); + var svg = project.exportSVG({ bounds: 'content', asString: true }); + compareSVG(assert.async(), svg, project.activeLayer); + }); + test('Export gradients', function(assert) { var bounds = new Rectangle(new Size(300, 600)); var stops = [new Color(1, 1, 0, 0), 'red', 'black']; @@ -212,4 +229,19 @@ if (!isNode) { tolerance: 1e-2 }); }); + + test('Export symbol with stroke', function(assert) { + var item = new Path.Circle({ + center: [0, 0], + radius: 50, + strokeColor: 'blue', + strokeWidth: 10 + }); + + var symbol = new Symbol(item); + symbol.place([50, 50]); + + var svg = project.exportSVG({ bounds: 'content', asString: true }); + compareSVG(assert.async(), svg, project.activeLayer); + }); } diff --git a/test/tests/SvgImport.js b/test/tests/SvgImport.js index a7e256bf..a7dc2a48 100644 --- a/test/tests/SvgImport.js +++ b/test/tests/SvgImport.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -143,6 +143,21 @@ test('Import SVG without insertion', function() { }, true); }); +test('Import SVG switch', function(assert) { + var done = assert.async(); + var svg = ''; + paper.project.importSVG(svg, { + onLoad: function(item) { + equals(item.className, 'Group'); + equals(item.children.length, 1); + equals(item.firstChild.className, 'Group'); + equals(item.firstChild.children.length, 1); + equals(item.firstChild.firstChild, new Path([new Point(0, 0), new Point(10, 10)])); + done(); + } + }); +}); + function importSVG(assert, url, message, options) { var done = assert.async(); project.importSVG(url, { @@ -166,7 +181,7 @@ function importSVG(assert, url, message, options) { }); } -if (!isNode) { +if (!isNodeContext) { // JSDom does not have SVG rendering, so we can't test there. var svgFiles = { 'butterfly': { tolerance: 1e-2 }, @@ -176,16 +191,18 @@ if (!isNode) { 'symbol': {}, 'symbols': {}, 'blendModes': {}, - 'gradients-1': {} + 'gradients-1': {}, + 'gradients-2': !isPhantomContext && {}, + 'gradients-3': {}, + 'gradients-4': {} }; - // TODO: Investigate why Phantom struggles with this file: - if (!isPhantom) - svgFiles['gradients-2'] = {}; Base.each(svgFiles, function(options, name) { - name += '.svg'; - test('Import ' + name, function(assert) { - importSVG(assert, 'assets/' + name, null, options); - }); + if (options) { + name += '.svg'; + test('Import ' + name, function(assert) { + importSVG(assert, 'assets/' + name, null, options); + }); + } }); test('Import inexistent file', function(assert) { diff --git a/test/tests/SymbolItem.js b/test/tests/SymbolItem.js index 23957210..9e3ba191 100644 --- a/test/tests/SymbolItem.js +++ b/test/tests/SymbolItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/TextItem.js b/test/tests/TextItem.js index 4223f249..d544dcc2 100644 --- a/test/tests/TextItem.js +++ b/test/tests/TextItem.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * diff --git a/test/tests/load.js b/test/tests/load.js index 17e34a9a..a2546737 100644 --- a/test/tests/load.js +++ b/test/tests/load.js @@ -2,8 +2,8 @@ * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & https://puckey.studio/ * * Distributed under the MIT license. See LICENSE file for details. * @@ -63,7 +63,9 @@ /*#*/ include('Numerical.js'); +/*#*/ include('PaperScript.js'); + // There is no need to test interactions in node context. -if (!isNode) { +if (!isNodeContext) { /*#*/ include('Interactions.js'); } diff --git a/travis/deploy-prebuilt.sh b/travis/deploy-prebuilt.sh index 491eabc8..4e786d91 100755 --- a/travis/deploy-prebuilt.sh +++ b/travis/deploy-prebuilt.sh @@ -3,8 +3,8 @@ # Paper.js - The Swiss Army Knife of Vector Graphics Scripting. # http://paperjs.org/ # -# Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey -# http://scratchdisk.com/ & http://jonathanpuckey.com/ +# Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey +# http://scratchdisk.com/ & https://puckey.studio/ # # Distributed under the MIT license. See LICENSE file for details. # diff --git a/travis/install-assets.sh b/travis/install-assets.sh index 9ca3d767..8c1b9b8e 100755 --- a/travis/install-assets.sh +++ b/travis/install-assets.sh @@ -3,8 +3,8 @@ # Paper.js - The Swiss Army Knife of Vector Graphics Scripting. # http://paperjs.org/ # -# Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey -# http://scratchdisk.com/ & http://jonathanpuckey.com/ +# Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey +# http://scratchdisk.com/ & https://puckey.studio/ # # Distributed under the MIT license. See LICENSE file for details. # diff --git a/travis/setup-git.sh b/travis/setup-git.sh index fbc225bf..52021b5f 100755 --- a/travis/setup-git.sh +++ b/travis/setup-git.sh @@ -3,8 +3,8 @@ # Paper.js - The Swiss Army Knife of Vector Graphics Scripting. # http://paperjs.org/ # -# Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey -# http://scratchdisk.com/ & http://jonathanpuckey.com/ +# Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey +# http://scratchdisk.com/ & https://puckey.studio/ # # Distributed under the MIT license. See LICENSE file for details. #