@tscircuit/schematic-viewer 2.0.29 → 2.0.31
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/bun.lockb +0 -0
- package/dist/index.js +227 -39
- package/dist/index.js.map +1 -1
- package/examples/example12-spice-boost-converter.fixture.tsx +78 -0
- package/lib/components/SchematicViewer.tsx +16 -3
- package/lib/components/SpicePlot.tsx +11 -1
- package/lib/components/SpiceSimulationOverlay.tsx +127 -1
- package/lib/hooks/useSpiceSimulation.ts +3 -5
- package/lib/utils/spice-utils.ts +53 -6
- package/package.json +6 -5
- /package/examples/{example9-spice-simulation.fixture.tsx → example9-spice-rc-charging-voltage-divider.fixture.tsx} +0 -0
package/bun.lockb
CHANGED
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -457,7 +457,7 @@ var enableDebug = () => {
|
|
|
457
457
|
var debug_default = debug;
|
|
458
458
|
|
|
459
459
|
// lib/components/SchematicViewer.tsx
|
|
460
|
-
import { useEffect as
|
|
460
|
+
import { useEffect as useEffect8, useMemo as useMemo3, useRef as useRef4, useState as useState5 } from "react";
|
|
461
461
|
import {
|
|
462
462
|
fromString,
|
|
463
463
|
identity,
|
|
@@ -962,6 +962,7 @@ var SpiceSimulationIcon = ({
|
|
|
962
962
|
};
|
|
963
963
|
|
|
964
964
|
// lib/components/SpicePlot.tsx
|
|
965
|
+
import { useMemo as useMemo2 } from "react";
|
|
965
966
|
import {
|
|
966
967
|
Chart as ChartJS,
|
|
967
968
|
CategoryScale,
|
|
@@ -1013,6 +1014,14 @@ var SpicePlot = ({
|
|
|
1013
1014
|
isLoading,
|
|
1014
1015
|
error
|
|
1015
1016
|
}) => {
|
|
1017
|
+
const yAxisLabel = useMemo2(() => {
|
|
1018
|
+
const hasVoltage = nodes.some((n) => n.toLowerCase().startsWith("v("));
|
|
1019
|
+
const hasCurrent = nodes.some((n) => n.toLowerCase().startsWith("i("));
|
|
1020
|
+
if (hasVoltage && hasCurrent) return "Value";
|
|
1021
|
+
if (hasVoltage) return "Voltage (V)";
|
|
1022
|
+
if (hasCurrent) return "Current (A)";
|
|
1023
|
+
return "Value";
|
|
1024
|
+
}, [nodes]);
|
|
1016
1025
|
if (isLoading) {
|
|
1017
1026
|
return /* @__PURE__ */ jsx7(
|
|
1018
1027
|
"div",
|
|
@@ -1122,7 +1131,7 @@ var SpicePlot = ({
|
|
|
1122
1131
|
y: {
|
|
1123
1132
|
title: {
|
|
1124
1133
|
display: true,
|
|
1125
|
-
text:
|
|
1134
|
+
text: yAxisLabel,
|
|
1126
1135
|
font: {
|
|
1127
1136
|
family: "sans-serif"
|
|
1128
1137
|
}
|
|
@@ -1139,6 +1148,7 @@ var SpicePlot = ({
|
|
|
1139
1148
|
};
|
|
1140
1149
|
|
|
1141
1150
|
// lib/components/SpiceSimulationOverlay.tsx
|
|
1151
|
+
import { useEffect as useEffect6, useState as useState3 } from "react";
|
|
1142
1152
|
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1143
1153
|
var SpiceSimulationOverlay = ({
|
|
1144
1154
|
spiceString,
|
|
@@ -1146,8 +1156,34 @@ var SpiceSimulationOverlay = ({
|
|
|
1146
1156
|
plotData,
|
|
1147
1157
|
nodes,
|
|
1148
1158
|
isLoading,
|
|
1149
|
-
error
|
|
1159
|
+
error,
|
|
1160
|
+
simOptions,
|
|
1161
|
+
onSimOptionsChange
|
|
1150
1162
|
}) => {
|
|
1163
|
+
const [startTimeDraft, setStartTimeDraft] = useState3(
|
|
1164
|
+
String(simOptions.startTime)
|
|
1165
|
+
);
|
|
1166
|
+
const [durationDraft, setDurationDraft] = useState3(
|
|
1167
|
+
String(simOptions.duration)
|
|
1168
|
+
);
|
|
1169
|
+
useEffect6(() => {
|
|
1170
|
+
setStartTimeDraft(String(simOptions.startTime));
|
|
1171
|
+
setDurationDraft(String(simOptions.duration));
|
|
1172
|
+
}, [simOptions.startTime, simOptions.duration]);
|
|
1173
|
+
const handleRerun = () => {
|
|
1174
|
+
onSimOptionsChange({
|
|
1175
|
+
...simOptions,
|
|
1176
|
+
startTime: Number(startTimeDraft),
|
|
1177
|
+
duration: Number(durationDraft)
|
|
1178
|
+
});
|
|
1179
|
+
};
|
|
1180
|
+
const filteredNodes = nodes.filter((node) => {
|
|
1181
|
+
const isVoltage = node.toLowerCase().startsWith("v(");
|
|
1182
|
+
const isCurrent = node.toLowerCase().startsWith("i(");
|
|
1183
|
+
if (simOptions.showVoltage && isVoltage) return true;
|
|
1184
|
+
if (simOptions.showCurrent && isCurrent) return true;
|
|
1185
|
+
return false;
|
|
1186
|
+
});
|
|
1151
1187
|
return /* @__PURE__ */ jsx8(
|
|
1152
1188
|
"div",
|
|
1153
1189
|
{
|
|
@@ -1223,11 +1259,119 @@ var SpiceSimulationOverlay = ({
|
|
|
1223
1259
|
SpicePlot,
|
|
1224
1260
|
{
|
|
1225
1261
|
plotData,
|
|
1226
|
-
nodes,
|
|
1262
|
+
nodes: filteredNodes,
|
|
1227
1263
|
isLoading,
|
|
1228
1264
|
error
|
|
1229
1265
|
}
|
|
1230
1266
|
) }),
|
|
1267
|
+
/* @__PURE__ */ jsxs5(
|
|
1268
|
+
"div",
|
|
1269
|
+
{
|
|
1270
|
+
style: {
|
|
1271
|
+
marginTop: "16px",
|
|
1272
|
+
padding: "12px",
|
|
1273
|
+
backgroundColor: "#f7f7f7",
|
|
1274
|
+
borderRadius: "6px",
|
|
1275
|
+
display: "flex",
|
|
1276
|
+
flexWrap: "wrap",
|
|
1277
|
+
gap: "24px",
|
|
1278
|
+
alignItems: "center",
|
|
1279
|
+
fontSize: "14px"
|
|
1280
|
+
},
|
|
1281
|
+
children: [
|
|
1282
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "16px" }, children: [
|
|
1283
|
+
/* @__PURE__ */ jsxs5(
|
|
1284
|
+
"label",
|
|
1285
|
+
{
|
|
1286
|
+
style: { display: "flex", alignItems: "center", gap: "6px" },
|
|
1287
|
+
children: [
|
|
1288
|
+
/* @__PURE__ */ jsx8(
|
|
1289
|
+
"input",
|
|
1290
|
+
{
|
|
1291
|
+
type: "checkbox",
|
|
1292
|
+
checked: simOptions.showVoltage,
|
|
1293
|
+
onChange: (e) => onSimOptionsChange({
|
|
1294
|
+
...simOptions,
|
|
1295
|
+
showVoltage: e.target.checked
|
|
1296
|
+
})
|
|
1297
|
+
}
|
|
1298
|
+
),
|
|
1299
|
+
"Voltage"
|
|
1300
|
+
]
|
|
1301
|
+
}
|
|
1302
|
+
),
|
|
1303
|
+
/* @__PURE__ */ jsxs5(
|
|
1304
|
+
"label",
|
|
1305
|
+
{
|
|
1306
|
+
style: { display: "flex", alignItems: "center", gap: "6px" },
|
|
1307
|
+
children: [
|
|
1308
|
+
/* @__PURE__ */ jsx8(
|
|
1309
|
+
"input",
|
|
1310
|
+
{
|
|
1311
|
+
type: "checkbox",
|
|
1312
|
+
checked: simOptions.showCurrent,
|
|
1313
|
+
onChange: (e) => onSimOptionsChange({
|
|
1314
|
+
...simOptions,
|
|
1315
|
+
showCurrent: e.target.checked
|
|
1316
|
+
})
|
|
1317
|
+
}
|
|
1318
|
+
),
|
|
1319
|
+
"Current"
|
|
1320
|
+
]
|
|
1321
|
+
}
|
|
1322
|
+
)
|
|
1323
|
+
] }),
|
|
1324
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "16px", alignItems: "center" }, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx8("label", { htmlFor: "startTime", children: "Start Time (ms):" }),
|
|
1326
|
+
/* @__PURE__ */ jsx8(
|
|
1327
|
+
"input",
|
|
1328
|
+
{
|
|
1329
|
+
id: "startTime",
|
|
1330
|
+
type: "number",
|
|
1331
|
+
value: startTimeDraft,
|
|
1332
|
+
onChange: (e) => setStartTimeDraft(e.target.value),
|
|
1333
|
+
style: {
|
|
1334
|
+
width: "80px",
|
|
1335
|
+
padding: "4px 8px",
|
|
1336
|
+
borderRadius: "4px",
|
|
1337
|
+
border: "1px solid #ccc"
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
),
|
|
1341
|
+
/* @__PURE__ */ jsx8("label", { htmlFor: "duration", children: "Duration (ms):" }),
|
|
1342
|
+
/* @__PURE__ */ jsx8(
|
|
1343
|
+
"input",
|
|
1344
|
+
{
|
|
1345
|
+
id: "duration",
|
|
1346
|
+
type: "number",
|
|
1347
|
+
value: durationDraft,
|
|
1348
|
+
onChange: (e) => setDurationDraft(e.target.value),
|
|
1349
|
+
style: {
|
|
1350
|
+
width: "80px",
|
|
1351
|
+
padding: "4px 8px",
|
|
1352
|
+
borderRadius: "4px",
|
|
1353
|
+
border: "1px solid #ccc"
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
),
|
|
1357
|
+
/* @__PURE__ */ jsx8(
|
|
1358
|
+
"button",
|
|
1359
|
+
{
|
|
1360
|
+
onClick: handleRerun,
|
|
1361
|
+
style: {
|
|
1362
|
+
padding: "4px 12px",
|
|
1363
|
+
borderRadius: "4px",
|
|
1364
|
+
border: "1px solid #ccc",
|
|
1365
|
+
backgroundColor: "#f0f0f0",
|
|
1366
|
+
cursor: "pointer"
|
|
1367
|
+
},
|
|
1368
|
+
children: "Rerun"
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
] })
|
|
1372
|
+
]
|
|
1373
|
+
}
|
|
1374
|
+
),
|
|
1231
1375
|
/* @__PURE__ */ jsxs5("div", { style: { marginTop: "24px" }, children: [
|
|
1232
1376
|
/* @__PURE__ */ jsx8(
|
|
1233
1377
|
"h3",
|
|
@@ -1268,7 +1412,7 @@ var SpiceSimulationOverlay = ({
|
|
|
1268
1412
|
};
|
|
1269
1413
|
|
|
1270
1414
|
// lib/hooks/useSpiceSimulation.ts
|
|
1271
|
-
import { useState as
|
|
1415
|
+
import { useState as useState4, useEffect as useEffect7 } from "react";
|
|
1272
1416
|
|
|
1273
1417
|
// lib/workers/spice-simulation.worker.blob.js
|
|
1274
1418
|
var b64 = "dmFyIGU9bnVsbCxzPWFzeW5jKCk9Pihhd2FpdCBpbXBvcnQoImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWVjaXJjdWl0LWVuZ2luZUAxLjUuMi8rZXNtIikpLlNpbXVsYXRpb24sYz1hc3luYygpPT57aWYoZSYmZS5pc0luaXRpYWxpemVkKCkpcmV0dXJuO2xldCBpPWF3YWl0IHMoKTtlPW5ldyBpLGF3YWl0IGUuc3RhcnQoKX07c2VsZi5vbm1lc3NhZ2U9YXN5bmMgaT0+e3RyeXtpZihhd2FpdCBjKCksIWUpdGhyb3cgbmV3IEVycm9yKCJTaW11bGF0aW9uIG5vdCBpbml0aWFsaXplZCIpO2xldCB0PWkuZGF0YS5zcGljZVN0cmluZyxhPXQubWF0Y2goL3dyZGF0YVxzKyhcUyspXHMrKC4qKS9pKTtpZihhKXtsZXQgbz1gLnByb2JlICR7YVsyXS50cmltKCkuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKX1gO3Q9dC5yZXBsYWNlKC93cmRhdGEuKi9pLG8pfWVsc2UgaWYoIXQubWF0Y2goL1wucHJvYmUvaSkpdGhyb3cgdC5tYXRjaCgvcGxvdFxzKyguKikvaSk/bmV3IEVycm9yKCJUaGUgJ3Bsb3QnIGNvbW1hbmQgaXMgbm90IHN1cHBvcnRlZCBmb3IgZGF0YSBleHRyYWN0aW9uLiBQbGVhc2UgdXNlICd3cmRhdGEgPGZpbGVuYW1lPiA8dmFyMT4gLi4uJyBvciAnLnByb2JlIDx2YXIxPiAuLi4nIGluc3RlYWQuIik6bmV3IEVycm9yKCJObyAnLnByb2JlJyBvciAnd3JkYXRhJyBjb21tYW5kIGZvdW5kIGluIFNQSUNFIGZpbGUuIFVzZSAnd3JkYXRhIDxmaWxlbmFtZT4gPHZhcjE+IC4uLicgdG8gc3BlY2lmeSBvdXRwdXQuIik7ZS5zZXROZXRMaXN0KHQpO2xldCBuPWF3YWl0IGUucnVuU2ltKCk7c2VsZi5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixyZXN1bHQ6bn0pfWNhdGNoKHQpe3NlbGYucG9zdE1lc3NhZ2Uoe3R5cGU6ImVycm9yIixlcnJvcjp0Lm1lc3NhZ2V9KX19Owo=";
|
|
@@ -1308,24 +1452,22 @@ var parseEecEngineOutput = (result) => {
|
|
|
1308
1452
|
}
|
|
1309
1453
|
const timeValues = columnData[timeKey];
|
|
1310
1454
|
const probedVariables = Object.keys(columnData).filter((k) => k !== timeKey);
|
|
1311
|
-
const plotableNodes = probedVariables
|
|
1312
|
-
(n) => n.replace(/v\(([^)]+)\)/i, "$1")
|
|
1313
|
-
);
|
|
1455
|
+
const plotableNodes = probedVariables;
|
|
1314
1456
|
const plotData = timeValues.map((t, i) => {
|
|
1315
1457
|
const point = { name: t.toExponential(2) };
|
|
1316
|
-
probedVariables.forEach((variable
|
|
1317
|
-
point[
|
|
1458
|
+
probedVariables.forEach((variable) => {
|
|
1459
|
+
point[variable] = columnData[variable][i];
|
|
1318
1460
|
});
|
|
1319
1461
|
return point;
|
|
1320
1462
|
});
|
|
1321
1463
|
return { plotData, nodes: plotableNodes };
|
|
1322
1464
|
};
|
|
1323
1465
|
var useSpiceSimulation = (spiceString) => {
|
|
1324
|
-
const [plotData, setPlotData] =
|
|
1325
|
-
const [nodes, setNodes] =
|
|
1326
|
-
const [isLoading, setIsLoading] =
|
|
1327
|
-
const [error, setError] =
|
|
1328
|
-
|
|
1466
|
+
const [plotData, setPlotData] = useState4([]);
|
|
1467
|
+
const [nodes, setNodes] = useState4([]);
|
|
1468
|
+
const [isLoading, setIsLoading] = useState4(true);
|
|
1469
|
+
const [error, setError] = useState4(null);
|
|
1470
|
+
useEffect7(() => {
|
|
1329
1471
|
if (!spiceString) {
|
|
1330
1472
|
setIsLoading(false);
|
|
1331
1473
|
setPlotData([]);
|
|
@@ -1373,7 +1515,19 @@ var useSpiceSimulation = (spiceString) => {
|
|
|
1373
1515
|
|
|
1374
1516
|
// lib/utils/spice-utils.ts
|
|
1375
1517
|
import { circuitJsonToSpice } from "circuit-json-to-spice";
|
|
1376
|
-
var
|
|
1518
|
+
var formatSimTime = (seconds) => {
|
|
1519
|
+
if (seconds === 0) return "0";
|
|
1520
|
+
const absSeconds = Math.abs(seconds);
|
|
1521
|
+
const precision = (v) => v.toPrecision(4);
|
|
1522
|
+
if (absSeconds >= 1) return precision(seconds);
|
|
1523
|
+
if (absSeconds >= 1e-3) return `${precision(seconds * 1e3)}m`;
|
|
1524
|
+
if (absSeconds >= 1e-6) return `${precision(seconds * 1e6)}u`;
|
|
1525
|
+
if (absSeconds >= 1e-9) return `${precision(seconds * 1e9)}n`;
|
|
1526
|
+
if (absSeconds >= 1e-12) return `${precision(seconds * 1e12)}p`;
|
|
1527
|
+
if (absSeconds >= 1e-15) return `${precision(seconds * 1e15)}f`;
|
|
1528
|
+
return seconds.toExponential(3);
|
|
1529
|
+
};
|
|
1530
|
+
var getSpiceFromCircuitJson = (circuitJson, options) => {
|
|
1377
1531
|
const spiceNetlist = circuitJsonToSpice(circuitJson);
|
|
1378
1532
|
const baseSpiceString = spiceNetlist.toSpiceString();
|
|
1379
1533
|
const lines = baseSpiceString.split("\n").filter((l) => l.trim() !== "");
|
|
@@ -1382,13 +1536,18 @@ var getSpiceFromCircuitJson = (circuitJson) => {
|
|
|
1382
1536
|
);
|
|
1383
1537
|
const allNodes = /* @__PURE__ */ new Set();
|
|
1384
1538
|
const capacitorNodes = /* @__PURE__ */ new Set();
|
|
1539
|
+
const componentNamesToProbeCurrent = /* @__PURE__ */ new Set();
|
|
1385
1540
|
for (const line of componentLines) {
|
|
1386
1541
|
const parts = line.trim().split(/\s+/);
|
|
1387
1542
|
if (parts.length < 3) continue;
|
|
1388
|
-
const
|
|
1543
|
+
const componentName = parts[0];
|
|
1544
|
+
const componentType = componentName[0].toUpperCase();
|
|
1389
1545
|
let nodesOnLine = [];
|
|
1390
1546
|
if (["R", "C", "L", "V", "I", "D"].includes(componentType)) {
|
|
1391
1547
|
nodesOnLine = parts.slice(1, 3);
|
|
1548
|
+
if (componentType === "V") {
|
|
1549
|
+
componentNamesToProbeCurrent.add(componentName);
|
|
1550
|
+
}
|
|
1392
1551
|
} else if (componentType === "Q" && parts.length >= 4) {
|
|
1393
1552
|
nodesOnLine = parts.slice(1, 4);
|
|
1394
1553
|
} else if (componentType === "M" && parts.length >= 5) {
|
|
@@ -1406,9 +1565,23 @@ var getSpiceFromCircuitJson = (circuitJson) => {
|
|
|
1406
1565
|
allNodes.delete("0");
|
|
1407
1566
|
capacitorNodes.delete("0");
|
|
1408
1567
|
const icLines = Array.from(capacitorNodes).map((node) => `.ic V(${node})=0`);
|
|
1409
|
-
const
|
|
1410
|
-
const
|
|
1411
|
-
|
|
1568
|
+
const probes = [];
|
|
1569
|
+
const probeVoltages = Array.from(allNodes).map((node) => `V(${node})`);
|
|
1570
|
+
probes.push(...probeVoltages);
|
|
1571
|
+
const probeCurrents = Array.from(componentNamesToProbeCurrent).map(
|
|
1572
|
+
(name) => `I(${name})`
|
|
1573
|
+
);
|
|
1574
|
+
probes.push(...probeCurrents);
|
|
1575
|
+
const probeLine = probes.length > 0 ? `.probe ${probes.join(" ")}` : "";
|
|
1576
|
+
const tstart_ms = options?.startTime ?? 0;
|
|
1577
|
+
const duration_ms = options?.duration ?? 20;
|
|
1578
|
+
const tstart = tstart_ms * 1e-3;
|
|
1579
|
+
const duration = duration_ms * 1e-3;
|
|
1580
|
+
const tstop = tstart + duration;
|
|
1581
|
+
const tstep = duration / 50;
|
|
1582
|
+
const tranLine = `.tran ${formatSimTime(tstep)} ${formatSimTime(
|
|
1583
|
+
tstop
|
|
1584
|
+
)} ${formatSimTime(tstart)} UIC`;
|
|
1412
1585
|
const endStatement = ".end";
|
|
1413
1586
|
const originalLines = baseSpiceString.split("\n");
|
|
1414
1587
|
let endIndex = -1;
|
|
@@ -1448,36 +1621,49 @@ var SchematicViewer = ({
|
|
|
1448
1621
|
if (debug3) {
|
|
1449
1622
|
enableDebug();
|
|
1450
1623
|
}
|
|
1451
|
-
const [showSpiceOverlay, setShowSpiceOverlay] =
|
|
1624
|
+
const [showSpiceOverlay, setShowSpiceOverlay] = useState5(false);
|
|
1625
|
+
const [spiceSimOptions, setSpiceSimOptions] = useState5({
|
|
1626
|
+
showVoltage: true,
|
|
1627
|
+
showCurrent: false,
|
|
1628
|
+
startTime: 0,
|
|
1629
|
+
// in ms
|
|
1630
|
+
duration: 20
|
|
1631
|
+
// in ms
|
|
1632
|
+
});
|
|
1452
1633
|
const getCircuitHash = (circuitJson2) => {
|
|
1453
1634
|
return `${circuitJson2?.length || 0}_${circuitJson2?.editCount || 0}`;
|
|
1454
1635
|
};
|
|
1455
|
-
const circuitJsonKey =
|
|
1636
|
+
const circuitJsonKey = useMemo3(
|
|
1456
1637
|
() => getCircuitHash(circuitJson),
|
|
1457
1638
|
[circuitJson]
|
|
1458
1639
|
);
|
|
1459
|
-
const spiceString =
|
|
1640
|
+
const spiceString = useMemo3(() => {
|
|
1460
1641
|
if (!spiceSimulationEnabled) return null;
|
|
1461
1642
|
try {
|
|
1462
|
-
return getSpiceFromCircuitJson(circuitJson);
|
|
1643
|
+
return getSpiceFromCircuitJson(circuitJson, spiceSimOptions);
|
|
1463
1644
|
} catch (e) {
|
|
1464
1645
|
console.error("Failed to generate SPICE string", e);
|
|
1465
1646
|
return null;
|
|
1466
1647
|
}
|
|
1467
|
-
}, [
|
|
1648
|
+
}, [
|
|
1649
|
+
circuitJsonKey,
|
|
1650
|
+
spiceSimulationEnabled,
|
|
1651
|
+
spiceSimOptions.startTime,
|
|
1652
|
+
spiceSimOptions.duration
|
|
1653
|
+
]);
|
|
1468
1654
|
const {
|
|
1469
1655
|
plotData,
|
|
1470
1656
|
nodes,
|
|
1471
1657
|
isLoading: isSpiceSimLoading,
|
|
1472
1658
|
error: spiceSimError
|
|
1473
1659
|
} = useSpiceSimulation(spiceString);
|
|
1474
|
-
const [editModeEnabled, setEditModeEnabled] =
|
|
1475
|
-
const [snapToGrid, setSnapToGrid] =
|
|
1476
|
-
const [isInteractionEnabled, setIsInteractionEnabled] =
|
|
1660
|
+
const [editModeEnabled, setEditModeEnabled] = useState5(defaultEditMode);
|
|
1661
|
+
const [snapToGrid, setSnapToGrid] = useState5(true);
|
|
1662
|
+
const [isInteractionEnabled, setIsInteractionEnabled] = useState5(
|
|
1477
1663
|
!clickToInteractEnabled
|
|
1478
1664
|
);
|
|
1479
|
-
const [showViewMenu, setShowViewMenu] =
|
|
1480
|
-
const [showSchematicGroups, setShowSchematicGroups] =
|
|
1665
|
+
const [showViewMenu, setShowViewMenu] = useState5(false);
|
|
1666
|
+
const [showSchematicGroups, setShowSchematicGroups] = useState5(false);
|
|
1481
1667
|
const svgDivRef = useRef4(null);
|
|
1482
1668
|
const touchStartRef = useRef4(null);
|
|
1483
1669
|
const handleTouchStart = (e) => {
|
|
@@ -1499,9 +1685,9 @@ var SchematicViewer = ({
|
|
|
1499
1685
|
}
|
|
1500
1686
|
touchStartRef.current = null;
|
|
1501
1687
|
};
|
|
1502
|
-
const [internalEditEvents, setInternalEditEvents] =
|
|
1688
|
+
const [internalEditEvents, setInternalEditEvents] = useState5([]);
|
|
1503
1689
|
const circuitJsonRef = useRef4(circuitJson);
|
|
1504
|
-
|
|
1690
|
+
useEffect8(() => {
|
|
1505
1691
|
const circuitHash = getCircuitHash(circuitJson);
|
|
1506
1692
|
const circuitHashRef = getCircuitHash(circuitJsonRef.current);
|
|
1507
1693
|
if (circuitHash !== circuitHashRef) {
|
|
@@ -1522,7 +1708,7 @@ var SchematicViewer = ({
|
|
|
1522
1708
|
enabled: isInteractionEnabled && !showSpiceOverlay
|
|
1523
1709
|
});
|
|
1524
1710
|
const { containerWidth, containerHeight } = useResizeHandling(containerRef);
|
|
1525
|
-
const svgString =
|
|
1711
|
+
const svgString = useMemo3(() => {
|
|
1526
1712
|
if (!containerWidth || !containerHeight) return "";
|
|
1527
1713
|
return convertCircuitJsonToSchematicSvg(circuitJson, {
|
|
1528
1714
|
width: containerWidth,
|
|
@@ -1533,14 +1719,14 @@ var SchematicViewer = ({
|
|
|
1533
1719
|
},
|
|
1534
1720
|
colorOverrides
|
|
1535
1721
|
});
|
|
1536
|
-
}, [
|
|
1537
|
-
const containerBackgroundColor =
|
|
1722
|
+
}, [circuitJsonKey, containerWidth, containerHeight]);
|
|
1723
|
+
const containerBackgroundColor = useMemo3(() => {
|
|
1538
1724
|
const match = svgString.match(
|
|
1539
1725
|
/<svg[^>]*style="[^"]*background-color:\s*([^;\"]+)/i
|
|
1540
1726
|
);
|
|
1541
1727
|
return match?.[1] ?? "transparent";
|
|
1542
1728
|
}, [svgString]);
|
|
1543
|
-
const realToSvgProjection =
|
|
1729
|
+
const realToSvgProjection = useMemo3(() => {
|
|
1544
1730
|
if (!svgString) return identity();
|
|
1545
1731
|
const transformString = svgString.match(
|
|
1546
1732
|
/data-real-to-screen-transform="([^"]+)"/
|
|
@@ -1558,7 +1744,7 @@ var SchematicViewer = ({
|
|
|
1558
1744
|
onEditEvent(event);
|
|
1559
1745
|
}
|
|
1560
1746
|
};
|
|
1561
|
-
const editEventsWithUnappliedEditEvents =
|
|
1747
|
+
const editEventsWithUnappliedEditEvents = useMemo3(() => {
|
|
1562
1748
|
return [...unappliedEditEvents, ...internalEditEvents];
|
|
1563
1749
|
}, [unappliedEditEvents, internalEditEvents]);
|
|
1564
1750
|
const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
|
|
@@ -1592,7 +1778,7 @@ var SchematicViewer = ({
|
|
|
1592
1778
|
circuitJsonKey,
|
|
1593
1779
|
showGroups: showSchematicGroups
|
|
1594
1780
|
});
|
|
1595
|
-
const svgDiv =
|
|
1781
|
+
const svgDiv = useMemo3(
|
|
1596
1782
|
() => /* @__PURE__ */ jsx9(
|
|
1597
1783
|
"div",
|
|
1598
1784
|
{
|
|
@@ -1724,7 +1910,9 @@ var SchematicViewer = ({
|
|
|
1724
1910
|
plotData,
|
|
1725
1911
|
nodes,
|
|
1726
1912
|
isLoading: isSpiceSimLoading,
|
|
1727
|
-
error: spiceSimError
|
|
1913
|
+
error: spiceSimError,
|
|
1914
|
+
simOptions: spiceSimOptions,
|
|
1915
|
+
onSimOptionsChange: setSpiceSimOptions
|
|
1728
1916
|
}
|
|
1729
1917
|
),
|
|
1730
1918
|
svgDiv
|