Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
293 lines (286 loc) · 25 KB
/
Copy pathindex.html
File metadata and controls
293 lines (286 loc) · 25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="轻量级 PCB 接口标注与连接图绘制工具" />
<title>WireSketch · PCB 连接图</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header class="topbar">
<a class="brand" href="#" aria-label="WireSketch 首页">
<span class="brand-mark" aria-hidden="true"><i></i><i></i><i></i></span>
<span>WireSketch</span>
</a>
<nav class="mode-switch" aria-label="工作区">
<button class="mode-btn active" data-view="board">板卡标注</button>
<button class="mode-btn" data-view="assembly">连接装配</button>
</nav>
<div class="top-actions">
<span class="save-status"><i></i> 已自动保存</span>
<button class="icon-btn" id="helpBtn" title="使用帮助">?</button>
</div>
</header>
<main>
<section id="boardView" class="workspace active">
<aside class="sidebar left-panel">
<div class="panel-heading">
<div><span class="eyebrow">PCB LIBRARY</span><h2>板卡库</h2></div>
<button class="square-btn" id="newBoardBtn" title="新建板卡">+</button>
</div>
<label class="search-box">
<span>⌕</span><input id="boardSearch" type="search" placeholder="搜索板卡…" />
</label>
<div id="boardList" class="board-list"></div>
<div class="sidebar-footer">
<button class="secondary-btn full" id="importBoardsBtn">导入描述文件</button>
<input id="importBoardsInput" type="file" accept="application/json,.json,.pcb.json" multiple hidden />
</div>
</aside>
<section class="main-panel board-editor">
<div class="editor-toolbar">
<div>
<span class="breadcrumb">板卡库 / <b id="boardBreadcrumb">未命名板卡</b></span>
<input id="boardName" class="title-input" value="未命名板卡" aria-label="板卡名称" />
</div>
<div class="toolbar-actions">
<button class="secondary-btn" id="replaceImageBtn">替换图片</button>
<button class="primary-btn" id="exportBoardBtn">导出 PCB 描述</button>
<input id="imageInput" type="file" accept="image/*" hidden />
</div>
</div>
<div class="editor-content">
<div class="canvas-section">
<div class="section-tip"><span class="step-pill">1</span> 在图片上拖拽框选接口</div>
<div id="virtualBoardControls" class="virtual-board-controls hidden">
<span class="virtual-badge">虚拟 PCB</span>
<label>宽 <input id="virtualBoardWidth" type="number" min="120" max="2400" step="10" value="420" /> px</label>
<label>高 <input id="virtualBoardHeight" type="number" min="80" max="1600" step="10" value="260" /> px</label>
<label>背景 <input id="virtualBoardColor" type="color" value="#1d5b42" /></label>
<span class="virtual-tip">修改上方名称可同步更新板中文字</span>
</div>
<div id="imageTransparencyControls" class="image-transparency-controls hidden">
<span class="transparency-badge">图片背景</span>
<label class="image-rotation-field">旋转 <input id="imageRotationSlider" type="range" min="-180" max="180" step="1" value="0" aria-label="图片旋转角度" /><input id="imageRotationAngle" type="number" min="-180" max="180" step="0.1" value="0" />°</label>
<button class="secondary-btn transparency-picker-btn" id="pickTransparentColorBtn" type="button">吸取透明色</button>
<span id="transparentColorStatus" class="transparent-color-status"><i></i><span>尚未设置</span></span>
<button class="danger-link transparency-clear hidden" id="clearTransparentColorBtn" type="button">清除</button>
<span class="transparency-tip">点击取色后,再点击图片中的背景颜色</span>
</div>
<div id="imageStage" class="image-stage" tabindex="0">
<div id="emptyImage" class="empty-image">
<div class="upload-graphic">⌁</div>
<h3>添加 PCB 图片</h3>
<p>支持 PNG、JPG、WEBP,建议使用俯视图</p>
<button class="primary-btn" id="uploadImageBtn">选择图片</button>
</div>
<div id="imageWorkspace" class="image-workspace hidden">
<img id="boardImage" alt="PCB 板卡" draggable="false" />
<div id="interfaceOverlay" class="interface-overlay"></div>
</div>
</div>
<div class="canvas-hint">
<span><span class="mouse-icon"></span> 按住鼠标左键框选 · 点击标注可编辑 · Delete 删除</span>
<div class="board-zoom-controls">
<button id="boardZoomOutBtn" title="缩小">−</button>
<span id="boardZoomLabel">适配</span>
<button id="boardZoomInBtn" title="放大">+</button>
<button id="boardZoomFitBtn" class="fit-btn" title="完整显示图片">适配</button>
</div>
</div>
</div>
<aside class="property-panel">
<div class="section-tip"><span class="step-pill">2</span> 编辑接口定义</div>
<div id="interfaceEmpty" class="property-empty">
<div class="empty-symbol">⌗</div>
<h3>还没有选中接口</h3>
<p>在左侧图片上拖拽一个矩形,创建接口区域。</p>
</div>
<form id="interfaceForm" class="interface-form hidden">
<label>接口名称<input id="interfaceName" required placeholder="例如:J1 / UART" /></label>
<div class="field-row">
<label>接口类型<select id="interfaceType" title="选择协议类型后会应用对应的默认线序"><option value="generic">通用</option><option value="power">电源</option><option value="uart">UART</option><option value="i2c">I²C</option><option value="spi">SPI</option><option value="usb">USB</option><option value="gpio">GPIO</option></select></label>
<label>针脚数量<input id="pinCount" type="number" min="1" max="64" value="4" /></label>
</div>
<label class="orientation-field">接口旋转 / Pin 1 方位
<select id="interfaceRotation">
<option value="0">0° · Pin 1 在左</option>
<option value="90">90° · Pin 1 在上</option>
<option value="180">180° · Pin 1 在右</option>
<option value="270">270° · Pin 1 在下</option>
</select>
<small>角度为顺时针方向;画布上的红色 P1 标记表示线序起点。</small>
</label>
<div class="pins-heading"><span>线序 / 针脚定义</span><small>从 Pin 1 开始</small></div>
<div id="pinList" class="pin-list"></div>
<button type="button" class="danger-link" id="deleteInterfaceBtn">删除此接口</button>
</form>
</aside>
</div>
</section>
</section>
<section id="assemblyView" class="workspace">
<aside class="sidebar left-panel assembly-sidebar">
<div class="panel-heading"><div><span class="eyebrow">COMPONENTS</span><h2>可用板卡</h2></div></div>
<p class="panel-note">拖拽或点击板卡添加到画布</p>
<div id="componentList" class="component-list"></div>
<div class="sidebar-footer stack">
<button class="secondary-btn full" id="assemblyImportBoardsBtn">导入 PCB 描述</button>
<button class="secondary-btn full" id="importAssemblyBtn">打开装配体</button>
<input id="assemblyImportBoardsInput" type="file" accept="application/json,.json" multiple hidden />
<input id="importAssemblyInput" type="file" accept="application/json,.json" hidden />
</div>
</aside>
<section class="main-panel assembly-editor">
<div class="editor-toolbar assembly-toolbar">
<div>
<span class="breadcrumb">装配体</span>
<input id="assemblyName" class="title-input" value="新建连接图" aria-label="装配体名称" />
</div>
<div class="toolbar-actions">
<button class="secondary-btn" id="addAssemblyTextBtn">+ 自由文本</button>
<button class="secondary-btn" id="clearAssemblyBtn">清空</button>
<button class="secondary-btn accent" id="autoLayoutBtn">✦ 自动美化布局</button>
<label class="export-scale-control" title="选择导出格式和 PNG 分辨率倍率">
<select id="exportFormat" aria-label="图片导出格式">
<option value="png">PNG</option>
<option value="svg">SVG</option>
</select>
<select id="exportScale" aria-label="PNG 导出分辨率倍率">
<option value="1">1×</option>
<option value="2">2×</option>
<option value="3">3×</option>
<option value="4" selected>4×</option>
</select>
</label>
<button class="secondary-btn" id="renderAssemblyBtn">导出 PNG</button>
<button class="primary-btn" id="exportAssemblyBtn">导出装配体</button>
</div>
</div>
<div id="assemblyViewport" class="assembly-viewport">
<div id="assemblyCanvas" class="assembly-canvas">
<div id="nodeLayer" class="node-layer"></div>
<svg id="wireLayer" class="wire-layer" aria-hidden="true"></svg>
<div id="nodeControlLayer" class="node-control-layer"></div>
<div id="selectionMarquee" class="selection-marquee hidden" aria-hidden="true"></div>
<div id="assemblyEmpty" class="assembly-empty">
<div class="flow-graphic"><span></span><i>+</i><span></span></div>
<h3>开始搭建连接图</h3>
<p>从左侧添加板卡,然后依次点击两个接口建立连接</p>
</div>
<div class="canvas-controls">
<button id="zoomOutBtn" title="缩小">−</button><span id="zoomLabel">100%</span><button id="zoomInBtn" title="放大">+</button>
</div>
<div id="connectionToast" class="connection-toast hidden"></div>
</div>
</div>
<div class="statusbar">
<span><i class="dot blue"></i><b id="nodeCount">0</b> 块板卡</span>
<span><i class="dot orange"></i><b id="wireCount">0</b> 根导线</span>
<span class="status-help">提示:空白处拖动框选 · Shift 追加框选 · 拖动已选元素整体移动 · Esc 取消接线</span>
</div>
</section>
<aside class="assembly-property-panel">
<div class="assembly-property-heading"><span class="eyebrow">PROPERTIES</span><h2 id="assemblyPropertyTitle">全局属性</h2></div>
<section id="globalPropertyGroup" class="property-group">
<h3>全局设置</h3>
<label class="range-field"><span>默认线宽<output id="defaultWireWidthValue">2.2</output></span><input id="defaultWireWidth" type="range" min="1" max="8" step="0.1" value="2.2" /></label>
<label class="range-field"><span>默认标签间距<output id="defaultWireGapValue">6</output></span><input id="defaultWireGap" type="range" min="0" max="24" step="1" value="6" /></label>
<label class="range-field"><span>默认导线间距<output id="defaultRouteGapValue">6</output></span><input id="defaultRouteGap" type="range" min="0" max="20" step="0.5" value="6" /></label>
<label class="range-field"><span>默认折线圆角<output id="defaultCornerRadiusValue">0</output></span><input id="defaultCornerRadius" type="range" min="0" max="24" step="1" value="0" /></label>
<label class="range-field"><span>画布宽度<output id="canvasWidthValue">1200</output></span><input id="canvasWidth" type="range" min="600" max="3000" step="50" value="1200" /></label>
<label class="range-field"><span>画布高度<output id="canvasHeightValue">800</output></span><input id="canvasHeight" type="range" min="400" max="2000" step="50" value="800" /></label>
<label class="check-field"><input id="defaultShowFromLabels" type="checkbox" checked /><span>默认显示端点 1 信号名</span></label>
<label class="check-field"><input id="defaultShowToLabels" type="checkbox" checked /><span>默认显示端点 2 信号名</span></label>
<h3 class="property-subheading">所有文本默认样式</h3>
<label class="range-field"><span>默认字号<output id="defaultTextFontSizeValue">16</output></span><input id="defaultTextFontSize" type="range" min="8" max="72" step="1" value="16" /></label>
<label>默认字体<select id="defaultTextFontFamily" class="property-select"><option value="sans-serif">系统无衬线</option><option value="serif">系统衬线</option><option value="monospace">系统等宽</option><option value="Arial">Arial</option><option value="Helvetica">Helvetica</option><option value="Verdana">Verdana</option><option value="Tahoma">Tahoma</option><option value="Georgia">Georgia</option><option value="TimesNewRoman">Times New Roman</option><option value="CourierNew">Courier New</option><option value="MicrosoftYaHei">微软雅黑</option><option value="PingFangSC">苹方</option><option value="NotoSansSC">思源黑体</option><option value="SimHei">黑体</option><option value="SimSun">宋体</option><option value="KaiTi">楷体</option><option value="FangSong">仿宋</option></select></label>
<label>默认字重<select id="defaultTextFontWeight" class="property-select"><option value="300">细体</option><option value="500" selected>中等</option><option value="700">粗体</option></select></label>
<label class="color-field"><span>默认颜色</span><input id="defaultTextColor" type="color" value="#25334a" /></label>
<label class="check-field"><input id="defaultTextShadowEnabled" type="checkbox" /><span>默认文字阴影</span></label>
<label class="color-field"><span>默认阴影颜色</span><input id="defaultTextShadowColor" type="color" value="#000000" /></label>
<label class="range-field"><span>默认阴影模糊<output id="defaultTextShadowBlurValue">3</output></span><input id="defaultTextShadowBlur" type="range" min="0" max="12" step="1" value="3" /></label>
<label class="range-field"><span>默认阴影 X<output id="defaultTextShadowXValue">0</output></span><input id="defaultTextShadowX" type="range" min="-10" max="10" step="1" value="0" /></label>
<label class="range-field"><span>默认阴影 Y<output id="defaultTextShadowYValue">2</output></span><input id="defaultTextShadowY" type="range" min="-10" max="10" step="1" value="2" /></label>
</section>
<section id="multiPropertyGroup" class="property-group hidden">
<h3>批量选择</h3>
<div class="wire-endpoint-summary">已选择 <b id="multiSelectionCount">0</b> 项。拖动任一已选板卡或文本即可整体移动;固定板卡保持原位。</div>
</section>
<section id="nodePropertyGroup" class="property-group hidden">
<h3>所选板卡</h3>
<div id="nodePropertySummary" class="wire-endpoint-summary"></div>
<label class="check-field"><input id="nodeFixed" type="checkbox" /><span>固定板卡位置</span></label>
<label class="check-field"><input id="nodeShowName" type="checkbox" checked /><span>显示板卡名称</span></label>
<label class="range-field"><span>名称大小<output id="nodeNameFontSizeValue">11</output></span><input id="nodeNameFontSize" type="range" min="8" max="72" step="1" value="11" /></label>
<label>名称字体<select id="nodeNameFontFamily" class="property-select"><option value="sans-serif">系统无衬线</option><option value="serif">系统衬线</option><option value="monospace">系统等宽</option><option value="Arial">Arial</option><option value="Helvetica">Helvetica</option><option value="Verdana">Verdana</option><option value="Tahoma">Tahoma</option><option value="Georgia">Georgia</option><option value="TimesNewRoman">Times New Roman</option><option value="CourierNew">Courier New</option><option value="MicrosoftYaHei">微软雅黑</option><option value="PingFangSC">苹方</option><option value="NotoSansSC">思源黑体</option><option value="SimHei">黑体</option><option value="SimSun">宋体</option><option value="KaiTi">楷体</option><option value="FangSong">仿宋</option></select></label>
<label>名称字重<select id="nodeNameFontWeight" class="property-select"><option value="300">细体</option><option value="500">中等</option><option value="700">粗体</option></select></label>
<label class="color-field"><span>名称颜色</span><input id="nodeNameColor" type="color" value="#25334a" /></label>
<label class="check-field"><input id="nodeNameShadowEnabled" type="checkbox" /><span>名称阴影</span></label>
<label class="color-field"><span>阴影颜色</span><input id="nodeNameShadowColor" type="color" value="#000000" /></label>
<label class="range-field"><span>阴影模糊<output id="nodeNameShadowBlurValue">3</output></span><input id="nodeNameShadowBlur" type="range" min="0" max="12" step="1" value="3" /></label>
<label class="range-field"><span>阴影 X<output id="nodeNameShadowXValue">0</output></span><input id="nodeNameShadowX" type="range" min="-10" max="10" step="1" value="0" /></label>
<label class="range-field"><span>阴影 Y<output id="nodeNameShadowYValue">2</output></span><input id="nodeNameShadowY" type="range" min="-10" max="10" step="1" value="2" /></label>
<button type="button" class="secondary-btn full" id="resetNodeNameStyleBtn">名称样式恢复全局默认</button>
<button type="button" class="secondary-btn full" id="resetNodeNamePositionBtn">名称恢复默认位置</button>
<div id="nodeInterfaceGaps" class="interface-gap-list"></div>
<button type="button" class="secondary-btn full" id="resetNodeGapsBtn">全部恢复全局标签间距</button>
</section>
<section id="textPropertyGroup" class="property-group hidden">
<h3>自由文本</h3>
<label>文本内容<textarea id="assemblyTextContent" maxlength="500" rows="4"></textarea></label>
<label class="range-field"><span>文本大小<output id="assemblyTextFontSizeValue">16</output></span><input id="assemblyTextFontSize" type="range" min="8" max="72" step="1" value="16" /></label>
<label>文本字体<select id="assemblyTextFontFamily" class="property-select"><option value="sans-serif">系统无衬线</option><option value="serif">系统衬线</option><option value="monospace">系统等宽</option><option value="Arial">Arial</option><option value="Helvetica">Helvetica</option><option value="Verdana">Verdana</option><option value="Tahoma">Tahoma</option><option value="Georgia">Georgia</option><option value="TimesNewRoman">Times New Roman</option><option value="CourierNew">Courier New</option><option value="MicrosoftYaHei">微软雅黑</option><option value="PingFangSC">苹方</option><option value="NotoSansSC">思源黑体</option><option value="SimHei">黑体</option><option value="SimSun">宋体</option><option value="KaiTi">楷体</option><option value="FangSong">仿宋</option></select></label>
<label>文本字重<select id="assemblyTextFontWeight" class="property-select"><option value="300">细体</option><option value="500">中等</option><option value="700">粗体</option></select></label>
<label class="color-field"><span>文本颜色</span><input id="assemblyTextColor" type="color" value="#25334a" /></label>
<label class="check-field"><input id="assemblyTextShadowEnabled" type="checkbox" /><span>文字阴影</span></label>
<label class="color-field"><span>阴影颜色</span><input id="assemblyTextShadowColor" type="color" value="#000000" /></label>
<label class="range-field"><span>阴影模糊<output id="assemblyTextShadowBlurValue">3</output></span><input id="assemblyTextShadowBlur" type="range" min="0" max="12" step="1" value="3" /></label>
<label class="range-field"><span>阴影 X<output id="assemblyTextShadowXValue">0</output></span><input id="assemblyTextShadowX" type="range" min="-10" max="10" step="1" value="0" /></label>
<label class="range-field"><span>阴影 Y<output id="assemblyTextShadowYValue">2</output></span><input id="assemblyTextShadowY" type="range" min="-10" max="10" step="1" value="2" /></label>
<button type="button" class="secondary-btn full" id="resetAssemblyTextStyleBtn">文本样式恢复全局默认</button>
<button type="button" class="danger-link" id="deleteAssemblyTextBtn">删除此文本</button>
</section>
<section id="portPropertyGroup" class="property-group hidden">
<h3>所选端口</h3>
<div id="portPropertySummary" class="wire-endpoint-summary"></div>
<label class="check-field"><input id="portSingleSignalMode" type="checkbox" /><span>开启单信号线连接模式</span></label>
<p id="portModeHint" class="port-mode-hint"></p>
</section>
<section id="wirePropertyGroup" class="property-group wire-property-group hidden">
<h3>所选信号线</h3>
<form id="wirePropertyForm" class="wire-property-form">
<div id="wireEndpointSummary" class="wire-endpoint-summary"></div>
<label>中间显示名称<input id="wireDisplayName" maxlength="80" placeholder="留空则不显示" /></label>
<label class="range-field"><span>线宽<output id="wireWidthValue">2.2</output></span><input id="wireWidth" type="range" min="1" max="8" step="0.1" value="2.2" /></label>
<label class="range-field"><span>折线圆角<output id="wireCornerRadiusValue">0</output></span><input id="wireCornerRadius" type="range" min="0" max="24" step="1" value="0" /></label>
<label class="range-field"><span>所属线束间距<output id="wireRouteGapValue">6</output></span><input id="wireRouteGap" type="range" min="0" max="20" step="0.5" value="6" /></label>
<button type="button" class="secondary-btn full" id="resetWireGapBtn">线束间距恢复全局</button>
<label class="check-field"><input id="wireShowFromLabels" type="checkbox" /><span>显示端点 1 信号名</span></label>
<label class="check-field"><input id="wireShowToLabels" type="checkbox" /><span>显示端点 2 信号名</span></label>
<button type="button" class="secondary-btn full" id="resetWireStyleBtn">恢复全局样式</button>
<button type="button" class="danger-link" id="deleteWireBtn">删除整条线束</button>
</form>
</section>
<section id="bundlePropertyGroup" class="property-group hidden">
<h3>所选线束</h3>
<div id="bundleEndpointSummary" class="wire-endpoint-summary"></div>
<label class="range-field"><span>导线间距<output id="bundleRouteGapValue">6</output></span><input id="bundleRouteGap" type="range" min="0" max="20" step="0.5" value="6" /></label>
<button type="button" class="secondary-btn full" id="resetBundleGapBtn">线束间距恢复全局</button>
<label class="check-field"><input id="bundleShowFromLabels" type="checkbox" /><span>显示端点 1 信号名</span></label>
<label class="check-field"><input id="bundleShowToLabels" type="checkbox" /><span>显示端点 2 信号名</span></label>
<button type="button" class="danger-link" id="deleteBundleBtn">删除整条线束</button>
</section>
</aside>
</section>
</main>
<dialog id="helpDialog">
<button class="dialog-close" aria-label="关闭">×</button>
<span class="eyebrow">QUICK GUIDE</span><h2>三步画好连接图</h2>
<ol><li><b>创建板卡</b><span>上传 PCB 俯视图片,在接口位置拖拽框选,填写针脚线序。</span></li><li><b>定义连接</b><span>进入“连接装配”,添加板卡并依次点击需要相连的接口。</span></li><li><b>整理与导出</b><span>拖动板卡自由摆放,或使用自动布局,然后导出 JSON 装配体文件。</span></li></ol>
<p class="dialog-note">所有编辑会自动保存在当前浏览器中。</p>
</dialog>
<script src="app.js"></script>
</body>
</html>