From bcb1ff4529708ed2b34e66eafc745f4918f297da Mon Sep 17 00:00:00 2001 From: seveibar Date: Wed, 12 Aug 2026 11:17:40 -0700 Subject: [PATCH 1/2] Add line join SVG repro --- ...ine-joins.snapshot-acute-polyline.snap.svg | 44 +++++++++++++++++++ tests/line-joins.snapshot.test.ts | 26 +++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg create mode 100644 tests/line-joins.snapshot.test.ts diff --git a/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg b/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg new file mode 100644 index 0000000..9d6a70f --- /dev/null +++ b/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg @@ -0,0 +1,44 @@ + diff --git a/tests/line-joins.snapshot.test.ts b/tests/line-joins.snapshot.test.ts new file mode 100644 index 0000000..9af8dff --- /dev/null +++ b/tests/line-joins.snapshot.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from "bun:test" +import { getSvgFromGraphicsObject } from "../lib/getSvgFromGraphicsObject" +import type { GraphicsObject } from "../lib/types" + +test("renders the join of a thick, acute polyline", () => { + const input: GraphicsObject = { + lines: [ + { + points: [ + { x: -1.5, y: 2 }, + { x: 0, y: -2 }, + { x: 1.5, y: 2 }, + ], + strokeColor: "#2563eb", + strokeWidth: 0.8, + }, + ], + } + + const svg = getSvgFromGraphicsObject(input, { + svgWidth: 320, + svgHeight: 240, + }) + + expect(svg).toMatchSvgSnapshot(import.meta.path, "acute-polyline") +}) From bde3d88fce685a0da5ac822649621e99e9349672 Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Wed, 12 Aug 2026 11:39:23 -0700 Subject: [PATCH 2/2] Render lines with round joins (#229) --- lib/drawGraphicsToCanvas.ts | 1 + lib/getPngBufferFromGraphicsObject.ts | 1 + lib/getSvgFromGraphicsObject.ts | 1 + .../line-joins.snapshot-acute-polyline.snap.svg | 2 +- tests/getSvgFromGraphicsObject.test.ts | 9 ++++++++- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/drawGraphicsToCanvas.ts b/lib/drawGraphicsToCanvas.ts index 8c2bd45..ba565cb 100644 --- a/lib/drawGraphicsToCanvas.ts +++ b/lib/drawGraphicsToCanvas.ts @@ -383,6 +383,7 @@ export function drawGraphicsToCanvas( ctx.lineWidth = 2 } ctx.lineCap = "round" + ctx.lineJoin = "round" if (line.strokeDash) { if (typeof line.strokeDash === "string") { diff --git a/lib/getPngBufferFromGraphicsObject.ts b/lib/getPngBufferFromGraphicsObject.ts index 724ba1a..5328be2 100644 --- a/lib/getPngBufferFromGraphicsObject.ts +++ b/lib/getPngBufferFromGraphicsObject.ts @@ -234,6 +234,7 @@ export async function getPngBufferFromGraphicsObject( line.strokeWidth === undefined ? 1 : Math.max(line.strokeWidth * strokeScale, 1) + ctx.lineJoin = "round" strokePolyline(ctx, projectedPoints, dashPattern) if ( diff --git a/lib/getSvgFromGraphicsObject.ts b/lib/getSvgFromGraphicsObject.ts index 20aed0f..331e38c 100644 --- a/lib/getSvgFromGraphicsObject.ts +++ b/lib/getSvgFromGraphicsObject.ts @@ -234,6 +234,7 @@ export function getSvgFromGraphicsObject( points: projectedPoints.map((p) => `${p.x},${p.y}`).join(" "), fill: "none", stroke: line.strokeColor || "black", + "stroke-linejoin": "round", "stroke-width": !line.strokeWidth ? "1px" : typeof line.strokeWidth === "string" diff --git a/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg b/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg index 9d6a70f..5b7b1bd 100644 --- a/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg +++ b/tests/__snapshots__/line-joins.snapshot-acute-polyline.snap.svg @@ -1,4 +1,4 @@ -