circuit-to-svg 0.0.164 → 0.0.166

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
@@ -1442,6 +1442,72 @@ function getSoftwareUsedString(circuitJson) {
1442
1442
  return metadata?.software_used_string;
1443
1443
  }
1444
1444
 
1445
+ // package.json
1446
+ var package_default = {
1447
+ name: "circuit-to-svg",
1448
+ type: "module",
1449
+ version: "0.0.165",
1450
+ description: "Convert Circuit JSON to SVG",
1451
+ main: "dist/index.js",
1452
+ files: [
1453
+ "dist"
1454
+ ],
1455
+ scripts: {
1456
+ start: "storybook dev -p 6006",
1457
+ prepublish: "npm run build",
1458
+ build: "tsup-node ./lib/index.ts --format esm --dts --sourcemap",
1459
+ format: "biome format . --write",
1460
+ "format:check": "biome format .",
1461
+ storybook: "storybook dev -p 6006",
1462
+ "build-storybook": "storybook build"
1463
+ },
1464
+ license: "ISC",
1465
+ devDependencies: {
1466
+ "@biomejs/biome": "^1.9.4",
1467
+ "@chromatic-com/storybook": "^1.6.1",
1468
+ "@storybook/addon-essentials": "^8.2.5",
1469
+ "@storybook/addon-interactions": "^8.2.5",
1470
+ "@storybook/addon-links": "^8.2.5",
1471
+ "@storybook/addon-onboarding": "^8.2.5",
1472
+ "@storybook/blocks": "^8.2.5",
1473
+ "@storybook/react": "^8.2.5",
1474
+ "@storybook/react-vite": "^8.2.5",
1475
+ "@storybook/test": "^8.2.5",
1476
+ "@tscircuit/core": "0.0.477",
1477
+ "@tscircuit/plop": "^0.0.10",
1478
+ "@types/bun": "^1.2.8",
1479
+ biome: "^0.3.3",
1480
+ "bun-match-svg": "^0.0.6",
1481
+ "circuit-json": "^0.0.218",
1482
+ esbuild: "^0.20.2",
1483
+ "performance-now": "^2.1.0",
1484
+ react: "^18.3.1",
1485
+ "schematic-symbols": "^0.0.153",
1486
+ storybook: "^8.2.5",
1487
+ tsup: "^8.0.2",
1488
+ typescript: "^5.4.5",
1489
+ "vite-tsconfig-paths": "^5.0.1",
1490
+ "@tscircuit/checks": "^0.0.44",
1491
+ "@tscircuit/circuit-json-util": "^0.0.47",
1492
+ "@tscircuit/footprinter": "^0.0.91"
1493
+ },
1494
+ peerDependencies: {
1495
+ "circuit-json": "*",
1496
+ "@tscircuit/circuit-json-util": "*",
1497
+ "@tscircuit/footprinter": "*",
1498
+ "schematic-symbols": "*"
1499
+ },
1500
+ dependencies: {
1501
+ "@types/node": "^22.5.5",
1502
+ "bun-types": "^1.1.40",
1503
+ svgson: "^5.3.1",
1504
+ "transformation-matrix": "^2.16.1"
1505
+ }
1506
+ };
1507
+
1508
+ // lib/package-version.ts
1509
+ var CIRCUIT_TO_SVG_VERSION = package_default.version;
1510
+
1445
1511
  // lib/pcb/convert-circuit-json-to-pcb-svg.ts
1446
1512
  var OBJECT_ORDER = [
1447
1513
  "pcb_trace_error",
@@ -1641,6 +1707,7 @@ function convertCircuitJsonToPcbSvg(circuitJson, options) {
1641
1707
  }
1642
1708
  children.push(...svgObjects);
1643
1709
  const softwareUsedString = getSoftwareUsedString(circuitJson);
1710
+ const version = CIRCUIT_TO_SVG_VERSION;
1644
1711
  const svgObject = {
1645
1712
  name: "svg",
1646
1713
  type: "element",
@@ -1650,6 +1717,9 @@ function convertCircuitJsonToPcbSvg(circuitJson, options) {
1650
1717
  height: svgHeight.toString(),
1651
1718
  ...softwareUsedString && {
1652
1719
  "data-software-used-string": softwareUsedString
1720
+ },
1721
+ ...options?.includeVersion && {
1722
+ "data-circuit-to-svg-version": version
1653
1723
  }
1654
1724
  },
1655
1725
  value: "",
@@ -2470,6 +2540,7 @@ function convertCircuitJsonToAssemblySvg(soup, options) {
2470
2540
  (a, b) => (OBJECT_ORDER2.indexOf(b.type) ?? 9999) - (OBJECT_ORDER2.indexOf(a.type) ?? 9999)
2471
2541
  ).flatMap((item) => createSvgObjects2(item, ctx, soup));
2472
2542
  const softwareUsedString = getSoftwareUsedString(soup);
2543
+ const version = CIRCUIT_TO_SVG_VERSION;
2473
2544
  const svgObject = {
2474
2545
  name: "svg",
2475
2546
  type: "element",
@@ -2479,6 +2550,9 @@ function convertCircuitJsonToAssemblySvg(soup, options) {
2479
2550
  height: svgHeight.toString(),
2480
2551
  ...softwareUsedString && {
2481
2552
  "data-software-used-string": softwareUsedString
2553
+ },
2554
+ ...options?.includeVersion && {
2555
+ "data-circuit-to-svg-version": version
2482
2556
  }
2483
2557
  },
2484
2558
  value: "",
@@ -2987,69 +3061,6 @@ function drawSchematicLabeledPoints(params) {
2987
3061
  };
2988
3062
  }
2989
3063
 
2990
- // lib/utils/get-unit-vector-from-outside-to-edge.ts
2991
- var getUnitVectorFromOutsideToEdge = (side) => {
2992
- switch (side) {
2993
- case "top":
2994
- return { x: 0, y: -1 };
2995
- case "bottom":
2996
- return { x: 0, y: 1 };
2997
- case "left":
2998
- return { x: 1, y: 0 };
2999
- case "right":
3000
- return { x: -1, y: 0 };
3001
- }
3002
- throw new Error(`Invalid side: ${side}`);
3003
- };
3004
-
3005
- // lib/utils/net-label-utils.ts
3006
- import "transformation-matrix";
3007
- import "schematic-symbols";
3008
- var ARROW_POINT_WIDTH_FSR = 0.3;
3009
- var END_PADDING_FSR = 0.3;
3010
- var END_PADDING_EXTRA_PER_CHARACTER_FSR = 0.06;
3011
- var ninePointAnchorToTextAnchor = {
3012
- top_left: "start",
3013
- top_right: "end",
3014
- middle_left: "start",
3015
- middle_right: "end",
3016
- bottom_left: "start",
3017
- bottom_right: "end",
3018
- center: "middle",
3019
- middle_top: "middle",
3020
- middle_bottom: "middle"
3021
- };
3022
- var ninePointAnchorToDominantBaseline = {
3023
- top_left: "hanging",
3024
- top_right: "hanging",
3025
- bottom_left: "ideographic",
3026
- bottom_right: "ideographic",
3027
- center: "middle",
3028
- middle_left: "middle",
3029
- middle_right: "middle",
3030
- middle_top: "hanging",
3031
- middle_bottom: "ideographic"
3032
- };
3033
- function getPathRotation(anchorSide) {
3034
- const rotationMap = {
3035
- left: 180,
3036
- top: 90,
3037
- bottom: -90,
3038
- right: 0
3039
- };
3040
- return rotationMap[anchorSide] ?? 0;
3041
- }
3042
- function calculateAnchorPosition(schNetLabel, fontSizeMm, textWidthFSR) {
3043
- const fullWidthFsr = textWidthFSR + ARROW_POINT_WIDTH_FSR * 2 + END_PADDING_EXTRA_PER_CHARACTER_FSR * schNetLabel.text.length + END_PADDING_FSR;
3044
- const realTextGrowthVec = getUnitVectorFromOutsideToEdge(
3045
- schNetLabel.anchor_side
3046
- );
3047
- return schNetLabel.anchor_position ?? {
3048
- x: schNetLabel.center.x - realTextGrowthVec.x * fullWidthFsr * fontSizeMm / 2,
3049
- y: schNetLabel.center.y - realTextGrowthVec.y * fullWidthFsr * fontSizeMm / 2
3050
- };
3051
- }
3052
-
3053
3064
  // lib/sch/arial-text-metrics.ts
3054
3065
  var arialTextMetrics = {
3055
3066
  "0": {
@@ -3829,6 +3840,149 @@ var estimateTextWidth = (text) => {
3829
3840
  return totalWidth / 27;
3830
3841
  };
3831
3842
 
3843
+ // lib/sch/get-table-dimensions.ts
3844
+ var getTableDimensions = (schematicTable, circuitJson) => {
3845
+ if (schematicTable.column_widths && schematicTable.column_widths.length > 0 && schematicTable.row_heights && schematicTable.row_heights.length > 0) {
3846
+ const unitToMm = (v) => {
3847
+ if (typeof v === "number") return v;
3848
+ if (v.endsWith("mm")) return parseFloat(v);
3849
+ if (v.endsWith("in")) return parseFloat(v) * 25.4;
3850
+ return parseFloat(v);
3851
+ };
3852
+ return {
3853
+ column_widths: schematicTable.column_widths.map(unitToMm),
3854
+ row_heights: schematicTable.row_heights.map(unitToMm)
3855
+ };
3856
+ }
3857
+ const cells = circuitJson.filter(
3858
+ (elm) => elm.type === "schematic_table_cell" && elm.schematic_table_id === schematicTable.schematic_table_id
3859
+ );
3860
+ if (cells.length === 0) {
3861
+ return { column_widths: [], row_heights: [] };
3862
+ }
3863
+ const numColumns = cells.reduce((max, c) => Math.max(max, c.end_column_index), -1) + 1;
3864
+ const numRows = cells.reduce((max, c) => Math.max(max, c.end_row_index), -1) + 1;
3865
+ const { cell_padding = 0.2 } = schematicTable;
3866
+ const column_widths = new Array(numColumns).fill(0);
3867
+ const row_heights = new Array(numRows).fill(0);
3868
+ const cell_widths = {};
3869
+ const cell_heights = {};
3870
+ for (const cell of cells) {
3871
+ const fontSizeMm = getSchMmFontSize("reference_designator", cell.font_size);
3872
+ const textWidthMm = estimateTextWidth(cell.text ?? "") * fontSizeMm;
3873
+ const requiredWidth = textWidthMm + 2 * cell_padding;
3874
+ const requiredHeight = fontSizeMm * 1.2 + 2 * cell_padding;
3875
+ const key = `${cell.start_row_index}-${cell.start_column_index}`;
3876
+ cell_widths[key] = requiredWidth;
3877
+ cell_heights[key] = requiredHeight;
3878
+ }
3879
+ for (let i = 0; i < numRows; i++) {
3880
+ for (let j = 0; j < numColumns; j++) {
3881
+ const key = `${i}-${j}`;
3882
+ if (cell_widths[key] && cell_widths[key] > column_widths[j]) {
3883
+ column_widths[j] = cell_widths[key];
3884
+ }
3885
+ if (cell_heights[key] && cell_heights[key] > row_heights[i]) {
3886
+ row_heights[i] = cell_heights[key];
3887
+ }
3888
+ }
3889
+ }
3890
+ for (const cell of cells) {
3891
+ if (cell.start_column_index === cell.end_column_index && cell.start_row_index === cell.end_row_index)
3892
+ continue;
3893
+ const key = `${cell.start_row_index}-${cell.start_column_index}`;
3894
+ const requiredWidth = cell_widths[key];
3895
+ const requiredHeight = cell_heights[key];
3896
+ if (requiredWidth === void 0 || requiredHeight === void 0) continue;
3897
+ let currentWidth = 0;
3898
+ for (let i = cell.start_column_index; i <= cell.end_column_index; i++) {
3899
+ currentWidth += column_widths[i];
3900
+ }
3901
+ if (requiredWidth > currentWidth) {
3902
+ const diff = requiredWidth - currentWidth;
3903
+ const extraPerColumn = diff / (cell.end_column_index - cell.start_column_index + 1);
3904
+ for (let i = cell.start_column_index; i <= cell.end_column_index; i++) {
3905
+ column_widths[i] += extraPerColumn;
3906
+ }
3907
+ }
3908
+ let currentHeight = 0;
3909
+ for (let i = cell.start_row_index; i <= cell.end_row_index; i++) {
3910
+ currentHeight += row_heights[i];
3911
+ }
3912
+ if (requiredHeight > currentHeight) {
3913
+ const diff = requiredHeight - currentHeight;
3914
+ const extraPerRow = diff / (cell.end_row_index - cell.start_row_index + 1);
3915
+ for (let i = cell.start_row_index; i <= cell.end_row_index; i++) {
3916
+ row_heights[i] += extraPerRow;
3917
+ }
3918
+ }
3919
+ }
3920
+ return { column_widths, row_heights };
3921
+ };
3922
+
3923
+ // lib/utils/get-unit-vector-from-outside-to-edge.ts
3924
+ var getUnitVectorFromOutsideToEdge = (side) => {
3925
+ switch (side) {
3926
+ case "top":
3927
+ return { x: 0, y: -1 };
3928
+ case "bottom":
3929
+ return { x: 0, y: 1 };
3930
+ case "left":
3931
+ return { x: 1, y: 0 };
3932
+ case "right":
3933
+ return { x: -1, y: 0 };
3934
+ }
3935
+ throw new Error(`Invalid side: ${side}`);
3936
+ };
3937
+
3938
+ // lib/utils/net-label-utils.ts
3939
+ import "transformation-matrix";
3940
+ import "schematic-symbols";
3941
+ var ARROW_POINT_WIDTH_FSR = 0.3;
3942
+ var END_PADDING_FSR = 0.3;
3943
+ var END_PADDING_EXTRA_PER_CHARACTER_FSR = 0.06;
3944
+ var ninePointAnchorToTextAnchor = {
3945
+ top_left: "start",
3946
+ top_right: "end",
3947
+ middle_left: "start",
3948
+ middle_right: "end",
3949
+ bottom_left: "start",
3950
+ bottom_right: "end",
3951
+ center: "middle",
3952
+ middle_top: "middle",
3953
+ middle_bottom: "middle"
3954
+ };
3955
+ var ninePointAnchorToDominantBaseline = {
3956
+ top_left: "hanging",
3957
+ top_right: "hanging",
3958
+ bottom_left: "ideographic",
3959
+ bottom_right: "ideographic",
3960
+ center: "middle",
3961
+ middle_left: "middle",
3962
+ middle_right: "middle",
3963
+ middle_top: "hanging",
3964
+ middle_bottom: "ideographic"
3965
+ };
3966
+ function getPathRotation(anchorSide) {
3967
+ const rotationMap = {
3968
+ left: 180,
3969
+ top: 90,
3970
+ bottom: -90,
3971
+ right: 0
3972
+ };
3973
+ return rotationMap[anchorSide] ?? 0;
3974
+ }
3975
+ function calculateAnchorPosition(schNetLabel, fontSizeMm, textWidthFSR) {
3976
+ const fullWidthFsr = textWidthFSR + ARROW_POINT_WIDTH_FSR * 2 + END_PADDING_EXTRA_PER_CHARACTER_FSR * schNetLabel.text.length + END_PADDING_FSR;
3977
+ const realTextGrowthVec = getUnitVectorFromOutsideToEdge(
3978
+ schNetLabel.anchor_side
3979
+ );
3980
+ return schNetLabel.anchor_position ?? {
3981
+ x: schNetLabel.center.x - realTextGrowthVec.x * fullWidthFsr * fontSizeMm / 2,
3982
+ y: schNetLabel.center.y - realTextGrowthVec.y * fullWidthFsr * fontSizeMm / 2
3983
+ };
3984
+ }
3985
+
3832
3986
  // lib/sch/get-schematic-bounds-from-circuit-json.ts
3833
3987
  function getSchematicBoundsFromCircuitJson(soup, padding = 0.5) {
3834
3988
  let minX = Number.POSITIVE_INFINITY;
@@ -3889,6 +4043,30 @@ function getSchematicBoundsFromCircuitJson(soup, padding = 0.5) {
3889
4043
  { width: item.width, height: item.height },
3890
4044
  0
3891
4045
  );
4046
+ } else if (item.type === "schematic_table") {
4047
+ const { column_widths, row_heights } = getTableDimensions(item, soup);
4048
+ const totalWidth = column_widths.reduce((a, b) => a + b, 0);
4049
+ const totalHeight = row_heights.reduce((a, b) => a + b, 0);
4050
+ const anchor = item.anchor ?? "center";
4051
+ let topLeftX = item.anchor_position.x;
4052
+ let topLeftY = item.anchor_position.y;
4053
+ if (anchor.includes("center")) {
4054
+ topLeftX -= totalWidth / 2;
4055
+ } else if (anchor.includes("right")) {
4056
+ topLeftX -= totalWidth;
4057
+ }
4058
+ if (anchor.includes("center")) {
4059
+ topLeftY += totalHeight / 2;
4060
+ } else if (anchor.includes("bottom")) {
4061
+ topLeftY += totalHeight;
4062
+ }
4063
+ const centerX = topLeftX + totalWidth / 2;
4064
+ const centerY = topLeftY - totalHeight / 2;
4065
+ updateBounds(
4066
+ { x: centerX, y: centerY },
4067
+ { width: totalWidth, height: totalHeight },
4068
+ 0
4069
+ );
3892
4070
  }
3893
4071
  }
3894
4072
  minX -= padding;
@@ -5412,6 +5590,206 @@ var createSvgObjectsFromSchematicBox = ({
5412
5590
  ];
5413
5591
  };
5414
5592
 
5593
+ // lib/sch/svg-object-fns/create-svg-objects-from-sch-table.ts
5594
+ import { applyToPoint as applyToPoint42 } from "transformation-matrix";
5595
+ var createSvgObjectsFromSchematicTable = ({
5596
+ schematicTable,
5597
+ transform,
5598
+ colorMap: colorMap2,
5599
+ circuitJson
5600
+ }) => {
5601
+ const {
5602
+ anchor_position,
5603
+ border_width = 0.05,
5604
+ anchor = "center"
5605
+ } = schematicTable;
5606
+ const { column_widths, row_heights } = getTableDimensions(
5607
+ schematicTable,
5608
+ circuitJson
5609
+ );
5610
+ const totalWidth = column_widths.reduce((a, b) => a + b, 0);
5611
+ const totalHeight = row_heights.reduce((a, b) => a + b, 0);
5612
+ let topLeftX = anchor_position.x;
5613
+ let topLeftY = anchor_position.y;
5614
+ if (anchor.includes("center")) {
5615
+ topLeftX -= totalWidth / 2;
5616
+ } else if (anchor.includes("right")) {
5617
+ topLeftX -= totalWidth;
5618
+ }
5619
+ if (anchor.includes("center")) {
5620
+ topLeftY += totalHeight / 2;
5621
+ } else if (anchor.includes("bottom")) {
5622
+ topLeftY += totalHeight;
5623
+ }
5624
+ const svgObjects = [];
5625
+ const borderStrokeWidth = border_width * Math.abs(transform.a);
5626
+ const gridStrokeWidth = getSchStrokeSize(transform);
5627
+ const [screenTopLeftX, screenTopLeftY] = applyToPoint42(transform, [
5628
+ topLeftX,
5629
+ topLeftY
5630
+ ]);
5631
+ const [screenBottomRightX, screenBottomRightY] = applyToPoint42(transform, [
5632
+ topLeftX + totalWidth,
5633
+ topLeftY - totalHeight
5634
+ ]);
5635
+ svgObjects.push({
5636
+ name: "rect",
5637
+ type: "element",
5638
+ attributes: {
5639
+ x: screenTopLeftX.toString(),
5640
+ y: screenTopLeftY.toString(),
5641
+ width: (screenBottomRightX - screenTopLeftX).toString(),
5642
+ height: (screenBottomRightY - screenTopLeftY).toString(),
5643
+ fill: "none",
5644
+ stroke: "#666",
5645
+ "stroke-width": borderStrokeWidth.toString()
5646
+ },
5647
+ children: [],
5648
+ value: ""
5649
+ });
5650
+ const cells = circuitJson.filter(
5651
+ (elm) => elm.type === "schematic_table_cell" && elm.schematic_table_id === schematicTable.schematic_table_id
5652
+ );
5653
+ let currentX = topLeftX;
5654
+ for (let i = 0; i < column_widths.length - 1; i++) {
5655
+ currentX += column_widths[i];
5656
+ let segmentStartY = topLeftY;
5657
+ for (let j = 0; j < row_heights.length; j++) {
5658
+ const segmentEndY = segmentStartY - row_heights[j];
5659
+ const isMerged = cells.some(
5660
+ (cell) => cell.start_column_index <= i && cell.end_column_index > i && cell.start_row_index <= j && cell.end_row_index >= j
5661
+ );
5662
+ if (!isMerged) {
5663
+ const start = applyToPoint42(transform, { x: currentX, y: segmentStartY });
5664
+ const end = applyToPoint42(transform, { x: currentX, y: segmentEndY });
5665
+ svgObjects.push({
5666
+ name: "line",
5667
+ type: "element",
5668
+ attributes: {
5669
+ x1: start.x.toString(),
5670
+ y1: start.y.toString(),
5671
+ x2: end.x.toString(),
5672
+ y2: end.y.toString(),
5673
+ stroke: "#666",
5674
+ "stroke-width": gridStrokeWidth.toString()
5675
+ },
5676
+ children: [],
5677
+ value: ""
5678
+ });
5679
+ }
5680
+ segmentStartY = segmentEndY;
5681
+ }
5682
+ }
5683
+ let currentY = topLeftY;
5684
+ for (let i = 0; i < row_heights.length - 1; i++) {
5685
+ currentY -= row_heights[i];
5686
+ let segmentStartX = topLeftX;
5687
+ for (let j = 0; j < column_widths.length; j++) {
5688
+ const segmentEndX = segmentStartX + column_widths[j];
5689
+ const isMerged = cells.some(
5690
+ (cell) => cell.start_row_index <= i && cell.end_row_index > i && cell.start_column_index <= j && cell.end_column_index >= j
5691
+ );
5692
+ if (!isMerged) {
5693
+ const start = applyToPoint42(transform, {
5694
+ x: segmentStartX,
5695
+ y: currentY
5696
+ });
5697
+ const end = applyToPoint42(transform, { x: segmentEndX, y: currentY });
5698
+ svgObjects.push({
5699
+ name: "line",
5700
+ type: "element",
5701
+ attributes: {
5702
+ x1: start.x.toString(),
5703
+ y1: start.y.toString(),
5704
+ x2: end.x.toString(),
5705
+ y2: end.y.toString(),
5706
+ stroke: "#666",
5707
+ "stroke-width": gridStrokeWidth.toString()
5708
+ },
5709
+ children: [],
5710
+ value: ""
5711
+ });
5712
+ }
5713
+ segmentStartX = segmentEndX;
5714
+ }
5715
+ }
5716
+ for (const cell of cells) {
5717
+ if (cell.text) {
5718
+ const cellWidth = column_widths.slice(cell.start_column_index, cell.end_column_index + 1).reduce((a, b) => a + b, 0);
5719
+ const cellHeight = row_heights.slice(cell.start_row_index, cell.end_row_index + 1).reduce((a, b) => a + b, 0);
5720
+ const cellTopLeftX = topLeftX + column_widths.slice(0, cell.start_column_index).reduce((a, b) => a + b, 0);
5721
+ const cellTopLeftY = topLeftY - row_heights.slice(0, cell.start_row_index).reduce((a, b) => a + b, 0);
5722
+ const { cell_padding = 0.2 } = schematicTable;
5723
+ const horizontal_align = cell.horizontal_align ?? "center";
5724
+ const vertical_align = cell.vertical_align ?? "middle";
5725
+ let realTextAnchorPos = {
5726
+ x: cellTopLeftX + cellWidth / 2,
5727
+ y: cellTopLeftY - cellHeight / 2
5728
+ };
5729
+ if (horizontal_align === "left") {
5730
+ realTextAnchorPos.x = cellTopLeftX + cell_padding;
5731
+ } else if (horizontal_align === "right") {
5732
+ realTextAnchorPos.x = cellTopLeftX + cellWidth - cell_padding;
5733
+ }
5734
+ if (vertical_align === "top") {
5735
+ realTextAnchorPos.y = cellTopLeftY - cell_padding;
5736
+ } else if (vertical_align === "bottom") {
5737
+ realTextAnchorPos.y = cellTopLeftY - cellHeight + cell_padding;
5738
+ }
5739
+ const screenTextAnchorPos = applyToPoint42(transform, realTextAnchorPos);
5740
+ const fontSize = getSchScreenFontSize(
5741
+ transform,
5742
+ "reference_designator",
5743
+ cell.font_size
5744
+ );
5745
+ const textAnchorMap = {
5746
+ left: "start",
5747
+ center: "middle",
5748
+ right: "end"
5749
+ };
5750
+ const dominantBaselineMap = {
5751
+ top: "hanging",
5752
+ middle: "middle",
5753
+ bottom: "ideographic"
5754
+ };
5755
+ svgObjects.push({
5756
+ name: "text",
5757
+ type: "element",
5758
+ attributes: {
5759
+ x: screenTextAnchorPos.x.toString(),
5760
+ y: screenTextAnchorPos.y.toString(),
5761
+ "font-size": `${fontSize}px`,
5762
+ "text-anchor": textAnchorMap[horizontal_align],
5763
+ "dominant-baseline": dominantBaselineMap[vertical_align],
5764
+ fill: colorMap2.schematic.sheet_label,
5765
+ "font-family": "sans-serif"
5766
+ },
5767
+ children: [
5768
+ {
5769
+ type: "text",
5770
+ value: cell.text,
5771
+ name: "",
5772
+ attributes: {},
5773
+ children: []
5774
+ }
5775
+ ],
5776
+ value: ""
5777
+ });
5778
+ }
5779
+ }
5780
+ return [
5781
+ {
5782
+ name: "g",
5783
+ type: "element",
5784
+ attributes: {
5785
+ "data-schematic-table-id": schematicTable.schematic_table_id
5786
+ },
5787
+ children: svgObjects,
5788
+ value: ""
5789
+ }
5790
+ ];
5791
+ };
5792
+
5415
5793
  // lib/sch/convert-circuit-json-to-schematic-svg.ts
5416
5794
  function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5417
5795
  const realBounds = getSchematicBoundsFromCircuitJson(circuitJson);
@@ -5482,6 +5860,7 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5482
5860
  const schText = [];
5483
5861
  const voltageProbeSvgs = [];
5484
5862
  const schBoxSvgs = [];
5863
+ const schTableSvgs = [];
5485
5864
  for (const elm of circuitJson) {
5486
5865
  if (elm.type === "schematic_debug_object") {
5487
5866
  schDebugObjectSvgs.push(
@@ -5539,6 +5918,15 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5539
5918
  colorMap: colorMap2
5540
5919
  })
5541
5920
  );
5921
+ } else if (elm.type === "schematic_table") {
5922
+ schTableSvgs.push(
5923
+ ...createSvgObjectsFromSchematicTable({
5924
+ schematicTable: elm,
5925
+ transform,
5926
+ colorMap: colorMap2,
5927
+ circuitJson
5928
+ })
5929
+ );
5542
5930
  }
5543
5931
  }
5544
5932
  svgChildren.push(
@@ -5548,7 +5936,8 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5548
5936
  ...schNetLabel,
5549
5937
  ...schText,
5550
5938
  ...schBoxSvgs,
5551
- ...voltageProbeSvgs
5939
+ ...voltageProbeSvgs,
5940
+ ...schTableSvgs
5552
5941
  );
5553
5942
  if (options?.labeledPoints) {
5554
5943
  svgChildren.push(
@@ -5559,6 +5948,7 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5559
5948
  );
5560
5949
  }
5561
5950
  const softwareUsedString = getSoftwareUsedString(circuitJson);
5951
+ const version = CIRCUIT_TO_SVG_VERSION;
5562
5952
  const svgObject = {
5563
5953
  name: "svg",
5564
5954
  type: "element",
@@ -5570,6 +5960,9 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
5570
5960
  "data-real-to-screen-transform": toSVG(transform),
5571
5961
  ...softwareUsedString && {
5572
5962
  "data-software-used-string": softwareUsedString
5963
+ },
5964
+ ...options?.includeVersion && {
5965
+ "data-circuit-to-svg-version": version
5573
5966
  }
5574
5967
  },
5575
5968
  children: [
@@ -5621,18 +6014,18 @@ var circuitJsonToSchematicSvg = convertCircuitJsonToSchematicSvg;
5621
6014
  // lib/pcb/convert-circuit-json-to-solder-paste-mask.ts
5622
6015
  import { stringify as stringify4 } from "svgson";
5623
6016
  import {
5624
- applyToPoint as applyToPoint44,
6017
+ applyToPoint as applyToPoint45,
5625
6018
  compose as compose11,
5626
6019
  scale as scale8,
5627
6020
  translate as translate11
5628
6021
  } from "transformation-matrix";
5629
6022
 
5630
6023
  // lib/pcb/svg-object-fns/convert-circuit-json-to-solder-paste-mask.ts
5631
- import { applyToPoint as applyToPoint43 } from "transformation-matrix";
6024
+ import { applyToPoint as applyToPoint44 } from "transformation-matrix";
5632
6025
  function createSvgObjectsFromSolderPaste(solderPaste, ctx) {
5633
6026
  const { transform, layer: layerFilter } = ctx;
5634
6027
  if (layerFilter && solderPaste.layer !== layerFilter) return [];
5635
- const [x, y] = applyToPoint43(transform, [solderPaste.x, solderPaste.y]);
6028
+ const [x, y] = applyToPoint44(transform, [solderPaste.x, solderPaste.y]);
5636
6029
  if (solderPaste.shape === "rect" || solderPaste.shape === "rotated_rect") {
5637
6030
  const width = solderPaste.width * Math.abs(transform.a);
5638
6031
  const height = solderPaste.height * Math.abs(transform.d);
@@ -5757,6 +6150,7 @@ function convertCircuitJsonToSolderPasteMask(circuitJson, options) {
5757
6150
  (a, b) => (OBJECT_ORDER3.indexOf(b.type) ?? 9999) - (OBJECT_ORDER3.indexOf(a.type) ?? 9999)
5758
6151
  ).flatMap((item) => createSvgObjects3({ elm: item, ctx }));
5759
6152
  const softwareUsedString = getSoftwareUsedString(circuitJson);
6153
+ const version = CIRCUIT_TO_SVG_VERSION;
5760
6154
  const svgObject = {
5761
6155
  name: "svg",
5762
6156
  type: "element",
@@ -5766,6 +6160,9 @@ function convertCircuitJsonToSolderPasteMask(circuitJson, options) {
5766
6160
  height: svgHeight.toString(),
5767
6161
  ...softwareUsedString && {
5768
6162
  "data-software-used-string": softwareUsedString
6163
+ },
6164
+ ...options.includeVersion && {
6165
+ "data-circuit-to-svg-version": version
5769
6166
  }
5770
6167
  },
5771
6168
  value: "",
@@ -5831,8 +6228,8 @@ function createSvgObjects3({ elm, ctx }) {
5831
6228
  }
5832
6229
  }
5833
6230
  function createSvgObjectFromPcbBoundary2(transform, minX, minY, maxX, maxY) {
5834
- const [x1, y1] = applyToPoint44(transform, [minX, minY]);
5835
- const [x2, y2] = applyToPoint44(transform, [maxX, maxY]);
6231
+ const [x1, y1] = applyToPoint45(transform, [minX, minY]);
6232
+ const [x2, y2] = applyToPoint45(transform, [maxX, maxY]);
5836
6233
  const width = Math.abs(x2 - x1);
5837
6234
  const height = Math.abs(y2 - y1);
5838
6235
  const x = Math.min(x1, x2);
@@ -5855,6 +6252,7 @@ function createSvgObjectFromPcbBoundary2(transform, minX, minY, maxX, maxY) {
5855
6252
  };
5856
6253
  }
5857
6254
  export {
6255
+ CIRCUIT_TO_SVG_VERSION,
5858
6256
  circuitJsonToPcbSvg,
5859
6257
  circuitJsonToSchematicSvg,
5860
6258
  convertCircuitJsonToAssemblySvg,