From 4ba48ee7d3a2f550168e0b590cfc373514c9d35c Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Fri, 14 Nov 2025 18:11:15 -0800 Subject: [PATCH 1/2] Scale line stroke width in SVG snapshots --- lib/getSvgFromGraphicsObject.ts | 9 ++-- .../getSvgFromGraphicsObject-lines.snap.svg | 44 +++++++++++++++++++ tests/getSvgFromGraphicsObject.test.ts | 22 +++++++--- 3 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 tests/__snapshots__/getSvgFromGraphicsObject-lines.snap.svg diff --git a/lib/getSvgFromGraphicsObject.ts b/lib/getSvgFromGraphicsObject.ts index bf20088..d864323 100644 --- a/lib/getSvgFromGraphicsObject.ts +++ b/lib/getSvgFromGraphicsObject.ts @@ -139,10 +139,9 @@ export function getSvgFromGraphicsObject( svgWidth, svgHeight, ) + const strokeScale = Math.hypot(matrix.a, matrix.b) - const shouldRenderLabel = ( - type: "points" | "lines" | "rects", - ): boolean => { + const shouldRenderLabel = (type: "points" | "lines" | "rects"): boolean => { if (typeof includeTextLabels === "boolean") { return includeTextLabels } @@ -236,7 +235,9 @@ export function getSvgFromGraphicsObject( points: projectedPoints.map((p) => `${p.x},${p.y}`).join(" "), fill: "none", stroke: line.strokeColor || "black", - "stroke-width": (line.strokeWidth ?? 1).toString(), + "stroke-width": ( + strokeScale * (line.strokeWidth ?? 1) + ).toString(), ...(line.strokeDash && { "stroke-dasharray": Array.isArray(line.strokeDash) ? line.strokeDash.join(" ") diff --git a/tests/__snapshots__/getSvgFromGraphicsObject-lines.snap.svg b/tests/__snapshots__/getSvgFromGraphicsObject-lines.snap.svg new file mode 100644 index 0000000..df0c534 --- /dev/null +++ b/tests/__snapshots__/getSvgFromGraphicsObject-lines.snap.svg @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/tests/getSvgFromGraphicsObject.test.ts b/tests/getSvgFromGraphicsObject.test.ts index b1a2577..925fe50 100644 --- a/tests/getSvgFromGraphicsObject.test.ts +++ b/tests/getSvgFromGraphicsObject.test.ts @@ -42,29 +42,37 @@ describe("getSvgFromGraphicsObject", () => { { points: [ { x: 0, y: 0 }, - { x: 1, y: 1 }, + { x: 10, y: 10 }, ], strokeWidth: 2, strokeColor: "blue", }, { points: [ - { x: 1, y: 0 }, - { x: 0, y: 1 }, + { x: 10, y: 0 }, + { x: 0, y: 10 }, ], // Test default values when properties are not specified }, ], } - const svg = getSvgFromGraphicsObject(input) + const svg = getSvgFromGraphicsObject(input, { + svgWidth: 200, + svgHeight: 200, + }) expect(svg).toBeString() expect(svg).toContain("]*stroke-width="([0-9.]+)"/g), + ).map(([, value]) => parseFloat(value)) + expect(strokeWidths).toHaveLength(2) + expect(strokeWidths[0]).toBeCloseTo(24) + expect(strokeWidths[1]).toBeCloseTo(12) + // Test default color expect(svg).toContain('stroke="black"') expect(svg).toMatchSvgSnapshot(import.meta.path, "lines") }) From a3ab3f10d9758cbe8c17b5a4ef755cc616fb59e4 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 14 Nov 2025 18:16:42 -0800 Subject: [PATCH 2/2] edge case handling --- lib/getSvgFromGraphicsObject.ts | 9 +++++---- site/components/InteractiveGraphics/Arrow.tsx | 14 +++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/getSvgFromGraphicsObject.ts b/lib/getSvgFromGraphicsObject.ts index d864323..a2f756e 100644 --- a/lib/getSvgFromGraphicsObject.ts +++ b/lib/getSvgFromGraphicsObject.ts @@ -139,7 +139,7 @@ export function getSvgFromGraphicsObject( svgWidth, svgHeight, ) - const strokeScale = Math.hypot(matrix.a, matrix.b) + const strokeScale = Math.abs(matrix.a) const shouldRenderLabel = (type: "points" | "lines" | "rects"): boolean => { if (typeof includeTextLabels === "boolean") { @@ -235,9 +235,10 @@ export function getSvgFromGraphicsObject( points: projectedPoints.map((p) => `${p.x},${p.y}`).join(" "), fill: "none", stroke: line.strokeColor || "black", - "stroke-width": ( - strokeScale * (line.strokeWidth ?? 1) - ).toString(), + "stroke-width": + typeof line.strokeWidth === "string" + ? line.strokeWidth + : (strokeScale * (line.strokeWidth ?? 1)).toString(), ...(line.strokeDash && { "stroke-dasharray": Array.isArray(line.strokeDash) ? line.strokeDash.join(" ") diff --git a/site/components/InteractiveGraphics/Arrow.tsx b/site/components/InteractiveGraphics/Arrow.tsx index 928043b..af8b544 100644 --- a/site/components/InteractiveGraphics/Arrow.tsx +++ b/site/components/InteractiveGraphics/Arrow.tsx @@ -34,10 +34,7 @@ export const Arrow = ({ } }, [geometry, realToScreen]) - const scaleFactor = useMemo(() => Math.hypot(realToScreen.a, realToScreen.b), [ - realToScreen.a, - realToScreen.b, - ]) + const scaleFactor = Math.abs(realToScreen.a) const baseColor = arrow.color || defaultColors[index % defaultColors.length] || "black" @@ -62,7 +59,14 @@ export const Arrow = ({ ] const isNear = segments.some(({ from, to }) => { - const distance = distToLineSegment(mouseX, mouseY, from.x, from.y, to.x, to.y) + const distance = distToLineSegment( + mouseX, + mouseY, + from.x, + from.y, + to.x, + to.y, + ) return distance < hoverThreshold })