circuit-to-canvas 0.0.36 → 0.0.38

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
@@ -249,17 +249,252 @@ function drawPolygon(params) {
249
249
  ctx.fill();
250
250
  }
251
251
 
252
+ // lib/drawer/elements/soldermask-margin.ts
253
+ import { applyToPoint as applyToPoint6 } from "transformation-matrix";
254
+ function drawSoldermaskRingForRect(ctx, center, width, height, margin, borderRadius, rotation, realToCanvasMat, soldermaskColor, padColor) {
255
+ const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
256
+ const scaledWidth = width * Math.abs(realToCanvasMat.a);
257
+ const scaledHeight = height * Math.abs(realToCanvasMat.a);
258
+ const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
259
+ const scaledRadius = borderRadius * Math.abs(realToCanvasMat.a);
260
+ ctx.save();
261
+ ctx.translate(cx, cy);
262
+ if (rotation !== 0) {
263
+ ctx.rotate(-rotation * (Math.PI / 180));
264
+ }
265
+ const prevCompositeOp = ctx.globalCompositeOperation;
266
+ if (ctx.globalCompositeOperation !== void 0) {
267
+ ctx.globalCompositeOperation = "source-atop";
268
+ }
269
+ const outerWidth = scaledWidth;
270
+ const outerHeight = scaledHeight;
271
+ const outerRadius = scaledRadius;
272
+ ctx.beginPath();
273
+ if (outerRadius > 0) {
274
+ const x = -outerWidth / 2;
275
+ const y = -outerHeight / 2;
276
+ const r = Math.min(outerRadius, outerWidth / 2, outerHeight / 2);
277
+ ctx.moveTo(x + r, y);
278
+ ctx.lineTo(x + outerWidth - r, y);
279
+ ctx.arcTo(x + outerWidth, y, x + outerWidth, y + r, r);
280
+ ctx.lineTo(x + outerWidth, y + outerHeight - r);
281
+ ctx.arcTo(
282
+ x + outerWidth,
283
+ y + outerHeight,
284
+ x + outerWidth - r,
285
+ y + outerHeight,
286
+ r
287
+ );
288
+ ctx.lineTo(x + r, y + outerHeight);
289
+ ctx.arcTo(x, y + outerHeight, x, y + outerHeight - r, r);
290
+ ctx.lineTo(x, y + r);
291
+ ctx.arcTo(x, y, x + r, y, r);
292
+ } else {
293
+ ctx.rect(-outerWidth / 2, -outerHeight / 2, outerWidth, outerHeight);
294
+ }
295
+ ctx.fillStyle = soldermaskColor;
296
+ ctx.fill();
297
+ if (ctx.globalCompositeOperation !== void 0) {
298
+ ctx.globalCompositeOperation = prevCompositeOp || "source-over";
299
+ }
300
+ const innerWidth = scaledWidth - scaledMargin * 2;
301
+ const innerHeight = scaledHeight - scaledMargin * 2;
302
+ const innerRadius = Math.max(0, scaledRadius - scaledMargin);
303
+ if (innerWidth > 0 && innerHeight > 0) {
304
+ ctx.beginPath();
305
+ if (innerRadius > 0) {
306
+ const x = -innerWidth / 2;
307
+ const y = -innerHeight / 2;
308
+ const r = Math.min(innerRadius, innerWidth / 2, innerHeight / 2);
309
+ ctx.moveTo(x + r, y);
310
+ ctx.lineTo(x + innerWidth - r, y);
311
+ ctx.arcTo(x + innerWidth, y, x + innerWidth, y + r, r);
312
+ ctx.lineTo(x + innerWidth, y + innerHeight - r);
313
+ ctx.arcTo(
314
+ x + innerWidth,
315
+ y + innerHeight,
316
+ x + innerWidth - r,
317
+ y + innerHeight,
318
+ r
319
+ );
320
+ ctx.lineTo(x + r, y + innerHeight);
321
+ ctx.arcTo(x, y + innerHeight, x, y + innerHeight - r, r);
322
+ ctx.lineTo(x, y + r);
323
+ ctx.arcTo(x, y, x + r, y, r);
324
+ } else {
325
+ ctx.rect(-innerWidth / 2, -innerHeight / 2, innerWidth, innerHeight);
326
+ }
327
+ ctx.fillStyle = padColor;
328
+ ctx.fill();
329
+ }
330
+ ctx.restore();
331
+ }
332
+ function drawSoldermaskRingForCircle(ctx, center, radius, margin, realToCanvasMat, soldermaskColor, padColor) {
333
+ const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
334
+ const scaledRadius = radius * Math.abs(realToCanvasMat.a);
335
+ const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
336
+ ctx.save();
337
+ const prevCompositeOp = ctx.globalCompositeOperation;
338
+ if (ctx.globalCompositeOperation !== void 0) {
339
+ ctx.globalCompositeOperation = "source-atop";
340
+ }
341
+ ctx.beginPath();
342
+ ctx.arc(cx, cy, scaledRadius, 0, Math.PI * 2);
343
+ ctx.fillStyle = soldermaskColor;
344
+ ctx.fill();
345
+ if (ctx.globalCompositeOperation !== void 0) {
346
+ ctx.globalCompositeOperation = prevCompositeOp || "source-over";
347
+ }
348
+ const innerRadius = Math.max(0, scaledRadius - scaledMargin);
349
+ if (innerRadius > 0) {
350
+ ctx.beginPath();
351
+ ctx.arc(cx, cy, innerRadius, 0, Math.PI * 2);
352
+ ctx.fillStyle = padColor;
353
+ ctx.fill();
354
+ }
355
+ ctx.restore();
356
+ }
357
+ function drawSoldermaskRingForPill(ctx, center, width, height, margin, rotation, realToCanvasMat, soldermaskColor, padColor) {
358
+ const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
359
+ const scaledWidth = width * Math.abs(realToCanvasMat.a);
360
+ const scaledHeight = height * Math.abs(realToCanvasMat.a);
361
+ const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
362
+ ctx.save();
363
+ ctx.translate(cx, cy);
364
+ if (rotation !== 0) {
365
+ ctx.rotate(-rotation * (Math.PI / 180));
366
+ }
367
+ const prevCompositeOp = ctx.globalCompositeOperation;
368
+ if (ctx.globalCompositeOperation !== void 0) {
369
+ ctx.globalCompositeOperation = "source-atop";
370
+ }
371
+ const outerWidth = scaledWidth;
372
+ const outerHeight = scaledHeight;
373
+ ctx.beginPath();
374
+ if (outerWidth > outerHeight) {
375
+ const radius = outerHeight / 2;
376
+ const straightLength = outerWidth - outerHeight;
377
+ ctx.moveTo(-straightLength / 2, -radius);
378
+ ctx.lineTo(straightLength / 2, -radius);
379
+ ctx.arc(straightLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2);
380
+ ctx.lineTo(-straightLength / 2, radius);
381
+ ctx.arc(-straightLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2);
382
+ } else if (outerHeight > outerWidth) {
383
+ const radius = outerWidth / 2;
384
+ const straightLength = outerHeight - outerWidth;
385
+ ctx.moveTo(radius, -straightLength / 2);
386
+ ctx.lineTo(radius, straightLength / 2);
387
+ ctx.arc(0, straightLength / 2, radius, 0, Math.PI);
388
+ ctx.lineTo(-radius, -straightLength / 2);
389
+ ctx.arc(0, -straightLength / 2, radius, Math.PI, 0);
390
+ } else {
391
+ ctx.arc(0, 0, outerWidth / 2, 0, Math.PI * 2);
392
+ }
393
+ ctx.fillStyle = soldermaskColor;
394
+ ctx.fill();
395
+ if (ctx.globalCompositeOperation !== void 0) {
396
+ ctx.globalCompositeOperation = prevCompositeOp || "source-over";
397
+ }
398
+ const innerWidth = scaledWidth - scaledMargin * 2;
399
+ const innerHeight = scaledHeight - scaledMargin * 2;
400
+ if (innerWidth > 0 && innerHeight > 0) {
401
+ ctx.beginPath();
402
+ if (innerWidth > innerHeight) {
403
+ const radius = innerHeight / 2;
404
+ const straightLength = innerWidth - innerHeight;
405
+ ctx.moveTo(-straightLength / 2, -radius);
406
+ ctx.lineTo(straightLength / 2, -radius);
407
+ ctx.arc(straightLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2);
408
+ ctx.lineTo(-straightLength / 2, radius);
409
+ ctx.arc(-straightLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2);
410
+ } else if (innerHeight > innerWidth) {
411
+ const radius = innerWidth / 2;
412
+ const straightLength = innerHeight - innerWidth;
413
+ ctx.moveTo(radius, -straightLength / 2);
414
+ ctx.lineTo(radius, straightLength / 2);
415
+ ctx.arc(0, straightLength / 2, radius, 0, Math.PI);
416
+ ctx.lineTo(-radius, -straightLength / 2);
417
+ ctx.arc(0, -straightLength / 2, radius, Math.PI, 0);
418
+ } else {
419
+ ctx.arc(0, 0, innerWidth / 2, 0, Math.PI * 2);
420
+ }
421
+ ctx.fillStyle = padColor;
422
+ ctx.fill();
423
+ }
424
+ ctx.restore();
425
+ }
426
+ function drawSoldermaskRingForOval(ctx, center, radius_x, radius_y, margin, rotation, realToCanvasMat, soldermaskColor, holeColor) {
427
+ const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
428
+ const scaledRadiusX = radius_x * Math.abs(realToCanvasMat.a);
429
+ const scaledRadiusY = radius_y * Math.abs(realToCanvasMat.a);
430
+ const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
431
+ ctx.save();
432
+ ctx.translate(cx, cy);
433
+ if (rotation !== 0) {
434
+ ctx.rotate(-rotation * (Math.PI / 180));
435
+ }
436
+ const prevCompositeOp = ctx.globalCompositeOperation;
437
+ if (ctx.globalCompositeOperation !== void 0) {
438
+ ctx.globalCompositeOperation = "source-atop";
439
+ }
440
+ ctx.beginPath();
441
+ ctx.ellipse(0, 0, scaledRadiusX, scaledRadiusY, 0, 0, Math.PI * 2);
442
+ ctx.fillStyle = soldermaskColor;
443
+ ctx.fill();
444
+ if (ctx.globalCompositeOperation !== void 0) {
445
+ ctx.globalCompositeOperation = prevCompositeOp || "source-over";
446
+ }
447
+ const innerRadiusX = Math.max(0, scaledRadiusX - scaledMargin);
448
+ const innerRadiusY = Math.max(0, scaledRadiusY - scaledMargin);
449
+ if (innerRadiusX > 0 && innerRadiusY > 0) {
450
+ ctx.beginPath();
451
+ ctx.ellipse(0, 0, innerRadiusX, innerRadiusY, 0, 0, Math.PI * 2);
452
+ ctx.fillStyle = holeColor;
453
+ ctx.fill();
454
+ }
455
+ ctx.restore();
456
+ }
457
+
252
458
  // lib/drawer/elements/pcb-plated-hole.ts
459
+ function getSoldermaskColor(layers, colorMap) {
460
+ const layer = layers?.includes("top") ? "top" : "bottom";
461
+ return colorMap.soldermaskOverCopper[layer] ?? colorMap.soldermaskOverCopper.top;
462
+ }
253
463
  function drawPcbPlatedHole(params) {
254
464
  const { ctx, hole, realToCanvasMat, colorMap } = params;
465
+ const hasSoldermask = hole.is_covered_with_solder_mask === true && hole.soldermask_margin !== void 0 && hole.soldermask_margin !== 0;
466
+ const margin = hasSoldermask ? hole.soldermask_margin : 0;
467
+ const soldermaskRingColor = getSoldermaskColor(hole.layers, colorMap);
468
+ const positiveMarginColor = colorMap.substrate;
469
+ const copperColor = colorMap.copper.top;
255
470
  if (hole.shape === "circle") {
471
+ if (hasSoldermask && margin > 0) {
472
+ drawCircle({
473
+ ctx,
474
+ center: { x: hole.x, y: hole.y },
475
+ radius: hole.outer_diameter / 2 + margin,
476
+ fill: positiveMarginColor,
477
+ realToCanvasMat
478
+ });
479
+ }
256
480
  drawCircle({
257
481
  ctx,
258
482
  center: { x: hole.x, y: hole.y },
259
483
  radius: hole.outer_diameter / 2,
260
- fill: colorMap.copper.top,
484
+ fill: copperColor,
261
485
  realToCanvasMat
262
486
  });
487
+ if (hasSoldermask && margin < 0) {
488
+ drawSoldermaskRingForCircle(
489
+ ctx,
490
+ { x: hole.x, y: hole.y },
491
+ hole.outer_diameter / 2,
492
+ margin,
493
+ realToCanvasMat,
494
+ soldermaskRingColor,
495
+ copperColor
496
+ );
497
+ }
263
498
  drawCircle({
264
499
  ctx,
265
500
  center: { x: hole.x, y: hole.y },
@@ -270,15 +505,39 @@ function drawPcbPlatedHole(params) {
270
505
  return;
271
506
  }
272
507
  if (hole.shape === "oval") {
508
+ if (hasSoldermask && margin > 0) {
509
+ drawOval({
510
+ ctx,
511
+ center: { x: hole.x, y: hole.y },
512
+ radius_x: hole.outer_width / 2 + margin,
513
+ radius_y: hole.outer_height / 2 + margin,
514
+ fill: positiveMarginColor,
515
+ realToCanvasMat,
516
+ rotation: hole.ccw_rotation
517
+ });
518
+ }
273
519
  drawOval({
274
520
  ctx,
275
521
  center: { x: hole.x, y: hole.y },
276
522
  radius_x: hole.outer_width / 2,
277
523
  radius_y: hole.outer_height / 2,
278
- fill: colorMap.copper.top,
524
+ fill: copperColor,
279
525
  realToCanvasMat,
280
526
  rotation: hole.ccw_rotation
281
527
  });
528
+ if (hasSoldermask && margin < 0) {
529
+ drawSoldermaskRingForOval(
530
+ ctx,
531
+ { x: hole.x, y: hole.y },
532
+ hole.outer_width / 2,
533
+ hole.outer_height / 2,
534
+ margin,
535
+ hole.ccw_rotation ?? 0,
536
+ realToCanvasMat,
537
+ soldermaskRingColor,
538
+ copperColor
539
+ );
540
+ }
282
541
  drawOval({
283
542
  ctx,
284
543
  center: { x: hole.x, y: hole.y },
@@ -291,15 +550,39 @@ function drawPcbPlatedHole(params) {
291
550
  return;
292
551
  }
293
552
  if (hole.shape === "pill") {
553
+ if (hasSoldermask && margin > 0) {
554
+ drawPill({
555
+ ctx,
556
+ center: { x: hole.x, y: hole.y },
557
+ width: hole.outer_width + margin * 2,
558
+ height: hole.outer_height + margin * 2,
559
+ fill: positiveMarginColor,
560
+ realToCanvasMat,
561
+ rotation: hole.ccw_rotation
562
+ });
563
+ }
294
564
  drawPill({
295
565
  ctx,
296
566
  center: { x: hole.x, y: hole.y },
297
567
  width: hole.outer_width,
298
568
  height: hole.outer_height,
299
- fill: colorMap.copper.top,
569
+ fill: copperColor,
300
570
  realToCanvasMat,
301
571
  rotation: hole.ccw_rotation
302
572
  });
573
+ if (hasSoldermask && margin < 0) {
574
+ drawSoldermaskRingForPill(
575
+ ctx,
576
+ { x: hole.x, y: hole.y },
577
+ hole.outer_width,
578
+ hole.outer_height,
579
+ margin,
580
+ hole.ccw_rotation ?? 0,
581
+ realToCanvasMat,
582
+ soldermaskRingColor,
583
+ copperColor
584
+ );
585
+ }
303
586
  drawPill({
304
587
  ctx,
305
588
  center: { x: hole.x, y: hole.y },
@@ -312,15 +595,40 @@ function drawPcbPlatedHole(params) {
312
595
  return;
313
596
  }
314
597
  if (hole.shape === "circular_hole_with_rect_pad") {
598
+ if (hasSoldermask && margin > 0) {
599
+ drawRect({
600
+ ctx,
601
+ center: { x: hole.x, y: hole.y },
602
+ width: hole.rect_pad_width + margin * 2,
603
+ height: hole.rect_pad_height + margin * 2,
604
+ fill: positiveMarginColor,
605
+ realToCanvasMat,
606
+ borderRadius: (hole.rect_border_radius ?? 0) + margin
607
+ });
608
+ }
315
609
  drawRect({
316
610
  ctx,
317
611
  center: { x: hole.x, y: hole.y },
318
612
  width: hole.rect_pad_width,
319
613
  height: hole.rect_pad_height,
320
- fill: colorMap.copper.top,
614
+ fill: copperColor,
321
615
  realToCanvasMat,
322
616
  borderRadius: hole.rect_border_radius ?? 0
323
617
  });
618
+ if (hasSoldermask && margin < 0) {
619
+ drawSoldermaskRingForRect(
620
+ ctx,
621
+ { x: hole.x, y: hole.y },
622
+ hole.rect_pad_width,
623
+ hole.rect_pad_height,
624
+ margin,
625
+ hole.rect_border_radius ?? 0,
626
+ 0,
627
+ realToCanvasMat,
628
+ soldermaskRingColor,
629
+ copperColor
630
+ );
631
+ }
324
632
  const holeX = hole.x + (hole.hole_offset_x ?? 0);
325
633
  const holeY = hole.y + (hole.hole_offset_y ?? 0);
326
634
  drawCircle({
@@ -333,15 +641,40 @@ function drawPcbPlatedHole(params) {
333
641
  return;
334
642
  }
335
643
  if (hole.shape === "pill_hole_with_rect_pad") {
644
+ if (hasSoldermask && margin > 0) {
645
+ drawRect({
646
+ ctx,
647
+ center: { x: hole.x, y: hole.y },
648
+ width: hole.rect_pad_width + margin * 2,
649
+ height: hole.rect_pad_height + margin * 2,
650
+ fill: positiveMarginColor,
651
+ realToCanvasMat,
652
+ borderRadius: (hole.rect_border_radius ?? 0) + margin
653
+ });
654
+ }
336
655
  drawRect({
337
656
  ctx,
338
657
  center: { x: hole.x, y: hole.y },
339
658
  width: hole.rect_pad_width,
340
659
  height: hole.rect_pad_height,
341
- fill: colorMap.copper.top,
660
+ fill: copperColor,
342
661
  realToCanvasMat,
343
662
  borderRadius: hole.rect_border_radius ?? 0
344
663
  });
664
+ if (hasSoldermask && margin < 0) {
665
+ drawSoldermaskRingForRect(
666
+ ctx,
667
+ { x: hole.x, y: hole.y },
668
+ hole.rect_pad_width,
669
+ hole.rect_pad_height,
670
+ margin,
671
+ hole.rect_border_radius ?? 0,
672
+ 0,
673
+ realToCanvasMat,
674
+ soldermaskRingColor,
675
+ copperColor
676
+ );
677
+ }
345
678
  const holeX = hole.x + (hole.hole_offset_x ?? 0);
346
679
  const holeY = hole.y + (hole.hole_offset_y ?? 0);
347
680
  drawPill({
@@ -355,16 +688,42 @@ function drawPcbPlatedHole(params) {
355
688
  return;
356
689
  }
357
690
  if (hole.shape === "rotated_pill_hole_with_rect_pad") {
691
+ if (hasSoldermask && margin > 0) {
692
+ drawRect({
693
+ ctx,
694
+ center: { x: hole.x, y: hole.y },
695
+ width: hole.rect_pad_width + margin * 2,
696
+ height: hole.rect_pad_height + margin * 2,
697
+ fill: positiveMarginColor,
698
+ realToCanvasMat,
699
+ borderRadius: (hole.rect_border_radius ?? 0) + margin,
700
+ rotation: hole.rect_ccw_rotation
701
+ });
702
+ }
358
703
  drawRect({
359
704
  ctx,
360
705
  center: { x: hole.x, y: hole.y },
361
706
  width: hole.rect_pad_width,
362
707
  height: hole.rect_pad_height,
363
- fill: colorMap.copper.top,
708
+ fill: copperColor,
364
709
  realToCanvasMat,
365
710
  borderRadius: hole.rect_border_radius ?? 0,
366
711
  rotation: hole.rect_ccw_rotation
367
712
  });
713
+ if (hasSoldermask && margin < 0) {
714
+ drawSoldermaskRingForRect(
715
+ ctx,
716
+ { x: hole.x, y: hole.y },
717
+ hole.rect_pad_width,
718
+ hole.rect_pad_height,
719
+ margin,
720
+ hole.rect_border_radius ?? 0,
721
+ hole.rect_ccw_rotation ?? 0,
722
+ realToCanvasMat,
723
+ soldermaskRingColor,
724
+ copperColor
725
+ );
726
+ }
368
727
  const holeX = hole.x + (hole.hole_offset_x ?? 0);
369
728
  const holeY = hole.y + (hole.hole_offset_y ?? 0);
370
729
  drawPill({
@@ -388,7 +747,7 @@ function drawPcbPlatedHole(params) {
388
747
  drawPolygon({
389
748
  ctx,
390
749
  points: padPoints,
391
- fill: colorMap.copper.top,
750
+ fill: copperColor,
392
751
  realToCanvasMat
393
752
  });
394
753
  }
@@ -589,217 +948,11 @@ function drawPcbHole(params) {
589
948
  }
590
949
  }
591
950
 
592
- // lib/drawer/elements/soldermask-margin.ts
593
- import { applyToPoint as applyToPoint6 } from "transformation-matrix";
594
- function drawSoldermaskRingForRect(ctx, center, width, height, margin, borderRadius, rotation, realToCanvasMat, soldermaskColor, padColor) {
595
- const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
596
- const scaledWidth = width * Math.abs(realToCanvasMat.a);
597
- const scaledHeight = height * Math.abs(realToCanvasMat.a);
598
- const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
599
- const scaledRadius = borderRadius * Math.abs(realToCanvasMat.a);
600
- ctx.save();
601
- ctx.translate(cx, cy);
602
- if (rotation !== 0) {
603
- ctx.rotate(-rotation * (Math.PI / 180));
604
- }
605
- const prevCompositeOp = ctx.globalCompositeOperation;
606
- if (ctx.globalCompositeOperation !== void 0) {
607
- ctx.globalCompositeOperation = "source-atop";
608
- }
609
- const outerWidth = scaledWidth;
610
- const outerHeight = scaledHeight;
611
- const outerRadius = scaledRadius;
612
- ctx.beginPath();
613
- if (outerRadius > 0) {
614
- const x = -outerWidth / 2;
615
- const y = -outerHeight / 2;
616
- const r = Math.min(outerRadius, outerWidth / 2, outerHeight / 2);
617
- ctx.moveTo(x + r, y);
618
- ctx.lineTo(x + outerWidth - r, y);
619
- ctx.arcTo(x + outerWidth, y, x + outerWidth, y + r, r);
620
- ctx.lineTo(x + outerWidth, y + outerHeight - r);
621
- ctx.arcTo(
622
- x + outerWidth,
623
- y + outerHeight,
624
- x + outerWidth - r,
625
- y + outerHeight,
626
- r
627
- );
628
- ctx.lineTo(x + r, y + outerHeight);
629
- ctx.arcTo(x, y + outerHeight, x, y + outerHeight - r, r);
630
- ctx.lineTo(x, y + r);
631
- ctx.arcTo(x, y, x + r, y, r);
632
- } else {
633
- ctx.rect(-outerWidth / 2, -outerHeight / 2, outerWidth, outerHeight);
634
- }
635
- ctx.fillStyle = soldermaskColor;
636
- ctx.fill();
637
- if (ctx.globalCompositeOperation !== void 0) {
638
- ctx.globalCompositeOperation = prevCompositeOp || "source-over";
639
- }
640
- const innerWidth = scaledWidth - scaledMargin * 2;
641
- const innerHeight = scaledHeight - scaledMargin * 2;
642
- const innerRadius = Math.max(0, scaledRadius - scaledMargin);
643
- if (innerWidth > 0 && innerHeight > 0) {
644
- ctx.beginPath();
645
- if (innerRadius > 0) {
646
- const x = -innerWidth / 2;
647
- const y = -innerHeight / 2;
648
- const r = Math.min(innerRadius, innerWidth / 2, innerHeight / 2);
649
- ctx.moveTo(x + r, y);
650
- ctx.lineTo(x + innerWidth - r, y);
651
- ctx.arcTo(x + innerWidth, y, x + innerWidth, y + r, r);
652
- ctx.lineTo(x + innerWidth, y + innerHeight - r);
653
- ctx.arcTo(
654
- x + innerWidth,
655
- y + innerHeight,
656
- x + innerWidth - r,
657
- y + innerHeight,
658
- r
659
- );
660
- ctx.lineTo(x + r, y + innerHeight);
661
- ctx.arcTo(x, y + innerHeight, x, y + innerHeight - r, r);
662
- ctx.lineTo(x, y + r);
663
- ctx.arcTo(x, y, x + r, y, r);
664
- } else {
665
- ctx.rect(-innerWidth / 2, -innerHeight / 2, innerWidth, innerHeight);
666
- }
667
- ctx.fillStyle = padColor;
668
- ctx.fill();
669
- }
670
- ctx.restore();
671
- }
672
- function drawSoldermaskRingForCircle(ctx, center, radius, margin, realToCanvasMat, soldermaskColor, padColor) {
673
- const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
674
- const scaledRadius = radius * Math.abs(realToCanvasMat.a);
675
- const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
676
- ctx.save();
677
- const prevCompositeOp = ctx.globalCompositeOperation;
678
- if (ctx.globalCompositeOperation !== void 0) {
679
- ctx.globalCompositeOperation = "source-atop";
680
- }
681
- ctx.beginPath();
682
- ctx.arc(cx, cy, scaledRadius, 0, Math.PI * 2);
683
- ctx.fillStyle = soldermaskColor;
684
- ctx.fill();
685
- if (ctx.globalCompositeOperation !== void 0) {
686
- ctx.globalCompositeOperation = prevCompositeOp || "source-over";
687
- }
688
- const innerRadius = Math.max(0, scaledRadius - scaledMargin);
689
- if (innerRadius > 0) {
690
- ctx.beginPath();
691
- ctx.arc(cx, cy, innerRadius, 0, Math.PI * 2);
692
- ctx.fillStyle = padColor;
693
- ctx.fill();
694
- }
695
- ctx.restore();
696
- }
697
- function drawSoldermaskRingForPill(ctx, center, width, height, margin, rotation, realToCanvasMat, soldermaskColor, padColor) {
698
- const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
699
- const scaledWidth = width * Math.abs(realToCanvasMat.a);
700
- const scaledHeight = height * Math.abs(realToCanvasMat.a);
701
- const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
702
- ctx.save();
703
- ctx.translate(cx, cy);
704
- if (rotation !== 0) {
705
- ctx.rotate(-rotation * (Math.PI / 180));
706
- }
707
- const prevCompositeOp = ctx.globalCompositeOperation;
708
- if (ctx.globalCompositeOperation !== void 0) {
709
- ctx.globalCompositeOperation = "source-atop";
710
- }
711
- const outerWidth = scaledWidth;
712
- const outerHeight = scaledHeight;
713
- ctx.beginPath();
714
- if (outerWidth > outerHeight) {
715
- const radius = outerHeight / 2;
716
- const straightLength = outerWidth - outerHeight;
717
- ctx.moveTo(-straightLength / 2, -radius);
718
- ctx.lineTo(straightLength / 2, -radius);
719
- ctx.arc(straightLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2);
720
- ctx.lineTo(-straightLength / 2, radius);
721
- ctx.arc(-straightLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2);
722
- } else if (outerHeight > outerWidth) {
723
- const radius = outerWidth / 2;
724
- const straightLength = outerHeight - outerWidth;
725
- ctx.moveTo(radius, -straightLength / 2);
726
- ctx.lineTo(radius, straightLength / 2);
727
- ctx.arc(0, straightLength / 2, radius, 0, Math.PI);
728
- ctx.lineTo(-radius, -straightLength / 2);
729
- ctx.arc(0, -straightLength / 2, radius, Math.PI, 0);
730
- } else {
731
- ctx.arc(0, 0, outerWidth / 2, 0, Math.PI * 2);
732
- }
733
- ctx.fillStyle = soldermaskColor;
734
- ctx.fill();
735
- if (ctx.globalCompositeOperation !== void 0) {
736
- ctx.globalCompositeOperation = prevCompositeOp || "source-over";
737
- }
738
- const innerWidth = scaledWidth - scaledMargin * 2;
739
- const innerHeight = scaledHeight - scaledMargin * 2;
740
- if (innerWidth > 0 && innerHeight > 0) {
741
- ctx.beginPath();
742
- if (innerWidth > innerHeight) {
743
- const radius = innerHeight / 2;
744
- const straightLength = innerWidth - innerHeight;
745
- ctx.moveTo(-straightLength / 2, -radius);
746
- ctx.lineTo(straightLength / 2, -radius);
747
- ctx.arc(straightLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2);
748
- ctx.lineTo(-straightLength / 2, radius);
749
- ctx.arc(-straightLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2);
750
- } else if (innerHeight > innerWidth) {
751
- const radius = innerWidth / 2;
752
- const straightLength = innerHeight - innerWidth;
753
- ctx.moveTo(radius, -straightLength / 2);
754
- ctx.lineTo(radius, straightLength / 2);
755
- ctx.arc(0, straightLength / 2, radius, 0, Math.PI);
756
- ctx.lineTo(-radius, -straightLength / 2);
757
- ctx.arc(0, -straightLength / 2, radius, Math.PI, 0);
758
- } else {
759
- ctx.arc(0, 0, innerWidth / 2, 0, Math.PI * 2);
760
- }
761
- ctx.fillStyle = padColor;
762
- ctx.fill();
763
- }
764
- ctx.restore();
765
- }
766
- function drawSoldermaskRingForOval(ctx, center, radius_x, radius_y, margin, rotation, realToCanvasMat, soldermaskColor, holeColor) {
767
- const [cx, cy] = applyToPoint6(realToCanvasMat, [center.x, center.y]);
768
- const scaledRadiusX = radius_x * Math.abs(realToCanvasMat.a);
769
- const scaledRadiusY = radius_y * Math.abs(realToCanvasMat.a);
770
- const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
771
- ctx.save();
772
- ctx.translate(cx, cy);
773
- if (rotation !== 0) {
774
- ctx.rotate(-rotation * (Math.PI / 180));
775
- }
776
- const prevCompositeOp = ctx.globalCompositeOperation;
777
- if (ctx.globalCompositeOperation !== void 0) {
778
- ctx.globalCompositeOperation = "source-atop";
779
- }
780
- ctx.beginPath();
781
- ctx.ellipse(0, 0, scaledRadiusX, scaledRadiusY, 0, 0, Math.PI * 2);
782
- ctx.fillStyle = soldermaskColor;
783
- ctx.fill();
784
- if (ctx.globalCompositeOperation !== void 0) {
785
- ctx.globalCompositeOperation = prevCompositeOp || "source-over";
786
- }
787
- const innerRadiusX = Math.max(0, scaledRadiusX - scaledMargin);
788
- const innerRadiusY = Math.max(0, scaledRadiusY - scaledMargin);
789
- if (innerRadiusX > 0 && innerRadiusY > 0) {
790
- ctx.beginPath();
791
- ctx.ellipse(0, 0, innerRadiusX, innerRadiusY, 0, 0, Math.PI * 2);
792
- ctx.fillStyle = holeColor;
793
- ctx.fill();
794
- }
795
- ctx.restore();
796
- }
797
-
798
951
  // lib/drawer/elements/pcb-smtpad.ts
799
952
  function layerToColor(layer, colorMap) {
800
953
  return colorMap.copper[layer] ?? colorMap.copper.top;
801
954
  }
802
- function getSoldermaskColor(layer, colorMap) {
955
+ function getSoldermaskColor2(layer, colorMap) {
803
956
  return colorMap.soldermaskOverCopper[layer] ?? colorMap.soldermaskOverCopper.top;
804
957
  }
805
958
  function drawPcbSmtPad(params) {
@@ -807,7 +960,7 @@ function drawPcbSmtPad(params) {
807
960
  const color = layerToColor(pad.layer, colorMap);
808
961
  const hasSoldermask = pad.is_covered_with_solder_mask === true && pad.soldermask_margin !== void 0 && pad.soldermask_margin !== 0;
809
962
  const margin = hasSoldermask ? pad.soldermask_margin : 0;
810
- const soldermaskRingColor = getSoldermaskColor(pad.layer, colorMap);
963
+ const soldermaskRingColor = getSoldermaskColor2(pad.layer, colorMap);
811
964
  const positiveMarginColor = colorMap.substrate;
812
965
  if (pad.shape === "rect") {
813
966
  if (hasSoldermask && margin > 0) {
@@ -1766,78 +1919,76 @@ function drawDimensionLine(params) {
1766
1919
  x: anchor.x + extensionDirection.x * extensionLength,
1767
1920
  y: anchor.y + extensionDirection.y * extensionLength
1768
1921
  };
1769
- const halfWidth2 = strokeWidth / 2;
1922
+ const halfWidth = strokeWidth / 2;
1770
1923
  const extPerpendicular = {
1771
1924
  x: -extensionDirection.y,
1772
1925
  y: extensionDirection.x
1773
1926
  };
1774
1927
  return [
1775
1928
  {
1776
- x: anchor.x + extPerpendicular.x * halfWidth2,
1777
- y: anchor.y + extPerpendicular.y * halfWidth2
1929
+ x: anchor.x + extPerpendicular.x * halfWidth,
1930
+ y: anchor.y + extPerpendicular.y * halfWidth
1778
1931
  },
1779
1932
  {
1780
- x: anchor.x - extPerpendicular.x * halfWidth2,
1781
- y: anchor.y - extPerpendicular.y * halfWidth2
1933
+ x: anchor.x - extPerpendicular.x * halfWidth,
1934
+ y: anchor.y - extPerpendicular.y * halfWidth
1782
1935
  },
1783
1936
  {
1784
- x: endPoint.x - extPerpendicular.x * halfWidth2,
1785
- y: endPoint.y - extPerpendicular.y * halfWidth2
1937
+ x: endPoint.x - extPerpendicular.x * halfWidth,
1938
+ y: endPoint.y - extPerpendicular.y * halfWidth
1786
1939
  },
1787
1940
  {
1788
- x: endPoint.x + extPerpendicular.x * halfWidth2,
1789
- y: endPoint.y + extPerpendicular.y * halfWidth2
1941
+ x: endPoint.x + extPerpendicular.x * halfWidth,
1942
+ y: endPoint.y + extPerpendicular.y * halfWidth
1790
1943
  }
1791
1944
  ];
1792
1945
  };
1793
- const ext1 = getExtensionPoints(from);
1794
- allPoints.push(...ext1, ext1[0]);
1795
- const ext2 = getExtensionPoints(to);
1796
- allPoints.push(...ext2, ext2[0]);
1797
- const halfWidth = strokeWidth / 2;
1798
- const mainLine = [
1799
- {
1800
- x: fromBase.x + perpendicular.x * halfWidth,
1801
- y: fromBase.y + perpendicular.y * halfWidth
1802
- },
1803
- {
1804
- x: fromBase.x - perpendicular.x * halfWidth,
1805
- y: fromBase.y - perpendicular.y * halfWidth
1806
- },
1807
- {
1808
- x: toBase.x - perpendicular.x * halfWidth,
1809
- y: toBase.y - perpendicular.y * halfWidth
1810
- },
1811
- {
1812
- x: toBase.x + perpendicular.x * halfWidth,
1813
- y: toBase.y + perpendicular.y * halfWidth
1814
- }
1815
- ];
1816
- allPoints.push(...mainLine, mainLine[0]);
1817
- const arrow1 = [
1818
- fromOffset,
1819
- {
1820
- x: fromOffset.x + direction.x * arrowSize + perpendicular.x * (arrowSize / 2),
1821
- y: fromOffset.y + direction.y * arrowSize + perpendicular.y * (arrowSize / 2)
1822
- },
1823
- {
1824
- x: fromOffset.x + direction.x * arrowSize - perpendicular.x * (arrowSize / 2),
1825
- y: fromOffset.y + direction.y * arrowSize - perpendicular.y * (arrowSize / 2)
1826
- }
1827
- ];
1828
- allPoints.push(...arrow1, arrow1[0]);
1829
- const arrow2 = [
1830
- toOffset,
1831
- {
1832
- x: toOffset.x - direction.x * arrowSize + perpendicular.x * (arrowSize / 2),
1833
- y: toOffset.y - direction.y * arrowSize + perpendicular.y * (arrowSize / 2)
1834
- },
1835
- {
1836
- x: toOffset.x - direction.x * arrowSize - perpendicular.x * (arrowSize / 2),
1837
- y: toOffset.y - direction.y * arrowSize - perpendicular.y * (arrowSize / 2)
1838
- }
1839
- ];
1840
- allPoints.push(...arrow2, arrow2[0]);
1946
+ allPoints.push(fromOffset);
1947
+ allPoints.push({
1948
+ x: fromBase.x + perpendicular.x * (arrowSize / 2),
1949
+ y: fromBase.y + perpendicular.y * (arrowSize / 2)
1950
+ });
1951
+ allPoints.push({
1952
+ x: fromBase.x + perpendicular.x * (strokeWidth / 2),
1953
+ y: fromBase.y + perpendicular.y * (strokeWidth / 2)
1954
+ });
1955
+ allPoints.push({
1956
+ x: toBase.x + perpendicular.x * (strokeWidth / 2),
1957
+ y: toBase.y + perpendicular.y * (strokeWidth / 2)
1958
+ });
1959
+ allPoints.push({
1960
+ x: toBase.x + perpendicular.x * (arrowSize / 2),
1961
+ y: toBase.y + perpendicular.y * (arrowSize / 2)
1962
+ });
1963
+ allPoints.push(toOffset);
1964
+ allPoints.push({
1965
+ x: toBase.x - perpendicular.x * (arrowSize / 2),
1966
+ y: toBase.y - perpendicular.y * (arrowSize / 2)
1967
+ });
1968
+ allPoints.push({
1969
+ x: toBase.x - perpendicular.x * (strokeWidth / 2),
1970
+ y: toBase.y - perpendicular.y * (strokeWidth / 2)
1971
+ });
1972
+ allPoints.push({
1973
+ x: fromBase.x - perpendicular.x * (strokeWidth / 2),
1974
+ y: fromBase.y - perpendicular.y * (strokeWidth / 2)
1975
+ });
1976
+ allPoints.push({
1977
+ x: fromBase.x - perpendicular.x * (arrowSize / 2),
1978
+ y: fromBase.y - perpendicular.y * (arrowSize / 2)
1979
+ });
1980
+ allPoints.push(fromOffset);
1981
+ const startPoint = allPoints[0];
1982
+ const addTick = (anchor) => {
1983
+ const pts = getExtensionPoints(anchor);
1984
+ allPoints.push(startPoint);
1985
+ allPoints.push(pts[0]);
1986
+ allPoints.push(...pts);
1987
+ allPoints.push(pts[0]);
1988
+ allPoints.push(startPoint);
1989
+ };
1990
+ addTick(from);
1991
+ addTick(to);
1841
1992
  drawPolygon({
1842
1993
  ctx,
1843
1994
  points: allPoints,
@@ -1873,9 +2024,9 @@ function drawDimensionLine(params) {
1873
2024
  const rotationRad = textRotation * Math.PI / 180;
1874
2025
  const sinRot = Math.abs(Math.sin(rotationRad));
1875
2026
  const cosRot = Math.abs(Math.cos(rotationRad));
1876
- const halfWidth2 = textWidth / 2;
2027
+ const halfWidth = textWidth / 2;
1877
2028
  const halfHeight = textHeight / 2;
1878
- const maxExtension = halfWidth2 * sinRot + halfHeight * cosRot;
2029
+ const maxExtension = halfWidth * sinRot + halfHeight * cosRot;
1879
2030
  additionalOffset = maxExtension + fontSize * TEXT_INTERSECTION_PADDING_MULTIPLIER;
1880
2031
  }
1881
2032
  const textOffset = arrowSize * TEXT_OFFSET_MULTIPLIER + additionalOffset;
@@ -2039,8 +2190,11 @@ var CircuitToCanvasDrawer = class {
2039
2190
  const hasSoldermaskHoles = elements.some(
2040
2191
  (el) => el.type === "pcb_hole" && el.is_covered_with_solder_mask === true
2041
2192
  );
2193
+ const hasSoldermaskPlatedHoles = elements.some(
2194
+ (el) => el.type === "pcb_plated_hole" && el.is_covered_with_solder_mask === true
2195
+ );
2042
2196
  for (const element of elements) {
2043
- if (element.type === "pcb_board" && (hasSoldermaskPads || hasSoldermaskHoles)) {
2197
+ if (element.type === "pcb_board" && (hasSoldermaskPads || hasSoldermaskHoles || hasSoldermaskPlatedHoles)) {
2044
2198
  this.drawBoardWithSoldermask(element);
2045
2199
  } else {
2046
2200
  this.drawElement(element, options);