@skillpet/circuit 0.6.1 → 0.6.2

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.
@@ -17345,29 +17345,52 @@ function resolveElementColor(el) {
17345
17345
  const p = mergeParamsFirstWins(el.userParams, el.elmParams, el.defaults, el.dwgParams);
17346
17346
  return p.color ?? "black";
17347
17347
  }
17348
+ function getOutputAnchors(el) {
17349
+ const pts = [];
17350
+ const aa = el.absanchors;
17351
+ if (aa.end) pts.push(aa.end);
17352
+ if (aa.out && (!aa.end || !pointsClose(aa.out, aa.end, 0.01))) pts.push(aa.out);
17353
+ return pts;
17354
+ }
17355
+ function getInputAnchors(el) {
17356
+ const pts = [];
17357
+ const aa = el.absanchors;
17358
+ if (aa.start) pts.push(aa.start);
17359
+ for (const [name, pt] of Object.entries(aa)) {
17360
+ if (name.startsWith("in") && /^in\d+$/.test(name)) {
17361
+ if (!aa.start || !pointsClose(pt, aa.start, 0.01)) pts.push(pt);
17362
+ }
17363
+ }
17364
+ return pts;
17365
+ }
17366
+ function pointsClose(a, b, tol) {
17367
+ return Math.hypot(a.x - b.x, a.y - b.y) <= tol;
17368
+ }
17348
17369
  function buildConnectionGraph(elements) {
17349
17370
  const edges = [];
17350
17371
  const seen = /* @__PURE__ */ new Set();
17351
17372
  const tol = 0.5;
17352
17373
  for (let i = 0; i < elements.length; i++) {
17353
17374
  const fromEl = elements[i];
17354
- const fromEnd = fromEl.absanchors.end;
17355
- if (!fromEnd) continue;
17375
+ const fromPts = getOutputAnchors(fromEl);
17376
+ if (fromPts.length === 0) continue;
17377
+ const fromColor = resolveElementColor(fromEl);
17356
17378
  for (let j = 0; j < elements.length; j++) {
17357
17379
  if (i === j) continue;
17358
17380
  const toEl = elements[j];
17359
- const toStart = toEl.absanchors.start;
17360
- if (!toStart) continue;
17361
- const dx = fromEnd.x - toStart.x;
17362
- const dy = fromEnd.y - toStart.y;
17363
- if (Math.hypot(dx, dy) > tol) continue;
17364
- const fromColor = resolveElementColor(fromEl);
17381
+ const toPts = getInputAnchors(toEl);
17382
+ if (toPts.length === 0) continue;
17365
17383
  const toColor = resolveElementColor(toEl);
17366
17384
  if (colorsEqual(fromColor, toColor)) continue;
17367
- const key = `${i}|${j}`;
17368
- if (seen.has(key)) continue;
17369
- seen.add(key);
17370
- edges.push({ fromEl, toEl, fromColor, toColor });
17385
+ for (const fp of fromPts) {
17386
+ for (const tp of toPts) {
17387
+ if (!pointsClose(fp, tp, tol)) continue;
17388
+ const key = `${i}|${j}`;
17389
+ if (seen.has(key)) continue;
17390
+ seen.add(key);
17391
+ edges.push({ fromEl, toEl, fromColor, toColor, junctionPt: fp });
17392
+ }
17393
+ }
17371
17394
  }
17372
17395
  }
17373
17396
  return edges;
@@ -17382,8 +17405,8 @@ function assignLeadTransitionIds(elements, edges, scale) {
17382
17405
  const cleanups = [];
17383
17406
  let n = 0;
17384
17407
  for (const edge of edges) {
17385
- const lead2Seg = findLeadSegment(edge.fromEl, "lead2");
17386
- const lead1Seg = findLeadSegment(edge.toEl, "lead1");
17408
+ const lead2Seg = findLeadSegmentFor(edge.fromEl, "out", edge.junctionPt);
17409
+ const lead1Seg = findLeadSegmentFor(edge.toEl, "in", edge.junctionPt);
17387
17410
  if (!lead2Seg && !lead1Seg) continue;
17388
17411
  if (lead2Seg?.gradientStrokeId && lead1Seg?.gradientStrokeId) continue;
17389
17412
  let gx1, gy1, gx2, gy2;
@@ -17430,11 +17453,32 @@ function assignLeadTransitionIds(elements, edges, scale) {
17430
17453
  }
17431
17454
  };
17432
17455
  }
17433
- function findLeadSegment(el, role) {
17456
+ function findLeadSegmentFor(el, side, junctionPt) {
17457
+ const role = side === "in" ? "lead1" : "lead2";
17434
17458
  for (const s of el.segments) {
17435
17459
  if (s instanceof Segment && s.role === role) return s;
17436
17460
  }
17437
- return void 0;
17461
+ return findSegmentNearPoint(el, junctionPt);
17462
+ }
17463
+ function findSegmentNearPoint(el, absPt) {
17464
+ let best;
17465
+ let bestDist = Infinity;
17466
+ const tol = 0.6;
17467
+ for (const s of el.segments) {
17468
+ if (!(s instanceof Segment)) continue;
17469
+ if (s.path.length < 2) continue;
17470
+ if (s.role === "body") continue;
17471
+ const p0 = el.transform.transform(s.path[0]);
17472
+ const pN = el.transform.transform(s.path[s.path.length - 1]);
17473
+ const d0 = Math.hypot(p0.x - absPt.x, p0.y - absPt.y);
17474
+ const dN = Math.hypot(pN.x - absPt.x, pN.y - absPt.y);
17475
+ const d = Math.min(d0, dN);
17476
+ if (d < bestDist && d < tol) {
17477
+ bestDist = d;
17478
+ best = s;
17479
+ }
17480
+ }
17481
+ return best;
17438
17482
  }
17439
17483
  function segEndpointsSvg(el, seg, scale) {
17440
17484
  const p0 = el.transform.transform(seg.path[0]);
@@ -6,18 +6,21 @@
6
6
  * a smooth color fade at the junction.
7
7
  */
8
8
  import type { Element } from "./element.js";
9
+ import { Point } from "./geometry/point.js";
9
10
  interface ConnectionEdge {
10
11
  fromEl: Element;
11
12
  toEl: Element;
12
13
  fromColor: string;
13
14
  toColor: string;
15
+ /** The absolute point where the connection occurs. */
16
+ junctionPt: Point;
14
17
  }
15
18
  /**
16
- * Find directed pairs (fromEl → toEl) where `fromEl.absanchors.end` meets
17
- * `toEl.absanchors.start` (within tolerance) and resolved stroke colors differ.
19
+ * Find directed pairs (fromEl → toEl) where an output anchor of fromEl meets
20
+ * an input anchor of toEl (within tolerance) and resolved stroke colors differ.
18
21
  *
19
- * Uses all element pairs, not only consecutive indices, so chain order in the
20
- * array can differ from electrical adjacency (e.g. explicit `at` / `to`).
22
+ * Checks end/out start/in1/in2/… to support both two-terminal chains
23
+ * and multi-terminal elements (logic gates, opamps, etc.).
21
24
  */
22
25
  export declare function buildConnectionGraph(elements: readonly Element[]): ConnectionEdge[];
23
26
  /**
package/dist/index.cjs CHANGED
@@ -17732,29 +17732,52 @@ function resolveElementColor(el) {
17732
17732
  const p = mergeParamsFirstWins(el.userParams, el.elmParams, el.defaults, el.dwgParams);
17733
17733
  return p.color ?? "black";
17734
17734
  }
17735
+ function getOutputAnchors(el) {
17736
+ const pts = [];
17737
+ const aa = el.absanchors;
17738
+ if (aa.end) pts.push(aa.end);
17739
+ if (aa.out && (!aa.end || !pointsClose(aa.out, aa.end, 0.01))) pts.push(aa.out);
17740
+ return pts;
17741
+ }
17742
+ function getInputAnchors(el) {
17743
+ const pts = [];
17744
+ const aa = el.absanchors;
17745
+ if (aa.start) pts.push(aa.start);
17746
+ for (const [name, pt] of Object.entries(aa)) {
17747
+ if (name.startsWith("in") && /^in\d+$/.test(name)) {
17748
+ if (!aa.start || !pointsClose(pt, aa.start, 0.01)) pts.push(pt);
17749
+ }
17750
+ }
17751
+ return pts;
17752
+ }
17753
+ function pointsClose(a, b, tol) {
17754
+ return Math.hypot(a.x - b.x, a.y - b.y) <= tol;
17755
+ }
17735
17756
  function buildConnectionGraph(elements) {
17736
17757
  const edges = [];
17737
17758
  const seen = /* @__PURE__ */ new Set();
17738
17759
  const tol = 0.5;
17739
17760
  for (let i = 0; i < elements.length; i++) {
17740
17761
  const fromEl = elements[i];
17741
- const fromEnd = fromEl.absanchors.end;
17742
- if (!fromEnd) continue;
17762
+ const fromPts = getOutputAnchors(fromEl);
17763
+ if (fromPts.length === 0) continue;
17764
+ const fromColor = resolveElementColor(fromEl);
17743
17765
  for (let j = 0; j < elements.length; j++) {
17744
17766
  if (i === j) continue;
17745
17767
  const toEl = elements[j];
17746
- const toStart = toEl.absanchors.start;
17747
- if (!toStart) continue;
17748
- const dx = fromEnd.x - toStart.x;
17749
- const dy = fromEnd.y - toStart.y;
17750
- if (Math.hypot(dx, dy) > tol) continue;
17751
- const fromColor = resolveElementColor(fromEl);
17768
+ const toPts = getInputAnchors(toEl);
17769
+ if (toPts.length === 0) continue;
17752
17770
  const toColor = resolveElementColor(toEl);
17753
17771
  if (colorsEqual(fromColor, toColor)) continue;
17754
- const key = `${i}|${j}`;
17755
- if (seen.has(key)) continue;
17756
- seen.add(key);
17757
- edges.push({ fromEl, toEl, fromColor, toColor });
17772
+ for (const fp of fromPts) {
17773
+ for (const tp of toPts) {
17774
+ if (!pointsClose(fp, tp, tol)) continue;
17775
+ const key = `${i}|${j}`;
17776
+ if (seen.has(key)) continue;
17777
+ seen.add(key);
17778
+ edges.push({ fromEl, toEl, fromColor, toColor, junctionPt: fp });
17779
+ }
17780
+ }
17758
17781
  }
17759
17782
  }
17760
17783
  return edges;
@@ -17769,8 +17792,8 @@ function assignLeadTransitionIds(elements, edges, scale) {
17769
17792
  const cleanups = [];
17770
17793
  let n = 0;
17771
17794
  for (const edge of edges) {
17772
- const lead2Seg = findLeadSegment(edge.fromEl, "lead2");
17773
- const lead1Seg = findLeadSegment(edge.toEl, "lead1");
17795
+ const lead2Seg = findLeadSegmentFor(edge.fromEl, "out", edge.junctionPt);
17796
+ const lead1Seg = findLeadSegmentFor(edge.toEl, "in", edge.junctionPt);
17774
17797
  if (!lead2Seg && !lead1Seg) continue;
17775
17798
  if (lead2Seg?.gradientStrokeId && lead1Seg?.gradientStrokeId) continue;
17776
17799
  let gx1, gy1, gx2, gy2;
@@ -17817,11 +17840,32 @@ function assignLeadTransitionIds(elements, edges, scale) {
17817
17840
  }
17818
17841
  };
17819
17842
  }
17820
- function findLeadSegment(el, role) {
17843
+ function findLeadSegmentFor(el, side, junctionPt) {
17844
+ const role = side === "in" ? "lead1" : "lead2";
17821
17845
  for (const s of el.segments) {
17822
17846
  if (s instanceof Segment && s.role === role) return s;
17823
17847
  }
17824
- return void 0;
17848
+ return findSegmentNearPoint(el, junctionPt);
17849
+ }
17850
+ function findSegmentNearPoint(el, absPt) {
17851
+ let best;
17852
+ let bestDist = Infinity;
17853
+ const tol = 0.6;
17854
+ for (const s of el.segments) {
17855
+ if (!(s instanceof Segment)) continue;
17856
+ if (s.path.length < 2) continue;
17857
+ if (s.role === "body") continue;
17858
+ const p0 = el.transform.transform(s.path[0]);
17859
+ const pN = el.transform.transform(s.path[s.path.length - 1]);
17860
+ const d0 = Math.hypot(p0.x - absPt.x, p0.y - absPt.y);
17861
+ const dN = Math.hypot(pN.x - absPt.x, pN.y - absPt.y);
17862
+ const d = Math.min(d0, dN);
17863
+ if (d < bestDist && d < tol) {
17864
+ bestDist = d;
17865
+ best = s;
17866
+ }
17867
+ }
17868
+ return best;
17825
17869
  }
17826
17870
  function segEndpointsSvg(el, seg, scale) {
17827
17871
  const p0 = el.transform.transform(seg.path[0]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillpet/circuit",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Circuit diagram library — render electrical schematics from JSON, with interactive SVG, themes, and Vue/React components",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",