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/README.md +9 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +467 -69
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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] =
|
|
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] =
|
|
5835
|
-
const [x2, y2] =
|
|
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,
|