diff --git a/package.json b/package.json index b7714ac..06b92a4 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "dependencies": { "@types/bezier-js": "^4.1.3", "bezier-js": "^6.1.4", - "linearly": "^0.21.0" + "linearly": "^0.21.0", + "paper": "^0.12.17" } } diff --git a/src/Path.ts b/src/Path.ts index 70c691b..6239032 100644 --- a/src/Path.ts +++ b/src/Path.ts @@ -1,4 +1,5 @@ import {mat2d, scalar, vec2} from 'linearly' +import paper from 'paper' import {Bezier} from './Bezier' import {memoize, toFixedSimple} from './utils' @@ -622,6 +623,84 @@ export namespace Path { return path2d }) + /** + * Converts the given path to paper.Path + * @see http://paperjs.org/reference/pathitem/ + * @param path The path to convert + * @returns The newly created paper.Path instance + */ + export const toPaperPath = memoize((path: Path): paper.Path => { + const paperPath = new paper.Path() + + let prev: vec2 | undefined + let prevControl: vec2 | undefined + + for (const seg of path) { + switch (seg[0]) { + case 'M': + paperPath.moveTo(toPoint(seg[1])) + prev = seg[1] + break + case 'L': + paperPath.lineTo(toPoint(seg[1])) + prev = seg[1] + break + case 'H': + paperPath.lineTo({x: seg[1], y: prev![1]}) + prev = [seg[1], prev![1]] + break + case 'V': + paperPath.lineTo({x: prev![0], y: seg[1]}) + prev = [prev![0], seg[1]] + break + case 'C': + paperPath.cubicCurveTo( + toPoint(seg[1]), + toPoint(seg[2]), + toPoint(seg[3]) + ) + prevControl = seg[2] + prev = seg[3] + break + case 'S': { + const control1 = vec2.add(seg[1], vec2.sub(seg[1], prevControl!)) + paperPath.cubicCurveTo( + toPoint(control1), + toPoint(seg[1]), + toPoint(seg[2]) + ) + prevControl = seg[1] + prev = seg[2] + break + } + case 'Q': + paperPath.quadraticCurveTo(toPoint(seg[1]), toPoint(seg[2])) + prevControl = seg[1] + prev = seg[2] + break + case 'T': { + const control = vec2.add(seg[1], vec2.sub(seg[1], prevControl!)) + paperPath.quadraticCurveTo(toPoint(control), toPoint(seg[1])) + prevControl = seg[1] + prev = seg[1] + break + } + case 'A': { + throw new Error('Not supported yet') + } + case 'Z': + paperPath.closePath() + break + } + } + + return paperPath + + function toPoint(point: vec2): paper.PointLike { + return {x: point[0], y: point[1]} + } + }) + /** * Converts the Arc command to a center parameterization that can be used in Context2D.ellipse(). * https://observablehq.com/@awhitty/svg-2-elliptical-arc-to-canvas-path2d diff --git a/yarn.lock b/yarn.lock index ac37195..42476a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2836,6 +2836,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +paper@^0.12.17: + version "0.12.17" + resolved "https://registry.yarnpkg.com/paper/-/paper-0.12.17.tgz#57215615f3db5a32826ab60d3e08bc7953614052" + integrity sha512-oCe+e1C2w8hKIcGoAqUjD0GGxGPv+itrRXlEFUmp3H8tY/NTnHOkYgpJFPGw6OJ8Q1Wa6+RgzlY7Dx/2WWHtkA== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"