circuit-to-canvas 0.0.53 → 0.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -253,12 +253,26 @@ interface DrawDimensionLineParams {
253
253
  }
254
254
  declare function drawDimensionLine(params: DrawDimensionLineParams): void;
255
255
 
256
+ type AlphabetLayout = {
257
+ width: number;
258
+ height: number;
259
+ glyphWidth: number;
260
+ letterSpacing: number;
261
+ spaceWidth: number;
262
+ strokeWidth: number;
263
+ lineHeight: number;
264
+ lines: string[];
265
+ lineWidths: number[];
266
+ };
267
+ declare function getAlphabetLayout(text: string, fontSize: number): AlphabetLayout;
268
+
256
269
  interface StrokeAlphabetTextParams {
257
270
  ctx: CanvasContext;
258
271
  text: string;
259
272
  fontSize: number;
260
273
  startX: number;
261
274
  startY: number;
275
+ anchorAlignment?: NinePointAnchor;
262
276
  }
263
277
  declare function strokeAlphabetText(params: StrokeAlphabetTextParams): void;
264
278
  interface DrawTextParams {
@@ -274,16 +288,6 @@ interface DrawTextParams {
274
288
  }
275
289
  declare function drawText(params: DrawTextParams): void;
276
290
 
277
- type AlphabetLayout = {
278
- width: number;
279
- height: number;
280
- glyphWidth: number;
281
- letterSpacing: number;
282
- spaceWidth: number;
283
- strokeWidth: number;
284
- };
285
- declare function getAlphabetLayout(text: string, fontSize: number): AlphabetLayout;
286
-
287
291
  type AnchorAlignment = NinePointAnchor;
288
292
  declare function getTextStartPosition(alignment: NinePointAnchor, layout: AlphabetLayout): {
289
293
  x: number;
package/dist/index.js CHANGED
@@ -400,25 +400,38 @@ var GLYPH_WIDTH_RATIO = 0.62;
400
400
  var LETTER_SPACING_RATIO = 0.3;
401
401
  var SPACE_WIDTH_RATIO = 1;
402
402
  var STROKE_WIDTH_RATIO = 0.13;
403
+ var LINE_HEIGHT_RATIO = 1.2;
403
404
  function getAlphabetLayout(text, fontSize) {
404
405
  const glyphWidth = fontSize * GLYPH_WIDTH_RATIO;
405
406
  const letterSpacing = glyphWidth * LETTER_SPACING_RATIO;
406
407
  const spaceWidth = glyphWidth * SPACE_WIDTH_RATIO;
407
- const characters = Array.from(text);
408
- let width = 0;
409
- characters.forEach((char, index) => {
410
- const advance = char === " " ? spaceWidth : glyphWidth;
411
- width += advance;
412
- if (index < characters.length - 1) width += letterSpacing;
413
- });
414
408
  const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35);
409
+ const lineHeight = fontSize * LINE_HEIGHT_RATIO;
410
+ const lines = text.split("\n");
411
+ const lineWidths = [];
412
+ let maxWidth = 0;
413
+ for (const line of lines) {
414
+ const characters = Array.from(line);
415
+ let lineWidth = 0;
416
+ characters.forEach((char, index) => {
417
+ const advance = char === " " ? spaceWidth : glyphWidth;
418
+ lineWidth += advance;
419
+ if (index < characters.length - 1) lineWidth += letterSpacing;
420
+ });
421
+ lineWidths.push(lineWidth);
422
+ if (lineWidth > maxWidth) maxWidth = lineWidth;
423
+ }
424
+ const totalHeight = lines.length > 1 ? fontSize + (lines.length - 1) * lineHeight : fontSize;
415
425
  return {
416
- width,
417
- height: fontSize,
426
+ width: maxWidth,
427
+ height: totalHeight,
418
428
  glyphWidth,
419
429
  letterSpacing,
420
430
  spaceWidth,
421
- strokeWidth
431
+ strokeWidth,
432
+ lineHeight,
433
+ lines,
434
+ lineWidths
422
435
  };
423
436
  }
424
437
 
@@ -434,6 +447,8 @@ function getTextStartPosition(alignment, layout) {
434
447
  x = 0;
435
448
  } else if (alignment === "top_right" || alignment === "bottom_right" || alignment === "center_right") {
436
449
  x = -totalWidth;
450
+ } else if (alignment === "top_center" || alignment === "bottom_center") {
451
+ x = -totalWidth / 2;
437
452
  }
438
453
  if (alignment === "center" || alignment === "center_left" || alignment === "center_right") {
439
454
  y = -totalHeight / 2;
@@ -444,26 +459,38 @@ function getTextStartPosition(alignment, layout) {
444
459
  }
445
460
  return { x, y };
446
461
  }
462
+ function getLineStartX(params) {
463
+ const { alignment, lineWidth, maxWidth, strokeWidth } = params;
464
+ const totalLineWidth = lineWidth + strokeWidth;
465
+ const totalMaxWidth = maxWidth + strokeWidth;
466
+ if (alignment === "top_left" || alignment === "bottom_left" || alignment === "center_left") {
467
+ return 0;
468
+ }
469
+ if (alignment === "top_right" || alignment === "bottom_right" || alignment === "center_right") {
470
+ return totalMaxWidth - totalLineWidth;
471
+ }
472
+ return (totalMaxWidth - totalLineWidth) / 2;
473
+ }
447
474
 
448
475
  // lib/drawer/shapes/text/text.ts
449
476
  var getGlyphLines = (char) => lineAlphabet[char] ?? lineAlphabet[char.toUpperCase()];
450
- function strokeAlphabetText(params) {
451
- const { ctx, text, fontSize, startX, startY } = params;
452
- const layout = getAlphabetLayout(text, fontSize);
453
- const { glyphWidth, letterSpacing, spaceWidth, height, strokeWidth } = layout;
477
+ function strokeAlphabetLine(params) {
478
+ const { ctx, line, fontSize, startX, startY, layout } = params;
479
+ const { glyphWidth, letterSpacing, spaceWidth, strokeWidth } = layout;
480
+ const height = fontSize;
454
481
  const topY = startY;
455
- const characters = Array.from(text);
482
+ const characters = Array.from(line);
456
483
  let cursor = startX + strokeWidth / 2;
457
484
  characters.forEach((char, index) => {
458
- const lines = getGlyphLines(char);
485
+ const glyphLines = getGlyphLines(char);
459
486
  const advance = char === " " ? spaceWidth : glyphWidth;
460
- if (lines?.length) {
487
+ if (glyphLines?.length) {
461
488
  ctx.beginPath();
462
- for (const line of lines) {
463
- const x1 = cursor + line.x1 * glyphWidth;
464
- const y1 = topY + (1 - line.y1) * height;
465
- const x2 = cursor + line.x2 * glyphWidth;
466
- const y2 = topY + (1 - line.y2) * height;
489
+ for (const glyph of glyphLines) {
490
+ const x1 = cursor + glyph.x1 * glyphWidth;
491
+ const y1 = topY + (1 - glyph.y1) * height;
492
+ const x2 = cursor + glyph.x2 * glyphWidth;
493
+ const y2 = topY + (1 - glyph.y2) * height;
467
494
  ctx.moveTo(x1, y1);
468
495
  ctx.lineTo(x2, y2);
469
496
  }
@@ -475,6 +502,35 @@ function strokeAlphabetText(params) {
475
502
  }
476
503
  });
477
504
  }
505
+ function strokeAlphabetText(params) {
506
+ const {
507
+ ctx,
508
+ text,
509
+ fontSize,
510
+ startX,
511
+ startY,
512
+ anchorAlignment = "center"
513
+ } = params;
514
+ const layout = getAlphabetLayout(text, fontSize);
515
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout;
516
+ lines.forEach((line, lineIndex) => {
517
+ const lineStartX = startX + getLineStartX({
518
+ alignment: anchorAlignment,
519
+ lineWidth: lineWidths[lineIndex],
520
+ maxWidth: width,
521
+ strokeWidth
522
+ });
523
+ const lineStartY = startY + lineIndex * lineHeight;
524
+ strokeAlphabetLine({
525
+ ctx,
526
+ line,
527
+ fontSize,
528
+ startX: lineStartX,
529
+ startY: lineStartY,
530
+ layout
531
+ });
532
+ });
533
+ }
478
534
  function drawText(params) {
479
535
  const {
480
536
  ctx,
@@ -502,12 +558,23 @@ function drawText(params) {
502
558
  ctx.lineCap = "round";
503
559
  ctx.lineJoin = "round";
504
560
  ctx.strokeStyle = color;
505
- strokeAlphabetText({
506
- ctx,
507
- text,
508
- fontSize: scaledFontSize,
509
- startX: startPos.x,
510
- startY: startPos.y
561
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout;
562
+ lines.forEach((line, lineIndex) => {
563
+ const lineStartX = startPos.x + getLineStartX({
564
+ alignment: anchorAlignment,
565
+ lineWidth: lineWidths[lineIndex],
566
+ maxWidth: width,
567
+ strokeWidth
568
+ });
569
+ const lineStartY = startPos.y + lineIndex * lineHeight;
570
+ strokeAlphabetLine({
571
+ ctx,
572
+ line,
573
+ fontSize: scaledFontSize,
574
+ startX: lineStartX,
575
+ startY: lineStartY,
576
+ layout
577
+ });
511
578
  });
512
579
  ctx.restore();
513
580
  }
@@ -566,7 +633,8 @@ function drawPcbCopperText(params) {
566
633
  text: content,
567
634
  fontSize,
568
635
  startX: startPos.x,
569
- startY: startPos.y
636
+ startY: startPos.y,
637
+ anchorAlignment: alignment
570
638
  });
571
639
  ctx.restore();
572
640
  }
@@ -1884,12 +1952,23 @@ function drawPcbSilkscreenText(params) {
1884
1952
  ctx.lineCap = "round";
1885
1953
  ctx.lineJoin = "round";
1886
1954
  ctx.strokeStyle = color;
1887
- strokeAlphabetText({
1888
- ctx,
1889
- text: content,
1890
- fontSize,
1891
- startX: startPos.x,
1892
- startY: startPos.y
1955
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout;
1956
+ lines.forEach((line, lineIndex) => {
1957
+ const lineStartX = startPos.x + getLineStartX({
1958
+ alignment,
1959
+ lineWidth: lineWidths[lineIndex],
1960
+ maxWidth: width,
1961
+ strokeWidth
1962
+ });
1963
+ const lineStartY = startPos.y + lineIndex * lineHeight;
1964
+ strokeAlphabetLine({
1965
+ ctx,
1966
+ line,
1967
+ fontSize,
1968
+ startX: lineStartX,
1969
+ startY: lineStartY,
1970
+ layout
1971
+ });
1893
1972
  });
1894
1973
  ctx.restore();
1895
1974
  }
@@ -83,6 +83,7 @@ export function drawPcbCopperText(params: DrawPcbCopperTextParams): void {
83
83
  fontSize,
84
84
  startX: startPos.x,
85
85
  startY: startPos.y,
86
+ anchorAlignment: alignment,
86
87
  })
87
88
  ctx.restore()
88
89
  }
@@ -4,8 +4,9 @@ import { applyToPoint } from "transformation-matrix"
4
4
  import type { PcbColorMap, CanvasContext } from "../types"
5
5
  import {
6
6
  getAlphabetLayout,
7
- strokeAlphabetText,
8
7
  getTextStartPosition,
8
+ getLineStartX,
9
+ strokeAlphabetLine,
9
10
  type AnchorAlignment,
10
11
  } from "../shapes/text"
11
12
 
@@ -65,12 +66,27 @@ export function drawPcbSilkscreenText(
65
66
  ctx.lineJoin = "round"
66
67
  ctx.strokeStyle = color
67
68
 
68
- strokeAlphabetText({
69
- ctx,
70
- text: content,
71
- fontSize,
72
- startX: startPos.x,
73
- startY: startPos.y,
69
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout
70
+
71
+ lines.forEach((line, lineIndex) => {
72
+ const lineStartX =
73
+ startPos.x +
74
+ getLineStartX({
75
+ alignment,
76
+ lineWidth: lineWidths[lineIndex]!,
77
+ maxWidth: width,
78
+ strokeWidth,
79
+ })
80
+ const lineStartY = startPos.y + lineIndex * lineHeight
81
+
82
+ strokeAlphabetLine({
83
+ ctx,
84
+ line,
85
+ fontSize,
86
+ startX: lineStartX,
87
+ startY: lineStartY,
88
+ layout,
89
+ })
74
90
  })
75
91
 
76
92
  ctx.restore()
@@ -2,6 +2,7 @@ export const GLYPH_WIDTH_RATIO = 0.62
2
2
  export const LETTER_SPACING_RATIO = 0.3 // Letter spacing between characters (25% of glyph width)
3
3
  export const SPACE_WIDTH_RATIO = 1
4
4
  export const STROKE_WIDTH_RATIO = 0.13
5
+ export const LINE_HEIGHT_RATIO = 1.2 // Line height as a ratio of font size
5
6
 
6
7
  export type AlphabetLayout = {
7
8
  width: number
@@ -10,6 +11,9 @@ export type AlphabetLayout = {
10
11
  letterSpacing: number
11
12
  spaceWidth: number
12
13
  strokeWidth: number
14
+ lineHeight: number
15
+ lines: string[]
16
+ lineWidths: number[]
13
17
  }
14
18
 
15
19
  export function getAlphabetLayout(
@@ -19,23 +23,37 @@ export function getAlphabetLayout(
19
23
  const glyphWidth = fontSize * GLYPH_WIDTH_RATIO
20
24
  const letterSpacing = glyphWidth * LETTER_SPACING_RATIO
21
25
  const spaceWidth = glyphWidth * SPACE_WIDTH_RATIO
22
- const characters = Array.from(text)
26
+ const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35)
27
+ const lineHeight = fontSize * LINE_HEIGHT_RATIO
23
28
 
24
- let width = 0
25
- characters.forEach((char, index) => {
26
- const advance = char === " " ? spaceWidth : glyphWidth
27
- width += advance
28
- if (index < characters.length - 1) width += letterSpacing
29
- })
29
+ const lines = text.split("\n")
30
+ const lineWidths: number[] = []
30
31
 
31
- const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35)
32
+ let maxWidth = 0
33
+ for (const line of lines) {
34
+ const characters = Array.from(line)
35
+ let lineWidth = 0
36
+ characters.forEach((char, index) => {
37
+ const advance = char === " " ? spaceWidth : glyphWidth
38
+ lineWidth += advance
39
+ if (index < characters.length - 1) lineWidth += letterSpacing
40
+ })
41
+ lineWidths.push(lineWidth)
42
+ if (lineWidth > maxWidth) maxWidth = lineWidth
43
+ }
44
+
45
+ const totalHeight =
46
+ lines.length > 1 ? fontSize + (lines.length - 1) * lineHeight : fontSize
32
47
 
33
48
  return {
34
- width,
35
- height: fontSize,
49
+ width: maxWidth,
50
+ height: totalHeight,
36
51
  glyphWidth,
37
52
  letterSpacing,
38
53
  spaceWidth,
39
54
  strokeWidth,
55
+ lineHeight,
56
+ lines,
57
+ lineWidths,
40
58
  }
41
59
  }
@@ -32,6 +32,8 @@ export function getTextStartPosition(
32
32
  alignment === "center_right"
33
33
  ) {
34
34
  x = -totalWidth
35
+ } else if (alignment === "top_center" || alignment === "bottom_center") {
36
+ x = -totalWidth / 2
35
37
  }
36
38
 
37
39
  // Vertical alignment
@@ -57,3 +59,37 @@ export function getTextStartPosition(
57
59
 
58
60
  return { x, y }
59
61
  }
62
+
63
+ export interface GetLineStartXParams {
64
+ alignment: NinePointAnchor
65
+ lineWidth: number
66
+ maxWidth: number
67
+ strokeWidth: number
68
+ }
69
+
70
+ export function getLineStartX(params: GetLineStartXParams): number {
71
+ const { alignment, lineWidth, maxWidth, strokeWidth } = params
72
+ const totalLineWidth = lineWidth + strokeWidth
73
+ const totalMaxWidth = maxWidth + strokeWidth
74
+
75
+ // For left-aligned text, lines start at x=0 (relative to the start position)
76
+ if (
77
+ alignment === "top_left" ||
78
+ alignment === "bottom_left" ||
79
+ alignment === "center_left"
80
+ ) {
81
+ return 0
82
+ }
83
+
84
+ // For right-aligned text, lines end at the same position
85
+ if (
86
+ alignment === "top_right" ||
87
+ alignment === "bottom_right" ||
88
+ alignment === "center_right"
89
+ ) {
90
+ return totalMaxWidth - totalLineWidth
91
+ }
92
+
93
+ // For center-aligned text, center each line
94
+ return (totalMaxWidth - totalLineWidth) / 2
95
+ }
@@ -1,3 +1,7 @@
1
1
  export * from "./text"
2
2
  export * from "./getAlphabetLayout"
3
- export * from "./getTextStartPosition"
3
+ export {
4
+ getTextStartPosition,
5
+ getLineStartX,
6
+ type AnchorAlignment,
7
+ } from "./getTextStartPosition"
@@ -4,7 +4,7 @@ import { applyToPoint } from "transformation-matrix"
4
4
  import type { CanvasContext } from "../../types"
5
5
  import type { NinePointAnchor } from "circuit-json"
6
6
  import { getAlphabetLayout, type AlphabetLayout } from "./getAlphabetLayout"
7
- import { getTextStartPosition } from "./getTextStartPosition"
7
+ import { getTextStartPosition, getLineStartX } from "./getTextStartPosition"
8
8
 
9
9
  const getGlyphLines = (char: string) =>
10
10
  lineAlphabet[char] ?? lineAlphabet[char.toUpperCase()]
@@ -15,29 +15,37 @@ export interface StrokeAlphabetTextParams {
15
15
  fontSize: number
16
16
  startX: number
17
17
  startY: number
18
+ anchorAlignment?: NinePointAnchor
18
19
  }
19
20
 
20
- export function strokeAlphabetText(params: StrokeAlphabetTextParams): void {
21
- const { ctx, text, fontSize, startX, startY } = params
22
- const layout = getAlphabetLayout(text, fontSize)
23
- const { glyphWidth, letterSpacing, spaceWidth, height, strokeWidth } = layout
21
+ export interface StrokeAlphabetLineParams {
22
+ ctx: CanvasContext
23
+ line: string
24
+ fontSize: number
25
+ startX: number
26
+ startY: number
27
+ layout: AlphabetLayout
28
+ }
29
+
30
+ export function strokeAlphabetLine(params: StrokeAlphabetLineParams): void {
31
+ const { ctx, line, fontSize, startX, startY, layout } = params
32
+ const { glyphWidth, letterSpacing, spaceWidth, strokeWidth } = layout
33
+ const height = fontSize
24
34
  const topY = startY
25
- const characters = Array.from(text)
35
+ const characters = Array.from(line)
26
36
  let cursor = startX + strokeWidth / 2
27
37
 
28
38
  characters.forEach((char, index) => {
29
- const lines = getGlyphLines(char)
39
+ const glyphLines = getGlyphLines(char)
30
40
  const advance = char === " " ? spaceWidth : glyphWidth
31
41
 
32
- if (lines?.length) {
42
+ if (glyphLines?.length) {
33
43
  ctx.beginPath()
34
- for (const line of lines) {
35
- // Convert normalized y coordinates to canvas coordinates (inverted for canvas)
36
- // In normalized coords: y=0 is bottom, y=1 is top
37
- const x1 = cursor + line.x1 * glyphWidth
38
- const y1 = topY + (1 - line.y1) * height
39
- const x2 = cursor + line.x2 * glyphWidth
40
- const y2 = topY + (1 - line.y2) * height
44
+ for (const glyph of glyphLines) {
45
+ const x1 = cursor + glyph.x1 * glyphWidth
46
+ const y1 = topY + (1 - glyph.y1) * height
47
+ const x2 = cursor + glyph.x2 * glyphWidth
48
+ const y2 = topY + (1 - glyph.y2) * height
41
49
  ctx.moveTo(x1, y1)
42
50
  ctx.lineTo(x2, y2)
43
51
  }
@@ -51,6 +59,40 @@ export function strokeAlphabetText(params: StrokeAlphabetTextParams): void {
51
59
  })
52
60
  }
53
61
 
62
+ export function strokeAlphabetText(params: StrokeAlphabetTextParams): void {
63
+ const {
64
+ ctx,
65
+ text,
66
+ fontSize,
67
+ startX,
68
+ startY,
69
+ anchorAlignment = "center",
70
+ } = params
71
+ const layout = getAlphabetLayout(text, fontSize)
72
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout
73
+
74
+ lines.forEach((line, lineIndex) => {
75
+ const lineStartX =
76
+ startX +
77
+ getLineStartX({
78
+ alignment: anchorAlignment,
79
+ lineWidth: lineWidths[lineIndex]!,
80
+ maxWidth: width,
81
+ strokeWidth,
82
+ })
83
+ const lineStartY = startY + lineIndex * lineHeight
84
+
85
+ strokeAlphabetLine({
86
+ ctx,
87
+ line,
88
+ fontSize,
89
+ startX: lineStartX,
90
+ startY: lineStartY,
91
+ layout,
92
+ })
93
+ })
94
+ }
95
+
54
96
  export interface DrawTextParams {
55
97
  ctx: CanvasContext
56
98
  text: string
@@ -96,12 +138,27 @@ export function drawText(params: DrawTextParams): void {
96
138
  ctx.lineJoin = "round"
97
139
  ctx.strokeStyle = color
98
140
 
99
- strokeAlphabetText({
100
- ctx,
101
- text,
102
- fontSize: scaledFontSize,
103
- startX: startPos.x,
104
- startY: startPos.y,
141
+ const { lines, lineWidths, lineHeight, width, strokeWidth } = layout
142
+
143
+ lines.forEach((line, lineIndex) => {
144
+ const lineStartX =
145
+ startPos.x +
146
+ getLineStartX({
147
+ alignment: anchorAlignment,
148
+ lineWidth: lineWidths[lineIndex]!,
149
+ maxWidth: width,
150
+ strokeWidth,
151
+ })
152
+ const lineStartY = startPos.y + lineIndex * lineHeight
153
+
154
+ strokeAlphabetLine({
155
+ ctx,
156
+ line,
157
+ fontSize: scaledFontSize,
158
+ startX: lineStartX,
159
+ startY: lineStartY,
160
+ layout,
161
+ })
105
162
  })
106
163
 
107
164
  ctx.restore()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-to-canvas",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.53",
4
+ "version": "0.0.54",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --format esm --dts",
@@ -0,0 +1,33 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbCopperText } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ test("draw multiline copper text with left alignment", async () => {
7
+ const SCALE = 4
8
+ const canvas = createCanvas(150 * SCALE, 100 * SCALE)
9
+ const ctx = canvas.getContext("2d")
10
+ ctx.scale(SCALE, SCALE)
11
+ const drawer = new CircuitToCanvasDrawer(ctx)
12
+
13
+ ctx.fillStyle = "#1a1a1a"
14
+ ctx.fillRect(0, 0, canvas.width / SCALE, canvas.height / SCALE)
15
+
16
+ const text: PcbCopperText = {
17
+ type: "pcb_copper_text",
18
+ pcb_copper_text_id: "copper-text-1",
19
+ pcb_component_id: "component1",
20
+ layer: "top",
21
+ text: "SHORT\nLONGERTEXT\nMED",
22
+ anchor_position: { x: 20, y: 50 },
23
+ anchor_alignment: "center_left",
24
+ font: "tscircuit2024",
25
+ font_size: 6,
26
+ }
27
+
28
+ drawer.drawElements([text])
29
+
30
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
31
+ import.meta.path,
32
+ )
33
+ })
@@ -0,0 +1,33 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbCopperText } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ test("draw multiline copper text with right alignment", async () => {
7
+ const SCALE = 4
8
+ const canvas = createCanvas(150 * SCALE, 100 * SCALE)
9
+ const ctx = canvas.getContext("2d")
10
+ ctx.scale(SCALE, SCALE)
11
+ const drawer = new CircuitToCanvasDrawer(ctx)
12
+
13
+ ctx.fillStyle = "#1a1a1a"
14
+ ctx.fillRect(0, 0, canvas.width / SCALE, canvas.height / SCALE)
15
+
16
+ const text: PcbCopperText = {
17
+ type: "pcb_copper_text",
18
+ pcb_copper_text_id: "copper-text-1",
19
+ pcb_component_id: "component1",
20
+ layer: "top",
21
+ text: "SHORT\nLONGERTEXT\nMED",
22
+ anchor_position: { x: 130, y: 50 },
23
+ anchor_alignment: "center_right",
24
+ font: "tscircuit2024",
25
+ font_size: 6,
26
+ }
27
+
28
+ drawer.drawElements([text])
29
+
30
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
31
+ import.meta.path,
32
+ )
33
+ })
@@ -0,0 +1,33 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbCopperText } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ test("draw multiline copper text with center alignment", async () => {
7
+ const SCALE = 4
8
+ const canvas = createCanvas(150 * SCALE, 100 * SCALE)
9
+ const ctx = canvas.getContext("2d")
10
+ ctx.scale(SCALE, SCALE)
11
+ const drawer = new CircuitToCanvasDrawer(ctx)
12
+
13
+ ctx.fillStyle = "#1a1a1a"
14
+ ctx.fillRect(0, 0, canvas.width / SCALE, canvas.height / SCALE)
15
+
16
+ const text: PcbCopperText = {
17
+ type: "pcb_copper_text",
18
+ pcb_copper_text_id: "copper-text-1",
19
+ pcb_component_id: "component1",
20
+ layer: "top",
21
+ text: "LINE1\nLONGERLINE2\nL3",
22
+ anchor_position: { x: 75, y: 50 },
23
+ anchor_alignment: "center",
24
+ font: "tscircuit2024",
25
+ font_size: 6,
26
+ }
27
+
28
+ drawer.drawElements([text])
29
+
30
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
31
+ import.meta.path,
32
+ )
33
+ })
@@ -0,0 +1,31 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbSilkscreenText } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ test("draw silkscreen text with multiple lines", async () => {
7
+ const canvas = createCanvas(200, 200)
8
+ const ctx = canvas.getContext("2d")
9
+ const drawer = new CircuitToCanvasDrawer(ctx)
10
+
11
+ ctx.fillStyle = "#1a1a1a"
12
+ ctx.fillRect(0, 0, 200, 200)
13
+
14
+ const text: PcbSilkscreenText = {
15
+ type: "pcb_silkscreen_text",
16
+ pcb_silkscreen_text_id: "text1",
17
+ pcb_component_id: "component1",
18
+ layer: "top",
19
+ text: "TOP\nMIDDLE\nBOTTOM",
20
+ anchor_position: { x: 100, y: 100 },
21
+ anchor_alignment: "center",
22
+ font: "tscircuit2024",
23
+ font_size: 10,
24
+ }
25
+
26
+ drawer.drawElements([text])
27
+
28
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
29
+ import.meta.path,
30
+ )
31
+ })