circuit-to-canvas 0.0.44 → 0.0.46
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 +407 -182
- package/lib/drawer/CircuitToCanvasDrawer.ts +1 -5
- package/lib/drawer/elements/pcb-copper-text.ts +23 -37
- package/lib/drawer/elements/pcb-hole.ts +248 -61
- package/lib/drawer/elements/pcb-plated-hole.ts +194 -102
- package/lib/drawer/elements/pcb-smtpad.ts +14 -17
- package/package.json +1 -1
- package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
- package/tests/elements/__snapshots__/board-with-elements.snap.png +0 -0
- package/tests/elements/__snapshots__/custom-outline-board.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-board.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-comprehensive-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-copper-text-knockout.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-fabrication-note-dimension.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-hole-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-layer-filter.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-multiple-layers.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-rect-and-circle.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-with-group-id.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-with-offset.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-plated-hole-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-silkscreen-oval.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-smtpad-soldermask-margin.snap.png +0 -0
- package/tests/elements/pcb-comprehensive-soldermask-margin.test.ts +330 -0
- package/tests/elements/pcb-hole-soldermask-margin.test.ts +5 -5
- package/tests/elements/pcb-plated-hole-soldermask-margin.test.ts +8 -8
- package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +0 -6
- package/tests/shapes/__snapshots__/dimension-line.snap.png +0 -0
|
@@ -35,11 +35,12 @@ function getSoldermaskColor(
|
|
|
35
35
|
export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
36
36
|
const { ctx, hole, realToCanvasMat, colorMap } = params
|
|
37
37
|
|
|
38
|
+
const isCoveredWithSoldermask = hole.is_covered_with_solder_mask === true
|
|
39
|
+
const margin = isCoveredWithSoldermask ? 0 : (hole.soldermask_margin ?? 0)
|
|
38
40
|
const hasSoldermask =
|
|
39
|
-
|
|
41
|
+
!isCoveredWithSoldermask &&
|
|
40
42
|
hole.soldermask_margin !== undefined &&
|
|
41
43
|
hole.soldermask_margin !== 0
|
|
42
|
-
const margin = hasSoldermask ? hole.soldermask_margin! : 0
|
|
43
44
|
const soldermaskRingColor = getSoldermaskColor(hole.layers, colorMap)
|
|
44
45
|
const positiveMarginColor = colorMap.substrate
|
|
45
46
|
const copperColor = colorMap.copper.top
|
|
@@ -78,14 +79,27 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
78
79
|
)
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
// If fully covered, draw soldermask overlay
|
|
83
|
+
if (isCoveredWithSoldermask) {
|
|
84
|
+
drawCircle({
|
|
85
|
+
ctx,
|
|
86
|
+
center: { x: hole.x, y: hole.y },
|
|
87
|
+
radius: hole.outer_diameter / 2,
|
|
88
|
+
fill: soldermaskRingColor,
|
|
89
|
+
realToCanvasMat,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
94
|
+
if (!isCoveredWithSoldermask) {
|
|
95
|
+
drawCircle({
|
|
96
|
+
ctx,
|
|
97
|
+
center: { x: hole.x, y: hole.y },
|
|
98
|
+
radius: hole.hole_diameter / 2,
|
|
99
|
+
fill: colorMap.drill,
|
|
100
|
+
realToCanvasMat,
|
|
101
|
+
})
|
|
102
|
+
}
|
|
89
103
|
return
|
|
90
104
|
}
|
|
91
105
|
|
|
@@ -129,16 +143,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
129
143
|
)
|
|
130
144
|
}
|
|
131
145
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
// If fully covered, draw soldermask overlay
|
|
147
|
+
if (isCoveredWithSoldermask) {
|
|
148
|
+
drawOval({
|
|
149
|
+
ctx,
|
|
150
|
+
center: { x: hole.x, y: hole.y },
|
|
151
|
+
radius_x: hole.outer_width / 2,
|
|
152
|
+
radius_y: hole.outer_height / 2,
|
|
153
|
+
fill: soldermaskRingColor,
|
|
154
|
+
realToCanvasMat,
|
|
155
|
+
rotation: hole.ccw_rotation,
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
160
|
+
if (!isCoveredWithSoldermask) {
|
|
161
|
+
drawOval({
|
|
162
|
+
ctx,
|
|
163
|
+
center: { x: hole.x, y: hole.y },
|
|
164
|
+
radius_x: hole.hole_width / 2,
|
|
165
|
+
radius_y: hole.hole_height / 2,
|
|
166
|
+
fill: colorMap.drill,
|
|
167
|
+
realToCanvasMat,
|
|
168
|
+
rotation: hole.ccw_rotation,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
142
171
|
return
|
|
143
172
|
}
|
|
144
173
|
|
|
@@ -182,16 +211,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
182
211
|
)
|
|
183
212
|
}
|
|
184
213
|
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
214
|
+
// If fully covered, draw soldermask overlay
|
|
215
|
+
if (isCoveredWithSoldermask) {
|
|
216
|
+
drawPill({
|
|
217
|
+
ctx,
|
|
218
|
+
center: { x: hole.x, y: hole.y },
|
|
219
|
+
width: hole.outer_width,
|
|
220
|
+
height: hole.outer_height,
|
|
221
|
+
fill: soldermaskRingColor,
|
|
222
|
+
realToCanvasMat,
|
|
223
|
+
rotation: hole.ccw_rotation,
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
228
|
+
if (!isCoveredWithSoldermask) {
|
|
229
|
+
drawPill({
|
|
230
|
+
ctx,
|
|
231
|
+
center: { x: hole.x, y: hole.y },
|
|
232
|
+
width: hole.hole_width,
|
|
233
|
+
height: hole.hole_height,
|
|
234
|
+
fill: colorMap.drill,
|
|
235
|
+
realToCanvasMat,
|
|
236
|
+
rotation: hole.ccw_rotation,
|
|
237
|
+
})
|
|
238
|
+
}
|
|
195
239
|
return
|
|
196
240
|
}
|
|
197
241
|
|
|
@@ -236,16 +280,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
236
280
|
)
|
|
237
281
|
}
|
|
238
282
|
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
283
|
+
// If fully covered, draw soldermask overlay
|
|
284
|
+
if (isCoveredWithSoldermask) {
|
|
285
|
+
drawRect({
|
|
286
|
+
ctx,
|
|
287
|
+
center: { x: hole.x, y: hole.y },
|
|
288
|
+
width: hole.rect_pad_width,
|
|
289
|
+
height: hole.rect_pad_height,
|
|
290
|
+
fill: soldermaskRingColor,
|
|
291
|
+
realToCanvasMat,
|
|
292
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Draw circular drill hole (with offset, only if not fully covered with soldermask)
|
|
297
|
+
if (!isCoveredWithSoldermask) {
|
|
298
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
299
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
300
|
+
drawCircle({
|
|
301
|
+
ctx,
|
|
302
|
+
center: { x: holeX, y: holeY },
|
|
303
|
+
radius: hole.hole_diameter / 2,
|
|
304
|
+
fill: colorMap.drill,
|
|
305
|
+
realToCanvasMat,
|
|
306
|
+
})
|
|
307
|
+
}
|
|
249
308
|
return
|
|
250
309
|
}
|
|
251
310
|
|
|
@@ -290,17 +349,32 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
290
349
|
)
|
|
291
350
|
}
|
|
292
351
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
352
|
+
// If fully covered, draw soldermask overlay
|
|
353
|
+
if (isCoveredWithSoldermask) {
|
|
354
|
+
drawRect({
|
|
355
|
+
ctx,
|
|
356
|
+
center: { x: hole.x, y: hole.y },
|
|
357
|
+
width: hole.rect_pad_width,
|
|
358
|
+
height: hole.rect_pad_height,
|
|
359
|
+
fill: soldermaskRingColor,
|
|
360
|
+
realToCanvasMat,
|
|
361
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Draw pill drill hole (with offset, only if not fully covered with soldermask)
|
|
366
|
+
if (!isCoveredWithSoldermask) {
|
|
367
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
368
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
369
|
+
drawPill({
|
|
370
|
+
ctx,
|
|
371
|
+
center: { x: holeX, y: holeY },
|
|
372
|
+
width: hole.hole_width,
|
|
373
|
+
height: hole.hole_height,
|
|
374
|
+
fill: colorMap.drill,
|
|
375
|
+
realToCanvasMat,
|
|
376
|
+
})
|
|
377
|
+
}
|
|
304
378
|
return
|
|
305
379
|
}
|
|
306
380
|
|
|
@@ -347,18 +421,34 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
347
421
|
)
|
|
348
422
|
}
|
|
349
423
|
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
424
|
+
// If fully covered, draw soldermask overlay
|
|
425
|
+
if (isCoveredWithSoldermask) {
|
|
426
|
+
drawRect({
|
|
427
|
+
ctx,
|
|
428
|
+
center: { x: hole.x, y: hole.y },
|
|
429
|
+
width: hole.rect_pad_width,
|
|
430
|
+
height: hole.rect_pad_height,
|
|
431
|
+
fill: soldermaskRingColor,
|
|
432
|
+
realToCanvasMat,
|
|
433
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
434
|
+
rotation: hole.rect_ccw_rotation,
|
|
435
|
+
})
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Draw rotated pill drill hole (with offset, only if not fully covered with soldermask)
|
|
439
|
+
if (!isCoveredWithSoldermask) {
|
|
440
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
441
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
442
|
+
drawPill({
|
|
443
|
+
ctx,
|
|
444
|
+
center: { x: holeX, y: holeY },
|
|
445
|
+
width: hole.hole_width,
|
|
446
|
+
height: hole.hole_height,
|
|
447
|
+
fill: colorMap.drill,
|
|
448
|
+
realToCanvasMat,
|
|
449
|
+
rotation: hole.hole_ccw_rotation,
|
|
450
|
+
})
|
|
451
|
+
}
|
|
362
452
|
return
|
|
363
453
|
}
|
|
364
454
|
|
|
@@ -380,46 +470,48 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
380
470
|
})
|
|
381
471
|
}
|
|
382
472
|
|
|
383
|
-
// Draw drill hole (with offset)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
473
|
+
// Draw drill hole (with offset, only if not fully covered with soldermask)
|
|
474
|
+
if (!isCoveredWithSoldermask) {
|
|
475
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
476
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
477
|
+
const holeShape = hole.hole_shape
|
|
387
478
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
479
|
+
if (holeShape === "circle") {
|
|
480
|
+
drawCircle({
|
|
481
|
+
ctx,
|
|
482
|
+
center: { x: holeX, y: holeY },
|
|
483
|
+
radius: (hole.hole_diameter ?? 0) / 2,
|
|
484
|
+
fill: colorMap.drill,
|
|
485
|
+
realToCanvasMat,
|
|
486
|
+
})
|
|
487
|
+
} else if (holeShape === "oval") {
|
|
488
|
+
drawOval({
|
|
489
|
+
ctx,
|
|
490
|
+
center: { x: holeX, y: holeY },
|
|
491
|
+
radius_x: (hole.hole_width ?? 0) / 2,
|
|
492
|
+
radius_y: (hole.hole_height ?? 0) / 2,
|
|
493
|
+
fill: colorMap.drill,
|
|
494
|
+
realToCanvasMat,
|
|
495
|
+
})
|
|
496
|
+
} else if (holeShape === "pill") {
|
|
497
|
+
drawPill({
|
|
498
|
+
ctx,
|
|
499
|
+
center: { x: holeX, y: holeY },
|
|
500
|
+
width: hole.hole_width ?? 0,
|
|
501
|
+
height: hole.hole_height ?? 0,
|
|
502
|
+
fill: colorMap.drill,
|
|
503
|
+
realToCanvasMat,
|
|
504
|
+
})
|
|
505
|
+
} else if (holeShape === "rotated_pill") {
|
|
506
|
+
drawPill({
|
|
507
|
+
ctx,
|
|
508
|
+
center: { x: holeX, y: holeY },
|
|
509
|
+
width: hole.hole_width ?? 0,
|
|
510
|
+
height: hole.hole_height ?? 0,
|
|
511
|
+
fill: colorMap.drill,
|
|
512
|
+
realToCanvasMat,
|
|
513
|
+
})
|
|
514
|
+
}
|
|
423
515
|
}
|
|
424
516
|
return
|
|
425
517
|
}
|
|
@@ -33,7 +33,7 @@ function getSoldermaskColor(layer: string, colorMap: PcbColorMap): string {
|
|
|
33
33
|
)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function getBorderRadius(pad: PcbSmtPad, margin
|
|
36
|
+
function getBorderRadius(pad: PcbSmtPad, margin = 0): number {
|
|
37
37
|
return (
|
|
38
38
|
((pad as { corner_radius?: number }).corner_radius ??
|
|
39
39
|
(pad as { rect_border_radius?: number }).rect_border_radius ??
|
|
@@ -46,13 +46,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
46
46
|
|
|
47
47
|
const color = layerToColor(pad.layer, colorMap)
|
|
48
48
|
const isCoveredWithSoldermask = pad.is_covered_with_solder_mask === true
|
|
49
|
-
//
|
|
50
|
-
const margin =
|
|
51
|
-
isCoveredWithSoldermask && pad.soldermask_margin !== undefined
|
|
52
|
-
? pad.soldermask_margin
|
|
53
|
-
: 0
|
|
49
|
+
// If covered with soldermask, fully covered with no margin; otherwise use soldermask_margin if set
|
|
50
|
+
const margin = isCoveredWithSoldermask ? 0 : (pad.soldermask_margin ?? 0)
|
|
54
51
|
const hasSoldermask =
|
|
55
|
-
isCoveredWithSoldermask &&
|
|
52
|
+
!isCoveredWithSoldermask &&
|
|
56
53
|
pad.soldermask_margin !== undefined &&
|
|
57
54
|
pad.soldermask_margin !== 0
|
|
58
55
|
const soldermaskRingColor = getSoldermaskColor(pad.layer, colorMap)
|
|
@@ -61,8 +58,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
61
58
|
|
|
62
59
|
// Draw the copper pad
|
|
63
60
|
if (pad.shape === "rect") {
|
|
64
|
-
// For positive margins
|
|
65
|
-
if (
|
|
61
|
+
// For positive margins, draw extended mask area first
|
|
62
|
+
if (hasSoldermask && margin > 0) {
|
|
66
63
|
drawRect({
|
|
67
64
|
ctx,
|
|
68
65
|
center: { x: pad.x, y: pad.y },
|
|
@@ -117,8 +114,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
117
114
|
}
|
|
118
115
|
|
|
119
116
|
if (pad.shape === "rotated_rect") {
|
|
120
|
-
// For positive margins
|
|
121
|
-
if (
|
|
117
|
+
// For positive margins, draw extended mask area first
|
|
118
|
+
if (hasSoldermask && margin > 0) {
|
|
122
119
|
drawRect({
|
|
123
120
|
ctx,
|
|
124
121
|
center: { x: pad.x, y: pad.y },
|
|
@@ -176,8 +173,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
176
173
|
}
|
|
177
174
|
|
|
178
175
|
if (pad.shape === "circle") {
|
|
179
|
-
// For positive margins
|
|
180
|
-
if (
|
|
176
|
+
// For positive margins, draw extended mask area first
|
|
177
|
+
if (hasSoldermask && margin > 0) {
|
|
181
178
|
drawCircle({
|
|
182
179
|
ctx,
|
|
183
180
|
center: { x: pad.x, y: pad.y },
|
|
@@ -223,8 +220,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
223
220
|
}
|
|
224
221
|
|
|
225
222
|
if (pad.shape === "pill") {
|
|
226
|
-
// For positive margins
|
|
227
|
-
if (
|
|
223
|
+
// For positive margins, draw extended mask area first
|
|
224
|
+
if (hasSoldermask && margin > 0) {
|
|
228
225
|
drawPill({
|
|
229
226
|
ctx,
|
|
230
227
|
center: { x: pad.x, y: pad.y },
|
|
@@ -275,8 +272,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
275
272
|
}
|
|
276
273
|
|
|
277
274
|
if (pad.shape === "rotated_pill") {
|
|
278
|
-
// For positive margins
|
|
279
|
-
if (
|
|
275
|
+
// For positive margins, draw extended mask area first
|
|
276
|
+
if (hasSoldermask && margin > 0) {
|
|
280
277
|
drawPill({
|
|
281
278
|
ctx,
|
|
282
279
|
center: { x: pad.x, y: pad.y },
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|