topo-engine 0.1.7 → 0.1.8

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.
@@ -25026,8 +25026,8 @@ function injectCustomers(model, customerMap) {
25026
25026
  node._customers = customers;
25027
25027
  if (customers.length === 1) {
25028
25028
  node._meterBoxMode = "single";
25029
- node._meterBoxW = 30;
25030
- node._meterBoxH = 38;
25029
+ node._meterBoxW = 22;
25030
+ node._meterBoxH = 30;
25031
25031
  } else {
25032
25032
  const showName = customers.length <= SHOW_NAME_LIMIT;
25033
25033
  const cols = Math.min(customers.length, MAX_COLS);
@@ -25100,17 +25100,26 @@ class TopoApi {
25100
25100
  this._nodeLabels = /* @__PURE__ */ new Map();
25101
25101
  this._originalNodeStyles = /* @__PURE__ */ new Map();
25102
25102
  this._originalEdgeStyles = /* @__PURE__ */ new Map();
25103
+ this._nodeColorOverrides = /* @__PURE__ */ new Map();
25104
+ this._custColorOverrides = /* @__PURE__ */ new Map();
25103
25105
  this._bindConnGraphEvents();
25104
25106
  }
25105
25107
  /** 数据刷新(图重新渲染后调用) */
25106
25108
  update(graph, model, layout, nodeByIdMap) {
25109
+ const colorSnapshot = {
25110
+ node: new Map(this._nodeColorOverrides),
25111
+ cust: new Map(this._custColorOverrides)
25112
+ };
25107
25113
  this.destroy();
25108
25114
  this._graph = graph;
25109
25115
  this._model = model;
25110
25116
  this._layout = layout;
25111
25117
  this._nodeByIdMap = nodeByIdMap;
25112
25118
  this._selectedId = null;
25119
+ this._nodeColorOverrides = colorSnapshot.node;
25120
+ this._custColorOverrides = colorSnapshot.cust;
25113
25121
  this._bindConnGraphEvents();
25122
+ this._applyColorOverrides();
25114
25123
  }
25115
25124
  /** 销毁,释放所有资源 */
25116
25125
  destroy() {
@@ -25123,6 +25132,8 @@ class TopoApi {
25123
25132
  this._originalNodeStyles.clear();
25124
25133
  this._originalEdgeStyles.clear();
25125
25134
  this._nodeLabels.clear();
25135
+ this._nodeColorOverrides.clear();
25136
+ this._custColorOverrides.clear();
25126
25137
  this._graph = null;
25127
25138
  this._model = null;
25128
25139
  this._layout = null;
@@ -25506,6 +25517,230 @@ class TopoApi {
25506
25517
  this._originalNodeStyles.clear();
25507
25518
  }
25508
25519
  // ============================================================
25520
+ // 三·五、节点 / 箱内电表户染色(支持 psrId / 资产编号 / 节点 id)
25521
+ //
25522
+ // 普通节点(变压器/开关/熔丝/导线点/用户接入点…)→ 图元“整图单色换装”,
25523
+ // 主体/引线/描边换成指定色,白字与浅色细节保留可读;
25524
+ // 箱内电表户(计量箱 grid/single 里的每只电表)→ 该户电表图标与户名染色。
25525
+ // 引用规则与 addConnection 完全一致:
25526
+ // 节点:节点内部 id 或 psrId(设备编码);电表户:客户档案 assetNo(资产编号,
25527
+ // 兼容 consNo / consId)。染色记录随数据重渲染(主题切换/换数据)自动保留重放。
25528
+ // ============================================================
25529
+ /**
25530
+ * 把当前记录的染色覆盖(节点 / 电表户)重新写进图 style(update 后调用)。
25531
+ * 仅做 updateNodeData 合并,不主动 render —— 由随后的一次 render 统一生效。
25532
+ * 顺带清理指向已不存在节点 / 表位的过期记录(换数据后自动丢弃)。
25533
+ */
25534
+ _applyColorOverrides() {
25535
+ if (!this._graph) return;
25536
+ const updates = [];
25537
+ if (this._nodeColorOverrides.size) {
25538
+ const stale = [];
25539
+ for (const [id2, color2] of this._nodeColorOverrides) {
25540
+ if (!this._graph.getNodeData(id2)) {
25541
+ stale.push(id2);
25542
+ continue;
25543
+ }
25544
+ updates.push({ id: id2, style: { color: color2 || "" } });
25545
+ }
25546
+ for (const id2 of stale) this._nodeColorOverrides.delete(id2);
25547
+ }
25548
+ if (this._custColorOverrides.size) {
25549
+ const byBox = /* @__PURE__ */ new Map();
25550
+ const stale = [];
25551
+ for (const [key, color2] of this._custColorOverrides) {
25552
+ const sep = key.indexOf("#cust");
25553
+ if (sep < 0) {
25554
+ stale.push(key);
25555
+ continue;
25556
+ }
25557
+ const boxId = key.slice(0, sep);
25558
+ if (!this._graph.getNodeData(boxId)) {
25559
+ stale.push(key);
25560
+ continue;
25561
+ }
25562
+ if (!byBox.has(boxId)) byBox.set(boxId, /* @__PURE__ */ new Map());
25563
+ byBox.get(boxId).set(Number(key.slice(sep + 5)), color2);
25564
+ }
25565
+ for (const [boxId, cellMap] of byBox) {
25566
+ const cur = this._safeNodeStyle(boxId, {});
25567
+ const customers = cur._customers;
25568
+ if (!Array.isArray(customers) || !customers.length) continue;
25569
+ const arr = new Array(customers.length).fill(null);
25570
+ let any = false;
25571
+ for (const [idx, color2] of cellMap) {
25572
+ if (idx >= 0 && idx < arr.length && color2) {
25573
+ arr[idx] = color2;
25574
+ any = true;
25575
+ }
25576
+ }
25577
+ updates.push({ id: boxId, style: { _cellColors: any ? arr : null } });
25578
+ }
25579
+ for (const key of stale) this._custColorOverrides.delete(key);
25580
+ }
25581
+ if (updates.length) {
25582
+ try {
25583
+ this._graph.updateNodeData(updates);
25584
+ } catch (e2) {
25585
+ console.error("[TopoApi] _applyColorOverrides error:", e2);
25586
+ }
25587
+ }
25588
+ }
25589
+ /**
25590
+ * 写入某个解析端点的染色(setNodeColor / batchSetNodeColor 共用)。
25591
+ * @param {{kind:'node',id:string}|{kind:'customer',boxId:string,index:number,node:object}} e
25592
+ * @param {string|null} color 颜色;null/''/undefined = 清除该处染色
25593
+ */
25594
+ _writeColorEndpoint(e2, color2) {
25595
+ if (!this._graph) return;
25596
+ color2 = color2 == null ? null : String(color2).trim() || null;
25597
+ if (e2.kind === "node") {
25598
+ const id2 = e2.id;
25599
+ if (color2) this._nodeColorOverrides.set(id2, color2);
25600
+ else this._nodeColorOverrides.delete(id2);
25601
+ this._updateNodes([{ id: id2, style: { color: color2 || "" } }]);
25602
+ return;
25603
+ }
25604
+ const key = `${e2.boxId}#cust${e2.index}`;
25605
+ if (color2) this._custColorOverrides.set(key, color2);
25606
+ else this._custColorOverrides.delete(key);
25607
+ const cur = this._safeNodeStyle(e2.boxId, {});
25608
+ const customers = cur._customers;
25609
+ if (!Array.isArray(customers) || !customers.length) return;
25610
+ const arr = new Array(customers.length).fill(null);
25611
+ let any = false;
25612
+ for (const [k, c] of this._custColorOverrides) {
25613
+ if (!k.startsWith(`${e2.boxId}#cust`)) continue;
25614
+ const idx = Number(k.slice(k.indexOf("#cust") + 5));
25615
+ if (idx >= 0 && idx < arr.length && c) {
25616
+ arr[idx] = c;
25617
+ any = true;
25618
+ }
25619
+ }
25620
+ this._updateNodes([{ id: e2.boxId, style: { _cellColors: any ? arr : null } }]);
25621
+ }
25622
+ /**
25623
+ * 给节点 / 箱内电表户设置颜色。
25624
+ * @param {string} ref 节点内部 id / 节点 psrId(普通节点、计量箱本体)
25625
+ * 或 客户资产编号 assetNo(兼容 consNo/consId,箱内电表户)
25626
+ * @param {string} [color] 颜色('#RRGGBB' / 'red' 等);传 null/''/undefined 清除该处染色
25627
+ * @returns {boolean} 是否命中并设置成功
25628
+ */
25629
+ setNodeColor(ref, color2) {
25630
+ this._assertReady();
25631
+ const e2 = this._parseEndpoint(ref);
25632
+ if (!e2) {
25633
+ console.warn(`[TopoApi] setNodeColor: 无法解析目标 ${ref}(普通节点请用 psrId/节点id,电表户请用 assetNo/consNo/consId)`);
25634
+ return false;
25635
+ }
25636
+ this._writeColorEndpoint(e2, color2);
25637
+ return true;
25638
+ }
25639
+ /**
25640
+ * 批量设置颜色。三种入参形式:
25641
+ * 1) 数组:[ ['8ff4…', '#FF0000'], ['4230…资产编号', '#00FF00'], … ]
25642
+ * 2) 数组:[{ ref / psrId / assetNo / nodeId, color? }](color 缺省用第 2 参)
25643
+ * 3) 对象:{ 'psrId或assetNo': '#FF0000', … }
25644
+ * @param {*} entries
25645
+ * @param {string} [color] 未在单项里给色时的兜底颜色
25646
+ * @returns {{total:number, ok:number, failed:Array<{ref:string, reason:string}>}}
25647
+ */
25648
+ batchSetNodeColor(entries, color2) {
25649
+ this._assertReady();
25650
+ const failed = [];
25651
+ let total = 0;
25652
+ const applyRef = (ref, c) => {
25653
+ total++;
25654
+ const e2 = this._parseEndpoint(ref);
25655
+ if (!e2) {
25656
+ failed.push({ ref: String(ref), reason: "未命中任何节点/电表户" });
25657
+ return;
25658
+ }
25659
+ this._writeColorEndpoint(e2, c);
25660
+ };
25661
+ if (Array.isArray(entries)) {
25662
+ for (const item of entries) {
25663
+ if (Array.isArray(item)) {
25664
+ applyRef(item[0], item[1] != null ? item[1] : color2);
25665
+ } else if (item && typeof item === "object") {
25666
+ const ref = item.ref != null ? item.ref : item.psrId != null ? item.psrId : item.assetNo != null ? item.assetNo : item.nodeId;
25667
+ if (ref == null) {
25668
+ total++;
25669
+ failed.push({ ref: JSON.stringify(item), reason: "缺少 ref/psrId/assetNo/nodeId" });
25670
+ continue;
25671
+ }
25672
+ applyRef(ref, item.color != null ? item.color : color2);
25673
+ }
25674
+ }
25675
+ } else if (entries && typeof entries === "object") {
25676
+ for (const [ref, c] of Object.entries(entries)) applyRef(ref, c);
25677
+ }
25678
+ return { total, ok: total - failed.length, failed };
25679
+ }
25680
+ /**
25681
+ * 清除某处染色(返回节点 / 电表户到主题默认配色)。
25682
+ * @param {string} ref 同 setNodeColor 的引用
25683
+ */
25684
+ resetNodeColor(ref) {
25685
+ this._assertReady();
25686
+ const e2 = this._parseEndpoint(ref);
25687
+ if (!e2) {
25688
+ console.warn(`[TopoApi] resetNodeColor: 无法解析目标 ${ref}`);
25689
+ return false;
25690
+ }
25691
+ this._writeColorEndpoint(e2, null);
25692
+ return true;
25693
+ }
25694
+ /** 清除全部染色(所有节点与电表户回到主题默认配色) */
25695
+ resetAllNodeColors() {
25696
+ this._assertReady();
25697
+ const nodeUpdates = [];
25698
+ for (const [id2] of this._nodeColorOverrides) {
25699
+ if (this._graph.getNodeData(id2)) nodeUpdates.push({ id: id2, style: { color: "" } });
25700
+ }
25701
+ const boxes = /* @__PURE__ */ new Set();
25702
+ for (const [key] of this._custColorOverrides) {
25703
+ const sep = key.indexOf("#cust");
25704
+ if (sep >= 0) boxes.add(key.slice(0, sep));
25705
+ }
25706
+ for (const boxId of boxes) {
25707
+ if (this._graph.getNodeData(boxId)) {
25708
+ nodeUpdates.push({ id: boxId, style: { _cellColors: null } });
25709
+ }
25710
+ }
25711
+ if (nodeUpdates.length) this._updateNodes(nodeUpdates);
25712
+ this._nodeColorOverrides.clear();
25713
+ this._custColorOverrides.clear();
25714
+ }
25715
+ /**
25716
+ * 查询某处当前生效的染色。
25717
+ * @param {string} ref 同 setNodeColor 的引用
25718
+ * @returns {{ kind: 'node'|'customer', id: string, index?: number, color: string|null } | null}
25719
+ */
25720
+ getNodeColor(ref) {
25721
+ this._assertReady();
25722
+ const e2 = this._parseEndpoint(ref);
25723
+ if (!e2) return null;
25724
+ if (e2.kind === "node") {
25725
+ const color3 = this._nodeColorOverrides.get(e2.id);
25726
+ if (color3) return { kind: "node", id: e2.id, color: color3 };
25727
+ const cur2 = this._safeNodeStyle(e2.id, {});
25728
+ return { kind: "node", id: e2.id, color: cur2.color || null };
25729
+ }
25730
+ const key = `${e2.boxId}#cust${e2.index}`;
25731
+ const color2 = this._custColorOverrides.get(key);
25732
+ if (color2) return { kind: "customer", id: key, boxId: e2.boxId, index: e2.index, color: color2 };
25733
+ const cur = this._safeNodeStyle(e2.boxId, {});
25734
+ const arr = cur._cellColors;
25735
+ return {
25736
+ kind: "customer",
25737
+ id: key,
25738
+ boxId: e2.boxId,
25739
+ index: e2.index,
25740
+ color: Array.isArray(arr) && arr[e2.index] || null
25741
+ };
25742
+ }
25743
+ // ============================================================
25509
25744
  // 四、边样式
25510
25745
  // ============================================================
25511
25746
  /** 设置边样式 */
@@ -27901,6 +28136,9 @@ function buildGraphData(model, layout) {
27901
28136
  size: [w, h],
27902
28137
  // 自定义字段(进 attributes,供 svg-symbol 节点绘制使用)
27903
28138
  cat: n.cat,
28139
+ // labelText:节点标签文字(canvasNode 用固定每行 N 字换行绘制)。
28140
+ // 禁用 G6 内置 label(label:false),避免其单行画出长名不换行。
28141
+ label: false,
27904
28142
  labelText: n.cat === "bus" || n.cat === "cableTerminal" || n.cat === "consumer" ? "" : n.shortName || "",
27905
28143
  rotate: layout.stationRotate && layout.stationRotate.get(n.id) || 0,
27906
28144
  highlight: 0,
@@ -28037,21 +28275,56 @@ function setNodePalette(themeName) {
28037
28275
  if (key in C2) C2[key] = t[key];
28038
28276
  }
28039
28277
  }
28278
+ function nodeColor(attributes) {
28279
+ return attributes && attributes.color || null;
28280
+ }
28281
+ function cellColorAt(attributes, i) {
28282
+ const arr = attributes && attributes._cellColors;
28283
+ return Array.isArray(arr) ? arr[i] || null : null;
28284
+ }
28285
+ function localPalette(attributes) {
28286
+ const c = nodeColor(attributes);
28287
+ if (!c) return C2;
28288
+ return {
28289
+ ...C2,
28290
+ red: c,
28291
+ orange: c,
28292
+ cyan: c,
28293
+ gold: c,
28294
+ trunkLine: c,
28295
+ dotFill: withAlpha(c, 0.18)
28296
+ };
28297
+ }
28298
+ function withAlpha(color2, a2) {
28299
+ if (typeof color2 !== "string") return color2;
28300
+ const m = color2.match(/^#([0-9a-f]{6}|[0-9a-f]{3})$/i);
28301
+ if (!m) return color2;
28302
+ let hex2 = m[1];
28303
+ if (hex2.length === 3) hex2 = hex2.split("").map((h) => h + h).join("");
28304
+ const n = parseInt(hex2, 16);
28305
+ const r = n >> 16 & 255, g = n >> 8 & 255, b = n & 255;
28306
+ return `rgba(${r},${g},${b},${a2})`;
28307
+ }
28308
+ const LW = 1.8;
28309
+ const LW_HI = 2.2;
28040
28310
  function drawHighlight(attributes, group) {
28041
28311
  if (!attributes.highlight) return;
28042
28312
  const [w, h] = attributes.size;
28313
+ const color2 = attributes.highlightColor || C2.gold;
28314
+ const lw = attributes.highlightWidth || 2;
28315
+ const dash = attributes.highlightDash || [5, 4];
28043
28316
  group.appendChild(
28044
28317
  new Rect({
28045
28318
  style: {
28046
- x: -w / 2 + 1,
28047
- y: -h / 2 + 1,
28048
- width: w - 2,
28049
- height: h - 2,
28050
- radius: 4,
28319
+ x: -w / 2 - 3,
28320
+ y: -h / 2 - 3,
28321
+ width: w + 6,
28322
+ height: h + 6,
28323
+ radius: 6,
28051
28324
  fill: "none",
28052
- stroke: C2.gold,
28053
- lineWidth: 1.6,
28054
- lineDash: [4, 3]
28325
+ stroke: color2,
28326
+ lineWidth: lw,
28327
+ lineDash: dash
28055
28328
  }
28056
28329
  })
28057
28330
  );
@@ -28063,15 +28336,16 @@ function drawAnnotation(attributes, group) {
28063
28336
  const pos = attributes.annotationPos || "top";
28064
28337
  const offset = attributes.annotationOffset || 4;
28065
28338
  const y = pos === "top" ? -h / 2 - offset - 6 : h / 2 + offset + 6;
28066
- _drawWrappedText(group, label, 0, y, attributes.annotationSize || 12, attributes.annotationColor || C2.white, w + 10, 1.25);
28339
+ _drawWrappedText(group, label, 0, y, attributes.annotationSize || 12, attributes.annotationColor || C2.white, w + 10, 1.25, 600);
28067
28340
  }
28068
28341
  function drawLabelUnder(attributes, group) {
28069
28342
  const label = attributes.labelText || "";
28070
28343
  if (!label) return;
28071
28344
  const [w, h] = attributes.size;
28072
- _drawWrappedText(group, label, 0, h / 2 + 8, 11, C2.white, w + 4, 1.3);
28345
+ const x0 = w / 2 + 6;
28346
+ _drawWrappedTextFixed(group, label, x0, -h / 2, 8, C2.white, 4, 1.3, 500, "left");
28073
28347
  }
28074
- function text(attributes, group, str2, x, y, size, fill) {
28348
+ function text(attributes, group, str2, x, y, size, fill, weight = 400) {
28075
28349
  if (!str2) return;
28076
28350
  group.appendChild(
28077
28351
  new Text({
@@ -28081,6 +28355,7 @@ function text(attributes, group, str2, x, y, size, fill) {
28081
28355
  y,
28082
28356
  fontSize: size,
28083
28357
  fill,
28358
+ fontWeight: weight,
28084
28359
  fontFamily: FONT,
28085
28360
  textAlign: "center",
28086
28361
  textBaseline: "middle"
@@ -28111,7 +28386,44 @@ function _wrapLines(str2, fontSize2, maxWidth) {
28111
28386
  if (line) lines.push(line);
28112
28387
  return lines;
28113
28388
  }
28114
- function _drawWrappedText(group, str2, x, y, fontSize2, fill, maxWidth, lineGap = 1.3) {
28389
+ function _wrapLinesFixed(str2, chars2) {
28390
+ if (!str2) return [];
28391
+ const lines = [];
28392
+ let line = "";
28393
+ for (const ch of str2) {
28394
+ line += ch;
28395
+ if (line.length >= chars2) {
28396
+ lines.push(line);
28397
+ line = "";
28398
+ }
28399
+ }
28400
+ if (line) lines.push(line);
28401
+ return lines;
28402
+ }
28403
+ function _drawWrappedTextFixed(group, str2, x, y, fontSize2, fill, chars2, lineGap = 1.3, weight = 400, align = "center") {
28404
+ if (!str2) return;
28405
+ const lines = _wrapLinesFixed(str2, chars2);
28406
+ if (!lines.length) return;
28407
+ const lineHeight2 = fontSize2 * lineGap;
28408
+ for (let i = 0; i < lines.length; i++) {
28409
+ group.appendChild(
28410
+ new Text({
28411
+ style: {
28412
+ text: lines[i],
28413
+ x,
28414
+ y: y + lineHeight2 * i,
28415
+ fontSize: fontSize2,
28416
+ fill,
28417
+ fontWeight: weight,
28418
+ fontFamily: FONT,
28419
+ textAlign: align === "left" ? "left" : "center",
28420
+ textBaseline: "middle"
28421
+ }
28422
+ })
28423
+ );
28424
+ }
28425
+ }
28426
+ function _drawWrappedText(group, str2, x, y, fontSize2, fill, maxWidth, lineGap = 1.3, weight = 400) {
28115
28427
  if (!str2) return;
28116
28428
  const lines = _wrapLines(str2, fontSize2, maxWidth);
28117
28429
  if (!lines.length) return;
@@ -28126,6 +28438,7 @@ function _drawWrappedText(group, str2, x, y, fontSize2, fill, maxWidth, lineGap
28126
28438
  y: y - totalH / 2 + lineHeight2 * (i + 0.5),
28127
28439
  fontSize: fontSize2,
28128
28440
  fill,
28441
+ fontWeight: weight,
28129
28442
  fontFamily: FONT,
28130
28443
  textAlign: "center",
28131
28444
  textBaseline: "middle"
@@ -28135,77 +28448,122 @@ function _drawWrappedText(group, str2, x, y, fontSize2, fill, maxWidth, lineGap
28135
28448
  }
28136
28449
  }
28137
28450
  function drawTransformer(attributes, group) {
28138
- const lw = 1.4;
28139
- group.appendChild(new Line({ style: { x1: -24, y1: 0, x2: -15, y2: 0, stroke: C2.trunkLine, lineWidth: lw } }));
28140
- group.appendChild(new Circle({ style: { cx: -5, cy: 0, r: 10, fill: C2.orange, stroke: C2.trunkLine, lineWidth: 1.2 } }));
28141
- group.appendChild(new Circle({ style: { cx: 10, cy: 0, r: 10, fill: "none", stroke: C2.red, lineWidth: 1.2 } }));
28142
- group.appendChild(new Line({ style: { x1: 20, y1: 0, x2: 29, y2: 0, stroke: C2.red, lineWidth: lw } }));
28451
+ const P = localPalette(attributes);
28452
+ const lw = LW;
28453
+ group.appendChild(new Line({ style: { x1: -26, y1: 0, x2: -14, y2: 0, stroke: P.trunkLine, lineWidth: lw, lineCap: "round" } }));
28454
+ group.appendChild(new Circle({ style: { cx: -4.5, cy: 0, r: 10, fill: P.orange, stroke: P.trunkLine, lineWidth: 1.4 } }));
28455
+ group.appendChild(new Circle({ style: { cx: -7.2, cy: -3.2, r: 3.2, fill: withAlpha(C2.white, 0.25), stroke: "none" } }));
28456
+ group.appendChild(new Circle({ style: { cx: 10, cy: 0, r: 10, fill: withAlpha(P.red, 0.06), stroke: P.red, lineWidth: LW_HI } }));
28457
+ group.appendChild(new Line({ style: { x1: 20, y1: 0, x2: 30, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28143
28458
  }
28144
28459
  function drawFuse(attributes, group) {
28145
- const lw = 1.4;
28146
- group.appendChild(new Line({ style: { x1: -26, y1: 0, x2: -19, y2: 0, stroke: C2.red, lineWidth: lw } }));
28147
- group.appendChild(new Rect({ style: { x: -19, y: -7, width: 38, height: 14, radius: 1, fill: "none", stroke: C2.red, lineWidth: lw } }));
28148
- group.appendChild(new Circle({ style: { cx: -13, cy: 0, r: 3.6, fill: C2.red } }));
28149
- group.appendChild(new Rect({ style: { x: -8, y: -2.4, width: 5, height: 4.8, fill: C2.red } }));
28150
- group.appendChild(new Rect({ style: { x: -1, y: -5.4, width: 13, height: 10.8, fill: C2.red } }));
28151
- group.appendChild(new Line({ style: { x1: 19, y1: 0, x2: 26, y2: 0, stroke: C2.red, lineWidth: lw } }));
28460
+ const P = localPalette(attributes);
28461
+ const lw = LW;
28462
+ group.appendChild(new Line({ style: { x1: -28, y1: 0, x2: -19, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28463
+ group.appendChild(new Line({ style: { x1: 19, y1: 0, x2: 28, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28464
+ group.appendChild(new Rect({ style: { x: -19, y: -7.5, width: 38, height: 15, radius: 2, fill: withAlpha(P.red, 0.05), stroke: P.red, lineWidth: lw } }));
28465
+ group.appendChild(new Circle({ style: { cx: -13, cy: 0, r: 3.4, fill: P.red, stroke: "none" } }));
28466
+ group.appendChild(new Rect({ style: { x: -8.2, y: -2.4, width: 5, height: 4.8, radius: 0.6, fill: P.red } }));
28467
+ group.appendChild(new Rect({ style: { x: -1.4, y: -5.4, width: 13, height: 10.8, radius: 0.8, fill: P.red } }));
28468
+ group.appendChild(new Rect({ style: { x: 5, y: -1.2, width: 8, height: 2.4, fill: C2.white, opacity: 0.55 } }));
28152
28469
  }
28153
28470
  function drawBreaker(attributes, group) {
28154
- const lw = 1.4;
28155
- group.appendChild(new Line({ style: { x1: -28, y1: 0, x2: -21, y2: 0, stroke: C2.red, lineWidth: lw } }));
28156
- group.appendChild(new Rect({ style: { x: -21, y: -9, width: 42, height: 18, radius: 2, fill: "none", stroke: C2.red, lineWidth: lw } }));
28157
- group.appendChild(new Rect({ style: { x: -21, y: -9, width: 42, height: 7, fill: "rgba(255,0,0,0.25)" } }));
28158
- _drawWrappedText(group, attributes.labelText, 0, 0.5, 10, C2.white, 36, 1.2);
28159
- group.appendChild(new Line({ style: { x1: 21, y1: 0, x2: 28, y2: 0, stroke: C2.red, lineWidth: lw } }));
28471
+ const P = localPalette(attributes);
28472
+ const lw = LW;
28473
+ const [nw] = attributes.size;
28474
+ const bw = 42;
28475
+ const bh = 20, r = 4;
28476
+ const bx = -bw / 2, by = -bh / 2;
28477
+ const xEdge = (nw || 60) / 2;
28478
+ const xBox = bw / 2;
28479
+ if (xEdge > xBox) {
28480
+ group.appendChild(new Line({ style: { x1: -xEdge, y1: 0, x2: -xBox, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28481
+ group.appendChild(new Line({ style: { x1: xBox, y1: 0, x2: xEdge, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28482
+ }
28483
+ group.appendChild(new Rect({ style: { x: bx, y: by, width: bw, height: bh, radius: r, fill: P.red, stroke: withAlpha(C2.white, 0.22), lineWidth: 1 } }));
28484
+ if (attributes.labelText) {
28485
+ _drawWrappedText(group, attributes.labelText, 0, 0.6, 11.5, "#FFFFFF", bw - 8, 1.15, 700);
28486
+ }
28160
28487
  }
28161
28488
  function drawCableTerminal(attributes, group) {
28162
- group.appendChild(new Polygon({ style: { points: [[1, -8], [-7, 8], [9, 8]], fill: C2.red, stroke: C2.red, lineWidth: 1 } }));
28489
+ const P = localPalette(attributes);
28490
+ const lw = 1.6;
28491
+ group.appendChild(new Line({ style: { x1: -11, y1: 0, x2: -5.5, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28492
+ group.appendChild(new Polygon({
28493
+ style: {
28494
+ points: [[-5, -9.5], [11, 0], [-5, 9.5]],
28495
+ fill: P.red,
28496
+ stroke: withAlpha(C2.white, 0.3),
28497
+ lineWidth: 1
28498
+ }
28499
+ }));
28163
28500
  }
28164
28501
  function drawStationTerminal(attributes, group) {
28165
- group.appendChild(new Line({ style: { x1: -9, y1: 0, x2: -1, y2: 0, stroke: C2.red, lineWidth: 1.4 } }));
28166
- group.appendChild(new Polygon({ style: { points: [[0, -5], [0, 5], [9, 0]], fill: "none", stroke: C2.red, lineWidth: 1.4 } }));
28502
+ const P = localPalette(attributes);
28503
+ const lw = LW;
28504
+ group.appendChild(new Line({ style: { x1: -12, y1: 0, x2: -4, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28505
+ group.appendChild(new Polygon({
28506
+ style: {
28507
+ points: [[0, -6], [0, 6], [10, 0]],
28508
+ fill: withAlpha(P.red, 0.08),
28509
+ stroke: P.red,
28510
+ lineWidth: lw
28511
+ }
28512
+ }));
28513
+ }
28514
+ function drawMeterFace(group, cx, cy, meterW, meterH, lineColor, markCell, cellIdx) {
28515
+ const r = Math.max(2, meterW * 0.16);
28516
+ const body = new Rect({ style: { x: cx - meterW / 2, y: cy - meterH / 2, width: meterW, height: meterH, radius: r, fill: withAlpha(lineColor, 0.06), stroke: lineColor, lineWidth: 1.2, cursor: "pointer" } });
28517
+ if (markCell) markCell(body, cellIdx);
28518
+ group.appendChild(body);
28519
+ const winW = meterW * 0.66, winH = Math.max(2.4, meterH * 0.17);
28520
+ const win = new Rect({ style: { x: cx - winW / 2, y: cy - meterH * 0.31, width: winW, height: winH, radius: winH / 2, fill: lineColor, opacity: 0.5, stroke: "none" } });
28521
+ if (markCell) markCell(win, cellIdx);
28522
+ group.appendChild(win);
28523
+ const dot2 = new Circle({ style: { cx, cy: cy + meterH * 0.12, r: 1.6, fill: lineColor, opacity: 0.85, stroke: "none" } });
28524
+ if (markCell) markCell(dot2, cellIdx);
28525
+ group.appendChild(dot2);
28167
28526
  }
28168
28527
  function drawMeterBox(attributes, group) {
28169
28528
  const [w, h] = attributes.size;
28529
+ const boxColor = nodeColor(attributes);
28170
28530
  if (attributes._meterBoxMode === "single") {
28171
28531
  const nodeId = attributes._nodeId || "";
28172
28532
  const sel = attributes._custSel === 0;
28173
28533
  const hover = attributes._custHover === 0;
28174
- const lineColor = sel ? C2.gold : hover ? C2.cyan : C2.white;
28534
+ const baseColor = cellColorAt(attributes, 0) || boxColor || C2.white;
28535
+ const lineColor = sel ? C2.gold : hover ? C2.cyan : baseColor;
28175
28536
  const markCell = (shape) => {
28176
28537
  if (!nodeId) return;
28177
28538
  shape.__custBox = nodeId;
28178
28539
  shape.__custIndex = 0;
28179
28540
  };
28541
+ const meterW = 20;
28542
+ const meterH = 26;
28543
+ drawMeterFace(group, 0, -1, meterW, meterH, lineColor, markCell, 0);
28180
28544
  if (sel || hover) {
28181
- const ring = new Circle({
28545
+ const ring = new Rect({
28182
28546
  style: {
28183
- cx: 0,
28184
- cy: -3,
28185
- r: 13,
28186
- fill: sel ? C2.gold : C2.cyan,
28187
- fillOpacity: sel ? 0.3 : 0.18,
28547
+ x: -meterW / 2 - 4,
28548
+ y: -meterH / 2 - 4,
28549
+ width: meterW + 8,
28550
+ height: meterH + 8,
28551
+ radius: 5,
28552
+ fill: "none",
28188
28553
  stroke: sel ? C2.gold : C2.cyan,
28189
- lineWidth: sel ? 1.6 : 1.1
28554
+ lineWidth: sel ? 2 : 1.3
28190
28555
  }
28191
28556
  });
28192
28557
  markCell(ring);
28193
28558
  group.appendChild(ring);
28194
28559
  }
28195
- const meterCircle = new Circle({ style: { cx: 0, cy: -3, r: 11, fill: "none", stroke: lineColor, lineWidth: sel ? 1.8 : 1.6, cursor: "pointer" } });
28196
- markCell(meterCircle);
28197
- group.appendChild(meterCircle);
28198
- const stub = new Line({ style: { x1: 0, y1: -14, x2: 0, y2: -7, stroke: lineColor, lineWidth: 1.6, cursor: "pointer" } });
28199
- markCell(stub);
28200
- group.appendChild(stub);
28201
28560
  const name = attributes._customers && attributes._customers[0] ? attributes._customers[0].realConsName || attributes._customers[0].consName || "" : "";
28202
28561
  if (name) {
28203
- const nameText = new Text({ style: { text: name, x: 0, y: 12, fontSize: 8, fill: sel ? C2.gold : hover ? C2.cyan : C2.white, fontFamily: FONT, textAlign: "center", textBaseline: "middle", cursor: "pointer" } });
28204
- markCell(nameText);
28205
- group.appendChild(nameText);
28562
+ _drawWrappedTextFixed(group, name, 0, meterH / 2 + 7, 7, lineColor, 4, 1.15, 500);
28206
28563
  }
28207
28564
  } else if (attributes._meterBoxMode === "grid" && attributes._customers) {
28208
- group.appendChild(new Rect({ style: { x: -w / 2, y: -h / 2, width: w, height: h, fill: C2.meterFill, stroke: C2.meterText, lineWidth: 0.9, radius: 2 } }));
28565
+ const frameColor = boxColor || C2.meterText;
28566
+ group.appendChild(new Rect({ style: { x: -w / 2, y: -h / 2, width: w, height: h, fill: withAlpha(frameColor, 0.04), stroke: frameColor, lineWidth: 1, radius: 4 } }));
28209
28567
  const cols = attributes._meterBoxCols || 5;
28210
28568
  const customers = attributes._customers;
28211
28569
  const showName = attributes._meterBoxShowName;
@@ -28216,11 +28574,12 @@ function drawMeterBox(attributes, group) {
28216
28574
  const gridH = rows * cellH + (rows - 1) * METER_GAP;
28217
28575
  const startX = -gridW / 2;
28218
28576
  const startY = -gridH / 2;
28219
- const meterR = 9;
28577
+ const meterW = Math.min(13, cellW * 0.5);
28578
+ const meterH = meterW * 1.5;
28579
+ const hitR = Math.max(9, meterH * 0.4);
28220
28580
  const custSel = attributes._custSel == null ? -1 : attributes._custSel;
28221
28581
  const custHover = attributes._custHover == null ? -1 : attributes._custHover;
28222
28582
  const nodeId = attributes._nodeId || "";
28223
- const hitR = meterR + 2.5;
28224
28583
  const markCell = (shape, i) => {
28225
28584
  if (!nodeId) return;
28226
28585
  shape.__custBox = nodeId;
@@ -28233,7 +28592,8 @@ function drawMeterBox(attributes, group) {
28233
28592
  const cy = startY + row2 * (cellH + METER_GAP) + cellW / 2;
28234
28593
  const sel = i === custSel;
28235
28594
  const hover = i === custHover;
28236
- const lineColor = sel ? C2.gold : hover ? C2.cyan : C2.meterText;
28595
+ const baseColor = cellColorAt(attributes, i) || C2.meterText;
28596
+ const lineColor = sel ? C2.gold : hover ? C2.cyan : baseColor;
28237
28597
  if (sel || hover) {
28238
28598
  group.appendChild(new Circle({
28239
28599
  style: {
@@ -28243,49 +28603,69 @@ function drawMeterBox(attributes, group) {
28243
28603
  fill: sel ? C2.gold : C2.cyan,
28244
28604
  fillOpacity: sel ? 0.3 : 0.18,
28245
28605
  stroke: sel ? C2.gold : C2.cyan,
28246
- lineWidth: sel ? 1.6 : 1.1
28606
+ lineWidth: sel ? 1.7 : 1.1
28247
28607
  }
28248
28608
  }));
28249
28609
  }
28250
- group.appendChild(new Circle({ style: { cx, cy, r: meterR, fill: "none", stroke: lineColor, lineWidth: sel ? 1.2 : 0.8 } }));
28251
- group.appendChild(new Line({ style: { x1: cx, y1: cy - meterR, x2: cx, y2: cy - meterR + 4, stroke: lineColor, lineWidth: 0.8 } }));
28610
+ drawMeterFace(group, cx, cy, meterW, meterH, lineColor, markCell, i);
28252
28611
  const hit = new Circle({ style: { cx, cy, r: hitR, fill: "rgba(255,255,255,0.01)", stroke: "none", cursor: "pointer" } });
28253
28612
  markCell(hit, i);
28254
28613
  group.appendChild(hit);
28255
28614
  if (showName) {
28256
28615
  const name = customers[i].realConsName || customers[i].consName || "";
28257
28616
  if (name) {
28258
- const nameText = new Text({ style: { text: name, x: cx, y: cy + meterR + 6, fontSize: 7, fill: sel ? C2.gold : hover ? C2.cyan : C2.meterText, fontFamily: FONT, textAlign: "center", textBaseline: "middle", cursor: "pointer" } });
28259
- markCell(nameText, i);
28260
- group.appendChild(nameText);
28617
+ _drawWrappedTextFixed(group, name, cx, cy + meterH / 2 + 6.5, 6.5, lineColor, 4, 1.15, 500);
28618
+ const hitName = new Circle({
28619
+ style: {
28620
+ cx,
28621
+ cy: cy + meterH / 2 + 6.5 + 4,
28622
+ r: Math.max(8, Math.min(14, Math.ceil(name.length / 4) * 4 + 4)),
28623
+ fill: "rgba(255,255,255,0.01)",
28624
+ stroke: "none",
28625
+ cursor: "pointer"
28626
+ }
28627
+ });
28628
+ markCell(hitName, i);
28629
+ group.appendChild(hitName);
28261
28630
  }
28262
28631
  }
28263
28632
  }
28264
28633
  } else {
28265
- group.appendChild(new Rect({ style: { x: -9.5, y: -9.5, width: 19, height: 19, fill: C2.meterFill, stroke: C2.meterText, lineWidth: 0.9 } }));
28266
- text(attributes, group, "JX", 0, 0.5, 7.5, C2.meterText);
28634
+ const s2 = Math.min(w, h) || 21;
28635
+ const ink = boxColor || C2.meterText;
28636
+ group.appendChild(new Rect({ style: { x: -s2 / 2, y: -s2 / 2, width: s2, height: s2, radius: Math.max(2, s2 * 0.16), fill: C2.meterFill, stroke: ink, lineWidth: 1.4 } }));
28637
+ group.appendChild(new Rect({ style: { x: -s2 / 2 + 2, y: -s2 / 2 + 2, width: s2 - 4, height: 2, radius: 1, fill: withAlpha(ink, 0.35), stroke: "none" } }));
28638
+ text(attributes, group, "JX", 0, s2 * 0.06, Math.max(8, s2 * 0.4), ink, 700);
28267
28639
  }
28268
28640
  }
28269
28641
  function drawConsumer(attributes, group) {
28270
- group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 12.5, fill: "none", stroke: C2.white, lineWidth: 1.8 } }));
28271
- text(attributes, group, "J", 0, 0.5, 13, C2.white);
28642
+ const ink = nodeColor(attributes) || C2.white;
28643
+ group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 13, fill: "none", stroke: ink, lineWidth: LW_HI } }));
28644
+ text(attributes, group, "J", 0, 0.8, 14.5, ink, 700);
28272
28645
  }
28273
28646
  function drawBus(attributes, group) {
28274
28647
  const [w] = attributes.size;
28275
- group.appendChild(new Rect({ style: { x: -w / 2, y: -3, width: w, height: 6, radius: 2, fill: C2.busFill, stroke: C2.white, lineWidth: 1.4 } }));
28648
+ const ink = nodeColor(attributes) || C2.white;
28649
+ const hh = Math.max(4.5, Math.min(6, w / 10));
28650
+ group.appendChild(new Rect({ style: { x: -w / 2, y: -hh / 2, width: w, height: hh, radius: hh / 2, fill: withAlpha(ink, 0.5), stroke: ink, lineWidth: 1.2 } }));
28651
+ group.appendChild(new Rect({ style: { x: -w / 2 + 1, y: -0.7, width: w - 2, height: 1.4, fill: withAlpha(C2.canvasBg || "#000", 0.18), stroke: "none" } }));
28276
28652
  }
28277
28653
  function drawLineDot(attributes, group) {
28278
- group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 4, fill: C2.dotFill, stroke: C2.cyan, lineWidth: 1.4 } }));
28654
+ const P = localPalette(attributes);
28655
+ group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 4.6, fill: P.dotFill, stroke: P.cyan, lineWidth: 1.6 } }));
28656
+ group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 1.5, fill: P.cyan, stroke: "none" } }));
28279
28657
  }
28280
28658
  function drawJunction(attributes, group) {
28281
- const lw = 1.4;
28282
- group.appendChild(new Line({ style: { x1: -5, y1: 0, x2: 5, y2: 0, stroke: C2.red, lineWidth: lw } }));
28283
- group.appendChild(new Line({ style: { x1: 0, y1: -5, x2: 0, y2: 5, stroke: C2.red, lineWidth: lw } }));
28284
- group.appendChild(new Line({ style: { x1: -3.5, y1: -3.5, x2: 3.5, y2: 3.5, stroke: C2.red, lineWidth: lw } }));
28285
- group.appendChild(new Line({ style: { x1: 3.5, y1: -3.5, x2: -3.5, y2: 3.5, stroke: C2.red, lineWidth: lw } }));
28659
+ const P = localPalette(attributes);
28660
+ const lw = LW;
28661
+ group.appendChild(new Line({ style: { x1: -5.5, y1: 0, x2: 5.5, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28662
+ group.appendChild(new Line({ style: { x1: 0, y1: -5.5, x2: 0, y2: 5.5, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28663
+ group.appendChild(new Line({ style: { x1: -3.9, y1: -3.9, x2: 3.9, y2: 3.9, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28664
+ group.appendChild(new Line({ style: { x1: 3.9, y1: -3.9, x2: -3.9, y2: 3.9, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
28286
28665
  }
28287
28666
  function drawUnknown(attributes, group) {
28288
- group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 8, fill: C2.unknownFill, stroke: C2.unknownStroke, lineWidth: 1.2 } }));
28667
+ group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 9, fill: C2.unknownFill, stroke: C2.unknownStroke, lineWidth: 1.4 } }));
28668
+ text(attributes, group, "?", 0, 0.8, 13, C2.unknownStroke, 700);
28289
28669
  }
28290
28670
  function drawStation(attributes, group) {
28291
28671
  const [w, h] = attributes.size;
@@ -28296,16 +28676,30 @@ function drawStation(attributes, group) {
28296
28676
  y: -h / 2,
28297
28677
  width: w,
28298
28678
  height: h,
28299
- radius: 2,
28679
+ radius: 5,
28300
28680
  fill: C2.stationFill,
28301
28681
  stroke: C2.white,
28302
- lineWidth: 1.2,
28682
+ lineWidth: 1.5,
28683
+ opacity: 0.95
28684
+ }
28685
+ })
28686
+ );
28687
+ group.appendChild(
28688
+ new Rect({
28689
+ style: {
28690
+ x: -w / 2 + 2,
28691
+ y: -h / 2 + 2,
28692
+ width: w - 4,
28693
+ height: 2.4,
28694
+ radius: 1.2,
28695
+ fill: withAlpha(C2.white, 0.28),
28696
+ stroke: "none",
28303
28697
  opacity: 0.9
28304
28698
  }
28305
28699
  })
28306
28700
  );
28307
28701
  if (attributes._stationTitle) {
28308
- _drawWrappedText(group, attributes._stationTitle, 0, -h / 2 + 13, 11, C2.stationText, w - 12, 1.35);
28702
+ _drawWrappedText(group, attributes._stationTitle, 0, -h / 2 + 15, 12, C2.stationText, w - 12, 1.35, 600);
28309
28703
  }
28310
28704
  }
28311
28705
  const DRAWERS = {
@@ -28322,7 +28716,6 @@ const DRAWERS = {
28322
28716
  station: drawStation,
28323
28717
  other: drawUnknown
28324
28718
  };
28325
- const LABEL_UNDER = /* @__PURE__ */ new Set(["transformer", "fuse"]);
28326
28719
  const _pulseState = /* @__PURE__ */ new Map();
28327
28720
  class SvgSymbolNode extends g6.BaseNode {
28328
28721
  drawKeyShape(attributes, container) {
@@ -28356,7 +28749,9 @@ class SvgSymbolNode extends g6.BaseNode {
28356
28749
  draw(attributes, target);
28357
28750
  drawHighlight(attributes, target);
28358
28751
  drawAnnotation(attributes, target);
28359
- if (LABEL_UNDER.has(attributes.cat)) drawLabelUnder(attributes, target);
28752
+ if (attributes.labelText && !attributes._stationTitle && attributes.cat !== "bus" && attributes.cat !== "cableTerminal" && attributes.cat !== "consumer" && attributes.cat !== "switch" && attributes.cat !== "meterBox") {
28753
+ drawLabelUnder(attributes, target);
28754
+ }
28360
28755
  const pulse = _pulseState.get(attributes._nodeId || "");
28361
28756
  if (pulse) {
28362
28757
  const items = rot ? [target] : key.children || [];
@@ -29269,7 +29664,7 @@ const _sfc_main = {
29269
29664
  }
29270
29665
  };
29271
29666
  const DistanceTop10 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-438b6017"]]);
29272
- const VERSION = "0.1.7";
29667
+ const VERSION = "0.1.8";
29273
29668
  const DESCRIPTION = "配电台区单线图拓扑成图引擎";
29274
29669
  exports.DESCRIPTION = DESCRIPTION;
29275
29670
  exports.DistanceTop10 = DistanceTop10;