circuit-to-canvas 0.0.42 → 0.0.44

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.js CHANGED
@@ -816,6 +816,12 @@ function drawPcbVia(params) {
816
816
  }
817
817
 
818
818
  // lib/drawer/elements/pcb-hole.ts
819
+ function getRotation(hole) {
820
+ if ("ccw_rotation" in hole && typeof hole.ccw_rotation === "number") {
821
+ return hole.ccw_rotation;
822
+ }
823
+ return 0;
824
+ }
819
825
  function drawPcbHole(params) {
820
826
  const { ctx, hole, realToCanvasMat, colorMap } = params;
821
827
  const hasSoldermask = hole.is_covered_with_solder_mask === true && hole.soldermask_margin !== void 0 && hole.soldermask_margin > 0;
@@ -841,6 +847,7 @@ function drawPcbHole(params) {
841
847
  return;
842
848
  }
843
849
  if (hole.hole_shape === "square") {
850
+ const rotation = getRotation(hole);
844
851
  if (hasSoldermask && margin > 0) {
845
852
  drawRect({
846
853
  ctx,
@@ -848,7 +855,8 @@ function drawPcbHole(params) {
848
855
  width: hole.hole_diameter + margin * 2,
849
856
  height: hole.hole_diameter + margin * 2,
850
857
  fill: positiveMarginColor,
851
- realToCanvasMat
858
+ realToCanvasMat,
859
+ rotation
852
860
  });
853
861
  }
854
862
  drawRect({
@@ -857,11 +865,13 @@ function drawPcbHole(params) {
857
865
  width: hole.hole_diameter,
858
866
  height: hole.hole_diameter,
859
867
  fill: colorMap.drill,
860
- realToCanvasMat
868
+ realToCanvasMat,
869
+ rotation
861
870
  });
862
871
  return;
863
872
  }
864
873
  if (hole.hole_shape === "oval") {
874
+ const rotation = getRotation(hole);
865
875
  if (hasSoldermask && margin > 0) {
866
876
  drawOval({
867
877
  ctx,
@@ -869,7 +879,8 @@ function drawPcbHole(params) {
869
879
  radius_x: hole.hole_width / 2 + margin,
870
880
  radius_y: hole.hole_height / 2 + margin,
871
881
  fill: positiveMarginColor,
872
- realToCanvasMat
882
+ realToCanvasMat,
883
+ rotation
873
884
  });
874
885
  }
875
886
  drawOval({
@@ -878,11 +889,13 @@ function drawPcbHole(params) {
878
889
  radius_x: hole.hole_width / 2,
879
890
  radius_y: hole.hole_height / 2,
880
891
  fill: colorMap.drill,
881
- realToCanvasMat
892
+ realToCanvasMat,
893
+ rotation
882
894
  });
883
895
  return;
884
896
  }
885
897
  if (hole.hole_shape === "rect") {
898
+ const rotation = getRotation(hole);
886
899
  if (hasSoldermask && margin > 0) {
887
900
  drawRect({
888
901
  ctx,
@@ -890,7 +903,8 @@ function drawPcbHole(params) {
890
903
  width: hole.hole_width + margin * 2,
891
904
  height: hole.hole_height + margin * 2,
892
905
  fill: positiveMarginColor,
893
- realToCanvasMat
906
+ realToCanvasMat,
907
+ rotation
894
908
  });
895
909
  }
896
910
  drawRect({
@@ -899,11 +913,13 @@ function drawPcbHole(params) {
899
913
  width: hole.hole_width,
900
914
  height: hole.hole_height,
901
915
  fill: colorMap.drill,
902
- realToCanvasMat
916
+ realToCanvasMat,
917
+ rotation
903
918
  });
904
919
  return;
905
920
  }
906
921
  if (hole.hole_shape === "pill") {
922
+ const rotation = getRotation(hole);
907
923
  if (hasSoldermask && margin > 0) {
908
924
  drawPill({
909
925
  ctx,
@@ -911,7 +927,8 @@ function drawPcbHole(params) {
911
927
  width: hole.hole_width + margin * 2,
912
928
  height: hole.hole_height + margin * 2,
913
929
  fill: positiveMarginColor,
914
- realToCanvasMat
930
+ realToCanvasMat,
931
+ rotation
915
932
  });
916
933
  }
917
934
  drawPill({
@@ -920,12 +937,13 @@ function drawPcbHole(params) {
920
937
  width: hole.hole_width,
921
938
  height: hole.hole_height,
922
939
  fill: colorMap.drill,
923
- realToCanvasMat
940
+ realToCanvasMat,
941
+ rotation
924
942
  });
925
943
  return;
926
944
  }
927
945
  if (hole.hole_shape === "rotated_pill") {
928
- const rotation = hole.ccw_rotation ?? 0;
946
+ const rotation = getRotation(hole);
929
947
  if (hasSoldermask && margin > 0) {
930
948
  drawPill({
931
949
  ctx,
@@ -957,6 +975,9 @@ function layerToColor(layer, colorMap) {
957
975
  function getSoldermaskColor2(layer, colorMap) {
958
976
  return colorMap.soldermaskOverCopper[layer] ?? colorMap.soldermaskOverCopper.top;
959
977
  }
978
+ function getBorderRadius(pad, margin = 0) {
979
+ return (pad.corner_radius ?? pad.rect_border_radius ?? 0) + margin;
980
+ }
960
981
  function drawPcbSmtPad(params) {
961
982
  const { ctx, pad, realToCanvasMat, colorMap } = params;
962
983
  const color = layerToColor(pad.layer, colorMap);
@@ -975,7 +996,7 @@ function drawPcbSmtPad(params) {
975
996
  height: pad.height + margin * 2,
976
997
  fill: positiveMarginColor,
977
998
  realToCanvasMat,
978
- borderRadius: (pad.corner_radius ?? pad.rect_border_radius ?? 0) + margin
999
+ borderRadius: getBorderRadius(pad, margin)
979
1000
  });
980
1001
  }
981
1002
  drawRect({
@@ -985,7 +1006,7 @@ function drawPcbSmtPad(params) {
985
1006
  height: pad.height,
986
1007
  fill: color,
987
1008
  realToCanvasMat,
988
- borderRadius: pad.corner_radius ?? pad.rect_border_radius ?? 0
1009
+ borderRadius: getBorderRadius(pad)
989
1010
  });
990
1011
  if (hasSoldermask && margin < 0) {
991
1012
  drawSoldermaskRingForRect(
@@ -994,7 +1015,7 @@ function drawPcbSmtPad(params) {
994
1015
  pad.width,
995
1016
  pad.height,
996
1017
  margin,
997
- pad.corner_radius ?? pad.rect_border_radius ?? 0,
1018
+ getBorderRadius(pad),
998
1019
  0,
999
1020
  realToCanvasMat,
1000
1021
  soldermaskRingColor,
@@ -1009,7 +1030,7 @@ function drawPcbSmtPad(params) {
1009
1030
  height: pad.height,
1010
1031
  fill: soldermaskOverlayColor,
1011
1032
  realToCanvasMat,
1012
- borderRadius: pad.corner_radius ?? pad.rect_border_radius ?? 0
1033
+ borderRadius: getBorderRadius(pad)
1013
1034
  });
1014
1035
  }
1015
1036
  return;
@@ -1023,7 +1044,7 @@ function drawPcbSmtPad(params) {
1023
1044
  height: pad.height + margin * 2,
1024
1045
  fill: positiveMarginColor,
1025
1046
  realToCanvasMat,
1026
- borderRadius: (pad.corner_radius ?? pad.rect_border_radius ?? 0) + margin,
1047
+ borderRadius: getBorderRadius(pad, margin),
1027
1048
  rotation: pad.ccw_rotation ?? 0
1028
1049
  });
1029
1050
  }
@@ -1034,7 +1055,7 @@ function drawPcbSmtPad(params) {
1034
1055
  height: pad.height,
1035
1056
  fill: color,
1036
1057
  realToCanvasMat,
1037
- borderRadius: pad.corner_radius ?? pad.rect_border_radius ?? 0,
1058
+ borderRadius: getBorderRadius(pad),
1038
1059
  rotation: pad.ccw_rotation ?? 0
1039
1060
  });
1040
1061
  if (hasSoldermask && margin < 0) {
@@ -1044,7 +1065,7 @@ function drawPcbSmtPad(params) {
1044
1065
  pad.width,
1045
1066
  pad.height,
1046
1067
  margin,
1047
- pad.corner_radius ?? pad.rect_border_radius ?? 0,
1068
+ getBorderRadius(pad),
1048
1069
  pad.ccw_rotation ?? 0,
1049
1070
  realToCanvasMat,
1050
1071
  soldermaskRingColor,
@@ -1059,7 +1080,7 @@ function drawPcbSmtPad(params) {
1059
1080
  height: pad.height,
1060
1081
  fill: soldermaskOverlayColor,
1061
1082
  realToCanvasMat,
1062
- borderRadius: pad.corner_radius ?? pad.rect_border_radius ?? 0,
1083
+ borderRadius: getBorderRadius(pad),
1063
1084
  rotation: pad.ccw_rotation ?? 0
1064
1085
  });
1065
1086
  }
@@ -13,6 +13,14 @@ export interface DrawPcbHoleParams {
13
13
  colorMap: PcbColorMap
14
14
  }
15
15
 
16
+ // Helper function to safely access ccw_rotation property
17
+ function getRotation(hole: PCBHole): number {
18
+ if ("ccw_rotation" in hole && typeof hole.ccw_rotation === "number") {
19
+ return hole.ccw_rotation
20
+ }
21
+ return 0
22
+ }
23
+
16
24
  export function drawPcbHole(params: DrawPcbHoleParams): void {
17
25
  const { ctx, hole, realToCanvasMat, colorMap } = params
18
26
 
@@ -47,6 +55,7 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
47
55
  }
48
56
 
49
57
  if (hole.hole_shape === "square") {
58
+ const rotation = getRotation(hole)
50
59
  // For positive margins, draw extended mask area first
51
60
  if (hasSoldermask && margin > 0) {
52
61
  drawRect({
@@ -56,6 +65,7 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
56
65
  height: hole.hole_diameter + margin * 2,
57
66
  fill: positiveMarginColor,
58
67
  realToCanvasMat,
68
+ rotation,
59
69
  })
60
70
  }
61
71
 
@@ -67,11 +77,13 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
67
77
  height: hole.hole_diameter,
68
78
  fill: colorMap.drill,
69
79
  realToCanvasMat,
80
+ rotation,
70
81
  })
71
82
  return
72
83
  }
73
84
 
74
85
  if (hole.hole_shape === "oval") {
86
+ const rotation = getRotation(hole)
75
87
  // For positive margins, draw extended mask area first
76
88
  if (hasSoldermask && margin > 0) {
77
89
  drawOval({
@@ -81,6 +93,7 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
81
93
  radius_y: hole.hole_height / 2 + margin,
82
94
  fill: positiveMarginColor,
83
95
  realToCanvasMat,
96
+ rotation,
84
97
  })
85
98
  }
86
99
 
@@ -92,11 +105,13 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
92
105
  radius_y: hole.hole_height / 2,
93
106
  fill: colorMap.drill,
94
107
  realToCanvasMat,
108
+ rotation,
95
109
  })
96
110
  return
97
111
  }
98
112
 
99
113
  if (hole.hole_shape === "rect") {
114
+ const rotation = getRotation(hole)
100
115
  // For positive margins, draw extended mask area first
101
116
  if (hasSoldermask && margin > 0) {
102
117
  drawRect({
@@ -106,6 +121,7 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
106
121
  height: hole.hole_height + margin * 2,
107
122
  fill: positiveMarginColor,
108
123
  realToCanvasMat,
124
+ rotation,
109
125
  })
110
126
  }
111
127
 
@@ -117,11 +133,13 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
117
133
  height: hole.hole_height,
118
134
  fill: colorMap.drill,
119
135
  realToCanvasMat,
136
+ rotation,
120
137
  })
121
138
  return
122
139
  }
123
140
 
124
141
  if (hole.hole_shape === "pill") {
142
+ const rotation = getRotation(hole)
125
143
  // For positive margins, draw extended mask area first
126
144
  if (hasSoldermask && margin > 0) {
127
145
  drawPill({
@@ -131,6 +149,7 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
131
149
  height: hole.hole_height + margin * 2,
132
150
  fill: positiveMarginColor,
133
151
  realToCanvasMat,
152
+ rotation,
134
153
  })
135
154
  }
136
155
 
@@ -142,12 +161,13 @@ export function drawPcbHole(params: DrawPcbHoleParams): void {
142
161
  height: hole.hole_height,
143
162
  fill: colorMap.drill,
144
163
  realToCanvasMat,
164
+ rotation,
145
165
  })
146
166
  return
147
167
  }
148
168
 
149
169
  if (hole.hole_shape === "rotated_pill") {
150
- const rotation = (hole as any).ccw_rotation ?? 0
170
+ const rotation = getRotation(hole)
151
171
 
152
172
  // For positive margins, draw extended mask area first
153
173
  if (hasSoldermask && margin > 0) {
@@ -33,6 +33,14 @@ function getSoldermaskColor(layer: string, colorMap: PcbColorMap): string {
33
33
  )
34
34
  }
35
35
 
36
+ function getBorderRadius(pad: PcbSmtPad, margin: number = 0): number {
37
+ return (
38
+ ((pad as { corner_radius?: number }).corner_radius ??
39
+ (pad as { rect_border_radius?: number }).rect_border_radius ??
40
+ 0) + margin
41
+ )
42
+ }
43
+
36
44
  export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
37
45
  const { ctx, pad, realToCanvasMat, colorMap } = params
38
46
 
@@ -62,10 +70,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
62
70
  height: pad.height + margin * 2,
63
71
  fill: positiveMarginColor,
64
72
  realToCanvasMat,
65
- borderRadius:
66
- ((pad as { corner_radius?: number }).corner_radius ??
67
- pad.rect_border_radius ??
68
- 0) + margin,
73
+ borderRadius: getBorderRadius(pad, margin),
69
74
  })
70
75
  }
71
76
 
@@ -77,10 +82,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
77
82
  height: pad.height,
78
83
  fill: color,
79
84
  realToCanvasMat,
80
- borderRadius:
81
- (pad as { corner_radius?: number }).corner_radius ??
82
- pad.rect_border_radius ??
83
- 0,
85
+ borderRadius: getBorderRadius(pad),
84
86
  })
85
87
 
86
88
  // For negative margins, draw soldermask ring on top of the pad
@@ -91,9 +93,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
91
93
  pad.width,
92
94
  pad.height,
93
95
  margin,
94
- (pad as { corner_radius?: number }).corner_radius ??
95
- pad.rect_border_radius ??
96
- 0,
96
+ getBorderRadius(pad),
97
97
  0,
98
98
  realToCanvasMat,
99
99
  soldermaskRingColor,
@@ -110,10 +110,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
110
110
  height: pad.height,
111
111
  fill: soldermaskOverlayColor,
112
112
  realToCanvasMat,
113
- borderRadius:
114
- (pad as { corner_radius?: number }).corner_radius ??
115
- pad.rect_border_radius ??
116
- 0,
113
+ borderRadius: getBorderRadius(pad),
117
114
  })
118
115
  }
119
116
  return
@@ -129,10 +126,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
129
126
  height: pad.height + margin * 2,
130
127
  fill: positiveMarginColor,
131
128
  realToCanvasMat,
132
- borderRadius:
133
- ((pad as { corner_radius?: number }).corner_radius ??
134
- pad.rect_border_radius ??
135
- 0) + margin,
129
+ borderRadius: getBorderRadius(pad, margin),
136
130
  rotation: pad.ccw_rotation ?? 0,
137
131
  })
138
132
  }
@@ -145,10 +139,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
145
139
  height: pad.height,
146
140
  fill: color,
147
141
  realToCanvasMat,
148
- borderRadius:
149
- (pad as { corner_radius?: number }).corner_radius ??
150
- pad.rect_border_radius ??
151
- 0,
142
+ borderRadius: getBorderRadius(pad),
152
143
  rotation: pad.ccw_rotation ?? 0,
153
144
  })
154
145
 
@@ -160,9 +151,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
160
151
  pad.width,
161
152
  pad.height,
162
153
  margin,
163
- (pad as { corner_radius?: number }).corner_radius ??
164
- pad.rect_border_radius ??
165
- 0,
154
+ getBorderRadius(pad),
166
155
  pad.ccw_rotation ?? 0,
167
156
  realToCanvasMat,
168
157
  soldermaskRingColor,
@@ -179,10 +168,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
179
168
  height: pad.height,
180
169
  fill: soldermaskOverlayColor,
181
170
  realToCanvasMat,
182
- borderRadius:
183
- (pad as { corner_radius?: number }).corner_radius ??
184
- pad.rect_border_radius ??
185
- 0,
171
+ borderRadius: getBorderRadius(pad),
186
172
  rotation: pad.ccw_rotation ?? 0,
187
173
  })
188
174
  }
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.42",
4
+ "version": "0.0.44",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --format esm --dts",
@@ -103,3 +103,110 @@ test("draw pill hole", async () => {
103
103
  "pill-hole",
104
104
  )
105
105
  })
106
+
107
+ test("draw rotated oval hole", async () => {
108
+ const canvas = createCanvas(100, 100)
109
+ const ctx = canvas.getContext("2d")
110
+ const drawer = new CircuitToCanvasDrawer(ctx)
111
+
112
+ ctx.fillStyle = "#1a1a1a"
113
+ ctx.fillRect(0, 0, 100, 100)
114
+
115
+ const hole: PCBHole & { ccw_rotation?: number } = {
116
+ type: "pcb_hole",
117
+ pcb_hole_id: "hole1",
118
+ hole_shape: "oval",
119
+ hole_width: 50,
120
+ hole_height: 30,
121
+ x: 50,
122
+ y: 50,
123
+ ccw_rotation: 45,
124
+ }
125
+
126
+ drawer.drawElements([hole])
127
+
128
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
129
+ import.meta.path,
130
+ "rotated-oval-hole",
131
+ )
132
+ })
133
+
134
+ test("draw rotated rect hole", async () => {
135
+ const canvas = createCanvas(100, 100)
136
+ const ctx = canvas.getContext("2d")
137
+ const drawer = new CircuitToCanvasDrawer(ctx)
138
+
139
+ ctx.fillStyle = "#1a1a1a"
140
+ ctx.fillRect(0, 0, 100, 100)
141
+
142
+ const hole: PCBHole & { ccw_rotation?: number } = {
143
+ type: "pcb_hole",
144
+ pcb_hole_id: "hole1",
145
+ hole_shape: "rect",
146
+ hole_width: 50,
147
+ hole_height: 30,
148
+ x: 50,
149
+ y: 50,
150
+ ccw_rotation: 45,
151
+ }
152
+
153
+ drawer.drawElements([hole])
154
+
155
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
156
+ import.meta.path,
157
+ "rotated-rect-hole",
158
+ )
159
+ })
160
+
161
+ test("draw rotated square hole", async () => {
162
+ const canvas = createCanvas(100, 100)
163
+ const ctx = canvas.getContext("2d")
164
+ const drawer = new CircuitToCanvasDrawer(ctx)
165
+
166
+ ctx.fillStyle = "#1a1a1a"
167
+ ctx.fillRect(0, 0, 100, 100)
168
+
169
+ const hole: PCBHole & { ccw_rotation?: number } = {
170
+ type: "pcb_hole",
171
+ pcb_hole_id: "hole1",
172
+ hole_shape: "square",
173
+ hole_diameter: 30,
174
+ x: 50,
175
+ y: 50,
176
+ ccw_rotation: 45,
177
+ }
178
+
179
+ drawer.drawElements([hole])
180
+
181
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
182
+ import.meta.path,
183
+ "rotated-square-hole",
184
+ )
185
+ })
186
+
187
+ test("draw rotated pill hole", async () => {
188
+ const canvas = createCanvas(100, 100)
189
+ const ctx = canvas.getContext("2d")
190
+ const drawer = new CircuitToCanvasDrawer(ctx)
191
+
192
+ ctx.fillStyle = "#1a1a1a"
193
+ ctx.fillRect(0, 0, 100, 100)
194
+
195
+ const hole: PCBHole & { ccw_rotation?: number } = {
196
+ type: "pcb_hole",
197
+ pcb_hole_id: "hole1",
198
+ hole_shape: "pill",
199
+ hole_width: 60,
200
+ hole_height: 30,
201
+ x: 50,
202
+ y: 50,
203
+ ccw_rotation: 45,
204
+ }
205
+
206
+ drawer.drawElements([hole])
207
+
208
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
209
+ import.meta.path,
210
+ "rotated-pill-hole",
211
+ )
212
+ })