From 8686c06f1f30fa722201db011d0663b969ad0ebf Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Wed, 7 Sep 2022 13:43:40 +0100 Subject: [PATCH] Update examples --- packages/dev/src/state/shapes/draw.tsx | 37 ++++++++++++------- packages/perfect-freehand/README.md | 34 +++++++++++------ .../src/test/getStroke.spec.ts | 35 ++++++++++++------ 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/packages/dev/src/state/shapes/draw.tsx b/packages/dev/src/state/shapes/draw.tsx index 35bbbcc..5ff3dd7 100644 --- a/packages/dev/src/state/shapes/draw.tsx +++ b/packages/dev/src/state/shapes/draw.tsx @@ -231,21 +231,30 @@ export class DrawUtil extends TLShapeUtil { } } +const average = (a: number, b: number) => (a + b) / 2 + function getSvgPathFromStroke(points: number[][]): string { - if (!points.length) return '' - - return points - .reduce( - (acc, point, i, arr) => { - if (i === points.length - 1) - acc.push(point, Vec.med(point, arr[0]), 'Z') - else acc.push(point, Vec.med(point, arr[i + 1])) - return acc - }, - ['M', points[0], 'Q'] - ) - .join(' ') - .replaceAll(/(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g, '$1') + const len = points.length + + if (!len) { + return '' + } + + const first = points[0] + let result = `M${first[0].toFixed(3)},${first[1].toFixed(3)}Q` + + for (let i = 0, max = len - 1; i < max; i++) { + const a = points[i] + const b = points[i + 1] + result += `${a[0].toFixed(3)},${a[1].toFixed(3)} ${average( + a[0], + b[0] + ).toFixed(3)},${average(a[1], b[1]).toFixed(3)} ` + } + + result += 'Z' + + return result } export function dot([x, y]: number[]) { diff --git a/packages/perfect-freehand/README.md b/packages/perfect-freehand/README.md index 3b74c08..3ceed69 100644 --- a/packages/perfect-freehand/README.md +++ b/packages/perfect-freehand/README.md @@ -262,20 +262,30 @@ While `getStroke` returns an array of points representing the outline of a strok The function below will turn the points returned by `getStroke` into SVG path data. ```js +const average = (a, b) => (a + b) / 2 + function getSvgPathFromStroke(stroke) { - if (!stroke.length) return '' - - const d = stroke.reduce( - (acc, [x0, y0], i, arr) => { - const [x1, y1] = arr[(i + 1) % arr.length] - acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2) - return acc - }, - ['M', ...stroke[0], 'Q'] - ) + const len = points.length - d.push('Z') - return d.join(' ') + if (!len) { + return '' + } + + const first = points[0] + let result = `M${first[0].toFixed(3)},${first[1].toFixed(3)}Q` + + for (let i = 0, max = len - 1; i < max; i++) { + const a = points[i] + const b = points[i + 1] + result += `${a[0].toFixed(3)},${a[1].toFixed(3)} ${average( + a[0], + b[0] + ).toFixed(3)},${average(a[1], b[1]).toFixed(3)} ` + } + + result += 'Z' + + return result } ``` diff --git a/packages/perfect-freehand/src/test/getStroke.spec.ts b/packages/perfect-freehand/src/test/getStroke.spec.ts index 7d235af..ce78ec4 100644 --- a/packages/perfect-freehand/src/test/getStroke.spec.ts +++ b/packages/perfect-freehand/src/test/getStroke.spec.ts @@ -27,19 +27,30 @@ function getRng(seed = ''): () => number { return next } +const average = (a: number, b: number) => (a + b) / 2 + function getSvgPathFromStroke(points: number[][]): string { - if (!points.length) return '' - - return points - .reduce( - (acc, point, i, arr) => { - if (i === points.length - 1) acc.push(point, med(point, arr[0])) - else acc.push(point, med(point, arr[i + 1])) - return acc - }, - ['M', points[0], 'Q'] - ) - .join(' ') + const len = points.length + + if (!len) { + return '' + } + + const first = points[0] + let result = `M${first[0].toFixed(3)},${first[1].toFixed(3)}Q` + + for (let i = 0, max = len - 1; i < max; i++) { + const a = points[i] + const b = points[i + 1] + result += `${a[0].toFixed(3)},${a[1].toFixed(3)} ${average( + a[0], + b[0] + ).toFixed(3)},${average(a[1], b[1]).toFixed(3)} ` + } + + result += 'Z' + + return result } describe('getStroke', () => {