circuit-to-canvas 0.0.3 → 0.0.5

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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +82 -3
  3. package/dist/index.js +357 -4
  4. package/lib/drawer/CircuitToCanvasDrawer.ts +55 -0
  5. package/lib/drawer/elements/index.ts +25 -0
  6. package/lib/drawer/elements/pcb-copper-text.ts +99 -0
  7. package/lib/drawer/elements/pcb-fabrication-note-path.ts +41 -0
  8. package/lib/drawer/elements/pcb-fabrication-note-rect.ts +39 -0
  9. package/lib/drawer/elements/pcb-fabrication-note-text.ts +42 -0
  10. package/lib/drawer/elements/pcb-note-rect.ts +37 -0
  11. package/lib/drawer/shapes/index.ts +9 -0
  12. package/lib/drawer/shapes/rect.ts +28 -3
  13. package/lib/drawer/shapes/text.ts +218 -0
  14. package/lib/drawer/types.ts +8 -0
  15. package/package.json +3 -1
  16. package/tests/elements/__snapshots__/pcb-copper-text-knockout.snap.png +0 -0
  17. package/tests/elements/__snapshots__/pcb-copper-text.snap.png +0 -0
  18. package/tests/elements/__snapshots__/pcb-fabrication-note-path-custom-color.snap.png +0 -0
  19. package/tests/elements/__snapshots__/pcb-fabrication-note-path-thick-stroke.snap.png +0 -0
  20. package/tests/elements/__snapshots__/pcb-fabrication-note-path.snap.png +0 -0
  21. package/tests/elements/__snapshots__/pcb-fabrication-note-rect-all-features.snap.png +0 -0
  22. package/tests/elements/__snapshots__/pcb-fabrication-note-rect-corner-radius.snap.png +0 -0
  23. package/tests/elements/__snapshots__/pcb-fabrication-note-rect-custom-color.snap.png +0 -0
  24. package/tests/elements/__snapshots__/pcb-fabrication-note-rect-dashed.snap.png +0 -0
  25. package/tests/elements/__snapshots__/pcb-fabrication-note-rect-default-color.snap.png +0 -0
  26. package/tests/elements/__snapshots__/pcb-fabrication-note-text-rgba-color.snap.png +0 -0
  27. package/tests/elements/__snapshots__/pcb-fabrication-note-text-small.snap.png +0 -0
  28. package/tests/elements/__snapshots__/pcb-note-rect-all-features.snap.png +0 -0
  29. package/tests/elements/__snapshots__/pcb-note-rect-dashed-stroke.snap.png +0 -0
  30. package/tests/elements/__snapshots__/pcb-note-rect-filled-no-stroke.snap.png +0 -0
  31. package/tests/elements/pcb-copper-text.test.ts +102 -0
  32. package/tests/elements/pcb-fabrication-note-path-custom-color.test.ts +37 -0
  33. package/tests/elements/pcb-fabrication-note-path-thick-stroke.test.ts +37 -0
  34. package/tests/elements/pcb-fabrication-note-path.test.ts +36 -0
  35. package/tests/elements/pcb-fabrication-note-rect-all-features.test.ts +35 -0
  36. package/tests/elements/pcb-fabrication-note-rect-corner-radius.test.ts +33 -0
  37. package/tests/elements/pcb-fabrication-note-rect-custom-color.test.ts +32 -0
  38. package/tests/elements/pcb-fabrication-note-rect-dashed.test.ts +33 -0
  39. package/tests/elements/pcb-fabrication-note-rect-default-color.test.ts +32 -0
  40. package/tests/elements/pcb-fabrication-note-text-rgba-color.test.ts +34 -0
  41. package/tests/elements/pcb-fabrication-note-text-small.test.ts +33 -0
  42. package/tests/elements/pcb-note-rect-all-features.test.ts +38 -0
  43. package/tests/elements/pcb-note-rect-dashed-stroke.test.ts +32 -0
  44. package/tests/elements/pcb-note-rect-filled-no-stroke.test.ts +32 -0
package/README.md CHANGED
@@ -71,7 +71,7 @@ This checklist tracks PCB drawing features from [circuit-to-svg](https://github.
71
71
 
72
72
  ### Fabrication Notes
73
73
 
74
- - [ ] `pcb_fabrication_note_text` - Fabrication note text
74
+ - [x] `pcb_fabrication_note_text` - Fabrication note text
75
75
  - [ ] `pcb_fabrication_note_rect` - Fabrication note rectangles
76
76
  - [ ] `pcb_fabrication_note_path` - Fabrication note paths
77
77
  - [ ] `pcb_fabrication_note_dimension` - Fabrication dimension annotations
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AnyCircuitElement, PcbPlatedHole, PCBVia, PCBHole, PcbSmtPad, PCBTrace, PcbBoard, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbCutout, PcbCopperPour } from 'circuit-json';
1
+ import { AnyCircuitElement, PcbPlatedHole, PCBVia, PCBHole, PcbSmtPad, PCBTrace, PcbBoard, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbCutout, PcbCopperPour, PcbCopperText, PcbFabricationNoteText, PcbFabricationNoteRect, PcbNoteRect, PcbFabricationNotePath } from 'circuit-json';
2
2
  import { Matrix } from 'transformation-matrix';
3
3
 
4
4
  /**
@@ -21,16 +21,24 @@ interface CanvasContext {
21
21
  translate(x: number, y: number): void;
22
22
  rotate(angle: number): void;
23
23
  scale(x: number, y: number): void;
24
+ globalCompositeOperation?: string;
24
25
  fillStyle: string | CanvasGradient | CanvasPattern;
25
26
  strokeStyle: string | CanvasGradient | CanvasPattern;
26
27
  lineWidth: number;
27
28
  lineCap: "butt" | "round" | "square";
28
29
  lineJoin: "bevel" | "round" | "miter";
30
+ setLineDash(segments: number[]): void;
29
31
  canvas: {
30
32
  width: number;
31
33
  height: number;
32
34
  };
33
35
  fillText(text: string, x: number, y: number): void;
36
+ fillRect(x: number, y: number, width: number, height: number): void;
37
+ measureText?: (text: string) => {
38
+ width: number;
39
+ actualBoundingBoxAscent?: number;
40
+ actualBoundingBoxDescent?: number;
41
+ };
34
42
  font: string;
35
43
  textAlign: "start" | "end" | "left" | "right" | "center";
36
44
  textBaseline: "top" | "hanging" | "middle" | "alphabetic" | "ideographic" | "bottom";
@@ -115,10 +123,13 @@ interface DrawRectParams {
115
123
  };
116
124
  width: number;
117
125
  height: number;
118
- fill: string;
126
+ fill?: string;
119
127
  transform: Matrix;
120
128
  borderRadius?: number;
121
129
  rotation?: number;
130
+ stroke?: string;
131
+ strokeWidth?: number;
132
+ isStrokeDashed?: boolean;
122
133
  }
123
134
  declare function drawRect(params: DrawRectParams): void;
124
135
 
@@ -192,6 +203,34 @@ interface DrawPathParams {
192
203
  }
193
204
  declare function drawPath(params: DrawPathParams): void;
194
205
 
206
+ type AlphabetLayout = {
207
+ width: number;
208
+ height: number;
209
+ glyphWidth: number;
210
+ letterSpacing: number;
211
+ spaceWidth: number;
212
+ strokeWidth: number;
213
+ };
214
+ declare function getAlphabetLayout(text: string, fontSize: number): AlphabetLayout;
215
+ type AnchorAlignment = "center" | "top_left" | "top_right" | "bottom_left" | "bottom_right" | "left" | "right" | "top" | "bottom";
216
+ declare function getTextStartPosition(alignment: AnchorAlignment, layout: AlphabetLayout): {
217
+ x: number;
218
+ y: number;
219
+ };
220
+ declare function strokeAlphabetText(ctx: CanvasContext, text: string, layout: AlphabetLayout, startX: number, startY: number): void;
221
+ interface DrawTextParams {
222
+ ctx: CanvasContext;
223
+ text: string;
224
+ x: number;
225
+ y: number;
226
+ fontSize: number;
227
+ color: string;
228
+ transform: Matrix;
229
+ anchorAlignment: AnchorAlignment;
230
+ rotation?: number;
231
+ }
232
+ declare function drawText(params: DrawTextParams): void;
233
+
195
234
  interface DrawPcbPlatedHoleParams {
196
235
  ctx: CanvasContext;
197
236
  hole: PcbPlatedHole;
@@ -292,4 +331,44 @@ interface DrawPcbCopperPourParams {
292
331
  }
293
332
  declare function drawPcbCopperPour(params: DrawPcbCopperPourParams): void;
294
333
 
295
- export { type CameraBounds, type CanvasContext, CircuitToCanvasDrawer, type CopperColorMap, type CopperLayerName, DEFAULT_PCB_COLOR_MAP, type DrawCircleParams, type DrawContext, type DrawElementsOptions, type DrawLineParams, type DrawOvalParams, type DrawPathParams, type DrawPcbBoardParams, type DrawPcbCopperPourParams, type DrawPcbCutoutParams, type DrawPcbHoleParams, type DrawPcbPlatedHoleParams, type DrawPcbSilkscreenCircleParams, type DrawPcbSilkscreenLineParams, type DrawPcbSilkscreenPathParams, type DrawPcbSilkscreenRectParams, type DrawPcbSilkscreenTextParams, type DrawPcbSmtPadParams, type DrawPcbTraceParams, type DrawPcbViaParams, type DrawPillParams, type DrawPolygonParams, type DrawRectParams, type DrawerConfig, type PcbColorMap, drawCircle, drawLine, drawOval, drawPath, drawPcbBoard, drawPcbCopperPour, drawPcbCutout, drawPcbHole, drawPcbPlatedHole, drawPcbSilkscreenCircle, drawPcbSilkscreenLine, drawPcbSilkscreenPath, drawPcbSilkscreenRect, drawPcbSilkscreenText, drawPcbSmtPad, drawPcbTrace, drawPcbVia, drawPill, drawPolygon, drawRect };
334
+ interface DrawPcbCopperTextParams {
335
+ ctx: CanvasContext;
336
+ text: PcbCopperText;
337
+ transform: Matrix;
338
+ colorMap: PcbColorMap;
339
+ }
340
+ declare function drawPcbCopperText(params: DrawPcbCopperTextParams): void;
341
+
342
+ interface DrawPcbFabricationNoteTextParams {
343
+ ctx: CanvasContext;
344
+ text: PcbFabricationNoteText;
345
+ transform: Matrix;
346
+ colorMap: PcbColorMap;
347
+ }
348
+ declare function drawPcbFabricationNoteText(params: DrawPcbFabricationNoteTextParams): void;
349
+
350
+ interface DrawPcbFabricationNoteRectParams {
351
+ ctx: CanvasContext;
352
+ rect: PcbFabricationNoteRect;
353
+ transform: Matrix;
354
+ colorMap: PcbColorMap;
355
+ }
356
+ declare function drawPcbFabricationNoteRect(params: DrawPcbFabricationNoteRectParams): void;
357
+
358
+ interface DrawPcbNoteRectParams {
359
+ ctx: CanvasContext;
360
+ rect: PcbNoteRect;
361
+ transform: Matrix;
362
+ colorMap: PcbColorMap;
363
+ }
364
+ declare function drawPcbNoteRect(params: DrawPcbNoteRectParams): void;
365
+
366
+ interface DrawPcbFabricationNotePathParams {
367
+ ctx: CanvasContext;
368
+ path: PcbFabricationNotePath;
369
+ transform: Matrix;
370
+ colorMap: PcbColorMap;
371
+ }
372
+ declare function drawPcbFabricationNotePath(params: DrawPcbFabricationNotePathParams): void;
373
+
374
+ export { type AlphabetLayout, type AnchorAlignment, type CameraBounds, type CanvasContext, CircuitToCanvasDrawer, type CopperColorMap, type CopperLayerName, DEFAULT_PCB_COLOR_MAP, type DrawCircleParams, type DrawContext, type DrawElementsOptions, type DrawLineParams, type DrawOvalParams, type DrawPathParams, type DrawPcbBoardParams, type DrawPcbCopperPourParams, type DrawPcbCopperTextParams, type DrawPcbCutoutParams, type DrawPcbFabricationNotePathParams, type DrawPcbFabricationNoteRectParams, type DrawPcbFabricationNoteTextParams, type DrawPcbHoleParams, type DrawPcbNoteRectParams, type DrawPcbPlatedHoleParams, type DrawPcbSilkscreenCircleParams, type DrawPcbSilkscreenLineParams, type DrawPcbSilkscreenPathParams, type DrawPcbSilkscreenRectParams, type DrawPcbSilkscreenTextParams, type DrawPcbSmtPadParams, type DrawPcbTraceParams, type DrawPcbViaParams, type DrawPillParams, type DrawPolygonParams, type DrawRectParams, type DrawTextParams, type DrawerConfig, type PcbColorMap, drawCircle, drawLine, drawOval, drawPath, drawPcbBoard, drawPcbCopperPour, drawPcbCopperText, drawPcbCutout, drawPcbFabricationNotePath, drawPcbFabricationNoteRect, drawPcbFabricationNoteText, drawPcbHole, drawPcbNoteRect, drawPcbPlatedHole, drawPcbSilkscreenCircle, drawPcbSilkscreenLine, drawPcbSilkscreenPath, drawPcbSilkscreenRect, drawPcbSilkscreenText, drawPcbSmtPad, drawPcbTrace, drawPcbVia, drawPill, drawPolygon, drawRect, drawText, getAlphabetLayout, getTextStartPosition, strokeAlphabetText };
package/dist/index.js CHANGED
@@ -58,17 +58,26 @@ function drawRect(params) {
58
58
  fill,
59
59
  transform,
60
60
  borderRadius = 0,
61
- rotation = 0
61
+ rotation = 0,
62
+ stroke,
63
+ strokeWidth,
64
+ isStrokeDashed = false
62
65
  } = params;
63
66
  const [cx, cy] = applyToPoint2(transform, [center.x, center.y]);
64
67
  const scaledWidth = width * Math.abs(transform.a);
65
68
  const scaledHeight = height * Math.abs(transform.a);
66
69
  const scaledRadius = borderRadius * Math.abs(transform.a);
70
+ const scaledStrokeWidth = strokeWidth ? strokeWidth * Math.abs(transform.a) : void 0;
67
71
  ctx.save();
68
72
  ctx.translate(cx, cy);
69
73
  if (rotation !== 0) {
70
74
  ctx.rotate(-rotation * (Math.PI / 180));
71
75
  }
76
+ if (isStrokeDashed && scaledStrokeWidth) {
77
+ ctx.setLineDash([scaledStrokeWidth * 2, scaledStrokeWidth * 2]);
78
+ } else {
79
+ ctx.setLineDash([]);
80
+ }
72
81
  ctx.beginPath();
73
82
  if (scaledRadius > 0) {
74
83
  const x = -scaledWidth / 2;
@@ -92,8 +101,15 @@ function drawRect(params) {
92
101
  } else {
93
102
  ctx.rect(-scaledWidth / 2, -scaledHeight / 2, scaledWidth, scaledHeight);
94
103
  }
95
- ctx.fillStyle = fill;
96
- ctx.fill();
104
+ if (fill) {
105
+ ctx.fillStyle = fill;
106
+ ctx.fill();
107
+ }
108
+ if (stroke && scaledStrokeWidth) {
109
+ ctx.strokeStyle = stroke;
110
+ ctx.lineWidth = scaledStrokeWidth;
111
+ ctx.stroke();
112
+ }
97
113
  ctx.restore();
98
114
  }
99
115
 
@@ -794,6 +810,294 @@ function drawPcbCopperPour(params) {
794
810
  ctx.restore();
795
811
  }
796
812
 
813
+ // lib/drawer/elements/pcb-copper-text.ts
814
+ import { applyToPoint as applyToPoint11 } from "transformation-matrix";
815
+
816
+ // lib/drawer/shapes/text.ts
817
+ import { lineAlphabet } from "@tscircuit/alphabet";
818
+ import { applyToPoint as applyToPoint10 } from "transformation-matrix";
819
+ var GLYPH_WIDTH_RATIO = 0.62;
820
+ var LETTER_SPACING_RATIO = 0.3;
821
+ var SPACE_WIDTH_RATIO = 1;
822
+ var STROKE_WIDTH_RATIO = 0.13;
823
+ var CURVED_GLYPHS = /* @__PURE__ */ new Set(["O", "o", "0"]);
824
+ function getAlphabetLayout(text, fontSize) {
825
+ const glyphWidth = fontSize * GLYPH_WIDTH_RATIO;
826
+ const letterSpacing = glyphWidth * LETTER_SPACING_RATIO;
827
+ const spaceWidth = glyphWidth * SPACE_WIDTH_RATIO;
828
+ const characters = Array.from(text);
829
+ let width = 0;
830
+ characters.forEach((char, index) => {
831
+ const advance = char === " " ? spaceWidth : glyphWidth;
832
+ width += advance;
833
+ if (index < characters.length - 1) width += letterSpacing;
834
+ });
835
+ const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35);
836
+ return {
837
+ width,
838
+ height: fontSize,
839
+ glyphWidth,
840
+ letterSpacing,
841
+ spaceWidth,
842
+ strokeWidth
843
+ };
844
+ }
845
+ var getGlyphLines = (char) => lineAlphabet[char] ?? lineAlphabet[char.toUpperCase()];
846
+ function getTextStartPosition(alignment, layout) {
847
+ const totalWidth = layout.width + layout.strokeWidth;
848
+ const totalHeight = layout.height + layout.strokeWidth;
849
+ let x = 0;
850
+ let y = 0;
851
+ if (alignment === "center") {
852
+ x = -totalWidth / 2;
853
+ } else if (alignment === "top_left" || alignment === "bottom_left" || alignment === "left") {
854
+ x = 0;
855
+ } else if (alignment === "top_right" || alignment === "bottom_right" || alignment === "right") {
856
+ x = -totalWidth;
857
+ }
858
+ if (alignment === "center") {
859
+ y = -totalHeight / 2;
860
+ } else if (alignment === "top_left" || alignment === "top_right" || alignment === "top") {
861
+ y = 0;
862
+ } else if (alignment === "bottom_left" || alignment === "bottom_right" || alignment === "bottom") {
863
+ y = -totalHeight;
864
+ }
865
+ return { x, y };
866
+ }
867
+ function strokeAlphabetText(ctx, text, layout, startX, startY) {
868
+ const { glyphWidth, letterSpacing, spaceWidth, height, strokeWidth } = layout;
869
+ const yOffset = startY + height / 2;
870
+ const characters = Array.from(text);
871
+ let cursor = startX + strokeWidth / 2;
872
+ characters.forEach((char, index) => {
873
+ const lines = getGlyphLines(char);
874
+ const advance = char === " " ? spaceWidth : glyphWidth;
875
+ if (CURVED_GLYPHS.has(char)) {
876
+ const radiusX = Math.max(glyphWidth / 2 - strokeWidth / 2, strokeWidth);
877
+ const radiusY = Math.max(height / 2 - strokeWidth / 2, strokeWidth);
878
+ const centerY = yOffset - height / 2;
879
+ ctx.beginPath();
880
+ ctx.ellipse(
881
+ cursor + glyphWidth / 2,
882
+ centerY,
883
+ radiusX,
884
+ radiusY,
885
+ 0,
886
+ 0,
887
+ Math.PI * 2
888
+ );
889
+ ctx.stroke();
890
+ } else if (lines?.length) {
891
+ ctx.beginPath();
892
+ for (const line of lines) {
893
+ const x1 = cursor + line.x1 * glyphWidth;
894
+ const y1 = yOffset - line.y1 * height;
895
+ const x2 = cursor + line.x2 * glyphWidth;
896
+ const y2 = yOffset - line.y2 * height;
897
+ ctx.moveTo(x1, y1);
898
+ ctx.lineTo(x2, y2);
899
+ }
900
+ ctx.stroke();
901
+ }
902
+ cursor += advance;
903
+ if (index < characters.length - 1) {
904
+ cursor += letterSpacing;
905
+ }
906
+ });
907
+ }
908
+ function drawText(params) {
909
+ const {
910
+ ctx,
911
+ text,
912
+ x,
913
+ y,
914
+ fontSize,
915
+ color,
916
+ transform,
917
+ anchorAlignment,
918
+ rotation = 0
919
+ } = params;
920
+ if (!text) return;
921
+ const [transformedX, transformedY] = applyToPoint10(transform, [x, y]);
922
+ const scale2 = Math.abs(transform.a);
923
+ const scaledFontSize = fontSize * scale2;
924
+ const layout = getAlphabetLayout(text, scaledFontSize);
925
+ const startPos = getTextStartPosition(anchorAlignment, layout);
926
+ ctx.save();
927
+ ctx.translate(transformedX, transformedY);
928
+ if (rotation !== 0) {
929
+ ctx.rotate(-rotation * (Math.PI / 180));
930
+ }
931
+ ctx.lineWidth = layout.strokeWidth;
932
+ ctx.lineCap = "round";
933
+ ctx.lineJoin = "round";
934
+ ctx.strokeStyle = color;
935
+ strokeAlphabetText(
936
+ ctx,
937
+ text,
938
+ layout,
939
+ startPos.x,
940
+ startPos.y + layout.strokeWidth / 2
941
+ );
942
+ ctx.restore();
943
+ }
944
+
945
+ // lib/drawer/elements/pcb-copper-text.ts
946
+ var DEFAULT_PADDING = { left: 0.2, right: 0.2, top: 0.2, bottom: 0.2 };
947
+ function layerToCopperColor(layer, colorMap) {
948
+ return colorMap.copper[layer] ?? colorMap.copper.top;
949
+ }
950
+ function mapAnchorAlignment2(alignment) {
951
+ if (!alignment) return "center";
952
+ if (alignment.includes("left")) return "left";
953
+ if (alignment.includes("right")) return "right";
954
+ return "center";
955
+ }
956
+ function drawPcbCopperText(params) {
957
+ const { ctx, text, transform, colorMap } = params;
958
+ const content = text.text ?? "";
959
+ if (!content) return;
960
+ const [x, y] = applyToPoint11(transform, [
961
+ text.anchor_position.x,
962
+ text.anchor_position.y
963
+ ]);
964
+ const scale2 = Math.abs(transform.a);
965
+ const fontSize = (text.font_size ?? 1) * scale2;
966
+ const rotation = text.ccw_rotation ?? 0;
967
+ const padding = {
968
+ ...DEFAULT_PADDING,
969
+ ...text.knockout_padding
970
+ };
971
+ const textColor = layerToCopperColor(text.layer, colorMap);
972
+ const layout = getAlphabetLayout(content, fontSize);
973
+ const totalWidth = layout.width + layout.strokeWidth;
974
+ const totalHeight = layout.height + layout.strokeWidth;
975
+ const alignment = mapAnchorAlignment2(text.anchor_alignment);
976
+ const startPos = getTextStartPosition(alignment, layout);
977
+ const startX = startPos.x;
978
+ const startY = 0;
979
+ ctx.save();
980
+ ctx.translate(x, y);
981
+ if (text.is_mirrored) ctx.scale(-1, 1);
982
+ if (rotation !== 0) ctx.rotate(-rotation * (Math.PI / 180));
983
+ ctx.lineWidth = layout.strokeWidth;
984
+ ctx.lineCap = "round";
985
+ ctx.lineJoin = "round";
986
+ if (text.is_knockout) {
987
+ const paddingLeft = padding.left * scale2;
988
+ const paddingRight = padding.right * scale2;
989
+ const paddingTop = padding.top * scale2;
990
+ const paddingBottom = padding.bottom * scale2;
991
+ const xOffset = startX - paddingLeft;
992
+ const yOffset = -(layout.height / 2) - layout.strokeWidth / 2 - paddingTop;
993
+ const knockoutWidth = totalWidth + paddingLeft + paddingRight;
994
+ const knockoutHeight = totalHeight + paddingTop + paddingBottom;
995
+ ctx.fillStyle = textColor;
996
+ ctx.fillRect(xOffset, yOffset, knockoutWidth, knockoutHeight);
997
+ const previousCompositeOperation = ctx.globalCompositeOperation;
998
+ ctx.globalCompositeOperation = "destination-out";
999
+ ctx.fillStyle = "rgba(0,0,0,1)";
1000
+ ctx.strokeStyle = "rgba(0,0,0,1)";
1001
+ strokeAlphabetText(ctx, content, layout, startX, startY);
1002
+ if (previousCompositeOperation) {
1003
+ ctx.globalCompositeOperation = previousCompositeOperation;
1004
+ } else {
1005
+ ctx.globalCompositeOperation = "source-over";
1006
+ }
1007
+ } else {
1008
+ ctx.strokeStyle = textColor;
1009
+ strokeAlphabetText(ctx, content, layout, startX, startY);
1010
+ }
1011
+ ctx.restore();
1012
+ }
1013
+
1014
+ // lib/drawer/elements/pcb-fabrication-note-text.ts
1015
+ var DEFAULT_FABRICATION_NOTE_COLOR = "rgba(255,255,255,0.5)";
1016
+ function layerToColor4(layer, colorMap) {
1017
+ return DEFAULT_FABRICATION_NOTE_COLOR;
1018
+ }
1019
+ function drawPcbFabricationNoteText(params) {
1020
+ const { ctx, text, transform, colorMap } = params;
1021
+ const defaultColor = layerToColor4(text.layer, colorMap);
1022
+ const color = text.color ?? defaultColor;
1023
+ const fontSize = text.font_size;
1024
+ drawText({
1025
+ ctx,
1026
+ text: text.text,
1027
+ x: text.anchor_position.x,
1028
+ y: text.anchor_position.y,
1029
+ fontSize,
1030
+ color,
1031
+ transform,
1032
+ anchorAlignment: text.anchor_alignment
1033
+ });
1034
+ }
1035
+
1036
+ // lib/drawer/elements/pcb-fabrication-note-rect.ts
1037
+ function drawPcbFabricationNoteRect(params) {
1038
+ const { ctx, rect, transform, colorMap } = params;
1039
+ const defaultColor = "rgba(255,255,255,0.5)";
1040
+ const color = rect.color ?? defaultColor;
1041
+ const isFilled = rect.is_filled ?? false;
1042
+ const hasStroke = rect.has_stroke ?? true;
1043
+ const isStrokeDashed = rect.is_stroke_dashed ?? false;
1044
+ drawRect({
1045
+ ctx,
1046
+ center: rect.center,
1047
+ width: rect.width,
1048
+ height: rect.height,
1049
+ fill: isFilled ? color : void 0,
1050
+ stroke: hasStroke ? color : void 0,
1051
+ strokeWidth: hasStroke ? rect.stroke_width : void 0,
1052
+ borderRadius: rect.corner_radius,
1053
+ transform,
1054
+ isStrokeDashed
1055
+ });
1056
+ }
1057
+
1058
+ // lib/drawer/elements/pcb-note-rect.ts
1059
+ function drawPcbNoteRect(params) {
1060
+ const { ctx, rect, transform, colorMap } = params;
1061
+ const defaultColor = "rgb(89, 148, 220)";
1062
+ const color = rect.color ?? defaultColor;
1063
+ const isFilled = rect.is_filled ?? false;
1064
+ const hasStroke = rect.has_stroke ?? true;
1065
+ const isStrokeDashed = rect.is_stroke_dashed ?? false;
1066
+ drawRect({
1067
+ ctx,
1068
+ center: rect.center,
1069
+ width: rect.width,
1070
+ height: rect.height,
1071
+ fill: isFilled ? color : void 0,
1072
+ stroke: hasStroke ? color : void 0,
1073
+ strokeWidth: hasStroke ? rect.stroke_width : void 0,
1074
+ borderRadius: rect.corner_radius,
1075
+ transform,
1076
+ isStrokeDashed
1077
+ });
1078
+ }
1079
+
1080
+ // lib/drawer/elements/pcb-fabrication-note-path.ts
1081
+ function drawPcbFabricationNotePath(params) {
1082
+ const { ctx, path, transform, colorMap } = params;
1083
+ const defaultColor = "rgba(255,255,255,0.5)";
1084
+ const color = path.color ?? defaultColor;
1085
+ if (!path.route || path.route.length < 2) return;
1086
+ for (let i = 0; i < path.route.length - 1; i++) {
1087
+ const start = path.route[i];
1088
+ const end = path.route[i + 1];
1089
+ if (!start || !end) continue;
1090
+ drawLine({
1091
+ ctx,
1092
+ start: { x: start.x, y: start.y },
1093
+ end: { x: end.x, y: end.y },
1094
+ strokeWidth: path.stroke_width ?? 0.1,
1095
+ stroke: color,
1096
+ transform
1097
+ });
1098
+ }
1099
+ }
1100
+
797
1101
  // lib/drawer/CircuitToCanvasDrawer.ts
798
1102
  var CircuitToCanvasDrawer = class {
799
1103
  ctx;
@@ -967,6 +1271,46 @@ var CircuitToCanvasDrawer = class {
967
1271
  colorMap: this.colorMap
968
1272
  });
969
1273
  }
1274
+ if (element.type === "pcb_copper_text") {
1275
+ drawPcbCopperText({
1276
+ ctx: this.ctx,
1277
+ text: element,
1278
+ transform: this.realToCanvasMat,
1279
+ colorMap: this.colorMap
1280
+ });
1281
+ }
1282
+ if (element.type === "pcb_fabrication_note_text") {
1283
+ drawPcbFabricationNoteText({
1284
+ ctx: this.ctx,
1285
+ text: element,
1286
+ transform: this.realToCanvasMat,
1287
+ colorMap: this.colorMap
1288
+ });
1289
+ }
1290
+ if (element.type === "pcb_fabrication_note_rect") {
1291
+ drawPcbFabricationNoteRect({
1292
+ ctx: this.ctx,
1293
+ rect: element,
1294
+ transform: this.realToCanvasMat,
1295
+ colorMap: this.colorMap
1296
+ });
1297
+ }
1298
+ if (element.type === "pcb_note_rect") {
1299
+ drawPcbNoteRect({
1300
+ transform: this.realToCanvasMat,
1301
+ colorMap: this.colorMap,
1302
+ ctx: this.ctx,
1303
+ rect: element
1304
+ });
1305
+ }
1306
+ if (element.type === "pcb_fabrication_note_path") {
1307
+ drawPcbFabricationNotePath({
1308
+ ctx: this.ctx,
1309
+ path: element,
1310
+ transform: this.realToCanvasMat,
1311
+ colorMap: this.colorMap
1312
+ });
1313
+ }
970
1314
  }
971
1315
  };
972
1316
  export {
@@ -978,8 +1322,13 @@ export {
978
1322
  drawPath,
979
1323
  drawPcbBoard,
980
1324
  drawPcbCopperPour,
1325
+ drawPcbCopperText,
981
1326
  drawPcbCutout,
1327
+ drawPcbFabricationNotePath,
1328
+ drawPcbFabricationNoteRect,
1329
+ drawPcbFabricationNoteText,
982
1330
  drawPcbHole,
1331
+ drawPcbNoteRect,
983
1332
  drawPcbPlatedHole,
984
1333
  drawPcbSilkscreenCircle,
985
1334
  drawPcbSilkscreenLine,
@@ -991,5 +1340,9 @@ export {
991
1340
  drawPcbVia,
992
1341
  drawPill,
993
1342
  drawPolygon,
994
- drawRect
1343
+ drawRect,
1344
+ drawText,
1345
+ getAlphabetLayout,
1346
+ getTextStartPosition,
1347
+ strokeAlphabetText
995
1348
  };
@@ -13,6 +13,11 @@ import type {
13
13
  PcbSilkscreenPath,
14
14
  PcbCutout,
15
15
  PcbCopperPour,
16
+ PcbCopperText,
17
+ PcbFabricationNoteText,
18
+ PcbFabricationNoteRect,
19
+ PcbNoteRect,
20
+ PcbFabricationNotePath,
16
21
  } from "circuit-json"
17
22
  import { identity, compose, translate, scale } from "transformation-matrix"
18
23
  import type { Matrix } from "transformation-matrix"
@@ -38,6 +43,11 @@ import {
38
43
  } from "./elements/pcb-silkscreen"
39
44
  import { drawPcbCutout } from "./elements/pcb-cutout"
40
45
  import { drawPcbCopperPour } from "./elements/pcb-copper-pour"
46
+ import { drawPcbCopperText } from "./elements/pcb-copper-text"
47
+ import { drawPcbFabricationNoteText } from "./elements/pcb-fabrication-note-text"
48
+ import { drawPcbFabricationNoteRect } from "./elements/pcb-fabrication-note-rect"
49
+ import { drawPcbNoteRect } from "./elements/pcb-note-rect"
50
+ import { drawPcbFabricationNotePath } from "./elements/pcb-fabrication-note-path"
41
51
 
42
52
  export interface DrawElementsOptions {
43
53
  layers?: string[]
@@ -252,5 +262,50 @@ export class CircuitToCanvasDrawer {
252
262
  colorMap: this.colorMap,
253
263
  })
254
264
  }
265
+
266
+ if (element.type === "pcb_copper_text") {
267
+ drawPcbCopperText({
268
+ ctx: this.ctx,
269
+ text: element as PcbCopperText,
270
+ transform: this.realToCanvasMat,
271
+ colorMap: this.colorMap,
272
+ })
273
+ }
274
+
275
+ if (element.type === "pcb_fabrication_note_text") {
276
+ drawPcbFabricationNoteText({
277
+ ctx: this.ctx,
278
+ text: element as PcbFabricationNoteText,
279
+ transform: this.realToCanvasMat,
280
+ colorMap: this.colorMap,
281
+ })
282
+ }
283
+
284
+ if (element.type === "pcb_fabrication_note_rect") {
285
+ drawPcbFabricationNoteRect({
286
+ ctx: this.ctx,
287
+ rect: element as PcbFabricationNoteRect,
288
+ transform: this.realToCanvasMat,
289
+ colorMap: this.colorMap,
290
+ })
291
+ }
292
+
293
+ if (element.type === "pcb_note_rect") {
294
+ drawPcbNoteRect({
295
+ transform: this.realToCanvasMat,
296
+ colorMap: this.colorMap,
297
+ ctx: this.ctx,
298
+ rect: element as PcbNoteRect,
299
+ })
300
+ }
301
+
302
+ if (element.type === "pcb_fabrication_note_path") {
303
+ drawPcbFabricationNotePath({
304
+ ctx: this.ctx,
305
+ path: element as PcbFabricationNotePath,
306
+ transform: this.realToCanvasMat,
307
+ colorMap: this.colorMap,
308
+ })
309
+ }
255
310
  }
256
311
  }
@@ -32,3 +32,28 @@ export {
32
32
  drawPcbCopperPour,
33
33
  type DrawPcbCopperPourParams,
34
34
  } from "./pcb-copper-pour"
35
+
36
+ export {
37
+ drawPcbCopperText,
38
+ type DrawPcbCopperTextParams,
39
+ } from "./pcb-copper-text"
40
+
41
+ export {
42
+ drawPcbFabricationNoteText,
43
+ type DrawPcbFabricationNoteTextParams,
44
+ } from "./pcb-fabrication-note-text"
45
+
46
+ export {
47
+ drawPcbFabricationNoteRect,
48
+ type DrawPcbFabricationNoteRectParams,
49
+ } from "./pcb-fabrication-note-rect"
50
+
51
+ export {
52
+ drawPcbNoteRect,
53
+ type DrawPcbNoteRectParams,
54
+ } from "./pcb-note-rect"
55
+
56
+ export {
57
+ drawPcbFabricationNotePath,
58
+ type DrawPcbFabricationNotePathParams,
59
+ } from "./pcb-fabrication-note-path"