diff --git a/lib/constants.ts b/lib/constants.ts new file mode 100644 index 0000000..1a001d0 --- /dev/null +++ b/lib/constants.ts @@ -0,0 +1,2 @@ +export const FONT_SIZE_WIDTH_RATIO = 0.6 +export const FONT_SIZE_HEIGHT_RATIO = 1 diff --git a/lib/drawGraphicsToCanvas.ts b/lib/drawGraphicsToCanvas.ts index 628837b..82896a4 100644 --- a/lib/drawGraphicsToCanvas.ts +++ b/lib/drawGraphicsToCanvas.ts @@ -12,6 +12,7 @@ import type { TransformOptions, } from "./types" import { defaultColors } from "site/components/InteractiveGraphics/defaultColors" +import { FONT_SIZE_WIDTH_RATIO, FONT_SIZE_HEIGHT_RATIO } from "./constants" /** * Computes a transformation matrix based on a provided viewbox @@ -79,7 +80,30 @@ export function getBounds(graphics: GraphicsObject): Viewbox { { x: circle.center.x, y: circle.center.y - circle.radius }, // top { x: circle.center.x, y: circle.center.y + circle.radius }, // bottom ]), - ...(graphics.texts || []).map((text) => ({ x: text.x, y: text.y })), + ...(graphics.texts || []).flatMap((text) => { + const fontSize = text.fontSize ?? 12 + const width = text.text.length * fontSize * FONT_SIZE_WIDTH_RATIO + const height = fontSize * FONT_SIZE_HEIGHT_RATIO + const anchor = text.anchorSide ?? "center" + const offsetMap: Record = { + top_left: { dx: 0, dy: 0 }, + top_center: { dx: -width / 2, dy: 0 }, + top_right: { dx: -width, dy: 0 }, + center_left: { dx: 0, dy: -height / 2 }, + center: { dx: -width / 2, dy: -height / 2 }, + center_right: { dx: -width, dy: -height / 2 }, + bottom_left: { dx: 0, dy: -height }, + bottom_center: { dx: -width / 2, dy: -height }, + bottom_right: { dx: -width, dy: -height }, + } + const { dx, dy } = offsetMap[anchor] + const x0 = text.x + dx + const y0 = text.y + dy + return [ + { x: x0, y: y0 }, + { x: x0 + width, y: y0 + height }, + ] + }), ] if (points.length === 0) { @@ -296,7 +320,7 @@ export function drawGraphicsToCanvas( graphics.texts.forEach((text) => { const projected = applyToPoint(matrix, { x: text.x, y: text.y }) ctx.fillStyle = text.color || "black" - ctx.font = `${text.fontSize ?? 12}px sans-serif` + ctx.font = `${(text.fontSize ?? 12) * Math.abs(matrix.a)}px sans-serif` const anchor = text.anchorSide ?? "center" const alignMap: Record = { diff --git a/lib/getSvgFromGraphicsObject.ts b/lib/getSvgFromGraphicsObject.ts index d0b94eb..826738f 100644 --- a/lib/getSvgFromGraphicsObject.ts +++ b/lib/getSvgFromGraphicsObject.ts @@ -10,6 +10,7 @@ import { import type { GraphicsObject, Point } from "./types" import { stringify } from "svgson" import pretty from "pretty" +import { FONT_SIZE_WIDTH_RATIO, FONT_SIZE_HEIGHT_RATIO } from "./constants" const DEFAULT_SVG_SIZE = 640 const PADDING = 40 @@ -41,7 +42,30 @@ function getBounds(graphics: GraphicsObject): Bounds { { x: circle.center.x, y: circle.center.y - circle.radius }, // top { x: circle.center.x, y: circle.center.y + circle.radius }, // bottom ]), - ...(graphics.texts || []).map((t) => ({ x: t.x, y: t.y })), + ...(graphics.texts || []).flatMap((t) => { + const fontSize = t.fontSize ?? 12 + const width = t.text.length * fontSize * FONT_SIZE_WIDTH_RATIO + const height = fontSize * FONT_SIZE_HEIGHT_RATIO + const anchor = t.anchorSide ?? "center" + const offsetMap: Record = { + top_left: { dx: 0, dy: 0 }, + top_center: { dx: -width / 2, dy: 0 }, + top_right: { dx: -width, dy: 0 }, + center_left: { dx: 0, dy: -height / 2 }, + center: { dx: -width / 2, dy: -height / 2 }, + center_right: { dx: -width, dy: -height / 2 }, + bottom_left: { dx: 0, dy: -height }, + bottom_center: { dx: -width / 2, dy: -height }, + bottom_right: { dx: -width, dy: -height }, + } + const { dx, dy } = offsetMap[anchor] + const x0 = t.x + dx + const y0 = t.y + dy + return [ + { x: x0, y: y0 }, + { x: x0 + width, y: y0 + height }, + ] + }), ] if (points.length === 0) { @@ -337,7 +361,7 @@ export function getSvgFromGraphicsObject( x: projected.x.toString(), y: projected.y.toString(), fill: txt.color || "black", - "font-size": (txt.fontSize ?? 12).toString(), + "font-size": ((txt.fontSize ?? 12) * Math.abs(matrix.a)).toString(), "font-family": "sans-serif", "text-anchor": alignMap[anchor], "dominant-baseline": baselineMap[anchor], diff --git a/lib/index.ts b/lib/index.ts index 28925df..c5613b3 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -29,6 +29,7 @@ export { } from "./drawGraphicsToCanvas" export { translateGraphics } from "./translateGraphics" export { mergeGraphics } from "./mergeGraphics" +export { FONT_SIZE_WIDTH_RATIO, FONT_SIZE_HEIGHT_RATIO } from "./constants" export function getSvgFromLogString(logString: string): string { const objects = getGraphicsObjectsFromLogString(logString) diff --git a/tests/SVGRenderer.test.tsx b/tests/SVGRenderer.test.tsx index f9536a2..5216b15 100644 --- a/tests/SVGRenderer.test.tsx +++ b/tests/SVGRenderer.test.tsx @@ -56,7 +56,7 @@ describe("SVGRenderer", () => { document.body.removeChild(container) throw error } - }, 0) + }, 50) }) }) }) diff --git a/tests/__snapshots__/texts.snap.svg b/tests/__snapshots__/texts.snap.svg index dc58b2b..afa565e 100644 --- a/tests/__snapshots__/texts.snap.svg +++ b/tests/__snapshots__/texts.snap.svg @@ -1,4 +1,4 @@ -Hello +Hello