diff --git a/packages/tldraw/src/lib/shapes/draw/toolStates/Drawing.ts b/packages/tldraw/src/lib/shapes/draw/toolStates/Drawing.ts index 5d6f7c548..8c23577e1 100644 --- a/packages/tldraw/src/lib/shapes/draw/toolStates/Drawing.ts +++ b/packages/tldraw/src/lib/shapes/draw/toolStates/Drawing.ts @@ -97,7 +97,7 @@ export class Drawing extends StateNode { this.mergeNextPoint = false } - this.updateShapes() + this.updateDrawingShape() } } @@ -115,7 +115,7 @@ export class Drawing extends StateNode { } } } - this.updateShapes() + this.updateDrawingShape() } override onKeyUp: TLEventHandlers['onKeyUp'] = (info) => { @@ -137,7 +137,7 @@ export class Drawing extends StateNode { } } - this.updateShapes() + this.updateDrawingShape() } override onExit? = () => { @@ -281,7 +281,7 @@ export class Drawing extends StateNode { this.initialShape = this.editor.getShape(id) } - private updateShapes() { + private updateDrawingShape() { const { initialShape } = this const { inputs } = this.editor diff --git a/packages/tldraw/src/lib/shapes/shared/freehand/svgInk.ts b/packages/tldraw/src/lib/shapes/shared/freehand/svgInk.ts index bb60d358b..eb1241877 100644 --- a/packages/tldraw/src/lib/shapes/shared/freehand/svgInk.ts +++ b/packages/tldraw/src/lib/shapes/shared/freehand/svgInk.ts @@ -1,12 +1,4 @@ -import { - Vec, - VecLike, - assert, - average, - precise, - shortAngleDist, - toDomPrecision, -} from '@tldraw/editor' +import { Vec, VecLike, assert, average, precise, toDomPrecision } from '@tldraw/editor' import { getStrokeOutlineTracks } from './getStrokeOutlinePoints' import { getStrokePoints } from './getStrokePoints' import { setStrokePointRadii } from './setStrokePointRadii' @@ -36,17 +28,20 @@ function partitionAtElbows(points: StrokePoint[]): StrokePoint[][] { const result: StrokePoint[][] = [] let currentPartition: StrokePoint[] = [points[0]] - for (let i = 1; i < points.length - 1; i++) { - const prevPoint = points[i - 1] - const thisPoint = points[i] - const nextPoint = points[i + 1] - const prevAngle = Vec.Angle(prevPoint.point, thisPoint.point) - const nextAngle = Vec.Angle(thisPoint.point, nextPoint.point) - // acuteness is a normalized representation of how acute the angle is. - // 1 is an infinitely thin wedge - // 0 is a straight line - const acuteness = Math.abs(shortAngleDist(prevAngle, nextAngle)) / Math.PI - if (acuteness > 0.8) { + let prevV = Vec.Sub(points[1].point, points[0].point).uni() + let nextV: Vec + let dpr: number + let prevPoint: StrokePoint, thisPoint: StrokePoint, nextPoint: StrokePoint + for (let i = 1, n = points.length; i < n - 1; i++) { + prevPoint = points[i - 1] + thisPoint = points[i] + nextPoint = points[i + 1] + + nextV = Vec.Sub(nextPoint.point, thisPoint.point).uni() + dpr = Vec.Dpr(prevV, nextV) + prevV = nextV + + if (dpr < -0.8) { // always treat such acute angles as elbows // and use the extended .input point as the elbow point for swooshiness in fast zaggy lines const elbowPoint = { @@ -59,19 +54,20 @@ function partitionAtElbows(points: StrokePoint[]): StrokePoint[][] { continue } currentPartition.push(thisPoint) - if (acuteness < 0.25) { - // this is not an elbow, bail out + + if (dpr > 0.7) { + // Not an elbow continue } + // so now we have a reasonably acute angle but it might not be an elbow if it's far - // away from it's neighbors - const avgRadius = (prevPoint.radius + thisPoint.radius + nextPoint.radius) / 3 - const incomingNormalizedDist = Vec.Dist(prevPoint.point, thisPoint.point) / avgRadius - const outgoingNormalizedDist = Vec.Dist(thisPoint.point, nextPoint.point) / avgRadius - // angular dist is a normalized representation of how far away the point is from it's neighbors + // away from it's neighbors, angular dist is a normalized representation of how far away the point is from it's neighbors // (normalized by the radius) - const angularDist = incomingNormalizedDist + outgoingNormalizedDist - if (angularDist < 1.5) { + if ( + (Vec.Dist2(prevPoint.point, thisPoint.point) + Vec.Dist2(thisPoint.point, nextPoint.point)) / + ((prevPoint.radius + thisPoint.radius + nextPoint.radius) / 3) ** 2 < + 1.5 + ) { // if this point is kinda close to its neighbors and it has a reasonably // acute angle, it's probably a hard elbow currentPartition.push(thisPoint) @@ -89,11 +85,13 @@ function partitionAtElbows(points: StrokePoint[]): StrokePoint[][] { function cleanUpPartition(partition: StrokePoint[]) { // clean up start of partition (remove points that are too close to the start) const startPoint = partition[0] + let nextPoint: StrokePoint while (partition.length > 2) { - const nextPoint = partition[1] - const dist = Vec.Dist(startPoint.point, nextPoint.point) - const avgRadius = (startPoint.radius + nextPoint.radius) / 2 - if (dist < avgRadius * 0.5) { + nextPoint = partition[1] + if ( + Vec.Dist2(startPoint.point, nextPoint.point) < + (((startPoint.radius + nextPoint.radius) / 2) * 0.5) ** 2 + ) { partition.splice(1, 1) } else { break @@ -101,11 +99,13 @@ function cleanUpPartition(partition: StrokePoint[]) { } // clean up end of partition in the same fashion const endPoint = partition[partition.length - 1] + let prevPoint: StrokePoint while (partition.length > 2) { - const prevPoint = partition[partition.length - 2] - const dist = Vec.Dist(endPoint.point, prevPoint.point) - const avgRadius = (endPoint.radius + prevPoint.radius) / 2 - if (dist < avgRadius * 0.5) { + prevPoint = partition[partition.length - 2] + if ( + Vec.Dist2(endPoint.point, prevPoint.point) < + (((endPoint.radius + prevPoint.radius) / 2) * 0.5) ** 2 + ) { partition.splice(partition.length - 2, 1) } else { break @@ -115,13 +115,14 @@ function cleanUpPartition(partition: StrokePoint[]) { if (partition.length > 1) { partition[0] = { ...partition[0], - vector: Vec.FromAngle(Vec.Angle(partition[1].point, partition[0].point)), + vector: Vec.Sub(partition[0].point, partition[1].point).uni(), } partition[partition.length - 1] = { ...partition[partition.length - 1], - vector: Vec.FromAngle( - Vec.Angle(partition[partition.length - 1].point, partition[partition.length - 2].point) - ), + vector: Vec.Sub( + partition[partition.length - 2].point, + partition[partition.length - 1].point + ).uni(), } } return partition diff --git a/packages/tldraw/src/test/__snapshots__/drawing.test.ts.snap b/packages/tldraw/src/test/__snapshots__/drawing.test.ts.snap new file mode 100644 index 000000000..d0450b5e3 --- /dev/null +++ b/packages/tldraw/src/test/__snapshots__/drawing.test.ts.snap @@ -0,0 +1,1287 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Draws a bunch: draw shape 1`] = ` +{ + "index": "a1", + "isLocked": false, + "meta": {}, + "opacity": 1, + "parentId": "page:page", + "props": { + "color": "black", + "dash": "draw", + "fill": "none", + "isClosed": false, + "isComplete": true, + "isPen": false, + "segments": [ + { + "points": [ + { + "x": 0, + "y": 0, + "z": 0.5, + }, + { + "x": 1, + "y": 0, + "z": 0.5, + }, + { + "x": 4, + "y": 0, + "z": 0.5, + }, + { + "x": 10, + "y": -1, + "z": 0.5, + }, + { + "x": 19, + "y": -4, + "z": 0.5, + }, + { + "x": 30, + "y": -10, + "z": 0.5, + }, + { + "x": 46, + "y": -20, + "z": 0.5, + }, + { + "x": 61, + "y": -30, + "z": 0.5, + }, + { + "x": 74, + "y": -43, + "z": 0.5, + }, + { + "x": 89, + "y": -59, + "z": 0.5, + }, + { + "x": 102, + "y": -77, + "z": 0.5, + }, + { + "x": 108, + "y": -90, + "z": 0.5, + }, + { + "x": 112, + "y": -103, + "z": 0.5, + }, + { + "x": 117, + "y": -119, + "z": 0.5, + }, + { + "x": 118, + "y": -131, + "z": 0.5, + }, + { + "x": 119, + "y": -137, + "z": 0.5, + }, + { + "x": 119, + "y": -145, + "z": 0.5, + }, + { + "x": 120, + "y": -152, + "z": 0.5, + }, + { + "x": 119, + "y": -158, + "z": 0.5, + }, + { + "x": 117, + "y": -163, + "z": 0.5, + }, + { + "x": 114, + "y": -167, + "z": 0.5, + }, + { + "x": 109, + "y": -169, + "z": 0.5, + }, + { + "x": 103, + "y": -170, + "z": 0.5, + }, + { + "x": 97, + "y": -170, + "z": 0.5, + }, + { + "x": 89, + "y": -170, + "z": 0.5, + }, + { + "x": 80, + "y": -166, + "z": 0.5, + }, + { + "x": 71, + "y": -159, + "z": 0.5, + }, + { + "x": 62, + "y": -150, + "z": 0.5, + }, + { + "x": 54, + "y": -138, + "z": 0.5, + }, + { + "x": 50, + "y": -126, + "z": 0.5, + }, + { + "x": 47, + "y": -113, + "z": 0.5, + }, + { + "x": 46, + "y": -99, + "z": 0.5, + }, + { + "x": 46, + "y": -82, + "z": 0.5, + }, + { + "x": 47, + "y": -61, + "z": 0.5, + }, + { + "x": 53, + "y": -41, + "z": 0.5, + }, + { + "x": 60, + "y": -24, + "z": 0.5, + }, + { + "x": 68, + "y": -7, + "z": 0.5, + }, + { + "x": 79, + "y": 12, + "z": 0.5, + }, + { + "x": 88, + "y": 32, + "z": 0.5, + }, + { + "x": 96, + "y": 50, + "z": 0.5, + }, + { + "x": 103, + "y": 69, + "z": 0.5, + }, + { + "x": 106, + "y": 86, + "z": 0.5, + }, + { + "x": 107, + "y": 102, + "z": 0.5, + }, + { + "x": 107, + "y": 120, + "z": 0.5, + }, + { + "x": 102, + "y": 136, + "z": 0.5, + }, + { + "x": 90, + "y": 146, + "z": 0.5, + }, + { + "x": 74, + "y": 154, + "z": 0.5, + }, + { + "x": 43, + "y": 163, + "z": 0.5, + }, + { + "x": 32, + "y": 164, + "z": 0.5, + }, + { + "x": 21, + "y": 164, + "z": 0.5, + }, + { + "x": 11, + "y": 164, + "z": 0.5, + }, + { + "x": 2, + "y": 164, + "z": 0.5, + }, + { + "x": -7, + "y": 162, + "z": 0.5, + }, + { + "x": -13, + "y": 159, + "z": 0.5, + }, + { + "x": -15, + "y": 153, + "z": 0.5, + }, + { + "x": -15, + "y": 147, + "z": 0.5, + }, + { + "x": -11, + "y": 138, + "z": 0.5, + }, + { + "x": 1, + "y": 127, + "z": 0.5, + }, + { + "x": 15, + "y": 112, + "z": 0.5, + }, + { + "x": 34, + "y": 96, + "z": 0.5, + }, + { + "x": 56, + "y": 79, + "z": 0.5, + }, + { + "x": 81, + "y": 58, + "z": 0.5, + }, + { + "x": 107, + "y": 33, + "z": 0.5, + }, + { + "x": 126, + "y": 12, + "z": 0.5, + }, + { + "x": 145, + "y": -10, + "z": 0.5, + }, + { + "x": 160, + "y": -30, + "z": 0.5, + }, + { + "x": 172, + "y": -50, + "z": 0.5, + }, + { + "x": 185, + "y": -73, + "z": 0.5, + }, + { + "x": 194, + "y": -93, + "z": 0.5, + }, + { + "x": 199, + "y": -112, + "z": 0.5, + }, + { + "x": 202, + "y": -127, + "z": 0.5, + }, + { + "x": 203, + "y": -138, + "z": 0.5, + }, + { + "x": 203, + "y": -146, + "z": 0.5, + }, + { + "x": 201, + "y": -152, + "z": 0.5, + }, + { + "x": 196, + "y": -155, + "z": 0.5, + }, + { + "x": 191, + "y": -156, + "z": 0.5, + }, + { + "x": 186, + "y": -157, + "z": 0.5, + }, + { + "x": 178, + "y": -156, + "z": 0.5, + }, + { + "x": 170, + "y": -150, + "z": 0.5, + }, + { + "x": 164, + "y": -140, + "z": 0.5, + }, + { + "x": 158, + "y": -128, + "z": 0.5, + }, + { + "x": 151, + "y": -110, + "z": 0.5, + }, + { + "x": 144, + "y": -89, + "z": 0.5, + }, + { + "x": 139, + "y": -64, + "z": 0.5, + }, + { + "x": 135, + "y": -36, + "z": 0.5, + }, + { + "x": 132, + "y": -7, + "z": 0.5, + }, + { + "x": 132, + "y": 22, + "z": 0.5, + }, + { + "x": 132, + "y": 49, + "z": 0.5, + }, + { + "x": 133, + "y": 74, + "z": 0.5, + }, + { + "x": 140, + "y": 97, + "z": 0.5, + }, + { + "x": 148, + "y": 113, + "z": 0.5, + }, + { + "x": 156, + "y": 124, + "z": 0.5, + }, + { + "x": 166, + "y": 137, + "z": 0.5, + }, + { + "x": 175, + "y": 145, + "z": 0.5, + }, + { + "x": 183, + "y": 150, + "z": 0.5, + }, + { + "x": 191, + "y": 152, + "z": 0.5, + }, + { + "x": 197, + "y": 152, + "z": 0.5, + }, + { + "x": 205, + "y": 151, + "z": 0.5, + }, + { + "x": 214, + "y": 146, + "z": 0.5, + }, + { + "x": 223, + "y": 136, + "z": 0.5, + }, + { + "x": 230, + "y": 125, + "z": 0.5, + }, + { + "x": 236, + "y": 112, + "z": 0.5, + }, + { + "x": 242, + "y": 95, + "z": 0.5, + }, + { + "x": 247, + "y": 78, + "z": 0.5, + }, + { + "x": 250, + "y": 61, + "z": 0.5, + }, + { + "x": 252, + "y": 46, + "z": 0.5, + }, + { + "x": 253, + "y": 37, + "z": 0.5, + }, + { + "x": 253, + "y": 31, + "z": 0.5, + }, + { + "x": 253, + "y": 24, + "z": 0.5, + }, + { + "x": 251, + "y": 20, + "z": 0.5, + }, + { + "x": 248, + "y": 16, + "z": 0.5, + }, + { + "x": 246, + "y": 16, + "z": 0.5, + }, + { + "x": 243, + "y": 16, + "z": 0.5, + }, + { + "x": 240, + "y": 17, + "z": 0.5, + }, + { + "x": 238, + "y": 19, + "z": 0.5, + }, + { + "x": 236, + "y": 26, + "z": 0.5, + }, + { + "x": 234, + "y": 34, + "z": 0.5, + }, + { + "x": 233, + "y": 45, + "z": 0.5, + }, + { + "x": 232, + "y": 56, + "z": 0.5, + }, + { + "x": 232, + "y": 66, + "z": 0.5, + }, + { + "x": 235, + "y": 79, + "z": 0.5, + }, + { + "x": 241, + "y": 91, + "z": 0.5, + }, + { + "x": 247, + "y": 100, + "z": 0.5, + }, + { + "x": 255, + "y": 109, + "z": 0.5, + }, + { + "x": 260, + "y": 113, + "z": 0.5, + }, + { + "x": 266, + "y": 116, + "z": 0.5, + }, + { + "x": 274, + "y": 118, + "z": 0.5, + }, + { + "x": 280, + "y": 118, + "z": 0.5, + }, + { + "x": 286, + "y": 115, + "z": 0.5, + }, + { + "x": 291, + "y": 105, + "z": 0.5, + }, + { + "x": 296, + "y": 93, + "z": 0.5, + }, + { + "x": 298, + "y": 83, + "z": 0.5, + }, + { + "x": 301, + "y": 70, + "z": 0.5, + }, + { + "x": 303, + "y": 58, + "z": 0.5, + }, + { + "x": 305, + "y": 48, + "z": 0.5, + }, + { + "x": 306, + "y": 38, + "z": 0.5, + }, + { + "x": 307, + "y": 31, + "z": 0.5, + }, + { + "x": 308, + "y": 25, + "z": 0.5, + }, + { + "x": 308, + "y": 22, + "z": 0.5, + }, + { + "x": 308, + "y": 20, + "z": 0.5, + }, + { + "x": 308, + "y": 19, + "z": 0.5, + }, + { + "x": 308, + "y": 22, + "z": 0.5, + }, + { + "x": 308, + "y": 27, + "z": 0.5, + }, + { + "x": 308, + "y": 35, + "z": 0.5, + }, + { + "x": 308, + "y": 44, + "z": 0.5, + }, + { + "x": 308, + "y": 51, + "z": 0.5, + }, + { + "x": 308, + "y": 56, + "z": 0.5, + }, + { + "x": 308, + "y": 61, + "z": 0.5, + }, + { + "x": 309, + "y": 66, + "z": 0.5, + }, + { + "x": 312, + "y": 71, + "z": 0.5, + }, + { + "x": 314, + "y": 74, + "z": 0.5, + }, + { + "x": 317, + "y": 75, + "z": 0.5, + }, + { + "x": 320, + "y": 76, + "z": 0.5, + }, + { + "x": 324, + "y": 76, + "z": 0.5, + }, + { + "x": 329, + "y": 73, + "z": 0.5, + }, + { + "x": 333, + "y": 69, + "z": 0.5, + }, + { + "x": 336, + "y": 66, + "z": 0.5, + }, + { + "x": 339, + "y": 62, + "z": 0.5, + }, + { + "x": 342, + "y": 59, + "z": 0.5, + }, + { + "x": 344, + "y": 57, + "z": 0.5, + }, + { + "x": 346, + "y": 55, + "z": 0.5, + }, + { + "x": 348, + "y": 55, + "z": 0.5, + }, + { + "x": 348, + "y": 55, + "z": 0.5, + }, + { + "x": 349, + "y": 55, + "z": 0.5, + }, + { + "x": 349, + "y": 56, + "z": 0.5, + }, + { + "x": 350, + "y": 57, + "z": 0.5, + }, + { + "x": 351, + "y": 59, + "z": 0.5, + }, + { + "x": 351, + "y": 61, + "z": 0.5, + }, + { + "x": 352, + "y": 62, + "z": 0.5, + }, + { + "x": 352, + "y": 63, + "z": 0.5, + }, + { + "x": 353, + "y": 64, + "z": 0.5, + }, + { + "x": 354, + "y": 64, + "z": 0.5, + }, + { + "x": 355, + "y": 64, + "z": 0.5, + }, + { + "x": 356, + "y": 58, + "z": 0.5, + }, + { + "x": 358, + "y": 49, + "z": 0.5, + }, + { + "x": 360, + "y": 40, + "z": 0.5, + }, + { + "x": 363, + "y": 32, + "z": 0.5, + }, + { + "x": 365, + "y": 26, + "z": 0.5, + }, + { + "x": 367, + "y": 19, + "z": 0.5, + }, + { + "x": 369, + "y": 13, + "z": 0.5, + }, + { + "x": 373, + "y": 7, + "z": 0.5, + }, + { + "x": 376, + "y": 3, + "z": 0.5, + }, + { + "x": 380, + "y": 2, + "z": 0.5, + }, + { + "x": 385, + "y": 2, + "z": 0.5, + }, + { + "x": 390, + "y": 2, + "z": 0.5, + }, + { + "x": 397, + "y": 3, + "z": 0.5, + }, + { + "x": 410, + "y": 11, + "z": 0.5, + }, + { + "x": 424, + "y": 23, + "z": 0.5, + }, + { + "x": 434, + "y": 34, + "z": 0.5, + }, + { + "x": 446, + "y": 49, + "z": 0.5, + }, + { + "x": 456, + "y": 64, + "z": 0.5, + }, + { + "x": 464, + "y": 81, + "z": 0.5, + }, + { + "x": 468, + "y": 95, + "z": 0.5, + }, + { + "x": 470, + "y": 116, + "z": 0.5, + }, + { + "x": 472, + "y": 142, + "z": 0.5, + }, + { + "x": 472, + "y": 162, + "z": 0.5, + }, + { + "x": 468, + "y": 178, + "z": 0.5, + }, + { + "x": 458, + "y": 195, + "z": 0.5, + }, + { + "x": 442, + "y": 213, + "z": 0.5, + }, + { + "x": 423, + "y": 230, + "z": 0.5, + }, + { + "x": 407, + "y": 240, + "z": 0.5, + }, + { + "x": 393, + "y": 245, + "z": 0.5, + }, + { + "x": 377, + "y": 250, + "z": 0.5, + }, + { + "x": 364, + "y": 252, + "z": 0.5, + }, + { + "x": 354, + "y": 252, + "z": 0.5, + }, + { + "x": 346, + "y": 248, + "z": 0.5, + }, + { + "x": 340, + "y": 239, + "z": 0.5, + }, + { + "x": 339, + "y": 225, + "z": 0.5, + }, + { + "x": 339, + "y": 198, + "z": 0.5, + }, + { + "x": 349, + "y": 165, + "z": 0.5, + }, + { + "x": 372, + "y": 130, + "z": 0.5, + }, + { + "x": 403, + "y": 89, + "z": 0.5, + }, + { + "x": 432, + "y": 54, + "z": 0.5, + }, + { + "x": 467, + "y": 16, + "z": 0.5, + }, + { + "x": 504, + "y": -21, + "z": 0.5, + }, + { + "x": 551, + "y": -68, + "z": 0.5, + }, + { + "x": 597, + "y": -115, + "z": 0.5, + }, + { + "x": 619, + "y": -138, + "z": 0.5, + }, + { + "x": 641, + "y": -162, + "z": 0.5, + }, + { + "x": 663, + "y": -188, + "z": 0.5, + }, + { + "x": 675, + "y": -203, + "z": 0.5, + }, + { + "x": 684, + "y": -219, + "z": 0.5, + }, + { + "x": 692, + "y": -237, + "z": 0.5, + }, + { + "x": 693, + "y": -244, + "z": 0.5, + }, + { + "x": 691, + "y": -250, + "z": 0.5, + }, + { + "x": 682, + "y": -254, + "z": 0.5, + }, + { + "x": 664, + "y": -256, + "z": 0.5, + }, + { + "x": 642, + "y": -256, + "z": 0.5, + }, + { + "x": 621, + "y": -253, + "z": 0.5, + }, + { + "x": 589, + "y": -240, + "z": 0.5, + }, + { + "x": 554, + "y": -221, + "z": 0.5, + }, + { + "x": 526, + "y": -201, + "z": 0.5, + }, + { + "x": 502, + "y": -182, + "z": 0.5, + }, + { + "x": 484, + "y": -165, + "z": 0.5, + }, + { + "x": 467, + "y": -146, + "z": 0.5, + }, + { + "x": 456, + "y": -131, + "z": 0.5, + }, + { + "x": 450, + "y": -120, + "z": 0.5, + }, + { + "x": 448, + "y": -112, + "z": 0.5, + }, + { + "x": 448, + "y": -107, + "z": 0.5, + }, + { + "x": 449, + "y": -104, + "z": 0.5, + }, + { + "x": 452, + "y": -103, + "z": 0.5, + }, + { + "x": 458, + "y": -102, + "z": 0.5, + }, + { + "x": 462, + "y": -102, + "z": 0.5, + }, + { + "x": 465, + "y": -103, + "z": 0.5, + }, + { + "x": 470, + "y": -104, + "z": 0.5, + }, + { + "x": 472, + "y": -105, + "z": 0.5, + }, + { + "x": 474, + "y": -106, + "z": 0.5, + }, + { + "x": 475, + "y": -106, + "z": 0.5, + }, + { + "x": 476, + "y": -107, + "z": 0.5, + }, + { + "x": 476, + "y": -107, + "z": 0.5, + }, + { + "x": 477, + "y": -107, + "z": 0.5, + }, + ], + "type": "free", + }, + ], + "size": "m", + }, + "rotation": 0, + "type": "draw", + "typeName": "shape", + "x": 511, + "y": 234, +} +`; diff --git a/packages/tldraw/src/test/drawing.data.ts b/packages/tldraw/src/test/drawing.data.ts new file mode 100644 index 000000000..6345b6645 --- /dev/null +++ b/packages/tldraw/src/test/drawing.data.ts @@ -0,0 +1,1006 @@ +export const TEST_DRAW_SHAPE_SCREEN_POINTS = [ + { + x: 511, + y: 234, + }, + { + x: 512, + y: 234, + }, + { + x: 515, + y: 234, + }, + { + x: 521, + y: 233, + }, + { + x: 530, + y: 230, + }, + { + x: 541, + y: 224, + }, + { + x: 557, + y: 214, + }, + { + x: 572, + y: 204, + }, + { + x: 585, + y: 191, + }, + { + x: 600, + y: 175, + }, + { + x: 613, + y: 157, + }, + { + x: 619, + y: 144, + }, + { + x: 623, + y: 131, + }, + { + x: 628, + y: 115, + }, + { + x: 629, + y: 103, + }, + { + x: 630, + y: 97, + }, + { + x: 630, + y: 89, + }, + { + x: 631, + y: 82, + }, + { + x: 630, + y: 76, + }, + { + x: 628, + y: 71, + }, + { + x: 625, + y: 67, + }, + { + x: 620, + y: 65, + }, + { + x: 614, + y: 64, + }, + { + x: 608, + y: 64, + }, + { + x: 600, + y: 64, + }, + { + x: 591, + y: 68, + }, + { + x: 582, + y: 75, + }, + { + x: 573, + y: 84, + }, + { + x: 565, + y: 96, + }, + { + x: 561, + y: 108, + }, + { + x: 558, + y: 121, + }, + { + x: 557, + y: 135, + }, + { + x: 557, + y: 152, + }, + { + x: 558, + y: 173, + }, + { + x: 564, + y: 193, + }, + { + x: 571, + y: 210, + }, + { + x: 579, + y: 227, + }, + { + x: 590, + y: 246, + }, + { + x: 599, + y: 266, + }, + { + x: 607, + y: 284, + }, + { + x: 614, + y: 303, + }, + { + x: 617, + y: 320, + }, + { + x: 618, + y: 336, + }, + { + x: 618, + y: 354, + }, + { + x: 613, + y: 370, + }, + { + x: 601, + y: 380, + }, + { + x: 585, + y: 388, + }, + { + x: 554, + y: 397, + }, + { + x: 543, + y: 398, + }, + { + x: 532, + y: 398, + }, + { + x: 522, + y: 398, + }, + { + x: 513, + y: 398, + }, + { + x: 504, + y: 396, + }, + { + x: 498, + y: 393, + }, + { + x: 496, + y: 387, + }, + { + x: 496, + y: 381, + }, + { + x: 500, + y: 372, + }, + { + x: 512, + y: 361, + }, + { + x: 526, + y: 346, + }, + { + x: 545, + y: 330, + }, + { + x: 567, + y: 313, + }, + { + x: 592, + y: 292, + }, + { + x: 618, + y: 267, + }, + { + x: 637, + y: 246, + }, + { + x: 656, + y: 224, + }, + { + x: 671, + y: 204, + }, + { + x: 683, + y: 184, + }, + { + x: 696, + y: 161, + }, + { + x: 705, + y: 141, + }, + { + x: 710, + y: 122, + }, + { + x: 713, + y: 107, + }, + { + x: 714, + y: 96, + }, + { + x: 714, + y: 88, + }, + { + x: 712, + y: 82, + }, + { + x: 707, + y: 79, + }, + { + x: 702, + y: 78, + }, + { + x: 697, + y: 77, + }, + { + x: 689, + y: 78, + }, + { + x: 681, + y: 84, + }, + { + x: 675, + y: 94, + }, + { + x: 669, + y: 106, + }, + { + x: 662, + y: 124, + }, + { + x: 655, + y: 145, + }, + { + x: 650, + y: 170, + }, + { + x: 646, + y: 198, + }, + { + x: 643, + y: 227, + }, + { + x: 643, + y: 256, + }, + { + x: 643, + y: 283, + }, + { + x: 644, + y: 308, + }, + { + x: 651, + y: 331, + }, + { + x: 659, + y: 347, + }, + { + x: 667, + y: 358, + }, + { + x: 677, + y: 371, + }, + { + x: 686, + y: 379, + }, + { + x: 694, + y: 384, + }, + { + x: 702, + y: 386, + }, + { + x: 708, + y: 386, + }, + { + x: 716, + y: 385, + }, + { + x: 725, + y: 380, + }, + { + x: 734, + y: 370, + }, + { + x: 741, + y: 359, + }, + { + x: 747, + y: 346, + }, + { + x: 753, + y: 329, + }, + { + x: 758, + y: 312, + }, + { + x: 761, + y: 295, + }, + { + x: 763, + y: 280, + }, + { + x: 764, + y: 271, + }, + { + x: 764, + y: 265, + }, + { + x: 764, + y: 258, + }, + { + x: 762, + y: 254, + }, + { + x: 759, + y: 250, + }, + { + x: 757, + y: 250, + }, + { + x: 754, + y: 250, + }, + { + x: 751, + y: 251, + }, + { + x: 749, + y: 253, + }, + { + x: 747, + y: 260, + }, + { + x: 745, + y: 268, + }, + { + x: 744, + y: 279, + }, + { + x: 743, + y: 290, + }, + { + x: 743, + y: 300, + }, + { + x: 746, + y: 313, + }, + { + x: 752, + y: 325, + }, + { + x: 758, + y: 334, + }, + { + x: 766, + y: 343, + }, + { + x: 771, + y: 347, + }, + { + x: 777, + y: 350, + }, + { + x: 785, + y: 352, + }, + { + x: 791, + y: 352, + }, + { + x: 797, + y: 349, + }, + { + x: 802, + y: 339, + }, + { + x: 807, + y: 327, + }, + { + x: 809, + y: 317, + }, + { + x: 812, + y: 304, + }, + { + x: 814, + y: 292, + }, + { + x: 816, + y: 282, + }, + { + x: 817, + y: 272, + }, + { + x: 818, + y: 265, + }, + { + x: 819, + y: 259, + }, + { + x: 819, + y: 256, + }, + { + x: 819, + y: 254, + }, + { + x: 819, + y: 253, + }, + { + x: 819, + y: 256, + }, + { + x: 819, + y: 261, + }, + { + x: 819, + y: 269, + }, + { + x: 819, + y: 278, + }, + { + x: 819, + y: 285, + }, + { + x: 819, + y: 290, + }, + { + x: 819, + y: 295, + }, + { + x: 820, + y: 300, + }, + { + x: 823, + y: 305, + }, + { + x: 825, + y: 308, + }, + { + x: 828, + y: 309, + }, + { + x: 831, + y: 310, + }, + { + x: 835, + y: 310, + }, + { + x: 840, + y: 307, + }, + { + x: 844, + y: 303, + }, + { + x: 847, + y: 300, + }, + { + x: 850, + y: 296, + }, + { + x: 853, + y: 293, + }, + { + x: 855, + y: 291, + }, + { + x: 857, + y: 289, + }, + { + x: 859, + y: 289, + }, + { + x: 859, + y: 289, + }, + { + x: 860, + y: 289, + }, + { + x: 860, + y: 290, + }, + { + x: 861, + y: 291, + }, + { + x: 862, + y: 293, + }, + { + x: 862, + y: 295, + }, + { + x: 863, + y: 296, + }, + { + x: 863, + y: 297, + }, + { + x: 864, + y: 298, + }, + { + x: 865, + y: 298, + }, + { + x: 866, + y: 298, + }, + { + x: 867, + y: 292, + }, + { + x: 869, + y: 283, + }, + { + x: 871, + y: 274, + }, + { + x: 874, + y: 266, + }, + { + x: 876, + y: 260, + }, + { + x: 878, + y: 253, + }, + { + x: 880, + y: 247, + }, + { + x: 884, + y: 241, + }, + { + x: 887, + y: 237, + }, + { + x: 891, + y: 236, + }, + { + x: 896, + y: 236, + }, + { + x: 901, + y: 236, + }, + { + x: 908, + y: 237, + }, + { + x: 921, + y: 245, + }, + { + x: 935, + y: 257, + }, + { + x: 945, + y: 268, + }, + { + x: 957, + y: 283, + }, + { + x: 967, + y: 298, + }, + { + x: 975, + y: 315, + }, + { + x: 979, + y: 329, + }, + { + x: 981, + y: 350, + }, + { + x: 983, + y: 376, + }, + { + x: 983, + y: 396, + }, + { + x: 979, + y: 412, + }, + { + x: 969, + y: 429, + }, + { + x: 953, + y: 447, + }, + { + x: 934, + y: 464, + }, + { + x: 918, + y: 474, + }, + { + x: 904, + y: 479, + }, + { + x: 888, + y: 484, + }, + { + x: 875, + y: 486, + }, + { + x: 865, + y: 486, + }, + { + x: 857, + y: 482, + }, + { + x: 851, + y: 473, + }, + { + x: 850, + y: 459, + }, + { + x: 850, + y: 432, + }, + { + x: 860, + y: 399, + }, + { + x: 883, + y: 364, + }, + { + x: 914, + y: 323, + }, + { + x: 943, + y: 288, + }, + { + x: 978, + y: 250, + }, + { + x: 1015, + y: 213, + }, + { + x: 1062, + y: 166, + }, + { + x: 1108, + y: 119, + }, + { + x: 1130, + y: 96, + }, + { + x: 1152, + y: 72, + }, + { + x: 1174, + y: 46, + }, + { + x: 1186, + y: 31, + }, + { + x: 1195, + y: 15, + }, + { + x: 1203, + y: -3, + }, + { + x: 1204, + y: -10, + }, + { + x: 1202, + y: -16, + }, + { + x: 1193, + y: -20, + }, + { + x: 1175, + y: -22, + }, + { + x: 1153, + y: -22, + }, + { + x: 1132, + y: -19, + }, + { + x: 1100, + y: -6, + }, + { + x: 1065, + y: 13, + }, + { + x: 1037, + y: 33, + }, + { + x: 1013, + y: 52, + }, + { + x: 995, + y: 69, + }, + { + x: 978, + y: 88, + }, + { + x: 967, + y: 103, + }, + { + x: 961, + y: 114, + }, + { + x: 959, + y: 122, + }, + { + x: 959, + y: 127, + }, + { + x: 960, + y: 130, + }, + { + x: 963, + y: 131, + }, + { + x: 969, + y: 132, + }, + { + x: 973, + y: 132, + }, + { + x: 976, + y: 131, + }, + { + x: 981, + y: 130, + }, + { + x: 983, + y: 129, + }, + { + x: 985, + y: 128, + }, + { + x: 986, + y: 128, + }, + { + x: 987, + y: 127, + }, + { + x: 987, + y: 127, + }, + { + x: 988, + y: 127, + }, +] diff --git a/packages/tldraw/src/test/drawing.test.ts b/packages/tldraw/src/test/drawing.test.ts index eb96dcecb..c2041cf95 100644 --- a/packages/tldraw/src/test/drawing.test.ts +++ b/packages/tldraw/src/test/drawing.test.ts @@ -1,5 +1,6 @@ import { TLDrawShape, TLHighlightShape, last } from '@tldraw/editor' import { TestEditor } from './TestEditor' +import { TEST_DRAW_SHAPE_SCREEN_POINTS } from './drawing.data' jest.useFakeTimers() @@ -260,3 +261,22 @@ for (const toolType of ['draw', 'highlight'] as const) { }) }) } + +it('Draws a bunch', () => { + editor.setCurrentTool('draw').setCamera({ x: 0, y: 0, z: 1 }) + + const [first, ...rest] = TEST_DRAW_SHAPE_SCREEN_POINTS + editor.pointerMove(first.x, first.y).pointerDown() + + for (const point of rest) { + editor.pointerMove(point.x, point.y) + } + + editor.pointerUp() + editor.selectAll() + + const shape = { ...editor.getLastCreatedShape() } + // @ts-expect-error + delete shape.id + expect(shape).toMatchSnapshot('draw shape') +}) diff --git a/packages/utils/src/lib/perf.ts b/packages/utils/src/lib/perf.ts index e6ac86450..2f9283fd9 100644 --- a/packages/utils/src/lib/perf.ts +++ b/packages/utils/src/lib/perf.ts @@ -34,15 +34,17 @@ export function measureAverageDuration( const start = performance.now() const result = originalMethod.apply(this, args) const end = performance.now() - const value = averages.get(descriptor.value)! const length = end - start - const total = value.total + length - const count = value.count + 1 - averages.set(descriptor.value, { total, count }) - // eslint-disable-next-line no-console - console.log( - `${propertyKey} took ${(end - start).toFixed(2)}ms | average ${(total / count).toFixed(2)}ms` - ) + if (length !== 0) { + const value = averages.get(descriptor.value)! + const total = value.total + length + const count = value.count + 1 + averages.set(descriptor.value, { total, count }) + // eslint-disable-next-line no-console + console.log( + `${propertyKey} took ${(end - start).toFixed(2)}ms | average ${(total / count).toFixed(2)}ms` + ) + } return result } averages.set(descriptor.value, { total: 0, count: 0 })