circuit-to-canvas 0.0.31 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AnyCircuitElement, PcbRenderLayer, NinePointAnchor, PcbPlatedHole, PCBVia, PCBHole, PcbSmtPad, PCBTrace, PcbBoard, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbSilkscreenPill, PcbCutout, PcbCopperPour, PcbCopperText, PcbFabricationNoteText, PcbFabricationNoteRect, PcbNoteRect, PcbFabricationNotePath, PcbNotePath, PcbNoteText, PcbNoteDimension } from 'circuit-json';
1
+ import { AnyCircuitElement, PcbRenderLayer, NinePointAnchor, PcbPlatedHole, PCBVia, PCBHole, PcbSmtPad, PCBTrace, PcbBoard, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbSilkscreenPill, PcbSilkscreenOval, PcbCutout, PcbCopperPour, PcbCopperText, PcbFabricationNoteText, PcbFabricationNoteRect, PcbNoteRect, PcbFabricationNotePath, PcbNotePath, PcbNoteText, PcbNoteDimension, PcbFabricationNoteDimension } from 'circuit-json';
2
2
  import { Matrix } from 'transformation-matrix';
3
3
 
4
4
  /**
@@ -139,9 +139,11 @@ interface DrawOvalParams {
139
139
  x: number;
140
140
  y: number;
141
141
  };
142
- width: number;
143
- height: number;
144
- fill: string;
142
+ radius_x: number;
143
+ radius_y: number;
144
+ fill?: string;
145
+ stroke?: string;
146
+ strokeWidth?: number;
145
147
  realToCanvasMat: Matrix;
146
148
  rotation?: number;
147
149
  }
@@ -219,6 +221,33 @@ interface DrawArrowParams {
219
221
  */
220
222
  declare function drawArrow(params: DrawArrowParams): void;
221
223
 
224
+ interface DrawDimensionLineParams {
225
+ ctx: CanvasContext;
226
+ from: {
227
+ x: number;
228
+ y: number;
229
+ };
230
+ to: {
231
+ x: number;
232
+ y: number;
233
+ };
234
+ realToCanvasMat: Matrix;
235
+ color: string;
236
+ fontSize: number;
237
+ arrowSize?: number;
238
+ strokeWidth?: number;
239
+ text?: string;
240
+ textRotation?: number;
241
+ offset?: {
242
+ distance: number;
243
+ direction: {
244
+ x: number;
245
+ y: number;
246
+ };
247
+ };
248
+ }
249
+ declare function drawDimensionLine(params: DrawDimensionLineParams): void;
250
+
222
251
  interface StrokeAlphabetTextParams {
223
252
  ctx: CanvasContext;
224
253
  text: string;
@@ -377,6 +406,14 @@ interface DrawPcbSilkscreenPillParams {
377
406
  }
378
407
  declare function drawPcbSilkscreenPill(params: DrawPcbSilkscreenPillParams): void;
379
408
 
409
+ interface DrawPcbSilkscreenOvalParams {
410
+ ctx: CanvasContext;
411
+ oval: PcbSilkscreenOval;
412
+ realToCanvasMat: Matrix;
413
+ colorMap: PcbColorMap;
414
+ }
415
+ declare function drawPcbSilkscreenOval(params: DrawPcbSilkscreenOvalParams): void;
416
+
380
417
  interface DrawPcbCutoutParams {
381
418
  ctx: CanvasContext;
382
419
  cutout: PcbCutout;
@@ -457,4 +494,12 @@ interface DrawPcbNoteDimensionParams {
457
494
  }
458
495
  declare function drawPcbNoteDimension(params: DrawPcbNoteDimensionParams): void;
459
496
 
460
- export { type AlphabetLayout, type AnchorAlignment, type CameraBounds, type CanvasContext, CircuitToCanvasDrawer, type CopperColorMap, type CopperLayerName, DEFAULT_PCB_COLOR_MAP, type DrawArrowParams, 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 DrawPcbNoteDimensionParams, type DrawPcbNotePathParams, type DrawPcbNoteRectParams, type DrawPcbNoteTextParams, type DrawPcbPlatedHoleParams, type DrawPcbSilkscreenCircleParams, type DrawPcbSilkscreenLineParams, type DrawPcbSilkscreenPathParams, type DrawPcbSilkscreenPillParams, type DrawPcbSilkscreenRectParams, type DrawPcbSilkscreenTextParams, type DrawPcbSmtPadParams, type DrawPcbTraceParams, type DrawPcbViaParams, type DrawPillParams, type DrawPolygonParams, type DrawRectParams, type DrawTextParams, type DrawerConfig, type PcbColorMap, drawArrow, drawCircle, drawLine, drawOval, drawPath, drawPcbBoard, drawPcbCopperPour, drawPcbCopperText, drawPcbCutout, drawPcbFabricationNotePath, drawPcbFabricationNoteRect, drawPcbFabricationNoteText, drawPcbHole, drawPcbNoteDimension, drawPcbNotePath, drawPcbNoteRect, drawPcbNoteText, drawPcbPlatedHole, drawPcbSilkscreenCircle, drawPcbSilkscreenLine, drawPcbSilkscreenPath, drawPcbSilkscreenPill, drawPcbSilkscreenRect, drawPcbSilkscreenText, drawPcbSmtPad, drawPcbTrace, drawPcbVia, drawPill, drawPolygon, drawRect, drawSoldermaskRingForCircle, drawSoldermaskRingForPill, drawSoldermaskRingForRect, drawText, getAlphabetLayout, getTextStartPosition, strokeAlphabetText };
497
+ interface DrawPcbFabricationNoteDimensionParams {
498
+ ctx: CanvasContext;
499
+ pcbFabricationNoteDimension: PcbFabricationNoteDimension;
500
+ realToCanvasMat: Matrix;
501
+ colorMap: PcbColorMap;
502
+ }
503
+ declare function drawPcbFabricationNoteDimension(params: DrawPcbFabricationNoteDimensionParams): void;
504
+
505
+ export { type AlphabetLayout, type AnchorAlignment, type CameraBounds, type CanvasContext, CircuitToCanvasDrawer, type CopperColorMap, type CopperLayerName, DEFAULT_PCB_COLOR_MAP, type DrawArrowParams, type DrawCircleParams, type DrawContext, type DrawDimensionLineParams, type DrawElementsOptions, type DrawLineParams, type DrawOvalParams, type DrawPathParams, type DrawPcbBoardParams, type DrawPcbCopperPourParams, type DrawPcbCopperTextParams, type DrawPcbCutoutParams, type DrawPcbFabricationNoteDimensionParams, type DrawPcbFabricationNotePathParams, type DrawPcbFabricationNoteRectParams, type DrawPcbFabricationNoteTextParams, type DrawPcbHoleParams, type DrawPcbNoteDimensionParams, type DrawPcbNotePathParams, type DrawPcbNoteRectParams, type DrawPcbNoteTextParams, type DrawPcbPlatedHoleParams, type DrawPcbSilkscreenCircleParams, type DrawPcbSilkscreenLineParams, type DrawPcbSilkscreenOvalParams, type DrawPcbSilkscreenPathParams, type DrawPcbSilkscreenPillParams, type DrawPcbSilkscreenRectParams, type DrawPcbSilkscreenTextParams, type DrawPcbSmtPadParams, type DrawPcbTraceParams, type DrawPcbViaParams, type DrawPillParams, type DrawPolygonParams, type DrawRectParams, type DrawTextParams, type DrawerConfig, type PcbColorMap, drawArrow, drawCircle, drawDimensionLine, drawLine, drawOval, drawPath, drawPcbBoard, drawPcbCopperPour, drawPcbCopperText, drawPcbCutout, drawPcbFabricationNoteDimension, drawPcbFabricationNotePath, drawPcbFabricationNoteRect, drawPcbFabricationNoteText, drawPcbHole, drawPcbNoteDimension, drawPcbNotePath, drawPcbNoteRect, drawPcbNoteText, drawPcbPlatedHole, drawPcbSilkscreenCircle, drawPcbSilkscreenLine, drawPcbSilkscreenOval, drawPcbSilkscreenPath, drawPcbSilkscreenPill, drawPcbSilkscreenRect, drawPcbSilkscreenText, drawPcbSmtPad, drawPcbTrace, drawPcbVia, drawPill, drawPolygon, drawRect, drawSoldermaskRingForCircle, drawSoldermaskRingForPill, drawSoldermaskRingForRect, drawText, getAlphabetLayout, getTextStartPosition, strokeAlphabetText };
package/dist/index.js CHANGED
@@ -138,24 +138,34 @@ function drawOval(params) {
138
138
  const {
139
139
  ctx,
140
140
  center,
141
- width,
142
- height,
141
+ radius_x,
142
+ radius_y,
143
143
  fill,
144
+ stroke,
145
+ strokeWidth = 0.1,
144
146
  realToCanvasMat,
145
147
  rotation = 0
146
148
  } = params;
147
149
  const [cx, cy] = applyToPoint3(realToCanvasMat, [center.x, center.y]);
148
- const scaledWidth = width * Math.abs(realToCanvasMat.a);
149
- const scaledHeight = height * Math.abs(realToCanvasMat.a);
150
+ const scaledRadiusX = radius_x * Math.abs(realToCanvasMat.a);
151
+ const scaledRadiusY = radius_y * Math.abs(realToCanvasMat.a);
152
+ const scaledStrokeWidth = strokeWidth * Math.abs(realToCanvasMat.a);
150
153
  ctx.save();
151
154
  ctx.translate(cx, cy);
152
155
  if (rotation !== 0) {
153
156
  ctx.rotate(-rotation * (Math.PI / 180));
154
157
  }
155
158
  ctx.beginPath();
156
- ctx.ellipse(0, 0, scaledWidth / 2, scaledHeight / 2, 0, 0, Math.PI * 2);
157
- ctx.fillStyle = fill;
158
- ctx.fill();
159
+ ctx.ellipse(0, 0, scaledRadiusX, scaledRadiusY, 0, 0, Math.PI * 2);
160
+ if (fill) {
161
+ ctx.fillStyle = fill;
162
+ ctx.fill();
163
+ }
164
+ if (stroke) {
165
+ ctx.strokeStyle = stroke;
166
+ ctx.lineWidth = scaledStrokeWidth;
167
+ ctx.stroke();
168
+ }
159
169
  ctx.restore();
160
170
  }
161
171
 
@@ -263,8 +273,8 @@ function drawPcbPlatedHole(params) {
263
273
  drawOval({
264
274
  ctx,
265
275
  center: { x: hole.x, y: hole.y },
266
- width: hole.outer_width,
267
- height: hole.outer_height,
276
+ radius_x: hole.outer_width / 2,
277
+ radius_y: hole.outer_height / 2,
268
278
  fill: colorMap.copper.top,
269
279
  realToCanvasMat,
270
280
  rotation: hole.ccw_rotation
@@ -272,8 +282,8 @@ function drawPcbPlatedHole(params) {
272
282
  drawOval({
273
283
  ctx,
274
284
  center: { x: hole.x, y: hole.y },
275
- width: hole.hole_width,
276
- height: hole.hole_height,
285
+ radius_x: hole.hole_width / 2,
286
+ radius_y: hole.hole_height / 2,
277
287
  fill: colorMap.drill,
278
288
  realToCanvasMat,
279
289
  rotation: hole.ccw_rotation
@@ -397,8 +407,8 @@ function drawPcbPlatedHole(params) {
397
407
  drawOval({
398
408
  ctx,
399
409
  center: { x: holeX, y: holeY },
400
- width: hole.hole_width ?? 0,
401
- height: hole.hole_height ?? 0,
410
+ radius_x: (hole.hole_width ?? 0) / 2,
411
+ radius_y: (hole.hole_height ?? 0) / 2,
402
412
  fill: colorMap.drill,
403
413
  realToCanvasMat
404
414
  });
@@ -472,8 +482,8 @@ function drawPcbHole(params) {
472
482
  drawOval({
473
483
  ctx,
474
484
  center: { x: hole.x, y: hole.y },
475
- width: hole.hole_width,
476
- height: hole.hole_height,
485
+ radius_x: hole.hole_width / 2,
486
+ radius_y: hole.hole_height / 2,
477
487
  fill: colorMap.drill,
478
488
  realToCanvasMat
479
489
  });
@@ -1275,13 +1285,32 @@ function drawPcbSilkscreenPath(params) {
1275
1285
  }
1276
1286
  }
1277
1287
 
1278
- // lib/drawer/elements/pcb-silkscreen-pill.ts
1288
+ // lib/drawer/elements/pcb-silkscreen-oval.ts
1279
1289
  function layerToSilkscreenColor6(layer, colorMap) {
1280
1290
  return layer === "bottom" ? colorMap.silkscreen.bottom : colorMap.silkscreen.top;
1281
1291
  }
1292
+ function drawPcbSilkscreenOval(params) {
1293
+ const { ctx, oval, realToCanvasMat, colorMap } = params;
1294
+ const color = layerToSilkscreenColor6(oval.layer, colorMap);
1295
+ drawOval({
1296
+ ctx,
1297
+ center: oval.center,
1298
+ radius_x: oval.radius_x,
1299
+ radius_y: oval.radius_y,
1300
+ stroke: color,
1301
+ strokeWidth: 0.1,
1302
+ realToCanvasMat,
1303
+ rotation: oval.ccw_rotation ?? 0
1304
+ });
1305
+ }
1306
+
1307
+ // lib/drawer/elements/pcb-silkscreen-pill.ts
1308
+ function layerToSilkscreenColor7(layer, colorMap) {
1309
+ return layer === "bottom" ? colorMap.silkscreen.bottom : colorMap.silkscreen.top;
1310
+ }
1282
1311
  function drawPcbSilkscreenPill(params) {
1283
1312
  const { ctx, pill, realToCanvasMat, colorMap } = params;
1284
- const color = layerToSilkscreenColor6(pill.layer, colorMap);
1313
+ const color = layerToSilkscreenColor7(pill.layer, colorMap);
1285
1314
  const strokeWidth = 0.2;
1286
1315
  drawPill({
1287
1316
  ctx,
@@ -1589,7 +1618,7 @@ function drawPcbNoteText(params) {
1589
1618
  });
1590
1619
  }
1591
1620
 
1592
- // lib/drawer/elements/pcb-note-dimension.ts
1621
+ // lib/drawer/shapes/dimension-line.ts
1593
1622
  import { applyToPoint as applyToPoint13 } from "transformation-matrix";
1594
1623
 
1595
1624
  // lib/drawer/shapes/arrow.ts
@@ -1611,134 +1640,208 @@ function drawArrow(params) {
1611
1640
  ctx.restore();
1612
1641
  }
1613
1642
 
1614
- // lib/drawer/elements/pcb-note-dimension.ts
1615
- var DEFAULT_NOTE_COLOR = "rgba(255,255,255,0.5)";
1616
- function drawPcbNoteDimension(params) {
1617
- const { ctx, pcbNoteDimension, realToCanvasMat } = params;
1618
- const color = pcbNoteDimension.color ?? DEFAULT_NOTE_COLOR;
1619
- const arrowSize = pcbNoteDimension.arrow_size;
1620
- const realFromX = pcbNoteDimension.from.x;
1621
- const realFromY = pcbNoteDimension.from.y;
1622
- const realToX = pcbNoteDimension.to.x;
1623
- const realToY = pcbNoteDimension.to.y;
1624
- let fromX = realFromX;
1625
- let fromY = realFromY;
1626
- let toX = realToX;
1627
- let toY = realToY;
1628
- let hasOffset = false;
1629
- let offsetX = 0;
1630
- let offsetY = 0;
1631
- if (pcbNoteDimension.offset_distance && pcbNoteDimension.offset_direction) {
1632
- const dirX = pcbNoteDimension.offset_direction.x;
1633
- const dirY = pcbNoteDimension.offset_direction.y;
1634
- const length = Math.hypot(dirX, dirY);
1635
- if (length > 0) {
1636
- const normX = dirX / length;
1637
- const normY = dirY / length;
1638
- hasOffset = true;
1639
- offsetX = pcbNoteDimension.offset_distance * normX;
1640
- offsetY = pcbNoteDimension.offset_distance * normY;
1641
- fromX += offsetX;
1642
- fromY += offsetY;
1643
- toX += offsetX;
1644
- toY += offsetY;
1645
- }
1646
- }
1647
- const STROKE_WIDTH_RATIO2 = 0.13;
1648
- const strokeWidth = Math.max(
1649
- pcbNoteDimension.font_size * STROKE_WIDTH_RATIO2,
1650
- 0.35
1651
- );
1652
- if (hasOffset) {
1653
- drawLine({
1654
- ctx,
1655
- start: { x: realFromX, y: realFromY },
1656
- end: { x: fromX, y: fromY },
1657
- strokeWidth,
1658
- stroke: color,
1659
- realToCanvasMat
1660
- });
1643
+ // lib/drawer/shapes/dimension-line.ts
1644
+ var TEXT_OFFSET_MULTIPLIER = 1.5;
1645
+ var CHARACTER_WIDTH_MULTIPLIER = 0.6;
1646
+ var TEXT_INTERSECTION_PADDING_MULTIPLIER = 0.3;
1647
+ function normalize(v) {
1648
+ const len = Math.hypot(v.x, v.y) || 1;
1649
+ return { x: v.x / len, y: v.y / len };
1650
+ }
1651
+ function drawDimensionLine(params) {
1652
+ const {
1653
+ ctx,
1654
+ from,
1655
+ to,
1656
+ realToCanvasMat,
1657
+ color,
1658
+ fontSize,
1659
+ arrowSize = 1,
1660
+ strokeWidth: manualStrokeWidth,
1661
+ text,
1662
+ textRotation,
1663
+ offset
1664
+ } = params;
1665
+ const direction = normalize({ x: to.x - from.x, y: to.y - from.y });
1666
+ const perpendicular = { x: -direction.y, y: direction.x };
1667
+ const hasOffsetDirection = offset?.direction && typeof offset.direction.x === "number" && typeof offset.direction.y === "number";
1668
+ const normalizedOffsetDirection = hasOffsetDirection ? normalize(offset.direction) : { x: 0, y: 0 };
1669
+ const offsetMagnitude = offset?.distance ?? 0;
1670
+ const offsetVector = {
1671
+ x: normalizedOffsetDirection.x * offsetMagnitude,
1672
+ y: normalizedOffsetDirection.y * offsetMagnitude
1673
+ };
1674
+ const fromOffset = { x: from.x + offsetVector.x, y: from.y + offsetVector.y };
1675
+ const toOffset = { x: to.x + offsetVector.x, y: to.y + offsetVector.y };
1676
+ const fromBase = {
1677
+ x: fromOffset.x + direction.x * arrowSize,
1678
+ y: fromOffset.y + direction.y * arrowSize
1679
+ };
1680
+ const toBase = {
1681
+ x: toOffset.x - direction.x * arrowSize,
1682
+ y: toOffset.y - direction.y * arrowSize
1683
+ };
1684
+ const scaleValue = Math.abs(realToCanvasMat.a);
1685
+ const strokeWidth = manualStrokeWidth ?? arrowSize / 5;
1686
+ const lineColor = color || "rgba(255,255,255,0.5)";
1687
+ const extensionDirection = hasOffsetDirection && (Math.abs(normalizedOffsetDirection.x) > Number.EPSILON || Math.abs(normalizedOffsetDirection.y) > Number.EPSILON) ? normalizedOffsetDirection : perpendicular;
1688
+ const extensionLength = offsetMagnitude + 0.5;
1689
+ const drawExtension = (anchor) => {
1690
+ const endPoint = {
1691
+ x: anchor.x + extensionDirection.x * extensionLength,
1692
+ y: anchor.y + extensionDirection.y * extensionLength
1693
+ };
1661
1694
  drawLine({
1662
1695
  ctx,
1663
- start: { x: realToX, y: realToY },
1664
- end: { x: toX, y: toY },
1696
+ start: anchor,
1697
+ end: endPoint,
1665
1698
  strokeWidth,
1666
- stroke: color,
1699
+ stroke: lineColor,
1667
1700
  realToCanvasMat
1668
1701
  });
1669
- }
1702
+ };
1703
+ drawExtension(from);
1704
+ drawExtension(to);
1670
1705
  drawLine({
1671
1706
  ctx,
1672
- start: { x: fromX, y: fromY },
1673
- end: { x: toX, y: toY },
1707
+ start: fromBase,
1708
+ end: toBase,
1674
1709
  strokeWidth,
1675
- stroke: color,
1710
+ stroke: lineColor,
1676
1711
  realToCanvasMat
1677
1712
  });
1678
1713
  const [canvasFromX, canvasFromY] = applyToPoint13(realToCanvasMat, [
1679
- fromX,
1680
- fromY
1714
+ fromOffset.x,
1715
+ fromOffset.y
1681
1716
  ]);
1682
- const [canvasToX, canvasToY] = applyToPoint13(realToCanvasMat, [toX, toY]);
1683
- const canvasDx = canvasToX - canvasFromX;
1684
- const canvasDy = canvasToY - canvasFromY;
1685
- const lineAngle = Math.atan2(canvasDy, canvasDx);
1686
- const scale2 = Math.abs(realToCanvasMat.a);
1687
- const scaledArrowSize = arrowSize * scale2;
1688
- const scaledStrokeWidth = strokeWidth * scale2;
1717
+ const [canvasToX, canvasToY] = applyToPoint13(realToCanvasMat, [
1718
+ toOffset.x,
1719
+ toOffset.y
1720
+ ]);
1721
+ const [canvasToDirX, canvasToDirY] = applyToPoint13(realToCanvasMat, [
1722
+ toOffset.x + direction.x,
1723
+ toOffset.y + direction.y
1724
+ ]);
1725
+ const canvasLineAngle = Math.atan2(
1726
+ canvasToDirY - canvasToY,
1727
+ canvasToDirX - canvasToX
1728
+ );
1689
1729
  drawArrow({
1690
1730
  ctx,
1691
1731
  x: canvasFromX,
1692
1732
  y: canvasFromY,
1693
- angle: lineAngle + Math.PI,
1694
- arrowSize: scaledArrowSize,
1695
- color,
1696
- strokeWidth: scaledStrokeWidth
1733
+ angle: canvasLineAngle + Math.PI,
1734
+ arrowSize: arrowSize * scaleValue,
1735
+ color: lineColor,
1736
+ strokeWidth: strokeWidth * scaleValue
1697
1737
  });
1698
1738
  drawArrow({
1699
1739
  ctx,
1700
1740
  x: canvasToX,
1701
1741
  y: canvasToY,
1702
- angle: lineAngle,
1703
- arrowSize: scaledArrowSize,
1704
- color,
1705
- strokeWidth: scaledStrokeWidth
1742
+ angle: canvasLineAngle,
1743
+ arrowSize: arrowSize * scaleValue,
1744
+ color: lineColor,
1745
+ strokeWidth: strokeWidth * scaleValue
1706
1746
  });
1707
- if (pcbNoteDimension.text) {
1708
- let textX = (fromX + toX) / 2;
1709
- let textY = (fromY + toY) / 2;
1710
- const perpX = toY - fromY;
1711
- const perpY = -(toX - fromX);
1712
- const perpLength = Math.sqrt(perpX * perpX + perpY * perpY);
1713
- if (perpLength > 0) {
1714
- const offsetDistance = pcbNoteDimension.font_size * 1.5;
1715
- const normalizedPerpX = perpX / perpLength;
1716
- const normalizedPerpY = perpY / perpLength;
1717
- textX += normalizedPerpX * offsetDistance;
1718
- textY += normalizedPerpY * offsetDistance;
1747
+ if (text) {
1748
+ const midPoint = {
1749
+ x: (from.x + to.x) / 2 + offsetVector.x,
1750
+ y: (from.y + to.y) / 2 + offsetVector.y
1751
+ };
1752
+ const [screenFromX, screenFromY] = applyToPoint13(realToCanvasMat, [
1753
+ fromOffset.x,
1754
+ fromOffset.y
1755
+ ]);
1756
+ const [screenToX, screenToY] = applyToPoint13(realToCanvasMat, [
1757
+ toOffset.x,
1758
+ toOffset.y
1759
+ ]);
1760
+ const screenDirection = normalize({
1761
+ x: screenToX - screenFromX,
1762
+ y: screenToY - screenFromY
1763
+ });
1764
+ let textAngle = Math.atan2(screenDirection.y, screenDirection.x) * 180 / Math.PI;
1765
+ if (textAngle > 90 || textAngle < -90) {
1766
+ textAngle += 180;
1719
1767
  }
1720
- const textRotation = -(() => {
1721
- const raw = pcbNoteDimension.text_ccw_rotation ?? lineAngle * 180 / Math.PI;
1722
- if (pcbNoteDimension.text_ccw_rotation !== void 0) return raw;
1723
- let deg = (raw + 180) % 360 - 180;
1724
- if (deg > 90) deg -= 180;
1725
- if (deg < -90) deg += 180;
1726
- return deg;
1727
- })();
1768
+ const finalTextAngle = typeof textRotation === "number" && Number.isFinite(textRotation) ? textAngle - textRotation : textAngle;
1769
+ let additionalOffset = 0;
1770
+ if (text && typeof textRotation === "number" && Number.isFinite(textRotation)) {
1771
+ const textWidth = text.length * fontSize * CHARACTER_WIDTH_MULTIPLIER;
1772
+ const textHeight = fontSize;
1773
+ const rotationRad = textRotation * Math.PI / 180;
1774
+ const sinRot = Math.abs(Math.sin(rotationRad));
1775
+ const cosRot = Math.abs(Math.cos(rotationRad));
1776
+ const halfWidth = textWidth / 2;
1777
+ const halfHeight = textHeight / 2;
1778
+ const maxExtension = halfWidth * sinRot + halfHeight * cosRot;
1779
+ additionalOffset = maxExtension + fontSize * TEXT_INTERSECTION_PADDING_MULTIPLIER;
1780
+ }
1781
+ const textOffset = arrowSize * TEXT_OFFSET_MULTIPLIER + additionalOffset;
1782
+ const textPoint = {
1783
+ x: midPoint.x + perpendicular.x * textOffset,
1784
+ y: midPoint.y + perpendicular.y * textOffset
1785
+ };
1728
1786
  drawText({
1729
1787
  ctx,
1730
- text: pcbNoteDimension.text,
1731
- x: textX,
1732
- y: textY,
1733
- fontSize: pcbNoteDimension.font_size,
1734
- color,
1788
+ text,
1789
+ x: textPoint.x,
1790
+ y: textPoint.y,
1791
+ fontSize,
1792
+ color: lineColor,
1735
1793
  realToCanvasMat,
1736
1794
  anchorAlignment: "center",
1737
- rotation: textRotation
1795
+ rotation: -finalTextAngle
1796
+ // drawText expects CCW rotation in degrees
1738
1797
  });
1739
1798
  }
1740
1799
  }
1741
1800
 
1801
+ // lib/drawer/elements/pcb-note-dimension.ts
1802
+ var DEFAULT_NOTE_COLOR = "rgba(255,255,255,0.5)";
1803
+ function drawPcbNoteDimension(params) {
1804
+ const { ctx, pcbNoteDimension, realToCanvasMat } = params;
1805
+ const color = pcbNoteDimension.color ?? DEFAULT_NOTE_COLOR;
1806
+ drawDimensionLine({
1807
+ ctx,
1808
+ from: pcbNoteDimension.from,
1809
+ to: pcbNoteDimension.to,
1810
+ realToCanvasMat,
1811
+ color,
1812
+ fontSize: pcbNoteDimension.font_size,
1813
+ arrowSize: pcbNoteDimension.arrow_size,
1814
+ text: pcbNoteDimension.text,
1815
+ textRotation: pcbNoteDimension.text_ccw_rotation,
1816
+ offset: pcbNoteDimension.offset_distance && pcbNoteDimension.offset_direction ? {
1817
+ distance: pcbNoteDimension.offset_distance,
1818
+ direction: pcbNoteDimension.offset_direction
1819
+ } : void 0
1820
+ });
1821
+ }
1822
+
1823
+ // lib/drawer/elements/pcb-fabrication-note-dimension.ts
1824
+ var DEFAULT_FABRICATION_NOTE_COLOR2 = "rgba(255,255,255,0.5)";
1825
+ function drawPcbFabricationNoteDimension(params) {
1826
+ const { ctx, pcbFabricationNoteDimension, realToCanvasMat } = params;
1827
+ const color = pcbFabricationNoteDimension.color ?? DEFAULT_FABRICATION_NOTE_COLOR2;
1828
+ drawDimensionLine({
1829
+ ctx,
1830
+ from: pcbFabricationNoteDimension.from,
1831
+ to: pcbFabricationNoteDimension.to,
1832
+ realToCanvasMat,
1833
+ color,
1834
+ fontSize: pcbFabricationNoteDimension.font_size ?? 1,
1835
+ arrowSize: pcbFabricationNoteDimension.arrow_size ?? 1,
1836
+ text: pcbFabricationNoteDimension.text,
1837
+ textRotation: pcbFabricationNoteDimension.text_ccw_rotation,
1838
+ offset: pcbFabricationNoteDimension.offset_distance && pcbFabricationNoteDimension.offset_direction ? {
1839
+ distance: pcbFabricationNoteDimension.offset_distance,
1840
+ direction: pcbFabricationNoteDimension.offset_direction
1841
+ } : void 0
1842
+ });
1843
+ }
1844
+
1742
1845
  // lib/drawer/elements/pcb-note-line.ts
1743
1846
  import { applyToPoint as applyToPoint14 } from "transformation-matrix";
1744
1847
  function drawPcbNoteLine(params) {
@@ -2002,6 +2105,14 @@ var CircuitToCanvasDrawer = class {
2002
2105
  colorMap: this.colorMap
2003
2106
  });
2004
2107
  }
2108
+ if (element.type === "pcb_silkscreen_oval") {
2109
+ drawPcbSilkscreenOval({
2110
+ ctx: this.ctx,
2111
+ oval: element,
2112
+ realToCanvasMat: this.realToCanvasMat,
2113
+ colorMap: this.colorMap
2114
+ });
2115
+ }
2005
2116
  if (element.type === "pcb_cutout") {
2006
2117
  drawPcbCutout({
2007
2118
  ctx: this.ctx,
@@ -2090,6 +2201,14 @@ var CircuitToCanvasDrawer = class {
2090
2201
  colorMap: this.colorMap
2091
2202
  });
2092
2203
  }
2204
+ if (element.type === "pcb_fabrication_note_dimension") {
2205
+ drawPcbFabricationNoteDimension({
2206
+ ctx: this.ctx,
2207
+ pcbFabricationNoteDimension: element,
2208
+ realToCanvasMat: this.realToCanvasMat,
2209
+ colorMap: this.colorMap
2210
+ });
2211
+ }
2093
2212
  }
2094
2213
  };
2095
2214
  export {
@@ -2097,6 +2216,7 @@ export {
2097
2216
  DEFAULT_PCB_COLOR_MAP,
2098
2217
  drawArrow,
2099
2218
  drawCircle,
2219
+ drawDimensionLine,
2100
2220
  drawLine,
2101
2221
  drawOval,
2102
2222
  drawPath,
@@ -2104,6 +2224,7 @@ export {
2104
2224
  drawPcbCopperPour,
2105
2225
  drawPcbCopperText,
2106
2226
  drawPcbCutout,
2227
+ drawPcbFabricationNoteDimension,
2107
2228
  drawPcbFabricationNotePath,
2108
2229
  drawPcbFabricationNoteRect,
2109
2230
  drawPcbFabricationNoteText,
@@ -2115,6 +2236,7 @@ export {
2115
2236
  drawPcbPlatedHole,
2116
2237
  drawPcbSilkscreenCircle,
2117
2238
  drawPcbSilkscreenLine,
2239
+ drawPcbSilkscreenOval,
2118
2240
  drawPcbSilkscreenPath,
2119
2241
  drawPcbSilkscreenPill,
2120
2242
  drawPcbSilkscreenRect,
@@ -10,6 +10,7 @@ import type {
10
10
  PcbSilkscreenRect,
11
11
  PcbSilkscreenCircle,
12
12
  PcbSilkscreenLine,
13
+ PcbSilkscreenOval,
13
14
  PcbSilkscreenPath,
14
15
  PcbSilkscreenPill,
15
16
  PcbCutout,
@@ -22,6 +23,7 @@ import type {
22
23
  PcbNotePath,
23
24
  PcbNoteText,
24
25
  PcbNoteDimension,
26
+ PcbFabricationNoteDimension,
25
27
  PcbNoteLine,
26
28
  PcbRenderLayer,
27
29
  } from "circuit-json"
@@ -54,6 +56,7 @@ import { drawPcbSilkscreenRect } from "./elements/pcb-silkscreen-rect"
54
56
  import { drawPcbSilkscreenCircle } from "./elements/pcb-silkscreen-circle"
55
57
  import { drawPcbSilkscreenLine } from "./elements/pcb-silkscreen-line"
56
58
  import { drawPcbSilkscreenPath } from "./elements/pcb-silkscreen-path"
59
+ import { drawPcbSilkscreenOval } from "./elements/pcb-silkscreen-oval"
57
60
  import { drawPcbSilkscreenPill } from "./elements/pcb-silkscreen-pill"
58
61
  import { drawPcbCutout } from "./elements/pcb-cutout"
59
62
  import { drawPcbCopperPour } from "./elements/pcb-copper-pour"
@@ -65,6 +68,7 @@ import { drawPcbFabricationNotePath } from "./elements/pcb-fabrication-note-path
65
68
  import { drawPcbNotePath } from "./elements/pcb-note-path"
66
69
  import { drawPcbNoteText } from "./elements/pcb-note-text"
67
70
  import { drawPcbNoteDimension } from "./elements/pcb-note-dimension"
71
+ import { drawPcbFabricationNoteDimension } from "./elements/pcb-fabrication-note-dimension"
68
72
  import { drawPcbNoteLine } from "./elements/pcb-note-line"
69
73
 
70
74
  export interface DrawElementsOptions {
@@ -373,6 +377,15 @@ export class CircuitToCanvasDrawer {
373
377
  })
374
378
  }
375
379
 
380
+ if (element.type === "pcb_silkscreen_oval") {
381
+ drawPcbSilkscreenOval({
382
+ ctx: this.ctx,
383
+ oval: element as PcbSilkscreenOval,
384
+ realToCanvasMat: this.realToCanvasMat,
385
+ colorMap: this.colorMap,
386
+ })
387
+ }
388
+
376
389
  if (element.type === "pcb_cutout") {
377
390
  drawPcbCutout({
378
391
  ctx: this.ctx,
@@ -471,5 +484,14 @@ export class CircuitToCanvasDrawer {
471
484
  colorMap: this.colorMap,
472
485
  })
473
486
  }
487
+
488
+ if (element.type === "pcb_fabrication_note_dimension") {
489
+ drawPcbFabricationNoteDimension({
490
+ ctx: this.ctx,
491
+ pcbFabricationNoteDimension: element as PcbFabricationNoteDimension,
492
+ realToCanvasMat: this.realToCanvasMat,
493
+ colorMap: this.colorMap,
494
+ })
495
+ }
474
496
  }
475
497
  }
@@ -48,6 +48,11 @@ export {
48
48
  type DrawPcbSilkscreenPillParams,
49
49
  } from "./pcb-silkscreen-pill"
50
50
 
51
+ export {
52
+ drawPcbSilkscreenOval,
53
+ type DrawPcbSilkscreenOvalParams,
54
+ } from "./pcb-silkscreen-oval"
55
+
51
56
  export { drawPcbCutout, type DrawPcbCutoutParams } from "./pcb-cutout"
52
57
 
53
58
  export {
@@ -94,3 +99,8 @@ export {
94
99
  drawPcbNoteDimension,
95
100
  type DrawPcbNoteDimensionParams,
96
101
  } from "./pcb-note-dimension"
102
+
103
+ export {
104
+ drawPcbFabricationNoteDimension,
105
+ type DrawPcbFabricationNoteDimensionParams,
106
+ } from "./pcb-fabrication-note-dimension"