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.
|
||||
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
|
||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -1,16 +1,15 @@
|
|||
language: node_js
|
||||
os: linux
|
||||
# Follow https://github.com/nodejs/LTS to decide when to remove a version
|
||||
node_js:
|
||||
- 9
|
||||
# Stable version is temporarily disabled due to a bug in resemblejs package with
|
||||
# node v12 (https://github.com/orgs/paperjs/teams/contributors/discussions/12).
|
||||
# - stable
|
||||
- 11
|
||||
- 10
|
||||
- 8
|
||||
# 6.13 and 6.14 causing unreasonable errors in SymbolDefinition.initialize.
|
||||
# https://travis-ci.org/paperjs/paper.js/jobs/434854796
|
||||
# To avoid these versions, we specify version to 6.12 as temporary solution.
|
||||
# See https://github.com/paperjs/paper.js/issues/1523
|
||||
- 6.12
|
||||
sudo: false
|
||||
env:
|
||||
matrix:
|
||||
jobs:
|
||||
- CXX=g++-4.9
|
||||
global:
|
||||
- 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)
|
||||
deploy:
|
||||
- provider: npm
|
||||
node_js: 8
|
||||
node_js: 10
|
||||
on:
|
||||
branch: develop
|
||||
skip_cleanup: true
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
## Authors
|
||||
|
||||
- Jürg Lehni <juerg@scratchdisk.com>
|
||||
- Jonathan Puckey <jonathan@studiomoniker.com>
|
||||
- Jonathan Puckey <jonathan@puckey.studio>
|
||||
|
||||
## Contributors
|
||||
|
||||
- Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
||||
- Jan Bösenberg <development@iconexperience.com>
|
||||
- Jan Bösenberg <jan.boesenberg@gmail.com>
|
||||
- Jt Whissel <jtwhissel@gmail.com>
|
||||
- Andrew Roles <jaroles58@gmail.com>
|
||||
- Jacob Lites <jnightlight@gmail.com>
|
||||
|
|
168
CHANGELOG.md
168
CHANGELOG.md
|
@ -1,5 +1,145 @@
|
|||
# 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`
|
||||
|
||||
### News
|
||||
|
@ -59,6 +199,7 @@ the fixes and additions from the past two weeks:
|
|||
## `0.11.5`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `Curve#isSelected()` to correctly reflect the state of `#handle1` (#1378).
|
||||
- Key Events: Fix auto-filling issue on Chrome (#1358, #1365).
|
||||
- Boolean: Check that overlaps are on the right path (#1321).
|
||||
|
@ -71,38 +212,42 @@ the fixes and additions from the past two weeks:
|
|||
## `0.11.4`
|
||||
|
||||
### Changed
|
||||
|
||||
- Node.js: Add support for v8, and keep testing v4, v6, v7 in Travis CI.
|
||||
|
||||
## `0.11.3`
|
||||
|
||||
### Fixed
|
||||
- Mouse Events: Fix item-based `doubleclick` events (#1316).
|
||||
|
||||
- Mouse Events: Fix item-based `doubleclick` events (#1316).
|
||||
- Overhaul the caching of bounds and matrix decomposition, improving reliability
|
||||
of `Item#rotation` and `#scaling` and fixing situations caused by wrongly
|
||||
caching `Item#position` and `#bounds` values.
|
||||
|
||||
- Prevent consumed properties in object literal constructors from being set on
|
||||
the instance.
|
||||
|
||||
### Changed
|
||||
|
||||
- Make all functions and accessors enumerable on all Paper.js classes.
|
||||
|
||||
## `0.11.2`
|
||||
|
||||
### Fixed
|
||||
|
||||
- PaperScript: Fix a parsing error in math operations without white-space
|
||||
(#1314).
|
||||
|
||||
## `0.11.1`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Bring back deactivation of Node.js modules on browsers. This has most probably
|
||||
broken Webpack bundling in `0.11.0`.
|
||||
|
||||
## `0.11.0`
|
||||
|
||||
### Changed
|
||||
|
||||
- Separate `paper` module on NPM into: `paper`, `paper-jsdom` and
|
||||
`paper-jsdom-canvas` (#1252):
|
||||
- `paper` is the main library, and can be used directly in a browser
|
||||
|
@ -115,12 +260,14 @@ the fixes and additions from the past two weeks:
|
|||
[jsdom](https://github.com/tmpvar/jsdom).
|
||||
|
||||
### Added
|
||||
|
||||
- PaperScript: Support newer, external versions of Acorn.js for PaperScript
|
||||
parsing, opening the doors to ES 2015 (#1183, #1275).
|
||||
- Hit Tests: Implement `options.position` to hit `Item#position` (#1249).
|
||||
- Split `Item#copyTo()` into `#addTo()` and `#copyTo()`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Intersections: Bring back special handling of curve end-points (#1284).
|
||||
- Intersections: Correctly handle `Item#applyMatrix = false` (#1289).
|
||||
- Boolean: Bring back on-path winding handling (#1281).
|
||||
|
@ -154,6 +301,7 @@ the fixes and additions from the past two weeks:
|
|||
## `0.10.3`
|
||||
|
||||
### Changed
|
||||
|
||||
- Node.js: Support v7, and keep testing v4 up to v7 in Travis CI.
|
||||
- Node.js: Loosely couple Node.js / Electron code to `Canvas` module, and treat
|
||||
its absence like a headless web worker context in the browser (#1103).
|
||||
|
@ -178,6 +326,7 @@ the fixes and additions from the past two weeks:
|
|||
`#reorient()` (#973).
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `Path#divideAt(location)`, in analogy to `Curve#divideAt(location)`.
|
||||
- Add `PathItem#compare()` as a way to compare the geometry of two paths to see
|
||||
if they describe the same shape, handling cases where paths start in different
|
||||
|
@ -196,6 +345,7 @@ the fixes and additions from the past two weeks:
|
|||
(#1004, #1177).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Many improvements to boolean operations:
|
||||
- Improve performance of boolean operations when there no actual crossings
|
||||
between the paths, but paths may be contained within each other.
|
||||
|
@ -236,17 +386,20 @@ the fixes and additions from the past two weeks:
|
|||
(#632).
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove `Numerical.TOLERANCE = 1e-6` as there is no internal use for it
|
||||
anymore.
|
||||
|
||||
## `0.10.2`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Get published version to work correctly in Bower again.
|
||||
|
||||
## `0.10.1`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Correct a few issues with documentation and NPM publishing that slipped
|
||||
through in the `0.10.0` release.
|
||||
|
||||
|
@ -284,6 +437,7 @@ Thank you all for using Paper.js, submitting bugs and ideas, and all those that
|
|||
contribute to the code.
|
||||
|
||||
### Changed
|
||||
|
||||
- Significant overhaul and improvements of boolean path operations
|
||||
`PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()`:
|
||||
- Improve handling of self-intersecting paths and non-zero fill-rules.
|
||||
|
@ -300,7 +454,7 @@ contribute to the code.
|
|||
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
||||
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
||||
- `Curve#getPointAt(time, true)` → `#getPointAtTime(time)`
|
||||
- `Curve#getTangentAt(time, true)` → `#getTangenttTime(time)`
|
||||
- `Curve#getTangentAt(time, true)` → `#getTangentAtTime(time)`
|
||||
- `Curve#getNormalAt(time, true)` → `#getNormalAtTime(time)`
|
||||
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
||||
- `CurveLocation#parameter` → `#time`
|
||||
|
@ -360,6 +514,7 @@ contribute to the code.
|
|||
`Color` (#1043).
|
||||
|
||||
### Added
|
||||
|
||||
- Use unified code-base for browsers, Node.js, Electron, and anything
|
||||
in-between, and enable npm install for browser use (#739).
|
||||
- Start using automatic code testing and deployment of prebuilt versions through
|
||||
|
@ -424,6 +579,7 @@ contribute to the code.
|
|||
- Add `Raster#loaded` to reflect the loading state of its image.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix calculations of `Item#strokeBounds` for all possible combinations of
|
||||
`Item#strokeScaling` and `Item#applyMatrix` for `Path`, `Shape` and
|
||||
`SymbolItem`, along with correct handling of such strokes in Item#hitTest()
|
||||
|
@ -502,10 +658,11 @@ contribute to the code.
|
|||
`Numerical.solveCubic()` for edge-cases (#1085).
|
||||
|
||||
### Removed
|
||||
|
||||
- Canvas attributes "resize" and "data-paper-resize" no longer cause paper to
|
||||
resize the canvas when the viewport size changes; Additional CSS styles are
|
||||
required since `0.9.22`, e.g.:
|
||||
|
||||
|
||||
```css
|
||||
/* Scale canvas with resize attribute to full size */
|
||||
canvas[resize] {
|
||||
|
@ -520,6 +677,7 @@ contribute to the code.
|
|||
It is replaced by `Project#addLayer()` and `Project#insertLayer()`.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `#windingRule` on `Item` and `Style` → `#fillRule`
|
||||
- `Curve#getNormalAt(time, true)` → `#getNormalAtTime(true)`
|
||||
- `Curve#divide()` → `#divideAt(offset)` / `#divideAtTime(time)`
|
||||
|
@ -527,7 +685,7 @@ contribute to the code.
|
|||
- `Curve#getParameterAt(offset)` → `#getTimeAt(offset)`
|
||||
- `Curve#getParameterOf(point)` → `getTimeOf(point)`
|
||||
- `Curve#getPointAt(time, true)` → `#getPointAtTime(time)`
|
||||
- `Curve#getTangentAt(time, true)` → `#getTangenttTime(time)`
|
||||
- `Curve#getTangentAt(time, true)` → `#getTangentAtTime(time)`
|
||||
- `Curve#getNormalAt(time, true)` → `#getNormalAtTime(time)`
|
||||
- `Curve#getCurvatureAt(time, true)` → `#getCurvatureAtTime(time)`
|
||||
- `CurveLocation#parameter` → `#time`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
http://juerglehni.com/ & https://puckey.studio/
|
||||
All rights reserved.
|
||||
|
||||
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
|
||||
from [http://paperjs.org/download/](http://paperjs.org/download/)
|
||||
|
||||
- Website: <http://paperjs.org/>
|
||||
- Questions: <https://stackoverflow.com/questions/tagged/paperjs>
|
||||
- Discussion forum: <https://groups.google.com/group/paperjs>
|
||||
- Mainline source code: <https://github.com/paperjs/paper.js>
|
||||
- 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
|
||||
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
|
||||
commands in your project folder:
|
||||
If NPM is already installed, simply type one of these commands in your project
|
||||
folder:
|
||||
|
||||
```sh
|
||||
npm install paper
|
||||
# Or:
|
||||
bower install paper
|
||||
```
|
||||
|
||||
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
|
||||
[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
|
||||
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
|
||||
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-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
|
||||
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
|
||||
issuing the command:
|
||||
Paper.js relies on [Node-Canvas](https://github.com/Automattic/node-canvas) for
|
||||
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
|
||||
|
||||
|
@ -112,7 +118,7 @@ After adding this line, your commands should work in the expected way:
|
|||
npm install paper
|
||||
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
|
||||
|
||||
|
@ -121,24 +127,23 @@ build from c++ sources:
|
|||
|
||||
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
|
||||
rendering from NPM:
|
||||
|
||||
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
|
||||
|
||||
The main Paper.js source tree is hosted on
|
||||
|
@ -163,8 +168,8 @@ run:
|
|||
### Setting Up For Building
|
||||
|
||||
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
|
||||
Node.js, NPM and Bower](#installing-nodejs-npm-and-bower) if you still need to
|
||||
couple of dependencies as NPM modules. Read the chapter [Installing
|
||||
Node.js and NPM](#installing-nodejs-and-npm) if you still need to
|
||||
install these.
|
||||
|
||||
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",
|
||||
"authors": [
|
||||
"Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)",
|
||||
"Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"
|
||||
"Jürg Lehni <juerg@scratchdisk.com> (http://juerglehni.com)",
|
||||
"Jonathan Puckey <jonathan@puckey.studio> (http://puckey.studio)"
|
||||
],
|
||||
"main": "dist/paper-full.js",
|
||||
"ignore": [
|
||||
|
|
|
@ -24,7 +24,7 @@ raster.onLoad = function() {
|
|||
var fs = require('fs');
|
||||
|
||||
var svg = new paper.XMLSerializer().serializeToString(project.exportSVG());
|
||||
fs.writeFile(path.resolve('./out.svg'),svg, function (err) {
|
||||
fs.writeFile(path.resolve('./out.svg'), svg, function (err) {
|
||||
if (err) throw err;
|
||||
console.log('Saved!');
|
||||
});
|
||||
|
|
|
@ -45,7 +45,7 @@ with (paper) {
|
|||
var svg = project.exportSVG({ asString: true });
|
||||
console.log(svg);
|
||||
|
||||
fs.writeFile(path.resolve('./out.svg'),svg, function (err) {
|
||||
fs.writeFile(path.resolve('./out.svg'), svg, function (err) {
|
||||
if (err) throw err;
|
||||
console.log('Saved!');
|
||||
});
|
||||
|
|
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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -22,6 +22,8 @@ gulp.task('zip', ['clean:zip', 'dist'], function() {
|
|||
gulp.src([
|
||||
'dist/paper-full*.js',
|
||||
'dist/paper-core*.js',
|
||||
'dist/paper.d.ts',
|
||||
'dist/paper-core.d.ts',
|
||||
'dist/node/**/*',
|
||||
'LICENSE.txt',
|
||||
'examples/**/*',
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -14,14 +14,15 @@ var gulp = require('gulp'),
|
|||
del = require('del'),
|
||||
rename = require('gulp-rename'),
|
||||
shell = require('gulp-shell'),
|
||||
options = require('../utils/options.js');
|
||||
options = require('../utils/options.js'),
|
||||
run = require('run-sequence');
|
||||
|
||||
var docOptions = {
|
||||
local: 'docs', // Generates the offline docs
|
||||
server: 'serverdocs' // Generates the website templates for the online docs
|
||||
};
|
||||
|
||||
gulp.task('docs', ['docs:local', 'build:full'], function() {
|
||||
gulp.task('docs', ['docs:local', 'docs:typescript', 'build:full'], function() {
|
||||
return gulp.src('dist/paper-full.js')
|
||||
.pipe(rename({ basename: 'paper' }))
|
||||
.pipe(gulp.dest('dist/docs/assets/js/'));
|
||||
|
@ -32,15 +33,58 @@ Object.keys(docOptions).forEach(function(name) {
|
|||
var mode = docOptions[name];
|
||||
return gulp.src('src')
|
||||
.pipe(shell(
|
||||
['java -cp jsrun.jar:lib/* JsRun app/run.js',
|
||||
' -c=conf/', name, '.conf ',
|
||||
' -D="renderMode:', mode, '" ',
|
||||
' -D="version:', options.version, '"'].join(''),
|
||||
[
|
||||
'java -cp jsrun.jar:lib/* JsRun app/run.js',
|
||||
' -c=conf/', name, '.conf ',
|
||||
' -D="renderMode:', mode, '" ',
|
||||
' -D="version:', options.version, '"'
|
||||
].join(''),
|
||||
{ cwd: 'gulp/jsdoc' })
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task('clean:docs:' + name, function() {
|
||||
return del([ 'dist/' + docOptions[name] + '/**' ]);
|
||||
return del(['dist/' + docOptions[name] + '/**']);
|
||||
});
|
||||
});
|
||||
|
||||
// The goal of the typescript task is to automatically generate a type
|
||||
// definition for the library.
|
||||
gulp.task('docs:typescript', function(callback) {
|
||||
run(
|
||||
'docs:typescript:clean:before',
|
||||
'docs:typescript:build',
|
||||
'docs:typescript:clean:after',
|
||||
callback
|
||||
);
|
||||
});
|
||||
// First clean eventually existing type definition...
|
||||
gulp.task('docs:typescript:clean:before', function() {
|
||||
return del('dist/paper.d.ts');
|
||||
});
|
||||
// ...then build the definition...
|
||||
gulp.task('docs:typescript:build', function() {
|
||||
// First parse JSDoc comments and store parsed data in a temporary file...
|
||||
return gulp.src('src')
|
||||
.pipe(shell(
|
||||
[
|
||||
'java -cp jsrun.jar:lib/* JsRun app/run.js',
|
||||
' -c=conf/typescript.conf ',
|
||||
' -D="file:../../gulp/typescript/typescript-definition-data.json"',
|
||||
' -D="version:', options.version, '"',
|
||||
' -D="date:', options.date, '"'
|
||||
].join(''),
|
||||
{ cwd: 'gulp/jsdoc' })
|
||||
)
|
||||
// ...then generate definition from parsed data...
|
||||
.pipe(shell('node gulp/typescript/typescript-definition-generator.js'))
|
||||
// ...finally test the definition by compiling a typescript file.
|
||||
.pipe(shell('node node_modules/typescript/bin/tsc --project gulp/typescript'));
|
||||
});
|
||||
// ...finally remove all unneeded temporary files that were used for building.
|
||||
gulp.task('docs:typescript:clean:after', function() {
|
||||
return del([
|
||||
'gulp/typescript/typescript-definition-data.json',
|
||||
'gulp/typescript/typescript-definition-test.js'
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -32,20 +32,21 @@ var packages = ['paper-jsdom', 'paper-jsdom-canvas'],
|
|||
end_with_newline: true
|
||||
};
|
||||
|
||||
gulp.task('publish', function() {
|
||||
gulp.task('publish', function(callback) {
|
||||
if (options.branch !== 'develop') {
|
||||
throw new Error('Publishing is only allowed on the develop branch.');
|
||||
}
|
||||
// publish:website comes before publish:release, so paperjs.zip file is gone
|
||||
// before npm publish:
|
||||
return run(
|
||||
run(
|
||||
'publish:json',
|
||||
'publish:dist',
|
||||
'publish:packages',
|
||||
'publish:commit',
|
||||
'publish:website',
|
||||
'publish:release',
|
||||
'publish:load'
|
||||
'publish:load',
|
||||
callback
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -108,11 +109,12 @@ packages.forEach(function(name) {
|
|||
});
|
||||
});
|
||||
|
||||
gulp.task('publish:website', function() {
|
||||
gulp.task('publish:website', function(callback) {
|
||||
if (fs.lstatSync(sitePath).isDirectory()) {
|
||||
return run(
|
||||
run(
|
||||
'publish:website:build',
|
||||
'publish:website:push'
|
||||
'publish:website:push',
|
||||
callback
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -24,9 +24,10 @@ options.date = git('log -1 --pretty=format:%ad');
|
|||
options.branch = git('rev-parse --abbrev-ref HEAD');
|
||||
|
||||
// If a specific branch is requested, quit without errors if we don't match.
|
||||
if (argv.branch && argv.branch !== options.branch) {
|
||||
console.log('Branch "' + options.branch + '" does not match "' +
|
||||
argv.branch + '". There is nothing to do here.');
|
||||
var ensureBranch = argv['ensure-branch'];
|
||||
if (ensureBranch && ensureBranch !== options.branch) {
|
||||
console.log('Branch "' + options.branch + '" does not match requested "' +
|
||||
ensureBranch + '". There is nothing to do here.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
85
package.json
85
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@scratch/paper",
|
||||
"version": "0.11.8",
|
||||
"version": "0.12.7",
|
||||
"description": "The Swiss Army Knife of Vector Graphics Scripting",
|
||||
"license": "MIT",
|
||||
"homepage": "http://paperjs.org",
|
||||
|
@ -9,11 +9,10 @@
|
|||
"url": "https://github.com/paperjs/paper.js"
|
||||
},
|
||||
"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",
|
||||
"types": "dist/paper.d.ts",
|
||||
"scripts": {
|
||||
"precommit": "gulp jshint --branch develop",
|
||||
"prepush": "gulp test --branch develop",
|
||||
"build": "gulp build",
|
||||
"dist": "gulp dist",
|
||||
"zip": "gulp zip",
|
||||
|
@ -24,42 +23,13 @@
|
|||
},
|
||||
"files": ["AUTHORS.md", "CHANGELOG.md", "dist/", "examples/", "LICENSE.txt", "README.md"],
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~0.5.0",
|
||||
"canvas-prebuilt": "^2.0.0-alpha.14",
|
||||
"del": "^2.2.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-cached": "^1.1.0",
|
||||
"gulp-git-streamed": "^2.8.1",
|
||||
"gulp-jshint": "^2.0.0",
|
||||
"gulp-json-editor": "^2.2.1",
|
||||
"gulp-prepro": "^2.4.0",
|
||||
"gulp-qunits": "^2.1.1",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-shell": "^0.5.2",
|
||||
"gulp-symlink": "^2.1.4",
|
||||
"gulp-uglify": "^1.5.4",
|
||||
"gulp-uncomment": "^0.3.0",
|
||||
"gulp-util": "^3.0.7",
|
||||
"gulp-webserver": "^0.9.1",
|
||||
"gulp-whitespace": "^0.1.0",
|
||||
"gulp-zip": "^3.2.0",
|
||||
"husky": "^0.11.4",
|
||||
"jsdom": "^9.4.0",
|
||||
"jshint": "^2.9.2",
|
||||
"jshint-summary": "^0.4.0",
|
||||
"merge-stream": "^1.0.0",
|
||||
"minimist": "^1.2.0",
|
||||
"prepro": "^2.4.0",
|
||||
"qunitjs": "^1.23.0",
|
||||
"require-dir": "^0.3.0",
|
||||
"resemblejs": "^2.2.1",
|
||||
"run-sequence": "^1.2.2",
|
||||
"source-map-support": "^0.4.0",
|
||||
"stats.js": "0.16.0",
|
||||
"straps": "^3.0.1"
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "gulp jshint --ensure-branch develop",
|
||||
"pre-push": "gulp test --ensure-branch develop"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"canvas": false,
|
||||
|
@ -69,5 +39,42 @@
|
|||
"./dist/node/self.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"]
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -12,8 +12,8 @@
|
|||
|
||||
/**
|
||||
* @name Line
|
||||
*
|
||||
* @class The Line object represents..
|
||||
* @private
|
||||
*/
|
||||
var Line = Base.extend(/** @lends Line# */{
|
||||
_class: 'Line',
|
||||
|
@ -141,7 +141,7 @@ var Line = Base.extend(/** @lends Line# */{
|
|||
}
|
||||
var cross = v1x * v2y - v1y * v2x;
|
||||
// Avoid divisions by 0, and errors when getting too close to 0
|
||||
if (!Numerical.isZero(cross)) {
|
||||
if (!Numerical.isMachineZero(cross)) {
|
||||
var dx = p1x - p2x,
|
||||
dy = p1y - p2y,
|
||||
u1 = (v2x * dy - v2y * dx) / cross,
|
||||
|
@ -175,7 +175,7 @@ var Line = Base.extend(/** @lends Line# */{
|
|||
v2y = y - py,
|
||||
// ccw = v2.cross(v1);
|
||||
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
|
||||
// finite line too: Project v2 onto v1 and determine ccw based
|
||||
// on which side of the finite line the point lies. Calculate
|
||||
|
@ -196,9 +196,13 @@ var Line = Base.extend(/** @lends Line# */{
|
|||
vy -= py;
|
||||
}
|
||||
// Based on the error analysis by @iconexperience outlined in #799
|
||||
return vx === 0 ? vy > 0 ? x - px : px - x
|
||||
: vy === 0 ? vx < 0 ? y - py : py - y
|
||||
: ((x-px) * vy - (y-py) * vx) / Math.sqrt(vx * vx + vy * vy);
|
||||
return vx === 0 ? (vy > 0 ? x - px : px - x)
|
||||
: vy === 0 ? (vx < 0 ? y - py : py - y)
|
||||
: ((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) {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
initialize: function Matrix(arg, _dontNotify) {
|
||||
var count = arguments.length,
|
||||
var args = arguments,
|
||||
count = args.length,
|
||||
ok = true;
|
||||
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) {
|
||||
// Support both Matrix and Array arguments through #_set(), and pass
|
||||
// on the optional _dontNotify argument:
|
||||
|
@ -104,6 +105,8 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* also work for calls of `set()`.
|
||||
*
|
||||
* @function
|
||||
* @param {...*} values
|
||||
* @return {Point}
|
||||
*/
|
||||
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,
|
||||
* meaning its transformation is baked into the item's content or children.
|
||||
*
|
||||
* @param {Boolean} recursively controls whether to apply transformations
|
||||
* recursively on children
|
||||
* @param {Boolean} [recursively=true] controls whether to apply
|
||||
* transformations recursively on children
|
||||
* @return {Boolean} {@true if the matrix was applied}
|
||||
*/
|
||||
apply: function(recursively, _setApplyMatrix) {
|
||||
var owner = this._owner;
|
||||
if (owner) {
|
||||
owner.transform(null, true, Base.pick(recursively, true),
|
||||
_setApplyMatrix);
|
||||
owner.transform(null, Base.pick(recursively, true), _setApplyMatrix);
|
||||
// If the matrix was successfully applied, it will be reset now.
|
||||
return this.isIdentity();
|
||||
}
|
||||
|
@ -245,8 +247,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* @return {Matrix} this affine transform
|
||||
*/
|
||||
scale: function(/* scale, center */) {
|
||||
var scale = Point.read(arguments),
|
||||
center = Point.read(arguments, 0, { readNull: true });
|
||||
var args = arguments,
|
||||
scale = Point.read(args),
|
||||
center = Point.read(args, 0, { readNull: true });
|
||||
if (center)
|
||||
this.translate(center);
|
||||
this._a *= scale.x;
|
||||
|
@ -326,8 +329,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
shear: function(/* shear, center */) {
|
||||
// Do not modify point, center, since that would arguments of which
|
||||
// we're reading from!
|
||||
var shear = Point.read(arguments),
|
||||
center = Point.read(arguments, 0, { readNull: true });
|
||||
var args = arguments,
|
||||
shear = Point.read(args),
|
||||
center = Point.read(args, 0, { readNull: true });
|
||||
if (center)
|
||||
this.translate(center);
|
||||
var a = this._a,
|
||||
|
@ -362,8 +366,9 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* @return {Matrix} this affine transform
|
||||
*/
|
||||
skew: function(/* skew, center */) {
|
||||
var skew = Point.read(arguments),
|
||||
center = Point.read(arguments, 0, { readNull: true }),
|
||||
var args = arguments,
|
||||
skew = Point.read(args),
|
||||
center = Point.read(args, 0, { readNull: true }),
|
||||
toRadians = Math.PI / 180,
|
||||
shear = new Point(Math.tan(skew.x * 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
|
||||
* to this matrix. This is the equivalent of multiplying
|
||||
* `(specified matrix) s* (this matrix)`.
|
||||
* `(specified matrix) * (this matrix)`.
|
||||
*
|
||||
* @param {Matrix} matrix the matrix to prepend
|
||||
* @return {Matrix} the newly created matrix
|
||||
|
@ -498,15 +503,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* @deprecated use use {@link #append(matrix)} instead.
|
||||
* @deprecated use {@link #append(matrix)} instead.
|
||||
*/
|
||||
concatenate: '#append',
|
||||
/**
|
||||
* @deprecated use use {@link #prepend(matrix)} instead.
|
||||
* @deprecated use {@link #prepend(matrix)} instead.
|
||||
*/
|
||||
preConcatenate: '#prepend',
|
||||
/**
|
||||
* @deprecated use use {@link #appended(matrix)} instead.
|
||||
* @deprecated use {@link #appended(matrix)} instead.
|
||||
*/
|
||||
chain: '#appended',
|
||||
|
||||
|
@ -644,6 +649,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* Inverse transforms a point and returns the result.
|
||||
*
|
||||
* @param {Point} point the point to be transformed
|
||||
* @return {Point}
|
||||
*/
|
||||
inverseTransform: function(/* point */) {
|
||||
return this._inverseTransform(Point.read(arguments));
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -170,6 +170,8 @@ var Point = Base.extend(/** @lends Point# */{
|
|||
* for calls of `set()`.
|
||||
*
|
||||
* @function
|
||||
* @param {...*} values
|
||||
* @return {Point}
|
||||
*/
|
||||
set: '#initialize',
|
||||
|
||||
|
@ -431,11 +433,12 @@ var Point = Base.extend(/** @lends Point# */{
|
|||
* @return {Number}
|
||||
*/
|
||||
getDistance: function(/* point, squared */) {
|
||||
var point = Point.read(arguments),
|
||||
var args = arguments,
|
||||
point = Point.read(args),
|
||||
x = point.x - this.x,
|
||||
y = point.y - this.y,
|
||||
d = x * x + y * y,
|
||||
squared = Base.read(arguments);
|
||||
squared = Base.read(args);
|
||||
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}
|
||||
*/
|
||||
isClose: function(/* point, tolerance */) {
|
||||
var point = Point.read(arguments),
|
||||
tolerance = Base.read(arguments);
|
||||
var args = arguments,
|
||||
point = Point.read(args),
|
||||
tolerance = Base.read(args);
|
||||
return this.getDistance(point) <= tolerance;
|
||||
},
|
||||
|
||||
|
@ -768,7 +772,7 @@ var Point = Base.extend(/** @lends Point# */{
|
|||
*
|
||||
* @param {Number} quadrant the quadrant to check against
|
||||
* @return {Boolean} {@true if either x or y are not a number}
|
||||
* @see #getQuadrant()
|
||||
* @see #quadrant
|
||||
*/
|
||||
isInQuadrant: function(q) {
|
||||
// Map quadrant to x & y coordinate pairs and multiply with coordinates,
|
||||
|
@ -935,8 +939,9 @@ var Point = Base.extend(/** @lends Point# */{
|
|||
* [point1, point2, point3].reduce(Point.min) // {x: 60, y: 5}
|
||||
*/
|
||||
min: function(/* point1, point2 */) {
|
||||
var point1 = Point.read(arguments),
|
||||
point2 = Point.read(arguments);
|
||||
var args = arguments,
|
||||
point1 = Point.read(args),
|
||||
point2 = Point.read(args);
|
||||
return new Point(
|
||||
Math.min(point1.x, point2.x),
|
||||
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}
|
||||
*/
|
||||
max: function(/* point1, point2 */) {
|
||||
var point1 = Point.read(arguments),
|
||||
point2 = Point.read(arguments);
|
||||
var args = arguments,
|
||||
point1 = Point.read(args),
|
||||
point2 = Point.read(args);
|
||||
return new Point(
|
||||
Math.max(point1.x, point2.x),
|
||||
Math.max(point1.y, point2.y)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @name Rectangle#initialize
|
||||
* @param {Rectangle} rt
|
||||
* @param {Rectangle} rectangle
|
||||
*/
|
||||
initialize: function Rectangle(arg0, arg1, arg2, arg3) {
|
||||
var type = typeof arg0,
|
||||
var args = arguments,
|
||||
type = typeof arg0,
|
||||
read;
|
||||
if (type === 'number') {
|
||||
// new Rectangle(x, y, width, height)
|
||||
|
@ -86,7 +87,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
// new Rectangle(), new Rectangle(null)
|
||||
this._set(0, 0, 0, 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.
|
||||
if (Array.isArray(arg0)) {
|
||||
this._set.apply(this, arg0);
|
||||
|
@ -98,11 +99,13 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
arg0.width || 0, arg0.height || 0);
|
||||
read = 1;
|
||||
} else if (arg0.from === undefined && arg0.to === undefined) {
|
||||
// Use Base.filter() to support whatever property the rectangle
|
||||
// can take, but handle from/to separately below.
|
||||
// Use `Base.readSupported()` to read and consume whatever
|
||||
// property the rectangle can receive, but handle `from` / `to`
|
||||
// separately below.
|
||||
this._set(0, 0, 0, 0);
|
||||
Base.filter(this, arg0);
|
||||
read = 1;
|
||||
if (Base.readSupported(args, this)) {
|
||||
read = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (read === undefined) {
|
||||
|
@ -111,17 +114,16 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
// We're supporting both reading from a normal arguments list and
|
||||
// covering the Rectangle({ from: , to: }) constructor, through
|
||||
// Point.readNamed().
|
||||
var frm = Point.readNamed(arguments, 'from'),
|
||||
next = Base.peek(arguments),
|
||||
var frm = Point.readNamed(args, 'from'),
|
||||
next = Base.peek(args),
|
||||
x = frm.x,
|
||||
y = frm.y,
|
||||
width,
|
||||
height;
|
||||
if (next && next.x !== undefined
|
||||
|| Base.hasNamed(arguments, 'to')) {
|
||||
if (next && next.x !== undefined || Base.hasNamed(args, 'to')) {
|
||||
// new Rectangle(from, to)
|
||||
// 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;
|
||||
height = to.y - y;
|
||||
// Check if horizontal or vertical order needs to be reversed.
|
||||
|
@ -135,19 +137,19 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
}
|
||||
} else {
|
||||
// new Rectangle(point, size)
|
||||
var size = Size.read(arguments);
|
||||
var size = Size.read(args);
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
}
|
||||
this._set(x, y, width, height);
|
||||
read = arguments.__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;
|
||||
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 = args.__filtered;
|
||||
if (filtered)
|
||||
this.__filtered = filtered;
|
||||
if (this.__read)
|
||||
this.__read = read;
|
||||
return this;
|
||||
|
@ -159,6 +161,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
* constructors also work for calls of `set()`.
|
||||
*
|
||||
* @function
|
||||
* @param {...*} values
|
||||
* @return {Rectangle}
|
||||
*/
|
||||
set: '#initialize',
|
||||
|
||||
|
@ -201,6 +205,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
|
||||
/**
|
||||
* Returns a copy of the rectangle.
|
||||
* @return {Rectangle}
|
||||
*/
|
||||
clone: function() {
|
||||
return new Rectangle(this.x, this.y, this.width, this.height);
|
||||
|
@ -772,6 +777,8 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
* Rectangle#contains(point)} returns `false` for that point.
|
||||
*
|
||||
* @param {Point} point
|
||||
* @return {Rectangle} the smallest rectangle that contains both the
|
||||
* original rectangle and the specified point
|
||||
*/
|
||||
include: function(/* point */) {
|
||||
var point = Point.read(arguments);
|
||||
|
@ -783,17 +790,18 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Expands the rectangle by the specified amount in horizontal and
|
||||
* vertical directions.
|
||||
* Returns a new rectangle expanded by the specified amount in horizontal
|
||||
* and vertical directions.
|
||||
*
|
||||
* @name Rectangle#expand
|
||||
* @function
|
||||
* @param {Number|Size|Point} amount the amount to expand the rectangle in
|
||||
* both directions
|
||||
* @return {Rectangle} the expanded rectangle
|
||||
*/
|
||||
/**
|
||||
* Expands the rectangle by the specified amounts in horizontal and
|
||||
* vertical directions.
|
||||
* Returns a new rectangle expanded by the specified amounts in horizontal
|
||||
* and vertical directions.
|
||||
*
|
||||
* @name Rectangle#expand
|
||||
* @function
|
||||
|
@ -801,6 +809,7 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
* direction
|
||||
* @param {Number} ver the amount to expand the rectangle in vertical
|
||||
* direction
|
||||
* @return {Rectangle} the expanded rectangle
|
||||
*/
|
||||
expand: function(/* amount */) {
|
||||
var amount = Size.read(arguments),
|
||||
|
@ -811,21 +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
|
||||
* @function
|
||||
* @param {Number} amount
|
||||
* @return {Rectangle} the scaled rectangle
|
||||
*/
|
||||
/**
|
||||
* Scales the rectangle in horizontal direction by the specified `hor`
|
||||
* amount and in vertical direction by the specified `ver` amount from its
|
||||
* center.
|
||||
* Returns a new rectangle scaled in horizontal direction by the specified
|
||||
* `hor` amount and in vertical direction by the specified `ver` amount
|
||||
* from its center.
|
||||
*
|
||||
* @name Rectangle#scale
|
||||
* @function
|
||||
* @param {Number} hor
|
||||
* @param {Number} ver
|
||||
* @return {Rectangle} the scaled rectangle
|
||||
*/
|
||||
scale: function(hor, ver) {
|
||||
return this.expand(this.width * hor - this.width,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -130,6 +130,8 @@ var Size = Base.extend(/** @lends Size# */{
|
|||
* for calls of `set()`.
|
||||
*
|
||||
* @function
|
||||
* @param {...*} values
|
||||
* @return {Size}
|
||||
*/
|
||||
set: '#initialize',
|
||||
|
||||
|
@ -158,7 +160,7 @@ var Size = Base.extend(/** @lends Size# */{
|
|||
* Checks whether the width and height of the size are equal to those of the
|
||||
* supplied size.
|
||||
*
|
||||
* @param {Size}
|
||||
* @param {Size} size the size to compare to
|
||||
* @return {Boolean}
|
||||
*
|
||||
* @example
|
||||
|
@ -176,6 +178,7 @@ var Size = Base.extend(/** @lends Size# */{
|
|||
|
||||
/**
|
||||
* Returns a copy of the size.
|
||||
* @return {Size}
|
||||
*/
|
||||
clone: function() {
|
||||
return new Size(this.width, this.height);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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
|
||||
* arguments form a passed property object literal. Calling Base.readNamed()
|
||||
* can read both from such named properties and normal unnamed arguments
|
||||
* through Base.read(). In use for example for the various
|
||||
* Path.Constructors.
|
||||
* Allows using of `Base.read()` mechanism in combination with reading named
|
||||
* arguments form a passed property object literal. Calling
|
||||
* `Base.readNamed()` can read both from such named properties and normal
|
||||
* unnamed arguments through `Base.read()`. In use for example for
|
||||
* the various `Path` constructors in `Path.Constructors.js`.
|
||||
*
|
||||
* @param {Array} list the list to read from, either an arguments object or
|
||||
* a normal array
|
||||
|
@ -287,24 +287,68 @@ statics: /** @lends Base */{
|
|||
*/
|
||||
readNamed: function(list, name, start, options, amount) {
|
||||
var value = this.getNamed(list, name),
|
||||
hasObject = value !== undefined;
|
||||
if (hasObject) {
|
||||
// Create a _filtered object that inherits from list[0], and
|
||||
hasValue = value !== undefined;
|
||||
if (hasValue) {
|
||||
// Create a _filtered object that inherits from `source`, and
|
||||
// override all fields that were already read with undefined.
|
||||
var filtered = list.__filtered;
|
||||
if (!filtered) {
|
||||
filtered = list.__filtered = Base.create(list[0]);
|
||||
// Point _unfiltered to the original so Base#_set() can
|
||||
// execute hasOwnProperty on it.
|
||||
filtered.__unfiltered = list[0];
|
||||
var source = this.getSource(list);
|
||||
filtered = list.__filtered = Base.create(source);
|
||||
// Point __unfiltered to the original, so `Base.filter()` can
|
||||
// use it to get all keys to iterate over.
|
||||
filtered.__unfiltered = source;
|
||||
}
|
||||
// delete wouldn't work since the masked parent's value would
|
||||
// shine through.
|
||||
filtered[name] = undefined;
|
||||
}
|
||||
var l = hasObject ? [value] : list,
|
||||
res = this.read(l, start, options, amount);
|
||||
return res;
|
||||
return this.read(hasValue ? [value] : list, start, options, amount);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
getNamed: function(list, name) {
|
||||
var arg = list[0];
|
||||
if (list._hasObject === undefined)
|
||||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
||||
if (list._hasObject)
|
||||
var source = this.getSource(list);
|
||||
if (source) {
|
||||
// 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
|
||||
&& (useTarget || !(obj instanceof Layer))) {
|
||||
var arg = args[0];
|
||||
if (Base.isPlainObject(arg))
|
||||
if (Base.isPlainObject(arg)) {
|
||||
arg.insert = false;
|
||||
// When using target, make sure the `item.insert()`
|
||||
// method is not overridden with the `arg.insert`
|
||||
// property that was just set. Pass an exclude
|
||||
// object to the call of `obj.set()` below (#1392).
|
||||
if (useTarget) {
|
||||
args = args.concat([{ insert: true }]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// When reusing an object, initialize it through #set()
|
||||
// instead of the constructor function:
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -68,9 +68,9 @@ var Emitter = {
|
|||
},
|
||||
|
||||
once: function(type, func) {
|
||||
return this.on(type, function() {
|
||||
return this.on(type, function handler() {
|
||||
func.apply(this, arguments);
|
||||
this.off(type, func);
|
||||
this.off(type, handler);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -87,7 +87,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
// here: { chrome: true, webkit: false }, Mozilla missing is the
|
||||
// only difference to jQuery.browser
|
||||
user.replace(
|
||||
/(opera|chrome|safari|webkit|firefox|msie|trident|atom|node)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g,
|
||||
/(opera|chrome|safari|webkit|firefox|msie|trident|atom|node|jsdom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g,
|
||||
function(match, n, v1, v2, rv) {
|
||||
// Do not set additional browsers once chrome is detected.
|
||||
if (!agent.chrome) {
|
||||
|
@ -95,7 +95,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
/^(node|trident)$/.test(n) ? rv : v1;
|
||||
agent.version = v;
|
||||
agent.versionNumber = parseFloat(v);
|
||||
n = n === 'trident' ? 'msie' : n;
|
||||
n = { trident: 'msie', jsdom: 'node' }[n] || n;
|
||||
agent.name = n;
|
||||
agent[n] = true;
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
* The version of Paper.js, as a string.
|
||||
*
|
||||
* @type String
|
||||
* @readonly
|
||||
*/
|
||||
version: /*#=*/__options.version,
|
||||
|
||||
|
@ -200,7 +201,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
* mapping, in case the code that's passed in has already been mingled.
|
||||
*
|
||||
* @param {String} code the PaperScript code
|
||||
* @param {Object} [option] the compilation options
|
||||
* @param {Object} [options] the compilation options
|
||||
*/
|
||||
execute: function(code, options) {
|
||||
/*#*/ if (__options.paperScript) {
|
||||
|
@ -310,6 +311,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
* Retrieves a PaperScope object with the given scope id.
|
||||
*
|
||||
* @param id
|
||||
* @return {PaperScope}
|
||||
*/
|
||||
get: function(id) {
|
||||
return this._scopes[id] || null;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -127,7 +127,7 @@ Base.exports.PaperScript = function() {
|
|||
* mapping, in case the code that's passed in has already been mingled.
|
||||
*
|
||||
* @param {String} code the PaperScript code
|
||||
* @param {Object} [option] the compilation options
|
||||
* @param {Object} [options] the compilation options
|
||||
* @return {Object} an object holding the compiled PaperScript translated
|
||||
* into JavaScript code along with source-maps and other information.
|
||||
*/
|
||||
|
@ -177,7 +177,7 @@ Base.exports.PaperScript = function() {
|
|||
var start = getOffset(node.range[0]),
|
||||
end = getOffset(node.range[1]),
|
||||
insert = 0;
|
||||
// Sort insertions by their offset, so getOffest() can do its thing
|
||||
// Sort insertions by their offset, so getOffset() can do its thing
|
||||
for (var i = insertions.length - 1; i >= 0; i--) {
|
||||
if (start > insertions[i][0]) {
|
||||
insert = i + 1;
|
||||
|
@ -188,27 +188,8 @@ Base.exports.PaperScript = function() {
|
|||
code = code.substring(0, start) + str + code.substring(end);
|
||||
}
|
||||
|
||||
// Recursively walks the AST and replaces the code of certain nodes
|
||||
function walkAST(node, parent) {
|
||||
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) {
|
||||
function handleOverloading(node, parent) {
|
||||
switch (node.type) {
|
||||
case 'UnaryExpression': // -a
|
||||
if (node.operator in unaryOperators
|
||||
&& node.argument.type !== 'Literal') {
|
||||
|
@ -256,12 +237,19 @@ Base.exports.PaperScript = function() {
|
|||
exp = '__$__(' + arg + ', "' + node.operator[0]
|
||||
+ '", 1)',
|
||||
str = arg + ' = ' + exp;
|
||||
// If this is not a prefixed update expression
|
||||
// (++a, --a), assign the old value before updating it.
|
||||
if (!node.prefix
|
||||
&& (parentType === 'AssignmentExpression'
|
||||
|| parentType === 'VariableDeclarator')) {
|
||||
// Handle special issue #691 where the old value is
|
||||
if (node.prefix) {
|
||||
// A prefixed update expression (++a / --a),
|
||||
// wrap expression in paranthesis. See #1611
|
||||
str = '(' + str + ')';
|
||||
} else if (
|
||||
// A suffixed update expression (a++, a--),
|
||||
// assign the old value before updating it.
|
||||
// See #691, #1450
|
||||
parentType === 'AssignmentExpression' ||
|
||||
parentType === 'VariableDeclarator' ||
|
||||
parentType === 'BinaryExpression'
|
||||
) {
|
||||
// Handle special case where the old value is
|
||||
// assigned to itself, and the expression is just
|
||||
// executed after, e.g.: `var x = ***; x = x++;`
|
||||
if (getCode(parent.left || parent.id) === arg)
|
||||
|
@ -284,6 +272,11 @@ Base.exports.PaperScript = function() {
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleExports(node) {
|
||||
switch (node.type) {
|
||||
case 'ExportDefaultDeclaration':
|
||||
// Convert `export default` to `module.exports = ` statements:
|
||||
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:
|
||||
// Encodes a Variable Length Quantity as a Base64 string.
|
||||
// See: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps
|
||||
// See: https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
|
||||
function encodeVLQ(value) {
|
||||
var res = '',
|
||||
base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
@ -339,15 +361,16 @@ Base.exports.PaperScript = function() {
|
|||
}
|
||||
|
||||
var url = options.url || '',
|
||||
agent = paper.agent,
|
||||
version = agent.versionNumber,
|
||||
offsetCode = false,
|
||||
sourceMaps = options.sourceMaps,
|
||||
paperFeatures = options.paperFeatures || {},
|
||||
// Include the original code in the sourceMap if there is no linked
|
||||
// source file so the debugger can still display it correctly.
|
||||
source = options.source || code,
|
||||
lineBreaks = /\r\n|\n|\r/mg,
|
||||
offset = options.offset || 0,
|
||||
agent = paper.agent,
|
||||
version = agent.versionNumber,
|
||||
offsetCode = false,
|
||||
lineBreaks = /\r\n|\n|\r/mg,
|
||||
map;
|
||||
// TODO: Verify these browser versions for source map support, and check
|
||||
// other browsers.
|
||||
|
@ -397,12 +420,17 @@ Base.exports.PaperScript = function() {
|
|||
sourcesContent: [source]
|
||||
};
|
||||
}
|
||||
// Now do the parsing magic
|
||||
walkAST(parse(code, {
|
||||
ranges: true,
|
||||
preserveParens: true,
|
||||
sourceType: 'module'
|
||||
}));
|
||||
if (
|
||||
paperFeatures.operatorOverloading !== false ||
|
||||
paperFeatures.moduleExports !== false
|
||||
) {
|
||||
// Now do the parsing magic
|
||||
walkAST(parse(code, {
|
||||
ranges: true,
|
||||
preserveParens: true,
|
||||
sourceType: 'module'
|
||||
}), null, paperFeatures);
|
||||
}
|
||||
if (map) {
|
||||
if (offsetCode) {
|
||||
// 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 {PaperScope} scope the scope for which the code is executed
|
||||
* @param {Object} [option] the compilation options
|
||||
* @return the exports defined in the executed code
|
||||
* @param {Object} [options] the compilation options
|
||||
* @return {Object} the exports defined in the executed code
|
||||
*/
|
||||
function execute(code, scope, options) {
|
||||
// Set currently active scope.
|
||||
|
@ -484,7 +512,7 @@ Base.exports.PaperScript = function() {
|
|||
}
|
||||
}
|
||||
}
|
||||
expose({ __$__: __$__, $__: $__, paper: scope, view: view, tool: tool },
|
||||
expose({ __$__: __$__, $__: $__, paper: scope, tool: tool },
|
||||
true);
|
||||
expose(scope);
|
||||
// Add a fake `module.exports` object so PaperScripts can export things.
|
||||
|
@ -657,7 +685,9 @@ Base.exports.PaperScript = function() {
|
|||
compile: compile,
|
||||
execute: execute,
|
||||
load: load,
|
||||
parse: parse
|
||||
parse: parse,
|
||||
calculateBinary: __$__,
|
||||
calculateUnary: $__
|
||||
};
|
||||
// Pass on `this` as the binding object, so we can reference Acorn both in
|
||||
// development and in the built library.
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -39,7 +39,7 @@
|
|||
*
|
||||
* The project for which the PaperScript is executed.
|
||||
*
|
||||
* Note that when working with mulitple projects, this does not necessarily
|
||||
* Note that when working with multiple projects, this does not necessarily
|
||||
* reflect the currently active project. For this, use
|
||||
* {@link PaperScope#project} instead.
|
||||
*
|
||||
|
@ -57,19 +57,20 @@
|
|||
/**
|
||||
* The reference to the project's view.
|
||||
*
|
||||
* Note that when working with mulitple projects, this does not necessarily
|
||||
* Note that when working with multiple projects, this does not necessarily
|
||||
* reflect the view of the currently active project. For this, use
|
||||
* {@link PaperScope#view} instead.
|
||||
*
|
||||
* @name view
|
||||
* @type View
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The reference to the tool object which is automatically created when global
|
||||
* tool event handlers are defined.
|
||||
*
|
||||
* Note that when working with mulitple tools, this does not necessarily
|
||||
* Note that when working with multiple tools, this does not necessarily
|
||||
* reflect the currently active tool. For this, use {@link PaperScope#tool}
|
||||
* instead.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -171,8 +171,7 @@ var Group = Item.extend(/** @lends Group# */{
|
|||
_getBounds: function _getBounds(matrix, options) {
|
||||
var clipItem = this._getClipItem();
|
||||
return clipItem
|
||||
? clipItem._getCachedBounds(
|
||||
matrix && matrix.appended(clipItem._matrix),
|
||||
? clipItem._getCachedBounds(clipItem._matrix.prepended(matrix),
|
||||
Base.set({}, options, { stroke: false }))
|
||||
: _getBounds.base.call(this, matrix, options);
|
||||
},
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -75,7 +75,7 @@ var HitResult = Base.extend(/** @lends HitResult# */{
|
|||
*
|
||||
* @name HitResult#color
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -105,7 +105,7 @@ var HitResult = Base.extend(/** @lends HitResult# */{
|
|||
*/
|
||||
getOptions: function(args) {
|
||||
var options = args && Base.read(args);
|
||||
return Base.set({
|
||||
return new Base({
|
||||
// Type of item, for instanceof check: Group, Layer, Path,
|
||||
// CompoundPath, Shape, Raster, SymbolItem, ...
|
||||
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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -658,8 +658,8 @@ new function() { // Injection scope for various item event handlers
|
|||
|
||||
/**
|
||||
* Specifies whether the item defines a clip mask. This can only be set on
|
||||
* paths, compound paths, and text frame objects, and only if the item is
|
||||
* already contained within a clipping group.
|
||||
* paths and compound paths, and only if the item is already contained
|
||||
* within a clipping group.
|
||||
*
|
||||
* @bean
|
||||
* @type Boolean
|
||||
|
@ -1075,7 +1075,9 @@ new function() { // Injection scope for various item event handlers
|
|||
options = options || {};
|
||||
for (var i = 0, l = items.length; i < l; i++) {
|
||||
var item = items[i];
|
||||
if (item._visible && !item.isEmpty()) {
|
||||
// Item is handled if it is visible and not recursively empty.
|
||||
// This avoid errors with nested empty groups (#1467).
|
||||
if (item._visible && !item.isEmpty(true)) {
|
||||
// Pass true for noInternal, since even when getting
|
||||
// internal bounds for this item, we need to apply the
|
||||
// matrices to its children.
|
||||
|
@ -1120,6 +1122,17 @@ new function() { // Injection scope for various item event handlers
|
|||
* @type Rectangle
|
||||
*/
|
||||
|
||||
/**
|
||||
* The bounding rectangle of the item without any matrix transformations.
|
||||
*
|
||||
* Typical use case would be drawing a frame around the object where you
|
||||
* want to draw something of the same size, position, rotation, and scaling,
|
||||
* like a selection frame.
|
||||
*
|
||||
* @name Item#internalBounds
|
||||
* @type Rectangle
|
||||
*/
|
||||
|
||||
/**
|
||||
* The rough bounding rectangle of the item that is sure to include all of
|
||||
* the drawing, including stroke width.
|
||||
|
@ -1805,11 +1818,15 @@ new function() { // Injection scope for various item event handlers
|
|||
* }
|
||||
*
|
||||
* @param {Point} point the point to check for
|
||||
* @return {Boolean}
|
||||
*/
|
||||
contains: function(/* point */) {
|
||||
// See CompoundPath#_contains() for the reason for !!
|
||||
return !!this._contains(
|
||||
this._matrix._inverseTransform(Point.read(arguments)));
|
||||
var matrix = this._matrix;
|
||||
return (
|
||||
matrix.isInvertible() &&
|
||||
!!this._contains(matrix._inverseTransform(Point.read(arguments)))
|
||||
);
|
||||
},
|
||||
|
||||
_contains: function(point) {
|
||||
|
@ -1866,16 +1883,18 @@ new function() { // Injection scope for various item event handlers
|
|||
},
|
||||
new function() { // Injection scope for hit-test functions shared with project
|
||||
function hitTest(/* point, options */) {
|
||||
var args = arguments;
|
||||
return this._hitTest(
|
||||
Point.read(arguments),
|
||||
HitResult.getOptions(arguments));
|
||||
Point.read(args),
|
||||
HitResult.getOptions(args));
|
||||
}
|
||||
|
||||
function hitTestAll(/* point, options */) {
|
||||
var point = Point.read(arguments),
|
||||
options = HitResult.getOptions(arguments),
|
||||
var args = arguments,
|
||||
point = Point.read(args),
|
||||
options = HitResult.getOptions(args),
|
||||
all = [];
|
||||
this._hitTest(point, Base.set({ all: all }, options));
|
||||
this._hitTest(point, new Base({ all: all }, options));
|
||||
return all;
|
||||
}
|
||||
|
||||
|
@ -2353,6 +2372,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
* items can have children.
|
||||
*
|
||||
* @param {String} json the JSON data to import from
|
||||
* @return {Item}
|
||||
*/
|
||||
importJSON: function(json) {
|
||||
// Try importing into `this`. If another item is returned, try adding
|
||||
|
@ -2388,7 +2408,8 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
* kept as a link to their external URL.
|
||||
*
|
||||
* @param {Object} [options] the export options
|
||||
* @return {SVGElement} the item converted to an SVG node
|
||||
* @return {SVGElement|String} the item converted to an SVG node or a
|
||||
* `String` depending on `option.asString` value
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -2772,6 +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
|
||||
* in the project hierarchy instead.
|
||||
*
|
||||
* @param {Item} item the item that will replace this item
|
||||
* @return {Boolean} {@true if the item was replaced}
|
||||
*/
|
||||
replaceWith: function(item) {
|
||||
|
@ -2840,11 +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}
|
||||
* 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;
|
||||
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.
|
||||
*/
|
||||
_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.
|
||||
function getList(item) {
|
||||
var list = [];
|
||||
|
@ -3057,7 +3091,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#strokeColor
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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
|
||||
* @property
|
||||
* @type Array
|
||||
* @type Number[]
|
||||
* @default []
|
||||
*/
|
||||
|
||||
|
@ -3219,7 +3253,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#fillColor
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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
|
||||
* @name Item#shadowColor
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*/
|
||||
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
|
||||
var rotate = key === 'rotate';
|
||||
this[key] = function(/* value, center */) {
|
||||
var value = (rotate ? Base : Point).read(arguments),
|
||||
center = Point.read(arguments, 0, { readNull: true });
|
||||
var args = arguments,
|
||||
value = (rotate ? Base : Point).read(args),
|
||||
center = Point.read(args, 0, { readNull: true });
|
||||
return this.transform(new Matrix()[key](value,
|
||||
center || this.getPosition(true)));
|
||||
};
|
||||
|
@ -3438,7 +3473,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#shear
|
||||
* @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}]
|
||||
* @see Matrix#shear(shear[, center])
|
||||
*/
|
||||
|
@ -3460,7 +3495,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#skew
|
||||
* @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}]
|
||||
* @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',
|
||||
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||
// 'lines'. Default: ['objects', 'children']
|
||||
transform: function(matrix, _applyMatrix, _applyRecursively,
|
||||
_setApplyMatrix) {
|
||||
transform: function(matrix, _applyRecursively, _setApplyMatrix) {
|
||||
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(),
|
||||
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
|
||||
// matrix would be identity.
|
||||
&& ((!_matrix.isIdentity() || transformMatrix)
|
||||
// Even if it's an identity matrix, we still need to
|
||||
// recursively apply the matrix to children.
|
||||
|| _applyMatrix && _applyRecursively && this._children);
|
||||
transformMatrix || !_matrix.isIdentity() ||
|
||||
// Even if it's an identity matrix, we may still need to
|
||||
// recursively apply the matrix to children.
|
||||
_applyRecursively && this._children
|
||||
)
|
||||
);
|
||||
// Bail out if there is nothing to do.
|
||||
if (!transformMatrix && !applyMatrix)
|
||||
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.
|
||||
// Application is not possible on Raster, PointText, SymbolItem, since
|
||||
// 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
|
||||
// it along too.
|
||||
var pivot = this._pivot;
|
||||
|
@ -3594,9 +3633,9 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
_transformContent: function(matrix, applyRecursively, setApplyMatrix) {
|
||||
var children = this._children;
|
||||
if (children) {
|
||||
for (var i = 0, l = children.length; i < l; i++)
|
||||
children[i].transform(matrix, true, applyRecursively,
|
||||
setApplyMatrix);
|
||||
for (var i = 0, l = children.length; i < l; i++) {
|
||||
children[i].transform(matrix, applyRecursively, setApplyMatrix);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
@ -3745,7 +3784,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onFrame
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onFrame
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -3772,7 +3811,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseDown
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseDown
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -3822,7 +3861,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseDrag
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseDrag
|
||||
*
|
||||
* @example {@paperscript height=240}
|
||||
|
@ -3851,7 +3890,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseUp
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseUp
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -3881,7 +3920,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onClick
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onClick
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -3931,7 +3970,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onDoubleClick
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onDoubleClick
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -3981,7 +4020,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseMove
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseMove
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -4012,7 +4051,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseEnter
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseEnter
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -4074,7 +4113,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
*
|
||||
* @name Item#onMouseLeave
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
* @see View#onMouseLeave
|
||||
*
|
||||
* @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
|
||||
// opacity by themselves (they also don't call _setStyles)
|
||||
var blendMode = this._blendMode,
|
||||
opacity = this._opacity,
|
||||
opacity = Numerical.clamp(this._opacity, 0, 1),
|
||||
normalBlend = blendMode === 'normal',
|
||||
nativeBlend = BlendMode.nativeModes[blendMode],
|
||||
// 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);
|
||||
ctx.restore();
|
||||
matrices.pop();
|
||||
if (param.clip && !param.dontFinish)
|
||||
ctx.clip();
|
||||
if (param.clip && !param.dontFinish) {
|
||||
// Pass fill-rule to handle clipping with compound-paths (#1361).
|
||||
ctx.clip(this.getFillRule());
|
||||
}
|
||||
// If a temporary canvas was created, composite it onto the main canvas:
|
||||
if (!direct) {
|
||||
// Use BlendMode.process even for processing normal blendMode with
|
||||
|
@ -4672,4 +4713,176 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
}
|
||||
return this;
|
||||
}
|
||||
}));
|
||||
}), /** @lends Item# */{
|
||||
/**
|
||||
* {@grouptitle Tweening Functions}
|
||||
*
|
||||
* Tween item between two states.
|
||||
*
|
||||
* @name Item#tween
|
||||
*
|
||||
* @option options.duration {Number} the duration of the tweening
|
||||
* @option [options.easing='linear'] {Function|String} an easing function or the type
|
||||
* of the easing: {@values 'linear' 'easeInQuad' 'easeOutQuad'
|
||||
* 'easeInOutQuad' 'easeInCubic' 'easeOutCubic' 'easeInOutCubic'
|
||||
* 'easeInQuart' 'easeOutQuart' 'easeInOutQuart' 'easeInQuint'
|
||||
* 'easeOutQuint' 'easeInOutQuint'}
|
||||
* @option [options.start=true] {Boolean} whether to start tweening automatically
|
||||
*
|
||||
* @function
|
||||
* @param {Object} from the state at the start of the tweening
|
||||
* @param {Object} to the state at the end of the tweening
|
||||
* @param {Object|Number} options the options or the duration
|
||||
* @return {Tween}
|
||||
*
|
||||
* @example {@paperscript height=100}
|
||||
* // Tween fillColor:
|
||||
* var path = new Path.Circle({
|
||||
* radius: view.bounds.height * 0.4,
|
||||
* center: view.center
|
||||
* });
|
||||
* path.tween(
|
||||
* { fillColor: 'blue' },
|
||||
* { fillColor: 'red' },
|
||||
* 3000
|
||||
* );
|
||||
* @example {@paperscript height=100}
|
||||
* // Tween rotation:
|
||||
* var path = new Shape.Rectangle({
|
||||
* fillColor: 'red',
|
||||
* center: [50, view.center.y],
|
||||
* size: [60, 60]
|
||||
* });
|
||||
* path.tween({
|
||||
* rotation: 180,
|
||||
* 'position.x': view.bounds.width - 50,
|
||||
* 'fillColor.hue': '+= 90'
|
||||
* }, {
|
||||
* easing: 'easeInOutCubic',
|
||||
* duration: 2000
|
||||
* });
|
||||
*/
|
||||
/**
|
||||
* Tween item to a state.
|
||||
*
|
||||
* @name Item#tween
|
||||
*
|
||||
* @function
|
||||
* @param {Object} to the state at the end of the tweening
|
||||
* @param {Object|Number} options the options or the duration
|
||||
* @return {Tween}
|
||||
*
|
||||
* @example {@paperscript height=200}
|
||||
* // Tween a nested property with relative values
|
||||
* var path = new Path.Rectangle({
|
||||
* size: [100, 100],
|
||||
* position: view.center,
|
||||
* fillColor: 'red',
|
||||
* });
|
||||
*
|
||||
* var delta = { x: path.bounds.width / 2, y: 0 };
|
||||
*
|
||||
* path.tween({
|
||||
* 'segments[1].point': ['+=', delta],
|
||||
* 'segments[2].point.x': '-= 50'
|
||||
* }, 3000);
|
||||
*
|
||||
* @see Item#tween(from, to, options)
|
||||
*/
|
||||
/**
|
||||
* Tween item.
|
||||
*
|
||||
* @name Item#tween
|
||||
*
|
||||
* @function
|
||||
* @param {Object|Number} options the options or the duration
|
||||
* @return {Tween}
|
||||
*
|
||||
* @see Item#tween(from, to, options)
|
||||
*
|
||||
* @example {@paperscript height=100}
|
||||
* // Start an empty tween and just use the update callback:
|
||||
* var path = new Path.Circle({
|
||||
* fillColor: 'blue',
|
||||
* radius: view.bounds.height * 0.4,
|
||||
* center: view.center,
|
||||
* });
|
||||
* var pathFrom = path.clone({ insert: false })
|
||||
* var pathTo = new Path.Rectangle({
|
||||
* position: view.center,
|
||||
* rectangle: path.bounds,
|
||||
* insert: false
|
||||
* });
|
||||
* path.tween(2000).onUpdate = function(event) {
|
||||
* path.interpolate(pathFrom, pathTo, event.factor)
|
||||
* };
|
||||
*/
|
||||
tween: function(from, to, options) {
|
||||
if (!options) {
|
||||
// If there are only two or one arguments, shift arguments to the
|
||||
// left by one (omit `from`):
|
||||
options = to;
|
||||
to = from;
|
||||
from = null;
|
||||
if (!options) {
|
||||
options = to;
|
||||
to = null;
|
||||
}
|
||||
}
|
||||
var easing = options && options.easing,
|
||||
start = options && options.start,
|
||||
duration = options != null && (
|
||||
typeof options === 'number' ? options : options.duration
|
||||
),
|
||||
tween = new Tween(this, from, to, duration, easing, start);
|
||||
function onFrame(event) {
|
||||
tween._handleFrame(event.time * 1000);
|
||||
if (!tween.running) {
|
||||
this.off('frame', onFrame);
|
||||
}
|
||||
}
|
||||
if (duration) {
|
||||
this.on('frame', onFrame);
|
||||
}
|
||||
return tween;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Tween item to a state.
|
||||
*
|
||||
* @function
|
||||
* @param {Object} to the state at the end of the tweening
|
||||
* @param {Object|Number} options the options or the duration
|
||||
* @return {Tween}
|
||||
*
|
||||
* @see Item#tween(to, options)
|
||||
*/
|
||||
tweenTo: function(to, options) {
|
||||
return this.tween(null, to, options);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Tween item from a state to its state before the tweening.
|
||||
*
|
||||
* @function
|
||||
* @param {Object} from the state at the start of the tweening
|
||||
* @param {Object|Number} options the options or the duration
|
||||
* @return {Tween}
|
||||
*
|
||||
* @see Item#tween(from, to, options)
|
||||
*
|
||||
* @example {@paperscript height=100}
|
||||
* // Tween fillColor from red to the path's initial fillColor:
|
||||
* var path = new Path.Circle({
|
||||
* fillColor: 'blue',
|
||||
* radius: view.bounds.height * 0.4,
|
||||
* center: view.center
|
||||
* });
|
||||
* path.tweenFrom({ fillColor: 'red' }, { duration: 1000 });
|
||||
*/
|
||||
tweenFrom: function(from, options) {
|
||||
return this.tween(from, null, options);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -133,7 +133,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
|||
/**
|
||||
* Checks whether the project has any content or not.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isEmpty: function() {
|
||||
return !this._children.length;
|
||||
|
@ -348,7 +348,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
|||
* {@link #layers} list.
|
||||
*
|
||||
* @param {Number} index the index at which to insert the layer
|
||||
* @param {Item} item the item to be inserted in the project
|
||||
* @param {Layer} layer the layer to be inserted in the project
|
||||
* @return {Layer} the added layer, or `null` if adding was not possible
|
||||
*/
|
||||
insertLayer: function(index, layer) {
|
||||
|
@ -745,6 +745,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
|||
* {@link Project#clear()} to do so.
|
||||
*
|
||||
* @param {String} json the JSON data to import from
|
||||
* @return {Item} the imported item
|
||||
*/
|
||||
importJSON: function(json) {
|
||||
this.activate();
|
||||
|
@ -781,7 +782,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
|||
* kept as a link to their external URL.
|
||||
*
|
||||
* @param {Object} [options] the export options
|
||||
* @return {SVGElement} the project converted to an SVG node
|
||||
* @return {SVGElement|String} the project converted to an SVG node or a
|
||||
* `String` depending on `option.asString` value
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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'],
|
||||
_smoothing: false,
|
||||
// Enforce creation of beans, as bean getters have hidden parameters.
|
||||
// See #getContext(_change) below.
|
||||
beans: true,
|
||||
|
||||
// TODO: Implement type, width, height.
|
||||
// TODO: Have SymbolItem & Raster inherit from a shared class?
|
||||
/**
|
||||
* Creates a new raster item from the passed argument, and places it in the
|
||||
* active layer. `object` can either be a DOM Image, a Canvas, or a string
|
||||
* active layer. `source` can either be a DOM Image, a Canvas, or a string
|
||||
* describing the URL to load the image from, or the ID of a DOM element to
|
||||
* get the image from (either a DOM Image or a Canvas).
|
||||
*
|
||||
* @name Raster#initialize
|
||||
* @param {HTMLImageElement|HTMLCanvasElement|String} [source] the source of
|
||||
* the raster
|
||||
* @param {Point} [position] the center position at which the raster item is
|
||||
|
@ -77,22 +81,64 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
* raster.scale(0.5);
|
||||
* raster.rotate(10);
|
||||
*/
|
||||
initialize: function Raster(object, position) {
|
||||
// Support two forms of item initialization: Passing one object literal
|
||||
// describing all the different properties to be set, or an image
|
||||
// (object) and a point where it should be placed (point).
|
||||
/**
|
||||
* Creates a new empty raster of the given size, and places it in the
|
||||
* active layer.
|
||||
*
|
||||
* @name Raster#initialize
|
||||
* @param {Size} size the size of the raster
|
||||
* @param {Point} [position] the center position at which the raster item is
|
||||
* placed
|
||||
*
|
||||
* @example {@paperscript height=150}
|
||||
* // Creating an empty raster and fill it with random pixels:
|
||||
* var width = 100;
|
||||
* var height = 100;
|
||||
*
|
||||
* // Create an empty raster placed at view center.
|
||||
* var raster = new Raster(new Size(width, height), view.center);
|
||||
*
|
||||
* // For all of its pixels...
|
||||
* for (var i = 0; i < width; i++) {
|
||||
* for (var j = 0; j < height; j++) {
|
||||
* // ...set a random color.
|
||||
* raster.setPixel(i, j, Color.random());
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
initialize: function Raster(source, position) {
|
||||
// Support three forms of item initialization:
|
||||
// - One object literal describing all the different properties.
|
||||
// - An image (Image|Canvas|String) and an optional position (Point).
|
||||
// - A size (Size) describing the canvas that will be created and an
|
||||
// optional position (Point).
|
||||
// If _initialize can set properties through object literal, we're done.
|
||||
// Otherwise we need to check the type of object:
|
||||
if (!this._initialize(object,
|
||||
position !== undefined && Point.read(arguments, 1))) {
|
||||
// object can be an image, canvas, URL or DOM-ID:
|
||||
var image = typeof object === 'string'
|
||||
? document.getElementById(object) : object;
|
||||
if (!this._initialize(source,
|
||||
position !== undefined && Point.read(arguments))) {
|
||||
var image,
|
||||
type = typeof source,
|
||||
object = type === 'string'
|
||||
? document.getElementById(source)
|
||||
: type === 'object'
|
||||
? source
|
||||
: null;
|
||||
if (object && object !== Item.NO_INSERT) {
|
||||
if (object.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) {
|
||||
// #setImage() handles both canvas and image types.
|
||||
this.setImage(image);
|
||||
} else {
|
||||
this.setSource(object);
|
||||
this.setSource(source);
|
||||
}
|
||||
}
|
||||
if (!this._size) {
|
||||
|
@ -305,7 +351,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
* case `null` is returned instead.
|
||||
*
|
||||
* @bean
|
||||
* @type HTMLCanvasELement
|
||||
* @type HTMLCanvasElement
|
||||
*/
|
||||
getCanvas: function() {
|
||||
if (!this._canvas) {
|
||||
|
@ -330,15 +376,15 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
* The Canvas 2D drawing context of the raster.
|
||||
*
|
||||
* @bean
|
||||
* @type Context
|
||||
* @type CanvasRenderingContext2D
|
||||
*/
|
||||
getContext: function(modify) {
|
||||
getContext: function(_change) {
|
||||
if (!this._context)
|
||||
this._context = this.getCanvas().getContext('2d');
|
||||
// Support a hidden parameter that indicates if the context will be used
|
||||
// to modify the Raster object. We can notify such changes ahead since
|
||||
// to change the Raster object. We can notify such changes ahead since
|
||||
// they are only used afterwards for redrawing.
|
||||
if (modify) {
|
||||
if (_change) {
|
||||
// Also set _image to null since the Raster stops representing it.
|
||||
// NOTE: This should theoretically be in our own _changed() handler
|
||||
// for ChangeFlag.PIXELS, but since it's only happening in one place
|
||||
|
@ -386,7 +432,11 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
crossOrigin = this._crossOrigin;
|
||||
if (crossOrigin)
|
||||
image.crossOrigin = crossOrigin;
|
||||
image.src = src;
|
||||
// Prevent setting image source to `null`, as this isn't supported by
|
||||
// browsers, and it would actually throw exceptions in JSDOM.
|
||||
// TODO: Look into fixing this bug in JSDOM.
|
||||
if (src)
|
||||
image.src = src;
|
||||
this.setImage(image);
|
||||
},
|
||||
|
||||
|
@ -463,7 +513,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
* @param {Rectangle} rect the boundaries of the sub image in pixel
|
||||
* coordinates
|
||||
*
|
||||
* @return {HTMLCanvasELement} the sub image as a Canvas object
|
||||
* @return {HTMLCanvasElement} the sub image as a Canvas object
|
||||
*/
|
||||
getSubCanvas: function(/* rect */) {
|
||||
var rect = Rectangle.read(arguments),
|
||||
|
@ -519,7 +569,7 @@ var Raster = Item.extend(/** @lends 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
|
||||
* coordinates
|
||||
*/
|
||||
|
@ -614,8 +664,8 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*
|
||||
* @name Raster#getPixel
|
||||
* @function
|
||||
* @param x the x offset of the pixel in pixel coordinates
|
||||
* @param y the y offset of the pixel in pixel coordinates
|
||||
* @param {Number} x the x offset of the pixel in pixel coordinates
|
||||
* @param {Number} y the y offset of the pixel in pixel coordinates
|
||||
* @return {Color} the color of the pixel
|
||||
*/
|
||||
/**
|
||||
|
@ -623,7 +673,8 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*
|
||||
* @name Raster#getPixel
|
||||
* @function
|
||||
* @param point the offset of the pixel as a point in pixel coordinates
|
||||
* @param {Point} point the offset of the pixel as a point in pixel
|
||||
* coordinates
|
||||
* @return {Color} the color of the pixel
|
||||
*/
|
||||
getPixel: function(/* point */) {
|
||||
|
@ -639,21 +690,23 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*
|
||||
* @name Raster#setPixel
|
||||
* @function
|
||||
* @param x the x offset of the pixel in pixel coordinates
|
||||
* @param y the y offset of the pixel in pixel coordinates
|
||||
* @param color the color that the pixel will be set to
|
||||
* @param {Number} x the x offset of the pixel in pixel coordinates
|
||||
* @param {Number} y the y offset of the pixel in pixel coordinates
|
||||
* @param {Color} color the color that the pixel will be set to
|
||||
*/
|
||||
/**
|
||||
* Sets the color of the specified pixel to the specified color.
|
||||
*
|
||||
* @name Raster#setPixel
|
||||
* @function
|
||||
* @param point the offset of the pixel as a point in pixel coordinates
|
||||
* @param color the color that the pixel will be set to
|
||||
* @param {Point} point the offset of the pixel as a point in pixel
|
||||
* coordinates
|
||||
* @param {Color} color the color that the pixel will be set to
|
||||
*/
|
||||
setPixel: function(/* point, color */) {
|
||||
var point = Point.read(arguments),
|
||||
color = Color.read(arguments),
|
||||
var args = arguments,
|
||||
point = Point.read(args),
|
||||
color = Color.read(args),
|
||||
components = color._convert('rgb'),
|
||||
alpha = color._alpha,
|
||||
ctx = this.getContext(true),
|
||||
|
@ -666,6 +719,14 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
ctx.putImageData(imageData, point.x, point.y);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the image, if it is backed by a canvas.
|
||||
*/
|
||||
clear: function() {
|
||||
var size = this._size;
|
||||
this.getContext(true).clearRect(0, 0, size.width + 1, size.height + 1);
|
||||
},
|
||||
|
||||
// DOCS: document Raster#createImageData
|
||||
/**
|
||||
* {@grouptitle Image Data}
|
||||
|
@ -710,7 +771,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*
|
||||
* @name Raster#onLoad
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example
|
||||
* var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
||||
|
@ -736,7 +797,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*
|
||||
* @name Raster#onError
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*/
|
||||
|
||||
_getBounds: function(matrix, options) {
|
||||
|
@ -761,10 +822,11 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
|
||||
_draw: function(ctx, param, viewMatrix) {
|
||||
var element = this.getElement();
|
||||
if (element) {
|
||||
// Only draw if image is not empty (#1320).
|
||||
if (element && element.width > 0 && element.height > 0) {
|
||||
// Handle opacity for Rasters separately from the rest, since
|
||||
// Rasters never draw a stroke. See Item#draw().
|
||||
ctx.globalAlpha = this._opacity;
|
||||
ctx.globalAlpha = Numerical.clamp(this._opacity, 0, 1);
|
||||
|
||||
// Call _setStyles() to make sure shadow is drawn (#1437).
|
||||
this._setStyles(ctx, param, viewMatrix);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -82,7 +82,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
|||
setSize: function(/* size */) {
|
||||
var size = Size.read(arguments);
|
||||
if (!this._size) {
|
||||
// First time, e.g. whean reading from JSON...
|
||||
// First time, e.g. when reading from JSON...
|
||||
this._size = size.clone();
|
||||
} else if (!this._size.equals(size)) {
|
||||
var type = this._type,
|
||||
|
@ -90,7 +90,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
|||
height = size.height;
|
||||
if (type === 'rectangle') {
|
||||
// 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') {
|
||||
// Use average of width and height as new size, then calculate
|
||||
// radius as a number from that:
|
||||
|
@ -130,7 +130,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
|||
} else {
|
||||
radius = Size.read(arguments);
|
||||
if (!this._radius) {
|
||||
// First time, e.g. whean reading from JSON...
|
||||
// First time, e.g. when reading from JSON...
|
||||
this._radius = radius.clone();
|
||||
} else {
|
||||
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:
|
||||
statics: new function() {
|
||||
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._size = size;
|
||||
item._radius = radius;
|
||||
item._initialize(Base.getNamed(args), point);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -427,10 +430,11 @@ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
Circle: function(/* center, radius */) {
|
||||
var center = Point.readNamed(arguments, 'center'),
|
||||
radius = Base.readNamed(arguments, 'radius');
|
||||
var args = arguments,
|
||||
center = Point.readNamed(args, 'center'),
|
||||
radius = Base.readNamed(args, 'radius');
|
||||
return createShape('circle', center, new Size(radius * 2), radius,
|
||||
arguments);
|
||||
args);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -524,11 +528,12 @@ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
Rectangle: function(/* rectangle */) {
|
||||
var rect = Rectangle.readNamed(arguments, 'rectangle'),
|
||||
radius = Size.min(Size.readNamed(arguments, 'radius'),
|
||||
var args = arguments,
|
||||
rect = Rectangle.readNamed(args, 'rectangle'),
|
||||
radius = Size.min(Size.readNamed(args, 'radius'),
|
||||
rect.getSize(true).divide(2));
|
||||
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 */) {
|
||||
var ellipse = Shape._readEllipse(arguments),
|
||||
var args = arguments,
|
||||
ellipse = Shape._readEllipse(args),
|
||||
radius = ellipse.radius;
|
||||
return createShape('ellipse', ellipse.center, radius.multiply(2),
|
||||
radius, arguments);
|
||||
radius, args);
|
||||
},
|
||||
|
||||
// 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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -140,7 +140,7 @@ var SymbolDefinition = Base.extend(/** @lends SymbolDefinition# */{
|
|||
/**
|
||||
* Returns a copy of the symbol.
|
||||
*
|
||||
* @return {Symbol}
|
||||
* @return {SymbolDefinition}
|
||||
*/
|
||||
clone: function() {
|
||||
return new SymbolDefinition(this._item.clone(false));
|
||||
|
@ -149,7 +149,7 @@ var SymbolDefinition = Base.extend(/** @lends SymbolDefinition# */{
|
|||
/**
|
||||
* Checks whether the symbol's definition is equal to the supplied symbol.
|
||||
*
|
||||
* @param {Symbol} symbol
|
||||
* @param {SymbolDefinition} symbol
|
||||
* @return {Boolean} {@true if they are equal}
|
||||
*/
|
||||
equals: function(symbol) {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -31,7 +31,9 @@ var SymbolItem = Item.extend(/** @lends SymbolItem# */{
|
|||
/**
|
||||
* Creates a new symbol item.
|
||||
*
|
||||
* @param {Symbol} definition the symbol definition to place
|
||||
* @name SymbolItem#initialize
|
||||
* @param {SymbolDefinition|Item} definition the definition to place or an
|
||||
* item to place as a symbol
|
||||
* @param {Point} [point] the center point of the placed symbol
|
||||
*
|
||||
* @example {@paperscript split=true height=240}
|
||||
|
@ -119,7 +121,11 @@ var SymbolItem = Item.extend(/** @lends SymbolItem# */{
|
|||
},
|
||||
|
||||
_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
|
||||
// contain information like HitResult#curve?
|
||||
if (res)
|
||||
|
|
11
src/load.js
11
src/load.js
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -38,11 +38,10 @@ if (typeof window === 'object') {
|
|||
} else {
|
||||
// Some native javascript classes have name collisions with Paper.js
|
||||
// classes. Store them to be able to use them later in tests.
|
||||
NativeClasses = {
|
||||
Event: Event,
|
||||
MouseEvent: MouseEvent
|
||||
this.nativeClasses = {
|
||||
Event: window.Event,
|
||||
MouseEvent: window.MouseEvent
|
||||
};
|
||||
|
||||
include('options.js');
|
||||
// Load constants.js, required by the on-the-fly preprocessing:
|
||||
include('constants.js');
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -18,7 +18,7 @@
|
|||
module.exports = function(self, requireName) {
|
||||
var Canvas;
|
||||
try {
|
||||
Canvas = require('canvas');
|
||||
Canvas = require('canvas').Canvas;
|
||||
} catch(error) {
|
||||
// Remove `self.window`, so we still have the global `self` reference,
|
||||
// but no `window` object:
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -37,15 +37,13 @@ try {
|
|||
if (jsdom) {
|
||||
// Create our document and window objects through jsdom.
|
||||
/* global document:true, window:true */
|
||||
var document = jsdom.jsdom('<html><body></body></html>', {
|
||||
var document = new jsdom.JSDOM('<html><body></body></html>', {
|
||||
// Use the current working directory as the document's origin, so
|
||||
// requests to local files work correctly with CORS.
|
||||
url: 'file://' + process.cwd() + '/',
|
||||
features: {
|
||||
FetchExternalResources: ['img', 'script']
|
||||
}
|
||||
resources: 'usable'
|
||||
});
|
||||
self = document.defaultView;
|
||||
self = document.window;
|
||||
require('./canvas.js')(self, requireName);
|
||||
require('./xml.js')(self);
|
||||
} else {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -17,7 +17,7 @@
|
|||
// The paper.js version.
|
||||
// NOTE: Adjust value here before calling `gulp publish`, which then updates and
|
||||
// publishes the various JSON package files automatically.
|
||||
var version = '0.11.8';
|
||||
var version = '0.12.7';
|
||||
|
||||
// If this file is loaded in the browser, we're in load.js mode.
|
||||
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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -15,15 +15,15 @@
|
|||
*
|
||||
* Straps.js - Class inheritance library with support for bean-style accessors
|
||||
*
|
||||
* Copyright (c) 2006 - 2016 Juerg Lehni
|
||||
* http://scratchdisk.com/
|
||||
* Copyright (c) 2006 - 2020 Jürg Lehni
|
||||
* http://juerglehni.com/
|
||||
*
|
||||
* Distributed under the MIT license.
|
||||
*
|
||||
***
|
||||
*
|
||||
* Acorn.js
|
||||
* http://marijnhaverbeke.nl/acorn/
|
||||
* https://marijnhaverbeke.nl/acorn/
|
||||
*
|
||||
* Acorn is a tiny, fast JavaScript parser written in JavaScript,
|
||||
* created by Marijn Haverbeke and released under an MIT license.
|
||||
|
@ -42,6 +42,7 @@ var paper = function(self, undefined) {
|
|||
/*#*/ include('core/PaperScope.js');
|
||||
/*#*/ include('core/PaperScopeItem.js');
|
||||
|
||||
/*#*/ include('util/CollisionDetection.js');
|
||||
/*#*/ include('util/Formatter.js');
|
||||
/*#*/ include('util/Numerical.js');
|
||||
/*#*/ include('util/UID.js');
|
||||
|
@ -102,6 +103,8 @@ var paper = function(self, undefined) {
|
|||
/*#*/ include('tool/ToolEvent.js');
|
||||
/*#*/ include('tool/Tool.js');
|
||||
|
||||
/*#*/ include('anim/Tween.js');
|
||||
|
||||
/*#*/ include('net/Http.js');
|
||||
|
||||
/*#*/ include('canvas/CanvasProvider.js');
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -161,7 +161,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
|||
*
|
||||
* @bean
|
||||
* @type Boolean
|
||||
* @see Path#isClosed()
|
||||
* @see Path#closed
|
||||
*/
|
||||
isClosed: function() {
|
||||
var children = this._children;
|
||||
|
@ -193,7 +193,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
|||
|
||||
/**
|
||||
* The last Segment contained within the compound-path, a short-cut to
|
||||
* calling {@link Path#lastChild} on {@link Item#lastChild}.
|
||||
* calling {@link Path#lastSegment} on {@link Item#lastChild}.
|
||||
*
|
||||
* @bean
|
||||
* @type Segment
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -1476,7 +1476,7 @@ new function() { // Scope for methods that require private functions
|
|||
// 2: normal, 1st derivative
|
||||
// 3: curvature, 1st derivative & 2nd derivative
|
||||
// Prevent tangents and normals of length 0:
|
||||
// http://stackoverflow.com/questions/10506868/
|
||||
// https://stackoverflow.com/questions/10506868/
|
||||
if (t < tMin) {
|
||||
x = cx;
|
||||
y = cy;
|
||||
|
@ -1698,7 +1698,7 @@ new function() { // Scope for methods that require private functions
|
|||
* Peaks are locations sharing some qualities of curvature extrema but
|
||||
* are cheaper to compute. They fulfill their purpose here quite well.
|
||||
* See:
|
||||
* http://math.stackexchange.com/questions/1954845/bezier-curvature-extrema
|
||||
* https://math.stackexchange.com/questions/1954845/bezier-curvature-extrema
|
||||
*
|
||||
* @param {Number[]} v the curve values array
|
||||
* @return {Number[]} the roots of all found peaks
|
||||
|
@ -1822,9 +1822,10 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
|||
} else {
|
||||
// Apply the result of the clipping to curve 1:
|
||||
v1 = Curve.getPart(v1, tMinClip, tMaxClip);
|
||||
var uDiff = uMax - uMin;
|
||||
if (tMaxClip - tMinClip > 0.8) {
|
||||
// Subdivide the curve which has converged the least.
|
||||
if (tMaxNew - tMinNew > uMax - uMin) {
|
||||
if (tMaxNew - tMinNew > uDiff) {
|
||||
var parts = Curve.subdivide(v1, 0.5),
|
||||
t = (tMinNew + tMaxNew) / 2;
|
||||
calls = addCurveIntersections(
|
||||
|
@ -1844,7 +1845,10 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
|||
recursion, calls, u, uMax, tMinNew, tMaxNew);
|
||||
}
|
||||
} 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(
|
||||
v2, v1, c2, c1, locations, include, !flip,
|
||||
recursion, calls, uMin, uMax, tMinNew, tMaxNew);
|
||||
|
@ -2087,7 +2091,7 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
|||
return locations;
|
||||
}
|
||||
|
||||
function getLoopIntersection(v1, c1, locations, include) {
|
||||
function getSelfIntersection(v1, c1, locations, include) {
|
||||
var info = Curve.classify(v1);
|
||||
if (info.type === 'loop') {
|
||||
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,
|
||||
_returnFirst) {
|
||||
var self = !curves2;
|
||||
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
||||
self = !curves2;
|
||||
if (self)
|
||||
curves2 = curves1;
|
||||
var length1 = curves1.length,
|
||||
length2 = curves2.length,
|
||||
values2 = [],
|
||||
arrays = [],
|
||||
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);
|
||||
values1 = new Array(length1),
|
||||
values2 = self ? values1 : new Array(length2),
|
||||
locations = [];
|
||||
|
||||
for (var i = 0; i < length1; i++) {
|
||||
var curve1 = curves1[i],
|
||||
values1 = self ? values2[i] : curve1.getValues(matrix1),
|
||||
path1 = curve1.getPath();
|
||||
// NOTE: Due to the nature of getCurveIntersections(), we use
|
||||
// separate location arrays per path1, to make sure the circularity
|
||||
// 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);
|
||||
values1[i] = curves1[i].getValues(matrix1);
|
||||
}
|
||||
if (!self) {
|
||||
for (var i = 0; i < length2; i++) {
|
||||
values2[i] = curves2[i].getValues(matrix2);
|
||||
}
|
||||
}
|
||||
// Flatten the list of location arrays to one array and return it.
|
||||
locations = [];
|
||||
for (var i = 0, l = arrays.length; i < l; i++) {
|
||||
Base.push(locations, arrays[i]);
|
||||
var boundsCollisions = CollisionDetection.findCurveBoundsCollisions(
|
||||
values1, values2, epsilon);
|
||||
for (var index1 = 0; index1 < length1; index1++) {
|
||||
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;
|
||||
}
|
||||
|
@ -2310,7 +2314,7 @@ new function() { // Scope for bezier intersection using fat-line clipping
|
|||
var v1 = this.getValues(),
|
||||
v2 = curve && curve !== this && curve.getValues();
|
||||
return v2 ? getCurveIntersections(v1, v2, this, curve, [])
|
||||
: getLoopIntersection(v1, this, []);
|
||||
: getSelfIntersection(v1, this, []);
|
||||
},
|
||||
|
||||
statics: /** @lends Curve */{
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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;
|
||||
},
|
||||
|
||||
_setCurve: function(curve) {
|
||||
var path = curve._path;
|
||||
// We only store the path to verify versions for cachd values.
|
||||
_setPath: function(path) {
|
||||
// We only store the path to verify versions for cached values.
|
||||
// To ensure we use the right path (e.g. after splitting), we shall
|
||||
// always access the path on the result of getCurve().
|
||||
this._path = path;
|
||||
this._version = path ? path._version : 0;
|
||||
},
|
||||
|
||||
_setCurve: function(curve) {
|
||||
this._setPath(curve._path);
|
||||
this._curve = curve;
|
||||
this._segment = null; // To be determined, see #getSegment()
|
||||
// Also store references to segment1 and segment2, in case path
|
||||
|
@ -74,7 +77,14 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
},
|
||||
|
||||
_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._time = segment === this._segment1 ? 0 : 1;
|
||||
// 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.
|
||||
*
|
||||
* @bean
|
||||
* @type Item
|
||||
* @type Path
|
||||
*/
|
||||
getPath: function() {
|
||||
var curve = this.getCurve();
|
||||
|
@ -159,7 +169,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* it is part of a {@link Path} item.
|
||||
*
|
||||
* @bean
|
||||
* @type Index
|
||||
* @type Number
|
||||
*/
|
||||
getIndex: function() {
|
||||
var curve = this.getCurve();
|
||||
|
@ -284,7 +294,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* @bean
|
||||
* @type Number
|
||||
* @see Curve#getNearestLocation(point)
|
||||
* @see Path#getNearestLocation(point)
|
||||
* @see PathItem#getNearestLocation(point)
|
||||
*/
|
||||
getDistance: function() {
|
||||
return this._distance;
|
||||
|
@ -424,9 +434,9 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
// both values point to the same curve, and the curve-time is to be
|
||||
// handled accordingly further down.
|
||||
var c2 = this.getCurve(),
|
||||
c1 = t1 < tMin ? c2.getPrevious() : c2,
|
||||
c1 = c2 && t1 < tMin ? c2.getPrevious() : c2,
|
||||
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 > tMax)
|
||||
c2 = c2.getNext();
|
||||
|
@ -450,11 +460,12 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
var v = curve.getValues(),
|
||||
roots = Curve.classify(v).roots || Curve.getPeaks(v),
|
||||
count = roots.length,
|
||||
t = end && count > 1 ? roots[count - 1]
|
||||
: count > 0 ? roots[0]
|
||||
: 0.5;
|
||||
// Then use half of the offset, for extra measure.
|
||||
offsets.push(Curve.getLength(v, end ? t : 0, end ? 1 : t) / 2);
|
||||
offset = Curve.getLength(v,
|
||||
end && count ? roots[count - 1] : 0,
|
||||
!end && count ? roots[0] : 1);
|
||||
// When no root was found, the full length was calculated. Use a
|
||||
// fraction of it. By trial & error, 64 was determined to work well.
|
||||
offsets.push(count ? offset : offset / 32);
|
||||
}
|
||||
|
||||
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.
|
||||
// If each pair of angles split the other two, then the edges cross.
|
||||
// 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
|
||||
? (isInRange(a1, a3, a4) ^ isInRange(a2, a3, a4)) &&
|
||||
(isInRange(a1, a4, a3) ^ isInRange(a2, a4, a3))
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -79,10 +79,11 @@ Path.inject({ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
Line: function(/* from, to */) {
|
||||
var args = arguments;
|
||||
return createPath([
|
||||
new Segment(Point.readNamed(arguments, 'from')),
|
||||
new Segment(Point.readNamed(arguments, 'to'))
|
||||
], false, arguments);
|
||||
new Segment(Point.readNamed(args, 'from')),
|
||||
new Segment(Point.readNamed(args, 'to'))
|
||||
], false, args);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -114,9 +115,10 @@ Path.inject({ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
Circle: function(/* center, radius */) {
|
||||
var center = Point.readNamed(arguments, 'center'),
|
||||
radius = Base.readNamed(arguments, 'radius');
|
||||
return createEllipse(center, new Size(radius), arguments);
|
||||
var args = arguments,
|
||||
center = Point.readNamed(args, 'center'),
|
||||
radius = Base.readNamed(args, 'radius');
|
||||
return createEllipse(center, new Size(radius), args);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -210,8 +212,9 @@ Path.inject({ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
Rectangle: function(/* rectangle */) {
|
||||
var rect = Rectangle.readNamed(arguments, 'rectangle'),
|
||||
radius = Size.readNamed(arguments, 'radius', 0,
|
||||
var args = arguments,
|
||||
rect = Rectangle.readNamed(args, 'rectangle'),
|
||||
radius = Size.readNamed(args, 'radius', 0,
|
||||
{ readNull: true }),
|
||||
bl = rect.getBottomLeft(true),
|
||||
tl = rect.getTopLeft(true),
|
||||
|
@ -242,7 +245,7 @@ Path.inject({ statics: new function() {
|
|||
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 */) {
|
||||
var ellipse = Shape._readEllipse(arguments);
|
||||
return createEllipse(ellipse.center, ellipse.radius, arguments);
|
||||
var args = 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 */) {
|
||||
var from = Point.readNamed(arguments, 'from'),
|
||||
through = Point.readNamed(arguments, 'through'),
|
||||
to = Point.readNamed(arguments, 'to'),
|
||||
props = Base.getNamed(arguments),
|
||||
var args = arguments,
|
||||
from = Point.readNamed(args, 'from'),
|
||||
through = Point.readNamed(args, 'through'),
|
||||
to = Point.readNamed(args, 'to'),
|
||||
props = Base.getNamed(args),
|
||||
// See createPath() for an explanation of the following sequence
|
||||
path = new Path(props && props.insert == false
|
||||
&& Item.NO_INSERT);
|
||||
|
@ -376,9 +381,10 @@ Path.inject({ statics: new function() {
|
|||
* });
|
||||
*/
|
||||
RegularPolygon: function(/* center, sides, radius */) {
|
||||
var center = Point.readNamed(arguments, 'center'),
|
||||
sides = Base.readNamed(arguments, 'sides'),
|
||||
radius = Base.readNamed(arguments, 'radius'),
|
||||
var args = arguments,
|
||||
center = Point.readNamed(args, 'center'),
|
||||
sides = Base.readNamed(args, 'sides'),
|
||||
radius = Base.readNamed(args, 'radius'),
|
||||
step = 360 / sides,
|
||||
three = sides % 3 === 0,
|
||||
vector = new Point(0, three ? -radius : radius),
|
||||
|
@ -387,7 +393,7 @@ Path.inject({ statics: new function() {
|
|||
for (var i = 0; i < sides; i++)
|
||||
segments[i] = new Segment(center.add(
|
||||
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 */) {
|
||||
var center = Point.readNamed(arguments, 'center'),
|
||||
points = Base.readNamed(arguments, 'points') * 2,
|
||||
radius1 = Base.readNamed(arguments, 'radius1'),
|
||||
radius2 = Base.readNamed(arguments, 'radius2'),
|
||||
var args = arguments,
|
||||
center = Point.readNamed(args, 'center'),
|
||||
points = Base.readNamed(args, 'points') * 2,
|
||||
radius1 = Base.readNamed(args, 'radius1'),
|
||||
radius2 = Base.readNamed(args, 'radius2'),
|
||||
step = 360 / points,
|
||||
vector = new Point(0, -1),
|
||||
segments = new Array(points);
|
||||
for (var i = 0; i < points; i++)
|
||||
segments[i] = new Segment(center.add(vector.rotate(step * i)
|
||||
.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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -75,7 +75,6 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
* Creates a new path item from SVG path-data and places it at the top of
|
||||
* the active layer.
|
||||
*
|
||||
* @param
|
||||
* @name Path#initialize
|
||||
* @param {String} pathData the SVG path-data that describes the geometry
|
||||
* of this path
|
||||
|
@ -99,15 +98,16 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
// check its first entry for object as well.
|
||||
// But first see if segments are directly passed at all. If not, try
|
||||
// _set(arg).
|
||||
var segments = Array.isArray(arg)
|
||||
var args = arguments,
|
||||
segments = Array.isArray(arg)
|
||||
? typeof arg[0] === 'object'
|
||||
? arg
|
||||
: arguments
|
||||
: args
|
||||
// See if it behaves like a segment or a point, but filter out
|
||||
// rectangles, as accepted by some Path.Constructor constructors.
|
||||
: arg && (arg.size === undefined && (arg.x !== undefined
|
||||
|| arg.point !== undefined))
|
||||
? arguments
|
||||
? args
|
||||
: null;
|
||||
// Always call setSegments() to initialize a few related variables.
|
||||
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
|
||||
* this path.
|
||||
*
|
||||
* @param {Segment|Point} segment the segment or point to be added.
|
||||
* @return {Segment} the added segment. This is not necessarily the same
|
||||
* object, e.g. if the segment to be added already belongs to another path
|
||||
* @param {...(Segment|Point|Number[])} segment the segment or point to be
|
||||
* added.
|
||||
* @return {Segment|Segment[]} the added segment(s). This is not necessarily
|
||||
* the same object, e.g. if the segment to be added already belongs to
|
||||
* another path.
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Adding segments to a path using point objects:
|
||||
|
@ -547,11 +549,12 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
* path.add(new Point(170, 75));
|
||||
*/
|
||||
add: function(segment1 /*, segment2, ... */) {
|
||||
return arguments.length > 1 && typeof segment1 !== 'number'
|
||||
var args = arguments;
|
||||
return args.length > 1 && typeof segment1 !== 'number'
|
||||
// addSegments
|
||||
? this._add(Segment.readList(arguments))
|
||||
? this._add(Segment.readList(args))
|
||||
// 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;
|
||||
*/
|
||||
insert: function(index, segment1 /*, segment2, ... */) {
|
||||
return arguments.length > 2 && typeof segment1 !== 'number'
|
||||
var args = arguments;
|
||||
return args.length > 2 && typeof segment1 !== 'number'
|
||||
// insertSegments
|
||||
? this._add(Segment.readList(arguments, 1), index)
|
||||
? this._add(Segment.readList(args, 1), index)
|
||||
// insertSegment
|
||||
: this._add([ Segment.read(arguments, 1) ], index)[0];
|
||||
: this._add([ Segment.read(args, 1) ], index)[0];
|
||||
},
|
||||
|
||||
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,
|
||||
* and unnecessary segments between two collinear flat curves.
|
||||
*
|
||||
* @return {Path} the reduced path
|
||||
*/
|
||||
reduce: function(options) {
|
||||
var curves = this.getCurves(),
|
||||
|
@ -2173,9 +2179,9 @@ new function() { // Scope for drawing
|
|||
// performance.
|
||||
|
||||
function drawHandles(ctx, segments, matrix, size, isFullySelected) {
|
||||
if (size === 0) {
|
||||
return;
|
||||
}
|
||||
// Only draw if size is not null or negative.
|
||||
if (size <= 0) return;
|
||||
|
||||
var half = size / 2,
|
||||
coords = new Array(6),
|
||||
pX, pY;
|
||||
|
@ -2402,9 +2408,10 @@ new function() { // PostScript-style drawing commands
|
|||
},
|
||||
|
||||
cubicCurveTo: function(/* handle1, handle2, to */) {
|
||||
var handle1 = Point.read(arguments),
|
||||
handle2 = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
var args = arguments,
|
||||
handle1 = Point.read(args),
|
||||
handle2 = Point.read(args),
|
||||
to = Point.read(args),
|
||||
// First modify the current segment:
|
||||
current = getCurrentSegment(this);
|
||||
// Convert to relative values:
|
||||
|
@ -2414,8 +2421,9 @@ new function() { // PostScript-style drawing commands
|
|||
},
|
||||
|
||||
quadraticCurveTo: function(/* handle, to */) {
|
||||
var handle = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
var args = arguments,
|
||||
handle = Point.read(args),
|
||||
to = Point.read(args),
|
||||
current = getCurrentSegment(this)._point;
|
||||
// This is exact:
|
||||
// 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 */) {
|
||||
var through = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
t = Base.pick(Base.read(arguments), 0.5),
|
||||
var args = arguments,
|
||||
through = Point.read(args),
|
||||
to = Point.read(args),
|
||||
t = Base.pick(Base.read(args), 0.5),
|
||||
t1 = 1 - t,
|
||||
current = getCurrentSegment(this)._point,
|
||||
// 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
|
||||
| to, radius, rotation, clockwise, large */) {
|
||||
// Get the start point:
|
||||
var abs = Math.abs,
|
||||
var args = arguments,
|
||||
abs = Math.abs,
|
||||
sqrt = Math.sqrt,
|
||||
current = getCurrentSegment(this),
|
||||
from = current._point,
|
||||
to = Point.read(arguments),
|
||||
to = Point.read(args),
|
||||
through,
|
||||
// Peek at next value to see if it's clockwise, with true as the
|
||||
// default value.
|
||||
peek = Base.peek(arguments),
|
||||
peek = Base.peek(args),
|
||||
clockwise = Base.pick(peek, true),
|
||||
center, extent, vector, matrix;
|
||||
// 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),
|
||||
through = middle.add(middle.subtract(from).rotate(
|
||||
clockwise ? -90 : 90));
|
||||
} else if (Base.remain(arguments) <= 2) {
|
||||
} else if (Base.remain(args) <= 2) {
|
||||
// #2: arcTo(through, to)
|
||||
through = to;
|
||||
to = Point.read(arguments);
|
||||
} else {
|
||||
to = Point.read(args);
|
||||
} else if (!from.equals(to)) {
|
||||
// #3: arcTo(to, radius, rotation, clockwise, large)
|
||||
// Drawing arcs in SVG style:
|
||||
var radius = Size.read(arguments),
|
||||
// Draw arc in SVG style, but only if `from` and `to` are not
|
||||
// equal (#1613).
|
||||
var radius = Size.read(args),
|
||||
isZero = Numerical.isZero;
|
||||
// If rx = 0 or ry = 0 then this arc is treated as a
|
||||
// straight line joining the endpoints.
|
||||
|
@ -2481,10 +2492,10 @@ new function() { // PostScript-style drawing commands
|
|||
if (isZero(radius.width) || isZero(radius.height))
|
||||
return this.lineTo(to);
|
||||
// See for an explanation of the following calculations:
|
||||
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
var rotation = Base.read(arguments),
|
||||
clockwise = !!Base.read(arguments),
|
||||
large = !!Base.read(arguments),
|
||||
// https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
var rotation = Base.read(args),
|
||||
clockwise = !!Base.read(args),
|
||||
large = !!Base.read(args),
|
||||
middle = from.add(to).divide(2),
|
||||
pt = from.subtract(middle).rotate(-rotation),
|
||||
x = pt.x,
|
||||
|
@ -2568,47 +2579,49 @@ new function() { // PostScript-style drawing commands
|
|||
extent += extent < 0 ? 360 : -360;
|
||||
}
|
||||
}
|
||||
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
||||
ext = abs(extent),
|
||||
// Calculate the amount of segments required to approximate over
|
||||
// `extend` degrees (extend / 90), but prevent ceil() from
|
||||
// rounding up small imprecisions by subtracting epsilon first.
|
||||
count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90),
|
||||
inc = extent / count,
|
||||
half = inc * Math.PI / 360,
|
||||
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
|
||||
segments = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
// Explicitly use to point for last segment, since depending
|
||||
// on values the calculation adds imprecision:
|
||||
var pt = to,
|
||||
out = null;
|
||||
if (i < count) {
|
||||
out = vector.rotate(90).multiply(z);
|
||||
if (matrix) {
|
||||
pt = matrix._transformPoint(vector);
|
||||
out = matrix._transformPoint(vector.add(out))
|
||||
.subtract(pt);
|
||||
if (extent) {
|
||||
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
|
||||
ext = abs(extent),
|
||||
// Calculate amount of segments required to approximate over
|
||||
// `extend` degrees (extend / 90), but prevent ceil() from
|
||||
// rounding up small imprecisions by subtracting epsilon.
|
||||
count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90),
|
||||
inc = extent / count,
|
||||
half = inc * Math.PI / 360,
|
||||
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
|
||||
segments = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
// Explicitly use to point for last segment, since depending
|
||||
// on values the calculation adds imprecision:
|
||||
var pt = to,
|
||||
out = null;
|
||||
if (i < count) {
|
||||
out = vector.rotate(90).multiply(z);
|
||||
if (matrix) {
|
||||
pt = matrix._transformPoint(vector);
|
||||
out = matrix._transformPoint(vector.add(out))
|
||||
.subtract(pt);
|
||||
} else {
|
||||
pt = center.add(vector);
|
||||
}
|
||||
}
|
||||
if (!i) {
|
||||
// Modify startSegment
|
||||
current.setHandleOut(out);
|
||||
} else {
|
||||
pt = center.add(vector);
|
||||
// Add new Segment
|
||||
var _in = vector.rotate(-90).multiply(z);
|
||||
if (matrix) {
|
||||
_in = matrix._transformPoint(vector.add(_in))
|
||||
.subtract(pt);
|
||||
}
|
||||
segments.push(new Segment(pt, _in, out));
|
||||
}
|
||||
vector = vector.rotate(inc);
|
||||
}
|
||||
if (!i) {
|
||||
// Modify startSegment
|
||||
current.setHandleOut(out);
|
||||
} else {
|
||||
// Add new Segment
|
||||
var _in = vector.rotate(-90).multiply(z);
|
||||
if (matrix) {
|
||||
_in = matrix._transformPoint(vector.add(_in))
|
||||
.subtract(pt);
|
||||
}
|
||||
segments.push(new Segment(pt, _in, out));
|
||||
}
|
||||
vector = vector.rotate(inc);
|
||||
// Add all segments at once at the end for higher performance
|
||||
this._add(segments);
|
||||
}
|
||||
// Add all segments at once at the end for higher performance
|
||||
this._add(segments);
|
||||
},
|
||||
|
||||
lineBy: function(/* to */) {
|
||||
|
@ -2618,40 +2631,44 @@ new function() { // PostScript-style drawing commands
|
|||
},
|
||||
|
||||
curveBy: function(/* through, to, parameter */) {
|
||||
var through = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
parameter = Base.read(arguments),
|
||||
var args = arguments,
|
||||
through = Point.read(args),
|
||||
to = Point.read(args),
|
||||
parameter = Base.read(args),
|
||||
current = getCurrentSegment(this)._point;
|
||||
this.curveTo(current.add(through), current.add(to), parameter);
|
||||
},
|
||||
|
||||
cubicCurveBy: function(/* handle1, handle2, to */) {
|
||||
var handle1 = Point.read(arguments),
|
||||
handle2 = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
var args = arguments,
|
||||
handle1 = Point.read(args),
|
||||
handle2 = Point.read(args),
|
||||
to = Point.read(args),
|
||||
current = getCurrentSegment(this)._point;
|
||||
this.cubicCurveTo(current.add(handle1), current.add(handle2),
|
||||
current.add(to));
|
||||
},
|
||||
|
||||
quadraticCurveBy: function(/* handle, to */) {
|
||||
var handle = Point.read(arguments),
|
||||
to = Point.read(arguments),
|
||||
var args = arguments,
|
||||
handle = Point.read(args),
|
||||
to = Point.read(args),
|
||||
current = getCurrentSegment(this)._point;
|
||||
this.quadraticCurveTo(current.add(handle), current.add(to));
|
||||
},
|
||||
|
||||
// TODO: Implement version for: (to, radius, rotation, clockwise, large)
|
||||
arcBy: function(/* to, clockwise | through, to */) {
|
||||
var current = getCurrentSegment(this)._point,
|
||||
point = current.add(Point.read(arguments)),
|
||||
var args = arguments,
|
||||
current = getCurrentSegment(this)._point,
|
||||
point = current.add(Point.read(args)),
|
||||
// Peek at next value to see if it's clockwise, with true as
|
||||
// default value.
|
||||
clockwise = Base.pick(Base.peek(arguments), true);
|
||||
clockwise = Base.pick(Base.peek(args), true);
|
||||
if (typeof clockwise === 'boolean') {
|
||||
this.arcTo(point, clockwise);
|
||||
} 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);
|
||||
for (var i = 1; i < length; i++)
|
||||
addJoin(segments[i], join);
|
||||
if (closed) {
|
||||
// Go back to the beginning
|
||||
addJoin(segments[0], join);
|
||||
} else if (length > 0) {
|
||||
// Handle caps on open paths
|
||||
addCap(segments[0], cap);
|
||||
addCap(segments[segments.length - 1], cap);
|
||||
if (length > 0) {
|
||||
for (var i = 1; i < length; i++) {
|
||||
addJoin(segments[i], join);
|
||||
}
|
||||
if (closed) {
|
||||
// Go back to the beginning
|
||||
addJoin(segments[0], join);
|
||||
} else {
|
||||
// Handle caps on open paths
|
||||
addCap(segments[0], cap);
|
||||
addCap(segments[segments.length - 1], cap);
|
||||
}
|
||||
}
|
||||
return bounds;
|
||||
},
|
||||
|
@ -2846,8 +2866,9 @@ statics: {
|
|||
normal1 = curve1.getNormalAtTime(1).multiply(radius)
|
||||
.transform(strokeMatrix),
|
||||
normal2 = curve2.getNormalAtTime(0).multiply(radius)
|
||||
.transform(strokeMatrix);
|
||||
if (normal1.getDirectedAngle(normal2) < 0) {
|
||||
.transform(strokeMatrix),
|
||||
angle = normal1.getDirectedAngle(normal2);
|
||||
if (angle < 0 || angle >= 180) {
|
||||
normal1 = normal1.negate();
|
||||
normal2 = normal2.negate();
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -13,7 +13,7 @@
|
|||
// An Algorithm for Automatically Fitting Digitized Curves
|
||||
// by Philip J. Schneider
|
||||
// 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
|
||||
|
@ -231,7 +231,7 @@ var PathFitter = Base.extend({
|
|||
diff = pt.subtract(point),
|
||||
df = pt1.dot(pt1) + diff.dot(pt2);
|
||||
// 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
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -23,9 +23,8 @@
|
|||
* - Boolean operations on self-intersecting Paths items
|
||||
*
|
||||
* @author Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
|
||||
* @author Jan Boesenberg <development@iconexperience.com>
|
||||
* @author Juerg Lehni <juerg@scratchdisk.com>
|
||||
* http://hkrish.com/playground/paperjs/booleanStudy.html
|
||||
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
|
||||
* @author Jürg Lehni <juerg@scratchdisk.com>
|
||||
*/
|
||||
PathItem.inject(new function() {
|
||||
var min = Math.min,
|
||||
|
@ -46,6 +45,10 @@ PathItem.inject(new function() {
|
|||
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
|
||||
* 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.
|
||||
*/
|
||||
function preparePath(path, resolve) {
|
||||
var res = path.clone(false).reduce({ simplify: true })
|
||||
.transform(null, true, true);
|
||||
return resolve
|
||||
? res.resolveCrossings().reorient(
|
||||
res.getFillRule() === 'nonzero', true)
|
||||
: res;
|
||||
var res = path
|
||||
.clone(false)
|
||||
.reduce({ simplify: true })
|
||||
.transform(null, true, true);
|
||||
if (resolve) {
|
||||
// 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) {
|
||||
|
@ -77,6 +96,17 @@ PathItem.inject(new function() {
|
|||
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) {
|
||||
// Only support subtract and intersect operations when computing stroke
|
||||
// based boolean operations (options.split = true).
|
||||
|
@ -101,15 +131,15 @@ PathItem.inject(new function() {
|
|||
_path2.reverse();
|
||||
// Split curves at crossings on both paths. Note that for self-
|
||||
// intersection, path2 is null and getIntersections() handles it.
|
||||
var crossings = divideLocations(
|
||||
CurveLocation.expand(_path1.getCrossings(_path2))),
|
||||
paths1 = _path1._children || [_path1],
|
||||
paths2 = _path2 && (_path2._children || [_path2]),
|
||||
var crossings = divideLocations(CurveLocation.expand(
|
||||
_path1.getIntersections(_path2, filterIntersection))),
|
||||
paths1 = getPaths(_path1),
|
||||
paths2 = _path2 && getPaths(_path2),
|
||||
segments = [],
|
||||
curves = [],
|
||||
paths;
|
||||
|
||||
function collect(paths) {
|
||||
function collectPaths(paths) {
|
||||
for (var i = 0, l = paths.length; i < l; i++) {
|
||||
var path = paths[i];
|
||||
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) {
|
||||
// Collect all segments and curves of both involved operands.
|
||||
collect(paths1);
|
||||
collectPaths(paths1);
|
||||
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
|
||||
// curves does not change between two crossings.
|
||||
// First, propagate winding contributions for curve chains starting
|
||||
// in all crossings:
|
||||
for (var i = 0, l = crossings.length; i < l; i++) {
|
||||
propagateWinding(crossings[i]._segment, _path1, _path2, curves,
|
||||
operator);
|
||||
propagateWinding(crossings[i]._segment, _path1, _path2,
|
||||
curveCollisionsMap, operator);
|
||||
}
|
||||
for (var i = 0, l = segments.length; i < l; i++) {
|
||||
var segment = segments[i],
|
||||
inter = segment._intersection;
|
||||
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.
|
||||
if (!(inter && inter._overlap))
|
||||
|
@ -155,14 +212,13 @@ PathItem.inject(new function() {
|
|||
return !!operator[w];
|
||||
});
|
||||
}
|
||||
|
||||
return createResult(paths, true, path1, path2, options);
|
||||
}
|
||||
|
||||
function splitBoolean(path1, path2, operation) {
|
||||
var _path1 = preparePath(path1),
|
||||
_path2 = preparePath(path2),
|
||||
crossings = _path1.getCrossings(_path2),
|
||||
crossings = _path1.getIntersections(_path2, filterIntersection),
|
||||
subtract = operation === 'subtract',
|
||||
divide = operation === 'divide',
|
||||
added = {},
|
||||
|
@ -269,29 +325,39 @@ PathItem.inject(new function() {
|
|||
// Get reference to the first, largest path and insert it
|
||||
// already.
|
||||
first = sorted[0];
|
||||
// create lookup containing potentially overlapping path bounds
|
||||
var collisions = CollisionDetection.findItemBoundsCollisions(sorted,
|
||||
null, Numerical.GEOMETRIC_EPSILON);
|
||||
if (clockwise == null)
|
||||
clockwise = first.isClockwise();
|
||||
// Now determine the winding for each path, from large to small.
|
||||
for (var i = 0; i < length; i++) {
|
||||
var path1 = sorted[i],
|
||||
entry1 = lookup[path1._id],
|
||||
point = path1.getInteriorPoint(),
|
||||
containerWinding = 0;
|
||||
for (var j = i - 1; j >= 0; j--) {
|
||||
var path2 = sorted[j];
|
||||
// As we run through the paths from largest to smallest, for
|
||||
// any current path, all potentially containing paths have
|
||||
// already been processed and their orientation fixed.
|
||||
// To achieve correct orientation of contained paths based
|
||||
// on winding, we have to find one containing path with
|
||||
// different "insideness" and set opposite orientation.
|
||||
if (path2.contains(point)) {
|
||||
var entry2 = lookup[path2._id];
|
||||
containerWinding = entry2.winding;
|
||||
entry1.winding += containerWinding;
|
||||
entry1.container = entry2.exclude ? entry2.container
|
||||
: path2;
|
||||
break;
|
||||
containerWinding = 0,
|
||||
indices = collisions[i];
|
||||
if (indices) {
|
||||
var point = null; // interior point, only get it if required.
|
||||
for (var j = indices.length - 1; j >= 0; j--) {
|
||||
if (indices[j] < i) {
|
||||
point = point || path1.getInteriorPoint();
|
||||
var path2 = sorted[indices[j]];
|
||||
// As we run through the paths from largest to
|
||||
// smallest, for any current path, all potentially
|
||||
// containing paths have already been processed and
|
||||
// their orientation fixed. To achieve correct
|
||||
// orientation of contained paths based on winding,
|
||||
// find one containing path with different
|
||||
// "insideness" and set opposite orientation.
|
||||
if (path2.contains(point)) {
|
||||
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
|
||||
|
@ -306,8 +372,8 @@ PathItem.inject(new function() {
|
|||
// If the containing path is not excluded, we're done
|
||||
// searching for the orientation defining path.
|
||||
var container = entry1.container;
|
||||
path1.setClockwise(container ? !container.isClockwise()
|
||||
: clockwise);
|
||||
path1.setClockwise(
|
||||
container ? !container.isClockwise() : clockwise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -452,9 +518,9 @@ PathItem.inject(new function() {
|
|||
*
|
||||
* @param {Point} point the location for which to determine the winding
|
||||
* 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
|
||||
* {@link CompoundPath#curves}
|
||||
* {@link CompoundPath#curves}.
|
||||
* @param {Boolean} [dir=false] the direction in which to determine the
|
||||
* winding contribution, `false`: in x-direction, `true`: in y-direction
|
||||
* @param {Boolean} [closed=false] determines how areas should be closed
|
||||
|
@ -468,6 +534,13 @@ PathItem.inject(new function() {
|
|||
* @private
|
||||
*/
|
||||
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
|
||||
// values arrays, based on the direction:
|
||||
var ia = dir ? 1 : 0, // the abscissa index
|
||||
|
@ -573,9 +646,7 @@ PathItem.inject(new function() {
|
|||
onPath = true;
|
||||
}
|
||||
}
|
||||
// TODO: Determine how to handle quality when curve is crossed
|
||||
// at starting point. Do we always need to set to 0?
|
||||
quality = 0;
|
||||
quality /= 4;
|
||||
}
|
||||
vPrev = v;
|
||||
// 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++) {
|
||||
var curve = curves[i],
|
||||
for (var i = 0, l = curvesList.length; i < l; i++) {
|
||||
var curve = curvesList[i],
|
||||
path = curve._path,
|
||||
v = curve.getValues(),
|
||||
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
|
||||
// the last non-horizontal curve on this path.
|
||||
vPrev = null;
|
||||
|
@ -664,7 +735,7 @@ PathItem.inject(new function() {
|
|||
if (res = handleCurve(v))
|
||||
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
|
||||
// closing curve was calculated at the beginning of it, handle
|
||||
// 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
|
||||
// for the curve-chain starting with this segment. Once we have enough
|
||||
// confidence in the winding contribution, we can propagate it until the
|
||||
|
@ -715,10 +787,14 @@ PathItem.inject(new function() {
|
|||
totalLength = 0,
|
||||
winding;
|
||||
do {
|
||||
var curve = segment.getCurve(),
|
||||
length = curve.getLength();
|
||||
chain.push({ segment: segment, curve: curve, length: length });
|
||||
totalLength += length;
|
||||
var curve = segment.getCurve();
|
||||
// We can encounter paths with only one segment, which would not
|
||||
// have a curve.
|
||||
if (curve) {
|
||||
var length = curve.getLength();
|
||||
chain.push({ segment: segment, curve: curve, length: length });
|
||||
totalLength += length;
|
||||
}
|
||||
segment = segment.getNext();
|
||||
} while (segment && !segment._intersection && segment !== start);
|
||||
// Determine winding at three points in the chain. If a winding with
|
||||
|
@ -726,7 +802,8 @@ PathItem.inject(new function() {
|
|||
// the best quality.
|
||||
var offsets = [0.5, 0.25, 0.75],
|
||||
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;
|
||||
for (var i = 0; i < offsets.length && winding.quality < 0.5; i++) {
|
||||
var length = totalLength * offsets[i];
|
||||
|
@ -751,9 +828,8 @@ PathItem.inject(new function() {
|
|||
var wind = null;
|
||||
if (operator.subtract && path2) {
|
||||
// Calculate path winding at point depending on operand.
|
||||
var pathWinding = operand === path1
|
||||
? path2._getWinding(pt, dir, true)
|
||||
: path1._getWinding(pt, dir, true);
|
||||
var otherPath = operand === path1 ? path2 : path1,
|
||||
pathWinding = otherPath._getWinding(pt, dir, true);
|
||||
// Check if curve should be omitted.
|
||||
if (operand === path1 && 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)
|
||||
winding = wind;
|
||||
break;
|
||||
|
@ -865,8 +943,8 @@ PathItem.inject(new function() {
|
|||
collect(inter);
|
||||
// Find the beginning of the linked intersections and loop all
|
||||
// the way back to start, to collect all valid intersections.
|
||||
while (inter && inter._prev)
|
||||
inter = inter._prev;
|
||||
while (inter && inter._previous)
|
||||
inter = inter._previous;
|
||||
collect(inter, start);
|
||||
}
|
||||
return crossings;
|
||||
|
@ -1125,7 +1203,7 @@ PathItem.inject(new function() {
|
|||
/**
|
||||
* Splits the geometry of this path along the geometry of the specified
|
||||
* path returns the result as a new group item. This is equivalent to
|
||||
* calling {@link #subtract(path)} and {@link #subtract(path)} and
|
||||
* calling {@link #subtract(path)} and {@link #intersect(path)} and
|
||||
* putting the results into a new group.
|
||||
*
|
||||
* @option [options.insert=true] {Boolean} whether the resulting item
|
||||
|
@ -1156,7 +1234,7 @@ PathItem.inject(new function() {
|
|||
* amount of resulting paths allows so, otherwise a new path /
|
||||
* compound-path is created, replacing the current one.
|
||||
*
|
||||
* @return {PahtItem} the resulting path item
|
||||
* @return {PathItem} the resulting path item
|
||||
*/
|
||||
resolveCrossings: function() {
|
||||
var children = this._children,
|
||||
|
@ -1168,7 +1246,7 @@ PathItem.inject(new function() {
|
|||
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.
|
||||
var hasOverlaps = false,
|
||||
hasCrossings = false,
|
||||
|
@ -1278,7 +1356,7 @@ PathItem.inject(new function() {
|
|||
* @param {Boolean} [clockwise] if provided, the orientation of the root
|
||||
* paths will be set to the orientation specified by `clockwise`,
|
||||
* otherwise the orientation of the largest root child is used.
|
||||
* @return {PahtItem} a reference to the item itself, reoriented
|
||||
* @return {PathItem} a reference to the item itself, reoriented
|
||||
*/
|
||||
reorient: function(nonZero, clockwise) {
|
||||
var children = this._children;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -102,8 +102,8 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
*
|
||||
* @bean
|
||||
* @type Boolean
|
||||
* @see Path#getArea()
|
||||
* @see CompoundPath#getArea()
|
||||
* @see Path#area
|
||||
* @see CompoundPath#area
|
||||
*/
|
||||
isClockwise: function() {
|
||||
return this.getArea() >= 0;
|
||||
|
@ -345,18 +345,13 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
* crossing each other, as opposed to simply touching.
|
||||
*
|
||||
* @param {PathItem} path the other item to find the crossings with
|
||||
* @return {CurveLocation[]} the locations of all crossings between the
|
||||
* paths
|
||||
* @see #getIntersections(path)
|
||||
*/
|
||||
getCrossings: function(path) {
|
||||
return this.getIntersections(path, function(inter) {
|
||||
// TODO: Only return overlaps that are actually crossings! 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 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();
|
||||
return inter.isCrossing();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -727,16 +722,20 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
matched = [],
|
||||
count = 0;
|
||||
ok = true;
|
||||
var boundsOverlaps = CollisionDetection.findItemBoundsCollisions(paths1, paths2, Numerical.GEOMETRIC_EPSILON);
|
||||
for (var i1 = length1 - 1; i1 >= 0 && ok; i1--) {
|
||||
var path1 = paths1[i1];
|
||||
ok = false;
|
||||
for (var i2 = length2 - 1; i2 >= 0 && !ok; i2--) {
|
||||
if (path1.compare(paths2[i2])) {
|
||||
if (!matched[i2]) {
|
||||
matched[i2] = true;
|
||||
count++;
|
||||
var pathBoundsOverlaps = boundsOverlaps[i1];
|
||||
if (pathBoundsOverlaps) {
|
||||
for (var i2 = pathBoundsOverlaps.length - 1; i2 >= 0 && !ok; i2--) {
|
||||
if (path1.compare(paths2[pathBoundsOverlaps[i2]])) {
|
||||
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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
@ -234,8 +234,8 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
* Checks if the segment has any curve handles set.
|
||||
*
|
||||
* @return {Boolean} {@true if the segment has handles set}
|
||||
* @see Segment#getHandleIn()
|
||||
* @see Segment#getHandleOut()
|
||||
* @see Segment#handleIn
|
||||
* @see Segment#handleOut
|
||||
* @see Curve#hasHandles()
|
||||
* @see Path#hasHandles()
|
||||
*/
|
||||
|
@ -554,6 +554,9 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
return this._path ? !!this._path.removeSegment(this._index) : false;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Segment}
|
||||
*/
|
||||
clone: function() {
|
||||
return new Segment(this._point, this._handleIn, this._handleOut);
|
||||
},
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -80,7 +80,7 @@ var Color = Base.extend(new function() {
|
|||
} else if (match = string.match(/^(rgb|hsl)a?\((.*)\)$/)) {
|
||||
// RGB / RGBA or HSL / HSLA
|
||||
type = match[1];
|
||||
components = match[2].split(/[,\s]+/g);
|
||||
components = match[2].trim().split(/[,\s]+/g);
|
||||
var isHSL = type === 'hsl';
|
||||
for (var i = 0, l = Math.min(components.length, 4); i < l; i++) {
|
||||
var component = components[i];
|
||||
|
@ -102,7 +102,7 @@ var Color = Base.extend(new function() {
|
|||
}
|
||||
} else if (i < 3) {
|
||||
// RGB color values to 0..1
|
||||
value /= 255;
|
||||
value /= /%$/.test(component) ? 100 : 255;
|
||||
}
|
||||
components[i] = value;
|
||||
}
|
||||
|
@ -691,6 +691,8 @@ var Color = Base.extend(new function() {
|
|||
* constructors also work for calls of `set()`.
|
||||
*
|
||||
* @function
|
||||
* @param {...*} values
|
||||
* @return {Color}
|
||||
*/
|
||||
set: '#initialize',
|
||||
|
||||
|
@ -709,8 +711,13 @@ var Color = Base.extend(new function() {
|
|||
*/
|
||||
_changed: function() {
|
||||
this._canvasStyle = null;
|
||||
if (this._owner)
|
||||
this._owner._changed(/*#=*/Change.STYLE);
|
||||
if (this._owner) {
|
||||
if (this._setter) {
|
||||
this._owner[this._setter](this);
|
||||
} else {
|
||||
this._owner._changed(/*#=*/Change.STYLE);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -729,7 +736,7 @@ var Color = Base.extend(new function() {
|
|||
},
|
||||
|
||||
/**
|
||||
* Converts the color another type.
|
||||
* Converts the color to another type.
|
||||
*
|
||||
* @param {String} type the color type to convert to. Possible values:
|
||||
* {@values 'rgb', 'gray', 'hsb', 'hsl'}
|
||||
|
@ -1183,9 +1190,35 @@ var Color = Base.extend(new function() {
|
|||
// Export for backward compatibility code below.
|
||||
_types: types,
|
||||
|
||||
/**
|
||||
* Returns a color object with random {@link #red}, {@link #green}
|
||||
* and {@link #blue} values between `0` and `1`.
|
||||
*
|
||||
* @return {Color} the newly created color object
|
||||
* @static
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* var circle = new Path.Circle(view.center, 50);
|
||||
* // Set a random color as circle fill color.
|
||||
* circle.fillColor = Color.random();
|
||||
*/
|
||||
random: function() {
|
||||
var random = Math.random;
|
||||
return new Color(random(), random(), random());
|
||||
},
|
||||
|
||||
_setOwner: function(color, owner, setter) {
|
||||
if (color) {
|
||||
// Clone color if owner changes:
|
||||
if (color._owner && owner && color._owner !== owner) {
|
||||
color = color.clone();
|
||||
}
|
||||
if (!color._owner ^ !owner) {
|
||||
color._owner = owner || null;
|
||||
color._setter = setter || null;
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -175,12 +175,10 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
|||
},
|
||||
|
||||
setColor: function(/* color */) {
|
||||
// Make sure newly set colors are cloned, since they can only have
|
||||
// one owner.
|
||||
var color = Color.read(arguments, 0, { clone: true });
|
||||
if (color)
|
||||
color._owner = this;
|
||||
this._color = color;
|
||||
// Clear old color owner before setting new one:
|
||||
Color._setOwner(this._color, null);
|
||||
this._color = Color._setOwner(Color.read(arguments, 0), this,
|
||||
'setColor');
|
||||
this._changed();
|
||||
},
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -162,29 +162,35 @@ var Style = Base.extend(new function() {
|
|||
// raw value is stored, and conversion only happens in the getter.
|
||||
fields[set] = function(value) {
|
||||
var owner = this._owner,
|
||||
children = owner && owner._children;
|
||||
children = owner && owner._children,
|
||||
applyToChildren = children && children.length > 0
|
||||
&& !(owner instanceof CompoundPath);
|
||||
// Only unify styles on children of Groups, excluding CompoundPaths.
|
||||
if (children && children.length > 0
|
||||
&& !(owner instanceof CompoundPath)) {
|
||||
if (applyToChildren) {
|
||||
for (var i = 0, l = children.length; i < l; i++)
|
||||
children[i]._style[set](value);
|
||||
} else if (key in this._defaults) {
|
||||
}
|
||||
// Always store selectedColor in item _values to make sure that
|
||||
// group selected bounds and position color is coherent whether it
|
||||
// has children or not when the value is set.
|
||||
if ((key === 'selectedColor' || !applyToChildren)
|
||||
&& key in this._defaults) {
|
||||
var old = this._values[key];
|
||||
if (old !== value) {
|
||||
if (isColor) {
|
||||
// The old value may be a native string or other color
|
||||
// description that wasn't coerced to a color object yet
|
||||
if (old && old._owner !== undefined) {
|
||||
old._owner = undefined;
|
||||
if (old) {
|
||||
Color._setOwner(old, null);
|
||||
old._canvasStyle = null;
|
||||
}
|
||||
if (value && value.constructor === Color) {
|
||||
// Clone color if it already has an owner.
|
||||
// NOTE: If value is not a Color, it is only
|
||||
// converted and cloned in the getter further down.
|
||||
if (value._owner)
|
||||
value = value.clone();
|
||||
value._owner = owner;
|
||||
value = Color._setOwner(value, owner,
|
||||
// Only provide a color-setter if the style
|
||||
// is to be applied to the children:
|
||||
applyToChildren && set);
|
||||
}
|
||||
}
|
||||
// NOTE: We do not convert the values to Colors in the
|
||||
|
@ -201,29 +207,13 @@ var Style = Base.extend(new function() {
|
|||
fields[get] = function(_dontMerge) {
|
||||
var owner = this._owner,
|
||||
children = owner && owner._children,
|
||||
applyToChildren = children && children.length > 0
|
||||
&& !(owner instanceof CompoundPath),
|
||||
value;
|
||||
// If the owner has children, walk through all of them and see if
|
||||
// they all have the same style.
|
||||
// If true is passed for _dontMerge, don't merge children styles
|
||||
if (key in this._defaults && (!children || !children.length
|
||||
|| _dontMerge || owner instanceof CompoundPath)) {
|
||||
var value = this._values[key];
|
||||
if (value === undefined) {
|
||||
value = this._defaults[key];
|
||||
if (value && value.clone)
|
||||
value = value.clone();
|
||||
} else {
|
||||
var ctor = isColor ? Color : isPoint ? Point : null;
|
||||
if (ctor && !(value && value.constructor === ctor)) {
|
||||
// Convert to a Color / Point, and stored result of the
|
||||
// conversion.
|
||||
this._values[key] = value = ctor.read([value], 0,
|
||||
{ readNull: true, clone: true });
|
||||
if (value && isColor)
|
||||
value._owner = owner;
|
||||
}
|
||||
}
|
||||
} else if (children) {
|
||||
// If true is passed for _dontMerge, don't merge children styles.
|
||||
if (applyToChildren && !_dontMerge) {
|
||||
for (var i = 0, l = children.length; i < l; i++) {
|
||||
var childValue = children[i]._style[get]();
|
||||
if (!i) {
|
||||
|
@ -234,6 +224,30 @@ var Style = Base.extend(new function() {
|
|||
return undefined;
|
||||
}
|
||||
}
|
||||
} else if (key in this._defaults) {
|
||||
var value = this._values[key];
|
||||
if (value === undefined) {
|
||||
value = this._defaults[key];
|
||||
// Clone defaults if available:
|
||||
if (value && value.clone) {
|
||||
value = value.clone();
|
||||
}
|
||||
} else {
|
||||
var ctor = isColor ? Color : isPoint ? Point : null;
|
||||
if (ctor && !(value && value.constructor === ctor)) {
|
||||
// Convert to a Color / Point, and stored result of the
|
||||
// conversion.
|
||||
this._values[key] = value = ctor.read([value], 0,
|
||||
{ readNull: true, clone: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value && isColor) {
|
||||
// Color._setOwner() may clone the color if it already has a
|
||||
// different owner (e.g. resulting from `childValue` above).
|
||||
// Only provide a color-setter if the style is to be applied to
|
||||
// the children:
|
||||
value = Color._setOwner(value, owner, applyToChildren && set);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
@ -397,7 +411,7 @@ var Style = Base.extend(new function() {
|
|||
*
|
||||
* @name Style#strokeColor
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Setting the stroke color of a path:
|
||||
|
@ -530,7 +544,7 @@ var Style = Base.extend(new function() {
|
|||
*
|
||||
* @name Style#dashArray
|
||||
* @property
|
||||
* @type Array
|
||||
* @type Number[]
|
||||
* @default []
|
||||
*/
|
||||
|
||||
|
@ -554,7 +568,7 @@ var Style = Base.extend(new function() {
|
|||
*
|
||||
* @name Style#fillColor
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Setting the fill color of a path to red:
|
||||
|
@ -585,7 +599,7 @@ var Style = Base.extend(new function() {
|
|||
*
|
||||
* @property
|
||||
* @name Style#shadowColor
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Creating a circle with a black shadow:
|
||||
|
@ -629,7 +643,7 @@ var Style = Base.extend(new function() {
|
|||
*
|
||||
* @name Style#selectedColor
|
||||
* @property
|
||||
* @type Color
|
||||
* @type ?Color
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -29,11 +29,16 @@ new function() {
|
|||
// in rotate(). To do so, SVG requries us to inverse transform the
|
||||
// translation point by the matrix itself, since they are provided
|
||||
// in local coordinates.
|
||||
matrix = matrix._shiftless();
|
||||
var point = matrix._inverseTransform(trans);
|
||||
var point;
|
||||
if (matrix.isInvertible()) {
|
||||
matrix = matrix._shiftless();
|
||||
point = matrix._inverseTransform(trans);
|
||||
trans = null;
|
||||
} else {
|
||||
point = new Point();
|
||||
}
|
||||
attrs[center ? 'cx' : 'x'] = point.x;
|
||||
attrs[center ? 'cy' : 'y'] = point.y;
|
||||
trans = null;
|
||||
}
|
||||
if (!matrix.isIdentity()) {
|
||||
// See if we can decompose the matrix and can formulate it as a
|
||||
|
@ -177,7 +182,7 @@ new function() {
|
|||
definition = item._definition,
|
||||
node = getDefinition(definition, 'symbol'),
|
||||
definitionItem = definition._item,
|
||||
bounds = definitionItem.getBounds();
|
||||
bounds = definitionItem.getStrokeBounds();
|
||||
if (!node) {
|
||||
node = SvgElement.create('symbol', {
|
||||
viewBox: formatter.rectangle(bounds)
|
||||
|
@ -456,7 +461,7 @@ new function() {
|
|||
if (rect) {
|
||||
attrs.width = rect.width;
|
||||
attrs.height = rect.height;
|
||||
if (rect.x || rect.y)
|
||||
if (rect.x || rect.x === 0 || rect.y || rect.y === 0)
|
||||
attrs.viewBox = formatter.rectangle(rect);
|
||||
}
|
||||
var node = SvgElement.create('svg', attrs, formatter),
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -22,11 +22,12 @@ new function() {
|
|||
var definitions = {},
|
||||
rootSize;
|
||||
|
||||
function getValue(node, name, isString, allowNull, allowPercent) {
|
||||
function getValue(node, name, isString, allowNull, allowPercent,
|
||||
defaultValue) {
|
||||
// Interpret value as number. Never return NaN, but 0 instead.
|
||||
// If the value is a sequence of numbers, parseFloat will
|
||||
// return the first occurring number, which is enough for now.
|
||||
var value = SvgElement.get(node, name),
|
||||
var value = SvgElement.get(node, name) || defaultValue,
|
||||
res = value == null
|
||||
? allowNull
|
||||
? null
|
||||
|
@ -43,9 +44,9 @@ new function() {
|
|||
: res;
|
||||
}
|
||||
|
||||
function getPoint(node, x, y, allowNull, allowPercent) {
|
||||
x = getValue(node, x || 'x', false, allowNull, allowPercent);
|
||||
y = getValue(node, y || 'y', false, allowNull, allowPercent);
|
||||
function getPoint(node, x, y, allowNull, allowPercent, defaultX, defaultY) {
|
||||
x = getValue(node, x || 'x', false, allowNull, allowPercent, defaultX);
|
||||
y = getValue(node, y || 'y', false, allowNull, allowPercent, defaultY);
|
||||
return allowNull && (x == null || y == null) ? null
|
||||
: new Point(x, y);
|
||||
}
|
||||
|
@ -168,13 +169,16 @@ new function() {
|
|||
'userSpaceOnUse';
|
||||
// Allow percentages in all values if scaleToBounds is true:
|
||||
if (radial) {
|
||||
origin = getPoint(node, 'cx', 'cy', false, scaleToBounds);
|
||||
origin = getPoint(node, 'cx', 'cy', false, scaleToBounds,
|
||||
'50%', '50%');
|
||||
destination = origin.add(
|
||||
getValue(node, 'r', false, false, scaleToBounds), 0);
|
||||
getValue(node, 'r', false, false, scaleToBounds, '50%'), 0);
|
||||
highlight = getPoint(node, 'fx', 'fy', true, scaleToBounds);
|
||||
} else {
|
||||
origin = getPoint(node, 'x1', 'y1', false, scaleToBounds);
|
||||
destination = getPoint(node, 'x2', 'y2', false, scaleToBounds);
|
||||
origin = getPoint(node, 'x1', 'y1', false, scaleToBounds,
|
||||
'0%', '0%');
|
||||
destination = getPoint(node, 'x2', 'y2', false, scaleToBounds,
|
||||
'100%', '0%');
|
||||
}
|
||||
var color = applyAttributes(
|
||||
new Color(gradient, origin, destination, highlight), node);
|
||||
|
@ -196,23 +200,23 @@ new function() {
|
|||
return importNode(child, options, isRoot);
|
||||
}
|
||||
},
|
||||
// http://www.w3.org/TR/SVG/struct.html#Groups
|
||||
// https://www.w3.org/TR/SVG/struct.html#Groups
|
||||
g: importGroup,
|
||||
// http://www.w3.org/TR/SVG/struct.html#NewDocument
|
||||
// https://www.w3.org/TR/SVG/struct.html#NewDocument
|
||||
svg: importGroup,
|
||||
clippath: importGroup,
|
||||
// http://www.w3.org/TR/SVG/shapes.html#PolygonElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#PolygonElement
|
||||
polygon: importPoly,
|
||||
// http://www.w3.org/TR/SVG/shapes.html#PolylineElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#PolylineElement
|
||||
polyline: importPoly,
|
||||
// http://www.w3.org/TR/SVG/paths.html
|
||||
// https://www.w3.org/TR/SVG/paths.html
|
||||
path: importPath,
|
||||
// http://www.w3.org/TR/SVG/pservers.html#LinearGradients
|
||||
// https://www.w3.org/TR/SVG/pservers.html#LinearGradients
|
||||
lineargradient: importGradient,
|
||||
// http://www.w3.org/TR/SVG/pservers.html#RadialGradients
|
||||
// https://www.w3.org/TR/SVG/pservers.html#RadialGradients
|
||||
radialgradient: importGradient,
|
||||
|
||||
// http://www.w3.org/TR/SVG/struct.html#ImageElement
|
||||
// https://www.w3.org/TR/SVG/struct.html#ImageElement
|
||||
image: function (node) {
|
||||
var raster = new Raster(getValue(node, 'href', true));
|
||||
raster.on('load', function() {
|
||||
|
@ -228,17 +232,17 @@ new function() {
|
|||
return raster;
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/struct.html#SymbolElement
|
||||
// https://www.w3.org/TR/SVG/struct.html#SymbolElement
|
||||
symbol: function(node, type, options, isRoot) {
|
||||
return new SymbolDefinition(
|
||||
// Pass true for dontCenter:
|
||||
importGroup(node, type, options, isRoot), true);
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/struct.html#DefsElement
|
||||
// https://www.w3.org/TR/SVG/struct.html#DefsElement
|
||||
defs: importGroup,
|
||||
|
||||
// http://www.w3.org/TR/SVG/struct.html#UseElement
|
||||
// https://www.w3.org/TR/SVG/struct.html#UseElement
|
||||
use: function(node) {
|
||||
// Note the namespaced xlink:href attribute is just called href
|
||||
// as a property on node.
|
||||
|
@ -258,14 +262,14 @@ new function() {
|
|||
: null;
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement
|
||||
circle: function(node) {
|
||||
return new Shape.Circle(
|
||||
getPoint(node, 'cx', 'cy'),
|
||||
getValue(node, 'r'));
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement
|
||||
ellipse: function(node) {
|
||||
// We only use object literal notation where the default one is not
|
||||
// supported (e.g. center / radius fo Shape.Ellipse).
|
||||
|
@ -275,7 +279,7 @@ new function() {
|
|||
});
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/shapes.html#RectElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#RectElement
|
||||
rect: function(node) {
|
||||
return new Shape.Rectangle(new Rectangle(
|
||||
getPoint(node),
|
||||
|
@ -283,7 +287,7 @@ new function() {
|
|||
), getSize(node, 'rx', 'ry'));
|
||||
},
|
||||
|
||||
// http://www.w3.org/TR/SVG/shapes.html#LineElement
|
||||
// https://www.w3.org/TR/SVG/shapes.html#LineElement
|
||||
line: function(node) {
|
||||
return new Path.Line(
|
||||
getPoint(node, 'x1', 'y1'),
|
||||
|
@ -345,7 +349,11 @@ new function() {
|
|||
text.setContent(lines.join('\n'));
|
||||
return text;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://www.w3.org/TR/SVG/struct.html#SwitchElement
|
||||
// Conditional attributes are ignored and all children are rendered.
|
||||
switch: importGroup
|
||||
};
|
||||
|
||||
// Attributes and Styles
|
||||
|
@ -356,7 +364,7 @@ new function() {
|
|||
|
||||
function applyTransform(item, value, name, node) {
|
||||
if (item.transform) {
|
||||
// http://www.w3.org/TR/SVG/types.html#DataTypeTransformList
|
||||
// https://www.w3.org/TR/SVG/types.html#DataTypeTransformList
|
||||
// Parse SVG transform string. First we split at /)\s*/, to separate
|
||||
// commands
|
||||
var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
|
||||
|
@ -399,8 +407,8 @@ new function() {
|
|||
}
|
||||
|
||||
function applyOpacity(item, value, name) {
|
||||
// http://www.w3.org/TR/SVG/painting.html#FillOpacityProperty
|
||||
// http://www.w3.org/TR/SVG/painting.html#StrokeOpacityProperty
|
||||
// https://www.w3.org/TR/SVG/painting.html#FillOpacityProperty
|
||||
// https://www.w3.org/TR/SVG/painting.html#StrokeOpacityProperty
|
||||
var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor',
|
||||
color = item[key] && item[key]();
|
||||
if (color)
|
||||
|
@ -442,7 +450,7 @@ new function() {
|
|||
},
|
||||
|
||||
'clip-path': function(item, value) {
|
||||
// http://www.w3.org/TR/SVG/masking.html#ClipPathProperty
|
||||
// https://www.w3.org/TR/SVG/masking.html#ClipPathProperty
|
||||
var clip = getDefinition(value);
|
||||
if (clip) {
|
||||
clip = clip.clone();
|
||||
|
@ -474,20 +482,20 @@ new function() {
|
|||
},
|
||||
|
||||
'stop-color': function(item, value) {
|
||||
// http://www.w3.org/TR/SVG/pservers.html#StopColorProperty
|
||||
// https://www.w3.org/TR/SVG/pservers.html#StopColorProperty
|
||||
if (item.setColor)
|
||||
item.setColor(value);
|
||||
},
|
||||
|
||||
'stop-opacity': function(item, value) {
|
||||
// http://www.w3.org/TR/SVG/pservers.html#StopOpacityProperty
|
||||
// https://www.w3.org/TR/SVG/pservers.html#StopOpacityProperty
|
||||
// NOTE: It is important that this is applied after stop-color!
|
||||
if (item._color)
|
||||
item._color.setAlpha(parseFloat(value));
|
||||
},
|
||||
|
||||
offset: function(item, value) {
|
||||
// http://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute
|
||||
// https://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute
|
||||
if (item.setOffset) {
|
||||
var percent = value.match(/(.*)%$/);
|
||||
item.setOffset(percent ? percent[1] / 100 : parseFloat(value));
|
||||
|
@ -495,7 +503,7 @@ new function() {
|
|||
},
|
||||
|
||||
viewBox: function(item, value, name, node, styles) {
|
||||
// http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
|
||||
// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
|
||||
// TODO: implement preserveAspectRatio attribute
|
||||
// viewBox will be applied both to the group that's created for the
|
||||
// content in SymbolDefinition#item, and the SymbolItem itself.
|
||||
|
@ -703,8 +711,12 @@ new function() {
|
|||
|
||||
function onLoad(svg) {
|
||||
try {
|
||||
var node = typeof svg === 'object' ? svg : new self.DOMParser()
|
||||
.parseFromString(svg, 'image/svg+xml');
|
||||
var node = typeof svg === 'object'
|
||||
? svg
|
||||
: new self.DOMParser().parseFromString(
|
||||
svg,
|
||||
'image/svg+xml'
|
||||
);
|
||||
if (!node.nodeName) {
|
||||
node = null;
|
||||
throw new Error('Unsupported SVG source: ' + source);
|
||||
|
@ -734,8 +746,10 @@ new function() {
|
|||
|
||||
// Have the group not pass on all transformations to its children,
|
||||
// as this is how SVG works too.
|
||||
// See if it's a string but handle markup separately
|
||||
if (typeof source === 'string' && !/^.*</.test(source)) {
|
||||
// See if it's a string but handle markup separately, using `[\s\S]` to
|
||||
// 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
|
||||
// id.
|
||||
var node = document.getElementById(source);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -135,7 +135,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
|||
*
|
||||
* @name Tool#onMouseDown
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Creating circle shaped paths where the user presses the mouse button:
|
||||
|
@ -157,7 +157,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
|||
*
|
||||
* @name Tool#onMouseDrag
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Moving a path to the position of the mouse:
|
||||
|
@ -206,7 +206,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
|||
*
|
||||
* @name Tool#onMouseUp
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Creating circle shaped paths where the user releases the mouse:
|
||||
|
@ -234,7 +234,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
|||
*
|
||||
* @name Tool#onKeyDown
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // Scaling a path whenever the user presses the space bar:
|
||||
|
@ -268,7 +268,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
|||
*
|
||||
* @name Tool#onKeyUp
|
||||
* @property
|
||||
* @type Function
|
||||
* @type ?Function
|
||||
*
|
||||
* @example
|
||||
* tool.onKeyUp = function(event) {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* 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.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||
* Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
|
||||
* http://juerglehni.com/ & https://puckey.studio/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
|
@ -168,6 +168,10 @@ var Numerical = new function() {
|
|||
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.
|
||||
*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue