circuit-to-svg 0.0.295 → 0.0.297

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
@@ -2751,12 +2751,13 @@ var CHAR_WIDTH = 1;
2751
2751
  var CHAR_SPACING = 0.2;
2752
2752
  var LINE_HEIGHT = 1.4;
2753
2753
  var FONT_SCALE = 0.53;
2754
- function linesToPathData(lines, offsetX, offsetY, charScale) {
2754
+ var BASELINE_Y = 0.241;
2755
+ function linesToPathData(lines, offsetX, offsetY, charScale, baselineAdjust = 0) {
2755
2756
  return lines.map((line) => {
2756
2757
  const x1 = offsetX + line.x1 * charScale;
2757
- const y1 = offsetY + (1 - line.y1) * charScale;
2758
+ const y1 = offsetY + (1 - line.y1 + baselineAdjust) * charScale;
2758
2759
  const x2 = offsetX + line.x2 * charScale;
2759
- const y2 = offsetY + (1 - line.y2) * charScale;
2760
+ const y2 = offsetY + (1 - line.y2 + baselineAdjust) * charScale;
2760
2761
  return `M${x1} ${y1}L${x2} ${y2}`;
2761
2762
  }).join(" ");
2762
2763
  }
@@ -2771,7 +2772,9 @@ function textToAlphabetPath(text, fontSize) {
2771
2772
  }
2772
2773
  const lines = lineAlphabet[char];
2773
2774
  if (lines) {
2774
- paths.push(linesToPathData(lines, x, 0, fontSize));
2775
+ const isLowercase = char >= "a" && char <= "z";
2776
+ const baselineAdjust = isLowercase ? BASELINE_Y : 0;
2777
+ paths.push(linesToPathData(lines, x, 0, fontSize, baselineAdjust));
2775
2778
  }
2776
2779
  x += charAdvance;
2777
2780
  }
@@ -2804,7 +2807,9 @@ function textToCenteredAlphabetPaths(text, fontSize) {
2804
2807
  }
2805
2808
  const charLines = lineAlphabet[char];
2806
2809
  if (charLines) {
2807
- paths.push(linesToPathData(charLines, x, y, fontSize));
2810
+ const isLowercase = char >= "a" && char <= "z";
2811
+ const baselineAdjust = isLowercase ? BASELINE_Y : 0;
2812
+ paths.push(linesToPathData(charLines, x, y, fontSize, baselineAdjust));
2808
2813
  }
2809
2814
  x += charAdvance;
2810
2815
  }
@@ -2875,7 +2880,6 @@ function createSvgObjectsFromPcbCopperText(pcbCopperText, ctx) {
2875
2880
  id: maskId
2876
2881
  },
2877
2882
  children: [
2878
- // White background - area that will show copper
2879
2883
  {
2880
2884
  name: "rect",
2881
2885
  type: "element",
@@ -2889,7 +2893,6 @@ function createSvgObjectsFromPcbCopperText(pcbCopperText, ctx) {
2889
2893
  },
2890
2894
  children: []
2891
2895
  },
2892
- // Black text strokes - area that will be cut out
2893
2896
  {
2894
2897
  name: "path",
2895
2898
  type: "element",
@@ -3774,13 +3777,17 @@ import { applyToPoint as applyToPoint23 } from "transformation-matrix";
3774
3777
 
3775
3778
  // lib/utils/create-pcb-component-anchor-offset-indicators.ts
3776
3779
  import { applyToPoint as applyToPoint22 } from "transformation-matrix";
3777
- var OFFSET_THRESHOLD_MM = 0.01;
3780
+ var OFFSET_THRESHOLD_MM = 0.05;
3778
3781
  var TICK_SIZE_PX = 4;
3779
3782
  var LABEL_GAP_PX = 8;
3780
3783
  var LABEL_FONT_SIZE_PX = 11;
3781
3784
  var STROKE_WIDTH_PX = 1;
3782
3785
  var ANCHOR_MARKER_SIZE_PX = 5;
3783
3786
  var ANCHOR_MARKER_STROKE_WIDTH_PX = 1.5;
3787
+ var COMPONENT_ANCHOR_MARKER_RADIUS_PX = 2;
3788
+ var CONNECTOR_GROUP_GAP_PX = ANCHOR_MARKER_SIZE_PX + 2;
3789
+ var CONNECTOR_COMPONENT_GAP_PX = COMPONENT_ANCHOR_MARKER_RADIUS_PX + 2;
3790
+ var DIMENSION_ANCHOR_CLEARANCE_PX = ANCHOR_MARKER_SIZE_PX + TICK_SIZE_PX + 6;
3784
3791
  var COMPONENT_GAP_PX = 15;
3785
3792
  var COMPONENT_SIDE_GAP_PX = 10;
3786
3793
  var DISTANCE_MULTIPLIER = 0.2;
@@ -3810,14 +3817,20 @@ function createAnchorOffsetIndicators(params) {
3810
3817
  const screenComponentWidth = componentWidth * scale10;
3811
3818
  const screenComponentHeight = componentHeight * scale10;
3812
3819
  objects.push(createAnchorMarker(screenGroupAnchorX, screenGroupAnchorY));
3820
+ const trimmedConnector = getTrimmedConnectorLine(
3821
+ screenGroupAnchorX,
3822
+ screenGroupAnchorY,
3823
+ screenComponentX,
3824
+ screenComponentY
3825
+ );
3813
3826
  objects.push({
3814
3827
  name: "line",
3815
3828
  type: "element",
3816
3829
  attributes: {
3817
- x1: screenGroupAnchorX.toString(),
3818
- y1: screenGroupAnchorY.toString(),
3819
- x2: screenComponentX.toString(),
3820
- y2: screenComponentY.toString(),
3830
+ x1: trimmedConnector.x1.toString(),
3831
+ y1: trimmedConnector.y1.toString(),
3832
+ x2: trimmedConnector.x2.toString(),
3833
+ y2: trimmedConnector.y2.toString(),
3821
3834
  stroke: "#ffffff",
3822
3835
  "stroke-width": "0.5",
3823
3836
  "stroke-dasharray": "3,3",
@@ -3833,7 +3846,7 @@ function createAnchorOffsetIndicators(params) {
3833
3846
  attributes: {
3834
3847
  cx: screenComponentX.toString(),
3835
3848
  cy: screenComponentY.toString(),
3836
- r: "2",
3849
+ r: COMPONENT_ANCHOR_MARKER_RADIUS_PX.toString(),
3837
3850
  fill: "#ffffff",
3838
3851
  opacity: "0.7",
3839
3852
  class: "anchor-offset-component-marker"
@@ -3849,9 +3862,23 @@ function createAnchorOffsetIndicators(params) {
3849
3862
  componentHeightOffset,
3850
3863
  Math.min(MAX_OFFSET_PX, totalDistance * DISTANCE_MULTIPLIER)
3851
3864
  );
3852
- const horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
3865
+ let horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
3853
3866
  const componentWidthOffset = screenComponentWidth / 2 + COMPONENT_SIDE_GAP_PX;
3854
- const verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
3867
+ let verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
3868
+ if (isTooCloseToAnchor(horizontalLineY, screenGroupAnchorY) || isTooCloseToAnchor(horizontalLineY, screenComponentY)) {
3869
+ const minY = Math.min(screenGroupAnchorY, screenComponentY);
3870
+ const maxY = Math.max(screenGroupAnchorY, screenComponentY);
3871
+ const candidateAbove = minY - DIMENSION_ANCHOR_CLEARANCE_PX;
3872
+ const candidateBelow = maxY + DIMENSION_ANCHOR_CLEARANCE_PX;
3873
+ horizontalLineY = Math.abs(horizontalLineY - candidateAbove) < Math.abs(horizontalLineY - candidateBelow) ? candidateAbove : candidateBelow;
3874
+ }
3875
+ if (isTooCloseToAnchor(verticalLineX, screenGroupAnchorX) || isTooCloseToAnchor(verticalLineX, screenComponentX)) {
3876
+ const minX = Math.min(screenGroupAnchorX, screenComponentX);
3877
+ const maxX = Math.max(screenGroupAnchorX, screenComponentX);
3878
+ const candidateLeft = minX - DIMENSION_ANCHOR_CLEARANCE_PX;
3879
+ const candidateRight = maxX + DIMENSION_ANCHOR_CLEARANCE_PX;
3880
+ verticalLineX = Math.abs(verticalLineX - candidateLeft) < Math.abs(verticalLineX - candidateRight) ? candidateLeft : candidateRight;
3881
+ }
3855
3882
  if (Math.abs(offsetX) > OFFSET_THRESHOLD_MM) {
3856
3883
  objects.push(
3857
3884
  ...createHorizontalDimension({
@@ -3878,6 +3905,24 @@ function createAnchorOffsetIndicators(params) {
3878
3905
  }
3879
3906
  return objects;
3880
3907
  }
3908
+ function getTrimmedConnectorLine(x1, y1, x2, y2) {
3909
+ const dx = x2 - x1;
3910
+ const dy = y2 - y1;
3911
+ const distance4 = Math.hypot(dx, dy);
3912
+ const totalTrim = CONNECTOR_GROUP_GAP_PX + CONNECTOR_COMPONENT_GAP_PX;
3913
+ if (!(distance4 > totalTrim)) return { x1, y1, x2, y2 };
3914
+ const ux = dx / distance4;
3915
+ const uy = dy / distance4;
3916
+ return {
3917
+ x1: x1 + ux * CONNECTOR_GROUP_GAP_PX,
3918
+ y1: y1 + uy * CONNECTOR_GROUP_GAP_PX,
3919
+ x2: x2 - ux * CONNECTOR_COMPONENT_GAP_PX,
3920
+ y2: y2 - uy * CONNECTOR_COMPONENT_GAP_PX
3921
+ };
3922
+ }
3923
+ function isTooCloseToAnchor(value, anchorValue) {
3924
+ return Math.abs(value - anchorValue) < DIMENSION_ANCHOR_CLEARANCE_PX;
3925
+ }
3881
3926
  function createAnchorMarker(x, y) {
3882
3927
  return {
3883
3928
  name: "g",
@@ -4082,8 +4127,7 @@ function createVerticalDimension({
4082
4127
  return objects;
4083
4128
  }
4084
4129
  function formatOffsetLabel(axis, offsetMm, displayOffset) {
4085
- const baseValue = displayOffset ?? offsetMm.toFixed(2);
4086
- const valueStr = typeof baseValue === "number" ? baseValue.toString() : baseValue;
4130
+ const valueStr = typeof displayOffset === "string" ? displayOffset : offsetMm.toFixed(2);
4087
4131
  const hasUnit = typeof valueStr === "string" && valueStr.trim().endsWith("mm");
4088
4132
  const unitSuffix = hasUnit ? "" : "mm";
4089
4133
  return `${axis}: ${valueStr}${unitSuffix}`;
@@ -5368,6 +5412,17 @@ function createMajorGridPatternChildren(cellSize, majorCellSize, lineColor, majo
5368
5412
 
5369
5413
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
5370
5414
  import { applyToPoint as applyToPoint31 } from "transformation-matrix";
5415
+
5416
+ // lib/utils/get-point-from-elm.ts
5417
+ function getPointFromElm(elm) {
5418
+ const candidate = elm?.anchor_position ?? elm?.center;
5419
+ if (candidate && typeof candidate.x === "number" && typeof candidate.y === "number") {
5420
+ return { x: candidate.x, y: candidate.y };
5421
+ }
5422
+ return void 0;
5423
+ }
5424
+
5425
+ // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
5371
5426
  function createSvgObjectsFromPcbComponent(component, ctx) {
5372
5427
  const { transform, circuitJson } = ctx;
5373
5428
  const { center, width, height, rotation = 0 } = component;
@@ -5429,13 +5484,15 @@ function getAnchorPosition(component, circuitJson) {
5429
5484
  const pcbGroup = circuitJson.find(
5430
5485
  (elm) => elm.type === "pcb_group" && elm.pcb_group_id === component.positioned_relative_to_pcb_group_id
5431
5486
  );
5432
- if (pcbGroup?.center) return pcbGroup.center;
5487
+ const point = getPointFromElm(pcbGroup);
5488
+ if (point) return point;
5433
5489
  }
5434
5490
  if (component.positioned_relative_to_pcb_board_id) {
5435
5491
  const pcbBoard = circuitJson.find(
5436
5492
  (elm) => elm.type === "pcb_board" && elm.pcb_board_id === component.positioned_relative_to_pcb_board_id
5437
5493
  );
5438
- if (pcbBoard?.center) return pcbBoard.center;
5494
+ const point = getPointFromElm(pcbBoard);
5495
+ if (point) return point;
5439
5496
  }
5440
5497
  return void 0;
5441
5498
  }
@@ -5454,7 +5511,7 @@ function createSvgObjectsFromPcbGroup(pcbGroup, ctx) {
5454
5511
  svgObjects.push(
5455
5512
  ...createAnchorOffsetIndicators({
5456
5513
  groupAnchorPosition: anchorPosition,
5457
- componentPosition: pcbGroup.center,
5514
+ componentPosition: pcbGroup.anchor_position ?? pcbGroup.center,
5458
5515
  transform,
5459
5516
  componentWidth: pcbGroup.width,
5460
5517
  componentHeight: pcbGroup.height,
@@ -5539,13 +5596,15 @@ function getAnchorPosition2(group, circuitJson) {
5539
5596
  const pcbGroup = circuitJson.find(
5540
5597
  (elm) => elm.type === "pcb_group" && elm.pcb_group_id === group.positioned_relative_to_pcb_group_id
5541
5598
  );
5542
- if (pcbGroup?.center) return pcbGroup.center;
5599
+ const point = getPointFromElm(pcbGroup);
5600
+ if (point) return point;
5543
5601
  }
5544
5602
  if (group.positioned_relative_to_pcb_board_id) {
5545
5603
  const pcbBoard = circuitJson.find(
5546
5604
  (elm) => elm.type === "pcb_board" && elm.pcb_board_id === group.positioned_relative_to_pcb_board_id
5547
5605
  );
5548
- if (pcbBoard?.center) return pcbBoard.center;
5606
+ const point = getPointFromElm(pcbBoard);
5607
+ if (point) return point;
5549
5608
  }
5550
5609
  return void 0;
5551
5610
  }
@@ -5562,7 +5621,7 @@ function getSoftwareUsedString(circuitJson) {
5562
5621
  var package_default = {
5563
5622
  name: "circuit-to-svg",
5564
5623
  type: "module",
5565
- version: "0.0.294",
5624
+ version: "0.0.296",
5566
5625
  description: "Convert Circuit JSON to SVG",
5567
5626
  main: "dist/index.js",
5568
5627
  files: [