circuit-to-svg 0.0.210 → 0.0.211
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 +7 -2
- package/dist/index.js +385 -227
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1783,7 +1783,7 @@ function getSoftwareUsedString(circuitJson) {
|
|
|
1783
1783
|
var package_default = {
|
|
1784
1784
|
name: "circuit-to-svg",
|
|
1785
1785
|
type: "module",
|
|
1786
|
-
version: "0.0.
|
|
1786
|
+
version: "0.0.210",
|
|
1787
1787
|
description: "Convert Circuit JSON to SVG",
|
|
1788
1788
|
main: "dist/index.js",
|
|
1789
1789
|
files: [
|
|
@@ -3211,7 +3211,7 @@ function createSvgObjectsFromPinoutComponent(elm, ctx) {
|
|
|
3211
3211
|
const [x, y] = applyToPoint29(transform, [center.x, center.y]);
|
|
3212
3212
|
const scaledWidth = width * Math.abs(transform.a);
|
|
3213
3213
|
const scaledHeight = height * Math.abs(transform.d);
|
|
3214
|
-
const transformStr = `translate(${x}, ${y})
|
|
3214
|
+
const transformStr = `translate(${x}, ${y})`;
|
|
3215
3215
|
const children = [
|
|
3216
3216
|
{
|
|
3217
3217
|
name: "rect",
|
|
@@ -3222,14 +3222,14 @@ function createSvgObjectsFromPinoutComponent(elm, ctx) {
|
|
|
3222
3222
|
y: (-scaledHeight / 2).toString(),
|
|
3223
3223
|
width: scaledWidth.toString(),
|
|
3224
3224
|
height: scaledHeight.toString(),
|
|
3225
|
-
fill: COMPONENT_FILL_COLOR
|
|
3225
|
+
fill: COMPONENT_FILL_COLOR,
|
|
3226
|
+
transform: `rotate(${rotation}deg)`
|
|
3226
3227
|
},
|
|
3227
3228
|
value: "",
|
|
3228
3229
|
children: []
|
|
3229
3230
|
}
|
|
3230
3231
|
];
|
|
3231
3232
|
if (sourceComponent?.name) {
|
|
3232
|
-
const isTall = scaledHeight > scaledWidth * 1.5;
|
|
3233
3233
|
const labelFontSize = Math.min(scaledWidth, scaledHeight) * 0.4;
|
|
3234
3234
|
children.push({
|
|
3235
3235
|
name: "text",
|
|
@@ -3241,8 +3241,7 @@ function createSvgObjectsFromPinoutComponent(elm, ctx) {
|
|
|
3241
3241
|
"font-size": `${labelFontSize}px`,
|
|
3242
3242
|
"font-family": "sans-serif",
|
|
3243
3243
|
"text-anchor": "middle",
|
|
3244
|
-
"dominant-baseline": "middle"
|
|
3245
|
-
transform: isTall ? "rotate(90)" : ""
|
|
3244
|
+
"dominant-baseline": "middle"
|
|
3246
3245
|
},
|
|
3247
3246
|
children: [
|
|
3248
3247
|
{
|
|
@@ -3694,9 +3693,77 @@ function createSvgObjectsFromPinoutSmtPad(pad, ctx) {
|
|
|
3694
3693
|
// lib/pinout/svg-object-fns/create-svg-objects-from-pinout-port.ts
|
|
3695
3694
|
import { applyToPoint as applyToPoint33 } from "transformation-matrix";
|
|
3696
3695
|
import { calculateElbow } from "calculate-elbow";
|
|
3696
|
+
|
|
3697
|
+
// lib/pinout/svg-object-fns/pinout-label-box.ts
|
|
3698
|
+
function createPinoutLabelBox(params) {
|
|
3699
|
+
const {
|
|
3700
|
+
rectX,
|
|
3701
|
+
rectY,
|
|
3702
|
+
rectWidth,
|
|
3703
|
+
rectHeight,
|
|
3704
|
+
textX,
|
|
3705
|
+
textY,
|
|
3706
|
+
text,
|
|
3707
|
+
fontSize,
|
|
3708
|
+
labelBackground,
|
|
3709
|
+
labelColor,
|
|
3710
|
+
rx = 4,
|
|
3711
|
+
ry = 4,
|
|
3712
|
+
fontFamily = "Arial, sans-serif",
|
|
3713
|
+
fontWeight = "bold",
|
|
3714
|
+
textAnchor = "middle",
|
|
3715
|
+
dominantBaseline = "middle"
|
|
3716
|
+
} = params;
|
|
3717
|
+
return [
|
|
3718
|
+
{
|
|
3719
|
+
name: "rect",
|
|
3720
|
+
type: "element",
|
|
3721
|
+
attributes: {
|
|
3722
|
+
x: rectX.toString(),
|
|
3723
|
+
y: rectY.toString(),
|
|
3724
|
+
width: rectWidth.toString(),
|
|
3725
|
+
height: rectHeight.toString(),
|
|
3726
|
+
fill: labelBackground,
|
|
3727
|
+
rx: typeof rx === "number" ? rx.toString() : rx,
|
|
3728
|
+
ry: typeof ry === "number" ? ry.toString() : ry,
|
|
3729
|
+
stroke: "none"
|
|
3730
|
+
},
|
|
3731
|
+
children: [],
|
|
3732
|
+
value: ""
|
|
3733
|
+
},
|
|
3734
|
+
{
|
|
3735
|
+
name: "text",
|
|
3736
|
+
type: "element",
|
|
3737
|
+
attributes: {
|
|
3738
|
+
x: textX.toString(),
|
|
3739
|
+
y: textY.toString(),
|
|
3740
|
+
fill: labelColor,
|
|
3741
|
+
"font-size": `${fontSize}px`,
|
|
3742
|
+
"font-family": fontFamily,
|
|
3743
|
+
"font-weight": fontWeight,
|
|
3744
|
+
"text-anchor": textAnchor,
|
|
3745
|
+
"dominant-baseline": dominantBaseline
|
|
3746
|
+
},
|
|
3747
|
+
children: [
|
|
3748
|
+
{
|
|
3749
|
+
type: "text",
|
|
3750
|
+
value: text,
|
|
3751
|
+
name: "",
|
|
3752
|
+
attributes: {},
|
|
3753
|
+
children: []
|
|
3754
|
+
}
|
|
3755
|
+
],
|
|
3756
|
+
value: ""
|
|
3757
|
+
}
|
|
3758
|
+
];
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
// lib/pinout/svg-object-fns/create-svg-objects-from-pinout-port.ts
|
|
3697
3762
|
var LABEL_COLOR = "rgb(255, 255, 255)";
|
|
3698
3763
|
var LABEL_BACKGROUND = "rgb(0, 0, 0)";
|
|
3699
3764
|
var LINE_COLOR = "rgba(0, 0, 0, 0.6)";
|
|
3765
|
+
var PIN_NUMBER_BACKGROUND = "rgb(200, 200, 200)";
|
|
3766
|
+
var PIN_NUMBER_COLOR = "rgb(0, 0, 0)";
|
|
3700
3767
|
function createSvgObjectsFromPinoutPort(pcb_port, ctx) {
|
|
3701
3768
|
const label_info = ctx.label_positions.get(pcb_port.pcb_port_id);
|
|
3702
3769
|
if (!label_info) return [];
|
|
@@ -3718,26 +3785,33 @@ function createSvgObjectsFromPinoutPort(pcb_port, ctx) {
|
|
|
3718
3785
|
{}
|
|
3719
3786
|
);
|
|
3720
3787
|
const line_points = [...elbow_path, label_pos].map((p) => `${p.x},${p.y}`).join(" ");
|
|
3721
|
-
const
|
|
3722
|
-
const
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3788
|
+
const numberMatch = /^pin(\d+)$/i.exec(label);
|
|
3789
|
+
const tokensWithStyle = [
|
|
3790
|
+
{
|
|
3791
|
+
text: numberMatch ? numberMatch[1] : label,
|
|
3792
|
+
bg: numberMatch ? PIN_NUMBER_BACKGROUND : LABEL_BACKGROUND,
|
|
3793
|
+
color: numberMatch ? PIN_NUMBER_COLOR : LABEL_COLOR
|
|
3794
|
+
},
|
|
3795
|
+
...aliases.map((t) => ({
|
|
3796
|
+
text: t,
|
|
3797
|
+
bg: LABEL_BACKGROUND,
|
|
3798
|
+
color: LABEL_COLOR
|
|
3799
|
+
}))
|
|
3800
|
+
];
|
|
3801
|
+
const scale10 = Math.abs(ctx.transform.a);
|
|
3802
|
+
const LABEL_RECT_HEIGHT_MM2 = 2.2;
|
|
3803
|
+
const rectHeight = LABEL_RECT_HEIGHT_MM2 * scale10;
|
|
3804
|
+
const fontSize = rectHeight * (11 / 21);
|
|
3805
|
+
const bgPadding = (rectHeight - fontSize) / 2;
|
|
3806
|
+
const gap = bgPadding;
|
|
3807
|
+
const tokenRects = tokensWithStyle.map(({ text, bg, color }) => {
|
|
3808
|
+
const safeText = text ?? "";
|
|
3809
|
+
const textWidth = safeText.length * fontSize * 0.6;
|
|
3810
|
+
const rectWidth = textWidth + 2 * bgPadding;
|
|
3811
|
+
return { text: safeText, rectWidth, bg, color };
|
|
3812
|
+
});
|
|
3727
3813
|
const text_y = label_pos.y;
|
|
3728
|
-
|
|
3729
|
-
let text_x;
|
|
3730
|
-
if (edge === "left") {
|
|
3731
|
-
rectX = label_pos.x - rectWidth;
|
|
3732
|
-
text_x = label_pos.x - rectWidth / 2;
|
|
3733
|
-
} else if (edge === "right") {
|
|
3734
|
-
rectX = label_pos.x;
|
|
3735
|
-
text_x = label_pos.x + rectWidth / 2;
|
|
3736
|
-
} else {
|
|
3737
|
-
rectX = label_pos.x - rectWidth / 2;
|
|
3738
|
-
text_x = label_pos.x;
|
|
3739
|
-
}
|
|
3740
|
-
return [
|
|
3814
|
+
const objects = [
|
|
3741
3815
|
{
|
|
3742
3816
|
name: "polyline",
|
|
3743
3817
|
type: "element",
|
|
@@ -3749,202 +3823,239 @@ function createSvgObjectsFromPinoutPort(pcb_port, ctx) {
|
|
|
3749
3823
|
},
|
|
3750
3824
|
children: [],
|
|
3751
3825
|
value: ""
|
|
3752
|
-
},
|
|
3753
|
-
{
|
|
3754
|
-
name: "rect",
|
|
3755
|
-
type: "element",
|
|
3756
|
-
attributes: {
|
|
3757
|
-
x: rectX.toString(),
|
|
3758
|
-
y: (text_y - rectHeight / 2).toString(),
|
|
3759
|
-
width: rectWidth.toString(),
|
|
3760
|
-
height: rectHeight.toString(),
|
|
3761
|
-
fill: LABEL_BACKGROUND,
|
|
3762
|
-
rx: "8",
|
|
3763
|
-
// More rounded corners
|
|
3764
|
-
ry: "8",
|
|
3765
|
-
stroke: "none"
|
|
3766
|
-
},
|
|
3767
|
-
children: [],
|
|
3768
|
-
value: ""
|
|
3769
|
-
},
|
|
3770
|
-
{
|
|
3771
|
-
name: "text",
|
|
3772
|
-
type: "element",
|
|
3773
|
-
attributes: {
|
|
3774
|
-
x: text_x.toString(),
|
|
3775
|
-
y: text_y.toString(),
|
|
3776
|
-
fill: LABEL_COLOR,
|
|
3777
|
-
"font-size": `${fontSize}px`,
|
|
3778
|
-
"font-family": "Arial, sans-serif",
|
|
3779
|
-
"font-weight": "bold",
|
|
3780
|
-
"text-anchor": "middle",
|
|
3781
|
-
"dominant-baseline": "middle"
|
|
3782
|
-
},
|
|
3783
|
-
children: [
|
|
3784
|
-
{
|
|
3785
|
-
type: "text",
|
|
3786
|
-
value: full_label,
|
|
3787
|
-
name: "",
|
|
3788
|
-
attributes: {},
|
|
3789
|
-
children: []
|
|
3790
|
-
}
|
|
3791
|
-
],
|
|
3792
|
-
value: ""
|
|
3793
3826
|
}
|
|
3794
3827
|
];
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3828
|
+
if (edge === "left") {
|
|
3829
|
+
let currentX = label_pos.x;
|
|
3830
|
+
for (const { text, rectWidth, bg, color } of tokenRects) {
|
|
3831
|
+
const rectX = currentX - rectWidth;
|
|
3832
|
+
const text_x = rectX + rectWidth / 2;
|
|
3833
|
+
objects.push(
|
|
3834
|
+
...createPinoutLabelBox({
|
|
3835
|
+
rectX,
|
|
3836
|
+
rectY: text_y - rectHeight / 2,
|
|
3837
|
+
rectWidth,
|
|
3838
|
+
rectHeight,
|
|
3839
|
+
textX: text_x,
|
|
3840
|
+
textY: text_y,
|
|
3841
|
+
text,
|
|
3842
|
+
fontSize,
|
|
3843
|
+
labelBackground: bg,
|
|
3844
|
+
labelColor: color
|
|
3845
|
+
})
|
|
3846
|
+
);
|
|
3847
|
+
currentX = rectX - gap;
|
|
3848
|
+
}
|
|
3849
|
+
} else if (edge === "right") {
|
|
3850
|
+
let currentX = label_pos.x;
|
|
3851
|
+
for (const { text, rectWidth, bg, color } of tokenRects) {
|
|
3852
|
+
const rectX = currentX;
|
|
3853
|
+
const text_x = rectX + rectWidth / 2;
|
|
3854
|
+
objects.push(
|
|
3855
|
+
...createPinoutLabelBox({
|
|
3856
|
+
rectX,
|
|
3857
|
+
rectY: text_y - rectHeight / 2,
|
|
3858
|
+
rectWidth,
|
|
3859
|
+
rectHeight,
|
|
3860
|
+
textX: text_x,
|
|
3861
|
+
textY: text_y,
|
|
3862
|
+
text,
|
|
3863
|
+
fontSize,
|
|
3864
|
+
labelBackground: bg,
|
|
3865
|
+
labelColor: color
|
|
3866
|
+
})
|
|
3867
|
+
);
|
|
3868
|
+
currentX = rectX + rectWidth + gap;
|
|
3869
|
+
}
|
|
3870
|
+
} else {
|
|
3871
|
+
const totalWidth = tokenRects.reduce((acc, t) => acc + t.rectWidth, 0) + gap * Math.max(0, tokenRects.length - 1);
|
|
3872
|
+
let currentX = label_pos.x - totalWidth / 2;
|
|
3873
|
+
for (const { text, rectWidth, bg, color } of tokenRects) {
|
|
3874
|
+
const rectX = currentX;
|
|
3875
|
+
const text_x = rectX + rectWidth / 2;
|
|
3876
|
+
objects.push(
|
|
3877
|
+
...createPinoutLabelBox({
|
|
3878
|
+
rectX,
|
|
3879
|
+
rectY: text_y - rectHeight / 2,
|
|
3880
|
+
rectWidth,
|
|
3881
|
+
rectHeight,
|
|
3882
|
+
textX: text_x,
|
|
3883
|
+
textY: text_y,
|
|
3884
|
+
text,
|
|
3885
|
+
fontSize,
|
|
3886
|
+
labelBackground: bg,
|
|
3887
|
+
labelColor: color
|
|
3888
|
+
})
|
|
3889
|
+
);
|
|
3890
|
+
currentX = rectX + rectWidth + gap;
|
|
3891
|
+
}
|
|
3834
3892
|
}
|
|
3835
|
-
return
|
|
3893
|
+
return objects;
|
|
3836
3894
|
}
|
|
3837
3895
|
|
|
3838
3896
|
// lib/pinout/calculate-label-positions.ts
|
|
3897
|
+
import "@tscircuit/circuit-json-util";
|
|
3898
|
+
import { applyToPoint as applyToPoint34 } from "transformation-matrix";
|
|
3839
3899
|
var STAGGER_OFFSET_MIN = 20;
|
|
3840
|
-
var STAGGER_OFFSET_PER_PIN =
|
|
3841
|
-
var STAGGER_OFFSET_STEP =
|
|
3900
|
+
var STAGGER_OFFSET_PER_PIN = 3;
|
|
3901
|
+
var STAGGER_OFFSET_STEP = 18;
|
|
3842
3902
|
var ALIGNED_OFFSET_MARGIN = 10;
|
|
3843
|
-
var
|
|
3844
|
-
var
|
|
3845
|
-
|
|
3846
|
-
var LABEL_MARGIN = 5;
|
|
3847
|
-
function calculateVerticalEdgeLabels(edge, ports, {
|
|
3903
|
+
var LABEL_RECT_HEIGHT_MM = 1.6;
|
|
3904
|
+
var LABEL_PITCH_MM = 2.54;
|
|
3905
|
+
function calculateVerticalEdgeLabels(edge, pinout_labels, {
|
|
3848
3906
|
transform,
|
|
3849
3907
|
soup,
|
|
3850
3908
|
board_bounds,
|
|
3851
3909
|
svgHeight
|
|
3852
3910
|
}, label_positions) {
|
|
3853
|
-
const
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3911
|
+
const x_coords = pinout_labels.map((l) => l.pcb_port.x);
|
|
3912
|
+
const counts = {};
|
|
3913
|
+
for (const x of x_coords) {
|
|
3914
|
+
const rounded = x.toFixed(1);
|
|
3915
|
+
counts[rounded] = (counts[rounded] || 0) + 1;
|
|
3916
|
+
}
|
|
3917
|
+
let edge_ports;
|
|
3918
|
+
if (Object.keys(counts).length > 1 && pinout_labels.length > 2) {
|
|
3919
|
+
const sorted_x_groups = Object.entries(counts).sort((a, b) => b[1] - a[1]);
|
|
3920
|
+
const primary_x = parseFloat(sorted_x_groups[0][0]);
|
|
3921
|
+
const primary_pins = pinout_labels.filter(
|
|
3922
|
+
(l) => Math.abs(l.pcb_port.x - primary_x) < 0.2
|
|
3923
|
+
);
|
|
3924
|
+
const other_pins = pinout_labels.filter(
|
|
3925
|
+
(l) => Math.abs(l.pcb_port.x - primary_x) >= 0.2
|
|
3926
|
+
);
|
|
3927
|
+
const mapToEdgePort = (pinout_label) => ({
|
|
3928
|
+
pcb_port: pinout_label.pcb_port,
|
|
3929
|
+
y: applyToPoint34(transform, [
|
|
3930
|
+
pinout_label.pcb_port.x,
|
|
3931
|
+
pinout_label.pcb_port.y
|
|
3932
|
+
])[1],
|
|
3933
|
+
aliases: pinout_label.aliases
|
|
3934
|
+
});
|
|
3935
|
+
primary_pins.sort((a, b) => b.pcb_port.y - a.pcb_port.y);
|
|
3936
|
+
other_pins.sort((a, b) => b.pcb_port.y - a.pcb_port.y);
|
|
3937
|
+
const max_y_primary = primary_pins.length > 0 ? Math.max(...primary_pins.map((p) => p.pcb_port.y)) : -Infinity;
|
|
3938
|
+
const max_y_other = other_pins.length > 0 ? Math.max(...other_pins.map((p) => p.pcb_port.y)) : -Infinity;
|
|
3939
|
+
const combined_pins = max_y_other > max_y_primary ? [...other_pins, ...primary_pins] : [...primary_pins, ...other_pins];
|
|
3940
|
+
edge_ports = combined_pins.map(mapToEdgePort);
|
|
3941
|
+
} else {
|
|
3942
|
+
edge_ports = pinout_labels.map((pinout_label) => ({
|
|
3943
|
+
pcb_port: pinout_label.pcb_port,
|
|
3944
|
+
y: applyToPoint34(transform, [
|
|
3945
|
+
pinout_label.pcb_port.x,
|
|
3946
|
+
pinout_label.pcb_port.y
|
|
3947
|
+
])[1],
|
|
3948
|
+
aliases: pinout_label.aliases
|
|
3949
|
+
})).sort((a, b) => a.y - b.y);
|
|
3950
|
+
}
|
|
3858
3951
|
if (edge_ports.length === 0) return;
|
|
3859
3952
|
const board_edge_x = applyToPoint34(transform, [
|
|
3860
3953
|
edge === "left" ? board_bounds.minX : board_bounds.maxX,
|
|
3861
3954
|
0
|
|
3862
3955
|
])[0];
|
|
3863
3956
|
const num_labels = edge_ports.length;
|
|
3864
|
-
const
|
|
3957
|
+
const x_coords_counts = {};
|
|
3958
|
+
for (const pl of pinout_labels) {
|
|
3959
|
+
const rounded = pl.pcb_port.x.toFixed(1);
|
|
3960
|
+
x_coords_counts[rounded] = (x_coords_counts[rounded] || 0) + 1;
|
|
3961
|
+
}
|
|
3962
|
+
let main_group_pin_port_ids = /* @__PURE__ */ new Set();
|
|
3963
|
+
if (Object.keys(x_coords_counts).length > 1 && pinout_labels.length > 2) {
|
|
3964
|
+
const sorted_x_groups = Object.entries(x_coords_counts).sort(
|
|
3965
|
+
(a, b) => b[1] - a[1]
|
|
3966
|
+
);
|
|
3967
|
+
const primary_x = parseFloat(sorted_x_groups[0][0]);
|
|
3968
|
+
const primary_pins = pinout_labels.filter(
|
|
3969
|
+
(l) => Math.abs(l.pcb_port.x - primary_x) < 0.2
|
|
3970
|
+
);
|
|
3971
|
+
main_group_pin_port_ids = new Set(
|
|
3972
|
+
primary_pins.map((p) => p.pcb_port.pcb_port_id)
|
|
3973
|
+
);
|
|
3974
|
+
}
|
|
3975
|
+
const main_group_indices = edge_ports.map((ep, i) => {
|
|
3976
|
+
if (main_group_pin_port_ids.has(ep.pcb_port.pcb_port_id)) {
|
|
3977
|
+
return i;
|
|
3978
|
+
}
|
|
3979
|
+
return -1;
|
|
3980
|
+
}).filter((i) => i !== -1);
|
|
3981
|
+
const geometric_middle_index = (num_labels - 1) / 2;
|
|
3982
|
+
const scale10 = Math.abs(transform.a);
|
|
3983
|
+
const label_rect_height = LABEL_RECT_HEIGHT_MM * scale10;
|
|
3984
|
+
const label_pitch = LABEL_PITCH_MM * scale10;
|
|
3985
|
+
const label_margin = Math.max(0, label_pitch - label_rect_height);
|
|
3865
3986
|
const stagger_offset_base = STAGGER_OFFSET_MIN + num_labels * STAGGER_OFFSET_PER_PIN;
|
|
3866
|
-
const max_stagger_offset = stagger_offset_base +
|
|
3987
|
+
const max_stagger_offset = stagger_offset_base + geometric_middle_index * STAGGER_OFFSET_STEP;
|
|
3867
3988
|
const aligned_label_offset = max_stagger_offset + ALIGNED_OFFSET_MARGIN;
|
|
3868
|
-
const
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3989
|
+
const num_other_pins = num_labels - main_group_indices.length;
|
|
3990
|
+
const num_pins_to_stack = main_group_indices.length === 0 ? num_labels : num_other_pins;
|
|
3991
|
+
const stack_total_height = num_pins_to_stack * label_rect_height + Math.max(0, num_pins_to_stack - 1) * label_margin;
|
|
3992
|
+
let current_y;
|
|
3993
|
+
if (main_group_indices.length > 0 && num_other_pins > 0) {
|
|
3994
|
+
const main_group_y_coords = main_group_indices.map((i) => edge_ports[i].y);
|
|
3995
|
+
const min_main_group_y = Math.min(...main_group_y_coords);
|
|
3996
|
+
const max_main_group_y = Math.max(...main_group_y_coords);
|
|
3997
|
+
const main_group_top_extent = min_main_group_y - label_rect_height / 2;
|
|
3998
|
+
const main_group_bottom_extent = max_main_group_y + label_rect_height / 2;
|
|
3999
|
+
const other_pin_indices = edge_ports.map((_, index) => index).filter((index) => !main_group_indices.includes(index));
|
|
4000
|
+
const others_are_above = other_pin_indices[0] < main_group_indices[0];
|
|
4001
|
+
if (others_are_above) {
|
|
4002
|
+
const stack_bottom_edge = main_group_top_extent - label_margin;
|
|
4003
|
+
current_y = stack_bottom_edge - stack_total_height + label_rect_height / 2;
|
|
4004
|
+
} else {
|
|
4005
|
+
const stack_top_edge = main_group_bottom_extent + label_margin;
|
|
4006
|
+
current_y = stack_top_edge + label_rect_height / 2;
|
|
4007
|
+
}
|
|
4008
|
+
} else {
|
|
4009
|
+
current_y = (svgHeight - stack_total_height) / 2 + label_rect_height / 2;
|
|
4010
|
+
}
|
|
4011
|
+
const is_all_main_group = main_group_indices.length === num_labels;
|
|
4012
|
+
edge_ports.forEach(({ pcb_port, aliases }, i) => {
|
|
4013
|
+
let stagger_rank;
|
|
4014
|
+
if (main_group_indices.length > 0) {
|
|
4015
|
+
if (main_group_indices.includes(i)) {
|
|
4016
|
+
stagger_rank = geometric_middle_index;
|
|
4017
|
+
} else {
|
|
4018
|
+
const min_lg_idx = Math.min(...main_group_indices);
|
|
4019
|
+
const max_lg_idx = Math.max(...main_group_indices);
|
|
4020
|
+
let dist_from_main_group;
|
|
4021
|
+
if (i < min_lg_idx) {
|
|
4022
|
+
dist_from_main_group = min_lg_idx - i;
|
|
4023
|
+
} else {
|
|
4024
|
+
dist_from_main_group = i - max_lg_idx;
|
|
4025
|
+
}
|
|
4026
|
+
stagger_rank = geometric_middle_index - dist_from_main_group;
|
|
4027
|
+
}
|
|
4028
|
+
} else {
|
|
4029
|
+
const dist_from_middle = Math.abs(i - geometric_middle_index);
|
|
4030
|
+
stagger_rank = geometric_middle_index - dist_from_middle;
|
|
4031
|
+
}
|
|
3873
4032
|
const stagger_offset = stagger_offset_base + stagger_rank * STAGGER_OFFSET_STEP;
|
|
3874
4033
|
const sign = edge === "left" ? -1 : 1;
|
|
4034
|
+
const is_main_group_pin = main_group_indices.includes(i);
|
|
4035
|
+
const y_pos = is_all_main_group ? edge_ports[i].y : main_group_indices.length > 0 && is_main_group_pin ? edge_ports[i].y : current_y;
|
|
3875
4036
|
const elbow_end = {
|
|
3876
4037
|
x: board_edge_x + sign * stagger_offset,
|
|
3877
|
-
y:
|
|
4038
|
+
y: y_pos
|
|
3878
4039
|
};
|
|
3879
4040
|
const label_pos = {
|
|
3880
4041
|
x: board_edge_x + sign * aligned_label_offset,
|
|
3881
|
-
y:
|
|
4042
|
+
y: y_pos
|
|
3882
4043
|
};
|
|
3883
|
-
label_positions.set(
|
|
3884
|
-
text:
|
|
3885
|
-
aliases:
|
|
4044
|
+
label_positions.set(pcb_port.pcb_port_id, {
|
|
4045
|
+
text: aliases[0],
|
|
4046
|
+
aliases: aliases.slice(1),
|
|
3886
4047
|
elbow_end,
|
|
3887
4048
|
label_pos,
|
|
3888
4049
|
edge
|
|
3889
4050
|
});
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
}
|
|
3893
|
-
function calculateHorizontalEdgeLabels(edge, ports, {
|
|
3894
|
-
transform,
|
|
3895
|
-
soup,
|
|
3896
|
-
board_bounds,
|
|
3897
|
-
svgWidth
|
|
3898
|
-
}, label_positions) {
|
|
3899
|
-
const edge_ports = ports.map((port) => ({
|
|
3900
|
-
port,
|
|
3901
|
-
x: applyToPoint34(transform, [port.x, port.y])[0],
|
|
3902
|
-
label_info: getPortLabelInfo(port, soup)
|
|
3903
|
-
})).filter((p) => p.label_info).sort((a, b) => a.x - b.x);
|
|
3904
|
-
if (edge_ports.length === 0) return;
|
|
3905
|
-
const board_edge_y = applyToPoint34(transform, [
|
|
3906
|
-
0,
|
|
3907
|
-
edge === "top" ? board_bounds.maxY : board_bounds.minY
|
|
3908
|
-
])[1];
|
|
3909
|
-
const labels_with_widths = edge_ports.map((p) => {
|
|
3910
|
-
const label = [p.label_info.text, ...p.label_info.aliases].join(" | ");
|
|
3911
|
-
const textWidth = label.length * FONT_SIZE * 0.6;
|
|
3912
|
-
const rectWidth = textWidth + 2 * BG_PADDING;
|
|
3913
|
-
return { ...p, rectWidth };
|
|
3914
|
-
});
|
|
3915
|
-
const num_labels = labels_with_widths.length;
|
|
3916
|
-
const middle_index = (num_labels - 1) / 2;
|
|
3917
|
-
const stagger_offset_base = STAGGER_OFFSET_MIN + num_labels * STAGGER_OFFSET_PER_PIN;
|
|
3918
|
-
const max_stagger_offset = stagger_offset_base + middle_index * STAGGER_OFFSET_STEP;
|
|
3919
|
-
const aligned_label_offset = max_stagger_offset + ALIGNED_OFFSET_MARGIN;
|
|
3920
|
-
const total_labels_width = labels_with_widths.reduce((sum, l) => sum + l.rectWidth, 0) + Math.max(0, num_labels - 1) * LABEL_MARGIN;
|
|
3921
|
-
let current_x = (svgWidth - total_labels_width) / 2;
|
|
3922
|
-
labels_with_widths.forEach(({ port, label_info, rectWidth }, i) => {
|
|
3923
|
-
const dist_from_middle = Math.abs(i - middle_index);
|
|
3924
|
-
const stagger_rank = middle_index - dist_from_middle;
|
|
3925
|
-
const stagger_offset = stagger_offset_base + stagger_rank * STAGGER_OFFSET_STEP;
|
|
3926
|
-
const sign = edge === "top" ? -1 : 1;
|
|
3927
|
-
const label_center_x = current_x + rectWidth / 2;
|
|
3928
|
-
const elbow_end = {
|
|
3929
|
-
x: label_center_x,
|
|
3930
|
-
y: board_edge_y + sign * stagger_offset
|
|
3931
|
-
};
|
|
3932
|
-
const label_pos = {
|
|
3933
|
-
x: label_center_x,
|
|
3934
|
-
y: board_edge_y + sign * aligned_label_offset
|
|
3935
|
-
};
|
|
3936
|
-
label_positions.set(port.pcb_port_id, {
|
|
3937
|
-
text: label_info.text,
|
|
3938
|
-
aliases: label_info.aliases,
|
|
3939
|
-
elbow_end,
|
|
3940
|
-
label_pos,
|
|
3941
|
-
edge
|
|
3942
|
-
});
|
|
3943
|
-
current_x += rectWidth + LABEL_MARGIN;
|
|
4051
|
+
if (!(main_group_indices.length > 0 && is_main_group_pin)) {
|
|
4052
|
+
current_y += label_rect_height + label_margin;
|
|
4053
|
+
}
|
|
3944
4054
|
});
|
|
3945
4055
|
}
|
|
3946
4056
|
var calculateLabelPositions = ({
|
|
3947
|
-
|
|
4057
|
+
left_labels,
|
|
4058
|
+
right_labels,
|
|
3948
4059
|
transform,
|
|
3949
4060
|
soup,
|
|
3950
4061
|
board_bounds,
|
|
@@ -3955,7 +4066,7 @@ var calculateLabelPositions = ({
|
|
|
3955
4066
|
const shared_params = { transform, soup, board_bounds };
|
|
3956
4067
|
calculateVerticalEdgeLabels(
|
|
3957
4068
|
"left",
|
|
3958
|
-
|
|
4069
|
+
left_labels,
|
|
3959
4070
|
{
|
|
3960
4071
|
...shared_params,
|
|
3961
4072
|
svgHeight
|
|
@@ -3964,34 +4075,54 @@ var calculateLabelPositions = ({
|
|
|
3964
4075
|
);
|
|
3965
4076
|
calculateVerticalEdgeLabels(
|
|
3966
4077
|
"right",
|
|
3967
|
-
|
|
4078
|
+
right_labels,
|
|
3968
4079
|
{
|
|
3969
4080
|
...shared_params,
|
|
3970
4081
|
svgHeight
|
|
3971
4082
|
},
|
|
3972
4083
|
label_positions
|
|
3973
4084
|
);
|
|
3974
|
-
calculateHorizontalEdgeLabels(
|
|
3975
|
-
"top",
|
|
3976
|
-
ports_by_edge.top,
|
|
3977
|
-
{
|
|
3978
|
-
...shared_params,
|
|
3979
|
-
svgWidth
|
|
3980
|
-
},
|
|
3981
|
-
label_positions
|
|
3982
|
-
);
|
|
3983
|
-
calculateHorizontalEdgeLabels(
|
|
3984
|
-
"bottom",
|
|
3985
|
-
ports_by_edge.bottom,
|
|
3986
|
-
{
|
|
3987
|
-
...shared_params,
|
|
3988
|
-
svgWidth
|
|
3989
|
-
},
|
|
3990
|
-
label_positions
|
|
3991
|
-
);
|
|
3992
4085
|
return label_positions;
|
|
3993
4086
|
};
|
|
3994
4087
|
|
|
4088
|
+
// lib/pinout/pinout-utils.ts
|
|
4089
|
+
import { su as su7 } from "@tscircuit/circuit-json-util";
|
|
4090
|
+
function getPortLabelInfo(port, soup) {
|
|
4091
|
+
const source_port = su7(soup).source_port.get(port.source_port_id);
|
|
4092
|
+
if (!source_port) return null;
|
|
4093
|
+
const eligible_hints = source_port.port_hints?.filter(
|
|
4094
|
+
(h) => !/^\d+$/.test(h) && !["left", "right", "top", "bottom"].includes(h)
|
|
4095
|
+
) ?? [];
|
|
4096
|
+
let label = eligible_hints[0];
|
|
4097
|
+
if (!label) label = source_port.name;
|
|
4098
|
+
if (!label) return null;
|
|
4099
|
+
const aliases = eligible_hints.filter((h) => h !== label);
|
|
4100
|
+
return { text: label, aliases };
|
|
4101
|
+
}
|
|
4102
|
+
function getClosestEdge(port_pos_real, board_bounds) {
|
|
4103
|
+
const dists = {
|
|
4104
|
+
left: port_pos_real.x - board_bounds.minX,
|
|
4105
|
+
right: board_bounds.maxX - port_pos_real.x,
|
|
4106
|
+
top: board_bounds.maxY - port_pos_real.y,
|
|
4107
|
+
bottom: port_pos_real.y - board_bounds.minY
|
|
4108
|
+
};
|
|
4109
|
+
let closest_edge = "left";
|
|
4110
|
+
let min_dist = dists.left;
|
|
4111
|
+
if (dists.right < min_dist) {
|
|
4112
|
+
min_dist = dists.right;
|
|
4113
|
+
closest_edge = "right";
|
|
4114
|
+
}
|
|
4115
|
+
if (dists.top < min_dist) {
|
|
4116
|
+
min_dist = dists.top;
|
|
4117
|
+
closest_edge = "top";
|
|
4118
|
+
}
|
|
4119
|
+
if (dists.bottom < min_dist) {
|
|
4120
|
+
min_dist = dists.bottom;
|
|
4121
|
+
closest_edge = "bottom";
|
|
4122
|
+
}
|
|
4123
|
+
return closest_edge;
|
|
4124
|
+
}
|
|
4125
|
+
|
|
3995
4126
|
// lib/pinout/convert-circuit-json-to-pinout-svg.ts
|
|
3996
4127
|
var OBJECT_ORDER3 = [
|
|
3997
4128
|
"pcb_board",
|
|
@@ -4029,8 +4160,8 @@ function convertCircuitJsonToPinoutSvg(soup, options) {
|
|
|
4029
4160
|
const padding = 20;
|
|
4030
4161
|
const circuitWidth = maxX - minX + 2 * padding;
|
|
4031
4162
|
const circuitHeight = maxY - minY + 2 * padding;
|
|
4032
|
-
const svgWidth = options?.width ??
|
|
4033
|
-
const svgHeight = options?.height ??
|
|
4163
|
+
const svgWidth = options?.width ?? 1200;
|
|
4164
|
+
const svgHeight = options?.height ?? 768;
|
|
4034
4165
|
const scaleX = svgWidth / circuitWidth;
|
|
4035
4166
|
const scaleY = svgHeight / circuitHeight;
|
|
4036
4167
|
const scaleFactor = Math.min(scaleX, scaleY);
|
|
@@ -4047,18 +4178,45 @@ function convertCircuitJsonToPinoutSvg(soup, options) {
|
|
|
4047
4178
|
const pinout_ports = soup.filter(
|
|
4048
4179
|
(elm) => elm.type === "pcb_port" && elm.is_board_pinout
|
|
4049
4180
|
);
|
|
4050
|
-
const
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4181
|
+
const pinout_labels = [];
|
|
4182
|
+
for (const pcb_port of pinout_ports) {
|
|
4183
|
+
const label_info = getPortLabelInfo(pcb_port, soup);
|
|
4184
|
+
if (!label_info) continue;
|
|
4185
|
+
const edge = getClosestEdge({ x: pcb_port.x, y: pcb_port.y }, board_bounds);
|
|
4186
|
+
pinout_labels.push({
|
|
4187
|
+
pcb_port,
|
|
4188
|
+
aliases: [label_info.text, ...label_info.aliases],
|
|
4189
|
+
edge
|
|
4190
|
+
});
|
|
4191
|
+
}
|
|
4192
|
+
const left_labels = pinout_labels.filter((p) => p.edge === "left");
|
|
4193
|
+
const right_labels = pinout_labels.filter((p) => p.edge === "right");
|
|
4194
|
+
const top_labels = pinout_labels.filter((p) => p.edge === "top");
|
|
4195
|
+
const bottom_labels = pinout_labels.filter((p) => p.edge === "bottom");
|
|
4196
|
+
const boardCenterX = (minX + maxX) / 2;
|
|
4197
|
+
if (top_labels.length > 0) {
|
|
4198
|
+
const top_left_count = top_labels.filter(
|
|
4199
|
+
(p) => p.pcb_port.x < boardCenterX
|
|
4200
|
+
).length;
|
|
4201
|
+
if (top_left_count > top_labels.length / 2) {
|
|
4202
|
+
left_labels.push(...top_labels);
|
|
4203
|
+
} else {
|
|
4204
|
+
right_labels.push(...top_labels);
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
if (bottom_labels.length > 0) {
|
|
4208
|
+
const bottom_left_count = bottom_labels.filter(
|
|
4209
|
+
(p) => p.pcb_port.x < boardCenterX
|
|
4210
|
+
).length;
|
|
4211
|
+
if (bottom_left_count > bottom_labels.length / 2) {
|
|
4212
|
+
left_labels.push(...bottom_labels);
|
|
4213
|
+
} else {
|
|
4214
|
+
right_labels.push(...bottom_labels);
|
|
4215
|
+
}
|
|
4059
4216
|
}
|
|
4060
4217
|
const label_positions = calculateLabelPositions({
|
|
4061
|
-
|
|
4218
|
+
left_labels,
|
|
4219
|
+
right_labels,
|
|
4062
4220
|
transform,
|
|
4063
4221
|
soup,
|
|
4064
4222
|
board_bounds,
|
|
@@ -5576,7 +5734,7 @@ function getSchematicBoundsFromCircuitJson(soup, padding = 0.5) {
|
|
|
5576
5734
|
}
|
|
5577
5735
|
|
|
5578
5736
|
// lib/sch/svg-object-fns/create-svg-objects-from-sch-component-with-symbol.ts
|
|
5579
|
-
import { su as
|
|
5737
|
+
import { su as su9 } from "@tscircuit/circuit-json-util";
|
|
5580
5738
|
import { symbols } from "schematic-symbols";
|
|
5581
5739
|
import "svgson";
|
|
5582
5740
|
import {
|
|
@@ -5737,10 +5895,10 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
|
|
|
5737
5895
|
})
|
|
5738
5896
|
];
|
|
5739
5897
|
}
|
|
5740
|
-
const schPorts =
|
|
5898
|
+
const schPorts = su9(circuitJson).schematic_port.list({
|
|
5741
5899
|
schematic_component_id: schComponent.schematic_component_id
|
|
5742
5900
|
});
|
|
5743
|
-
const srcComponent =
|
|
5901
|
+
const srcComponent = su9(circuitJson).source_component.get(
|
|
5744
5902
|
schComponent.source_component_id
|
|
5745
5903
|
);
|
|
5746
5904
|
const schPortsWithSymbolPorts = matchSchPortsToSymbolPorts({
|
|
@@ -5948,7 +6106,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
|
|
|
5948
6106
|
};
|
|
5949
6107
|
|
|
5950
6108
|
// lib/sch/svg-object-fns/create-svg-objects-from-sch-component-with-box.ts
|
|
5951
|
-
import { su as
|
|
6109
|
+
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
5952
6110
|
import "schematic-symbols";
|
|
5953
6111
|
import "svgson";
|
|
5954
6112
|
import { applyToPoint as applyToPoint45 } from "transformation-matrix";
|
|
@@ -5959,7 +6117,7 @@ import "@tscircuit/circuit-json-util";
|
|
|
5959
6117
|
|
|
5960
6118
|
// lib/sch/svg-object-fns/create-svg-objects-for-sch-port-box-line.ts
|
|
5961
6119
|
import { applyToPoint as applyToPoint40 } from "transformation-matrix";
|
|
5962
|
-
import { su as
|
|
6120
|
+
import { su as su10 } from "@tscircuit/circuit-json-util";
|
|
5963
6121
|
var PIN_CIRCLE_RADIUS_MM = 0.02;
|
|
5964
6122
|
var createArrow = (tip, angle, size, color, strokeWidth) => {
|
|
5965
6123
|
const arrowAngle = Math.PI / 6;
|
|
@@ -5991,7 +6149,7 @@ var createSvgObjectsForSchPortBoxLine = ({
|
|
|
5991
6149
|
circuitJson
|
|
5992
6150
|
}) => {
|
|
5993
6151
|
const svgObjects = [];
|
|
5994
|
-
const srcPort =
|
|
6152
|
+
const srcPort = su10(circuitJson).source_port.get(schPort.source_port_id);
|
|
5995
6153
|
const realEdgePos = {
|
|
5996
6154
|
x: schPort.center.x,
|
|
5997
6155
|
y: schPort.center.y
|
|
@@ -6392,7 +6550,7 @@ var createSvgObjectsFromSchematicComponentWithBox = ({
|
|
|
6392
6550
|
},
|
|
6393
6551
|
children: []
|
|
6394
6552
|
});
|
|
6395
|
-
const schTexts =
|
|
6553
|
+
const schTexts = su12(circuitJson).schematic_text.list();
|
|
6396
6554
|
for (const schText of schTexts) {
|
|
6397
6555
|
if (schText.schematic_component_id === schComponent.schematic_component_id) {
|
|
6398
6556
|
svgObjects.push(
|
|
@@ -6404,7 +6562,7 @@ var createSvgObjectsFromSchematicComponentWithBox = ({
|
|
|
6404
6562
|
);
|
|
6405
6563
|
}
|
|
6406
6564
|
}
|
|
6407
|
-
const schematicPorts =
|
|
6565
|
+
const schematicPorts = su12(circuitJson).schematic_port.list({
|
|
6408
6566
|
schematic_component_id: schComponent.schematic_component_id
|
|
6409
6567
|
});
|
|
6410
6568
|
for (const schPort of schematicPorts) {
|
|
@@ -7417,7 +7575,7 @@ var createSvgObjectsFromSchematicTable = ({
|
|
|
7417
7575
|
};
|
|
7418
7576
|
|
|
7419
7577
|
// lib/sch/svg-object-fns/create-svg-objects-for-sch-port-hover.ts
|
|
7420
|
-
import { su as
|
|
7578
|
+
import { su as su13 } from "@tscircuit/circuit-json-util";
|
|
7421
7579
|
import { applyToPoint as applyToPoint53 } from "transformation-matrix";
|
|
7422
7580
|
var PIN_CIRCLE_RADIUS_MM2 = 0.02;
|
|
7423
7581
|
var createSvgObjectsForSchPortHover = ({
|
|
@@ -7458,7 +7616,7 @@ var createSvgObjectsForSchComponentPortHovers = ({
|
|
|
7458
7616
|
transform,
|
|
7459
7617
|
circuitJson
|
|
7460
7618
|
}) => {
|
|
7461
|
-
const schematicPorts =
|
|
7619
|
+
const schematicPorts = su13(circuitJson).schematic_port.list({
|
|
7462
7620
|
schematic_component_id: component.schematic_component_id
|
|
7463
7621
|
});
|
|
7464
7622
|
const svgs = [];
|