circuit-to-svg 0.0.296 → 0.0.298

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,7 +2751,6 @@ 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
- var BASELINE_Y = 0.241;
2755
2754
  function linesToPathData(lines, offsetX, offsetY, charScale, baselineAdjust = 0) {
2756
2755
  return lines.map((line) => {
2757
2756
  const x1 = offsetX + line.x1 * charScale;
@@ -2772,9 +2771,7 @@ function textToAlphabetPath(text, fontSize) {
2772
2771
  }
2773
2772
  const lines = lineAlphabet[char];
2774
2773
  if (lines) {
2775
- const isLowercase = char >= "a" && char <= "z";
2776
- const baselineAdjust = isLowercase ? BASELINE_Y : 0;
2777
- paths.push(linesToPathData(lines, x, 0, fontSize, baselineAdjust));
2774
+ paths.push(linesToPathData(lines, x, 0, fontSize));
2778
2775
  }
2779
2776
  x += charAdvance;
2780
2777
  }
@@ -2807,9 +2804,7 @@ function textToCenteredAlphabetPaths(text, fontSize) {
2807
2804
  }
2808
2805
  const charLines = lineAlphabet[char];
2809
2806
  if (charLines) {
2810
- const isLowercase = char >= "a" && char <= "z";
2811
- const baselineAdjust = isLowercase ? BASELINE_Y : 0;
2812
- paths.push(linesToPathData(charLines, x, y, fontSize, baselineAdjust));
2807
+ paths.push(linesToPathData(charLines, x, y, fontSize));
2813
2808
  }
2814
2809
  x += charAdvance;
2815
2810
  }
@@ -3777,13 +3772,17 @@ import { applyToPoint as applyToPoint23 } from "transformation-matrix";
3777
3772
 
3778
3773
  // lib/utils/create-pcb-component-anchor-offset-indicators.ts
3779
3774
  import { applyToPoint as applyToPoint22 } from "transformation-matrix";
3780
- var OFFSET_THRESHOLD_MM = 0.01;
3775
+ var OFFSET_THRESHOLD_MM = 0.05;
3781
3776
  var TICK_SIZE_PX = 4;
3782
3777
  var LABEL_GAP_PX = 8;
3783
3778
  var LABEL_FONT_SIZE_PX = 11;
3784
3779
  var STROKE_WIDTH_PX = 1;
3785
3780
  var ANCHOR_MARKER_SIZE_PX = 5;
3786
3781
  var ANCHOR_MARKER_STROKE_WIDTH_PX = 1.5;
3782
+ var COMPONENT_ANCHOR_MARKER_RADIUS_PX = 2;
3783
+ var CONNECTOR_GROUP_GAP_PX = ANCHOR_MARKER_SIZE_PX + 2;
3784
+ var CONNECTOR_COMPONENT_GAP_PX = COMPONENT_ANCHOR_MARKER_RADIUS_PX + 2;
3785
+ var DIMENSION_ANCHOR_CLEARANCE_PX = ANCHOR_MARKER_SIZE_PX + TICK_SIZE_PX + 6;
3787
3786
  var COMPONENT_GAP_PX = 15;
3788
3787
  var COMPONENT_SIDE_GAP_PX = 10;
3789
3788
  var DISTANCE_MULTIPLIER = 0.2;
@@ -3813,14 +3812,20 @@ function createAnchorOffsetIndicators(params) {
3813
3812
  const screenComponentWidth = componentWidth * scale10;
3814
3813
  const screenComponentHeight = componentHeight * scale10;
3815
3814
  objects.push(createAnchorMarker(screenGroupAnchorX, screenGroupAnchorY));
3815
+ const trimmedConnector = getTrimmedConnectorLine(
3816
+ screenGroupAnchorX,
3817
+ screenGroupAnchorY,
3818
+ screenComponentX,
3819
+ screenComponentY
3820
+ );
3816
3821
  objects.push({
3817
3822
  name: "line",
3818
3823
  type: "element",
3819
3824
  attributes: {
3820
- x1: screenGroupAnchorX.toString(),
3821
- y1: screenGroupAnchorY.toString(),
3822
- x2: screenComponentX.toString(),
3823
- y2: screenComponentY.toString(),
3825
+ x1: trimmedConnector.x1.toString(),
3826
+ y1: trimmedConnector.y1.toString(),
3827
+ x2: trimmedConnector.x2.toString(),
3828
+ y2: trimmedConnector.y2.toString(),
3824
3829
  stroke: "#ffffff",
3825
3830
  "stroke-width": "0.5",
3826
3831
  "stroke-dasharray": "3,3",
@@ -3836,7 +3841,7 @@ function createAnchorOffsetIndicators(params) {
3836
3841
  attributes: {
3837
3842
  cx: screenComponentX.toString(),
3838
3843
  cy: screenComponentY.toString(),
3839
- r: "2",
3844
+ r: COMPONENT_ANCHOR_MARKER_RADIUS_PX.toString(),
3840
3845
  fill: "#ffffff",
3841
3846
  opacity: "0.7",
3842
3847
  class: "anchor-offset-component-marker"
@@ -3852,9 +3857,23 @@ function createAnchorOffsetIndicators(params) {
3852
3857
  componentHeightOffset,
3853
3858
  Math.min(MAX_OFFSET_PX, totalDistance * DISTANCE_MULTIPLIER)
3854
3859
  );
3855
- const horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
3860
+ let horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
3856
3861
  const componentWidthOffset = screenComponentWidth / 2 + COMPONENT_SIDE_GAP_PX;
3857
- const verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
3862
+ let verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
3863
+ if (isTooCloseToAnchor(horizontalLineY, screenGroupAnchorY) || isTooCloseToAnchor(horizontalLineY, screenComponentY)) {
3864
+ const minY = Math.min(screenGroupAnchorY, screenComponentY);
3865
+ const maxY = Math.max(screenGroupAnchorY, screenComponentY);
3866
+ const candidateAbove = minY - DIMENSION_ANCHOR_CLEARANCE_PX;
3867
+ const candidateBelow = maxY + DIMENSION_ANCHOR_CLEARANCE_PX;
3868
+ horizontalLineY = Math.abs(horizontalLineY - candidateAbove) < Math.abs(horizontalLineY - candidateBelow) ? candidateAbove : candidateBelow;
3869
+ }
3870
+ if (isTooCloseToAnchor(verticalLineX, screenGroupAnchorX) || isTooCloseToAnchor(verticalLineX, screenComponentX)) {
3871
+ const minX = Math.min(screenGroupAnchorX, screenComponentX);
3872
+ const maxX = Math.max(screenGroupAnchorX, screenComponentX);
3873
+ const candidateLeft = minX - DIMENSION_ANCHOR_CLEARANCE_PX;
3874
+ const candidateRight = maxX + DIMENSION_ANCHOR_CLEARANCE_PX;
3875
+ verticalLineX = Math.abs(verticalLineX - candidateLeft) < Math.abs(verticalLineX - candidateRight) ? candidateLeft : candidateRight;
3876
+ }
3858
3877
  if (Math.abs(offsetX) > OFFSET_THRESHOLD_MM) {
3859
3878
  objects.push(
3860
3879
  ...createHorizontalDimension({
@@ -3881,6 +3900,24 @@ function createAnchorOffsetIndicators(params) {
3881
3900
  }
3882
3901
  return objects;
3883
3902
  }
3903
+ function getTrimmedConnectorLine(x1, y1, x2, y2) {
3904
+ const dx = x2 - x1;
3905
+ const dy = y2 - y1;
3906
+ const distance4 = Math.hypot(dx, dy);
3907
+ const totalTrim = CONNECTOR_GROUP_GAP_PX + CONNECTOR_COMPONENT_GAP_PX;
3908
+ if (!(distance4 > totalTrim)) return { x1, y1, x2, y2 };
3909
+ const ux = dx / distance4;
3910
+ const uy = dy / distance4;
3911
+ return {
3912
+ x1: x1 + ux * CONNECTOR_GROUP_GAP_PX,
3913
+ y1: y1 + uy * CONNECTOR_GROUP_GAP_PX,
3914
+ x2: x2 - ux * CONNECTOR_COMPONENT_GAP_PX,
3915
+ y2: y2 - uy * CONNECTOR_COMPONENT_GAP_PX
3916
+ };
3917
+ }
3918
+ function isTooCloseToAnchor(value, anchorValue) {
3919
+ return Math.abs(value - anchorValue) < DIMENSION_ANCHOR_CLEARANCE_PX;
3920
+ }
3884
3921
  function createAnchorMarker(x, y) {
3885
3922
  return {
3886
3923
  name: "g",
@@ -4085,8 +4122,7 @@ function createVerticalDimension({
4085
4122
  return objects;
4086
4123
  }
4087
4124
  function formatOffsetLabel(axis, offsetMm, displayOffset) {
4088
- const baseValue = displayOffset ?? offsetMm.toFixed(2);
4089
- const valueStr = typeof baseValue === "number" ? baseValue.toString() : baseValue;
4125
+ const valueStr = typeof displayOffset === "string" ? displayOffset : offsetMm.toFixed(2);
4090
4126
  const hasUnit = typeof valueStr === "string" && valueStr.trim().endsWith("mm");
4091
4127
  const unitSuffix = hasUnit ? "" : "mm";
4092
4128
  return `${axis}: ${valueStr}${unitSuffix}`;
@@ -5371,6 +5407,17 @@ function createMajorGridPatternChildren(cellSize, majorCellSize, lineColor, majo
5371
5407
 
5372
5408
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
5373
5409
  import { applyToPoint as applyToPoint31 } from "transformation-matrix";
5410
+
5411
+ // lib/utils/get-point-from-elm.ts
5412
+ function getPointFromElm(elm) {
5413
+ const candidate = elm?.anchor_position ?? elm?.center;
5414
+ if (candidate && typeof candidate.x === "number" && typeof candidate.y === "number") {
5415
+ return { x: candidate.x, y: candidate.y };
5416
+ }
5417
+ return void 0;
5418
+ }
5419
+
5420
+ // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
5374
5421
  function createSvgObjectsFromPcbComponent(component, ctx) {
5375
5422
  const { transform, circuitJson } = ctx;
5376
5423
  const { center, width, height, rotation = 0 } = component;
@@ -5432,13 +5479,15 @@ function getAnchorPosition(component, circuitJson) {
5432
5479
  const pcbGroup = circuitJson.find(
5433
5480
  (elm) => elm.type === "pcb_group" && elm.pcb_group_id === component.positioned_relative_to_pcb_group_id
5434
5481
  );
5435
- if (pcbGroup?.center) return pcbGroup.center;
5482
+ const point = getPointFromElm(pcbGroup);
5483
+ if (point) return point;
5436
5484
  }
5437
5485
  if (component.positioned_relative_to_pcb_board_id) {
5438
5486
  const pcbBoard = circuitJson.find(
5439
5487
  (elm) => elm.type === "pcb_board" && elm.pcb_board_id === component.positioned_relative_to_pcb_board_id
5440
5488
  );
5441
- if (pcbBoard?.center) return pcbBoard.center;
5489
+ const point = getPointFromElm(pcbBoard);
5490
+ if (point) return point;
5442
5491
  }
5443
5492
  return void 0;
5444
5493
  }
@@ -5457,7 +5506,7 @@ function createSvgObjectsFromPcbGroup(pcbGroup, ctx) {
5457
5506
  svgObjects.push(
5458
5507
  ...createAnchorOffsetIndicators({
5459
5508
  groupAnchorPosition: anchorPosition,
5460
- componentPosition: pcbGroup.center,
5509
+ componentPosition: pcbGroup.anchor_position ?? pcbGroup.center,
5461
5510
  transform,
5462
5511
  componentWidth: pcbGroup.width,
5463
5512
  componentHeight: pcbGroup.height,
@@ -5542,13 +5591,15 @@ function getAnchorPosition2(group, circuitJson) {
5542
5591
  const pcbGroup = circuitJson.find(
5543
5592
  (elm) => elm.type === "pcb_group" && elm.pcb_group_id === group.positioned_relative_to_pcb_group_id
5544
5593
  );
5545
- if (pcbGroup?.center) return pcbGroup.center;
5594
+ const point = getPointFromElm(pcbGroup);
5595
+ if (point) return point;
5546
5596
  }
5547
5597
  if (group.positioned_relative_to_pcb_board_id) {
5548
5598
  const pcbBoard = circuitJson.find(
5549
5599
  (elm) => elm.type === "pcb_board" && elm.pcb_board_id === group.positioned_relative_to_pcb_board_id
5550
5600
  );
5551
- if (pcbBoard?.center) return pcbBoard.center;
5601
+ const point = getPointFromElm(pcbBoard);
5602
+ if (point) return point;
5552
5603
  }
5553
5604
  return void 0;
5554
5605
  }
@@ -5565,7 +5616,7 @@ function getSoftwareUsedString(circuitJson) {
5565
5616
  var package_default = {
5566
5617
  name: "circuit-to-svg",
5567
5618
  type: "module",
5568
- version: "0.0.295",
5619
+ version: "0.0.297",
5569
5620
  description: "Convert Circuit JSON to SVG",
5570
5621
  main: "dist/index.js",
5571
5622
  files: [
@@ -5583,19 +5634,19 @@ var package_default = {
5583
5634
  license: "ISC",
5584
5635
  devDependencies: {
5585
5636
  "@biomejs/biome": "^1.9.4",
5586
- "@tscircuit/alphabet": "^0.0.8",
5637
+ "@tscircuit/alphabet": "^0.0.9",
5587
5638
  "@types/bun": "^1.2.8",
5588
5639
  "@vitejs/plugin-react": "5.0.0",
5589
5640
  biome: "^0.3.3",
5590
5641
  "bun-match-svg": "^0.0.12",
5591
- "circuit-json": "^0.0.333",
5642
+ "circuit-json": "^0.0.335",
5592
5643
  esbuild: "^0.20.2",
5593
5644
  "performance-now": "^2.1.0",
5594
5645
  react: "19.1.0",
5595
5646
  "react-cosmos": "7.0.0",
5596
5647
  "react-cosmos-plugin-vite": "7.0.0",
5597
5648
  "react-dom": "19.1.0",
5598
- tscircuit: "^0.0.1018",
5649
+ tscircuit: "^0.0.1059",
5599
5650
  tsup: "^8.0.2",
5600
5651
  typescript: "^5.4.5",
5601
5652
  "vite-tsconfig-paths": "^5.0.1"