mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 00:42:54 -05:00
Merge commit '7bb34e4' into merge-latest-paper
This commit is contained in:
commit
c3c51d29f6
147 changed files with 4962 additions and 1100 deletions
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
This issues database is used to keep track of bugs and new features.
|
This issues database is used to keep track of bugs and new features.
|
||||||
For questions and support, please visit the Gitter channel instead:
|
For questions and support, please visit the Gitter channel instead:
|
||||||
https://gitter.im/Vincit/objection.js
|
https://gitter.im/paperjs/paper.js
|
||||||
-->
|
-->
|
||||||
|
|
||||||
# Description/Steps to reproduce
|
# Description/Steps to reproduce
|
||||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -1,16 +1,15 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
|
os: linux
|
||||||
# Follow https://github.com/nodejs/LTS to decide when to remove a version
|
# Follow https://github.com/nodejs/LTS to decide when to remove a version
|
||||||
node_js:
|
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
|
- 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:
|
env:
|
||||||
matrix:
|
jobs:
|
||||||
- CXX=g++-4.9
|
- CXX=g++-4.9
|
||||||
global:
|
global:
|
||||||
- secure: o1fJ/suqcL0aX6PiOmip602dAM6Q6O5oU/BDhSueUOnYknbzWfWGOdsoMun0UYhvvdcXU4sHGH+wm0VeXa2igaxryx36uMxPsXB3mO4sATo/QlWX/r3wLCg2CViXhykE5l2gP45OHh5DJgKWs51cwGLDZ9y9JHlXSP/xIGBNkMGVC7qvyhTfEb0EVvirn9b7Kt8fmD8KYgNDrsmcR3d42f4jitt4Di9LsRyOG+SCXZfI3u831tHo1sgZuGK2rxx2SdEclIblEUCkFHLp0HPjq1+032Cg5D7HNloSCPfoSwcY+rOWHubNXhmXgZHFeSkaVglkdWlDE3NiyjNlYwc4m9zqfCip8jw/jUeSfFVtruncEumGLLBxE/aMBQjAQLTq24juabm3qZNgrNCFeFo+XNyx2Oz1jllGve6Vuu8Qg0wFqE+qlZKnxNbu5/3IOIawOE1uhaOG8oSuvlpQuNrHFIMEfzh2UKPiUHbElUDyoTzHlrhQr7ZSPWPJax4uIPOTscpK4Yks7FBS4I0Vnuhw41f/bVR0kLE9jNAQoUpp47ma9O2Sw9fhOwEiopVrADzARUiy0eNeLx8F2F73L0wyPBOtEL1cfCr5oY+yZ5ZfDYb/L8/GIlbMnljYxVbXesmwd8RFi8X2HUNnEmusjih9oWazVuZpiFfUO0oeu15JTBg=
|
- secure: o1fJ/suqcL0aX6PiOmip602dAM6Q6O5oU/BDhSueUOnYknbzWfWGOdsoMun0UYhvvdcXU4sHGH+wm0VeXa2igaxryx36uMxPsXB3mO4sATo/QlWX/r3wLCg2CViXhykE5l2gP45OHh5DJgKWs51cwGLDZ9y9JHlXSP/xIGBNkMGVC7qvyhTfEb0EVvirn9b7Kt8fmD8KYgNDrsmcR3d42f4jitt4Di9LsRyOG+SCXZfI3u831tHo1sgZuGK2rxx2SdEclIblEUCkFHLp0HPjq1+032Cg5D7HNloSCPfoSwcY+rOWHubNXhmXgZHFeSkaVglkdWlDE3NiyjNlYwc4m9zqfCip8jw/jUeSfFVtruncEumGLLBxE/aMBQjAQLTq24juabm3qZNgrNCFeFo+XNyx2Oz1jllGve6Vuu8Qg0wFqE+qlZKnxNbu5/3IOIawOE1uhaOG8oSuvlpQuNrHFIMEfzh2UKPiUHbElUDyoTzHlrhQr7ZSPWPJax4uIPOTscpK4Yks7FBS4I0Vnuhw41f/bVR0kLE9jNAQoUpp47ma9O2Sw9fhOwEiopVrADzARUiy0eNeLx8F2F73L0wyPBOtEL1cfCr5oY+yZ5ZfDYb/L8/GIlbMnljYxVbXesmwd8RFi8X2HUNnEmusjih9oWazVuZpiFfUO0oeu15JTBg=
|
||||||
|
@ -51,7 +50,7 @@ before_deploy:
|
||||||
- git config --global user.name $(git log --pretty=format:"%an" -n1)
|
- git config --global user.name $(git log --pretty=format:"%an" -n1)
|
||||||
deploy:
|
deploy:
|
||||||
- provider: npm
|
- provider: npm
|
||||||
node_js: 8
|
node_js: 10
|
||||||
on:
|
on:
|
||||||
branch: develop
|
branch: develop
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
- Jürg Lehni <juerg@scratchdisk.com>
|
- Jürg Lehni <juerg@scratchdisk.com>
|
||||||
- Jonathan Puckey <jonathan@studiomoniker.com>
|
- Jonathan Puckey <jonathan@puckey.studio>
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
- Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
- Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
||||||
- Jan Bösenberg <development@iconexperience.com>
|
- Jan Bösenberg <jan.boesenberg@gmail.com>
|
||||||
- Jt Whissel <jtwhissel@gmail.com>
|
- Jt Whissel <jtwhissel@gmail.com>
|
||||||
- Andrew Roles <jaroles58@gmail.com>
|
- Andrew Roles <jaroles58@gmail.com>
|
||||||
- Jacob Lites <jnightlight@gmail.com>
|
- Jacob Lites <jnightlight@gmail.com>
|
||||||
|
|
168
CHANGELOG.md
168
CHANGELOG.md
|
@ -1,5 +1,145 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## `0.12.7`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- PaperScript: Actually make `options.paperFeatures.moduleExports` work
|
||||||
|
independently from `options.paperFeatures.operatorOverloading`.
|
||||||
|
|
||||||
|
## `0.12.6`
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- PaperScript: Add option `options.paperFeatures.moduleExports` to control
|
||||||
|
module exports conversion.
|
||||||
|
|
||||||
|
## `0.12.5`
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- PaperScript: Add option `options.paperFeatures.operatorOverloading` to control
|
||||||
|
operator overloading.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix `new Raster(HTMLCanvasElement)` constructor (#1745).
|
||||||
|
- Handle `CurveLocation` on paths with only one segment.
|
||||||
|
- Fix recently introduced error in `CompoundPath.compare()` (#1769).
|
||||||
|
- Clamp opacity values to [0, 1] (#1814).
|
||||||
|
- Support closed `Path` items with blend mode and no segments (#1763).
|
||||||
|
- Fix error in `getCrossingSegments()` (#1773).
|
||||||
|
- SVG Import: Support SVG strings with leading line-breaks (#1813).
|
||||||
|
- Docs: Improve documentation for `Raster#drawImage(CanvasImageSource)` (#1784).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Use `'paper-'` prefix in generated view ids.
|
||||||
|
|
||||||
|
## `0.12.4`
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Allow paper core import in TypeScript (#1713).
|
||||||
|
- Boolean: Improve performance from `O(n^2)` to nearly `O(n)` by the use of the
|
||||||
|
sweep and prune algorithm (#1737).
|
||||||
|
- Docs: Add support for nullable values.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix `PathItem#getCrossing()` to not return overlaps (#1409).
|
||||||
|
- Fix regression in `Curve.getIntersections()` (#1638).
|
||||||
|
- Fix edge cases in `CurveLocation.isCrossing()` (#1419, #1263).
|
||||||
|
- Fix `SymbolItem#hitTestAll()` to return only one match per symbol item
|
||||||
|
(#1680).
|
||||||
|
- Fix handling of negative `Shape` sizes (#1733).
|
||||||
|
- Fix parsing of RGB `Color` strings with percentages (#1736).
|
||||||
|
- Fix `Shape` bounds when passing position in constructor (#1686).
|
||||||
|
- Prevent nested group matrix from reset when transforming parent (#1711).
|
||||||
|
- Boolean: Fix edge cases in overlap detection (#1262).
|
||||||
|
- Boolean: Add check for paths with only one segment (#1351).
|
||||||
|
- Boolean: Correctly handle open filled paths (#1647).
|
||||||
|
- Boolean: Avoid winding number edge cases (#1619).
|
||||||
|
- Docs: Fix some documentation return types (#1679).
|
||||||
|
|
||||||
|
## `0.12.3`
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add documentation for `Item#internalBounds`.
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
|
## `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 `<switch/>` 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`
|
## `0.11.8`
|
||||||
|
|
||||||
### News
|
### News
|
||||||
|
@ -59,6 +199,7 @@ the fixes and additions from the past two weeks:
|
||||||
## `0.11.5`
|
## `0.11.5`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix `Curve#isSelected()` to correctly reflect the state of `#handle1` (#1378).
|
- Fix `Curve#isSelected()` to correctly reflect the state of `#handle1` (#1378).
|
||||||
- Key Events: Fix auto-filling issue on Chrome (#1358, #1365).
|
- Key Events: Fix auto-filling issue on Chrome (#1358, #1365).
|
||||||
- Boolean: Check that overlaps are on the right path (#1321).
|
- Boolean: Check that overlaps are on the right path (#1321).
|
||||||
|
@ -71,38 +212,42 @@ the fixes and additions from the past two weeks:
|
||||||
## `0.11.4`
|
## `0.11.4`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Node.js: Add support for v8, and keep testing v4, v6, v7 in Travis CI.
|
- Node.js: Add support for v8, and keep testing v4, v6, v7 in Travis CI.
|
||||||
|
|
||||||
## `0.11.3`
|
## `0.11.3`
|
||||||
|
|
||||||
### Fixed
|
### 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
|
- Overhaul the caching of bounds and matrix decomposition, improving reliability
|
||||||
of `Item#rotation` and `#scaling` and fixing situations caused by wrongly
|
of `Item#rotation` and `#scaling` and fixing situations caused by wrongly
|
||||||
caching `Item#position` and `#bounds` values.
|
caching `Item#position` and `#bounds` values.
|
||||||
|
|
||||||
- Prevent consumed properties in object literal constructors from being set on
|
- Prevent consumed properties in object literal constructors from being set on
|
||||||
the instance.
|
the instance.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Make all functions and accessors enumerable on all Paper.js classes.
|
- Make all functions and accessors enumerable on all Paper.js classes.
|
||||||
|
|
||||||
## `0.11.2`
|
## `0.11.2`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- PaperScript: Fix a parsing error in math operations without white-space
|
- PaperScript: Fix a parsing error in math operations without white-space
|
||||||
(#1314).
|
(#1314).
|
||||||
|
|
||||||
## `0.11.1`
|
## `0.11.1`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Bring back deactivation of Node.js modules on browsers. This has most probably
|
- Bring back deactivation of Node.js modules on browsers. This has most probably
|
||||||
broken Webpack bundling in `0.11.0`.
|
broken Webpack bundling in `0.11.0`.
|
||||||
|
|
||||||
## `0.11.0`
|
## `0.11.0`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Separate `paper` module on NPM into: `paper`, `paper-jsdom` and
|
- Separate `paper` module on NPM into: `paper`, `paper-jsdom` and
|
||||||
`paper-jsdom-canvas` (#1252):
|
`paper-jsdom-canvas` (#1252):
|
||||||
- `paper` is the main library, and can be used directly in a browser
|
- `paper` is the main library, and can be used directly in a browser
|
||||||
|
@ -115,12 +260,14 @@ the fixes and additions from the past two weeks:
|
||||||
[jsdom](https://github.com/tmpvar/jsdom).
|
[jsdom](https://github.com/tmpvar/jsdom).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- PaperScript: Support newer, external versions of Acorn.js for PaperScript
|
- PaperScript: Support newer, external versions of Acorn.js for PaperScript
|
||||||
parsing, opening the doors to ES 2015 (#1183, #1275).
|
parsing, opening the doors to ES 2015 (#1183, #1275).
|
||||||
- Hit Tests: Implement `options.position` to hit `Item#position` (#1249).
|
- Hit Tests: Implement `options.position` to hit `Item#position` (#1249).
|
||||||
- Split `Item#copyTo()` into `#addTo()` and `#copyTo()`.
|
- Split `Item#copyTo()` into `#addTo()` and `#copyTo()`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Intersections: Bring back special handling of curve end-points (#1284).
|
- Intersections: Bring back special handling of curve end-points (#1284).
|
||||||
- Intersections: Correctly handle `Item#applyMatrix = false` (#1289).
|
- Intersections: Correctly handle `Item#applyMatrix = false` (#1289).
|
||||||
- Boolean: Bring back on-path winding handling (#1281).
|
- Boolean: Bring back on-path winding handling (#1281).
|
||||||
|
@ -154,6 +301,7 @@ the fixes and additions from the past two weeks:
|
||||||
## `0.10.3`
|
## `0.10.3`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Node.js: Support v7, and keep testing v4 up to v7 in Travis CI.
|
- 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
|
- 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).
|
its absence like a headless web worker context in the browser (#1103).
|
||||||
|
@ -178,6 +326,7 @@ the fixes and additions from the past two weeks:
|
||||||
`#reorient()` (#973).
|
`#reorient()` (#973).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Implement `Path#divideAt(location)`, in analogy to `Curve#divideAt(location)`.
|
- 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
|
- 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
|
if they describe the same shape, handling cases where paths start in different
|
||||||
|
@ -196,6 +345,7 @@ the fixes and additions from the past two weeks:
|
||||||
(#1004, #1177).
|
(#1004, #1177).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Many improvements to boolean operations:
|
- Many improvements to boolean operations:
|
||||||
- Improve performance of boolean operations when there no actual crossings
|
- Improve performance of boolean operations when there no actual crossings
|
||||||
between the paths, but paths may be contained within each other.
|
between the paths, but paths may be contained within each other.
|
||||||
|
@ -236,17 +386,20 @@ the fixes and additions from the past two weeks:
|
||||||
(#632).
|
(#632).
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Remove `Numerical.TOLERANCE = 1e-6` as there is no internal use for it
|
- Remove `Numerical.TOLERANCE = 1e-6` as there is no internal use for it
|
||||||
anymore.
|
anymore.
|
||||||
|
|
||||||
## `0.10.2`
|
## `0.10.2`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Get published version to work correctly in Bower again.
|
- Get published version to work correctly in Bower again.
|
||||||
|
|
||||||
## `0.10.1`
|
## `0.10.1`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Correct a few issues with documentation and NPM publishing that slipped
|
- Correct a few issues with documentation and NPM publishing that slipped
|
||||||
through in the `0.10.0` release.
|
through in the `0.10.0` release.
|
||||||
|
|
||||||
|
@ -284,6 +437,7 @@ Thank you all for using Paper.js, submitting bugs and ideas, and all those that
|
||||||
contribute to the code.
|
contribute to the code.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Significant overhaul and improvements of boolean path operations
|
- Significant overhaul and improvements of boolean path operations
|
||||||
`PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()`:
|
`PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()`:
|
||||||
- Improve handling of self-intersecting paths and non-zero fill-rules.
|
- Improve handling of self-intersecting paths and non-zero fill-rules.
|
||||||
|
@ -300,7 +454,7 @@ contribute to the code.
|
||||||
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
||||||
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
||||||
- `Curve#getPointAt(time, true)` → `#getPointAtTime(time)`
|
- `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#getNormalAt(time, true)` → `#getNormalAtTime(time)`
|
||||||
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
||||||
- `CurveLocation#parameter` → `#time`
|
- `CurveLocation#parameter` → `#time`
|
||||||
|
@ -360,6 +514,7 @@ contribute to the code.
|
||||||
`Color` (#1043).
|
`Color` (#1043).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Use unified code-base for browsers, Node.js, Electron, and anything
|
- Use unified code-base for browsers, Node.js, Electron, and anything
|
||||||
in-between, and enable npm install for browser use (#739).
|
in-between, and enable npm install for browser use (#739).
|
||||||
- Start using automatic code testing and deployment of prebuilt versions through
|
- Start using automatic code testing and deployment of prebuilt versions through
|
||||||
|
@ -424,6 +579,7 @@ contribute to the code.
|
||||||
- Add `Raster#loaded` to reflect the loading state of its image.
|
- Add `Raster#loaded` to reflect the loading state of its image.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix calculations of `Item#strokeBounds` for all possible combinations of
|
- Fix calculations of `Item#strokeBounds` for all possible combinations of
|
||||||
`Item#strokeScaling` and `Item#applyMatrix` for `Path`, `Shape` and
|
`Item#strokeScaling` and `Item#applyMatrix` for `Path`, `Shape` and
|
||||||
`SymbolItem`, along with correct handling of such strokes in Item#hitTest()
|
`SymbolItem`, along with correct handling of such strokes in Item#hitTest()
|
||||||
|
@ -502,10 +658,11 @@ contribute to the code.
|
||||||
`Numerical.solveCubic()` for edge-cases (#1085).
|
`Numerical.solveCubic()` for edge-cases (#1085).
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Canvas attributes "resize" and "data-paper-resize" no longer cause paper to
|
- Canvas attributes "resize" and "data-paper-resize" no longer cause paper to
|
||||||
resize the canvas when the viewport size changes; Additional CSS styles are
|
resize the canvas when the viewport size changes; Additional CSS styles are
|
||||||
required since `0.9.22`, e.g.:
|
required since `0.9.22`, e.g.:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* Scale canvas with resize attribute to full size */
|
/* Scale canvas with resize attribute to full size */
|
||||||
canvas[resize] {
|
canvas[resize] {
|
||||||
|
@ -520,6 +677,7 @@ contribute to the code.
|
||||||
It is replaced by `Project#addLayer()` and `Project#insertLayer()`.
|
It is replaced by `Project#addLayer()` and `Project#insertLayer()`.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
- `#windingRule` on `Item` and `Style` → `#fillRule`
|
- `#windingRule` on `Item` and `Style` → `#fillRule`
|
||||||
- `Curve#getNormalAt(time, true)` → `#getNormalAtTime(true)`
|
- `Curve#getNormalAt(time, true)` → `#getNormalAtTime(true)`
|
||||||
- `Curve#divide()` → `#divideAt(offset)` / `#divideAtTime(time)`
|
- `Curve#divide()` → `#divideAt(offset)` / `#divideAtTime(time)`
|
||||||
|
@ -527,7 +685,7 @@ contribute to the code.
|
||||||
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
||||||
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
||||||
- `Curve#getPointAt(time, true)` → `#getPointAtTime(time)`
|
- `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#getNormalAt(time, true)` → `#getNormalAtTime(time)`
|
||||||
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
||||||
- `CurveLocation#parameter` → `#time`
|
- `CurveLocation#parameter` → `#time`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
http://scratchdisk.com/ & http://jonathanpuckey.com/
|
http://juerglehni.com/ & https://puckey.studio/
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
59
README.md
59
README.md
|
@ -1,9 +1,10 @@
|
||||||
# Paper.js - The Swiss Army Knife of Vector Graphics Scripting [![Build Status](https://travis-ci.org/paperjs/paper.js.svg?branch=develop)](https://travis-ci.org/paperjs/paper.js) [![NPM](https://img.shields.io/npm/v/paper.svg)](https://www.npmjs.com/package/paper) ![Bower](https://img.shields.io/bower/v/paper.svg)
|
# Paper.js - The Swiss Army Knife of Vector Graphics Scripting [![Build Status](https://travis-ci.org/paperjs/paper.js.svg?branch=develop)](https://travis-ci.org/paperjs/paper.js) [![NPM](https://img.shields.io/npm/v/paper.svg)](https://www.npmjs.com/package/paper)
|
||||||
|
|
||||||
If you want to work with Paper.js, simply download the latest "stable" version
|
If you want to work with Paper.js, simply download the latest "stable" version
|
||||||
from [http://paperjs.org/download/](http://paperjs.org/download/)
|
from [http://paperjs.org/download/](http://paperjs.org/download/)
|
||||||
|
|
||||||
- Website: <http://paperjs.org/>
|
- Website: <http://paperjs.org/>
|
||||||
|
- Questions: <https://stackoverflow.com/questions/tagged/paperjs>
|
||||||
- Discussion forum: <https://groups.google.com/group/paperjs>
|
- Discussion forum: <https://groups.google.com/group/paperjs>
|
||||||
- Mainline source code: <https://github.com/paperjs/paper.js>
|
- Mainline source code: <https://github.com/paperjs/paper.js>
|
||||||
- Twitter: [@paperjs](https://twitter.com/paperjs)
|
- Twitter: [@paperjs](https://twitter.com/paperjs)
|
||||||
|
@ -17,24 +18,22 @@ from [http://paperjs.org/download/](http://paperjs.org/download/)
|
||||||
|
|
||||||
The recommended way to install and maintain Paper.js as a dependency in your
|
The recommended way to install and maintain Paper.js as a dependency in your
|
||||||
project is through the [Node.js Package Manager (NPM)](https://www.npmjs.com/)
|
project is through the [Node.js Package Manager (NPM)](https://www.npmjs.com/)
|
||||||
for browsers, Node.js or Electron, as well as through Bower for browsers.
|
for browsers, Node.js or Electron.
|
||||||
|
|
||||||
If NPM or Bower is already installed, simply type one of these
|
If NPM is already installed, simply type one of these commands in your project
|
||||||
commands in your project folder:
|
folder:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install paper
|
npm install paper
|
||||||
# Or:
|
|
||||||
bower install paper
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Upon execution, you will find a `paper` folder inside the project's
|
Upon execution, you will find a `paper` folder inside the project's
|
||||||
`node_modules` / `bower_components` folder.
|
`node_modules` folder.
|
||||||
|
|
||||||
For more information on how to install Node.js and NPM, read the chapter
|
For more information on how to install Node.js and NPM, read the chapter
|
||||||
[Installing Node.js and NPM](#installing-nodejs-and-npm).
|
[Installing Node.js and NPM](#installing-nodejs-and-npm).
|
||||||
|
|
||||||
### Which Version to Use?
|
### Which Version to Use
|
||||||
|
|
||||||
The various distributions come with two different pre-build versions of
|
The various distributions come with two different pre-build versions of
|
||||||
Paper.js, in minified and normal variants:
|
Paper.js, in minified and normal variants:
|
||||||
|
@ -68,7 +67,7 @@ rendering to the Canvas on Node.js, as described in the next paragraph.
|
||||||
For Linux, see <https://nodejs.org/download/> to locate 32-bit and 64-bit Node.js
|
For Linux, see <https://nodejs.org/download/> to locate 32-bit and 64-bit Node.js
|
||||||
binaries as well as sources, or use NVM, as described in the paragraph above.
|
binaries as well as sources, or use NVM, as described in the paragraph above.
|
||||||
|
|
||||||
### Installing Paper.js for Node.js
|
### Installing Paper.js Using NPM
|
||||||
|
|
||||||
Paper.js comes in three different versions on NPM: `paper`, `paper-jsdom` and
|
Paper.js comes in three different versions on NPM: `paper`, `paper-jsdom` and
|
||||||
`paper-jsdom-canvas`. Depending on your use case, you need to required a
|
`paper-jsdom-canvas`. Depending on your use case, you need to required a
|
||||||
|
@ -85,10 +84,17 @@ different one:
|
||||||
In order to install `paper-jsdom-canvas`, you need the [Cairo Graphics
|
In order to install `paper-jsdom-canvas`, you need the [Cairo Graphics
|
||||||
library](https://cairographics.org/) installed in your system:
|
library](https://cairographics.org/) installed in your system:
|
||||||
|
|
||||||
##### Installing Cairo and Pango on macOS:
|
### Installing Native Dependencies
|
||||||
|
|
||||||
The easiest way to install Cairo is through [Homebrew](https://brew.sh/), by
|
Paper.js relies on [Node-Canvas](https://github.com/Automattic/node-canvas) for
|
||||||
issuing the command:
|
rendering, which in turn relies on the native libraries
|
||||||
|
[Cairo](https://cairographics.org/) and [Pango](https://www.pango.org/).
|
||||||
|
|
||||||
|
#### Installing Native Dependencies on macOS
|
||||||
|
|
||||||
|
Paper.js relies on Node-Canvas for rendering, which in turn relies on Cairo and
|
||||||
|
Pango. The easiest way to install Cairo is through
|
||||||
|
[Homebrew](https://brew.sh/), by issuing the command:
|
||||||
|
|
||||||
brew install cairo pango
|
brew install cairo pango
|
||||||
|
|
||||||
|
@ -112,7 +118,7 @@ After adding this line, your commands should work in the expected way:
|
||||||
npm install paper
|
npm install paper
|
||||||
npm update
|
npm update
|
||||||
|
|
||||||
##### Installing Cairo, Pango and all other dependencies on Debian/Ubuntu Linux:
|
#### Installing Native Dependencies on Debian/Ubuntu Linux
|
||||||
|
|
||||||
sudo apt-get install pkg-config libcairo2-dev libpango1.0-dev libssl-dev libjpeg62-dev libgif-dev
|
sudo apt-get install pkg-config libcairo2-dev libpango1.0-dev libssl-dev libjpeg62-dev libgif-dev
|
||||||
|
|
||||||
|
@ -121,24 +127,23 @@ build from c++ sources:
|
||||||
|
|
||||||
sudo apt-get install build-essential
|
sudo apt-get install build-essential
|
||||||
|
|
||||||
##### After Cairo has been installed:
|
#### Installing Native Dependencies for Electron
|
||||||
|
|
||||||
|
In order to build Node-Canvas for use of `paper-jsdom-canvas` in Electron, which
|
||||||
|
is likely to use a different version of V8 than the Node binary installed in
|
||||||
|
your system, you need to manually specify the location of Electron’s headers.
|
||||||
|
Follow these steps to do so:
|
||||||
|
|
||||||
|
[Electron — Using Native Node
|
||||||
|
Modules](https://electron.atom.io/docs/tutorial/using-native-node-modules/)
|
||||||
|
|
||||||
|
#### After Native Dependencies have been installed
|
||||||
|
|
||||||
You should now be able to install the Paper.js module with jsdom and Canvas
|
You should now be able to install the Paper.js module with jsdom and Canvas
|
||||||
rendering from NPM:
|
rendering from NPM:
|
||||||
|
|
||||||
npm install paper-jsdom-canvas
|
npm install paper-jsdom-canvas
|
||||||
|
|
||||||
### Installing Paper.js with Node-Canvas for Electron
|
|
||||||
|
|
||||||
[Node-Canvas](https://github.com/Automattic/node-canvas) is a native dependency.
|
|
||||||
In order to build it for use of `paper-jsdom-canvas` in Electron, which is
|
|
||||||
likely to use a different version of V8 than the Node binary installed in your
|
|
||||||
system, you need to manually specify the location of Electron’s headers. Follow
|
|
||||||
these steps to do so:
|
|
||||||
|
|
||||||
[Electron — Using Native Node
|
|
||||||
Modules](https://electron.atom.io/docs/tutorial/using-native-node-modules/)
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
The main Paper.js source tree is hosted on
|
The main Paper.js source tree is hosted on
|
||||||
|
@ -163,8 +168,8 @@ run:
|
||||||
### Setting Up For Building
|
### Setting Up For Building
|
||||||
|
|
||||||
As of 2016, Paper.js uses [Gulp.js](https://gulpjs.com/) for building, and has a
|
As of 2016, Paper.js uses [Gulp.js](https://gulpjs.com/) for building, and has a
|
||||||
couple of dependencies as Bower and NPM modules. Read the chapter [Installing
|
couple of dependencies as NPM modules. Read the chapter [Installing
|
||||||
Node.js, NPM and Bower](#installing-nodejs-npm-and-bower) if you still need to
|
Node.js and NPM](#installing-nodejs-and-npm) if you still need to
|
||||||
install these.
|
install these.
|
||||||
|
|
||||||
In order to be able to build Paper.js, after checking out the repository, paper
|
In order to be able to build Paper.js, after checking out the repository, paper
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
},
|
},
|
||||||
"bugs": "https://github.com/paperjs/paper.js/issues",
|
"bugs": "https://github.com/paperjs/paper.js/issues",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)",
|
"Jürg Lehni <juerg@scratchdisk.com> (http://juerglehni.com)",
|
||||||
"Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"
|
"Jonathan Puckey <jonathan@puckey.studio> (http://puckey.studio)"
|
||||||
],
|
],
|
||||||
"main": "dist/paper-full.js",
|
"main": "dist/paper-full.js",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
|
|
|
@ -24,7 +24,7 @@ raster.onLoad = function() {
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
var svg = new paper.XMLSerializer().serializeToString(project.exportSVG());
|
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;
|
if (err) throw err;
|
||||||
console.log('Saved!');
|
console.log('Saved!');
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,7 +45,7 @@ with (paper) {
|
||||||
var svg = project.exportSVG({ asString: true });
|
var svg = project.exportSVG({ asString: true });
|
||||||
console.log(svg);
|
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;
|
if (err) throw err;
|
||||||
console.log('Saved!');
|
console.log('Saved!');
|
||||||
});
|
});
|
||||||
|
|
115
examples/Paperjs.org/BooleanOperattions.html
Normal file
115
examples/Paperjs.org/BooleanOperattions.html
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Path Intersections</title>
|
||||||
|
<link rel="stylesheet" href="../css/style.css">
|
||||||
|
<script type="text/javascript" src="../../dist/paper-full.js"></script>
|
||||||
|
<script type="text/paperscript" canvas="canvas">
|
||||||
|
var text = new PointText({
|
||||||
|
position: view.center + [0, 200],
|
||||||
|
fillColor: 'black',
|
||||||
|
justification: 'center',
|
||||||
|
fontSize: 20
|
||||||
|
});
|
||||||
|
|
||||||
|
var originals = new Group({ insert: false }); // Don't insert in DOM.
|
||||||
|
|
||||||
|
var square = new Path.Rectangle({
|
||||||
|
position: view.center,
|
||||||
|
size: 300,
|
||||||
|
parent: originals,
|
||||||
|
fillColor: 'white'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make a ring using subtraction of two circles:
|
||||||
|
var inner = new Path.Circle({
|
||||||
|
center: view.center,
|
||||||
|
radius: 100,
|
||||||
|
parent: originals,
|
||||||
|
fillColor: 'white'
|
||||||
|
});
|
||||||
|
|
||||||
|
var outer = new Path.Circle({
|
||||||
|
center: view.center,
|
||||||
|
radius: 140,
|
||||||
|
parent: originals,
|
||||||
|
fillColor: 'white'
|
||||||
|
});
|
||||||
|
|
||||||
|
var ring = outer.subtract(inner);
|
||||||
|
|
||||||
|
var operations = ['unite', 'intersect', 'subtract', 'exclude', 'divide'];
|
||||||
|
var colors = ['red', 'green', 'blue', 'black'];
|
||||||
|
var curIndex = -1;
|
||||||
|
var operation, result, activeItem;
|
||||||
|
|
||||||
|
// Change the mode every 3 seconds:
|
||||||
|
setInterval(setMode, 3000);
|
||||||
|
|
||||||
|
// Set the initial mode:
|
||||||
|
setMode();
|
||||||
|
|
||||||
|
function setMode() {
|
||||||
|
curIndex++;
|
||||||
|
if (curIndex == operations.length * 2)
|
||||||
|
curIndex = 0;
|
||||||
|
operation = operations[curIndex % operations.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseDown(event) {
|
||||||
|
var hitResult = originals.hitTest(event.point);
|
||||||
|
activeItem = hitResult && hitResult.item;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseDrag(event) {
|
||||||
|
if (activeItem)
|
||||||
|
activeItem.position = event.point;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseUp() {
|
||||||
|
activeItem = null;
|
||||||
|
square.position = view.center;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFrame(event) {
|
||||||
|
if (activeItem != ring) {
|
||||||
|
// Move the ring around:
|
||||||
|
var offset = new Point(140, 80) * [Math.sin(event.count / 60), Math.sin(event.count / 40)];
|
||||||
|
ring.position = view.center + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the result of the last path operation:
|
||||||
|
if (result)
|
||||||
|
result.remove();
|
||||||
|
|
||||||
|
// Perform the path operation on the ring:
|
||||||
|
if (curIndex < operations.length) {
|
||||||
|
result = square[operation](ring);
|
||||||
|
text.content = 'square.' + operation + '(ring)';
|
||||||
|
} else {
|
||||||
|
result = ring[operation](square);
|
||||||
|
text.content = 'ring.' + operation + '(square)';
|
||||||
|
}
|
||||||
|
result.selected = true;
|
||||||
|
result.fillColor = colors[curIndex % colors.length];
|
||||||
|
result.moveBelow(text);
|
||||||
|
|
||||||
|
// If the result is a group, color each of its children differently:
|
||||||
|
if (result instanceof Group) {
|
||||||
|
for (var i = 0; i < result.children.length; i++) {
|
||||||
|
result.children[i].fillColor = colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onResize() {
|
||||||
|
text.position = view.center + [0, 200];
|
||||||
|
square.position = view.center;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" resize></canvas>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2533ac8e1863262f3c28cd29bc940c6d2ecdf147
|
Subproject commit 1d38968146973a4bb10f5495b73c9d5dd46188d7
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -22,6 +22,8 @@ gulp.task('zip', ['clean:zip', 'dist'], function() {
|
||||||
gulp.src([
|
gulp.src([
|
||||||
'dist/paper-full*.js',
|
'dist/paper-full*.js',
|
||||||
'dist/paper-core*.js',
|
'dist/paper-core*.js',
|
||||||
|
'dist/paper.d.ts',
|
||||||
|
'dist/paper-core.d.ts',
|
||||||
'dist/node/**/*',
|
'dist/node/**/*',
|
||||||
'LICENSE.txt',
|
'LICENSE.txt',
|
||||||
'examples/**/*',
|
'examples/**/*',
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -14,14 +14,15 @@ var gulp = require('gulp'),
|
||||||
del = require('del'),
|
del = require('del'),
|
||||||
rename = require('gulp-rename'),
|
rename = require('gulp-rename'),
|
||||||
shell = require('gulp-shell'),
|
shell = require('gulp-shell'),
|
||||||
options = require('../utils/options.js');
|
options = require('../utils/options.js'),
|
||||||
|
run = require('run-sequence');
|
||||||
|
|
||||||
var docOptions = {
|
var docOptions = {
|
||||||
local: 'docs', // Generates the offline docs
|
local: 'docs', // Generates the offline docs
|
||||||
server: 'serverdocs' // Generates the website templates for the online 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')
|
return gulp.src('dist/paper-full.js')
|
||||||
.pipe(rename({ basename: 'paper' }))
|
.pipe(rename({ basename: 'paper' }))
|
||||||
.pipe(gulp.dest('dist/docs/assets/js/'));
|
.pipe(gulp.dest('dist/docs/assets/js/'));
|
||||||
|
@ -32,15 +33,58 @@ Object.keys(docOptions).forEach(function(name) {
|
||||||
var mode = docOptions[name];
|
var mode = docOptions[name];
|
||||||
return gulp.src('src')
|
return gulp.src('src')
|
||||||
.pipe(shell(
|
.pipe(shell(
|
||||||
['java -cp jsrun.jar:lib/* JsRun app/run.js',
|
[
|
||||||
' -c=conf/', name, '.conf ',
|
'java -cp jsrun.jar:lib/* JsRun app/run.js',
|
||||||
' -D="renderMode:', mode, '" ',
|
' -c=conf/', name, '.conf ',
|
||||||
' -D="version:', options.version, '"'].join(''),
|
' -D="renderMode:', mode, '" ',
|
||||||
|
' -D="version:', options.version, '"'
|
||||||
|
].join(''),
|
||||||
{ cwd: 'gulp/jsdoc' })
|
{ cwd: 'gulp/jsdoc' })
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('clean:docs:' + name, function() {
|
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'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
end_with_newline: true
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('publish', function() {
|
gulp.task('publish', function(callback) {
|
||||||
if (options.branch !== 'develop') {
|
if (options.branch !== 'develop') {
|
||||||
throw new Error('Publishing is only allowed on the develop branch.');
|
throw new Error('Publishing is only allowed on the develop branch.');
|
||||||
}
|
}
|
||||||
// publish:website comes before publish:release, so paperjs.zip file is gone
|
// publish:website comes before publish:release, so paperjs.zip file is gone
|
||||||
// before npm publish:
|
// before npm publish:
|
||||||
return run(
|
run(
|
||||||
'publish:json',
|
'publish:json',
|
||||||
'publish:dist',
|
'publish:dist',
|
||||||
'publish:packages',
|
'publish:packages',
|
||||||
'publish:commit',
|
'publish:commit',
|
||||||
'publish:website',
|
'publish:website',
|
||||||
'publish:release',
|
'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()) {
|
if (fs.lstatSync(sitePath).isDirectory()) {
|
||||||
return run(
|
run(
|
||||||
'publish:website:build',
|
'publish:website:build',
|
||||||
'publish:website:push'
|
'publish:website:push',
|
||||||
|
callback
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
9
gulp/typescript/tsconfig.json
Normal file
9
gulp/typescript/tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES5",
|
||||||
|
"strictNullChecks": true
|
||||||
|
},
|
||||||
|
"files" : [
|
||||||
|
"typescript-definition-test.ts"
|
||||||
|
]
|
||||||
|
}
|
357
gulp/typescript/typescript-definition-generator.js
Normal file
357
gulp/typescript/typescript-definition-generator.js
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
/**
|
||||||
|
* 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(it => it.className === 'PaperScope');
|
||||||
|
paperScopeClass.classesPointers = classes.map(it => ({ name: it.className }));
|
||||||
|
|
||||||
|
// Format data trough a mustache template.
|
||||||
|
// Prepare data for the template.
|
||||||
|
const context = {
|
||||||
|
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<any>` 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 restPattern = /^\.\.\./;
|
||||||
|
const isRest = type.match(restPattern);
|
||||||
|
if (isRest) {
|
||||||
|
type = type.replace(restPattern, '');
|
||||||
|
}
|
||||||
|
const wrappedPattern = /^\(([^\)]+)\)$/;
|
||||||
|
const isWrapped = type.match(wrappedPattern);
|
||||||
|
if (isWrapped) {
|
||||||
|
type = type.replace(wrappedPattern, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle multiple types possibility by splitting on `|` then re-joining
|
||||||
|
// back parsed types.
|
||||||
|
const types = type.split('|');
|
||||||
|
|
||||||
|
// Hanle nullable type:
|
||||||
|
// - `?Type` => `Type|null`
|
||||||
|
// - `?TypeA|TypeB` => `TypeA|TypeB|null`
|
||||||
|
// - `?TypeA|?TypeB` => `TypeA|TypeB|null`
|
||||||
|
// If at least one type is nullable, we add null type at the end of the
|
||||||
|
// list.
|
||||||
|
const nullablePattern = /^\?/;
|
||||||
|
let isNullable = false;
|
||||||
|
for (let i = 0; i < types.length; i++) {
|
||||||
|
if (types[i].match(nullablePattern)) {
|
||||||
|
types[i] = types[i].replace(nullablePattern, '');
|
||||||
|
isNullable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isNullable) {
|
||||||
|
types.push('null');
|
||||||
|
}
|
||||||
|
|
||||||
|
type = types.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(' | ');
|
||||||
|
|
||||||
|
// Regroup types.
|
||||||
|
if (isWrapped) {
|
||||||
|
type = `(${type})`;
|
||||||
|
}
|
||||||
|
if (isRest) {
|
||||||
|
type += '[]';
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
65
gulp/typescript/typescript-definition-template.mustache
Normal file
65
gulp/typescript/typescript-definition-template.mustache
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*!
|
||||||
|
* Paper.js v{{version}} - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
|
* http://paperjs.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
|
* http://juerglehni.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 namespace paper {
|
||||||
|
{{#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/dist/paper-core'
|
||||||
|
{
|
||||||
|
const paperCore: Pick<paper.PaperScope, Exclude<keyof paper.PaperScope, 'PaperScript'>>;
|
||||||
|
export = paperCore
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'paper'
|
||||||
|
{
|
||||||
|
const paperFull: paper.PaperScope;
|
||||||
|
export = paperFull
|
||||||
|
}
|
1206
gulp/typescript/typescript-definition-test.ts
Normal file
1206
gulp/typescript/typescript-definition-test.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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');
|
options.branch = git('rev-parse --abbrev-ref HEAD');
|
||||||
|
|
||||||
// If a specific branch is requested, quit without errors if we don't match.
|
// If a specific branch is requested, quit without errors if we don't match.
|
||||||
if (argv.branch && argv.branch !== options.branch) {
|
var ensureBranch = argv['ensure-branch'];
|
||||||
console.log('Branch "' + options.branch + '" does not match "' +
|
if (ensureBranch && ensureBranch !== options.branch) {
|
||||||
argv.branch + '". There is nothing to do here.');
|
console.log('Branch "' + options.branch + '" does not match requested "' +
|
||||||
|
ensureBranch + '". There is nothing to do here.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
85
package.json
85
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@scratch/paper",
|
"name": "@scratch/paper",
|
||||||
"version": "0.11.8",
|
"version": "0.12.7",
|
||||||
"description": "The Swiss Army Knife of Vector Graphics Scripting",
|
"description": "The Swiss Army Knife of Vector Graphics Scripting",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "http://paperjs.org",
|
"homepage": "http://paperjs.org",
|
||||||
|
@ -9,11 +9,10 @@
|
||||||
"url": "https://github.com/paperjs/paper.js"
|
"url": "https://github.com/paperjs/paper.js"
|
||||||
},
|
},
|
||||||
"bugs": "https://github.com/paperjs/paper.js/issues",
|
"bugs": "https://github.com/paperjs/paper.js/issues",
|
||||||
"contributors": ["Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)", "Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"],
|
"contributors": ["Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)", "Jonathan Puckey <jonathan@puckey.studio> (http://studiomoniker.com)"],
|
||||||
"main": "dist/paper-full.js",
|
"main": "dist/paper-full.js",
|
||||||
|
"types": "dist/paper.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"precommit": "gulp jshint --branch develop",
|
|
||||||
"prepush": "gulp test --branch develop",
|
|
||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
"dist": "gulp dist",
|
"dist": "gulp dist",
|
||||||
"zip": "gulp zip",
|
"zip": "gulp zip",
|
||||||
|
@ -24,42 +23,13 @@
|
||||||
},
|
},
|
||||||
"files": ["AUTHORS.md", "CHANGELOG.md", "dist/", "examples/", "LICENSE.txt", "README.md"],
|
"files": ["AUTHORS.md", "CHANGELOG.md", "dist/", "examples/", "LICENSE.txt", "README.md"],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0.0"
|
"node": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"husky": {
|
||||||
"acorn": "~0.5.0",
|
"hooks": {
|
||||||
"canvas-prebuilt": "^2.0.0-alpha.14",
|
"pre-commit": "gulp jshint --ensure-branch develop",
|
||||||
"del": "^2.2.1",
|
"pre-push": "gulp test --ensure-branch develop"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"canvas": false,
|
"canvas": false,
|
||||||
|
@ -69,5 +39,42 @@
|
||||||
"./dist/node/self.js": false,
|
"./dist/node/self.js": false,
|
||||||
"./dist/node/extend.js": false
|
"./dist/node/extend.js": false
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"acorn": "~0.5.0",
|
||||||
|
"canvas": "^2.4.1",
|
||||||
|
"del": "^4.1.0",
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-cached": "^1.1.0",
|
||||||
|
"gulp-git-streamed": "^2.10.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.1.0",
|
||||||
|
"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"]
|
"keywords": ["vector", "graphic", "graphics", "2d", "geometry", "bezier", "curve", "curves", "path", "paths", "canvas", "svg", "paper", "paper.js", "paperjs"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f601084fc319734d0bf47da700d6b6bff95260ba
|
Subproject commit 33c25749460be037bf9afdb80700205c3cfd0942
|
|
@ -1 +1 @@
|
||||||
Subproject commit a07b7d149f02e980dfd837cd595f5000a9d5e052
|
Subproject commit 317d44cfa658b2ec242cbb2f54572e2e1b58a3d2
|
398
src/anim/Tween.js
Normal file
398
src/anim/Tween.js
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
/*
|
||||||
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
|
* http://paperjs.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
|
* http://juerglehni.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Line
|
* @name Line
|
||||||
*
|
|
||||||
* @class The Line object represents..
|
* @class The Line object represents..
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
var Line = Base.extend(/** @lends Line# */{
|
var Line = Base.extend(/** @lends Line# */{
|
||||||
_class: 'Line',
|
_class: 'Line',
|
||||||
|
@ -141,7 +141,7 @@ var Line = Base.extend(/** @lends Line# */{
|
||||||
}
|
}
|
||||||
var cross = v1x * v2y - v1y * v2x;
|
var cross = v1x * v2y - v1y * v2x;
|
||||||
// Avoid divisions by 0, and errors when getting too close to 0
|
// Avoid divisions by 0, and errors when getting too close to 0
|
||||||
if (!Numerical.isZero(cross)) {
|
if (!Numerical.isMachineZero(cross)) {
|
||||||
var dx = p1x - p2x,
|
var dx = p1x - p2x,
|
||||||
dy = p1y - p2y,
|
dy = p1y - p2y,
|
||||||
u1 = (v2x * dy - v2y * dx) / cross,
|
u1 = (v2x * dy - v2y * dx) / cross,
|
||||||
|
@ -175,7 +175,7 @@ var Line = Base.extend(/** @lends Line# */{
|
||||||
v2y = y - py,
|
v2y = y - py,
|
||||||
// ccw = v2.cross(v1);
|
// ccw = v2.cross(v1);
|
||||||
ccw = v2x * vy - v2y * vx;
|
ccw = v2x * vy - v2y * vx;
|
||||||
if (!isInfinite && Numerical.isZero(ccw)) {
|
if (!isInfinite && Numerical.isMachineZero(ccw)) {
|
||||||
// If the point is on the infinite line, check if it's on the
|
// If the point is on the infinite line, check if it's on the
|
||||||
// finite line too: Project v2 onto v1 and determine ccw based
|
// finite line too: Project v2 onto v1 and determine ccw based
|
||||||
// on which side of the finite line the point lies. Calculate
|
// on which side of the finite line the point lies. Calculate
|
||||||
|
@ -196,9 +196,13 @@ var Line = Base.extend(/** @lends Line# */{
|
||||||
vy -= py;
|
vy -= py;
|
||||||
}
|
}
|
||||||
// Based on the error analysis by @iconexperience outlined in #799
|
// Based on the error analysis by @iconexperience outlined in #799
|
||||||
return vx === 0 ? vy > 0 ? x - px : px - x
|
return vx === 0 ? (vy > 0 ? x - px : px - x)
|
||||||
: vy === 0 ? vx < 0 ? y - py : py - y
|
: vy === 0 ? (vx < 0 ? y - py : py - y)
|
||||||
: ((x-px) * vy - (y-py) * vx) / Math.sqrt(vx * vx + vy * vy);
|
: ((x - px) * vy - (y - py) * vx) / (
|
||||||
|
vy > vx
|
||||||
|
? vy * Math.sqrt(1 + (vx * vx) / (vy * vy))
|
||||||
|
: vx * Math.sqrt(1 + (vy * vy) / (vx * vx))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
getDistance: function(px, py, vx, vy, x, y, asVector) {
|
getDistance: function(px, py, vx, vy, x, y, asVector) {
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -71,10 +71,11 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* @param {Matrix} matrix the matrix to copy the values from
|
* @param {Matrix} matrix the matrix to copy the values from
|
||||||
*/
|
*/
|
||||||
initialize: function Matrix(arg, _dontNotify) {
|
initialize: function Matrix(arg, _dontNotify) {
|
||||||
var count = arguments.length,
|
var args = arguments,
|
||||||
|
count = args.length,
|
||||||
ok = true;
|
ok = true;
|
||||||
if (count >= 6) { // >= 6 to pass on optional _dontNotify argument.
|
if (count >= 6) { // >= 6 to pass on optional _dontNotify argument.
|
||||||
this._set.apply(this, arguments);
|
this._set.apply(this, args);
|
||||||
} else if (count === 1 || count === 2) {
|
} else if (count === 1 || count === 2) {
|
||||||
// Support both Matrix and Array arguments through #_set(), and pass
|
// Support both Matrix and Array arguments through #_set(), and pass
|
||||||
// on the optional _dontNotify argument:
|
// on the optional _dontNotify argument:
|
||||||
|
@ -104,6 +105,8 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* also work for calls of `set()`.
|
* also work for calls of `set()`.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
|
* @param {...*} values
|
||||||
|
* @return {Point}
|
||||||
*/
|
*/
|
||||||
set: '#initialize',
|
set: '#initialize',
|
||||||
|
|
||||||
|
@ -183,15 +186,14 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* Attempts to apply the matrix to the content of item that it belongs to,
|
* 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.
|
* 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
|
||||||
* recursively on children
|
* transformations recursively on children
|
||||||
* @return {Boolean} {@true if the matrix was applied}
|
* @return {Boolean} {@true if the matrix was applied}
|
||||||
*/
|
*/
|
||||||
apply: function(recursively, _setApplyMatrix) {
|
apply: function(recursively, _setApplyMatrix) {
|
||||||
var owner = this._owner;
|
var owner = this._owner;
|
||||||
if (owner) {
|
if (owner) {
|
||||||
owner.transform(null, true, Base.pick(recursively, true),
|
owner.transform(null, Base.pick(recursively, true), _setApplyMatrix);
|
||||||
_setApplyMatrix);
|
|
||||||
// If the matrix was successfully applied, it will be reset now.
|
// If the matrix was successfully applied, it will be reset now.
|
||||||
return this.isIdentity();
|
return this.isIdentity();
|
||||||
}
|
}
|
||||||
|
@ -245,8 +247,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* @return {Matrix} this affine transform
|
* @return {Matrix} this affine transform
|
||||||
*/
|
*/
|
||||||
scale: function(/* scale, center */) {
|
scale: function(/* scale, center */) {
|
||||||
var scale = Point.read(arguments),
|
var args = arguments,
|
||||||
center = Point.read(arguments, 0, { readNull: true });
|
scale = Point.read(args),
|
||||||
|
center = Point.read(args, 0, { readNull: true });
|
||||||
if (center)
|
if (center)
|
||||||
this.translate(center);
|
this.translate(center);
|
||||||
this._a *= scale.x;
|
this._a *= scale.x;
|
||||||
|
@ -326,8 +329,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
shear: function(/* shear, center */) {
|
shear: function(/* shear, center */) {
|
||||||
// Do not modify point, center, since that would arguments of which
|
// Do not modify point, center, since that would arguments of which
|
||||||
// we're reading from!
|
// we're reading from!
|
||||||
var shear = Point.read(arguments),
|
var args = arguments,
|
||||||
center = Point.read(arguments, 0, { readNull: true });
|
shear = Point.read(args),
|
||||||
|
center = Point.read(args, 0, { readNull: true });
|
||||||
if (center)
|
if (center)
|
||||||
this.translate(center);
|
this.translate(center);
|
||||||
var a = this._a,
|
var a = this._a,
|
||||||
|
@ -362,8 +366,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* @return {Matrix} this affine transform
|
* @return {Matrix} this affine transform
|
||||||
*/
|
*/
|
||||||
skew: function(/* skew, center */) {
|
skew: function(/* skew, center */) {
|
||||||
var skew = Point.read(arguments),
|
var args = arguments,
|
||||||
center = Point.read(arguments, 0, { readNull: true }),
|
skew = Point.read(args),
|
||||||
|
center = Point.read(args, 0, { readNull: true }),
|
||||||
toRadians = Math.PI / 180,
|
toRadians = Math.PI / 180,
|
||||||
shear = new Point(Math.tan(skew.x * toRadians),
|
shear = new Point(Math.tan(skew.x * toRadians),
|
||||||
Math.tan(skew.y * toRadians));
|
Math.tan(skew.y * toRadians));
|
||||||
|
@ -449,7 +454,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
/**
|
/**
|
||||||
* Returns a new matrix as the result of prepending the specified matrix
|
* Returns a new matrix as the result of prepending the specified matrix
|
||||||
* to this matrix. This is the equivalent of multiplying
|
* 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
|
* @param {Matrix} matrix the matrix to prepend
|
||||||
* @return {Matrix} the newly created matrix
|
* @return {Matrix} the newly created matrix
|
||||||
|
@ -498,15 +503,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use use {@link #append(matrix)} instead.
|
* @deprecated use {@link #append(matrix)} instead.
|
||||||
*/
|
*/
|
||||||
concatenate: '#append',
|
concatenate: '#append',
|
||||||
/**
|
/**
|
||||||
* @deprecated use use {@link #prepend(matrix)} instead.
|
* @deprecated use {@link #prepend(matrix)} instead.
|
||||||
*/
|
*/
|
||||||
preConcatenate: '#prepend',
|
preConcatenate: '#prepend',
|
||||||
/**
|
/**
|
||||||
* @deprecated use use {@link #appended(matrix)} instead.
|
* @deprecated use {@link #appended(matrix)} instead.
|
||||||
*/
|
*/
|
||||||
chain: '#appended',
|
chain: '#appended',
|
||||||
|
|
||||||
|
@ -644,6 +649,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* Inverse transforms a point and returns the result.
|
* Inverse transforms a point and returns the result.
|
||||||
*
|
*
|
||||||
* @param {Point} point the point to be transformed
|
* @param {Point} point the point to be transformed
|
||||||
|
* @return {Point}
|
||||||
*/
|
*/
|
||||||
inverseTransform: function(/* point */) {
|
inverseTransform: function(/* point */) {
|
||||||
return this._inverseTransform(Point.read(arguments));
|
return this._inverseTransform(Point.read(arguments));
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -170,6 +170,8 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* for calls of `set()`.
|
* for calls of `set()`.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
|
* @param {...*} values
|
||||||
|
* @return {Point}
|
||||||
*/
|
*/
|
||||||
set: '#initialize',
|
set: '#initialize',
|
||||||
|
|
||||||
|
@ -431,11 +433,12 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* @return {Number}
|
* @return {Number}
|
||||||
*/
|
*/
|
||||||
getDistance: function(/* point, squared */) {
|
getDistance: function(/* point, squared */) {
|
||||||
var point = Point.read(arguments),
|
var args = arguments,
|
||||||
|
point = Point.read(args),
|
||||||
x = point.x - this.x,
|
x = point.x - this.x,
|
||||||
y = point.y - this.y,
|
y = point.y - this.y,
|
||||||
d = x * x + y * y,
|
d = x * x + y * y,
|
||||||
squared = Base.read(arguments);
|
squared = Base.read(args);
|
||||||
return squared ? d : Math.sqrt(d);
|
return squared ? d : Math.sqrt(d);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -709,8 +712,9 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* @return {Boolean} {@true if it is within the given distance}
|
* @return {Boolean} {@true if it is within the given distance}
|
||||||
*/
|
*/
|
||||||
isClose: function(/* point, tolerance */) {
|
isClose: function(/* point, tolerance */) {
|
||||||
var point = Point.read(arguments),
|
var args = arguments,
|
||||||
tolerance = Base.read(arguments);
|
point = Point.read(args),
|
||||||
|
tolerance = Base.read(args);
|
||||||
return this.getDistance(point) <= tolerance;
|
return this.getDistance(point) <= tolerance;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -768,7 +772,7 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
*
|
*
|
||||||
* @param {Number} quadrant the quadrant to check against
|
* @param {Number} quadrant the quadrant to check against
|
||||||
* @return {Boolean} {@true if either x or y are not a number}
|
* @return {Boolean} {@true if either x or y are not a number}
|
||||||
* @see #getQuadrant()
|
* @see #quadrant
|
||||||
*/
|
*/
|
||||||
isInQuadrant: function(q) {
|
isInQuadrant: function(q) {
|
||||||
// Map quadrant to x & y coordinate pairs and multiply with coordinates,
|
// Map quadrant to x & y coordinate pairs and multiply with coordinates,
|
||||||
|
@ -935,8 +939,9 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* [point1, point2, point3].reduce(Point.min) // {x: 60, y: 5}
|
* [point1, point2, point3].reduce(Point.min) // {x: 60, y: 5}
|
||||||
*/
|
*/
|
||||||
min: function(/* point1, point2 */) {
|
min: function(/* point1, point2 */) {
|
||||||
var point1 = Point.read(arguments),
|
var args = arguments,
|
||||||
point2 = Point.read(arguments);
|
point1 = Point.read(args),
|
||||||
|
point2 = Point.read(args);
|
||||||
return new Point(
|
return new Point(
|
||||||
Math.min(point1.x, point2.x),
|
Math.min(point1.x, point2.x),
|
||||||
Math.min(point1.y, point2.y)
|
Math.min(point1.y, point2.y)
|
||||||
|
@ -966,8 +971,9 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* [point1, point2, point3].reduce(Point.max) // {x: 250, y: 100}
|
* [point1, point2, point3].reduce(Point.max) // {x: 250, y: 100}
|
||||||
*/
|
*/
|
||||||
max: function(/* point1, point2 */) {
|
max: function(/* point1, point2 */) {
|
||||||
var point1 = Point.read(arguments),
|
var args = arguments,
|
||||||
point2 = Point.read(arguments);
|
point1 = Point.read(args),
|
||||||
|
point2 = Point.read(args);
|
||||||
return new Point(
|
return new Point(
|
||||||
Math.max(point1.x, point2.x),
|
Math.max(point1.x, point2.x),
|
||||||
Math.max(point1.y, point2.y)
|
Math.max(point1.y, point2.y)
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -73,10 +73,11 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
* Creates a new rectangle object from the passed rectangle object.
|
* Creates a new rectangle object from the passed rectangle object.
|
||||||
*
|
*
|
||||||
* @name Rectangle#initialize
|
* @name Rectangle#initialize
|
||||||
* @param {Rectangle} rt
|
* @param {Rectangle} rectangle
|
||||||
*/
|
*/
|
||||||
initialize: function Rectangle(arg0, arg1, arg2, arg3) {
|
initialize: function Rectangle(arg0, arg1, arg2, arg3) {
|
||||||
var type = typeof arg0,
|
var args = arguments,
|
||||||
|
type = typeof arg0,
|
||||||
read;
|
read;
|
||||||
if (type === 'number') {
|
if (type === 'number') {
|
||||||
// new Rectangle(x, y, width, height)
|
// new Rectangle(x, y, width, height)
|
||||||
|
@ -86,7 +87,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
// new Rectangle(), new Rectangle(null)
|
// new Rectangle(), new Rectangle(null)
|
||||||
this._set(0, 0, 0, 0);
|
this._set(0, 0, 0, 0);
|
||||||
read = arg0 === null ? 1 : 0;
|
read = arg0 === null ? 1 : 0;
|
||||||
} else if (arguments.length === 1) {
|
} else if (args.length === 1) {
|
||||||
// This can either be an array, or an object literal.
|
// This can either be an array, or an object literal.
|
||||||
if (Array.isArray(arg0)) {
|
if (Array.isArray(arg0)) {
|
||||||
this._set.apply(this, arg0);
|
this._set.apply(this, arg0);
|
||||||
|
@ -98,11 +99,13 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
arg0.width || 0, arg0.height || 0);
|
arg0.width || 0, arg0.height || 0);
|
||||||
read = 1;
|
read = 1;
|
||||||
} else if (arg0.from === undefined && arg0.to === undefined) {
|
} else if (arg0.from === undefined && arg0.to === undefined) {
|
||||||
// Use Base.filter() to support whatever property the rectangle
|
// Use `Base.readSupported()` to read and consume whatever
|
||||||
// can take, but handle from/to separately below.
|
// property the rectangle can receive, but handle `from` / `to`
|
||||||
|
// separately below.
|
||||||
this._set(0, 0, 0, 0);
|
this._set(0, 0, 0, 0);
|
||||||
Base.filter(this, arg0);
|
if (Base.readSupported(args, this)) {
|
||||||
read = 1;
|
read = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (read === undefined) {
|
if (read === undefined) {
|
||||||
|
@ -111,17 +114,16 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
// We're supporting both reading from a normal arguments list and
|
// We're supporting both reading from a normal arguments list and
|
||||||
// covering the Rectangle({ from: , to: }) constructor, through
|
// covering the Rectangle({ from: , to: }) constructor, through
|
||||||
// Point.readNamed().
|
// Point.readNamed().
|
||||||
var frm = Point.readNamed(arguments, 'from'),
|
var frm = Point.readNamed(args, 'from'),
|
||||||
next = Base.peek(arguments),
|
next = Base.peek(args),
|
||||||
x = frm.x,
|
x = frm.x,
|
||||||
y = frm.y,
|
y = frm.y,
|
||||||
width,
|
width,
|
||||||
height;
|
height;
|
||||||
if (next && next.x !== undefined
|
if (next && next.x !== undefined || Base.hasNamed(args, 'to')) {
|
||||||
|| Base.hasNamed(arguments, 'to')) {
|
|
||||||
// new Rectangle(from, to)
|
// new Rectangle(from, to)
|
||||||
// Read above why we can use readNamed() to cover both cases.
|
// Read above why we can use readNamed() to cover both cases.
|
||||||
var to = Point.readNamed(arguments, 'to');
|
var to = Point.readNamed(args, 'to');
|
||||||
width = to.x - x;
|
width = to.x - x;
|
||||||
height = to.y - y;
|
height = to.y - y;
|
||||||
// Check if horizontal or vertical order needs to be reversed.
|
// Check if horizontal or vertical order needs to be reversed.
|
||||||
|
@ -135,19 +137,19 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// new Rectangle(point, size)
|
// new Rectangle(point, size)
|
||||||
var size = Size.read(arguments);
|
var size = Size.read(args);
|
||||||
width = size.width;
|
width = size.width;
|
||||||
height = size.height;
|
height = size.height;
|
||||||
}
|
}
|
||||||
this._set(x, y, width, height);
|
this._set(x, y, width, height);
|
||||||
read = arguments.__index;
|
read = args.__index;
|
||||||
// arguments.__filtered wouldn't survive the function call even if a
|
|
||||||
// previous arguments list was passed through Function#apply().
|
|
||||||
// Return it on the object instead, see Base.read()
|
|
||||||
var filtered = arguments.__filtered;
|
|
||||||
if (filtered)
|
|
||||||
this.__filtered = filtered;
|
|
||||||
}
|
}
|
||||||
|
// arguments.__filtered wouldn't survive the function call even if a
|
||||||
|
// previous arguments list was passed through Function#apply().
|
||||||
|
// Return it on the object instead, see Base.read()
|
||||||
|
var filtered = args.__filtered;
|
||||||
|
if (filtered)
|
||||||
|
this.__filtered = filtered;
|
||||||
if (this.__read)
|
if (this.__read)
|
||||||
this.__read = read;
|
this.__read = read;
|
||||||
return this;
|
return this;
|
||||||
|
@ -159,6 +161,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
* constructors also work for calls of `set()`.
|
* constructors also work for calls of `set()`.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
|
* @param {...*} values
|
||||||
|
* @return {Rectangle}
|
||||||
*/
|
*/
|
||||||
set: '#initialize',
|
set: '#initialize',
|
||||||
|
|
||||||
|
@ -201,6 +205,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of the rectangle.
|
* Returns a copy of the rectangle.
|
||||||
|
* @return {Rectangle}
|
||||||
*/
|
*/
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new Rectangle(this.x, this.y, this.width, this.height);
|
return new Rectangle(this.x, this.y, this.width, this.height);
|
||||||
|
@ -772,6 +777,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
* Rectangle#contains(point)} returns `false` for that point.
|
* Rectangle#contains(point)} returns `false` for that point.
|
||||||
*
|
*
|
||||||
* @param {Point} point
|
* @param {Point} point
|
||||||
|
* @return {Rectangle} the smallest rectangle that contains both the
|
||||||
|
* original rectangle and the specified point
|
||||||
*/
|
*/
|
||||||
include: function(/* point */) {
|
include: function(/* point */) {
|
||||||
var point = Point.read(arguments);
|
var point = Point.read(arguments);
|
||||||
|
@ -783,17 +790,18 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands the rectangle by the specified amount in horizontal and
|
* Returns a new rectangle expanded by the specified amount in horizontal
|
||||||
* vertical directions.
|
* and vertical directions.
|
||||||
*
|
*
|
||||||
* @name Rectangle#expand
|
* @name Rectangle#expand
|
||||||
* @function
|
* @function
|
||||||
* @param {Number|Size|Point} amount the amount to expand the rectangle in
|
* @param {Number|Size|Point} amount the amount to expand the rectangle in
|
||||||
* both directions
|
* both directions
|
||||||
|
* @return {Rectangle} the expanded rectangle
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Expands the rectangle by the specified amounts in horizontal and
|
* Returns a new rectangle expanded by the specified amounts in horizontal
|
||||||
* vertical directions.
|
* and vertical directions.
|
||||||
*
|
*
|
||||||
* @name Rectangle#expand
|
* @name Rectangle#expand
|
||||||
* @function
|
* @function
|
||||||
|
@ -801,6 +809,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
* direction
|
* direction
|
||||||
* @param {Number} ver the amount to expand the rectangle in vertical
|
* @param {Number} ver the amount to expand the rectangle in vertical
|
||||||
* direction
|
* direction
|
||||||
|
* @return {Rectangle} the expanded rectangle
|
||||||
*/
|
*/
|
||||||
expand: function(/* amount */) {
|
expand: function(/* amount */) {
|
||||||
var amount = Size.read(arguments),
|
var amount = Size.read(arguments),
|
||||||
|
@ -811,21 +820,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
|
* @name Rectangle#scale
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} amount
|
* @param {Number} amount
|
||||||
|
* @return {Rectangle} the scaled rectangle
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Scales the rectangle in horizontal direction by the specified `hor`
|
* Returns a new rectangle scaled in horizontal direction by the specified
|
||||||
* amount and in vertical direction by the specified `ver` amount from its
|
* `hor` amount and in vertical direction by the specified `ver` amount
|
||||||
* center.
|
* from its center.
|
||||||
*
|
*
|
||||||
* @name Rectangle#scale
|
* @name Rectangle#scale
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} hor
|
* @param {Number} hor
|
||||||
* @param {Number} ver
|
* @param {Number} ver
|
||||||
|
* @return {Rectangle} the scaled rectangle
|
||||||
*/
|
*/
|
||||||
scale: function(hor, ver) {
|
scale: function(hor, ver) {
|
||||||
return this.expand(this.width * hor - this.width,
|
return this.expand(this.width * hor - this.width,
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -130,6 +130,8 @@ var Size = Base.extend(/** @lends Size# */{
|
||||||
* for calls of `set()`.
|
* for calls of `set()`.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
|
* @param {...*} values
|
||||||
|
* @return {Size}
|
||||||
*/
|
*/
|
||||||
set: '#initialize',
|
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
|
* Checks whether the width and height of the size are equal to those of the
|
||||||
* supplied size.
|
* supplied size.
|
||||||
*
|
*
|
||||||
* @param {Size}
|
* @param {Size} size the size to compare to
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -176,6 +178,7 @@ var Size = Base.extend(/** @lends Size# */{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of the size.
|
* Returns a copy of the size.
|
||||||
|
* @return {Size}
|
||||||
*/
|
*/
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new Size(this.width, this.height);
|
return new Size(this.width, this.height);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -269,11 +269,11 @@ statics: /** @lends Base */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows using of Base.read() mechanism in combination with reading named
|
* Allows using of `Base.read()` mechanism in combination with reading named
|
||||||
* arguments form a passed property object literal. Calling Base.readNamed()
|
* arguments form a passed property object literal. Calling
|
||||||
* can read both from such named properties and normal unnamed arguments
|
* `Base.readNamed()` can read both from such named properties and normal
|
||||||
* through Base.read(). In use for example for the various
|
* unnamed arguments through `Base.read()`. In use for example for
|
||||||
* Path.Constructors.
|
* the various `Path` constructors in `Path.Constructors.js`.
|
||||||
*
|
*
|
||||||
* @param {Array} list the list to read from, either an arguments object or
|
* @param {Array} list the list to read from, either an arguments object or
|
||||||
* a normal array
|
* a normal array
|
||||||
|
@ -287,24 +287,68 @@ statics: /** @lends Base */{
|
||||||
*/
|
*/
|
||||||
readNamed: function(list, name, start, options, amount) {
|
readNamed: function(list, name, start, options, amount) {
|
||||||
var value = this.getNamed(list, name),
|
var value = this.getNamed(list, name),
|
||||||
hasObject = value !== undefined;
|
hasValue = value !== undefined;
|
||||||
if (hasObject) {
|
if (hasValue) {
|
||||||
// Create a _filtered object that inherits from list[0], and
|
// Create a _filtered object that inherits from `source`, and
|
||||||
// override all fields that were already read with undefined.
|
// override all fields that were already read with undefined.
|
||||||
var filtered = list.__filtered;
|
var filtered = list.__filtered;
|
||||||
if (!filtered) {
|
if (!filtered) {
|
||||||
filtered = list.__filtered = Base.create(list[0]);
|
var source = this.getSource(list);
|
||||||
// Point _unfiltered to the original so Base#_set() can
|
filtered = list.__filtered = Base.create(source);
|
||||||
// execute hasOwnProperty on it.
|
// Point __unfiltered to the original, so `Base.filter()` can
|
||||||
filtered.__unfiltered = list[0];
|
// use it to get all keys to iterate over.
|
||||||
|
filtered.__unfiltered = source;
|
||||||
}
|
}
|
||||||
// delete wouldn't work since the masked parent's value would
|
// delete wouldn't work since the masked parent's value would
|
||||||
// shine through.
|
// shine through.
|
||||||
filtered[name] = undefined;
|
filtered[name] = undefined;
|
||||||
}
|
}
|
||||||
var l = hasObject ? [value] : list,
|
return this.read(hasValue ? [value] : list, start, options, amount);
|
||||||
res = this.read(l, start, options, amount);
|
},
|
||||||
return res;
|
|
||||||
|
/**
|
||||||
|
* If `list[0]` is a source object, calls `Base.readNamed()` for each key in
|
||||||
|
* it that is supported on `dest`, consuming these values.
|
||||||
|
*
|
||||||
|
* @param {Array} list the list to read from, either an arguments object or
|
||||||
|
* a normal array
|
||||||
|
* @param {Object} dest the object on which to set the supported properties
|
||||||
|
* @return {Boolean} {@true if any property was read from the source object}
|
||||||
|
*/
|
||||||
|
readSupported: function(list, dest) {
|
||||||
|
var source = this.getSource(list),
|
||||||
|
that = this,
|
||||||
|
read = false;
|
||||||
|
if (source) {
|
||||||
|
// If `source` is a filtered object, we get the keys from the the
|
||||||
|
// original object (it's parent / prototype). See _filtered
|
||||||
|
// inheritance trick in the argument reading code.
|
||||||
|
Object.keys(source).forEach(function(key) {
|
||||||
|
if (key in dest) {
|
||||||
|
var value = that.readNamed(list, key);
|
||||||
|
// Due to the _filtered inheritance trick, undefined is used
|
||||||
|
// to mask already consumed named arguments.
|
||||||
|
if (value !== undefined) {
|
||||||
|
dest[key] = value;
|
||||||
|
}
|
||||||
|
read = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the arguments object if the list provides one at `list[0]`
|
||||||
|
*/
|
||||||
|
getSource: function(list) {
|
||||||
|
var source = list.__source;
|
||||||
|
if (source === undefined) {
|
||||||
|
var arg = list.length === 1 && list[0];
|
||||||
|
source = list.__source = arg && Base.isPlainObject(arg)
|
||||||
|
? arg : null;
|
||||||
|
}
|
||||||
|
return source;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,12 +358,11 @@ statics: /** @lends Base */{
|
||||||
* provided, it returns the whole arguments object
|
* provided, it returns the whole arguments object
|
||||||
*/
|
*/
|
||||||
getNamed: function(list, name) {
|
getNamed: function(list, name) {
|
||||||
var arg = list[0];
|
var source = this.getSource(list);
|
||||||
if (list._hasObject === undefined)
|
if (source) {
|
||||||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
|
||||||
if (list._hasObject)
|
|
||||||
// Return the whole arguments object if no name is provided.
|
// Return the whole arguments object if no name is provided.
|
||||||
return name ? arg[name] : list.__filtered || arg;
|
return name ? source[name] : list.__filtered || source;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -558,8 +601,16 @@ statics: /** @lends Base */{
|
||||||
if (args.length === 1 && obj instanceof Item
|
if (args.length === 1 && obj instanceof Item
|
||||||
&& (useTarget || !(obj instanceof Layer))) {
|
&& (useTarget || !(obj instanceof Layer))) {
|
||||||
var arg = args[0];
|
var arg = args[0];
|
||||||
if (Base.isPlainObject(arg))
|
if (Base.isPlainObject(arg)) {
|
||||||
arg.insert = false;
|
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()
|
// When reusing an object, initialize it through #set()
|
||||||
// instead of the constructor function:
|
// instead of the constructor function:
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -68,9 +68,9 @@ var Emitter = {
|
||||||
},
|
},
|
||||||
|
|
||||||
once: function(type, func) {
|
once: function(type, func) {
|
||||||
return this.on(type, function() {
|
return this.on(type, function handler() {
|
||||||
func.apply(this, arguments);
|
func.apply(this, arguments);
|
||||||
this.off(type, func);
|
this.off(type, handler);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
// here: { chrome: true, webkit: false }, Mozilla missing is the
|
||||||
// only difference to jQuery.browser
|
// only difference to jQuery.browser
|
||||||
user.replace(
|
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) {
|
function(match, n, v1, v2, rv) {
|
||||||
// Do not set additional browsers once chrome is detected.
|
// Do not set additional browsers once chrome is detected.
|
||||||
if (!agent.chrome) {
|
if (!agent.chrome) {
|
||||||
|
@ -95,7 +95,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
/^(node|trident)$/.test(n) ? rv : v1;
|
/^(node|trident)$/.test(n) ? rv : v1;
|
||||||
agent.version = v;
|
agent.version = v;
|
||||||
agent.versionNumber = parseFloat(v);
|
agent.versionNumber = parseFloat(v);
|
||||||
n = n === 'trident' ? 'msie' : n;
|
n = { trident: 'msie', jsdom: 'node' }[n] || n;
|
||||||
agent.name = n;
|
agent.name = n;
|
||||||
agent[n] = true;
|
agent[n] = true;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
* The version of Paper.js, as a string.
|
* The version of Paper.js, as a string.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type String
|
||||||
|
* @readonly
|
||||||
*/
|
*/
|
||||||
version: /*#=*/__options.version,
|
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.
|
* mapping, in case the code that's passed in has already been mingled.
|
||||||
*
|
*
|
||||||
* @param {String} code the PaperScript code
|
* @param {String} code the PaperScript code
|
||||||
* @param {Object} [option] the compilation options
|
* @param {Object} [options] the compilation options
|
||||||
*/
|
*/
|
||||||
execute: function(code, options) {
|
execute: function(code, options) {
|
||||||
/*#*/ if (__options.paperScript) {
|
/*#*/ if (__options.paperScript) {
|
||||||
|
@ -310,6 +311,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
* Retrieves a PaperScope object with the given scope id.
|
* Retrieves a PaperScope object with the given scope id.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
|
* @return {PaperScope}
|
||||||
*/
|
*/
|
||||||
get: function(id) {
|
get: function(id) {
|
||||||
return this._scopes[id] || null;
|
return this._scopes[id] || null;
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
* mapping, in case the code that's passed in has already been mingled.
|
||||||
*
|
*
|
||||||
* @param {String} code the PaperScript code
|
* @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
|
* @return {Object} an object holding the compiled PaperScript translated
|
||||||
* into JavaScript code along with source-maps and other information.
|
* into JavaScript code along with source-maps and other information.
|
||||||
*/
|
*/
|
||||||
|
@ -177,7 +177,7 @@ Base.exports.PaperScript = function() {
|
||||||
var start = getOffset(node.range[0]),
|
var start = getOffset(node.range[0]),
|
||||||
end = getOffset(node.range[1]),
|
end = getOffset(node.range[1]),
|
||||||
insert = 0;
|
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--) {
|
for (var i = insertions.length - 1; i >= 0; i--) {
|
||||||
if (start > insertions[i][0]) {
|
if (start > insertions[i][0]) {
|
||||||
insert = i + 1;
|
insert = i + 1;
|
||||||
|
@ -188,27 +188,8 @@ Base.exports.PaperScript = function() {
|
||||||
code = code.substring(0, start) + str + code.substring(end);
|
code = code.substring(0, start) + str + code.substring(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively walks the AST and replaces the code of certain nodes
|
function handleOverloading(node, parent) {
|
||||||
function walkAST(node, parent) {
|
switch (node.type) {
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
// The easiest way to walk through the whole AST is to simply loop
|
|
||||||
// over each property of the node and filter out fields we don't
|
|
||||||
// need to consider...
|
|
||||||
for (var key in node) {
|
|
||||||
if (key === 'range' || key === 'loc')
|
|
||||||
continue;
|
|
||||||
var value = node[key];
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
for (var i = 0, l = value.length; i < l; i++)
|
|
||||||
walkAST(value[i], node);
|
|
||||||
} else if (value && typeof value === 'object') {
|
|
||||||
// We cannot use Base.isPlainObject() for these since
|
|
||||||
// Acorn.js uses its own internal prototypes now.
|
|
||||||
walkAST(value, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (node.type) {
|
|
||||||
case 'UnaryExpression': // -a
|
case 'UnaryExpression': // -a
|
||||||
if (node.operator in unaryOperators
|
if (node.operator in unaryOperators
|
||||||
&& node.argument.type !== 'Literal') {
|
&& node.argument.type !== 'Literal') {
|
||||||
|
@ -256,12 +237,19 @@ Base.exports.PaperScript = function() {
|
||||||
exp = '__$__(' + arg + ', "' + node.operator[0]
|
exp = '__$__(' + arg + ', "' + node.operator[0]
|
||||||
+ '", 1)',
|
+ '", 1)',
|
||||||
str = arg + ' = ' + exp;
|
str = arg + ' = ' + exp;
|
||||||
// If this is not a prefixed update expression
|
if (node.prefix) {
|
||||||
// (++a, --a), assign the old value before updating it.
|
// A prefixed update expression (++a / --a),
|
||||||
if (!node.prefix
|
// wrap expression in paranthesis. See #1611
|
||||||
&& (parentType === 'AssignmentExpression'
|
str = '(' + str + ')';
|
||||||
|| parentType === 'VariableDeclarator')) {
|
} else if (
|
||||||
// Handle special issue #691 where the old value is
|
// 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
|
// assigned to itself, and the expression is just
|
||||||
// executed after, e.g.: `var x = ***; x = x++;`
|
// executed after, e.g.: `var x = ***; x = x++;`
|
||||||
if (getCode(parent.left || parent.id) === arg)
|
if (getCode(parent.left || parent.id) === arg)
|
||||||
|
@ -284,6 +272,11 @@ Base.exports.PaperScript = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleExports(node) {
|
||||||
|
switch (node.type) {
|
||||||
case 'ExportDefaultDeclaration':
|
case 'ExportDefaultDeclaration':
|
||||||
// Convert `export default` to `module.exports = ` statements:
|
// Convert `export default` to `module.exports = ` statements:
|
||||||
replaceCode({
|
replaceCode({
|
||||||
|
@ -321,9 +314,38 @@ Base.exports.PaperScript = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursively walks the AST and replaces the code of certain nodes
|
||||||
|
function walkAST(node, parent, paperFeatures) {
|
||||||
|
if (node) {
|
||||||
|
// The easiest way to walk through the whole AST is to simply
|
||||||
|
// loop over each property of the node and filter out fields we
|
||||||
|
// don't need to consider...
|
||||||
|
for (var key in node) {
|
||||||
|
if (key !== 'range' && key !== 'loc') {
|
||||||
|
var value = node[key];
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (var i = 0, l = value.length; i < l; i++) {
|
||||||
|
walkAST(value[i], node, paperFeatures);
|
||||||
|
}
|
||||||
|
} else if (value && typeof value === 'object') {
|
||||||
|
// Don't use Base.isPlainObject() for these since
|
||||||
|
// Acorn.js uses its own internal prototypes now.
|
||||||
|
walkAST(value, node, paperFeatures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paperFeatures.operatorOverloading !== false) {
|
||||||
|
handleOverloading(node, parent);
|
||||||
|
}
|
||||||
|
if (paperFeatures.moduleExports !== false) {
|
||||||
|
handleExports(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Source-map support:
|
// Source-map support:
|
||||||
// Encodes a Variable Length Quantity as a Base64 string.
|
// 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) {
|
function encodeVLQ(value) {
|
||||||
var res = '',
|
var res = '',
|
||||||
base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
|
@ -339,15 +361,16 @@ Base.exports.PaperScript = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = options.url || '',
|
var url = options.url || '',
|
||||||
agent = paper.agent,
|
|
||||||
version = agent.versionNumber,
|
|
||||||
offsetCode = false,
|
|
||||||
sourceMaps = options.sourceMaps,
|
sourceMaps = options.sourceMaps,
|
||||||
|
paperFeatures = options.paperFeatures || {},
|
||||||
// Include the original code in the sourceMap if there is no linked
|
// Include the original code in the sourceMap if there is no linked
|
||||||
// source file so the debugger can still display it correctly.
|
// source file so the debugger can still display it correctly.
|
||||||
source = options.source || code,
|
source = options.source || code,
|
||||||
lineBreaks = /\r\n|\n|\r/mg,
|
|
||||||
offset = options.offset || 0,
|
offset = options.offset || 0,
|
||||||
|
agent = paper.agent,
|
||||||
|
version = agent.versionNumber,
|
||||||
|
offsetCode = false,
|
||||||
|
lineBreaks = /\r\n|\n|\r/mg,
|
||||||
map;
|
map;
|
||||||
// TODO: Verify these browser versions for source map support, and check
|
// TODO: Verify these browser versions for source map support, and check
|
||||||
// other browsers.
|
// other browsers.
|
||||||
|
@ -397,12 +420,17 @@ Base.exports.PaperScript = function() {
|
||||||
sourcesContent: [source]
|
sourcesContent: [source]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Now do the parsing magic
|
if (
|
||||||
walkAST(parse(code, {
|
paperFeatures.operatorOverloading !== false ||
|
||||||
ranges: true,
|
paperFeatures.moduleExports !== false
|
||||||
preserveParens: true,
|
) {
|
||||||
sourceType: 'module'
|
// Now do the parsing magic
|
||||||
}));
|
walkAST(parse(code, {
|
||||||
|
ranges: true,
|
||||||
|
preserveParens: true,
|
||||||
|
sourceType: 'module'
|
||||||
|
}), null, paperFeatures);
|
||||||
|
}
|
||||||
if (map) {
|
if (map) {
|
||||||
if (offsetCode) {
|
if (offsetCode) {
|
||||||
// Adjust the line offset of the resulting code if required.
|
// Adjust the line offset of the resulting code if required.
|
||||||
|
@ -441,8 +469,8 @@ Base.exports.PaperScript = function() {
|
||||||
*
|
*
|
||||||
* @param {String} code the PaperScript code
|
* @param {String} code the PaperScript code
|
||||||
* @param {PaperScope} scope the scope for which the code is executed
|
* @param {PaperScope} scope the scope for which the code is executed
|
||||||
* @param {Object} [option] the compilation options
|
* @param {Object} [options] the compilation options
|
||||||
* @return the exports defined in the executed code
|
* @return {Object} the exports defined in the executed code
|
||||||
*/
|
*/
|
||||||
function execute(code, scope, options) {
|
function execute(code, scope, options) {
|
||||||
// Set currently active scope.
|
// Set currently active scope.
|
||||||
|
@ -484,7 +512,7 @@ Base.exports.PaperScript = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expose({ __$__: __$__, $__: $__, paper: scope, view: view, tool: tool },
|
expose({ __$__: __$__, $__: $__, paper: scope, tool: tool },
|
||||||
true);
|
true);
|
||||||
expose(scope);
|
expose(scope);
|
||||||
// Add a fake `module.exports` object so PaperScripts can export things.
|
// Add a fake `module.exports` object so PaperScripts can export things.
|
||||||
|
@ -657,7 +685,9 @@ Base.exports.PaperScript = function() {
|
||||||
compile: compile,
|
compile: compile,
|
||||||
execute: execute,
|
execute: execute,
|
||||||
load: load,
|
load: load,
|
||||||
parse: parse
|
parse: parse,
|
||||||
|
calculateBinary: __$__,
|
||||||
|
calculateUnary: $__
|
||||||
};
|
};
|
||||||
// Pass on `this` as the binding object, so we can reference Acorn both in
|
// Pass on `this` as the binding object, so we can reference Acorn both in
|
||||||
// development and in the built library.
|
// development and in the built library.
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
*
|
*
|
||||||
* The project for which the PaperScript is executed.
|
* 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
|
* reflect the currently active project. For this, use
|
||||||
* {@link PaperScope#project} instead.
|
* {@link PaperScope#project} instead.
|
||||||
*
|
*
|
||||||
|
@ -57,19 +57,20 @@
|
||||||
/**
|
/**
|
||||||
* The reference to the project's view.
|
* 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
|
* reflect the view of the currently active project. For this, use
|
||||||
* {@link PaperScope#view} instead.
|
* {@link PaperScope#view} instead.
|
||||||
*
|
*
|
||||||
* @name view
|
* @name view
|
||||||
* @type View
|
* @type View
|
||||||
|
* @readonly
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reference to the tool object which is automatically created when global
|
* The reference to the tool object which is automatically created when global
|
||||||
* tool event handlers are defined.
|
* 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}
|
* reflect the currently active tool. For this, use {@link PaperScope#tool}
|
||||||
* instead.
|
* instead.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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) {
|
_getBounds: function _getBounds(matrix, options) {
|
||||||
var clipItem = this._getClipItem();
|
var clipItem = this._getClipItem();
|
||||||
return clipItem
|
return clipItem
|
||||||
? clipItem._getCachedBounds(
|
? clipItem._getCachedBounds(clipItem._matrix.prepended(matrix),
|
||||||
matrix && matrix.appended(clipItem._matrix),
|
|
||||||
Base.set({}, options, { stroke: false }))
|
Base.set({}, options, { stroke: false }))
|
||||||
: _getBounds.base.call(this, matrix, options);
|
: _getBounds.base.call(this, matrix, options);
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -75,7 +75,7 @@ var HitResult = Base.extend(/** @lends HitResult# */{
|
||||||
*
|
*
|
||||||
* @name HitResult#color
|
* @name HitResult#color
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,7 +105,7 @@ var HitResult = Base.extend(/** @lends HitResult# */{
|
||||||
*/
|
*/
|
||||||
getOptions: function(args) {
|
getOptions: function(args) {
|
||||||
var options = args && Base.read(args);
|
var options = args && Base.read(args);
|
||||||
return Base.set({
|
return new Base({
|
||||||
// Type of item, for instanceof check: Group, Layer, Path,
|
// Type of item, for instanceof check: Group, Layer, Path,
|
||||||
// CompoundPath, Shape, Raster, SymbolItem, ...
|
// CompoundPath, Shape, Raster, SymbolItem, ...
|
||||||
type: null,
|
type: null,
|
||||||
|
|
319
src/item/Item.js
319
src/item/Item.js
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
* 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
|
* paths and compound paths, and only if the item is already contained
|
||||||
* already contained within a clipping group.
|
* within a clipping group.
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
|
@ -1075,7 +1075,9 @@ new function() { // Injection scope for various item event handlers
|
||||||
options = options || {};
|
options = options || {};
|
||||||
for (var i = 0, l = items.length; i < l; i++) {
|
for (var i = 0, l = items.length; i < l; i++) {
|
||||||
var item = items[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
|
// Pass true for noInternal, since even when getting
|
||||||
// internal bounds for this item, we need to apply the
|
// internal bounds for this item, we need to apply the
|
||||||
// matrices to its children.
|
// matrices to its children.
|
||||||
|
@ -1120,6 +1122,17 @@ new function() { // Injection scope for various item event handlers
|
||||||
* @type Rectangle
|
* @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 rough bounding rectangle of the item that is sure to include all of
|
||||||
* the drawing, including stroke width.
|
* 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
|
* @param {Point} point the point to check for
|
||||||
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
contains: function(/* point */) {
|
contains: function(/* point */) {
|
||||||
// See CompoundPath#_contains() for the reason for !!
|
// See CompoundPath#_contains() for the reason for !!
|
||||||
return !!this._contains(
|
var matrix = this._matrix;
|
||||||
this._matrix._inverseTransform(Point.read(arguments)));
|
return (
|
||||||
|
matrix.isInvertible() &&
|
||||||
|
!!this._contains(matrix._inverseTransform(Point.read(arguments)))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
_contains: function(point) {
|
_contains: function(point) {
|
||||||
|
@ -1866,16 +1883,18 @@ new function() { // Injection scope for various item event handlers
|
||||||
},
|
},
|
||||||
new function() { // Injection scope for hit-test functions shared with project
|
new function() { // Injection scope for hit-test functions shared with project
|
||||||
function hitTest(/* point, options */) {
|
function hitTest(/* point, options */) {
|
||||||
|
var args = arguments;
|
||||||
return this._hitTest(
|
return this._hitTest(
|
||||||
Point.read(arguments),
|
Point.read(args),
|
||||||
HitResult.getOptions(arguments));
|
HitResult.getOptions(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
function hitTestAll(/* point, options */) {
|
function hitTestAll(/* point, options */) {
|
||||||
var point = Point.read(arguments),
|
var args = arguments,
|
||||||
options = HitResult.getOptions(arguments),
|
point = Point.read(args),
|
||||||
|
options = HitResult.getOptions(args),
|
||||||
all = [];
|
all = [];
|
||||||
this._hitTest(point, Base.set({ all: all }, options));
|
this._hitTest(point, new Base({ all: all }, options));
|
||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2353,6 +2372,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* items can have children.
|
* items can have children.
|
||||||
*
|
*
|
||||||
* @param {String} json the JSON data to import from
|
* @param {String} json the JSON data to import from
|
||||||
|
* @return {Item}
|
||||||
*/
|
*/
|
||||||
importJSON: function(json) {
|
importJSON: function(json) {
|
||||||
// Try importing into `this`. If another item is returned, try adding
|
// Try importing into `this`. If another item is returned, try adding
|
||||||
|
@ -2388,7 +2408,8 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* kept as a link to their external URL.
|
* kept as a link to their external URL.
|
||||||
*
|
*
|
||||||
* @param {Object} [options] the export options
|
* @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 +2793,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
|
* Replaces this item with the provided new item which will takes its place
|
||||||
* in the project hierarchy instead.
|
* in the project hierarchy instead.
|
||||||
*
|
*
|
||||||
|
* @param {Item} item the item that will replace this item
|
||||||
* @return {Boolean} {@true if the item was replaced}
|
* @return {Boolean} {@true if the item was replaced}
|
||||||
*/
|
*/
|
||||||
replaceWith: function(item) {
|
replaceWith: function(item) {
|
||||||
|
@ -2840,11 +2862,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}
|
* no children, a {@link TextItem} with no text content and a {@link Path}
|
||||||
* with no segments all are considered empty.
|
* with no segments all are considered empty.
|
||||||
*
|
*
|
||||||
* @return Boolean
|
* @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;
|
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;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2907,7 +2941,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* defined in such a way, e.g. if one is a descendant of the other.
|
* defined in such a way, e.g. if one is a descendant of the other.
|
||||||
*/
|
*/
|
||||||
_getOrder: function(item) {
|
_getOrder: function(item) {
|
||||||
// Private method that produces a list of anchestors, starting with the
|
// Private method that produces a list of ancestors, starting with the
|
||||||
// root and ending with the actual element as the last entry.
|
// root and ending with the actual element as the last entry.
|
||||||
function getList(item) {
|
function getList(item) {
|
||||||
var list = [];
|
var list = [];
|
||||||
|
@ -3057,7 +3091,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#strokeColor
|
* @name Item#strokeColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Setting the stroke color of a path:
|
* // Setting the stroke color of a path:
|
||||||
|
@ -3194,7 +3228,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#dashArray
|
* @name Item#dashArray
|
||||||
* @property
|
* @property
|
||||||
* @type Array
|
* @type Number[]
|
||||||
* @default []
|
* @default []
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -3219,7 +3253,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#fillColor
|
* @name Item#fillColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Setting the fill color of a path to red:
|
* // Setting the fill color of a path to red:
|
||||||
|
@ -3253,7 +3287,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @property
|
* @property
|
||||||
* @name Item#shadowColor
|
* @name Item#shadowColor
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Creating a circle with a black shadow:
|
* // Creating a circle with a black shadow:
|
||||||
|
@ -3299,13 +3333,14 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#selectedColor
|
* @name Item#selectedColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*/
|
*/
|
||||||
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
|
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
|
||||||
var rotate = key === 'rotate';
|
var rotate = key === 'rotate';
|
||||||
this[key] = function(/* value, center */) {
|
this[key] = function(/* value, center */) {
|
||||||
var value = (rotate ? Base : Point).read(arguments),
|
var args = arguments,
|
||||||
center = Point.read(arguments, 0, { readNull: true });
|
value = (rotate ? Base : Point).read(args),
|
||||||
|
center = Point.read(args, 0, { readNull: true });
|
||||||
return this.transform(new Matrix()[key](value,
|
return this.transform(new Matrix()[key](value,
|
||||||
center || this.getPosition(true)));
|
center || this.getPosition(true)));
|
||||||
};
|
};
|
||||||
|
@ -3438,7 +3473,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#shear
|
* @name Item#shear
|
||||||
* @function
|
* @function
|
||||||
* @param {Point} shear the horziontal and vertical shear factors as a point
|
* @param {Point} shear the horizontal and vertical shear factors as a point
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
* @see Matrix#shear(shear[, center])
|
* @see Matrix#shear(shear[, center])
|
||||||
*/
|
*/
|
||||||
|
@ -3460,7 +3495,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#skew
|
* @name Item#skew
|
||||||
* @function
|
* @function
|
||||||
* @param {Point} skew the horziontal and vertical skew angles in degrees
|
* @param {Point} skew the horizontal and vertical skew angles in degrees
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
* @see Matrix#shear(skew[, center])
|
* @see Matrix#shear(skew[, center])
|
||||||
*/
|
*/
|
||||||
|
@ -3485,19 +3520,22 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
// @param {String[]} flags array of any of the following: 'objects',
|
// @param {String[]} flags array of any of the following: 'objects',
|
||||||
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||||
// 'lines'. Default: ['objects', 'children']
|
// 'lines'. Default: ['objects', 'children']
|
||||||
transform: function(matrix, _applyMatrix, _applyRecursively,
|
transform: function(matrix, _applyRecursively, _setApplyMatrix) {
|
||||||
_setApplyMatrix) {
|
|
||||||
var _matrix = this._matrix,
|
var _matrix = this._matrix,
|
||||||
// If no matrix is provided, or the matrix is the identity, we might
|
|
||||||
// still have some work to do in case _applyMatrix is true
|
|
||||||
transformMatrix = matrix && !matrix.isIdentity(),
|
transformMatrix = matrix && !matrix.isIdentity(),
|
||||||
applyMatrix = (_applyMatrix || this._applyMatrix)
|
// If no matrix is provided, or the matrix is the identity, we might
|
||||||
|
// still have some work to do: _setApplyMatrix or _applyRecursively.
|
||||||
|
applyMatrix = (
|
||||||
|
_setApplyMatrix && this._canApplyMatrix ||
|
||||||
|
this._applyMatrix && (
|
||||||
// Don't apply _matrix if the result of concatenating with
|
// Don't apply _matrix if the result of concatenating with
|
||||||
// matrix would be identity.
|
// matrix would be identity.
|
||||||
&& ((!_matrix.isIdentity() || transformMatrix)
|
transformMatrix || !_matrix.isIdentity() ||
|
||||||
// Even if it's an identity matrix, we still need to
|
// Even if it's an identity matrix, we may still need to
|
||||||
// recursively apply the matrix to children.
|
// recursively apply the matrix to children.
|
||||||
|| _applyMatrix && _applyRecursively && this._children);
|
_applyRecursively && this._children
|
||||||
|
)
|
||||||
|
);
|
||||||
// Bail out if there is nothing to do.
|
// Bail out if there is nothing to do.
|
||||||
if (!transformMatrix && !applyMatrix)
|
if (!transformMatrix && !applyMatrix)
|
||||||
return this;
|
return this;
|
||||||
|
@ -3529,8 +3567,9 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
// internal _matrix transformations to the item's content.
|
// internal _matrix transformations to the item's content.
|
||||||
// Application is not possible on Raster, PointText, SymbolItem, since
|
// Application is not possible on Raster, PointText, SymbolItem, since
|
||||||
// the matrix is where the actual transformation state is stored.
|
// the matrix is where the actual transformation state is stored.
|
||||||
if (applyMatrix && (applyMatrix = this._transformContent(_matrix,
|
|
||||||
_applyRecursively, _setApplyMatrix))) {
|
if (applyMatrix && (applyMatrix = this._transformContent(
|
||||||
|
_matrix, _applyRecursively, _setApplyMatrix))) {
|
||||||
// Pivot is provided in the parent's coordinate system, so transform
|
// Pivot is provided in the parent's coordinate system, so transform
|
||||||
// it along too.
|
// it along too.
|
||||||
var pivot = this._pivot;
|
var pivot = this._pivot;
|
||||||
|
@ -3594,9 +3633,9 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
_transformContent: function(matrix, applyRecursively, setApplyMatrix) {
|
_transformContent: function(matrix, applyRecursively, setApplyMatrix) {
|
||||||
var children = this._children;
|
var children = this._children;
|
||||||
if (children) {
|
if (children) {
|
||||||
for (var i = 0, l = children.length; i < l; i++)
|
for (var i = 0, l = children.length; i < l; i++) {
|
||||||
children[i].transform(matrix, true, applyRecursively,
|
children[i].transform(matrix, applyRecursively, setApplyMatrix);
|
||||||
setApplyMatrix);
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -3745,7 +3784,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onFrame
|
* @name Item#onFrame
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onFrame
|
* @see View#onFrame
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -3772,7 +3811,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseDown
|
* @name Item#onMouseDown
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseDown
|
* @see View#onMouseDown
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -3822,7 +3861,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseDrag
|
* @name Item#onMouseDrag
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseDrag
|
* @see View#onMouseDrag
|
||||||
*
|
*
|
||||||
* @example {@paperscript height=240}
|
* @example {@paperscript height=240}
|
||||||
|
@ -3851,7 +3890,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseUp
|
* @name Item#onMouseUp
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseUp
|
* @see View#onMouseUp
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -3881,7 +3920,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onClick
|
* @name Item#onClick
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onClick
|
* @see View#onClick
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -3931,7 +3970,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onDoubleClick
|
* @name Item#onDoubleClick
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onDoubleClick
|
* @see View#onDoubleClick
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -3981,7 +4020,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseMove
|
* @name Item#onMouseMove
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseMove
|
* @see View#onMouseMove
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -4012,7 +4051,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseEnter
|
* @name Item#onMouseEnter
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseEnter
|
* @see View#onMouseEnter
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -4074,7 +4113,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
*
|
*
|
||||||
* @name Item#onMouseLeave
|
* @name Item#onMouseLeave
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
* @see View#onMouseLeave
|
* @see View#onMouseLeave
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -4334,7 +4373,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
// Exclude Raster items since they never draw a stroke and handle
|
// Exclude Raster items since they never draw a stroke and handle
|
||||||
// opacity by themselves (they also don't call _setStyles)
|
// opacity by themselves (they also don't call _setStyles)
|
||||||
var blendMode = this._blendMode,
|
var blendMode = this._blendMode,
|
||||||
opacity = this._opacity,
|
opacity = Numerical.clamp(this._opacity, 0, 1),
|
||||||
normalBlend = blendMode === 'normal',
|
normalBlend = blendMode === 'normal',
|
||||||
nativeBlend = BlendMode.nativeModes[blendMode],
|
nativeBlend = BlendMode.nativeModes[blendMode],
|
||||||
// Determine if we can draw directly, or if we need to draw into a
|
// Determine if we can draw directly, or if we need to draw into a
|
||||||
|
@ -4417,8 +4456,10 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
this._draw(ctx, param, viewMatrix, strokeMatrix);
|
this._draw(ctx, param, viewMatrix, strokeMatrix);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
if (param.clip && !param.dontFinish)
|
if (param.clip && !param.dontFinish) {
|
||||||
ctx.clip();
|
// 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 a temporary canvas was created, composite it onto the main canvas:
|
||||||
if (!direct) {
|
if (!direct) {
|
||||||
// Use BlendMode.process even for processing normal blendMode with
|
// Use BlendMode.process even for processing normal blendMode with
|
||||||
|
@ -4672,4 +4713,176 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
}
|
}
|
||||||
return this;
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
* Checks whether the project has any content or not.
|
||||||
*
|
*
|
||||||
* @return Boolean
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
isEmpty: function() {
|
isEmpty: function() {
|
||||||
return !this._children.length;
|
return !this._children.length;
|
||||||
|
@ -348,7 +348,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
* {@link #layers} list.
|
* {@link #layers} list.
|
||||||
*
|
*
|
||||||
* @param {Number} index the index at which to insert the layer
|
* @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
|
* @return {Layer} the added layer, or `null` if adding was not possible
|
||||||
*/
|
*/
|
||||||
insertLayer: function(index, layer) {
|
insertLayer: function(index, layer) {
|
||||||
|
@ -745,6 +745,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
* {@link Project#clear()} to do so.
|
* {@link Project#clear()} to do so.
|
||||||
*
|
*
|
||||||
* @param {String} json the JSON data to import from
|
* @param {String} json the JSON data to import from
|
||||||
|
* @return {Item} the imported item
|
||||||
*/
|
*/
|
||||||
importJSON: function(json) {
|
importJSON: function(json) {
|
||||||
this.activate();
|
this.activate();
|
||||||
|
@ -781,7 +782,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
* kept as a link to their external URL.
|
* kept as a link to their external URL.
|
||||||
*
|
*
|
||||||
* @param {Object} [options] the export options
|
* @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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -31,15 +31,19 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
// Prioritize `crossOrigin` over `source`:
|
// Prioritize `crossOrigin` over `source`:
|
||||||
_prioritize: ['crossOrigin'],
|
_prioritize: ['crossOrigin'],
|
||||||
_smoothing: false,
|
_smoothing: false,
|
||||||
|
// Enforce creation of beans, as bean getters have hidden parameters.
|
||||||
|
// See #getContext(_change) below.
|
||||||
|
beans: true,
|
||||||
|
|
||||||
// TODO: Implement type, width, height.
|
// TODO: Implement type, width, height.
|
||||||
// TODO: Have SymbolItem & Raster inherit from a shared class?
|
// TODO: Have SymbolItem & Raster inherit from a shared class?
|
||||||
/**
|
/**
|
||||||
* Creates a new raster item from the passed argument, and places it in the
|
* 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
|
* 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).
|
* get the image from (either a DOM Image or a Canvas).
|
||||||
*
|
*
|
||||||
|
* @name Raster#initialize
|
||||||
* @param {HTMLImageElement|HTMLCanvasElement|String} [source] the source of
|
* @param {HTMLImageElement|HTMLCanvasElement|String} [source] the source of
|
||||||
* the raster
|
* the raster
|
||||||
* @param {Point} [position] the center position at which the raster item is
|
* @param {Point} [position] the center position at which the raster item is
|
||||||
|
@ -77,22 +81,64 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
* raster.scale(0.5);
|
* raster.scale(0.5);
|
||||||
* raster.rotate(10);
|
* raster.rotate(10);
|
||||||
*/
|
*/
|
||||||
initialize: function Raster(object, position) {
|
/**
|
||||||
// Support two forms of item initialization: Passing one object literal
|
* Creates a new empty raster of the given size, and places it in the
|
||||||
// describing all the different properties to be set, or an image
|
* active layer.
|
||||||
// (object) and a point where it should be placed (point).
|
*
|
||||||
|
* @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.
|
// If _initialize can set properties through object literal, we're done.
|
||||||
// Otherwise we need to check the type of object:
|
// Otherwise we need to check the type of object:
|
||||||
if (!this._initialize(object,
|
if (!this._initialize(source,
|
||||||
position !== undefined && Point.read(arguments, 1))) {
|
position !== undefined && Point.read(arguments))) {
|
||||||
// object can be an image, canvas, URL or DOM-ID:
|
var image,
|
||||||
var image = typeof object === 'string'
|
type = typeof source,
|
||||||
? document.getElementById(object) : object;
|
object = type === 'string'
|
||||||
|
? document.getElementById(source)
|
||||||
|
: type === 'object'
|
||||||
|
? source
|
||||||
|
: null;
|
||||||
|
if (object && object !== Item.NO_INSERT) {
|
||||||
|
if (object.getContext || 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) {
|
if (image) {
|
||||||
// #setImage() handles both canvas and image types.
|
// #setImage() handles both canvas and image types.
|
||||||
this.setImage(image);
|
this.setImage(image);
|
||||||
} else {
|
} else {
|
||||||
this.setSource(object);
|
this.setSource(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this._size) {
|
if (!this._size) {
|
||||||
|
@ -305,7 +351,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
* case `null` is returned instead.
|
* case `null` is returned instead.
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type HTMLCanvasELement
|
* @type HTMLCanvasElement
|
||||||
*/
|
*/
|
||||||
getCanvas: function() {
|
getCanvas: function() {
|
||||||
if (!this._canvas) {
|
if (!this._canvas) {
|
||||||
|
@ -330,15 +376,15 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
* The Canvas 2D drawing context of the raster.
|
* The Canvas 2D drawing context of the raster.
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Context
|
* @type CanvasRenderingContext2D
|
||||||
*/
|
*/
|
||||||
getContext: function(modify) {
|
getContext: function(_change) {
|
||||||
if (!this._context)
|
if (!this._context)
|
||||||
this._context = this.getCanvas().getContext('2d');
|
this._context = this.getCanvas().getContext('2d');
|
||||||
// Support a hidden parameter that indicates if the context will be used
|
// 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.
|
// they are only used afterwards for redrawing.
|
||||||
if (modify) {
|
if (_change) {
|
||||||
// Also set _image to null since the Raster stops representing it.
|
// Also set _image to null since the Raster stops representing it.
|
||||||
// NOTE: This should theoretically be in our own _changed() handler
|
// NOTE: This should theoretically be in our own _changed() handler
|
||||||
// for ChangeFlag.PIXELS, but since it's only happening in one place
|
// for ChangeFlag.PIXELS, but since it's only happening in one place
|
||||||
|
@ -386,7 +432,11 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
crossOrigin = this._crossOrigin;
|
crossOrigin = this._crossOrigin;
|
||||||
if (crossOrigin)
|
if (crossOrigin)
|
||||||
image.crossOrigin = 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);
|
this.setImage(image);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -463,7 +513,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
* @param {Rectangle} rect the boundaries of the sub image in pixel
|
* @param {Rectangle} rect the boundaries of the sub image in pixel
|
||||||
* coordinates
|
* coordinates
|
||||||
*
|
*
|
||||||
* @return {HTMLCanvasELement} the sub image as a Canvas object
|
* @return {HTMLCanvasElement} the sub image as a Canvas object
|
||||||
*/
|
*/
|
||||||
getSubCanvas: function(/* rect */) {
|
getSubCanvas: function(/* rect */) {
|
||||||
var rect = Rectangle.read(arguments),
|
var rect = Rectangle.read(arguments),
|
||||||
|
@ -519,7 +569,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
/**
|
/**
|
||||||
* Draws an image on the raster.
|
* Draws an image on the raster.
|
||||||
*
|
*
|
||||||
* @param {HTMLImageELement|HTMLCanvasELement} image
|
* @param {CanvasImageSource} image
|
||||||
* @param {Point} point the offset of the image as a point in pixel
|
* @param {Point} point the offset of the image as a point in pixel
|
||||||
* coordinates
|
* coordinates
|
||||||
*/
|
*/
|
||||||
|
@ -614,8 +664,8 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*
|
*
|
||||||
* @name Raster#getPixel
|
* @name Raster#getPixel
|
||||||
* @function
|
* @function
|
||||||
* @param x the x offset of the pixel in pixel coordinates
|
* @param {Number} x the x offset of the pixel in pixel coordinates
|
||||||
* @param y the y 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
|
* @return {Color} the color of the pixel
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
|
@ -623,7 +673,8 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*
|
*
|
||||||
* @name Raster#getPixel
|
* @name Raster#getPixel
|
||||||
* @function
|
* @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
|
* @return {Color} the color of the pixel
|
||||||
*/
|
*/
|
||||||
getPixel: function(/* point */) {
|
getPixel: function(/* point */) {
|
||||||
|
@ -639,21 +690,23 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*
|
*
|
||||||
* @name Raster#setPixel
|
* @name Raster#setPixel
|
||||||
* @function
|
* @function
|
||||||
* @param x the x offset of the pixel in pixel coordinates
|
* @param {Number} x the x offset of the pixel in pixel coordinates
|
||||||
* @param y the y offset of the pixel in pixel coordinates
|
* @param {Number} y the y offset of the pixel in pixel coordinates
|
||||||
* @param color the color that the pixel will be set to
|
* @param {Color} color the color that the pixel will be set to
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Sets the color of the specified pixel to the specified color.
|
* Sets the color of the specified pixel to the specified color.
|
||||||
*
|
*
|
||||||
* @name Raster#setPixel
|
* @name Raster#setPixel
|
||||||
* @function
|
* @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
|
||||||
* @param color the color that the pixel will be set to
|
* coordinates
|
||||||
|
* @param {Color} color the color that the pixel will be set to
|
||||||
*/
|
*/
|
||||||
setPixel: function(/* point, color */) {
|
setPixel: function(/* point, color */) {
|
||||||
var point = Point.read(arguments),
|
var args = arguments,
|
||||||
color = Color.read(arguments),
|
point = Point.read(args),
|
||||||
|
color = Color.read(args),
|
||||||
components = color._convert('rgb'),
|
components = color._convert('rgb'),
|
||||||
alpha = color._alpha,
|
alpha = color._alpha,
|
||||||
ctx = this.getContext(true),
|
ctx = this.getContext(true),
|
||||||
|
@ -666,6 +719,14 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
ctx.putImageData(imageData, point.x, point.y);
|
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
|
// DOCS: document Raster#createImageData
|
||||||
/**
|
/**
|
||||||
* {@grouptitle Image Data}
|
* {@grouptitle Image Data}
|
||||||
|
@ -710,7 +771,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*
|
*
|
||||||
* @name Raster#onLoad
|
* @name Raster#onLoad
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
* var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
||||||
|
@ -736,7 +797,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*
|
*
|
||||||
* @name Raster#onError
|
* @name Raster#onError
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_getBounds: function(matrix, options) {
|
_getBounds: function(matrix, options) {
|
||||||
|
@ -761,10 +822,11 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
|
|
||||||
_draw: function(ctx, param, viewMatrix) {
|
_draw: function(ctx, param, viewMatrix) {
|
||||||
var element = this.getElement();
|
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
|
// Handle opacity for Rasters separately from the rest, since
|
||||||
// Rasters never draw a stroke. See Item#draw().
|
// Rasters never draw a stroke. See Item#draw().
|
||||||
ctx.globalAlpha = this._opacity;
|
ctx.globalAlpha = Numerical.clamp(this._opacity, 0, 1);
|
||||||
|
|
||||||
// Call _setStyles() to make sure shadow is drawn (#1437).
|
// Call _setStyles() to make sure shadow is drawn (#1437).
|
||||||
this._setStyles(ctx, param, viewMatrix);
|
this._setStyles(ctx, param, viewMatrix);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -82,7 +82,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
setSize: function(/* size */) {
|
setSize: function(/* size */) {
|
||||||
var size = Size.read(arguments);
|
var size = Size.read(arguments);
|
||||||
if (!this._size) {
|
if (!this._size) {
|
||||||
// First time, e.g. whean reading from JSON...
|
// First time, e.g. when reading from JSON...
|
||||||
this._size = size.clone();
|
this._size = size.clone();
|
||||||
} else if (!this._size.equals(size)) {
|
} else if (!this._size.equals(size)) {
|
||||||
var type = this._type,
|
var type = this._type,
|
||||||
|
@ -90,7 +90,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
height = size.height;
|
height = size.height;
|
||||||
if (type === 'rectangle') {
|
if (type === 'rectangle') {
|
||||||
// Shrink radius accordingly
|
// Shrink radius accordingly
|
||||||
this._radius.set(Size.min(this._radius, size.divide(2)));
|
this._radius.set(Size.min(this._radius, size.divide(2).abs()));
|
||||||
} else if (type === 'circle') {
|
} else if (type === 'circle') {
|
||||||
// Use average of width and height as new size, then calculate
|
// Use average of width and height as new size, then calculate
|
||||||
// radius as a number from that:
|
// radius as a number from that:
|
||||||
|
@ -130,7 +130,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
} else {
|
} else {
|
||||||
radius = Size.read(arguments);
|
radius = Size.read(arguments);
|
||||||
if (!this._radius) {
|
if (!this._radius) {
|
||||||
// First time, e.g. whean reading from JSON...
|
// First time, e.g. when reading from JSON...
|
||||||
this._radius = radius.clone();
|
this._radius = radius.clone();
|
||||||
} else {
|
} else {
|
||||||
if (this._radius.equals(radius))
|
if (this._radius.equals(radius))
|
||||||
|
@ -390,10 +390,13 @@ new function() { // Scope for _contains() and _hitTestSelf() code.
|
||||||
// Mess with indentation in order to get more line-space below:
|
// Mess with indentation in order to get more line-space below:
|
||||||
statics: new function() {
|
statics: new function() {
|
||||||
function createShape(type, point, size, radius, args) {
|
function createShape(type, point, size, radius, args) {
|
||||||
var item = new Shape(Base.getNamed(args), point);
|
// Use `Base.create()` to avoid calling `initialize()` until after the
|
||||||
|
// internal fields are set here, then call `_initialize()` directly:
|
||||||
|
var item = Base.create(Shape.prototype);
|
||||||
item._type = type;
|
item._type = type;
|
||||||
item._size = size;
|
item._size = size;
|
||||||
item._radius = radius;
|
item._radius = radius;
|
||||||
|
item._initialize(Base.getNamed(args), point);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,10 +430,11 @@ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Circle: function(/* center, radius */) {
|
Circle: function(/* center, radius */) {
|
||||||
var center = Point.readNamed(arguments, 'center'),
|
var args = arguments,
|
||||||
radius = Base.readNamed(arguments, 'radius');
|
center = Point.readNamed(args, 'center'),
|
||||||
|
radius = Base.readNamed(args, 'radius');
|
||||||
return createShape('circle', center, new Size(radius * 2), radius,
|
return createShape('circle', center, new Size(radius * 2), radius,
|
||||||
arguments);
|
args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -524,11 +528,12 @@ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Rectangle: function(/* rectangle */) {
|
Rectangle: function(/* rectangle */) {
|
||||||
var rect = Rectangle.readNamed(arguments, 'rectangle'),
|
var args = arguments,
|
||||||
radius = Size.min(Size.readNamed(arguments, 'radius'),
|
rect = Rectangle.readNamed(args, 'rectangle'),
|
||||||
|
radius = Size.min(Size.readNamed(args, 'radius'),
|
||||||
rect.getSize(true).divide(2));
|
rect.getSize(true).divide(2));
|
||||||
return createShape('rectangle', rect.getCenter(true),
|
return createShape('rectangle', rect.getCenter(true),
|
||||||
rect.getSize(true), radius, arguments);
|
rect.getSize(true), radius, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -567,10 +572,11 @@ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Ellipse: function(/* rectangle */) {
|
Ellipse: function(/* rectangle */) {
|
||||||
var ellipse = Shape._readEllipse(arguments),
|
var args = arguments,
|
||||||
|
ellipse = Shape._readEllipse(args),
|
||||||
radius = ellipse.radius;
|
radius = ellipse.radius;
|
||||||
return createShape('ellipse', ellipse.center, radius.multiply(2),
|
return createShape('ellipse', ellipse.center, radius.multiply(2),
|
||||||
radius, arguments);
|
radius, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Private method to read ellipse center and radius from arguments list,
|
// Private method to read ellipse center and radius from arguments list,
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
* Returns a copy of the symbol.
|
||||||
*
|
*
|
||||||
* @return {Symbol}
|
* @return {SymbolDefinition}
|
||||||
*/
|
*/
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new SymbolDefinition(this._item.clone(false));
|
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.
|
* 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}
|
* @return {Boolean} {@true if they are equal}
|
||||||
*/
|
*/
|
||||||
equals: function(symbol) {
|
equals: function(symbol) {
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
* 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
|
* @param {Point} [point] the center point of the placed symbol
|
||||||
*
|
*
|
||||||
* @example {@paperscript split=true height=240}
|
* @example {@paperscript split=true height=240}
|
||||||
|
@ -119,7 +121,11 @@ var SymbolItem = Item.extend(/** @lends SymbolItem# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
_hitTestSelf: function(point, options, viewMatrix) {
|
_hitTestSelf: function(point, options, viewMatrix) {
|
||||||
var res = this._definition._item._hitTest(point, options, viewMatrix);
|
// We need to call definition item hit test with `options.all = false`,
|
||||||
|
// as otherwise it would populate the array with its own matches.
|
||||||
|
// Instead we want only returning one match per symbol-item, see #1680
|
||||||
|
var opts = options.extend({ all: false });
|
||||||
|
var res = this._definition._item._hitTest(point, opts, viewMatrix);
|
||||||
// TODO: When the symbol's definition is a path, should hitResult
|
// TODO: When the symbol's definition is a path, should hitResult
|
||||||
// contain information like HitResult#curve?
|
// contain information like HitResult#curve?
|
||||||
if (res)
|
if (res)
|
||||||
|
|
11
src/load.js
11
src/load.js
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -38,11 +38,10 @@ if (typeof window === 'object') {
|
||||||
} else {
|
} else {
|
||||||
// Some native javascript classes have name collisions with Paper.js
|
// Some native javascript classes have name collisions with Paper.js
|
||||||
// classes. Store them to be able to use them later in tests.
|
// classes. Store them to be able to use them later in tests.
|
||||||
NativeClasses = {
|
this.nativeClasses = {
|
||||||
Event: Event,
|
Event: window.Event,
|
||||||
MouseEvent: MouseEvent
|
MouseEvent: window.MouseEvent
|
||||||
};
|
};
|
||||||
|
|
||||||
include('options.js');
|
include('options.js');
|
||||||
// Load constants.js, required by the on-the-fly preprocessing:
|
// Load constants.js, required by the on-the-fly preprocessing:
|
||||||
include('constants.js');
|
include('constants.js');
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
module.exports = function(self, requireName) {
|
module.exports = function(self, requireName) {
|
||||||
var Canvas;
|
var Canvas;
|
||||||
try {
|
try {
|
||||||
Canvas = require('canvas');
|
Canvas = require('canvas').Canvas;
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
// Remove `self.window`, so we still have the global `self` reference,
|
// Remove `self.window`, so we still have the global `self` reference,
|
||||||
// but no `window` object:
|
// but no `window` object:
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -37,15 +37,13 @@ try {
|
||||||
if (jsdom) {
|
if (jsdom) {
|
||||||
// Create our document and window objects through jsdom.
|
// Create our document and window objects through jsdom.
|
||||||
/* global document:true, window:true */
|
/* global document:true, window:true */
|
||||||
var document = jsdom.jsdom('<html><body></body></html>', {
|
var document = new jsdom.JSDOM('<html><body></body></html>', {
|
||||||
// Use the current working directory as the document's origin, so
|
// Use the current working directory as the document's origin, so
|
||||||
// requests to local files work correctly with CORS.
|
// requests to local files work correctly with CORS.
|
||||||
url: 'file://' + process.cwd() + '/',
|
url: 'file://' + process.cwd() + '/',
|
||||||
features: {
|
resources: 'usable'
|
||||||
FetchExternalResources: ['img', 'script']
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self = document.defaultView;
|
self = document.window;
|
||||||
require('./canvas.js')(self, requireName);
|
require('./canvas.js')(self, requireName);
|
||||||
require('./xml.js')(self);
|
require('./xml.js')(self);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
// The paper.js version.
|
// The paper.js version.
|
||||||
// NOTE: Adjust value here before calling `gulp publish`, which then updates and
|
// NOTE: Adjust value here before calling `gulp publish`, which then updates and
|
||||||
// publishes the various JSON package files automatically.
|
// publishes the various JSON package files automatically.
|
||||||
var version = '0.11.8';
|
var version = '0.12.7';
|
||||||
|
|
||||||
// If this file is loaded in the browser, we're in load.js mode.
|
// If this file is loaded in the browser, we're in load.js mode.
|
||||||
var load = typeof window === 'object';
|
var load = typeof window === 'object';
|
||||||
|
|
13
src/paper.js
13
src/paper.js
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js v*#=*__options.version - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js v*#=*__options.version - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -15,15 +15,15 @@
|
||||||
*
|
*
|
||||||
* Straps.js - Class inheritance library with support for bean-style accessors
|
* Straps.js - Class inheritance library with support for bean-style accessors
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006 - 2016 Juerg Lehni
|
* Copyright (c) 2006 - 2020 Jürg Lehni
|
||||||
* http://scratchdisk.com/
|
* http://juerglehni.com/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license.
|
* Distributed under the MIT license.
|
||||||
*
|
*
|
||||||
***
|
***
|
||||||
*
|
*
|
||||||
* Acorn.js
|
* Acorn.js
|
||||||
* http://marijnhaverbeke.nl/acorn/
|
* https://marijnhaverbeke.nl/acorn/
|
||||||
*
|
*
|
||||||
* Acorn is a tiny, fast JavaScript parser written in JavaScript,
|
* Acorn is a tiny, fast JavaScript parser written in JavaScript,
|
||||||
* created by Marijn Haverbeke and released under an MIT license.
|
* created by Marijn Haverbeke and released under an MIT license.
|
||||||
|
@ -42,6 +42,7 @@ var paper = function(self, undefined) {
|
||||||
/*#*/ include('core/PaperScope.js');
|
/*#*/ include('core/PaperScope.js');
|
||||||
/*#*/ include('core/PaperScopeItem.js');
|
/*#*/ include('core/PaperScopeItem.js');
|
||||||
|
|
||||||
|
/*#*/ include('util/CollisionDetection.js');
|
||||||
/*#*/ include('util/Formatter.js');
|
/*#*/ include('util/Formatter.js');
|
||||||
/*#*/ include('util/Numerical.js');
|
/*#*/ include('util/Numerical.js');
|
||||||
/*#*/ include('util/UID.js');
|
/*#*/ include('util/UID.js');
|
||||||
|
@ -102,6 +103,8 @@ var paper = function(self, undefined) {
|
||||||
/*#*/ include('tool/ToolEvent.js');
|
/*#*/ include('tool/ToolEvent.js');
|
||||||
/*#*/ include('tool/Tool.js');
|
/*#*/ include('tool/Tool.js');
|
||||||
|
|
||||||
|
/*#*/ include('anim/Tween.js');
|
||||||
|
|
||||||
/*#*/ include('net/Http.js');
|
/*#*/ include('net/Http.js');
|
||||||
|
|
||||||
/*#*/ include('canvas/CanvasProvider.js');
|
/*#*/ include('canvas/CanvasProvider.js');
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -161,7 +161,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
* @see Path#isClosed()
|
* @see Path#closed
|
||||||
*/
|
*/
|
||||||
isClosed: function() {
|
isClosed: function() {
|
||||||
var children = this._children;
|
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
|
* 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
|
* @bean
|
||||||
* @type Segment
|
* @type Segment
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
// 2: normal, 1st derivative
|
||||||
// 3: curvature, 1st derivative & 2nd derivative
|
// 3: curvature, 1st derivative & 2nd derivative
|
||||||
// Prevent tangents and normals of length 0:
|
// Prevent tangents and normals of length 0:
|
||||||
// http://stackoverflow.com/questions/10506868/
|
// https://stackoverflow.com/questions/10506868/
|
||||||
if (t < tMin) {
|
if (t < tMin) {
|
||||||
x = cx;
|
x = cx;
|
||||||
y = cy;
|
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
|
* Peaks are locations sharing some qualities of curvature extrema but
|
||||||
* are cheaper to compute. They fulfill their purpose here quite well.
|
* are cheaper to compute. They fulfill their purpose here quite well.
|
||||||
* See:
|
* 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
|
* @param {Number[]} v the curve values array
|
||||||
* @return {Number[]} the roots of all found peaks
|
* @return {Number[]} the roots of all found peaks
|
||||||
|
@ -1822,9 +1822,10 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
||||||
} else {
|
} else {
|
||||||
// Apply the result of the clipping to curve 1:
|
// Apply the result of the clipping to curve 1:
|
||||||
v1 = Curve.getPart(v1, tMinClip, tMaxClip);
|
v1 = Curve.getPart(v1, tMinClip, tMaxClip);
|
||||||
|
var uDiff = uMax - uMin;
|
||||||
if (tMaxClip - tMinClip > 0.8) {
|
if (tMaxClip - tMinClip > 0.8) {
|
||||||
// Subdivide the curve which has converged the least.
|
// Subdivide the curve which has converged the least.
|
||||||
if (tMaxNew - tMinNew > uMax - uMin) {
|
if (tMaxNew - tMinNew > uDiff) {
|
||||||
var parts = Curve.subdivide(v1, 0.5),
|
var parts = Curve.subdivide(v1, 0.5),
|
||||||
t = (tMinNew + tMaxNew) / 2;
|
t = (tMinNew + tMaxNew) / 2;
|
||||||
calls = addCurveIntersections(
|
calls = addCurveIntersections(
|
||||||
|
@ -1844,7 +1845,10 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
||||||
recursion, calls, u, uMax, tMinNew, tMaxNew);
|
recursion, calls, u, uMax, tMinNew, tMaxNew);
|
||||||
}
|
}
|
||||||
} else { // Iterate
|
} else { // Iterate
|
||||||
if (uMax - uMin >= fatLineEpsilon) {
|
// For some unclear reason we need to check against uDiff === 0
|
||||||
|
// here, to prevent a regression from happening, see #1638.
|
||||||
|
// Maybe @iconexperience could shed some light on this.
|
||||||
|
if (uDiff === 0 || uDiff >= fatLineEpsilon) {
|
||||||
calls = addCurveIntersections(
|
calls = addCurveIntersections(
|
||||||
v2, v1, c2, c1, locations, include, !flip,
|
v2, v1, c2, c1, locations, include, !flip,
|
||||||
recursion, calls, uMin, uMax, tMinNew, tMaxNew);
|
recursion, calls, uMin, uMax, tMinNew, tMaxNew);
|
||||||
|
@ -2087,7 +2091,7 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
||||||
return locations;
|
return locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLoopIntersection(v1, c1, locations, include) {
|
function getSelfIntersection(v1, c1, locations, include) {
|
||||||
var info = Curve.classify(v1);
|
var info = Curve.classify(v1);
|
||||||
if (info.type === 'loop') {
|
if (info.type === 'loop') {
|
||||||
var roots = info.roots;
|
var roots = info.roots;
|
||||||
|
@ -2100,50 +2104,50 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
||||||
|
|
||||||
function getIntersections(curves1, curves2, include, matrix1, matrix2,
|
function getIntersections(curves1, curves2, include, matrix1, matrix2,
|
||||||
_returnFirst) {
|
_returnFirst) {
|
||||||
var self = !curves2;
|
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
||||||
|
self = !curves2;
|
||||||
if (self)
|
if (self)
|
||||||
curves2 = curves1;
|
curves2 = curves1;
|
||||||
var length1 = curves1.length,
|
var length1 = curves1.length,
|
||||||
length2 = curves2.length,
|
length2 = curves2.length,
|
||||||
values2 = [],
|
values1 = new Array(length1),
|
||||||
arrays = [],
|
values2 = self ? values1 : new Array(length2),
|
||||||
locations,
|
locations = [];
|
||||||
current;
|
|
||||||
// Cache values for curves2 as we re-iterate them for each in curves1.
|
|
||||||
for (var i = 0; i < length2; i++)
|
|
||||||
values2[i] = curves2[i].getValues(matrix2);
|
|
||||||
for (var i = 0; i < length1; i++) {
|
for (var i = 0; i < length1; i++) {
|
||||||
var curve1 = curves1[i],
|
values1[i] = curves1[i].getValues(matrix1);
|
||||||
values1 = self ? values2[i] : curve1.getValues(matrix1),
|
}
|
||||||
path1 = curve1.getPath();
|
if (!self) {
|
||||||
// NOTE: Due to the nature of getCurveIntersections(), we use
|
for (var i = 0; i < length2; i++) {
|
||||||
// separate location arrays per path1, to make sure the circularity
|
values2[i] = curves2[i].getValues(matrix2);
|
||||||
// checks are not getting confused by locations on separate paths.
|
|
||||||
// The separate arrays are then flattened in the end.
|
|
||||||
if (path1 !== current) {
|
|
||||||
current = path1;
|
|
||||||
locations = [];
|
|
||||||
arrays.push(locations);
|
|
||||||
}
|
|
||||||
if (self) {
|
|
||||||
// First check for self-intersections within the same curve.
|
|
||||||
getLoopIntersection(values1, curve1, locations, include);
|
|
||||||
}
|
|
||||||
// Check for intersections with other curves.
|
|
||||||
// For self-intersection, we can start at i + 1 instead of 0.
|
|
||||||
for (var j = self ? i + 1 : 0; j < length2; j++) {
|
|
||||||
// There might be already one location from the above
|
|
||||||
// self-intersection check:
|
|
||||||
if (_returnFirst && locations.length)
|
|
||||||
return locations;
|
|
||||||
getCurveIntersections(values1, values2[j], curve1, curves2[j],
|
|
||||||
locations, include);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Flatten the list of location arrays to one array and return it.
|
var boundsCollisions = CollisionDetection.findCurveBoundsCollisions(
|
||||||
locations = [];
|
values1, values2, epsilon);
|
||||||
for (var i = 0, l = arrays.length; i < l; i++) {
|
for (var index1 = 0; index1 < length1; index1++) {
|
||||||
Base.push(locations, arrays[i]);
|
var curve1 = curves1[index1],
|
||||||
|
v1 = values1[index1];
|
||||||
|
if (self) {
|
||||||
|
// First check for self-intersections within the same curve.
|
||||||
|
getSelfIntersection(v1, curve1, locations, include);
|
||||||
|
}
|
||||||
|
// Check for intersections with potentially intersecting curves.
|
||||||
|
var collisions1 = boundsCollisions[index1];
|
||||||
|
if (collisions1) {
|
||||||
|
for (var j = 0; j < collisions1.length; j++) {
|
||||||
|
// There might be already one location from the above
|
||||||
|
// self-intersection check:
|
||||||
|
if (_returnFirst && locations.length)
|
||||||
|
return locations;
|
||||||
|
var index2 = collisions1[j];
|
||||||
|
if (!self || index2 > index1) {
|
||||||
|
var curve2 = curves2[index2],
|
||||||
|
v2 = values2[index2];
|
||||||
|
getCurveIntersections(
|
||||||
|
v1, v2, curve1, curve2, locations, include);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return locations;
|
return locations;
|
||||||
}
|
}
|
||||||
|
@ -2310,7 +2314,7 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
||||||
var v1 = this.getValues(),
|
var v1 = this.getValues(),
|
||||||
v2 = curve && curve !== this && curve.getValues();
|
v2 = curve && curve !== this && curve.getValues();
|
||||||
return v2 ? getCurveIntersections(v1, v2, this, curve, [])
|
return v2 ? getCurveIntersections(v1, v2, this, curve, [])
|
||||||
: getLoopIntersection(v1, this, []);
|
: getSelfIntersection(v1, this, []);
|
||||||
},
|
},
|
||||||
|
|
||||||
statics: /** @lends Curve */{
|
statics: /** @lends Curve */{
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -57,13 +57,16 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
this._intersection = this._next = this._previous = null;
|
this._intersection = this._next = this._previous = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_setCurve: function(curve) {
|
_setPath: function(path) {
|
||||||
var path = curve._path;
|
// We only store the path to verify versions for cached values.
|
||||||
// We only store the path to verify versions for cachd values.
|
|
||||||
// To ensure we use the right path (e.g. after splitting), we shall
|
// To ensure we use the right path (e.g. after splitting), we shall
|
||||||
// always access the path on the result of getCurve().
|
// always access the path on the result of getCurve().
|
||||||
this._path = path;
|
this._path = path;
|
||||||
this._version = path ? path._version : 0;
|
this._version = path ? path._version : 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setCurve: function(curve) {
|
||||||
|
this._setPath(curve._path);
|
||||||
this._curve = curve;
|
this._curve = curve;
|
||||||
this._segment = null; // To be determined, see #getSegment()
|
this._segment = null; // To be determined, see #getSegment()
|
||||||
// Also store references to segment1 and segment2, in case path
|
// Also store references to segment1 and segment2, in case path
|
||||||
|
@ -74,7 +77,14 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
_setSegment: function(segment) {
|
_setSegment: function(segment) {
|
||||||
this._setCurve(segment.getCurve());
|
var curve = segment.getCurve();
|
||||||
|
if (curve) {
|
||||||
|
this._setCurve(curve);
|
||||||
|
} else {
|
||||||
|
this._setPath(segment._path);
|
||||||
|
this._segment1 = segment;
|
||||||
|
this._segment2 = null;
|
||||||
|
}
|
||||||
this._segment = segment;
|
this._segment = segment;
|
||||||
this._time = segment === this._segment1 ? 0 : 1;
|
this._time = segment === this._segment1 ? 0 : 1;
|
||||||
// To avoid issues with imprecision in getCurve() / trySegment()
|
// To avoid issues with imprecision in getCurve() / trySegment()
|
||||||
|
@ -147,7 +157,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
* The path that this locations is situated on.
|
* The path that this locations is situated on.
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Item
|
* @type Path
|
||||||
*/
|
*/
|
||||||
getPath: function() {
|
getPath: function() {
|
||||||
var curve = this.getCurve();
|
var curve = this.getCurve();
|
||||||
|
@ -159,7 +169,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
* it is part of a {@link Path} item.
|
* it is part of a {@link Path} item.
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Index
|
* @type Number
|
||||||
*/
|
*/
|
||||||
getIndex: function() {
|
getIndex: function() {
|
||||||
var curve = this.getCurve();
|
var curve = this.getCurve();
|
||||||
|
@ -284,7 +294,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
* @bean
|
* @bean
|
||||||
* @type Number
|
* @type Number
|
||||||
* @see Curve#getNearestLocation(point)
|
* @see Curve#getNearestLocation(point)
|
||||||
* @see Path#getNearestLocation(point)
|
* @see PathItem#getNearestLocation(point)
|
||||||
*/
|
*/
|
||||||
getDistance: function() {
|
getDistance: function() {
|
||||||
return this._distance;
|
return this._distance;
|
||||||
|
@ -424,9 +434,9 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
// both values point to the same curve, and the curve-time is to be
|
// both values point to the same curve, and the curve-time is to be
|
||||||
// handled accordingly further down.
|
// handled accordingly further down.
|
||||||
var c2 = this.getCurve(),
|
var c2 = this.getCurve(),
|
||||||
c1 = t1 < tMin ? c2.getPrevious() : c2,
|
c1 = c2 && t1 < tMin ? c2.getPrevious() : c2,
|
||||||
c4 = inter.getCurve(),
|
c4 = inter.getCurve(),
|
||||||
c3 = t2 < tMin ? c4.getPrevious() : c4;
|
c3 = c4 && t2 < tMin ? c4.getPrevious() : c4;
|
||||||
// If t1 / t2 are at the end, then step to the next curve.
|
// If t1 / t2 are at the end, then step to the next curve.
|
||||||
if (t1 > tMax)
|
if (t1 > tMax)
|
||||||
c2 = c2.getNext();
|
c2 = c2.getNext();
|
||||||
|
@ -450,11 +460,12 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
var v = curve.getValues(),
|
var v = curve.getValues(),
|
||||||
roots = Curve.classify(v).roots || Curve.getPeaks(v),
|
roots = Curve.classify(v).roots || Curve.getPeaks(v),
|
||||||
count = roots.length,
|
count = roots.length,
|
||||||
t = end && count > 1 ? roots[count - 1]
|
offset = Curve.getLength(v,
|
||||||
: count > 0 ? roots[0]
|
end && count ? roots[count - 1] : 0,
|
||||||
: 0.5;
|
!end && count ? roots[0] : 1);
|
||||||
// Then use half of the offset, for extra measure.
|
// When no root was found, the full length was calculated. Use a
|
||||||
offsets.push(Curve.getLength(v, end ? t : 0, end ? 1 : t) / 2);
|
// fraction of it. By trial & error, 64 was determined to work well.
|
||||||
|
offsets.push(count ? offset : offset / 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInRange(angle, min, max) {
|
function isInRange(angle, min, max) {
|
||||||
|
@ -491,7 +502,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
// Count how many times curve2 angles appear between the curve1 angles.
|
// Count how many times curve2 angles appear between the curve1 angles.
|
||||||
// If each pair of angles split the other two, then the edges cross.
|
// If each pair of angles split the other two, then the edges cross.
|
||||||
// Use t1Inside to decide which angle pair to check against.
|
// Use t1Inside to decide which angle pair to check against.
|
||||||
// If t1 is inside the curve, check against a3 & a4, othrwise a1 & a2.
|
// If t1 is inside the curve, check against a3 & a4, otherwise a1 & a2.
|
||||||
return !!(t1Inside
|
return !!(t1Inside
|
||||||
? (isInRange(a1, a3, a4) ^ isInRange(a2, a3, a4)) &&
|
? (isInRange(a1, a3, a4) ^ isInRange(a2, a3, a4)) &&
|
||||||
(isInRange(a1, a4, a3) ^ isInRange(a2, a4, a3))
|
(isInRange(a1, a4, a3) ^ isInRange(a2, a4, a3))
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -79,10 +79,11 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Line: function(/* from, to */) {
|
Line: function(/* from, to */) {
|
||||||
|
var args = arguments;
|
||||||
return createPath([
|
return createPath([
|
||||||
new Segment(Point.readNamed(arguments, 'from')),
|
new Segment(Point.readNamed(args, 'from')),
|
||||||
new Segment(Point.readNamed(arguments, 'to'))
|
new Segment(Point.readNamed(args, 'to'))
|
||||||
], false, arguments);
|
], false, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,9 +115,10 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Circle: function(/* center, radius */) {
|
Circle: function(/* center, radius */) {
|
||||||
var center = Point.readNamed(arguments, 'center'),
|
var args = arguments,
|
||||||
radius = Base.readNamed(arguments, 'radius');
|
center = Point.readNamed(args, 'center'),
|
||||||
return createEllipse(center, new Size(radius), arguments);
|
radius = Base.readNamed(args, 'radius');
|
||||||
|
return createEllipse(center, new Size(radius), args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,8 +212,9 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Rectangle: function(/* rectangle */) {
|
Rectangle: function(/* rectangle */) {
|
||||||
var rect = Rectangle.readNamed(arguments, 'rectangle'),
|
var args = arguments,
|
||||||
radius = Size.readNamed(arguments, 'radius', 0,
|
rect = Rectangle.readNamed(args, 'rectangle'),
|
||||||
|
radius = Size.readNamed(args, 'radius', 0,
|
||||||
{ readNull: true }),
|
{ readNull: true }),
|
||||||
bl = rect.getBottomLeft(true),
|
bl = rect.getBottomLeft(true),
|
||||||
tl = rect.getTopLeft(true),
|
tl = rect.getTopLeft(true),
|
||||||
|
@ -242,7 +245,7 @@ Path.inject({ statics: new function() {
|
||||||
new Segment(br.subtract(rx, 0), [hx, 0])
|
new Segment(br.subtract(rx, 0), [hx, 0])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return createPath(segments, true, arguments);
|
return createPath(segments, true, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,8 +289,9 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Ellipse: function(/* rectangle */) {
|
Ellipse: function(/* rectangle */) {
|
||||||
var ellipse = Shape._readEllipse(arguments);
|
var args = arguments,
|
||||||
return createEllipse(ellipse.center, ellipse.radius, arguments);
|
ellipse = Shape._readEllipse(args);
|
||||||
|
return createEllipse(ellipse.center, ellipse.radius, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -330,10 +334,11 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Arc: function(/* from, through, to */) {
|
Arc: function(/* from, through, to */) {
|
||||||
var from = Point.readNamed(arguments, 'from'),
|
var args = arguments,
|
||||||
through = Point.readNamed(arguments, 'through'),
|
from = Point.readNamed(args, 'from'),
|
||||||
to = Point.readNamed(arguments, 'to'),
|
through = Point.readNamed(args, 'through'),
|
||||||
props = Base.getNamed(arguments),
|
to = Point.readNamed(args, 'to'),
|
||||||
|
props = Base.getNamed(args),
|
||||||
// See createPath() for an explanation of the following sequence
|
// See createPath() for an explanation of the following sequence
|
||||||
path = new Path(props && props.insert == false
|
path = new Path(props && props.insert == false
|
||||||
&& Item.NO_INSERT);
|
&& Item.NO_INSERT);
|
||||||
|
@ -376,9 +381,10 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
RegularPolygon: function(/* center, sides, radius */) {
|
RegularPolygon: function(/* center, sides, radius */) {
|
||||||
var center = Point.readNamed(arguments, 'center'),
|
var args = arguments,
|
||||||
sides = Base.readNamed(arguments, 'sides'),
|
center = Point.readNamed(args, 'center'),
|
||||||
radius = Base.readNamed(arguments, 'radius'),
|
sides = Base.readNamed(args, 'sides'),
|
||||||
|
radius = Base.readNamed(args, 'radius'),
|
||||||
step = 360 / sides,
|
step = 360 / sides,
|
||||||
three = sides % 3 === 0,
|
three = sides % 3 === 0,
|
||||||
vector = new Point(0, three ? -radius : radius),
|
vector = new Point(0, three ? -radius : radius),
|
||||||
|
@ -387,7 +393,7 @@ Path.inject({ statics: new function() {
|
||||||
for (var i = 0; i < sides; i++)
|
for (var i = 0; i < sides; i++)
|
||||||
segments[i] = new Segment(center.add(
|
segments[i] = new Segment(center.add(
|
||||||
vector.rotate((i + offset) * step)));
|
vector.rotate((i + offset) * step)));
|
||||||
return createPath(segments, true, arguments);
|
return createPath(segments, true, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -431,17 +437,18 @@ Path.inject({ statics: new function() {
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Star: function(/* center, points, radius1, radius2 */) {
|
Star: function(/* center, points, radius1, radius2 */) {
|
||||||
var center = Point.readNamed(arguments, 'center'),
|
var args = arguments,
|
||||||
points = Base.readNamed(arguments, 'points') * 2,
|
center = Point.readNamed(args, 'center'),
|
||||||
radius1 = Base.readNamed(arguments, 'radius1'),
|
points = Base.readNamed(args, 'points') * 2,
|
||||||
radius2 = Base.readNamed(arguments, 'radius2'),
|
radius1 = Base.readNamed(args, 'radius1'),
|
||||||
|
radius2 = Base.readNamed(args, 'radius2'),
|
||||||
step = 360 / points,
|
step = 360 / points,
|
||||||
vector = new Point(0, -1),
|
vector = new Point(0, -1),
|
||||||
segments = new Array(points);
|
segments = new Array(points);
|
||||||
for (var i = 0; i < points; i++)
|
for (var i = 0; i < points; i++)
|
||||||
segments[i] = new Segment(center.add(vector.rotate(step * i)
|
segments[i] = new Segment(center.add(vector.rotate(step * i)
|
||||||
.multiply(i % 2 ? radius2 : radius1)));
|
.multiply(i % 2 ? radius2 : radius1)));
|
||||||
return createPath(segments, true, arguments);
|
return createPath(segments, true, args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}});
|
}});
|
||||||
|
|
217
src/path/Path.js
217
src/path/Path.js
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
* Creates a new path item from SVG path-data and places it at the top of
|
||||||
* the active layer.
|
* the active layer.
|
||||||
*
|
*
|
||||||
* @param
|
|
||||||
* @name Path#initialize
|
* @name Path#initialize
|
||||||
* @param {String} pathData the SVG path-data that describes the geometry
|
* @param {String} pathData the SVG path-data that describes the geometry
|
||||||
* of this path
|
* of this path
|
||||||
|
@ -99,15 +98,16 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
// check its first entry for object as well.
|
// check its first entry for object as well.
|
||||||
// But first see if segments are directly passed at all. If not, try
|
// But first see if segments are directly passed at all. If not, try
|
||||||
// _set(arg).
|
// _set(arg).
|
||||||
var segments = Array.isArray(arg)
|
var args = arguments,
|
||||||
|
segments = Array.isArray(arg)
|
||||||
? typeof arg[0] === 'object'
|
? typeof arg[0] === 'object'
|
||||||
? arg
|
? arg
|
||||||
: arguments
|
: args
|
||||||
// See if it behaves like a segment or a point, but filter out
|
// See if it behaves like a segment or a point, but filter out
|
||||||
// rectangles, as accepted by some Path.Constructor constructors.
|
// rectangles, as accepted by some Path.Constructor constructors.
|
||||||
: arg && (arg.size === undefined && (arg.x !== undefined
|
: arg && (arg.size === undefined && (arg.x !== undefined
|
||||||
|| arg.point !== undefined))
|
|| arg.point !== undefined))
|
||||||
? arguments
|
? args
|
||||||
: null;
|
: null;
|
||||||
// Always call setSegments() to initialize a few related variables.
|
// Always call setSegments() to initialize a few related variables.
|
||||||
if (segments && segments.length > 0) {
|
if (segments && segments.length > 0) {
|
||||||
|
@ -484,9 +484,11 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
* Adds one or more segments to the end of the {@link #segments} array of
|
* Adds one or more segments to the end of the {@link #segments} array of
|
||||||
* this path.
|
* this path.
|
||||||
*
|
*
|
||||||
* @param {Segment|Point} segment the segment or point to be added.
|
* @param {...(Segment|Point|Number[])} segment the segment or point to be
|
||||||
* @return {Segment} the added segment. This is not necessarily the same
|
* added.
|
||||||
* object, e.g. if the segment to be added already belongs to another path
|
* @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}
|
* @example {@paperscript}
|
||||||
* // Adding segments to a path using point objects:
|
* // Adding segments to a path using point objects:
|
||||||
|
@ -547,11 +549,12 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
* path.add(new Point(170, 75));
|
* path.add(new Point(170, 75));
|
||||||
*/
|
*/
|
||||||
add: function(segment1 /*, segment2, ... */) {
|
add: function(segment1 /*, segment2, ... */) {
|
||||||
return arguments.length > 1 && typeof segment1 !== 'number'
|
var args = arguments;
|
||||||
|
return args.length > 1 && typeof segment1 !== 'number'
|
||||||
// addSegments
|
// addSegments
|
||||||
? this._add(Segment.readList(arguments))
|
? this._add(Segment.readList(args))
|
||||||
// addSegment
|
// addSegment
|
||||||
: this._add([ Segment.read(arguments) ])[0];
|
: this._add([ Segment.read(args) ])[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -591,11 +594,12 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
* myPath.segments[2].selected = true;
|
* myPath.segments[2].selected = true;
|
||||||
*/
|
*/
|
||||||
insert: function(index, segment1 /*, segment2, ... */) {
|
insert: function(index, segment1 /*, segment2, ... */) {
|
||||||
return arguments.length > 2 && typeof segment1 !== 'number'
|
var args = arguments;
|
||||||
|
return args.length > 2 && typeof segment1 !== 'number'
|
||||||
// insertSegments
|
// insertSegments
|
||||||
? this._add(Segment.readList(arguments, 1), index)
|
? this._add(Segment.readList(args, 1), index)
|
||||||
// insertSegment
|
// insertSegment
|
||||||
: this._add([ Segment.read(arguments, 1) ], index)[0];
|
: this._add([ Segment.read(args, 1) ], index)[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
addSegment: function(/* segment */) {
|
addSegment: function(/* segment */) {
|
||||||
|
@ -1215,6 +1219,8 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
/**
|
/**
|
||||||
* Reduces the path by removing curves that have a length of 0,
|
* Reduces the path by removing curves that have a length of 0,
|
||||||
* and unnecessary segments between two collinear flat curves.
|
* and unnecessary segments between two collinear flat curves.
|
||||||
|
*
|
||||||
|
* @return {Path} the reduced path
|
||||||
*/
|
*/
|
||||||
reduce: function(options) {
|
reduce: function(options) {
|
||||||
var curves = this.getCurves(),
|
var curves = this.getCurves(),
|
||||||
|
@ -2173,9 +2179,9 @@ new function() { // Scope for drawing
|
||||||
// performance.
|
// performance.
|
||||||
|
|
||||||
function drawHandles(ctx, segments, matrix, size, isFullySelected) {
|
function drawHandles(ctx, segments, matrix, size, isFullySelected) {
|
||||||
if (size === 0) {
|
// Only draw if size is not null or negative.
|
||||||
return;
|
if (size <= 0) return;
|
||||||
}
|
|
||||||
var half = size / 2,
|
var half = size / 2,
|
||||||
coords = new Array(6),
|
coords = new Array(6),
|
||||||
pX, pY;
|
pX, pY;
|
||||||
|
@ -2402,9 +2408,10 @@ new function() { // PostScript-style drawing commands
|
||||||
},
|
},
|
||||||
|
|
||||||
cubicCurveTo: function(/* handle1, handle2, to */) {
|
cubicCurveTo: function(/* handle1, handle2, to */) {
|
||||||
var handle1 = Point.read(arguments),
|
var args = arguments,
|
||||||
handle2 = Point.read(arguments),
|
handle1 = Point.read(args),
|
||||||
to = Point.read(arguments),
|
handle2 = Point.read(args),
|
||||||
|
to = Point.read(args),
|
||||||
// First modify the current segment:
|
// First modify the current segment:
|
||||||
current = getCurrentSegment(this);
|
current = getCurrentSegment(this);
|
||||||
// Convert to relative values:
|
// Convert to relative values:
|
||||||
|
@ -2414,8 +2421,9 @@ new function() { // PostScript-style drawing commands
|
||||||
},
|
},
|
||||||
|
|
||||||
quadraticCurveTo: function(/* handle, to */) {
|
quadraticCurveTo: function(/* handle, to */) {
|
||||||
var handle = Point.read(arguments),
|
var args = arguments,
|
||||||
to = Point.read(arguments),
|
handle = Point.read(args),
|
||||||
|
to = Point.read(args),
|
||||||
current = getCurrentSegment(this)._point;
|
current = getCurrentSegment(this)._point;
|
||||||
// This is exact:
|
// This is exact:
|
||||||
// If we have the three quad points: A E D,
|
// If we have the three quad points: A E D,
|
||||||
|
@ -2430,9 +2438,10 @@ new function() { // PostScript-style drawing commands
|
||||||
},
|
},
|
||||||
|
|
||||||
curveTo: function(/* through, to, time */) {
|
curveTo: function(/* through, to, time */) {
|
||||||
var through = Point.read(arguments),
|
var args = arguments,
|
||||||
to = Point.read(arguments),
|
through = Point.read(args),
|
||||||
t = Base.pick(Base.read(arguments), 0.5),
|
to = Point.read(args),
|
||||||
|
t = Base.pick(Base.read(args), 0.5),
|
||||||
t1 = 1 - t,
|
t1 = 1 - t,
|
||||||
current = getCurrentSegment(this)._point,
|
current = getCurrentSegment(this)._point,
|
||||||
// handle = (through - (1 - t)^2 * current - t^2 * to) /
|
// handle = (through - (1 - t)^2 * current - t^2 * to) /
|
||||||
|
@ -2448,15 +2457,16 @@ new function() { // PostScript-style drawing commands
|
||||||
arcTo: function(/* to, clockwise | through, to
|
arcTo: function(/* to, clockwise | through, to
|
||||||
| to, radius, rotation, clockwise, large */) {
|
| to, radius, rotation, clockwise, large */) {
|
||||||
// Get the start point:
|
// Get the start point:
|
||||||
var abs = Math.abs,
|
var args = arguments,
|
||||||
|
abs = Math.abs,
|
||||||
sqrt = Math.sqrt,
|
sqrt = Math.sqrt,
|
||||||
current = getCurrentSegment(this),
|
current = getCurrentSegment(this),
|
||||||
from = current._point,
|
from = current._point,
|
||||||
to = Point.read(arguments),
|
to = Point.read(args),
|
||||||
through,
|
through,
|
||||||
// Peek at next value to see if it's clockwise, with true as the
|
// Peek at next value to see if it's clockwise, with true as the
|
||||||
// default value.
|
// default value.
|
||||||
peek = Base.peek(arguments),
|
peek = Base.peek(args),
|
||||||
clockwise = Base.pick(peek, true),
|
clockwise = Base.pick(peek, true),
|
||||||
center, extent, vector, matrix;
|
center, extent, vector, matrix;
|
||||||
// We're handling three different approaches to drawing arcs in one
|
// We're handling three different approaches to drawing arcs in one
|
||||||
|
@ -2466,14 +2476,15 @@ new function() { // PostScript-style drawing commands
|
||||||
var middle = from.add(to).divide(2),
|
var middle = from.add(to).divide(2),
|
||||||
through = middle.add(middle.subtract(from).rotate(
|
through = middle.add(middle.subtract(from).rotate(
|
||||||
clockwise ? -90 : 90));
|
clockwise ? -90 : 90));
|
||||||
} else if (Base.remain(arguments) <= 2) {
|
} else if (Base.remain(args) <= 2) {
|
||||||
// #2: arcTo(through, to)
|
// #2: arcTo(through, to)
|
||||||
through = to;
|
through = to;
|
||||||
to = Point.read(arguments);
|
to = Point.read(args);
|
||||||
} else {
|
} else if (!from.equals(to)) {
|
||||||
// #3: arcTo(to, radius, rotation, clockwise, large)
|
// #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
|
||||||
var radius = Size.read(arguments),
|
// equal (#1613).
|
||||||
|
var radius = Size.read(args),
|
||||||
isZero = Numerical.isZero;
|
isZero = Numerical.isZero;
|
||||||
// If rx = 0 or ry = 0 then this arc is treated as a
|
// If rx = 0 or ry = 0 then this arc is treated as a
|
||||||
// straight line joining the endpoints.
|
// straight line joining the endpoints.
|
||||||
|
@ -2481,10 +2492,10 @@ new function() { // PostScript-style drawing commands
|
||||||
if (isZero(radius.width) || isZero(radius.height))
|
if (isZero(radius.width) || isZero(radius.height))
|
||||||
return this.lineTo(to);
|
return this.lineTo(to);
|
||||||
// See for an explanation of the following calculations:
|
// 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),
|
var rotation = Base.read(args),
|
||||||
clockwise = !!Base.read(arguments),
|
clockwise = !!Base.read(args),
|
||||||
large = !!Base.read(arguments),
|
large = !!Base.read(args),
|
||||||
middle = from.add(to).divide(2),
|
middle = from.add(to).divide(2),
|
||||||
pt = from.subtract(middle).rotate(-rotation),
|
pt = from.subtract(middle).rotate(-rotation),
|
||||||
x = pt.x,
|
x = pt.x,
|
||||||
|
@ -2568,47 +2579,49 @@ new function() { // PostScript-style drawing commands
|
||||||
extent += extent < 0 ? 360 : -360;
|
extent += extent < 0 ? 360 : -360;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
if (extent) {
|
||||||
ext = abs(extent),
|
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
||||||
// Calculate the amount of segments required to approximate over
|
ext = abs(extent),
|
||||||
// `extend` degrees (extend / 90), but prevent ceil() from
|
// Calculate amount of segments required to approximate over
|
||||||
// rounding up small imprecisions by subtracting epsilon first.
|
// `extend` degrees (extend / 90), but prevent ceil() from
|
||||||
count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90),
|
// rounding up small imprecisions by subtracting epsilon.
|
||||||
inc = extent / count,
|
count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90),
|
||||||
half = inc * Math.PI / 360,
|
inc = extent / count,
|
||||||
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
|
half = inc * Math.PI / 360,
|
||||||
segments = [];
|
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
|
||||||
for (var i = 0; i <= count; i++) {
|
segments = [];
|
||||||
// Explicitly use to point for last segment, since depending
|
for (var i = 0; i <= count; i++) {
|
||||||
// on values the calculation adds imprecision:
|
// Explicitly use to point for last segment, since depending
|
||||||
var pt = to,
|
// on values the calculation adds imprecision:
|
||||||
out = null;
|
var pt = to,
|
||||||
if (i < count) {
|
out = null;
|
||||||
out = vector.rotate(90).multiply(z);
|
if (i < count) {
|
||||||
if (matrix) {
|
out = vector.rotate(90).multiply(z);
|
||||||
pt = matrix._transformPoint(vector);
|
if (matrix) {
|
||||||
out = matrix._transformPoint(vector.add(out))
|
pt = matrix._transformPoint(vector);
|
||||||
.subtract(pt);
|
out = matrix._transformPoint(vector.add(out))
|
||||||
|
.subtract(pt);
|
||||||
|
} else {
|
||||||
|
pt = center.add(vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!i) {
|
||||||
|
// Modify startSegment
|
||||||
|
current.setHandleOut(out);
|
||||||
} else {
|
} 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) {
|
// Add all segments at once at the end for higher performance
|
||||||
// Modify startSegment
|
this._add(segments);
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
lineBy: function(/* to */) {
|
lineBy: function(/* to */) {
|
||||||
|
@ -2618,40 +2631,44 @@ new function() { // PostScript-style drawing commands
|
||||||
},
|
},
|
||||||
|
|
||||||
curveBy: function(/* through, to, parameter */) {
|
curveBy: function(/* through, to, parameter */) {
|
||||||
var through = Point.read(arguments),
|
var args = arguments,
|
||||||
to = Point.read(arguments),
|
through = Point.read(args),
|
||||||
parameter = Base.read(arguments),
|
to = Point.read(args),
|
||||||
|
parameter = Base.read(args),
|
||||||
current = getCurrentSegment(this)._point;
|
current = getCurrentSegment(this)._point;
|
||||||
this.curveTo(current.add(through), current.add(to), parameter);
|
this.curveTo(current.add(through), current.add(to), parameter);
|
||||||
},
|
},
|
||||||
|
|
||||||
cubicCurveBy: function(/* handle1, handle2, to */) {
|
cubicCurveBy: function(/* handle1, handle2, to */) {
|
||||||
var handle1 = Point.read(arguments),
|
var args = arguments,
|
||||||
handle2 = Point.read(arguments),
|
handle1 = Point.read(args),
|
||||||
to = Point.read(arguments),
|
handle2 = Point.read(args),
|
||||||
|
to = Point.read(args),
|
||||||
current = getCurrentSegment(this)._point;
|
current = getCurrentSegment(this)._point;
|
||||||
this.cubicCurveTo(current.add(handle1), current.add(handle2),
|
this.cubicCurveTo(current.add(handle1), current.add(handle2),
|
||||||
current.add(to));
|
current.add(to));
|
||||||
},
|
},
|
||||||
|
|
||||||
quadraticCurveBy: function(/* handle, to */) {
|
quadraticCurveBy: function(/* handle, to */) {
|
||||||
var handle = Point.read(arguments),
|
var args = arguments,
|
||||||
to = Point.read(arguments),
|
handle = Point.read(args),
|
||||||
|
to = Point.read(args),
|
||||||
current = getCurrentSegment(this)._point;
|
current = getCurrentSegment(this)._point;
|
||||||
this.quadraticCurveTo(current.add(handle), current.add(to));
|
this.quadraticCurveTo(current.add(handle), current.add(to));
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Implement version for: (to, radius, rotation, clockwise, large)
|
// TODO: Implement version for: (to, radius, rotation, clockwise, large)
|
||||||
arcBy: function(/* to, clockwise | through, to */) {
|
arcBy: function(/* to, clockwise | through, to */) {
|
||||||
var current = getCurrentSegment(this)._point,
|
var args = arguments,
|
||||||
point = current.add(Point.read(arguments)),
|
current = getCurrentSegment(this)._point,
|
||||||
|
point = current.add(Point.read(args)),
|
||||||
// Peek at next value to see if it's clockwise, with true as
|
// Peek at next value to see if it's clockwise, with true as
|
||||||
// default value.
|
// default value.
|
||||||
clockwise = Base.pick(Base.peek(arguments), true);
|
clockwise = Base.pick(Base.peek(args), true);
|
||||||
if (typeof clockwise === 'boolean') {
|
if (typeof clockwise === 'boolean') {
|
||||||
this.arcTo(point, clockwise);
|
this.arcTo(point, clockwise);
|
||||||
} else {
|
} else {
|
||||||
this.arcTo(point, current.add(Point.read(arguments)));
|
this.arcTo(point, current.add(Point.read(args)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2780,15 +2797,18 @@ statics: {
|
||||||
}
|
}
|
||||||
|
|
||||||
var length = segments.length - (closed ? 0 : 1);
|
var length = segments.length - (closed ? 0 : 1);
|
||||||
for (var i = 1; i < length; i++)
|
if (length > 0) {
|
||||||
addJoin(segments[i], join);
|
for (var i = 1; i < length; i++) {
|
||||||
if (closed) {
|
addJoin(segments[i], join);
|
||||||
// Go back to the beginning
|
}
|
||||||
addJoin(segments[0], join);
|
if (closed) {
|
||||||
} else if (length > 0) {
|
// Go back to the beginning
|
||||||
// Handle caps on open paths
|
addJoin(segments[0], join);
|
||||||
addCap(segments[0], cap);
|
} else {
|
||||||
addCap(segments[segments.length - 1], cap);
|
// Handle caps on open paths
|
||||||
|
addCap(segments[0], cap);
|
||||||
|
addCap(segments[segments.length - 1], cap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return bounds;
|
return bounds;
|
||||||
},
|
},
|
||||||
|
@ -2846,8 +2866,9 @@ statics: {
|
||||||
normal1 = curve1.getNormalAtTime(1).multiply(radius)
|
normal1 = curve1.getNormalAtTime(1).multiply(radius)
|
||||||
.transform(strokeMatrix),
|
.transform(strokeMatrix),
|
||||||
normal2 = curve2.getNormalAtTime(0).multiply(radius)
|
normal2 = curve2.getNormalAtTime(0).multiply(radius)
|
||||||
.transform(strokeMatrix);
|
.transform(strokeMatrix),
|
||||||
if (normal1.getDirectedAngle(normal2) < 0) {
|
angle = normal1.getDirectedAngle(normal2);
|
||||||
|
if (angle < 0 || angle >= 180) {
|
||||||
normal1 = normal1.negate();
|
normal1 = normal1.negate();
|
||||||
normal2 = normal2.negate();
|
normal2 = normal2.negate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
// An Algorithm for Automatically Fitting Digitized Curves
|
// An Algorithm for Automatically Fitting Digitized Curves
|
||||||
// by Philip J. Schneider
|
// by Philip J. Schneider
|
||||||
// from "Graphics Gems", Academic Press, 1990
|
// from "Graphics Gems", Academic Press, 1990
|
||||||
// Modifications and optimizations of original algorithm by Juerg Lehni.
|
// Modifications and optimizations of original algorithm by Jürg Lehni.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name PathFitter
|
* @name PathFitter
|
||||||
|
@ -231,7 +231,7 @@ var PathFitter = Base.extend({
|
||||||
diff = pt.subtract(point),
|
diff = pt.subtract(point),
|
||||||
df = pt1.dot(pt1) + diff.dot(pt2);
|
df = pt1.dot(pt1) + diff.dot(pt2);
|
||||||
// u = u - f(u) / f'(u)
|
// u = u - f(u) / f'(u)
|
||||||
return Numerical.isZero(df) ? u : u - diff.dot(pt1) / df;
|
return Numerical.isMachineZero(df) ? u : u - diff.dot(pt1) / df;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Evaluate a bezier curve at a particular parameter value
|
// Evaluate a bezier curve at a particular parameter value
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -23,9 +23,8 @@
|
||||||
* - Boolean operations on self-intersecting Paths items
|
* - Boolean operations on self-intersecting Paths items
|
||||||
*
|
*
|
||||||
* @author Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
* @author Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
||||||
* @author Jan Boesenberg <development@iconexperience.com>
|
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
|
||||||
* @author Juerg Lehni <juerg@scratchdisk.com>
|
* @author Jürg Lehni <juerg@scratchdisk.com>
|
||||||
* http://hkrish.com/playground/paperjs/booleanStudy.html
|
|
||||||
*/
|
*/
|
||||||
PathItem.inject(new function() {
|
PathItem.inject(new function() {
|
||||||
var min = Math.min,
|
var min = Math.min,
|
||||||
|
@ -46,6 +45,10 @@ PathItem.inject(new function() {
|
||||||
exclude: { '1': true, '-1': true }
|
exclude: { '1': true, '-1': true }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getPaths(path) {
|
||||||
|
return path._children || [path];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a clone of the path that we can modify freely, with its matrix
|
* Creates a clone of the path that we can modify freely, with its matrix
|
||||||
* applied to its geometry. Calls #reduce() to simplify compound paths and
|
* applied to its geometry. Calls #reduce() to simplify compound paths and
|
||||||
|
@ -53,12 +56,28 @@ PathItem.inject(new function() {
|
||||||
* make sure all paths have correct winding direction.
|
* make sure all paths have correct winding direction.
|
||||||
*/
|
*/
|
||||||
function preparePath(path, resolve) {
|
function preparePath(path, resolve) {
|
||||||
var res = path.clone(false).reduce({ simplify: true })
|
var res = path
|
||||||
.transform(null, true, true);
|
.clone(false)
|
||||||
return resolve
|
.reduce({ simplify: true })
|
||||||
? res.resolveCrossings().reorient(
|
.transform(null, true, true);
|
||||||
res.getFillRule() === 'nonzero', true)
|
if (resolve) {
|
||||||
: res;
|
// For correct results, close open paths with straight lines:
|
||||||
|
var paths = getPaths(res);
|
||||||
|
for (var i = 0, l = paths.length; i < l; i++) {
|
||||||
|
var path = paths[i];
|
||||||
|
if (!path._closed && !path.isEmpty()) {
|
||||||
|
// Close with epsilon tolerance, to avoid tiny straight
|
||||||
|
// that would cause issues with intersection detection.
|
||||||
|
path.closePath(/*#=*/Numerical.EPSILON);
|
||||||
|
path.getFirstSegment().setHandleIn(0, 0);
|
||||||
|
path.getLastSegment().setHandleOut(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = res
|
||||||
|
.resolveCrossings()
|
||||||
|
.reorient(res.getFillRule() === 'nonzero', true);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResult(paths, simplify, path1, path2, options) {
|
function createResult(paths, simplify, path1, path2, options) {
|
||||||
|
@ -77,6 +96,17 @@ PathItem.inject(new function() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterIntersection(inter) {
|
||||||
|
// TODO: Change isCrossing() to also handle overlaps (hasOverlap())
|
||||||
|
// that are actually involved in a crossing! For this we need proper
|
||||||
|
// overlap range detection / merging first... But as we call
|
||||||
|
// #resolveCrossings() first in boolean operations, removing all
|
||||||
|
// self-touching areas in paths, this works for the known use cases.
|
||||||
|
// The ideal implementation would deal with it in a way outlined in:
|
||||||
|
// https://github.com/paperjs/paper.js/issues/874#issuecomment-168332391
|
||||||
|
return inter.hasOverlap() || inter.isCrossing();
|
||||||
|
}
|
||||||
|
|
||||||
function traceBoolean(path1, path2, operation, options) {
|
function traceBoolean(path1, path2, operation, options) {
|
||||||
// Only support subtract and intersect operations when computing stroke
|
// Only support subtract and intersect operations when computing stroke
|
||||||
// based boolean operations (options.split = true).
|
// based boolean operations (options.split = true).
|
||||||
|
@ -101,15 +131,15 @@ PathItem.inject(new function() {
|
||||||
_path2.reverse();
|
_path2.reverse();
|
||||||
// Split curves at crossings on both paths. Note that for self-
|
// Split curves at crossings on both paths. Note that for self-
|
||||||
// intersection, path2 is null and getIntersections() handles it.
|
// intersection, path2 is null and getIntersections() handles it.
|
||||||
var crossings = divideLocations(
|
var crossings = divideLocations(CurveLocation.expand(
|
||||||
CurveLocation.expand(_path1.getCrossings(_path2))),
|
_path1.getIntersections(_path2, filterIntersection))),
|
||||||
paths1 = _path1._children || [_path1],
|
paths1 = getPaths(_path1),
|
||||||
paths2 = _path2 && (_path2._children || [_path2]),
|
paths2 = _path2 && getPaths(_path2),
|
||||||
segments = [],
|
segments = [],
|
||||||
curves = [],
|
curves = [],
|
||||||
paths;
|
paths;
|
||||||
|
|
||||||
function collect(paths) {
|
function collectPaths(paths) {
|
||||||
for (var i = 0, l = paths.length; i < l; i++) {
|
for (var i = 0, l = paths.length; i < l; i++) {
|
||||||
var path = paths[i];
|
var path = paths[i];
|
||||||
Base.push(segments, path._segments);
|
Base.push(segments, path._segments);
|
||||||
|
@ -120,24 +150,51 @@ PathItem.inject(new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurves(indices) {
|
||||||
|
var list = [];
|
||||||
|
for (var i = 0, l = indices && indices.length; i < l; i++) {
|
||||||
|
list.push(curves[indices[i]]);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
if (crossings.length) {
|
if (crossings.length) {
|
||||||
// Collect all segments and curves of both involved operands.
|
// Collect all segments and curves of both involved operands.
|
||||||
collect(paths1);
|
collectPaths(paths1);
|
||||||
if (paths2)
|
if (paths2)
|
||||||
collect(paths2);
|
collectPaths(paths2);
|
||||||
|
|
||||||
|
var curvesValues = new Array(curves.length);
|
||||||
|
for (var i = 0, l = curves.length; i < l; i++) {
|
||||||
|
curvesValues[i] = curves[i].getValues();
|
||||||
|
}
|
||||||
|
var curveCollisions = CollisionDetection.findCurveBoundsCollisions(
|
||||||
|
curvesValues, curvesValues, 0, true);
|
||||||
|
var curveCollisionsMap = {};
|
||||||
|
for (var i = 0; i < curves.length; i++) {
|
||||||
|
var curve = curves[i],
|
||||||
|
id = curve._path._id,
|
||||||
|
map = curveCollisionsMap[id] = curveCollisionsMap[id] || {};
|
||||||
|
map[curve.getIndex()] = {
|
||||||
|
hor: getCurves(curveCollisions[i].hor),
|
||||||
|
ver: getCurves(curveCollisions[i].ver)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Propagate the winding contribution. Winding contribution of
|
// Propagate the winding contribution. Winding contribution of
|
||||||
// curves does not change between two crossings.
|
// curves does not change between two crossings.
|
||||||
// First, propagate winding contributions for curve chains starting
|
// First, propagate winding contributions for curve chains starting
|
||||||
// in all crossings:
|
// in all crossings:
|
||||||
for (var i = 0, l = crossings.length; i < l; i++) {
|
for (var i = 0, l = crossings.length; i < l; i++) {
|
||||||
propagateWinding(crossings[i]._segment, _path1, _path2, curves,
|
propagateWinding(crossings[i]._segment, _path1, _path2,
|
||||||
operator);
|
curveCollisionsMap, operator);
|
||||||
}
|
}
|
||||||
for (var i = 0, l = segments.length; i < l; i++) {
|
for (var i = 0, l = segments.length; i < l; i++) {
|
||||||
var segment = segments[i],
|
var segment = segments[i],
|
||||||
inter = segment._intersection;
|
inter = segment._intersection;
|
||||||
if (!segment._winding) {
|
if (!segment._winding) {
|
||||||
propagateWinding(segment, _path1, _path2, curves, operator);
|
propagateWinding(segment, _path1, _path2,
|
||||||
|
curveCollisionsMap, operator);
|
||||||
}
|
}
|
||||||
// See if all encountered segments in a path are overlaps.
|
// See if all encountered segments in a path are overlaps.
|
||||||
if (!(inter && inter._overlap))
|
if (!(inter && inter._overlap))
|
||||||
|
@ -155,14 +212,13 @@ PathItem.inject(new function() {
|
||||||
return !!operator[w];
|
return !!operator[w];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return createResult(paths, true, path1, path2, options);
|
return createResult(paths, true, path1, path2, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitBoolean(path1, path2, operation) {
|
function splitBoolean(path1, path2, operation) {
|
||||||
var _path1 = preparePath(path1),
|
var _path1 = preparePath(path1),
|
||||||
_path2 = preparePath(path2),
|
_path2 = preparePath(path2),
|
||||||
crossings = _path1.getCrossings(_path2),
|
crossings = _path1.getIntersections(_path2, filterIntersection),
|
||||||
subtract = operation === 'subtract',
|
subtract = operation === 'subtract',
|
||||||
divide = operation === 'divide',
|
divide = operation === 'divide',
|
||||||
added = {},
|
added = {},
|
||||||
|
@ -269,29 +325,39 @@ PathItem.inject(new function() {
|
||||||
// Get reference to the first, largest path and insert it
|
// Get reference to the first, largest path and insert it
|
||||||
// already.
|
// already.
|
||||||
first = sorted[0];
|
first = sorted[0];
|
||||||
|
// create lookup containing potentially overlapping path bounds
|
||||||
|
var collisions = CollisionDetection.findItemBoundsCollisions(sorted,
|
||||||
|
null, Numerical.GEOMETRIC_EPSILON);
|
||||||
if (clockwise == null)
|
if (clockwise == null)
|
||||||
clockwise = first.isClockwise();
|
clockwise = first.isClockwise();
|
||||||
// Now determine the winding for each path, from large to small.
|
// Now determine the winding for each path, from large to small.
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
var path1 = sorted[i],
|
var path1 = sorted[i],
|
||||||
entry1 = lookup[path1._id],
|
entry1 = lookup[path1._id],
|
||||||
point = path1.getInteriorPoint(),
|
containerWinding = 0,
|
||||||
containerWinding = 0;
|
indices = collisions[i];
|
||||||
for (var j = i - 1; j >= 0; j--) {
|
if (indices) {
|
||||||
var path2 = sorted[j];
|
var point = null; // interior point, only get it if required.
|
||||||
// As we run through the paths from largest to smallest, for
|
for (var j = indices.length - 1; j >= 0; j--) {
|
||||||
// any current path, all potentially containing paths have
|
if (indices[j] < i) {
|
||||||
// already been processed and their orientation fixed.
|
point = point || path1.getInteriorPoint();
|
||||||
// To achieve correct orientation of contained paths based
|
var path2 = sorted[indices[j]];
|
||||||
// on winding, we have to find one containing path with
|
// As we run through the paths from largest to
|
||||||
// different "insideness" and set opposite orientation.
|
// smallest, for any current path, all potentially
|
||||||
if (path2.contains(point)) {
|
// containing paths have already been processed and
|
||||||
var entry2 = lookup[path2._id];
|
// their orientation fixed. To achieve correct
|
||||||
containerWinding = entry2.winding;
|
// orientation of contained paths based on winding,
|
||||||
entry1.winding += containerWinding;
|
// find one containing path with different
|
||||||
entry1.container = entry2.exclude ? entry2.container
|
// "insideness" and set opposite orientation.
|
||||||
: path2;
|
if (path2.contains(point)) {
|
||||||
break;
|
var entry2 = lookup[path2._id];
|
||||||
|
containerWinding = entry2.winding;
|
||||||
|
entry1.winding += containerWinding;
|
||||||
|
entry1.container = entry2.exclude
|
||||||
|
? entry2.container : path2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Only keep paths if the "insideness" changes when crossing the
|
// Only keep paths if the "insideness" changes when crossing the
|
||||||
|
@ -306,8 +372,8 @@ PathItem.inject(new function() {
|
||||||
// If the containing path is not excluded, we're done
|
// If the containing path is not excluded, we're done
|
||||||
// searching for the orientation defining path.
|
// searching for the orientation defining path.
|
||||||
var container = entry1.container;
|
var container = entry1.container;
|
||||||
path1.setClockwise(container ? !container.isClockwise()
|
path1.setClockwise(
|
||||||
: clockwise);
|
container ? !container.isClockwise() : clockwise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,9 +518,9 @@ PathItem.inject(new function() {
|
||||||
*
|
*
|
||||||
* @param {Point} point the location for which to determine the winding
|
* @param {Point} point the location for which to determine the winding
|
||||||
* contribution
|
* contribution
|
||||||
* @param {Curve[]} curves the curves that describe the shape against which
|
* @param {Curve[]} curves The curves that describe the shape against which
|
||||||
* to check, as returned by {@link Path#curves} or
|
* to check, as returned by {@link Path#curves} or
|
||||||
* {@link CompoundPath#curves}
|
* {@link CompoundPath#curves}.
|
||||||
* @param {Boolean} [dir=false] the direction in which to determine the
|
* @param {Boolean} [dir=false] the direction in which to determine the
|
||||||
* winding contribution, `false`: in x-direction, `true`: in y-direction
|
* winding contribution, `false`: in x-direction, `true`: in y-direction
|
||||||
* @param {Boolean} [closed=false] determines how areas should be closed
|
* @param {Boolean} [closed=false] determines how areas should be closed
|
||||||
|
@ -468,6 +534,13 @@ PathItem.inject(new function() {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function getWinding(point, curves, dir, closed, dontFlip) {
|
function getWinding(point, curves, dir, closed, dontFlip) {
|
||||||
|
// `curves` can either be an array of curves, or an object containing of
|
||||||
|
// the form `{ hor: [], ver: [] }` (see `curveCollisionsMap`), with each
|
||||||
|
// key / value pair holding only those curves that can be crossed by a
|
||||||
|
// horizontal / vertical line through the point to be checked.
|
||||||
|
var curvesList = Array.isArray(curves)
|
||||||
|
? curves
|
||||||
|
: curves[dir ? 'hor' : 'ver'];
|
||||||
// Determine the index of the abscissa and ordinate values in the curve
|
// Determine the index of the abscissa and ordinate values in the curve
|
||||||
// values arrays, based on the direction:
|
// values arrays, based on the direction:
|
||||||
var ia = dir ? 1 : 0, // the abscissa index
|
var ia = dir ? 1 : 0, // the abscissa index
|
||||||
|
@ -573,9 +646,7 @@ PathItem.inject(new function() {
|
||||||
onPath = true;
|
onPath = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Determine how to handle quality when curve is crossed
|
quality /= 4;
|
||||||
// at starting point. Do we always need to set to 0?
|
|
||||||
quality = 0;
|
|
||||||
}
|
}
|
||||||
vPrev = v;
|
vPrev = v;
|
||||||
// If we're on the curve, look at the tangent to decide whether to
|
// If we're on the curve, look at the tangent to decide whether to
|
||||||
|
@ -615,12 +686,12 @@ PathItem.inject(new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0, l = curves.length; i < l; i++) {
|
for (var i = 0, l = curvesList.length; i < l; i++) {
|
||||||
var curve = curves[i],
|
var curve = curvesList[i],
|
||||||
path = curve._path,
|
path = curve._path,
|
||||||
v = curve.getValues(),
|
v = curve.getValues(),
|
||||||
res;
|
res;
|
||||||
if (!i || curves[i - 1]._path !== path) {
|
if (!i || curvesList[i - 1]._path !== path) {
|
||||||
// We're on a new (sub-)path, so we need to determine values of
|
// We're on a new (sub-)path, so we need to determine values of
|
||||||
// the last non-horizontal curve on this path.
|
// the last non-horizontal curve on this path.
|
||||||
vPrev = null;
|
vPrev = null;
|
||||||
|
@ -664,7 +735,7 @@ PathItem.inject(new function() {
|
||||||
if (res = handleCurve(v))
|
if (res = handleCurve(v))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
if (i + 1 === l || curves[i + 1]._path !== path) {
|
if (i + 1 === l || curvesList[i + 1]._path !== path) {
|
||||||
// We're at the last curve of the current (sub-)path. If a
|
// We're at the last curve of the current (sub-)path. If a
|
||||||
// closing curve was calculated at the beginning of it, handle
|
// closing curve was calculated at the beginning of it, handle
|
||||||
// it now to treat the path as closed:
|
// it now to treat the path as closed:
|
||||||
|
@ -705,7 +776,8 @@ PathItem.inject(new function() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function propagateWinding(segment, path1, path2, curves, operator) {
|
function propagateWinding(segment, path1, path2, curveCollisionsMap,
|
||||||
|
operator) {
|
||||||
// Here we try to determine the most likely winding number contribution
|
// Here we try to determine the most likely winding number contribution
|
||||||
// for the curve-chain starting with this segment. Once we have enough
|
// for the curve-chain starting with this segment. Once we have enough
|
||||||
// confidence in the winding contribution, we can propagate it until the
|
// confidence in the winding contribution, we can propagate it until the
|
||||||
|
@ -715,10 +787,14 @@ PathItem.inject(new function() {
|
||||||
totalLength = 0,
|
totalLength = 0,
|
||||||
winding;
|
winding;
|
||||||
do {
|
do {
|
||||||
var curve = segment.getCurve(),
|
var curve = segment.getCurve();
|
||||||
length = curve.getLength();
|
// We can encounter paths with only one segment, which would not
|
||||||
chain.push({ segment: segment, curve: curve, length: length });
|
// have a curve.
|
||||||
totalLength += length;
|
if (curve) {
|
||||||
|
var length = curve.getLength();
|
||||||
|
chain.push({ segment: segment, curve: curve, length: length });
|
||||||
|
totalLength += length;
|
||||||
|
}
|
||||||
segment = segment.getNext();
|
segment = segment.getNext();
|
||||||
} while (segment && !segment._intersection && segment !== start);
|
} while (segment && !segment._intersection && segment !== start);
|
||||||
// Determine winding at three points in the chain. If a winding with
|
// Determine winding at three points in the chain. If a winding with
|
||||||
|
@ -726,7 +802,8 @@ PathItem.inject(new function() {
|
||||||
// the best quality.
|
// the best quality.
|
||||||
var offsets = [0.5, 0.25, 0.75],
|
var offsets = [0.5, 0.25, 0.75],
|
||||||
winding = { winding: 0, quality: -1 },
|
winding = { winding: 0, quality: -1 },
|
||||||
tMin = /*#=*/Numerical.CURVETIME_EPSILON,
|
// Don't go too close to segments, to avoid special winding cases:
|
||||||
|
tMin = 1e-3,
|
||||||
tMax = 1 - tMin;
|
tMax = 1 - tMin;
|
||||||
for (var i = 0; i < offsets.length && winding.quality < 0.5; i++) {
|
for (var i = 0; i < offsets.length && winding.quality < 0.5; i++) {
|
||||||
var length = totalLength * offsets[i];
|
var length = totalLength * offsets[i];
|
||||||
|
@ -751,9 +828,8 @@ PathItem.inject(new function() {
|
||||||
var wind = null;
|
var wind = null;
|
||||||
if (operator.subtract && path2) {
|
if (operator.subtract && path2) {
|
||||||
// Calculate path winding at point depending on operand.
|
// Calculate path winding at point depending on operand.
|
||||||
var pathWinding = operand === path1
|
var otherPath = operand === path1 ? path2 : path1,
|
||||||
? path2._getWinding(pt, dir, true)
|
pathWinding = otherPath._getWinding(pt, dir, true);
|
||||||
: path1._getWinding(pt, dir, true);
|
|
||||||
// Check if curve should be omitted.
|
// Check if curve should be omitted.
|
||||||
if (operand === path1 && pathWinding.winding ||
|
if (operand === path1 && pathWinding.winding ||
|
||||||
operand === path2 && !pathWinding.winding) {
|
operand === path2 && !pathWinding.winding) {
|
||||||
|
@ -767,7 +843,9 @@ PathItem.inject(new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wind = wind || getWinding(pt, curves, dir, true);
|
wind = wind || getWinding(
|
||||||
|
pt, curveCollisionsMap[path._id][curve.getIndex()],
|
||||||
|
dir, true);
|
||||||
if (wind.quality > winding.quality)
|
if (wind.quality > winding.quality)
|
||||||
winding = wind;
|
winding = wind;
|
||||||
break;
|
break;
|
||||||
|
@ -865,8 +943,8 @@ PathItem.inject(new function() {
|
||||||
collect(inter);
|
collect(inter);
|
||||||
// Find the beginning of the linked intersections and loop all
|
// Find the beginning of the linked intersections and loop all
|
||||||
// the way back to start, to collect all valid intersections.
|
// the way back to start, to collect all valid intersections.
|
||||||
while (inter && inter._prev)
|
while (inter && inter._previous)
|
||||||
inter = inter._prev;
|
inter = inter._previous;
|
||||||
collect(inter, start);
|
collect(inter, start);
|
||||||
}
|
}
|
||||||
return crossings;
|
return crossings;
|
||||||
|
@ -1125,7 +1203,7 @@ PathItem.inject(new function() {
|
||||||
/**
|
/**
|
||||||
* Splits the geometry of this path along the geometry of the specified
|
* 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
|
* 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.
|
* putting the results into a new group.
|
||||||
*
|
*
|
||||||
* @option [options.insert=true] {Boolean} whether the resulting item
|
* @option [options.insert=true] {Boolean} whether the resulting item
|
||||||
|
@ -1156,7 +1234,7 @@ PathItem.inject(new function() {
|
||||||
* amount of resulting paths allows so, otherwise a new path /
|
* amount of resulting paths allows so, otherwise a new path /
|
||||||
* compound-path is created, replacing the current one.
|
* compound-path is created, replacing the current one.
|
||||||
*
|
*
|
||||||
* @return {PahtItem} the resulting path item
|
* @return {PathItem} the resulting path item
|
||||||
*/
|
*/
|
||||||
resolveCrossings: function() {
|
resolveCrossings: function() {
|
||||||
var children = this._children,
|
var children = this._children,
|
||||||
|
@ -1168,7 +1246,7 @@ PathItem.inject(new function() {
|
||||||
return inter && inter._overlap && inter._path === path;
|
return inter && inter._overlap && inter._path === path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First collect all overlaps and crossings while taking not of the
|
// First collect all overlaps and crossings while taking note of the
|
||||||
// existence of both.
|
// existence of both.
|
||||||
var hasOverlaps = false,
|
var hasOverlaps = false,
|
||||||
hasCrossings = false,
|
hasCrossings = false,
|
||||||
|
@ -1278,7 +1356,7 @@ PathItem.inject(new function() {
|
||||||
* @param {Boolean} [clockwise] if provided, the orientation of the root
|
* @param {Boolean} [clockwise] if provided, the orientation of the root
|
||||||
* paths will be set to the orientation specified by `clockwise`,
|
* paths will be set to the orientation specified by `clockwise`,
|
||||||
* otherwise the orientation of the largest root child is used.
|
* 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) {
|
reorient: function(nonZero, clockwise) {
|
||||||
var children = this._children;
|
var children = this._children;
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -102,8 +102,8 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
*
|
*
|
||||||
* @bean
|
* @bean
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
* @see Path#getArea()
|
* @see Path#area
|
||||||
* @see CompoundPath#getArea()
|
* @see CompoundPath#area
|
||||||
*/
|
*/
|
||||||
isClockwise: function() {
|
isClockwise: function() {
|
||||||
return this.getArea() >= 0;
|
return this.getArea() >= 0;
|
||||||
|
@ -345,18 +345,13 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
* crossing each other, as opposed to simply touching.
|
* crossing each other, as opposed to simply touching.
|
||||||
*
|
*
|
||||||
* @param {PathItem} path the other item to find the crossings with
|
* @param {PathItem} path the other item to find the crossings with
|
||||||
|
* @return {CurveLocation[]} the locations of all crossings between the
|
||||||
|
* paths
|
||||||
* @see #getIntersections(path)
|
* @see #getIntersections(path)
|
||||||
*/
|
*/
|
||||||
getCrossings: function(path) {
|
getCrossings: function(path) {
|
||||||
return this.getIntersections(path, function(inter) {
|
return this.getIntersections(path, function(inter) {
|
||||||
// TODO: Only return overlaps that are actually crossings! For this
|
return inter.isCrossing();
|
||||||
// we need proper overlap range detection / merging first...
|
|
||||||
// But as we call #resolveCrossings() first in boolean operations,
|
|
||||||
// removing all self-touching areas in paths, this currently works
|
|
||||||
// as it should in the known use cases.
|
|
||||||
// The ideal implementation would deal with it in a way outlined in:
|
|
||||||
// https://github.com/paperjs/paper.js/issues/874#issuecomment-168332391
|
|
||||||
return inter.hasOverlap() || inter.isCrossing();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -727,16 +722,20 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
matched = [],
|
matched = [],
|
||||||
count = 0;
|
count = 0;
|
||||||
ok = true;
|
ok = true;
|
||||||
|
var boundsOverlaps = CollisionDetection.findItemBoundsCollisions(paths1, paths2, Numerical.GEOMETRIC_EPSILON);
|
||||||
for (var i1 = length1 - 1; i1 >= 0 && ok; i1--) {
|
for (var i1 = length1 - 1; i1 >= 0 && ok; i1--) {
|
||||||
var path1 = paths1[i1];
|
var path1 = paths1[i1];
|
||||||
ok = false;
|
ok = false;
|
||||||
for (var i2 = length2 - 1; i2 >= 0 && !ok; i2--) {
|
var pathBoundsOverlaps = boundsOverlaps[i1];
|
||||||
if (path1.compare(paths2[i2])) {
|
if (pathBoundsOverlaps) {
|
||||||
if (!matched[i2]) {
|
for (var i2 = pathBoundsOverlaps.length - 1; i2 >= 0 && !ok; i2--) {
|
||||||
matched[i2] = true;
|
if (path1.compare(paths2[pathBoundsOverlaps[i2]])) {
|
||||||
count++;
|
if (!matched[pathBoundsOverlaps[i2]]) {
|
||||||
|
matched[pathBoundsOverlaps[i2]] = true;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
ok = true;
|
||||||
}
|
}
|
||||||
ok = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
* Checks if the segment has any curve handles set.
|
||||||
*
|
*
|
||||||
* @return {Boolean} {@true if the segment has handles set}
|
* @return {Boolean} {@true if the segment has handles set}
|
||||||
* @see Segment#getHandleIn()
|
* @see Segment#handleIn
|
||||||
* @see Segment#getHandleOut()
|
* @see Segment#handleOut
|
||||||
* @see Curve#hasHandles()
|
* @see Curve#hasHandles()
|
||||||
* @see Path#hasHandles()
|
* @see Path#hasHandles()
|
||||||
*/
|
*/
|
||||||
|
@ -554,6 +554,9 @@ var Segment = Base.extend(/** @lends Segment# */{
|
||||||
return this._path ? !!this._path.removeSegment(this._index) : false;
|
return this._path ? !!this._path.removeSegment(this._index) : false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Segment}
|
||||||
|
*/
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new Segment(this._point, this._handleIn, this._handleOut);
|
return new Segment(this._point, this._handleIn, this._handleOut);
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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?\((.*)\)$/)) {
|
} else if (match = string.match(/^(rgb|hsl)a?\((.*)\)$/)) {
|
||||||
// RGB / RGBA or HSL / HSLA
|
// RGB / RGBA or HSL / HSLA
|
||||||
type = match[1];
|
type = match[1];
|
||||||
components = match[2].split(/[,\s]+/g);
|
components = match[2].trim().split(/[,\s]+/g);
|
||||||
var isHSL = type === 'hsl';
|
var isHSL = type === 'hsl';
|
||||||
for (var i = 0, l = Math.min(components.length, 4); i < l; i++) {
|
for (var i = 0, l = Math.min(components.length, 4); i < l; i++) {
|
||||||
var component = components[i];
|
var component = components[i];
|
||||||
|
@ -102,7 +102,7 @@ var Color = Base.extend(new function() {
|
||||||
}
|
}
|
||||||
} else if (i < 3) {
|
} else if (i < 3) {
|
||||||
// RGB color values to 0..1
|
// RGB color values to 0..1
|
||||||
value /= 255;
|
value /= /%$/.test(component) ? 100 : 255;
|
||||||
}
|
}
|
||||||
components[i] = value;
|
components[i] = value;
|
||||||
}
|
}
|
||||||
|
@ -691,6 +691,8 @@ var Color = Base.extend(new function() {
|
||||||
* constructors also work for calls of `set()`.
|
* constructors also work for calls of `set()`.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
|
* @param {...*} values
|
||||||
|
* @return {Color}
|
||||||
*/
|
*/
|
||||||
set: '#initialize',
|
set: '#initialize',
|
||||||
|
|
||||||
|
@ -709,8 +711,13 @@ var Color = Base.extend(new function() {
|
||||||
*/
|
*/
|
||||||
_changed: function() {
|
_changed: function() {
|
||||||
this._canvasStyle = null;
|
this._canvasStyle = null;
|
||||||
if (this._owner)
|
if (this._owner) {
|
||||||
this._owner._changed(/*#=*/Change.STYLE);
|
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:
|
* @param {String} type the color type to convert to. Possible values:
|
||||||
* {@values 'rgb', 'gray', 'hsb', 'hsl'}
|
* {@values 'rgb', 'gray', 'hsb', 'hsl'}
|
||||||
|
@ -1183,9 +1190,35 @@ var Color = Base.extend(new function() {
|
||||||
// Export for backward compatibility code below.
|
// Export for backward compatibility code below.
|
||||||
_types: types,
|
_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() {
|
random: function() {
|
||||||
var random = Math.random;
|
var random = Math.random;
|
||||||
return new Color(random(), random(), 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -175,12 +175,10 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
setColor: function(/* color */) {
|
setColor: function(/* color */) {
|
||||||
// Make sure newly set colors are cloned, since they can only have
|
// Clear old color owner before setting new one:
|
||||||
// one owner.
|
Color._setOwner(this._color, null);
|
||||||
var color = Color.read(arguments, 0, { clone: true });
|
this._color = Color._setOwner(Color.read(arguments, 0), this,
|
||||||
if (color)
|
'setColor');
|
||||||
color._owner = this;
|
|
||||||
this._color = color;
|
|
||||||
this._changed();
|
this._changed();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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.
|
// raw value is stored, and conversion only happens in the getter.
|
||||||
fields[set] = function(value) {
|
fields[set] = function(value) {
|
||||||
var owner = this._owner,
|
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.
|
// Only unify styles on children of Groups, excluding CompoundPaths.
|
||||||
if (children && children.length > 0
|
if (applyToChildren) {
|
||||||
&& !(owner instanceof CompoundPath)) {
|
|
||||||
for (var i = 0, l = children.length; i < l; i++)
|
for (var i = 0, l = children.length; i < l; i++)
|
||||||
children[i]._style[set](value);
|
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];
|
var old = this._values[key];
|
||||||
if (old !== value) {
|
if (old !== value) {
|
||||||
if (isColor) {
|
if (isColor) {
|
||||||
// The old value may be a native string or other color
|
// The old value may be a native string or other color
|
||||||
// description that wasn't coerced to a color object yet
|
// description that wasn't coerced to a color object yet
|
||||||
if (old && old._owner !== undefined) {
|
if (old) {
|
||||||
old._owner = undefined;
|
Color._setOwner(old, null);
|
||||||
old._canvasStyle = null;
|
old._canvasStyle = null;
|
||||||
}
|
}
|
||||||
if (value && value.constructor === Color) {
|
if (value && value.constructor === Color) {
|
||||||
// Clone color if it already has an owner.
|
|
||||||
// NOTE: If value is not a Color, it is only
|
// NOTE: If value is not a Color, it is only
|
||||||
// converted and cloned in the getter further down.
|
// converted and cloned in the getter further down.
|
||||||
if (value._owner)
|
value = Color._setOwner(value, owner,
|
||||||
value = value.clone();
|
// Only provide a color-setter if the style
|
||||||
value._owner = owner;
|
// is to be applied to the children:
|
||||||
|
applyToChildren && set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NOTE: We do not convert the values to Colors in the
|
// 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) {
|
fields[get] = function(_dontMerge) {
|
||||||
var owner = this._owner,
|
var owner = this._owner,
|
||||||
children = owner && owner._children,
|
children = owner && owner._children,
|
||||||
|
applyToChildren = children && children.length > 0
|
||||||
|
&& !(owner instanceof CompoundPath),
|
||||||
value;
|
value;
|
||||||
// If the owner has children, walk through all of them and see if
|
// If the owner has children, walk through all of them and see if
|
||||||
// they all have the same style.
|
// they all have the same style.
|
||||||
// If true is passed for _dontMerge, don't merge children styles
|
// If true is passed for _dontMerge, don't merge children styles.
|
||||||
if (key in this._defaults && (!children || !children.length
|
if (applyToChildren && !_dontMerge) {
|
||||||
|| _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) {
|
|
||||||
for (var i = 0, l = children.length; i < l; i++) {
|
for (var i = 0, l = children.length; i < l; i++) {
|
||||||
var childValue = children[i]._style[get]();
|
var childValue = children[i]._style[get]();
|
||||||
if (!i) {
|
if (!i) {
|
||||||
|
@ -234,6 +224,30 @@ var Style = Base.extend(new function() {
|
||||||
return undefined;
|
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;
|
return value;
|
||||||
};
|
};
|
||||||
|
@ -397,7 +411,7 @@ var Style = Base.extend(new function() {
|
||||||
*
|
*
|
||||||
* @name Style#strokeColor
|
* @name Style#strokeColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Setting the stroke color of a path:
|
* // Setting the stroke color of a path:
|
||||||
|
@ -530,7 +544,7 @@ var Style = Base.extend(new function() {
|
||||||
*
|
*
|
||||||
* @name Style#dashArray
|
* @name Style#dashArray
|
||||||
* @property
|
* @property
|
||||||
* @type Array
|
* @type Number[]
|
||||||
* @default []
|
* @default []
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -554,7 +568,7 @@ var Style = Base.extend(new function() {
|
||||||
*
|
*
|
||||||
* @name Style#fillColor
|
* @name Style#fillColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Setting the fill color of a path to red:
|
* // Setting the fill color of a path to red:
|
||||||
|
@ -585,7 +599,7 @@ var Style = Base.extend(new function() {
|
||||||
*
|
*
|
||||||
* @property
|
* @property
|
||||||
* @name Style#shadowColor
|
* @name Style#shadowColor
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Creating a circle with a black shadow:
|
* // Creating a circle with a black shadow:
|
||||||
|
@ -629,7 +643,7 @@ var Style = Base.extend(new function() {
|
||||||
*
|
*
|
||||||
* @name Style#selectedColor
|
* @name Style#selectedColor
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @type ?Color
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* 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
|
// in rotate(). To do so, SVG requries us to inverse transform the
|
||||||
// translation point by the matrix itself, since they are provided
|
// translation point by the matrix itself, since they are provided
|
||||||
// in local coordinates.
|
// in local coordinates.
|
||||||
matrix = matrix._shiftless();
|
var point;
|
||||||
var point = matrix._inverseTransform(trans);
|
if (matrix.isInvertible()) {
|
||||||
|
matrix = matrix._shiftless();
|
||||||
|
point = matrix._inverseTransform(trans);
|
||||||
|
trans = null;
|
||||||
|
} else {
|
||||||
|
point = new Point();
|
||||||
|
}
|
||||||
attrs[center ? 'cx' : 'x'] = point.x;
|
attrs[center ? 'cx' : 'x'] = point.x;
|
||||||
attrs[center ? 'cy' : 'y'] = point.y;
|
attrs[center ? 'cy' : 'y'] = point.y;
|
||||||
trans = null;
|
|
||||||
}
|
}
|
||||||
if (!matrix.isIdentity()) {
|
if (!matrix.isIdentity()) {
|
||||||
// See if we can decompose the matrix and can formulate it as a
|
// See if we can decompose the matrix and can formulate it as a
|
||||||
|
@ -177,7 +182,7 @@ new function() {
|
||||||
definition = item._definition,
|
definition = item._definition,
|
||||||
node = getDefinition(definition, 'symbol'),
|
node = getDefinition(definition, 'symbol'),
|
||||||
definitionItem = definition._item,
|
definitionItem = definition._item,
|
||||||
bounds = definitionItem.getBounds();
|
bounds = definitionItem.getStrokeBounds();
|
||||||
if (!node) {
|
if (!node) {
|
||||||
node = SvgElement.create('symbol', {
|
node = SvgElement.create('symbol', {
|
||||||
viewBox: formatter.rectangle(bounds)
|
viewBox: formatter.rectangle(bounds)
|
||||||
|
@ -456,7 +461,7 @@ new function() {
|
||||||
if (rect) {
|
if (rect) {
|
||||||
attrs.width = rect.width;
|
attrs.width = rect.width;
|
||||||
attrs.height = rect.height;
|
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);
|
attrs.viewBox = formatter.rectangle(rect);
|
||||||
}
|
}
|
||||||
var node = SvgElement.create('svg', attrs, formatter),
|
var node = SvgElement.create('svg', attrs, formatter),
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -22,11 +22,12 @@ new function() {
|
||||||
var definitions = {},
|
var definitions = {},
|
||||||
rootSize;
|
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.
|
// Interpret value as number. Never return NaN, but 0 instead.
|
||||||
// If the value is a sequence of numbers, parseFloat will
|
// If the value is a sequence of numbers, parseFloat will
|
||||||
// return the first occurring number, which is enough for now.
|
// 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
|
res = value == null
|
||||||
? allowNull
|
? allowNull
|
||||||
? null
|
? null
|
||||||
|
@ -43,9 +44,9 @@ new function() {
|
||||||
: res;
|
: res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPoint(node, x, y, allowNull, allowPercent) {
|
function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) {
|
||||||
x = getValue(node, x || 'x', false, allowNull, allowPercent);
|
x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX);
|
||||||
y = getValue(node, y || 'y', false, allowNull, allowPercent);
|
y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY);
|
||||||
return allowNull && (x == null || y == null) ? null
|
return allowNull && (x == null || y == null) ? null
|
||||||
: new Point(x, y);
|
: new Point(x, y);
|
||||||
}
|
}
|
||||||
|
@ -168,13 +169,16 @@ new function() {
|
||||||
'userSpaceOnUse';
|
'userSpaceOnUse';
|
||||||
// Allow percentages in all values if scaleToBounds is true:
|
// Allow percentages in all values if scaleToBounds is true:
|
||||||
if (radial) {
|
if (radial) {
|
||||||
origin = getPoint(node, 'cx', 'cy', false, scaleToBounds);
|
origin = getPoint(node, 'cx', 'cy', false, scaleToBounds,
|
||||||
|
'50%', '50%');
|
||||||
destination = origin.add(
|
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);
|
highlight = getPoint(node, 'fx', 'fy', true, scaleToBounds);
|
||||||
} else {
|
} else {
|
||||||
origin = getPoint(node, 'x1', 'y1', false, scaleToBounds);
|
origin = getPoint(node, 'x1', 'y1', false, scaleToBounds,
|
||||||
destination = getPoint(node, 'x2', 'y2', false, scaleToBounds);
|
'0%', '0%');
|
||||||
|
destination = getPoint(node, 'x2', 'y2', false, scaleToBounds,
|
||||||
|
'100%', '0%');
|
||||||
}
|
}
|
||||||
var color = applyAttributes(
|
var color = applyAttributes(
|
||||||
new Color(gradient, origin, destination, highlight), node);
|
new Color(gradient, origin, destination, highlight), node);
|
||||||
|
@ -196,23 +200,23 @@ new function() {
|
||||||
return importNode(child, options, isRoot);
|
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,
|
g: importGroup,
|
||||||
// http://www.w3.org/TR/SVG/struct.html#NewDocument
|
// https://www.w3.org/TR/SVG/struct.html#NewDocument
|
||||||
svg: importGroup,
|
svg: importGroup,
|
||||||
clippath: importGroup,
|
clippath: importGroup,
|
||||||
// http://www.w3.org/TR/SVG/shapes.html#PolygonElement
|
// https://www.w3.org/TR/SVG/shapes.html#PolygonElement
|
||||||
polygon: importPoly,
|
polygon: importPoly,
|
||||||
// http://www.w3.org/TR/SVG/shapes.html#PolylineElement
|
// https://www.w3.org/TR/SVG/shapes.html#PolylineElement
|
||||||
polyline: importPoly,
|
polyline: importPoly,
|
||||||
// http://www.w3.org/TR/SVG/paths.html
|
// https://www.w3.org/TR/SVG/paths.html
|
||||||
path: importPath,
|
path: importPath,
|
||||||
// http://www.w3.org/TR/SVG/pservers.html#LinearGradients
|
// https://www.w3.org/TR/SVG/pservers.html#LinearGradients
|
||||||
lineargradient: importGradient,
|
lineargradient: importGradient,
|
||||||
// http://www.w3.org/TR/SVG/pservers.html#RadialGradients
|
// https://www.w3.org/TR/SVG/pservers.html#RadialGradients
|
||||||
radialgradient: importGradient,
|
radialgradient: importGradient,
|
||||||
|
|
||||||
// http://www.w3.org/TR/SVG/struct.html#ImageElement
|
// https://www.w3.org/TR/SVG/struct.html#ImageElement
|
||||||
image: function (node) {
|
image: function (node) {
|
||||||
var raster = new Raster(getValue(node, 'href', true));
|
var raster = new Raster(getValue(node, 'href', true));
|
||||||
raster.on('load', function() {
|
raster.on('load', function() {
|
||||||
|
@ -228,17 +232,17 @@ new function() {
|
||||||
return raster;
|
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) {
|
symbol: function(node, type, options, isRoot) {
|
||||||
return new SymbolDefinition(
|
return new SymbolDefinition(
|
||||||
// Pass true for dontCenter:
|
// Pass true for dontCenter:
|
||||||
importGroup(node, type, options, isRoot), true);
|
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,
|
defs: importGroup,
|
||||||
|
|
||||||
// http://www.w3.org/TR/SVG/struct.html#UseElement
|
// https://www.w3.org/TR/SVG/struct.html#UseElement
|
||||||
use: function(node) {
|
use: function(node) {
|
||||||
// Note the namespaced xlink:href attribute is just called href
|
// Note the namespaced xlink:href attribute is just called href
|
||||||
// as a property on node.
|
// as a property on node.
|
||||||
|
@ -258,14 +262,14 @@ new function() {
|
||||||
: null;
|
: null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement
|
// https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement
|
||||||
circle: function(node) {
|
circle: function(node) {
|
||||||
return new Shape.Circle(
|
return new Shape.Circle(
|
||||||
getPoint(node, 'cx', 'cy'),
|
getPoint(node, 'cx', 'cy'),
|
||||||
getValue(node, 'r'));
|
getValue(node, 'r'));
|
||||||
},
|
},
|
||||||
|
|
||||||
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement
|
// https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement
|
||||||
ellipse: function(node) {
|
ellipse: function(node) {
|
||||||
// We only use object literal notation where the default one is not
|
// We only use object literal notation where the default one is not
|
||||||
// supported (e.g. center / radius fo Shape.Ellipse).
|
// 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) {
|
rect: function(node) {
|
||||||
return new Shape.Rectangle(new Rectangle(
|
return new Shape.Rectangle(new Rectangle(
|
||||||
getPoint(node),
|
getPoint(node),
|
||||||
|
@ -283,7 +287,7 @@ new function() {
|
||||||
), getSize(node, 'rx', 'ry'));
|
), 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) {
|
line: function(node) {
|
||||||
return new Path.Line(
|
return new Path.Line(
|
||||||
getPoint(node, 'x1', 'y1'),
|
getPoint(node, 'x1', 'y1'),
|
||||||
|
@ -345,7 +349,11 @@ new function() {
|
||||||
text.setContent(lines.join('\n'));
|
text.setContent(lines.join('\n'));
|
||||||
return text;
|
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
|
// Attributes and Styles
|
||||||
|
@ -356,7 +364,7 @@ new function() {
|
||||||
|
|
||||||
function applyTransform(item, value, name, node) {
|
function applyTransform(item, value, name, node) {
|
||||||
if (item.transform) {
|
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
|
// Parse SVG transform string. First we split at /)\s*/, to separate
|
||||||
// commands
|
// commands
|
||||||
var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
|
var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
|
||||||
|
@ -399,8 +407,8 @@ new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyOpacity(item, value, name) {
|
function applyOpacity(item, value, name) {
|
||||||
// http://www.w3.org/TR/SVG/painting.html#FillOpacityProperty
|
// https://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#StrokeOpacityProperty
|
||||||
var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor',
|
var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor',
|
||||||
color = item[key] && item[key]();
|
color = item[key] && item[key]();
|
||||||
if (color)
|
if (color)
|
||||||
|
@ -442,7 +450,7 @@ new function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
'clip-path': function(item, value) {
|
'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);
|
var clip = getDefinition(value);
|
||||||
if (clip) {
|
if (clip) {
|
||||||
clip = clip.clone();
|
clip = clip.clone();
|
||||||
|
@ -474,20 +482,20 @@ new function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
'stop-color': function(item, value) {
|
'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)
|
if (item.setColor)
|
||||||
item.setColor(value);
|
item.setColor(value);
|
||||||
},
|
},
|
||||||
|
|
||||||
'stop-opacity': function(item, 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!
|
// NOTE: It is important that this is applied after stop-color!
|
||||||
if (item._color)
|
if (item._color)
|
||||||
item._color.setAlpha(parseFloat(value));
|
item._color.setAlpha(parseFloat(value));
|
||||||
},
|
},
|
||||||
|
|
||||||
offset: function(item, 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) {
|
if (item.setOffset) {
|
||||||
var percent = value.match(/(.*)%$/);
|
var percent = value.match(/(.*)%$/);
|
||||||
item.setOffset(percent ? percent[1] / 100 : parseFloat(value));
|
item.setOffset(percent ? percent[1] / 100 : parseFloat(value));
|
||||||
|
@ -495,7 +503,7 @@ new function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
viewBox: function(item, value, name, node, styles) {
|
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
|
// TODO: implement preserveAspectRatio attribute
|
||||||
// viewBox will be applied both to the group that's created for the
|
// viewBox will be applied both to the group that's created for the
|
||||||
// content in SymbolDefinition#item, and the SymbolItem itself.
|
// content in SymbolDefinition#item, and the SymbolItem itself.
|
||||||
|
@ -703,8 +711,12 @@ new function() {
|
||||||
|
|
||||||
function onLoad(svg) {
|
function onLoad(svg) {
|
||||||
try {
|
try {
|
||||||
var node = typeof svg === 'object' ? svg : new self.DOMParser()
|
var node = typeof svg === 'object'
|
||||||
.parseFromString(svg, 'image/svg+xml');
|
? svg
|
||||||
|
: new self.DOMParser().parseFromString(
|
||||||
|
svg,
|
||||||
|
'image/svg+xml'
|
||||||
|
);
|
||||||
if (!node.nodeName) {
|
if (!node.nodeName) {
|
||||||
node = null;
|
node = null;
|
||||||
throw new Error('Unsupported SVG source: ' + source);
|
throw new Error('Unsupported SVG source: ' + source);
|
||||||
|
@ -734,8 +746,10 @@ new function() {
|
||||||
|
|
||||||
// Have the group not pass on all transformations to its children,
|
// Have the group not pass on all transformations to its children,
|
||||||
// as this is how SVG works too.
|
// as this is how SVG works too.
|
||||||
// See if it's a string but handle markup separately
|
// See if it's a string but handle markup separately, using `[\s\S]` to
|
||||||
if (typeof source === 'string' && !/^.*</.test(source)) {
|
// also match the first tag if it only starts on the second line in a
|
||||||
|
// multi-line string.
|
||||||
|
if (typeof source === 'string' && !/^[\s\S]*</.test(source)) {
|
||||||
// First see if we're meant to import an element with the given
|
// First see if we're meant to import an element with the given
|
||||||
// id.
|
// id.
|
||||||
var node = document.getElementById(source);
|
var node = document.getElementById(source);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -135,7 +135,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onMouseDown
|
* @name Tool#onMouseDown
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Creating circle shaped paths where the user presses the mouse button:
|
* // Creating circle shaped paths where the user presses the mouse button:
|
||||||
|
@ -157,7 +157,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onMouseDrag
|
* @name Tool#onMouseDrag
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Draw a line by adding a segment to a path on every mouse drag event:
|
* // Draw a line by adding a segment to a path on every mouse drag event:
|
||||||
|
@ -180,7 +180,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onMouseMove
|
* @name Tool#onMouseMove
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Moving a path to the position of the mouse:
|
* // Moving a path to the position of the mouse:
|
||||||
|
@ -206,7 +206,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onMouseUp
|
* @name Tool#onMouseUp
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Creating circle shaped paths where the user releases the mouse:
|
* // Creating circle shaped paths where the user releases the mouse:
|
||||||
|
@ -234,7 +234,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onKeyDown
|
* @name Tool#onKeyDown
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Scaling a path whenever the user presses the space bar:
|
* // Scaling a path whenever the user presses the space bar:
|
||||||
|
@ -268,7 +268,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||||
*
|
*
|
||||||
* @name Tool#onKeyUp
|
* @name Tool#onKeyUp
|
||||||
* @property
|
* @property
|
||||||
* @type Function
|
* @type ?Function
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* tool.onKeyUp = function(event) {
|
* tool.onKeyUp = function(event) {
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
269
src/util/CollisionDetection.js
Normal file
269
src/util/CollisionDetection.js
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
|
* http://paperjs.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
|
*
|
||||||
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name CollisionDetection
|
||||||
|
* @namespace
|
||||||
|
* @private
|
||||||
|
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
|
||||||
|
*/
|
||||||
|
var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
|
/**
|
||||||
|
* Finds collisions between axis aligned bounding boxes of items.
|
||||||
|
*
|
||||||
|
* This function takes the bounds of all items in the items1 and items2
|
||||||
|
* arrays and calls findBoundsCollisions().
|
||||||
|
*
|
||||||
|
* @param {Array} items1 Array of items for which collisions should be
|
||||||
|
* found.
|
||||||
|
* @param {Array} [items2] Array of items that the first array should be
|
||||||
|
* compared with. If not provided, collisions between items within
|
||||||
|
* the first array will be returned.
|
||||||
|
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
||||||
|
* all sides of each bounds when checking for collisions.
|
||||||
|
* @returns {Array} Array containing for the bounds at the same index in
|
||||||
|
* items1 an array of the indexes of colliding bounds in items2
|
||||||
|
*/
|
||||||
|
findItemBoundsCollisions: function(items1, items2, tolerance) {
|
||||||
|
function getBounds(items) {
|
||||||
|
var bounds = new Array(items.length);
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var rect = items[i].getBounds();
|
||||||
|
bounds[i] = [rect.left, rect.top, rect.right, rect.bottom];
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds1 = getBounds(items1),
|
||||||
|
bounds2 = !items2 || items2 === items1
|
||||||
|
? bounds1
|
||||||
|
: getBounds(items2);
|
||||||
|
return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds collisions between curves bounds. For performance reasons this
|
||||||
|
* uses broad bounds of the curve, which can be calculated much faster than
|
||||||
|
* the actual bounds. Broad bounds guarantee to contain the full curve,
|
||||||
|
* but they are usually larger than the actual bounds of a curve.
|
||||||
|
*
|
||||||
|
* This function takes the broad bounds of all curve values in the curves1
|
||||||
|
* and curves2 arrays and calls findBoundsCollisions().
|
||||||
|
*
|
||||||
|
* @param {Array} curves1 Array of curve values for which collisions should
|
||||||
|
* be found.
|
||||||
|
* @param {Array} [curves2] Array of curve values that the first array
|
||||||
|
* should be compared with. If not provided, collisions between curve
|
||||||
|
* bounds within the first arrray will be returned.
|
||||||
|
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
||||||
|
* all sides of each bounds when checking for collisions.
|
||||||
|
* @param {Boolean} [bothAxis] If true, the sweep is performed along both
|
||||||
|
* axis, and the results include collisions for both: `{ hor, ver }`.
|
||||||
|
* @returns {Array} Array containing for the bounds at the same index in
|
||||||
|
* curves1 an array of the indexes of colliding bounds in curves2
|
||||||
|
*/
|
||||||
|
findCurveBoundsCollisions: function(curves1, curves2, tolerance, bothAxis) {
|
||||||
|
function getBounds(curves) {
|
||||||
|
var min = Math.min,
|
||||||
|
max = Math.max,
|
||||||
|
bounds = new Array(curves.length);
|
||||||
|
for (var i = 0; i < curves.length; i++) {
|
||||||
|
var v = curves[i];
|
||||||
|
bounds[i] = [
|
||||||
|
min(v[0], v[2], v[4], v[6]),
|
||||||
|
min(v[1], v[3], v[5], v[7]),
|
||||||
|
max(v[0], v[2], v[4], v[6]),
|
||||||
|
max(v[1], v[3], v[5], v[7])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds1 = getBounds(curves1),
|
||||||
|
bounds2 = !curves2 || curves2 === curves1
|
||||||
|
? bounds1
|
||||||
|
: getBounds(curves2);
|
||||||
|
if (bothAxis) {
|
||||||
|
var hor = this.findBoundsCollisions(
|
||||||
|
bounds1, bounds2, tolerance || 0, false, true),
|
||||||
|
ver = this.findBoundsCollisions(
|
||||||
|
bounds1, bounds2, tolerance || 0, true, true),
|
||||||
|
list = [];
|
||||||
|
for (var i = 0, l = hor.length; i < l; i++) {
|
||||||
|
list[i] = { hor: hor[i], ver: ver[i] };
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds collisions between two sets of bounding rectangles.
|
||||||
|
*
|
||||||
|
* The collision detection is implemented as a sweep and prune algorithm
|
||||||
|
* with sweep either along the x or y axis (primary axis) and immediate
|
||||||
|
* check on secondary axis for potential pairs.
|
||||||
|
*
|
||||||
|
* Each entry in the bounds arrays must be an array of length 4 with
|
||||||
|
* x0, y0, x1, and y1 as the array elements.
|
||||||
|
*
|
||||||
|
* The returned array has the same length as bounds1. Each entry
|
||||||
|
* contains an array with all indices of overlapping bounds of
|
||||||
|
* bounds2 (or bounds1 if bounds2 is not provided) sorted
|
||||||
|
* in ascending order.
|
||||||
|
*
|
||||||
|
* If the second bounds array parameter is null, collisions between bounds
|
||||||
|
* within the first bounds array will be found. In this case the indexed
|
||||||
|
* returned for each bounds will not contain the bounds' own index.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {Array} boundsA Array of bounds objects for which collisions
|
||||||
|
* should be found.
|
||||||
|
* @param {Array} [boundsB] Array of bounds that the first array should
|
||||||
|
* be compared with. If not provided, collisions between bounds within
|
||||||
|
* the first arrray will be returned.
|
||||||
|
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
||||||
|
* all sides of each bounds when checking for collisions.
|
||||||
|
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
|
||||||
|
* the y-axis.
|
||||||
|
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
|
||||||
|
* will be done on the secondary axis.
|
||||||
|
* @returns {Array} Array containing for the bounds at the same index in
|
||||||
|
* boundsA an array of the indexes of colliding bounds in boundsB
|
||||||
|
*/
|
||||||
|
findBoundsCollisions: function(boundsA, boundsB, tolerance,
|
||||||
|
sweepVertical, onlySweepAxisCollisions) {
|
||||||
|
var self = !boundsB || boundsA === boundsB,
|
||||||
|
allBounds = self ? boundsA : boundsA.concat(boundsB),
|
||||||
|
lengthA = boundsA.length,
|
||||||
|
lengthAll = allBounds.length;
|
||||||
|
|
||||||
|
// Binary search utility function.
|
||||||
|
// For multiple same entries, this returns the rightmost entry.
|
||||||
|
// https://en.wikipedia.org/wiki/Binary_search_algorithm#Procedure_for_finding_the_rightmost_element
|
||||||
|
function binarySearch(indices, coord, value) {
|
||||||
|
var lo = 0,
|
||||||
|
hi = indices.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = (hi + lo) >>> 1; // Same as Math.floor((hi + lo) / 2)
|
||||||
|
if (allBounds[indices[mid]][coord] < value) {
|
||||||
|
lo = mid + 1;
|
||||||
|
} else {
|
||||||
|
hi = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lo - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set coordinates for primary and secondary axis depending on sweep
|
||||||
|
// direction. By default we sweep in horizontal direction, which
|
||||||
|
// means x is the primary axis.
|
||||||
|
var pri0 = sweepVertical ? 1 : 0,
|
||||||
|
pri1 = pri0 + 2,
|
||||||
|
sec0 = sweepVertical ? 0 : 1,
|
||||||
|
sec1 = sec0 + 2;
|
||||||
|
// Create array with all indices sorted by lower boundary on primary
|
||||||
|
// axis.
|
||||||
|
var allIndicesByPri0 = new Array(lengthAll);
|
||||||
|
for (var i = 0; i < lengthAll; i++) {
|
||||||
|
allIndicesByPri0[i] = i;
|
||||||
|
}
|
||||||
|
allIndicesByPri0.sort(function(i1, i2) {
|
||||||
|
return allBounds[i1][pri0] - allBounds[i2][pri0];
|
||||||
|
});
|
||||||
|
// Sweep along primary axis. Indices of active bounds are kept in an
|
||||||
|
// array sorted by higher boundary on primary axis.
|
||||||
|
var activeIndicesByPri1 = [],
|
||||||
|
allCollisions = new Array(lengthA);
|
||||||
|
for (var i = 0; i < lengthAll; i++) {
|
||||||
|
var curIndex = allIndicesByPri0[i],
|
||||||
|
curBounds = allBounds[curIndex],
|
||||||
|
// The original index in boundsA or boundsB:
|
||||||
|
origIndex = self ? curIndex : curIndex - lengthA,
|
||||||
|
isCurrentA = curIndex < lengthA,
|
||||||
|
isCurrentB = self || !isCurrentA,
|
||||||
|
curCollisions = isCurrentA ? [] : null;
|
||||||
|
if (activeIndicesByPri1.length) {
|
||||||
|
// remove (prune) indices that are no longer active.
|
||||||
|
var pruneCount = binarySearch(activeIndicesByPri1, pri1,
|
||||||
|
curBounds[pri0] - tolerance) + 1;
|
||||||
|
activeIndicesByPri1.splice(0, pruneCount);
|
||||||
|
// Add collisions for current index.
|
||||||
|
if (self && onlySweepAxisCollisions) {
|
||||||
|
// All active indexes can be added, no further checks needed
|
||||||
|
curCollisions = curCollisions.concat(activeIndicesByPri1);
|
||||||
|
// Add current index to collisions of all active indexes
|
||||||
|
for (var j = 0; j < activeIndicesByPri1.length; j++) {
|
||||||
|
var activeIndex = activeIndicesByPri1[j];
|
||||||
|
allCollisions[activeIndex].push(origIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var curSec1 = curBounds[sec1],
|
||||||
|
curSec0 = curBounds[sec0];
|
||||||
|
for (var j = 0; j < activeIndicesByPri1.length; j++) {
|
||||||
|
var activeIndex = activeIndicesByPri1[j],
|
||||||
|
activeBounds = allBounds[activeIndex],
|
||||||
|
isActiveA = activeIndex < lengthA,
|
||||||
|
isActiveB = self || activeIndex >= lengthA;
|
||||||
|
|
||||||
|
// Check secondary axis bounds if necessary.
|
||||||
|
if (
|
||||||
|
onlySweepAxisCollisions ||
|
||||||
|
(
|
||||||
|
isCurrentA && isActiveB ||
|
||||||
|
isCurrentB && isActiveA
|
||||||
|
) && (
|
||||||
|
curSec1 >= activeBounds[sec0] - tolerance &&
|
||||||
|
curSec0 <= activeBounds[sec1] + tolerance
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Add current index to collisions of active
|
||||||
|
// indices and vice versa.
|
||||||
|
if (isCurrentA && isActiveB) {
|
||||||
|
curCollisions.push(
|
||||||
|
self ? activeIndex : activeIndex - lengthA);
|
||||||
|
}
|
||||||
|
if (isCurrentB && isActiveA) {
|
||||||
|
allCollisions[activeIndex].push(origIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isCurrentA) {
|
||||||
|
if (boundsA === boundsB) {
|
||||||
|
// If both arrays are the same, add self collision.
|
||||||
|
curCollisions.push(curIndex);
|
||||||
|
}
|
||||||
|
// Add collisions for current index.
|
||||||
|
allCollisions[curIndex] = curCollisions;
|
||||||
|
}
|
||||||
|
// Add current index to active indices. Keep array sorted by
|
||||||
|
// their higher boundary on the primary axis.s
|
||||||
|
if (activeIndicesByPri1.length) {
|
||||||
|
var curPri1 = curBounds[pri1],
|
||||||
|
index = binarySearch(activeIndicesByPri1, pri1, curPri1);
|
||||||
|
activeIndicesByPri1.splice(index + 1, 0, curIndex);
|
||||||
|
} else {
|
||||||
|
activeIndicesByPri1.push(curIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort collision indices in ascending order.
|
||||||
|
for (var i = 0; i < allCollisions.length; i++) {
|
||||||
|
var collisions = allCollisions[i];
|
||||||
|
if (collisions) {
|
||||||
|
collisions.sort(function(i1, i2) { return i1 - i2; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allCollisions;
|
||||||
|
}
|
||||||
|
};
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
* http://paperjs.org/
|
* http://paperjs.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
* http://juerglehni.com/ & https://puckey.studio/
|
||||||
*
|
*
|
||||||
* Distributed under the MIT license. See LICENSE file for details.
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
*
|
*
|
||||||
|
@ -168,6 +168,10 @@ var Numerical = new function() {
|
||||||
return val >= -EPSILON && val <= EPSILON;
|
return val >= -EPSILON && val <= EPSILON;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isMachineZero: function(val) {
|
||||||
|
return val >= -MACHINE_EPSILON && val <= MACHINE_EPSILON;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a number whose value is clamped by the given range.
|
* Returns a number whose value is clamped by the given range.
|
||||||
*
|
*
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue