@skillpet/circuit 0.6.2 → 0.6.4
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.de.md +150 -0
- package/README.es.md +150 -0
- package/README.fr.md +150 -0
- package/README.ja.md +150 -0
- package/README.ko.md +150 -0
- package/README.md +26 -1
- package/README.zh-CN.md +150 -0
- package/dist/circuit.bundle.js +87 -68
- package/dist/circuit.bundle.min.js +20 -20
- package/dist/circuit.esm.js +87 -68
- package/dist/drawing-transition.d.ts +9 -9
- package/dist/index.cjs +87 -68
- package/package.json +1 -1
package/README.ko.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @skillpet/circuit
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [Español](./README.es.md) | [Français](./README.fr.md) | [Deutsch](./README.de.md)
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>회로도 라이브러리 — JSON에서 전기 회로도를 렌더링합니다. 인터랙티브 SVG, 테마, Vue / React 컴포넌트를 지원합니다.</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/v/@skillpet/circuit.svg" alt="npm version"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/l/@skillpet/circuit.svg" alt="license"></a>
|
|
12
|
+
<a href="https://circuit.skill.pet"><img src="https://img.shields.io/badge/docs-circuit.skill.pet-blue" alt="docs"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
**웹사이트 & 데모:** [circuit.skill.pet](https://circuit.skill.pet)
|
|
18
|
+
|
|
19
|
+
## 특징
|
|
20
|
+
|
|
21
|
+
- 간단한 JSON 설명으로 회로도 렌더링
|
|
22
|
+
- 200개 이상의 내장 전기 부품 (저항, 커패시터, 다이오드, 트랜지스터, IC, 논리 게이트 등)
|
|
23
|
+
- 인터랙티브 SVG: 호버 하이라이트, 툴팁, 클릭 이벤트
|
|
24
|
+
- 3가지 내장 테마 (라이트, 다크, 인쇄) + 커스텀 테마
|
|
25
|
+
- 부품 간 부드러운 색상 전환
|
|
26
|
+
- Vue 3 & React 컴포넌트 기본 제공
|
|
27
|
+
- 브라우저 번들 (script 태그) & ESM / CJS 지원
|
|
28
|
+
- KaTeX 수학 레이블 렌더링
|
|
29
|
+
- 순서도, DSP 블록, 브레드보드 부품
|
|
30
|
+
- 런타임 의존성 없음 (KaTeX는 선택사항)
|
|
31
|
+
|
|
32
|
+
## 설치
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @skillpet/circuit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 빠른 시작
|
|
39
|
+
|
|
40
|
+
### ESM / TypeScript
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { renderFromJson } from "@skillpet/circuit";
|
|
44
|
+
|
|
45
|
+
const svg = renderFromJson({
|
|
46
|
+
elements: [
|
|
47
|
+
{ type: "SourceV", d: "up", label: "12V" },
|
|
48
|
+
{ type: "ResistorIEEE", label: "R1 10kΩ" },
|
|
49
|
+
{ type: "Capacitor", d: "down", label: "C1 100nF" },
|
|
50
|
+
{ type: "Line", d: "left" },
|
|
51
|
+
{ type: "Ground" },
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 브라우저 (Script 태그)
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<script src="https://unpkg.com/@skillpet/circuit/dist/circuit.bundle.min.js"></script>
|
|
60
|
+
<script>
|
|
61
|
+
const svg = Circuit.renderFromJson({
|
|
62
|
+
elements: [
|
|
63
|
+
{ type: "ResistorIEEE", label: "R1" },
|
|
64
|
+
{ type: "Capacitor", d: "down", label: "C1" },
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
document.getElementById("output").innerHTML = svg;
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 인터랙티브 모드
|
|
72
|
+
|
|
73
|
+
DOM에 마운트하여 호버 하이라이트, 툴팁, 클릭 이벤트를 활성화:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { mountFromJson } from "@skillpet/circuit";
|
|
77
|
+
|
|
78
|
+
const ctrl = mountFromJson(document.getElementById("container"), {
|
|
79
|
+
elements: [
|
|
80
|
+
{ type: "ResistorIEEE", id: "R1", tooltip: "100kΩ 탄소 피막" },
|
|
81
|
+
{ type: "Capacitor", d: "down", id: "C1", tooltip: "0.1μF 세라믹" },
|
|
82
|
+
],
|
|
83
|
+
}, { interactive: true });
|
|
84
|
+
|
|
85
|
+
ctrl.on("element:click", (info) => console.log("클릭:", info.id));
|
|
86
|
+
ctrl.on("element:hover", (info) => console.log("호버:", info.tooltip));
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Vue 3
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<script setup>
|
|
93
|
+
import { CircuitDiagram } from "@skillpet/circuit/vue";
|
|
94
|
+
|
|
95
|
+
const circuit = {
|
|
96
|
+
elements: [
|
|
97
|
+
{ type: "ResistorIEEE", label: "R1", id: "R1", tooltip: "100kΩ" },
|
|
98
|
+
{ type: "Capacitor", d: "down", label: "C1" },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<template>
|
|
104
|
+
<CircuitDiagram :circuit="circuit" interactive @element-click="console.log" />
|
|
105
|
+
</template>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### React
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { CircuitDiagram } from "@skillpet/circuit/react";
|
|
112
|
+
|
|
113
|
+
function App() {
|
|
114
|
+
return (
|
|
115
|
+
<CircuitDiagram
|
|
116
|
+
circuit={{ elements: [{ type: "ResistorIEEE", label: "R1" }] }}
|
|
117
|
+
interactive
|
|
118
|
+
onElementClick={(info) => console.log(info)}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 테마
|
|
125
|
+
|
|
126
|
+
3가지 내장 테마: `light` (기본값), `dark`, `print`.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const svg = renderFromJson(circuit, { theme: "dark" });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 색상 전환
|
|
133
|
+
|
|
134
|
+
서로 다른 색상의 부품 간 부드러운 그라데이션 전환:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const svg = renderFromJson({
|
|
138
|
+
drawing: { colorTransition: true },
|
|
139
|
+
elements: [
|
|
140
|
+
{ type: "SourceV", d: "up", color: "#2ecc71" },
|
|
141
|
+
{ type: "ResistorIEEE", color: "#e74c3c" },
|
|
142
|
+
],
|
|
143
|
+
}, { colorTransition: true });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 라이선스
|
|
147
|
+
|
|
148
|
+
개인 및 교육 목적은 무료입니다. 상업적 사용에는 별도의 라이선스가 필요합니다.
|
|
149
|
+
자세한 내용은 이 패키지에 포함된 LICENSE 파일을 참조하세요.
|
|
150
|
+
상용 라이선스 문의: **license@skill.pet** 또는 [circuit.skill.pet/license](https://circuit.skill.pet/license).
|
package/README.md
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
# @skillpet/circuit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [Español](./README.es.md) | [Français](./README.fr.md) | [Deutsch](./README.de.md)
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Circuit diagram library — render electrical schematics from JSON, with interactive SVG, themes, and Vue / React components.</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/v/@skillpet/circuit.svg" alt="npm version"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/l/@skillpet/circuit.svg" alt="license"></a>
|
|
12
|
+
<a href="https://circuit.skill.pet"><img src="https://img.shields.io/badge/docs-circuit.skill.pet-blue" alt="docs"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
4
16
|
|
|
5
17
|
**Website & Demos:** [circuit.skill.pet](https://circuit.skill.pet)
|
|
6
18
|
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- Render circuit diagrams from a simple JSON description
|
|
22
|
+
- 200+ built-in electrical components (resistors, capacitors, diodes, transistors, ICs, logic gates, etc.)
|
|
23
|
+
- Interactive SVG: hover highlights, tooltips, click events
|
|
24
|
+
- 3 built-in themes (light, dark, print) + custom themes
|
|
25
|
+
- Smooth color transitions between elements
|
|
26
|
+
- Vue 3 & React components out of the box
|
|
27
|
+
- Browser bundle (script tag) & ESM / CJS support
|
|
28
|
+
- KaTeX math label rendering
|
|
29
|
+
- Flow charts, DSP blocks, pictorial breadboard components
|
|
30
|
+
- Zero runtime dependencies (except optional KaTeX)
|
|
31
|
+
|
|
7
32
|
## Installation
|
|
8
33
|
|
|
9
34
|
```bash
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @skillpet/circuit
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [Español](./README.es.md) | [Français](./README.fr.md) | [Deutsch](./README.de.md)
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>电路图绘制库 — 从 JSON 描述渲染电气原理图,支持交互式 SVG、主题切换与 Vue / React 组件。</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/v/@skillpet/circuit.svg" alt="npm version"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@skillpet/circuit"><img src="https://img.shields.io/npm/l/@skillpet/circuit.svg" alt="license"></a>
|
|
12
|
+
<a href="https://circuit.skill.pet"><img src="https://img.shields.io/badge/docs-circuit.skill.pet-blue" alt="docs"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
**官网与在线演示:** [circuit.skill.pet](https://circuit.skill.pet)
|
|
18
|
+
|
|
19
|
+
## 特性
|
|
20
|
+
|
|
21
|
+
- 通过简洁的 JSON 描述渲染电路图
|
|
22
|
+
- 200+ 内置电气元件(电阻、电容、二极管、晶体管、集成电路、逻辑门等)
|
|
23
|
+
- 交互式 SVG:悬停高亮、工具提示、点击事件
|
|
24
|
+
- 3 种内置主题(浅色、深色、打印)+ 自定义主题
|
|
25
|
+
- 元件间平滑的颜色过渡
|
|
26
|
+
- 开箱即用的 Vue 3 与 React 组件
|
|
27
|
+
- 浏览器 Bundle(script 标签)与 ESM / CJS 支持
|
|
28
|
+
- KaTeX 数学公式标签渲染
|
|
29
|
+
- 流程图、DSP 模块、实物面包板元件
|
|
30
|
+
- 零运行时依赖(KaTeX 为可选)
|
|
31
|
+
|
|
32
|
+
## 安装
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @skillpet/circuit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 快速上手
|
|
39
|
+
|
|
40
|
+
### ESM / TypeScript
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { renderFromJson } from "@skillpet/circuit";
|
|
44
|
+
|
|
45
|
+
const svg = renderFromJson({
|
|
46
|
+
elements: [
|
|
47
|
+
{ type: "SourceV", d: "up", label: "12V" },
|
|
48
|
+
{ type: "ResistorIEEE", label: "R1 10kΩ" },
|
|
49
|
+
{ type: "Capacitor", d: "down", label: "C1 100nF" },
|
|
50
|
+
{ type: "Line", d: "left" },
|
|
51
|
+
{ type: "Ground" },
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 浏览器(Script 标签)
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<script src="https://unpkg.com/@skillpet/circuit/dist/circuit.bundle.min.js"></script>
|
|
60
|
+
<script>
|
|
61
|
+
const svg = Circuit.renderFromJson({
|
|
62
|
+
elements: [
|
|
63
|
+
{ type: "ResistorIEEE", label: "R1" },
|
|
64
|
+
{ type: "Capacitor", d: "down", label: "C1" },
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
document.getElementById("output").innerHTML = svg;
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 交互模式
|
|
72
|
+
|
|
73
|
+
挂载到 DOM,支持悬停高亮、工具提示和点击事件:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { mountFromJson } from "@skillpet/circuit";
|
|
77
|
+
|
|
78
|
+
const ctrl = mountFromJson(document.getElementById("container"), {
|
|
79
|
+
elements: [
|
|
80
|
+
{ type: "ResistorIEEE", id: "R1", tooltip: "100kΩ 碳膜电阻" },
|
|
81
|
+
{ type: "Capacitor", d: "down", id: "C1", tooltip: "0.1μF 瓷片电容" },
|
|
82
|
+
],
|
|
83
|
+
}, { interactive: true });
|
|
84
|
+
|
|
85
|
+
ctrl.on("element:click", (info) => console.log("点击:", info.id));
|
|
86
|
+
ctrl.on("element:hover", (info) => console.log("悬停:", info.tooltip));
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Vue 3
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<script setup>
|
|
93
|
+
import { CircuitDiagram } from "@skillpet/circuit/vue";
|
|
94
|
+
|
|
95
|
+
const circuit = {
|
|
96
|
+
elements: [
|
|
97
|
+
{ type: "ResistorIEEE", label: "R1", id: "R1", tooltip: "100kΩ" },
|
|
98
|
+
{ type: "Capacitor", d: "down", label: "C1" },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<template>
|
|
104
|
+
<CircuitDiagram :circuit="circuit" interactive @element-click="console.log" />
|
|
105
|
+
</template>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### React
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { CircuitDiagram } from "@skillpet/circuit/react";
|
|
112
|
+
|
|
113
|
+
function App() {
|
|
114
|
+
return (
|
|
115
|
+
<CircuitDiagram
|
|
116
|
+
circuit={{ elements: [{ type: "ResistorIEEE", label: "R1" }] }}
|
|
117
|
+
interactive
|
|
118
|
+
onElementClick={(info) => console.log(info)}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 主题
|
|
125
|
+
|
|
126
|
+
三种内置主题:`light`(默认)、`dark` 和 `print`。
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const svg = renderFromJson(circuit, { theme: "dark" });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 颜色过渡
|
|
133
|
+
|
|
134
|
+
不同颜色元件之间平滑的渐变过渡:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const svg = renderFromJson({
|
|
138
|
+
drawing: { colorTransition: true },
|
|
139
|
+
elements: [
|
|
140
|
+
{ type: "SourceV", d: "up", color: "#2ecc71" },
|
|
141
|
+
{ type: "ResistorIEEE", color: "#e74c3c" },
|
|
142
|
+
],
|
|
143
|
+
}, { colorTransition: true });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 许可证
|
|
147
|
+
|
|
148
|
+
个人和教育用途免费。商业使用需要单独授权。
|
|
149
|
+
详见本包中的 LICENSE 文件。
|
|
150
|
+
商业授权请联系 **license@skill.pet** 或访问 [circuit.skill.pet/license](https://circuit.skill.pet/license)。
|
package/dist/circuit.bundle.js
CHANGED
|
@@ -15539,8 +15539,8 @@ var Circuit = (() => {
|
|
|
15539
15539
|
let [x0, y0] = this.xform(x, y);
|
|
15540
15540
|
const fontsize = opts.fontsize ?? 14;
|
|
15541
15541
|
let font = opts.fontfamily ?? "sans-serif";
|
|
15542
|
-
if (font.toLowerCase() === "sans
|
|
15543
|
-
font = "sans";
|
|
15542
|
+
if (font.toLowerCase() === "sans" || font.toLowerCase() === "arial") {
|
|
15543
|
+
font = "sans-serif";
|
|
15544
15544
|
}
|
|
15545
15545
|
const valign = opts.valign ?? "center";
|
|
15546
15546
|
if (valign === "base") {
|
|
@@ -15552,14 +15552,13 @@ var Circuit = (() => {
|
|
|
15552
15552
|
const rot = opts.rotation ?? 0;
|
|
15553
15553
|
const transform = rot !== 0 ? ` transform="rotate(${fmt(rot)} ${fmt(x0)} ${fmt(y0)})"` : "";
|
|
15554
15554
|
const color = opts.color ?? "black";
|
|
15555
|
-
const textY = y0 - fontsize;
|
|
15556
15555
|
let textContent;
|
|
15557
15556
|
if (opts.textDecoration) {
|
|
15558
15557
|
textContent = `<tspan text-decoration="${opts.textDecoration}">${escapeXml(s)}</tspan>`;
|
|
15559
15558
|
} else {
|
|
15560
15559
|
textContent = escapeXml(s);
|
|
15561
15560
|
}
|
|
15562
|
-
let inner2 = `<text x="${fmt(x0)}" y="${fmt(
|
|
15561
|
+
let inner2 = `<text x="${fmt(x0)}" y="${fmt(y0)}" dominant-baseline="${baseline}" fill="${escapeXml(color)}" font-size="${fmt(fontsize)}" font-family="${escapeXml(font)}" text-anchor="${anchor}"${transform}>${textContent}</text>`;
|
|
15563
15562
|
if (opts.href) {
|
|
15564
15563
|
inner2 = `<a href="${escapeXml(opts.href)}">${inner2}</a>`;
|
|
15565
15564
|
}
|
|
@@ -17738,51 +17737,55 @@ var Circuit = (() => {
|
|
|
17738
17737
|
const p = mergeParamsFirstWins(el.userParams, el.elmParams, el.defaults, el.dwgParams);
|
|
17739
17738
|
return p.color ?? "black";
|
|
17740
17739
|
}
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17740
|
+
var EXCLUDED_ANCHORS = /* @__PURE__ */ new Set([
|
|
17741
|
+
"xy",
|
|
17742
|
+
"center",
|
|
17743
|
+
"istart",
|
|
17744
|
+
"iend",
|
|
17745
|
+
"mid",
|
|
17746
|
+
"label",
|
|
17747
|
+
"vd",
|
|
17748
|
+
"vs",
|
|
17749
|
+
"n1",
|
|
17750
|
+
"n2",
|
|
17751
|
+
"n1a",
|
|
17752
|
+
"n2a"
|
|
17753
|
+
]);
|
|
17754
|
+
function isConnectionAnchor(name) {
|
|
17755
|
+
return !EXCLUDED_ANCHORS.has(name);
|
|
17747
17756
|
}
|
|
17748
|
-
function
|
|
17757
|
+
function getConnectionAnchors(el) {
|
|
17749
17758
|
const pts = [];
|
|
17750
|
-
const
|
|
17751
|
-
|
|
17752
|
-
for (const [name, pt] of Object.entries(aa)) {
|
|
17753
|
-
if (name.startsWith("in") && /^in\d+$/.test(name)) {
|
|
17754
|
-
if (!aa.start || !pointsClose(pt, aa.start, 0.01)) pts.push(pt);
|
|
17755
|
-
}
|
|
17759
|
+
for (const [name, pt] of Object.entries(el.absanchors)) {
|
|
17760
|
+
if (isConnectionAnchor(name)) pts.push(pt);
|
|
17756
17761
|
}
|
|
17757
17762
|
return pts;
|
|
17758
17763
|
}
|
|
17759
|
-
function pointsClose(a, b, tol) {
|
|
17760
|
-
return Math.hypot(a.x - b.x, a.y - b.y) <= tol;
|
|
17761
|
-
}
|
|
17762
17764
|
function buildConnectionGraph(elements) {
|
|
17763
17765
|
const edges = [];
|
|
17764
17766
|
const seen = /* @__PURE__ */ new Set();
|
|
17765
17767
|
const tol = 0.5;
|
|
17766
17768
|
for (let i = 0; i < elements.length; i++) {
|
|
17767
|
-
const
|
|
17768
|
-
const
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
for (let j =
|
|
17772
|
-
|
|
17773
|
-
const
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
if (!pointsClose(fp, tp, tol)) continue;
|
|
17769
|
+
const elA = elements[i];
|
|
17770
|
+
const colorA = resolveElementColor(elA);
|
|
17771
|
+
const anchorsA = getConnectionAnchors(elA);
|
|
17772
|
+
if (anchorsA.length === 0) continue;
|
|
17773
|
+
for (let j = i + 1; j < elements.length; j++) {
|
|
17774
|
+
const elB = elements[j];
|
|
17775
|
+
const colorB = resolveElementColor(elB);
|
|
17776
|
+
if (colorsEqual(colorA, colorB)) continue;
|
|
17777
|
+
const anchorsB = getConnectionAnchors(elB);
|
|
17778
|
+
if (anchorsB.length === 0) continue;
|
|
17779
|
+
for (const pa of anchorsA) {
|
|
17780
|
+
for (const pb of anchorsB) {
|
|
17781
|
+
if (Math.hypot(pa.x - pb.x, pa.y - pb.y) > tol) continue;
|
|
17781
17782
|
const key = `${i}|${j}`;
|
|
17782
17783
|
if (seen.has(key)) continue;
|
|
17783
17784
|
seen.add(key);
|
|
17784
|
-
edges.push({
|
|
17785
|
+
edges.push({ elA, elB, colorA, colorB, junctionPt: pa });
|
|
17786
|
+
break;
|
|
17785
17787
|
}
|
|
17788
|
+
if (seen.has(`${i}|${j}`)) break;
|
|
17786
17789
|
}
|
|
17787
17790
|
}
|
|
17788
17791
|
}
|
|
@@ -17798,26 +17801,28 @@ var Circuit = (() => {
|
|
|
17798
17801
|
const cleanups = [];
|
|
17799
17802
|
let n = 0;
|
|
17800
17803
|
for (const edge of edges) {
|
|
17801
|
-
const
|
|
17802
|
-
const
|
|
17803
|
-
if (!
|
|
17804
|
-
if (
|
|
17804
|
+
const segA = findSegAtJunction(edge.elA, edge.junctionPt);
|
|
17805
|
+
const segB = findSegAtJunction(edge.elB, edge.junctionPt);
|
|
17806
|
+
if (!segA && !segB) continue;
|
|
17807
|
+
if (segA?.gradientStrokeId && segB?.gradientStrokeId) continue;
|
|
17805
17808
|
let gx1, gy1, gx2, gy2;
|
|
17806
|
-
if (
|
|
17807
|
-
const
|
|
17808
|
-
const
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17809
|
+
if (segA && segB) {
|
|
17810
|
+
const a = segEndpointsSvg(edge.elA, segA, scale);
|
|
17811
|
+
const b = segEndpointsSvg(edge.elB, segB, scale);
|
|
17812
|
+
const aNear = nearFarSvg(edge.elA, segA, edge.junctionPt, scale);
|
|
17813
|
+
const bNear = nearFarSvg(edge.elB, segB, edge.junctionPt, scale);
|
|
17814
|
+
gx1 = aNear.farX;
|
|
17815
|
+
gy1 = aNear.farY;
|
|
17816
|
+
gx2 = bNear.farX;
|
|
17817
|
+
gy2 = bNear.farY;
|
|
17818
|
+
} else if (segA) {
|
|
17819
|
+
const c = segEndpointsSvg(edge.elA, segA, scale);
|
|
17815
17820
|
gx1 = c.x1;
|
|
17816
17821
|
gy1 = c.y1;
|
|
17817
17822
|
gx2 = c.x2;
|
|
17818
17823
|
gy2 = c.y2;
|
|
17819
17824
|
} else {
|
|
17820
|
-
const c = segEndpointsSvg(edge.
|
|
17825
|
+
const c = segEndpointsSvg(edge.elB, segB, scale);
|
|
17821
17826
|
gx1 = c.x1;
|
|
17822
17827
|
gy1 = c.y1;
|
|
17823
17828
|
gx2 = c.x2;
|
|
@@ -17825,17 +17830,17 @@ var Circuit = (() => {
|
|
|
17825
17830
|
}
|
|
17826
17831
|
if (gradientVectorLength({ x1: gx1, y1: gy1, x2: gx2, y2: gy2 }) < 1e-6) continue;
|
|
17827
17832
|
const id = `sd-trans-${n++}`;
|
|
17828
|
-
parts.push(gradientXml(id, gx1, gy1, gx2, gy2, edge.
|
|
17829
|
-
if (
|
|
17830
|
-
|
|
17833
|
+
parts.push(gradientXml(id, gx1, gy1, gx2, gy2, edge.colorA, edge.colorB));
|
|
17834
|
+
if (segA && !segA.gradientStrokeId) {
|
|
17835
|
+
segA.gradientStrokeId = id;
|
|
17831
17836
|
cleanups.push(() => {
|
|
17832
|
-
|
|
17837
|
+
segA.gradientStrokeId = void 0;
|
|
17833
17838
|
});
|
|
17834
17839
|
}
|
|
17835
|
-
if (
|
|
17836
|
-
|
|
17840
|
+
if (segB && !segB.gradientStrokeId) {
|
|
17841
|
+
segB.gradientStrokeId = id;
|
|
17837
17842
|
cleanups.push(() => {
|
|
17838
|
-
|
|
17843
|
+
segB.gradientStrokeId = void 0;
|
|
17839
17844
|
});
|
|
17840
17845
|
}
|
|
17841
17846
|
}
|
|
@@ -17846,26 +17851,21 @@ var Circuit = (() => {
|
|
|
17846
17851
|
}
|
|
17847
17852
|
};
|
|
17848
17853
|
}
|
|
17849
|
-
function
|
|
17850
|
-
const
|
|
17854
|
+
function findSegAtJunction(el, junctionPt) {
|
|
17855
|
+
const tol = 0.6;
|
|
17851
17856
|
for (const s of el.segments) {
|
|
17852
|
-
if (s instanceof Segment
|
|
17857
|
+
if (!(s instanceof Segment)) continue;
|
|
17858
|
+
if (s.role !== "lead1" && s.role !== "lead2") continue;
|
|
17859
|
+
if (segTouchesPoint(el, s, junctionPt, tol)) return s;
|
|
17853
17860
|
}
|
|
17854
|
-
return findSegmentNearPoint(el, junctionPt);
|
|
17855
|
-
}
|
|
17856
|
-
function findSegmentNearPoint(el, absPt) {
|
|
17857
17861
|
let best;
|
|
17858
17862
|
let bestDist = Infinity;
|
|
17859
|
-
const tol = 0.6;
|
|
17860
17863
|
for (const s of el.segments) {
|
|
17861
17864
|
if (!(s instanceof Segment)) continue;
|
|
17862
17865
|
if (s.path.length < 2) continue;
|
|
17863
17866
|
if (s.role === "body") continue;
|
|
17864
|
-
|
|
17865
|
-
const
|
|
17866
|
-
const d0 = Math.hypot(p0.x - absPt.x, p0.y - absPt.y);
|
|
17867
|
-
const dN = Math.hypot(pN.x - absPt.x, pN.y - absPt.y);
|
|
17868
|
-
const d = Math.min(d0, dN);
|
|
17867
|
+
if (s.path.length > 6) continue;
|
|
17868
|
+
const d = segDistToPoint(el, s, junctionPt);
|
|
17869
17869
|
if (d < bestDist && d < tol) {
|
|
17870
17870
|
bestDist = d;
|
|
17871
17871
|
best = s;
|
|
@@ -17873,6 +17873,25 @@ var Circuit = (() => {
|
|
|
17873
17873
|
}
|
|
17874
17874
|
return best;
|
|
17875
17875
|
}
|
|
17876
|
+
function segTouchesPoint(el, seg, absPt, tol) {
|
|
17877
|
+
return segDistToPoint(el, seg, absPt) < tol;
|
|
17878
|
+
}
|
|
17879
|
+
function segDistToPoint(el, seg, absPt) {
|
|
17880
|
+
const p0 = el.transform.transform(seg.path[0]);
|
|
17881
|
+
const pN = el.transform.transform(seg.path[seg.path.length - 1]);
|
|
17882
|
+
return Math.min(
|
|
17883
|
+
Math.hypot(p0.x - absPt.x, p0.y - absPt.y),
|
|
17884
|
+
Math.hypot(pN.x - absPt.x, pN.y - absPt.y)
|
|
17885
|
+
);
|
|
17886
|
+
}
|
|
17887
|
+
function nearFarSvg(el, seg, junctionPt, scale) {
|
|
17888
|
+
const p0 = el.transform.transform(seg.path[0]);
|
|
17889
|
+
const pN = el.transform.transform(seg.path[seg.path.length - 1]);
|
|
17890
|
+
const d0 = Math.hypot(p0.x - junctionPt.x, p0.y - junctionPt.y);
|
|
17891
|
+
const dN = Math.hypot(pN.x - junctionPt.x, pN.y - junctionPt.y);
|
|
17892
|
+
const far = d0 > dN ? p0 : pN;
|
|
17893
|
+
return { farX: far.x * scale, farY: -far.y * scale };
|
|
17894
|
+
}
|
|
17876
17895
|
function segEndpointsSvg(el, seg, scale) {
|
|
17877
17896
|
const p0 = el.transform.transform(seg.path[0]);
|
|
17878
17897
|
const p1 = el.transform.transform(seg.path[seg.path.length - 1]);
|