@syhr/dga-charts 1.0.0

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/dist/index.js ADDED
@@ -0,0 +1,2796 @@
1
+ var Dt = Object.defineProperty;
2
+ var Et = (v, t, e) => t in v ? Dt(v, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : v[t] = e;
3
+ var K = (v, t, e) => Et(v, typeof t != "symbol" ? t + "" : t, e);
4
+ class At {
5
+ constructor() {
6
+ this._h = /* @__PURE__ */ Object.create(null);
7
+ }
8
+ on(t, e) {
9
+ return (this._h[t] || (this._h[t] = [])).push(e), this;
10
+ }
11
+ off(t, e) {
12
+ return e ? (this._h[t] && (this._h[t] = this._h[t].filter((o) => o !== e)), this) : (delete this._h[t], this);
13
+ }
14
+ emit(t, e) {
15
+ return (this._h[t] || []).slice().forEach((o) => o(e)), this;
16
+ }
17
+ dispose() {
18
+ this._h = /* @__PURE__ */ Object.create(null);
19
+ }
20
+ }
21
+ class ut {
22
+ constructor(t = {}) {
23
+ this.zoom = 1, this.panX = 0, this.panY = 0, this._min = t.min ?? 0.3, this._max = t.max ?? 6, this._step = t.step ?? 0.12, this._dragging = !1, this._dragStart = null, this._panStart = null;
24
+ }
25
+ onWheel(t, e, o) {
26
+ const s = t < 0 ? 1 : -1, i = Math.min(this._max, Math.max(this._min, this.zoom * (1 + s * this._step))), n = i / this.zoom;
27
+ return this.panX = e - n * (e - this.panX), this.panY = o - n * (o - this.panY), this.zoom = i, this;
28
+ }
29
+ startDrag(t, e) {
30
+ this._dragging = !0, this._dragStart = { x: t, y: e }, this._panStart = { x: this.panX, y: this.panY };
31
+ }
32
+ moveDrag(t, e, o) {
33
+ return this._dragging ? (this.panX = this._panStart.x + (t - this._dragStart.x) * o, this.panY = this._panStart.y + (e - this._dragStart.y) * o, !0) : !1;
34
+ }
35
+ endDrag() {
36
+ const t = this._dragging;
37
+ return this._dragging = !1, t;
38
+ }
39
+ reset() {
40
+ return this.zoom = 1, this.panX = 0, this.panY = 0, this;
41
+ }
42
+ get isDragging() {
43
+ return this._dragging;
44
+ }
45
+ get state() {
46
+ return { zoom: this.zoom, panX: this.panX, panY: this.panY };
47
+ }
48
+ applyTransform(t) {
49
+ t.translate(this.panX, this.panY), t.scale(this.zoom, this.zoom);
50
+ }
51
+ }
52
+ function Lt(v, t) {
53
+ const e = v.replace("#", ""), o = parseInt(e.slice(0, 2), 16), s = parseInt(e.slice(2, 4), 16), i = parseInt(e.slice(4, 6), 16);
54
+ return `rgba(${o},${s},${i},${t})`;
55
+ }
56
+ function E(v, t) {
57
+ for (const e of Object.keys(t)) {
58
+ const o = t[e];
59
+ o !== null && typeof o == "object" && !Array.isArray(o) ? (v[e] = v[e] && typeof v[e] == "object" ? v[e] : {}, E(v[e], o)) : v[e] = o;
60
+ }
61
+ return v;
62
+ }
63
+ function gt(v, t, e) {
64
+ let o = !1;
65
+ for (let s = 0, i = e.length - 1; s < e.length; i = s++) {
66
+ const [n, l] = e[s], [h, a] = e[i];
67
+ l > t != a > t && v < (h - n) * (t - l) / (a - l) + n && (o = !o);
68
+ }
69
+ return o;
70
+ }
71
+ class yt {
72
+ constructor(t, e) {
73
+ this.container = t, this.el = document.createElement("div"), this.el.style.position = "absolute", this.el.style.pointerEvents = "none", this.el.style.display = "none", this.el.style.zIndex = "9999", this.el.style.transition = "left 0.1s, top 0.1s", window.getComputedStyle(t).position === "static" && (t.style.position = "relative"), t.appendChild(this.el), this.updateTheme(e);
74
+ }
75
+ updateTheme(t) {
76
+ if (!t) return;
77
+ const e = t.tooltip || {}, o = e.textStyle || {};
78
+ this.el.style.backgroundColor = e.backgroundColor || t.tooltipBg || "rgba(6,13,31,0.93)", this.el.style.color = o.color || t.tooltipTextColor || "#c8ddf0";
79
+ let s = e.padding !== void 0 ? e.padding : t.tooltipPadding || 10;
80
+ typeof s == "number" ? this.el.style.padding = `${s}px` : Array.isArray(s) ? this.el.style.padding = s.map((i) => `${i}px`).join(" ") : this.el.style.padding = s + "px", this.el.style.borderRadius = "5px", this.el.style.border = `1px solid ${t.zoneBorderColor || "rgba(255,255,255,0.25)"}`, this.el.style.boxShadow = "0 0 10px rgba(0,0,0,0.45)", this.el.style.fontFamily = t.fontFamily || "Rajdhani, sans-serif", this.el.style.fontSize = o.fontSize !== void 0 ? typeof o.fontSize == "number" ? `${o.fontSize}px` : o.fontSize : "12px";
81
+ }
82
+ show(t, e, o, s = {}, i = {}, n = null) {
83
+ this.el.innerHTML = t, this.el.style.display = "block", this.el.style.backgroundColor = s.backgroundColor || i.tooltipBg || "rgba(6,13,31,0.93)";
84
+ const l = s.borderWidth !== void 0 ? typeof s.borderWidth == "number" ? `${s.borderWidth}px` : s.borderWidth : "1px", h = s.borderColor || (n ? n.borderColor || i.zoneBorderColor || n.color : "rgba(255,255,255,0.25)");
85
+ this.el.style.border = `${l} solid ${h}`, s.padding !== void 0 ? typeof s.padding == "number" ? this.el.style.padding = `${s.padding}px` : Array.isArray(s.padding) ? this.el.style.padding = s.padding.map((p) => `${p}px`).join(" ") : this.el.style.padding = s.padding : this.el.style.padding = (i.tooltipPadding || 10) + "px";
86
+ const a = s.textStyle || {};
87
+ this.el.style.color = a.color || i.tooltipTextColor || "#c8ddf0", this.el.style.fontStyle = a.fontStyle || "", this.el.style.fontWeight = a.fontWeight || a.fontStyle || "", this.el.style.fontSize = a.fontSize !== void 0 ? typeof a.fontSize == "number" ? `${a.fontSize}px` : a.fontSize : "12px", this.el.style.fontFamily = i.fontFamily || "Rajdhani, sans-serif";
88
+ const r = this.container.getBoundingClientRect(), c = this.el.offsetWidth, d = this.el.offsetHeight;
89
+ let f = e + 15, g = o - d / 2;
90
+ f + c > r.width && (f = e - c - 15), g < 0 && (g = 0), g + d > r.height && (g = r.height - d), this.el.style.left = f + "px", this.el.style.top = g + "px";
91
+ }
92
+ hide() {
93
+ this.el.style.display = "none";
94
+ }
95
+ dispose() {
96
+ this.el && this.el.parentNode && this.el.parentNode.removeChild(this.el);
97
+ }
98
+ }
99
+ function ct(v, t, e = {}, o = 45) {
100
+ const s = (f, g, p) => f == null ? p : typeof f == "string" && f.endsWith("%") ? parseFloat(f) / 100 * g : parseFloat(f) || 0, i = s(e.left, v, o), n = s(e.right, v, o), l = s(e.top, t, o), h = s(e.bottom, t, o), a = Math.max(0, v - i - n), r = Math.max(0, t - l - h), c = i + a / 2, d = l + r / 2;
101
+ return { left: i, right: n, top: l, bottom: h, availW: a, availH: r, cx: c, cy: d };
102
+ }
103
+ function nt(v, t, e, o, s, i = 1, n = 0) {
104
+ const l = (s + n) * i;
105
+ if (o === "circle" || o === "ring")
106
+ v.arc(t, e, l, 0, Math.PI * 2);
107
+ else if (o === "star") {
108
+ const h = l * 0.42;
109
+ for (let a = 0; a < 10; a++) {
110
+ const r = a * Math.PI / 5 - Math.PI / 2, c = a % 2 === 0 ? l : h;
111
+ a === 0 ? v.moveTo(t + c * Math.cos(r), e + c * Math.sin(r)) : v.lineTo(t + c * Math.cos(r), e + c * Math.sin(r));
112
+ }
113
+ v.closePath();
114
+ } else if (o === "triangle") {
115
+ for (let h = 0; h < 3; h++) {
116
+ const a = -Math.PI / 2 + h * 2 * Math.PI / 3, r = t + l * Math.cos(a), c = e + l * Math.sin(a);
117
+ h === 0 ? v.moveTo(r, c) : v.lineTo(r, c);
118
+ }
119
+ v.closePath();
120
+ } else if (o === "diamond")
121
+ v.moveTo(t, e - l), v.lineTo(t + l, e), v.lineTo(t, e + l), v.lineTo(t - l, e), v.closePath();
122
+ else if (o === "square" || o === "rect") {
123
+ const h = (s + n) * 2 * i, a = t - h / 2, r = e - h / 2;
124
+ v.rect(a, r, h, h);
125
+ } else
126
+ v.arc(t, e, l, 0, Math.PI * 2);
127
+ }
128
+ const Pt = [
129
+ {
130
+ id: "PD",
131
+ name: "PD",
132
+ desc: "局部放电",
133
+ color: "#A0DC99",
134
+ labelColor: "#1a4a1a",
135
+ points: [[1, 0, 0], [0.95, 0.05, 0], [0.95, 0, 0.05]]
136
+ },
137
+ {
138
+ id: "D1",
139
+ name: "D1",
140
+ desc: "低能放电",
141
+ color: "#77A3FC",
142
+ labelColor: "#ffffff",
143
+ points: [[0.85, 0.15, 0], [0, 1, 0], [0, 0.75, 0.25], [0.6, 0.15, 0.25]]
144
+ },
145
+ {
146
+ id: "D2",
147
+ name: "D2",
148
+ desc: "高能放电",
149
+ color: "#E3F2FF",
150
+ labelColor: "#1a3a6c",
151
+ points: [[0, 0.75, 0.25], [0, 0.28, 0.72], [0.32, 0.28, 0.4], [0.45, 0.15, 0.4], [0.6, 0.15, 0.25]]
152
+ },
153
+ {
154
+ id: "T1",
155
+ name: "T1",
156
+ desc: "热故障 < 300°C",
157
+ color: "#CBE4FD",
158
+ labelColor: "#1a2a6c",
159
+ points: [[0.95, 0.05, 0], [0.85, 0.05, 0.1], [0.9, 0, 0.1], [0.95, 0, 0.05]]
160
+ },
161
+ {
162
+ id: "T2",
163
+ name: "T2",
164
+ desc: "热故障 300 ~ 700°C",
165
+ color: "#56AD4A",
166
+ labelColor: "#e8ffe0",
167
+ points: [[0.85, 0.05, 0.1], [0.45, 0.05, 0.5], [0.5, 0, 0.5], [0.9, 0, 0.1]]
168
+ },
169
+ {
170
+ id: "T3",
171
+ name: "T3",
172
+ desc: "热故障 > 700°C",
173
+ color: "#5490FF",
174
+ labelColor: "#e0eeff",
175
+ points: [[0.5, 0, 0.5], [0.35, 0.15, 0.5], [0, 0.15, 0.85], [0, 0, 1]]
176
+ },
177
+ {
178
+ id: "DT",
179
+ name: "DT",
180
+ desc: "混合故障(放电+热)",
181
+ color: "#313CFF",
182
+ labelColor: "#c8d8ff",
183
+ points: [[0.95, 0.05, 0], [0.85, 0.15, 0], [0.45, 0.15, 0.4], [0.32, 0.28, 0.4], [0, 0.28, 0.72], [0, 0.15, 0.85], [0.35, 0.15, 0.5], [0.45, 0.05, 0.5]]
184
+ }
185
+ ], Ot = [
186
+ {
187
+ id: "PD",
188
+ name: "PD",
189
+ desc: "电晕型局部放电",
190
+ color: "#A0DC99",
191
+ labelColor: "#1a4a1a",
192
+ points: [[0.975, 0, 0.025], [0.955, 0.02, 0.025], [0.83, 0.02, 0.15], [0.85, 0, 0.15]]
193
+ },
194
+ {
195
+ id: "S",
196
+ name: "S",
197
+ desc: "温度<200℃时的杂散气体",
198
+ color: "#313CFF",
199
+ labelColor: "#c8d8ff",
200
+ points: [[1, 0, 0], [0.45, 0.55, 0], [0.08, 0.52, 0.4], [0.08, 0.3, 0.62], [0.15, 0.3, 0.55], [0.15, 0.25, 0.6], [0.4, 0.25, 0.35], [0.65, 0, 0.35], [0.85, 0, 0.15], [0.83, 0.02, 0.15], [0.955, 0.02, 0.025], [0.975, 0, 0.025]]
201
+ },
202
+ {
203
+ id: "C",
204
+ name: "C",
205
+ desc: "绝缘纸可能碳化",
206
+ color: "#3587FF",
207
+ labelColor: "#ffffff",
208
+ points: [[0.65, 0, 0.35], [0.4, 0.25, 0.35], [0.15, 0.25, 0.6], [0.15, 0.3, 0.55], [0, 0.3, 0.7], [0, 0, 1]]
209
+ },
210
+ {
211
+ id: "O",
212
+ name: "O",
213
+ desc: "过热温度<250℃,绝缘纸不碳化",
214
+ color: "#6AA4FF",
215
+ labelColor: "#c8d8ff",
216
+ points: [[0.08, 0.92, 0], [0, 1, 0], [0, 0.3, 0.7], [0.08, 0.3, 0.62]]
217
+ },
218
+ {
219
+ id: "ND",
220
+ name: "ND",
221
+ desc: "未确定",
222
+ color: "#BEE1FD",
223
+ labelColor: "#1a2a6c",
224
+ points: [[0.45, 0.55, 0], [0.08, 0.92, 0], [0.08, 0.52, 0.4]]
225
+ }
226
+ ], Nt = [
227
+ {
228
+ id: "PD",
229
+ name: "PD",
230
+ desc: "电晕型局部放电",
231
+ color: "#A0DC99",
232
+ labelColor: "#1a4a1a",
233
+ points: [[0.85, 0.15, 0], [0.83, 0.15, 0.02], [0.96, 0.02, 0.02], [0.98, 0.02, 0]]
234
+ },
235
+ {
236
+ id: "T2",
237
+ name: "T2",
238
+ desc: "中温过热 (300~700℃)",
239
+ color: "#56AD4A",
240
+ labelColor: "#1a4a1a",
241
+ points: [[0.9, 0, 0.1], [0.65, 0, 0.35], [0.525, 0.125, 0.35], [0.775, 0.125, 0.1]]
242
+ },
243
+ {
244
+ id: "S",
245
+ name: "S",
246
+ desc: "温度<200℃时的杂散气体",
247
+ color: "#313CFF",
248
+ labelColor: "#c8d8ff",
249
+ points: [[0.85, 0.15, 0], [0.35, 0.65, 0], [0.25, 0.65, 0.1], [0.75, 0.15, 0.1]]
250
+ },
251
+ {
252
+ id: "C",
253
+ name: "C",
254
+ desc: "绝缘纸可能碳化",
255
+ color: "#3587FF",
256
+ labelColor: "#ffffff",
257
+ points: [[0.6, 0.3, 0.1], [0, 0.3, 0.7], [0.15, 0.15, 0.7], [0.35, 0.15, 0.5], [0.375, 0.125, 0.5], [0.775, 0.125, 0.1]]
258
+ },
259
+ {
260
+ id: "O",
261
+ name: "O",
262
+ desc: "过热",
263
+ color: "#6AA4FF",
264
+ labelColor: "#1a3a6c",
265
+ points: [[1, 0, 0], [0.98, 0.02, 0], [0.96, 0.02, 0.02], [0.83, 0.15, 0.02], [0.85, 0.15, 0], [0, 1, 0], [0, 0.9, 0.1], [0.35, 0.55, 0.1], [0.45, 0.55, 0], [0.85, 0.15, 0], [0.75, 0.15, 0.1], [0.9, 0, 0.1]]
266
+ },
267
+ {
268
+ id: "T3-H",
269
+ name: "T3-H",
270
+ desc: "仅矿物油过热",
271
+ color: "#77A3FC",
272
+ labelColor: "#ffffff",
273
+ points: [[0.35, 0.3, 0.35], [0, 0.65, 0.35], [0, 0, 1], [0.65, 0, 0.35], [0.525, 0.125, 0.35], [0.375, 0.125, 0.5], [0.35, 0.15, 0.5], [0.15, 0.15, 0.7], [0, 0.3, 0.7]],
274
+ labelAt: [0.1, 0.42, 0.48]
275
+ },
276
+ {
277
+ id: "ND",
278
+ name: "ND",
279
+ desc: "未确定",
280
+ color: "#E3F2FF",
281
+ labelColor: "#1a3a6c",
282
+ points: [[0.6, 0.3, 0.1], [0, 0.9, 0.1], [0, 0.65, 0.35], [0.35, 0.3, 0.35]]
283
+ }
284
+ ], it = [
285
+ {
286
+ name: "PD",
287
+ title: "电晕型局部放电",
288
+ color: "#A0DC99",
289
+ desc: "电晕型局部放电",
290
+ poly: [
291
+ [0, 33],
292
+ [-1, 33],
293
+ [-1, 24.5],
294
+ [0, 24.5]
295
+ ]
296
+ },
297
+ {
298
+ name: "D1",
299
+ title: "低能量放电或火花型局部放电",
300
+ color: "#81ADFF",
301
+ desc: "低能量放电或火花型局部放电",
302
+ poly: [
303
+ [0, 40],
304
+ [38, 12],
305
+ [32, -6.1],
306
+ [4, 16],
307
+ [0, 1.5]
308
+ ]
309
+ },
310
+ {
311
+ name: "D2",
312
+ title: "高能量放电",
313
+ color: "#E3F2FF",
314
+ desc: "高能量放电",
315
+ poly: [
316
+ [4, 16],
317
+ [32, -6.1],
318
+ [24.3, -30],
319
+ [0, -3],
320
+ [0, 1.5]
321
+ ]
322
+ },
323
+ {
324
+ name: "T3",
325
+ title: "过热故障,t>700℃",
326
+ color: "#5490FF",
327
+ desc: "过热故障,t>700℃",
328
+ poly: [
329
+ [0, -3],
330
+ [24.3, -30],
331
+ [23.5, -32.4],
332
+ [1, -32.4],
333
+ [-6, -4]
334
+ ]
335
+ },
336
+ {
337
+ name: "T2",
338
+ title: "过热故障,300℃<t<700℃",
339
+ color: "#56AD4A",
340
+ desc: "中温热故障,铁心或铜导体局部过热,C₂H₄+CH₄ 均较高",
341
+ poly: [
342
+ [-6, -4],
343
+ [1, -32.4],
344
+ [-22.5, -32.4]
345
+ ]
346
+ },
347
+ {
348
+ name: "T1",
349
+ title: "过热故障,t<300℃",
350
+ color: "#CBE4FD",
351
+ desc: "低温热故障(<300°C),CH₄+C₂H₆ 为主要特征气体",
352
+ poly: [
353
+ [-6, -4],
354
+ [-22.5, -32.4],
355
+ [-23.5, -32.4],
356
+ [-35, 3],
357
+ [0, 1.5],
358
+ [0, -3]
359
+ ]
360
+ },
361
+ {
362
+ name: "S",
363
+ title: "温度<200℃时的杂散气体",
364
+ color: "#2735FF",
365
+ desc: "温度<200℃时的杂散气体",
366
+ poly: [
367
+ [0, 1.5],
368
+ [-35, 3.1],
369
+ [-38, 12.4],
370
+ [0, 40],
371
+ [0, 33],
372
+ [-1, 33],
373
+ [-1, 24.5],
374
+ [0, 24.5]
375
+ ]
376
+ }
377
+ ], lt = [
378
+ {
379
+ name: "PD",
380
+ title: "电晕型局部放电",
381
+ color: "#A0DC99",
382
+ desc: "内部局部放电,H₂ 占比 >93%",
383
+ poly: [
384
+ [0, 33],
385
+ [-1, 33],
386
+ [-1, 24.5],
387
+ [0, 24.5]
388
+ ]
389
+ },
390
+ {
391
+ name: "D1",
392
+ title: "低能量放电或火花型局部放电",
393
+ color: "#81ADFF",
394
+ desc: "低能量火花放电,绕组匝间短路早期,H₂+C₂H₂ 较高",
395
+ poly: [
396
+ [0, 40],
397
+ [38, 12],
398
+ [32, -6.1],
399
+ [4, 16],
400
+ [0, 1.5]
401
+ ]
402
+ },
403
+ {
404
+ name: "D2",
405
+ title: "高能量放电",
406
+ color: "#E3F2FF",
407
+ desc: "高能量电弧放电,严重绝缘故障,C₂H₂ 占比高",
408
+ poly: [
409
+ [4, 16],
410
+ [32, -6.1],
411
+ [24.3, -30],
412
+ [0, -3],
413
+ [0, 1.5]
414
+ ]
415
+ },
416
+ {
417
+ name: "S",
418
+ title: "温度<200℃时的杂散气体",
419
+ color: "#2735FF",
420
+ desc: "温度<200℃时的杂散气体",
421
+ poly: [
422
+ [0, 1.5],
423
+ [-35, 3.1],
424
+ [-38, 12.4],
425
+ [0, 40],
426
+ [0, 33],
427
+ [-1, 33],
428
+ [-1, 24.5],
429
+ [0, 24.5]
430
+ ]
431
+ },
432
+ {
433
+ name: "T3-H",
434
+ title: "——仅矿物油过热",
435
+ color: "#25A53D",
436
+ desc: "700℃以上高温过热,C₂H₄ 占比高,总烃快速增长",
437
+ poly: [
438
+ [0, -3],
439
+ [24.3, -30],
440
+ [23.5, -32.4],
441
+ [2.5, -32.4],
442
+ [-3.5, -3]
443
+ ]
444
+ },
445
+ {
446
+ name: "C",
447
+ title: "绝缘纸可能碳化",
448
+ color: "#3587FF",
449
+ desc: "绝缘纸可能碳化",
450
+ poly: [
451
+ [-3.5, -3],
452
+ [2.5, -32.4],
453
+ [-21.5, -32.4],
454
+ [-11, -8]
455
+ ]
456
+ },
457
+ {
458
+ name: "O",
459
+ title: "过热温度<250℃,绝缘纸不碳化",
460
+ color: "#6AA4FF",
461
+ desc: "过热温度<250℃,绝缘纸不碳化",
462
+ poly: [
463
+ [-3.5, -3],
464
+ [-11, -8],
465
+ [-21.5, -32.4],
466
+ [-23.5, -32.4],
467
+ [-35, 3.1],
468
+ [0, 1.5],
469
+ [0, -3]
470
+ ]
471
+ }
472
+ ], Wt = [
473
+ {
474
+ name: "D1/PD",
475
+ title: "局部放电",
476
+ color: "rgba(56,139,253,0.22)",
477
+ labelColor: "rgba(56,139,253,0.9)",
478
+ poly: [[-2, 3], [3, 3], [3, 0], [-2, 0]]
479
+ // Y >= 1 (logY >= 0), full X
480
+ },
481
+ {
482
+ name: "T3/DT",
483
+ title: "高温热故障/放电+热",
484
+ color: "rgba(63,185,80,0.18)",
485
+ labelColor: "rgba(63,185,80,0.9)",
486
+ poly: [[-2, 0], [3, 0], [3, -2], [-2, -2]]
487
+ // -2 <= logY <= 0, full X
488
+ },
489
+ {
490
+ name: "T1",
491
+ title: "过热故障,t<300℃",
492
+ color: "rgba(250,199,75,0.22)",
493
+ labelColor: "rgba(250,199,75,0.9)",
494
+ poly: [[-2, -2], [0, -2], [0, -3], [-2, -3]]
495
+ },
496
+ {
497
+ name: "T2",
498
+ title: "过热故障,300℃<t<700℃",
499
+ color: "rgba(240,120,60,0.25)",
500
+ labelColor: "rgba(240,120,60,0.9)",
501
+ poly: [[0, -2], [0.4, -2], [0.4, -3], [0, -3]]
502
+ },
503
+ {
504
+ name: "T3",
505
+ title: "过热故障,t>700℃",
506
+ color: "rgba(46,160,67,0.22)",
507
+ labelColor: "rgba(46,160,67,0.9)",
508
+ poly: [[0.4, -2], [3, -2], [3, -3], [0.4, -3]]
509
+ }
510
+ ], Zt = [
511
+ {
512
+ name: "D2",
513
+ title: "高能放电",
514
+ color: "rgba(56,139,253,0.28)",
515
+ labelColor: "rgba(100,180,255,0.95)",
516
+ // Y >= 10 AND X >= 10 → logY>=1, logX>=1
517
+ poly: [[-2, 3], [3, 3], [3, 0], [1, 0], [1, 1], [-2, 1]]
518
+ },
519
+ {
520
+ name: "D1",
521
+ title: "低能放电",
522
+ color: "rgba(56,139,253,0.15)",
523
+ labelColor: "rgba(130,190,255,0.85)",
524
+ // L-shape: Y>=1 AND X<10
525
+ // = (logY in [0,3], logX in [-2,1])
526
+ poly: [[-2, 1], [1, 1], [1, 0], [-2, 0]]
527
+ },
528
+ {
529
+ name: "PD",
530
+ title: "局部放电",
531
+ color: "rgba(63,185,80,0.18)",
532
+ labelColor: "rgba(63,185,80,0.9)",
533
+ poly: [[-2, 0], [0, 0], [0, -2], [-2, -2]]
534
+ },
535
+ {
536
+ name: "T3/DT",
537
+ title: "高温热/放电+热",
538
+ color: "rgba(250,199,75,0.18)",
539
+ labelColor: "rgba(250,199,75,0.9)",
540
+ poly: [[0, 0], [3, 0], [3, -2], [0, -2]]
541
+ },
542
+ {
543
+ name: "T1",
544
+ title: "过热故障,t<300℃",
545
+ color: "rgba(250,199,75,0.22)",
546
+ labelColor: "rgba(250,199,75,0.9)",
547
+ poly: [[-2, -2], [0, -2], [0, -3], [-2, -3]]
548
+ },
549
+ {
550
+ name: "T2",
551
+ title: "过热故障,300℃<t<700℃",
552
+ color: "rgba(240,120,60,0.25)",
553
+ labelColor: "rgba(240,120,60,0.9)",
554
+ poly: [[0, -2], [0.4, -2], [0.4, -3], [0, -3]]
555
+ },
556
+ {
557
+ name: "T3",
558
+ title: "过热故障,t>700℃",
559
+ color: "rgba(46,160,67,0.22)",
560
+ labelColor: "rgba(46,160,67,0.9)",
561
+ poly: [[0.4, -2], [3, -2], [3, -3], [0.4, -3]]
562
+ }
563
+ ], kt = [
564
+ {
565
+ name: "PD",
566
+ title: "电晕型局部放电",
567
+ fill: "#09FAFF",
568
+ edgeColor: "#09FAFF",
569
+ p1: [0, 0, 0],
570
+ // 开始坐标点
571
+ p2: [0.2, 0.1, 0.01]
572
+ // 结束坐标点
573
+ },
574
+ {
575
+ name: "T1",
576
+ title: "过热故障,t<300℃",
577
+ fill: "#EC9B9A",
578
+ edgeColor: "#EC9B9A",
579
+ p1: [0, 1, 0],
580
+ p2: [1, 10, 0.01]
581
+ },
582
+ {
583
+ name: "T2",
584
+ title: "过热故障,300℃<t<700℃",
585
+ fill: "#A0C9F5",
586
+ edgeColor: "#A0C9F5",
587
+ p1: [1, 1, 0],
588
+ p2: [4, 10, 0.1]
589
+ },
590
+ {
591
+ name: "T3",
592
+ title: "过热故障,t>700℃",
593
+ fill: "#CA677B",
594
+ edgeColor: "#CA677B",
595
+ p1: [4, 1, 0],
596
+ p2: [10, 10, 0.2]
597
+ },
598
+ {
599
+ name: "D1",
600
+ title: "低能量放电火花型局部放电",
601
+ fill: "#FF7B16",
602
+ edgeColor: "#FF7B16",
603
+ p1: [1, 0.1, 1],
604
+ p2: [10, 0.5, 10]
605
+ },
606
+ {
607
+ name: "D2",
608
+ title: "高能量放电",
609
+ fill: "#48FF16",
610
+ edgeColor: "#48FF16",
611
+ p1: [2, 0.1, 0.6],
612
+ p2: [10, 1, 2.5]
613
+ }
614
+ ];
615
+ function ft(v) {
616
+ if (!Array.isArray(v)) return [];
617
+ const t = v.map((o) => Math.max(Number(o) || 0, 0)), e = t.reduce((o, s) => o + s, 0);
618
+ return e === 0 ? t.map(() => 0) : t.map((o) => {
619
+ const s = o / e * 100;
620
+ return Math.round(s * 100) / 100;
621
+ });
622
+ }
623
+ function mt(v, t, e, o, s) {
624
+ const i = [v, t, e, o, s].map((d) => Math.max(0, Number(d) || 0)), n = i.reduce((d, f) => d + f, 0);
625
+ if (n <= 0) return null;
626
+ const l = i.map((d) => d / n), h = 40, a = [90, 18, -54, -126, 162];
627
+ let r = 0, c = 0;
628
+ for (let d = 0; d < 5; d++) {
629
+ const f = a[d] * Math.PI / 180;
630
+ r += l[d] * h * Math.cos(f), c += l[d] * h * Math.sin(f);
631
+ }
632
+ return { x: r, y: c, ratio: l };
633
+ }
634
+ function bt(v, t, e) {
635
+ let o = !1;
636
+ for (let s = 0, i = e.length - 1; s < e.length; i = s++) {
637
+ const [n, l] = e[s], [h, a] = e[i];
638
+ l > t != a > t && v < (h - n) * (t - l) / (a - l) + n && (o = !o);
639
+ }
640
+ return o;
641
+ }
642
+ const Ut = {
643
+ duvalTriangle1: (v, t, e) => {
644
+ if (v + t + e <= 0) return { code: "INVALID", label: "无效输入" };
645
+ const [s, i, n] = ft([v, t, e]);
646
+ return s >= 98 ? { code: "PD", label: "局部放电" } : i >= 23 && n <= 13 ? { code: "D1", label: "低能放电" } : i >= 23 && i <= 40 && n >= 13 && n <= 29 ? { code: "D2", label: "高能放电" } : n <= 4 && i <= 20 ? { code: "T1", label: "热故障(t < 300℃)" } : n <= 4 && i > 20 && i <= 50 ? { code: "T2", label: "热故障(300℃ < t < 700℃)" } : n <= 15 && i >= 50 ? { code: "T3", label: "热故障(t > 700℃)" } : { code: "ND", label: "区域未定义" };
647
+ },
648
+ duvalTriangle4: (v, t, e) => {
649
+ if (v + t + e <= 0) return { code: "INVALID", label: "无效输入" };
650
+ const [s, i, n] = ft([v, t, e]);
651
+ return i >= 1 && n >= 2 && n <= 15 ? { code: "PD", label: "电晕型局部放电" } : s <= 9 && i >= 24 && i <= 46 && n <= 36 ? { code: "S", label: "温度<200℃时的杂散气体" } : s <= 9 && i <= 30 ? { code: "O", label: "过热温度<250℃,绝缘纸不碳化" } : i >= 24 && i <= 30 && n >= 36 ? { code: "C", label: "绝缘纸可能碳化" } : { code: "ND", label: "区域未定义" };
652
+ },
653
+ duvalTriangle5: (v, t, e) => {
654
+ if (v + t + e <= 0) return { code: "INVALID", label: "无效输入" };
655
+ const [s, i, n] = ft([v, t, e]);
656
+ return s >= 85 && s <= 100 && n >= 0 && n <= 15 ? { code: "PD", label: "电晕型局部放电" } : i >= 35 && i <= 100 && n >= 0 && n <= 14 || i >= 35 && i <= 70 && n >= 30 && n <= 75 ? { code: "T3", label: "高温过热故障(t > 700℃)" } : i >= 10 && i <= 35 && n >= 0 && n <= 12 ? { code: "T2", label: "中温过热故障(t > 300℃)" } : i >= 10 && i <= 70 && n >= 12 && n <= 30 ? { code: "C", label: "绝缘纸碳化故障" } : i <= 10 && n >= 15 && n <= 54 ? { code: "S", label: "矿物油杂散气体(低温过热 90℃~200℃)" } : i <= 10 && (n <= 15 || n >= 54) ? { code: "O", label: "过热故障" } : { code: "ND", label: "区域未定义" };
657
+ },
658
+ duvalPentagon1: (v, t, e, o, s) => {
659
+ const i = mt(v, e, o, t, s);
660
+ if (!i) return { code: "INVALID", label: "无效输入", desc: "", color: "" };
661
+ const { x: n, y: l } = i;
662
+ for (let a = 0; a < it.length - 1; a++) {
663
+ const r = it[a];
664
+ if (bt(n, l, r.poly))
665
+ return { code: r.name, label: r.title, desc: r.desc, color: r.color };
666
+ }
667
+ const h = it[it.length - 1];
668
+ return { code: h.name, label: h.title, desc: h.desc, color: h.color };
669
+ },
670
+ duvalPentagon2: (v, t, e, o, s) => {
671
+ const i = mt(v, e, o, t, s);
672
+ if (!i) return { code: "INVALID", label: "无效输入", desc: "", color: "" };
673
+ const { x: n, y: l } = i;
674
+ for (let a = 0; a < lt.length - 1; a++) {
675
+ const r = lt[a];
676
+ if (bt(n, l, r.poly))
677
+ return { code: r.name, label: r.title, desc: r.desc, color: r.color };
678
+ }
679
+ const h = lt[lt.length - 1];
680
+ return { code: h.name, label: h.title, desc: h.desc, color: h.color };
681
+ }
682
+ }, $ = class $ {
683
+ // 度
684
+ /**
685
+ * 将 doc 坐标(R=40,Y向上)转换为归一化 ratio 向量
686
+ * @param {number} x - doc 坐标系 x
687
+ * @param {number} y - doc 坐标系 y
688
+ * @returns {number[]|null} - 长度为5的 ratio 向量,或 null(如果在五边形外)
689
+ */
690
+ static docToRatio(t, e) {
691
+ const o = $.DOC_R, i = $.DOC_ANGLES.map((n) => {
692
+ const l = n * Math.PI / 180;
693
+ return [o * Math.cos(l), o * Math.sin(l)];
694
+ });
695
+ for (let n = 0; n < 5; n++)
696
+ if (Math.hypot(t - i[n][0], e - i[n][1]) < 0.5) {
697
+ const l = [0, 0, 0, 0, 0];
698
+ return l[n] = 1, l;
699
+ }
700
+ for (let n = 0; n < 5; n++) {
701
+ const l = (n + 1) % 5, [h, a] = i[n], [r, c] = i[l], d = r - h, f = c - a, g = d * d + f * f;
702
+ if (g < 1e-10) continue;
703
+ const p = ((t - h) * d + (e - a) * f) / g;
704
+ if (p >= -1e-6 && p <= 1 + 1e-6 && Math.abs((e - a) * d - (t - h) * f) / Math.sqrt(g) < 0.15) {
705
+ const y = Math.max(0, Math.min(1, p)), u = [0, 0, 0, 0, 0];
706
+ return u[n] = 1 - y, u[l] = y, u;
707
+ }
708
+ }
709
+ for (let n = 0; n < 5; n++) {
710
+ const l = [0, 0], h = i[n], a = i[(n + 1) % 5], r = (h[1] - a[1]) * (l[0] - a[0]) + (a[0] - h[0]) * (l[1] - a[1]);
711
+ if (Math.abs(r) < 1e-10) continue;
712
+ const c = ((h[1] - a[1]) * (t - a[0]) + (a[0] - h[0]) * (e - a[1])) / r, d = ((a[1] - l[1]) * (t - a[0]) + (l[0] - a[0]) * (e - a[1])) / r, f = 1 - c - d;
713
+ if (c >= -0.01 && d >= -0.01 && f >= -0.01) {
714
+ const g = new Array(5).fill(c / 5);
715
+ g[n] += d, g[(n + 1) % 5] += f;
716
+ const p = g.reduce((m, y) => m + Math.max(0, y), 0);
717
+ return g.map((m) => Math.max(0, m) / p);
718
+ }
719
+ }
720
+ return null;
721
+ }
722
+ /**
723
+ * 将归一化 ratio 向量转换为 doc 坐标
724
+ * @param {number[]} ratio - 长度为5的 ratio 向量
725
+ * @returns {number[]} - [x, y] doc 坐标
726
+ */
727
+ static ratioToDoc(t) {
728
+ const e = $.DOC_R, o = $.DOC_ANGLES;
729
+ let s = 0, i = 0;
730
+ for (let n = 0; n < 5; n++) {
731
+ const l = o[n] * Math.PI / 180;
732
+ s += t[n] * e * Math.cos(l), i += t[n] * e * Math.sin(l);
733
+ }
734
+ return [s, i];
735
+ }
736
+ /**
737
+ * 将 canvas 像素坐标转换为归一化 ratio 向量
738
+ * @param {number} px - canvas 像素坐标 x
739
+ * @param {number} py - canvas 像素坐标 y
740
+ * @param {number} cx - 五边形中心 x
741
+ * @param {number} cy - 五边形中心 y
742
+ * @param {number} R - 五边形半径
743
+ * @returns {number[]|null} - ratio 向量或 null
744
+ */
745
+ static canvasToRatio(t, e, o, s, i) {
746
+ const n = Array.from({ length: 5 }, (l, h) => $.canvasVertex(h, o, s, i));
747
+ if (!gt(t, e, n)) return null;
748
+ for (let l = 0; l < 5; l++) {
749
+ const h = [o, s], a = n[l], r = n[(l + 1) % 5], c = (a[1] - r[1]) * (h[0] - r[0]) + (r[0] - a[0]) * (h[1] - r[1]);
750
+ if (Math.abs(c) < 1e-10) continue;
751
+ const d = ((a[1] - r[1]) * (t - r[0]) + (r[0] - a[0]) * (e - r[1])) / c, f = ((r[1] - h[1]) * (t - r[0]) + (h[0] - r[0]) * (e - r[1])) / c, g = 1 - d - f;
752
+ if (d >= -1e-9 && f >= -1e-9 && g >= -1e-9) {
753
+ const p = new Array(5).fill(d / 5);
754
+ p[l] += f, p[(l + 1) % 5] += g;
755
+ const m = p.reduce((y, u) => y + Math.max(0, u), 0);
756
+ return p.map((y) => Math.max(0, y) / m);
757
+ }
758
+ }
759
+ return null;
760
+ }
761
+ // canvas 顶点坐标(Y 向下,从顶部 12 点顺时针)
762
+ static canvasVertex(t, e, o, s) {
763
+ const i = -Math.PI / 2 + t * 2 * Math.PI / 5;
764
+ return [e + s * Math.cos(i), o + s * Math.sin(i)];
765
+ }
766
+ // doc 坐标 → canvas 坐标(直接线性映射)
767
+ static docToCanvas(t, e, o, s, i) {
768
+ return [
769
+ o + t / $.DOC_R * i,
770
+ s - e / $.DOC_R * i
771
+ // Y 轴反转
772
+ ];
773
+ }
774
+ // poly 统一解析 → canvas 点数组
775
+ static polyToCanvas(t, e, o, s) {
776
+ if (t.length === 2)
777
+ return $.docToCanvas(t[0], t[1], e, o, s);
778
+ let i = 0, n = 0;
779
+ for (let l = 0; l < 5; l++) {
780
+ const [h, a] = $.canvasVertex(l, e, o, s);
781
+ i += t[l] * h, n += t[l] * a;
782
+ }
783
+ return [i, n];
784
+ }
785
+ /**
786
+ * 将任意格式的 series.data 解析为归一化 ratio 向量
787
+ * @param {object|number[]} data - 待解析的数据
788
+ * @param {string[]} gasOrder - 气体顺序
789
+ * @returns {number[]|null} - ratio 向量或 null
790
+ */
791
+ static resolveData(t, e) {
792
+ if (!t) return null;
793
+ if (Array.isArray(t)) {
794
+ const o = t.length > 0 && t[0] && typeof t[0] == "object";
795
+ let s;
796
+ o && e ? s = e.map((n) => {
797
+ const l = t.find((h) => h.name === n);
798
+ return Math.max(0, (l ? l.value : 0) || 0);
799
+ }) : s = t.map((n) => Math.max(0, n || 0));
800
+ const i = s.reduce((n, l) => n + l, 0);
801
+ return i <= 1e-9 ? null : s.map((n) => n / i);
802
+ }
803
+ return "x" in t && "y" in t ? $.docToRatio(t.x, t.y) : null;
804
+ }
805
+ // ratio → doc 坐标字符串(调试/显示用)
806
+ static ratioToDocStr(t, e = 1) {
807
+ const [o, s] = $.ratioToDoc(t);
808
+ return `(${o.toFixed(e)}, ${s.toFixed(e)})`;
809
+ }
810
+ };
811
+ // doc 坐标系参数(固定)
812
+ K($, "DOC_R", 40), // 顶点角度(数学坐标,顺时针,H2 在顶部=90°)
813
+ K($, "DOC_ANGLES", [90, 18, -54, -126, 162]);
814
+ let W = $;
815
+ const J = class J {
816
+ static resolve(t) {
817
+ return !t || t === "dark" ? { ...J.DARK } : t === "light" ? { ...J.LIGHT } : E({ ...J.DARK }, t);
818
+ }
819
+ };
820
+ K(J, "DARK", {
821
+ backgroundColor: "transparent",
822
+ // 画布背景色
823
+ pointStyle: {
824
+ itemStyle: {
825
+ shape: "circle",
826
+ radius: 3,
827
+ color: "#00e5ff",
828
+ borderColor: "#ffffff",
829
+ borderWidth: 0.5
830
+ },
831
+ textStyle: {
832
+ show: !1,
833
+ fontSize: 11,
834
+ color: "#00e5ff",
835
+ position: "top"
836
+ }
837
+ },
838
+ vertex: {
839
+ show: !0,
840
+ labelStyle: {
841
+ color: "#01FFE1",
842
+ fontStyle: "normal",
843
+ fontWeight: "bold",
844
+ fontSize: 14
845
+ }
846
+ },
847
+ grid: {
848
+ show: !1,
849
+ lineStyle: {
850
+ lineType: "solid",
851
+ lineWidth: 1,
852
+ lineColor: "rgba(0, 229, 255, 0.15)"
853
+ }
854
+ },
855
+ zone: {
856
+ labelStyle: {
857
+ show: !0,
858
+ color: "#ffffff",
859
+ fontStyle: "bold",
860
+ fontSize: 12,
861
+ letterSpacing: 0,
862
+ textShadow: "rgba(0,0,0,0.85)",
863
+ padding: [4, 8],
864
+ borderRadius: 4,
865
+ backgroundColor: "transparent"
866
+ },
867
+ borderStyle: {
868
+ show: !0,
869
+ stroke: 1,
870
+ type: "solid",
871
+ color: "rgba(255, 255, 255, 0.25)"
872
+ }
873
+ },
874
+ tooltip: {
875
+ show: !0,
876
+ showDiagnostic: !1,
877
+ showPoint: !0,
878
+ backgroundColor: "rgba(6, 13, 31, 0.93)",
879
+ textStyle: {
880
+ color: "#c8ddf0",
881
+ fontStyle: "",
882
+ fontWeight: "",
883
+ fontSize: 12
884
+ },
885
+ padding: 10
886
+ },
887
+ fontFamily: "Rajdhani, sans-serif"
888
+ // 全局字体
889
+ }), K(J, "LIGHT", {
890
+ backgroundColor: "transparent",
891
+ // 画布背景色
892
+ pointStyle: {
893
+ itemStyle: {
894
+ shape: "circle",
895
+ radius: 3,
896
+ color: "#1d4ed8",
897
+ borderColor: "#ffffff",
898
+ borderWidth: 0.5
899
+ },
900
+ textStyle: {
901
+ show: !1,
902
+ fontSize: 11,
903
+ color: "#1d4ed8",
904
+ position: "top"
905
+ }
906
+ },
907
+ vertex: {
908
+ show: !0,
909
+ labelStyle: {
910
+ color: "#1d4ed8",
911
+ fontStyle: "normal",
912
+ fontWeight: "bold",
913
+ fontSize: 14
914
+ }
915
+ },
916
+ grid: {
917
+ show: !1,
918
+ lineStyle: {
919
+ lineType: "solid",
920
+ lineWidth: 1,
921
+ lineColor: "rgba(29, 78, 216, 0.15)"
922
+ }
923
+ },
924
+ zone: {
925
+ labelStyle: {
926
+ show: !0,
927
+ color: "#1e293b",
928
+ fontStyle: "bold",
929
+ fontSize: 11,
930
+ letterSpacing: 0,
931
+ textShadow: "rgba(255,255,255,0.8)",
932
+ padding: [4, 8],
933
+ borderRadius: 4,
934
+ backgroundColor: "transparent"
935
+ },
936
+ borderStyle: {
937
+ show: !0,
938
+ stroke: 1,
939
+ type: "solid",
940
+ color: "rgba(0, 0, 0, 0.25)"
941
+ }
942
+ },
943
+ tooltip: {
944
+ show: !0,
945
+ showDiagnostic: !1,
946
+ showPoint: !0,
947
+ backgroundColor: "rgba(240, 244, 248, 0.96)",
948
+ textStyle: {
949
+ color: "#334155",
950
+ fontStyle: "",
951
+ fontWeight: "",
952
+ fontSize: 12
953
+ },
954
+ padding: 10
955
+ },
956
+ fontFamily: "Rajdhani, sans-serif"
957
+ // 全局字体
958
+ });
959
+ let rt = J;
960
+ class pt {
961
+ /**
962
+ * 根据 ratio 向量诊断所在故障区域
963
+ * @param {number[]} ratio - 待诊断的 ratio 向量
964
+ * @param {object} zoneOpt - 区域配置对象
965
+ * @param {number} cx - 中心点 x
966
+ * @param {number} cy - 中心点 y
967
+ * @param {number} R - 半径
968
+ * @returns {object} - 匹配的区域对象
969
+ */
970
+ static diagnose(t, e, o, s, i) {
971
+ const n = e && Array.isArray(e.data) ? e.data : Array.isArray(e) ? e : [];
972
+ if (!n.length) return null;
973
+ const [l, h] = W.polyToCanvas(t, o, s, i);
974
+ for (let a = 0; a < n.length - 1; a++) {
975
+ const r = n[a].poly.map((c) => W.polyToCanvas(c, o, s, i));
976
+ if (gt(l, h, r)) return n[a];
977
+ }
978
+ return n[n.length - 1];
979
+ }
980
+ /**
981
+ * 绘制所有故障区域
982
+ * @param {CanvasRenderingContext2D} ctx - Canvas 2D 上下文
983
+ * @param {object} zoneOpt - 区域配置对象
984
+ * @param {object} theme - 主题配置
985
+ * @param {number} cx - 中心点 x
986
+ * @param {number} cy - 中心点 y
987
+ * @param {number} R - 半径
988
+ * @param {number} S - 容器尺寸
989
+ */
990
+ static draw(t, e, o, s, i, n, l) {
991
+ const h = e && Array.isArray(e.data) ? e.data : Array.isArray(e) ? e : [], a = e.labelStyle || {}, r = e.borderStyle || {};
992
+ for (const d of h) {
993
+ if (!d.poly || !d.poly.length) continue;
994
+ const f = d.poly.map((g) => W.polyToCanvas(g, s, i, n));
995
+ t.beginPath(), f.forEach(([g, p], m) => m === 0 ? t.moveTo(g, p) : t.lineTo(g, p)), t.closePath(), t.fillStyle = d.color || "transparent", t.fill();
996
+ }
997
+ for (const d of h) {
998
+ const f = { ...r, ...d.borderStyle || {} };
999
+ if (f.show === !1 || !d.poly || !d.poly.length) continue;
1000
+ const g = d.poly.map((p) => W.polyToCanvas(p, s, i, n));
1001
+ t.beginPath(), g.forEach(([p, m], y) => y === 0 ? t.moveTo(p, m) : t.lineTo(p, m)), t.closePath(), t.strokeStyle = f.color || d.borderColor || o.zoneBorderColor || "rgba(255,255,255,0.5)", t.lineWidth = (f.stroke ?? d.borderWidth ?? o.zoneBorderWidth ?? 1) * 1, f.type === "dashed" ? t.setLineDash([4, 4]) : f.type === "dotted" ? t.setLineDash([2, 4]) : t.setLineDash([]), t.stroke();
1002
+ }
1003
+ t.setLineDash([]);
1004
+ const c = o.fontFamily || "Rajdhani, sans-serif";
1005
+ for (const d of h) {
1006
+ const f = { ...a, ...d.labelStyle || {} };
1007
+ if (f.show === !1 || !d.name) continue;
1008
+ const g = d.poly ? d.poly.map((x) => W.polyToCanvas(x, s, i, n)) : [];
1009
+ let p, m;
1010
+ if (d.labelAt && Array.isArray(d.labelAt))
1011
+ [p, m] = W.polyToCanvas(d.labelAt, s, i, n);
1012
+ else if (g.length > 0)
1013
+ p = g.reduce((x, C) => x + C[0], 0) / g.length, m = g.reduce((x, C) => x + C[1], 0) / g.length;
1014
+ else
1015
+ continue;
1016
+ const y = Math.round((f.fontSize || o.zoneLabelSize || 12) * 1), u = f.fontStyle || "bold";
1017
+ t.font = `${u} ${y}px ${c}`, f.letterSpacing !== void 0 && "letterSpacing" in t && (t.letterSpacing = `${f.letterSpacing}px`), t.textAlign = "center", t.textBaseline = "middle";
1018
+ const b = d.name, w = t.measureText(b).width, S = y;
1019
+ if (f.backgroundColor && f.backgroundColor !== "transparent") {
1020
+ let x = 4, C = 4;
1021
+ Array.isArray(f.padding) ? (C = f.padding[0], x = f.padding[1] !== void 0 ? f.padding[1] : C) : typeof lstyle.padding == "number" && (x = C = lstyle.padding), x *= 1, C *= 1;
1022
+ const z = (f.borderRadius || 0) * 1, _ = w + x * 2, A = S + C * 2, Y = p - _ / 2, P = m - A / 2;
1023
+ t.fillStyle = f.backgroundColor, t.beginPath(), t.roundRect ? t.roundRect(Y, P, _, A, z) : t.rect(Y, P, _, A), t.fill();
1024
+ }
1025
+ f.textShadow && f.textShadow !== "none" ? (t.shadowColor = f.textShadow, t.shadowBlur = 4) : (t.shadowColor = "transparent", t.shadowBlur = 0), t.fillStyle = f.color || o.zoneLabelColor || "#fff", t.fillText(b, p, m), t.shadowBlur = 0, t.shadowColor = "transparent", "letterSpacing" in t && (t.letterSpacing = "0px");
1026
+ }
1027
+ }
1028
+ }
1029
+ class Xt {
1030
+ static draw(t, e, o, s, i, n, l, h) {
1031
+ var d;
1032
+ const r = o.fontFamily || "Rajdhani, sans-serif";
1033
+ if (h && h.show !== !1) {
1034
+ const f = h.lineStyle || {}, g = (f.lineWidth ?? 1) * 1, p = f.lineColor || "#e5e7eb", m = f.lineType || "solid";
1035
+ t.strokeStyle = p, t.lineWidth = g, m === "dashed" ? t.setLineDash([4, 4]) : m === "dotted" ? t.setLineDash([2, 4]) : t.setLineDash([]);
1036
+ for (const y of [0.2, 0.4, 0.6, 0.8, 1]) {
1037
+ t.beginPath();
1038
+ for (let u = 0; u < 5; u++) {
1039
+ const [b, w] = W.canvasVertex(u, s, i, n * y);
1040
+ u === 0 ? t.moveTo(b, w) : t.lineTo(b, w);
1041
+ }
1042
+ t.closePath(), t.stroke();
1043
+ }
1044
+ for (let y = 0; y < 5; y++) {
1045
+ const [u, b] = W.canvasVertex(y, s, i, n);
1046
+ t.beginPath(), t.moveTo(s, i), t.lineTo(u, b), t.stroke();
1047
+ }
1048
+ t.setLineDash([]);
1049
+ }
1050
+ if (!e || e.show === !1) return;
1051
+ const c = ((d = e.labelStyle) == null ? void 0 : d.distance) !== void 0 ? e.labelStyle.distance : 27.2;
1052
+ e.data.forEach((f, g) => {
1053
+ const p = f.labelStyle || {}, m = p.distance !== void 0 ? p.distance : c, y = typeof m == "string" && m.endsWith("%") ? parseFloat(m) / 100 * n : parseFloat(m) * 1, [u, b] = W.canvasVertex(g, s, i, n + y), w = p.fontStyle || "normal", S = p.fontWeight || "bold", x = Math.round((p.fontSize || o.gasLabelSize || 14) * 1);
1054
+ t.font = `${w} ${S} ${x}px ${r}`, t.fillStyle = p.color || o.gasLabelColor || "#fff", t.textAlign = "center", t.textBaseline = "middle", t.shadowColor = o.gasLabelShadow, t.shadowBlur = 7, t.fillText(f.name, u, b), t.shadowBlur = 0;
1055
+ });
1056
+ }
1057
+ }
1058
+ function wt(v) {
1059
+ const t = v.trim().toLowerCase();
1060
+ if (t.startsWith("#")) {
1061
+ let o = t.slice(1);
1062
+ o.length === 3 && (o = o[0] + o[0] + o[1] + o[1] + o[2] + o[2]);
1063
+ const s = parseInt(o.substring(0, 2), 16), i = parseInt(o.substring(2, 4), 16), n = parseInt(o.substring(4, 6), 16), l = o.length === 8 ? parseInt(o.substring(6, 8), 16) / 255 : 1;
1064
+ return [s, i, n, l];
1065
+ }
1066
+ const e = t.match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\)/);
1067
+ return e ? [
1068
+ parseInt(e[1], 10),
1069
+ parseInt(e[2], 10),
1070
+ parseInt(e[3], 10),
1071
+ e[4] !== void 0 ? parseFloat(e[4]) : 1
1072
+ ] : t === "transparent" ? [0, 0, 0, 0] : [255, 255, 255, 1];
1073
+ }
1074
+ function Ft(v, t, e) {
1075
+ const [o, s, i, n] = wt(v), [l, h, a, r] = wt(t), c = Math.round(o + (l - o) * e), d = Math.round(s + (h - s) * e), f = Math.round(i + (a - i) * e), g = n + (r - n) * e;
1076
+ return `rgba(${c},${d},${f},${g})`;
1077
+ }
1078
+ class Yt {
1079
+ /**
1080
+ * 绘制数据点及其辉光、标签
1081
+ */
1082
+ static draw(t, e, o, s, i, n, l, h, a, r) {
1083
+ if (!e || !e.data || !Array.isArray(e.data)) return [];
1084
+ const c = 1, d = o.fontFamily || "Rajdhani, sans-serif", f = [], g = e.data;
1085
+ if (!g || g.length === 0) return [];
1086
+ const p = W.resolveData(g, h);
1087
+ if (!p) return [];
1088
+ const m = e.name, y = e.shape || "circle", u = e.color || "#409eff";
1089
+ let b = e.size !== void 0 ? e.size : 5;
1090
+ const [w, S] = W.polyToCanvas(p, s, i, n), x = pt.diagnose(p, a, s, i, n), [C, z] = W.ratioToDoc(p);
1091
+ r && r.series === e && (b *= 1.5);
1092
+ const A = e.itemStyle || {}, Y = A.borderColor || "#fff", P = A.borderWidth !== void 0 ? A.borderWidth : 1, k = A.opacity !== void 0 ? A.opacity : 1, M = e.textStyle || {}, L = M.show !== void 0 ? M.show : !0, Q = M.color || u, N = M.fontSize !== void 0 ? M.fontSize : 12, st = M.fontWeight || "normal", Z = M.position || "top", tt = M.offset || [0, 0], H = e.glowStyle || {}, dt = H.show !== void 0 ? H.show : !1, X = H.colors, I = H.blur !== void 0 ? H.blur : 15, R = H.startColor || u, U = H.endColor || "transparent", V = H.count !== void 0 ? H.count : 3, Mt = H.glowDistance !== void 0 ? H.glowDistance : 2;
1093
+ if (t.save(), t.globalAlpha = k, dt) {
1094
+ t.shadowColor = X ? X[0] : R, t.shadowBlur = I;
1095
+ let O = [], j = V;
1096
+ if (Array.isArray(X) && X.length > 0)
1097
+ O = X, j = O.length;
1098
+ else
1099
+ for (let B = 0; B < j; B++) {
1100
+ const q = j > 1 ? B / (j - 1) : 0;
1101
+ O.push(Ft(R, U, q));
1102
+ }
1103
+ for (let B = j - 1; B >= 0; B--) {
1104
+ const q = O[B];
1105
+ t.save(), t.fillStyle = q, t.beginPath(), nt(t, w, S, y, b, c, (B + 1) * Mt), t.fill(), t.restore();
1106
+ }
1107
+ }
1108
+ if (t.beginPath(), nt(t, w, S, y, b, c, 0), y === "ring" ? (t.strokeStyle = u, t.lineWidth = P * c, t.stroke()) : (t.fillStyle = u, t.fill(), P > 0 && (t.strokeStyle = Y, t.lineWidth = P * c, t.stroke())), t.restore(), L && m) {
1109
+ t.save(), t.globalAlpha = k, t.font = `${st} ${Math.round(N * c)}px ${d}`, t.fillStyle = Q;
1110
+ let O = "center", j = "middle", B = w + tt[0] * c, q = S + tt[1] * c, et = 6 * c;
1111
+ y === "circle" || y === "ring" || y === "star" || y === "triangle" ? et += b * c : y === "square" && (et += b * c / 2), Z === "top" ? (O = "center", j = "bottom", q -= et) : Z === "bottom" ? (O = "center", j = "top", q += et) : Z === "left" ? (O = "right", j = "middle", B -= et) : Z === "right" ? (O = "left", j = "middle", B += et) : Z === "center" && (O = "center", j = "middle"), t.textAlign = O, t.textBaseline = j, t.fillText(m, B, q), t.restore();
1112
+ }
1113
+ return f.push({
1114
+ ratio: p,
1115
+ zone: x,
1116
+ docX: C,
1117
+ docY: z,
1118
+ rawData: g,
1119
+ name: m,
1120
+ series: e
1121
+ }), f;
1122
+ }
1123
+ }
1124
+ const G = class G {
1125
+ constructor(t, e = {}) {
1126
+ if (this._el = typeof t == "string" ? document.getElementById(t) : t, !this._el) throw new Error(`DuvalPentagon: container not found — "${t}"`);
1127
+ this._theme = rt.resolve(e.theme || G.DEFAULTS.theme), this._opt = E(E(E({}, G.DEFAULTS), this._theme), e), this._normalizeOptions(), this._bus = new At(), this._zoom = new ut(this._opt.zoom), this._canvas = document.createElement("canvas"), this._ctx = this._canvas.getContext("2d"), Object.assign(this._canvas.style, { display: "block", width: "100%", height: "100%" }), this._el.appendChild(this._canvas), this._tooltipRenderer = new yt(this._el, this._theme), this._hoverRatio = null, this._hoverZone = null, this._hoverPoint = null, this._bindEvents(), this._observeResize(), this._syncCanvas(), this._renderFull();
1128
+ }
1129
+ _normalizeOptions() {
1130
+ if (this._opt.showTooltip !== void 0 && (this._opt.tooltip || (this._opt.tooltip = {}), this._opt.tooltip.show = this._opt.showTooltip), this._opt.tooltipTrigger !== void 0 && (this._opt.tooltip || (this._opt.tooltip = {}), this._opt.tooltipTrigger === "point" ? (this._opt.tooltip.showDiagnostic = !1, this._opt.tooltip.showPoint = !0) : this._opt.tooltipTrigger === "zone" && (this._opt.tooltip.showDiagnostic = !0, this._opt.tooltip.showPoint = !0)), this._opt.vertex.data || (this._opt.vertex.data = ["H2", "C2H2", "C2H4", "CH4", "C2H6"]), !Array.isArray(this._opt.vertex.data) || this._opt.vertex.data.length !== 5)
1131
+ throw new Error("DuvalPentagon: vertex.data must be an array of exactly 5 elements.");
1132
+ const t = this._opt.vertex.labelStyle || {};
1133
+ this._opt.vertex.data = this._opt.vertex.data.map((e) => {
1134
+ if (typeof e == "string")
1135
+ return {
1136
+ name: e,
1137
+ labelStyle: { ...t }
1138
+ };
1139
+ if (e && typeof e == "object") {
1140
+ if (!e.name)
1141
+ throw new Error("DuvalPentagon: each vertex object in vertex.data must have a 'name' property.");
1142
+ return {
1143
+ name: e.name,
1144
+ labelStyle: E({ ...t }, e.labelStyle || {})
1145
+ };
1146
+ } else
1147
+ throw new Error("DuvalPentagon: vertex.data elements must be either strings or objects with a 'name' property.");
1148
+ }), this._opt.gasOrder = this._opt.vertex.data.map((e) => e.name), this._opt.zone ? Array.isArray(this._opt.zone) ? this._opt.zone = { data: this._opt.zone } : typeof this._opt.zone == "object" && !this._opt.zone.data && (this._opt.zone.data = G.DEFAULT_ZONES) : this._opt.zone = { data: G.DEFAULT_ZONES };
1149
+ }
1150
+ /* 公开 API ─ */
1151
+ /**
1152
+ * 深度合并配置并重绘图表
1153
+ * @param {object} opt - 需要合并的配置项
1154
+ * @returns {DuvalPentagon} - 当前实例,支持链式调用
1155
+ */
1156
+ setOption(t) {
1157
+ return t.theme !== void 0 && (this._theme = rt.resolve(t.theme), this._tooltipRenderer.updateTheme(this._theme), this._opt = E(E(E({}, G.DEFAULTS), this._theme), this._opt)), E(this._opt, t), this._normalizeOptions(), this._syncCanvas(), this._render(), this;
1158
+ }
1159
+ /**
1160
+ * 替换全部数据点并重绘
1161
+ * @param {object|object[]} series - 单个或多个数据点系列
1162
+ * @returns {DuvalPentagon} - 当前实例,支持链式调用
1163
+ */
1164
+ setSeries(t) {
1165
+ return this._opt.series = Array.isArray(t) ? t : [t], this._renderFull(), this;
1166
+ }
1167
+ zoomReset() {
1168
+ return this._zoom.reset(), this._renderFull(), this;
1169
+ }
1170
+ on(t, e) {
1171
+ return this._bus.on(t, e), this;
1172
+ }
1173
+ off(t, e) {
1174
+ return this._bus.off(t, e), this;
1175
+ }
1176
+ dispose() {
1177
+ var e, o;
1178
+ (e = this._ro) == null || e.disconnect(), this._tooltipRenderer.dispose();
1179
+ const t = this._canvas;
1180
+ t && (t.removeEventListener("wheel", this._onWheel), t.removeEventListener("mousedown", this._onDown), t.removeEventListener("mousemove", this._onMove), t.removeEventListener("mouseleave", this._onLeave), t.removeEventListener("dblclick", this._onDbl), (o = t.parentNode) == null || o.removeChild(t)), window.removeEventListener("mouseup", this._onUp), this._bus.dispose();
1181
+ }
1182
+ /* 内部:事件绑定 */
1183
+ _bindEvents() {
1184
+ const t = this._canvas;
1185
+ this._onWheel = (e) => {
1186
+ e.preventDefault();
1187
+ const o = t.getBoundingClientRect(), s = (e.clientX - o.left) * (this._cssW / o.width), i = (e.clientY - o.top) * (this._cssH / o.height);
1188
+ this._zoom.onWheel(e.deltaY, s, i), this._bus.emit("zoom", this._zoom.state), this._renderFull();
1189
+ }, this._onDown = (e) => {
1190
+ e.button === 0 && (this._zoom.startDrag(e.clientX, e.clientY), t.style.cursor = "grabbing");
1191
+ }, this._onMove = (e) => {
1192
+ const o = t.getBoundingClientRect(), s = this._cssW / o.width;
1193
+ if (this._zoom.moveDrag(e.clientX, e.clientY, s)) {
1194
+ this._renderFull();
1195
+ return;
1196
+ }
1197
+ const i = ((e.clientX - o.left) * s - this._zoom.panX) / this._zoom.zoom, n = ((e.clientY - o.top) * s - this._zoom.panY) / this._zoom.zoom, { cx: l, cy: h, R: a, S: r } = this._dims();
1198
+ let c = null, d = 1 / 0;
1199
+ if (this._drawnResults)
1200
+ for (const p of this._drawnResults) {
1201
+ const [m, y] = W.polyToCanvas(p.ratio, l, h, a), u = p.series.size || Math.max(5, r * 0.013), b = Math.hypot(m - i, y - n);
1202
+ b < Math.max(u * 1.5, 12) && b < d && (d = b, c = p);
1203
+ }
1204
+ const f = this._opt.tooltip || {}, g = f.show !== !1;
1205
+ if (c && g && f.showPoint !== !1)
1206
+ t.style.cursor = "pointer", this._hoverPoint = c, this._hoverRatio = c.ratio, this._hoverZone = c.zone, this._bus.emit("hover", {
1207
+ ratio: c.ratio,
1208
+ zone: c.zone,
1209
+ docX: c.docX,
1210
+ docY: c.docY,
1211
+ point: c.series
1212
+ });
1213
+ else {
1214
+ t.style.cursor = "default", this._hoverPoint = null;
1215
+ const p = W.canvasToRatio(i, n, l, h, a);
1216
+ if (p && g && f.showDiagnostic !== !1) {
1217
+ this._hoverRatio = p, this._hoverZone = pt.diagnose(p, this._opt.zone, l, h, a);
1218
+ const [m, y] = W.ratioToDoc(p);
1219
+ this._bus.emit("hover", { ratio: p, zone: this._hoverZone, docX: m, docY: y });
1220
+ } else
1221
+ this._hoverRatio = null, this._hoverZone = null, this._bus.emit("hover", null);
1222
+ }
1223
+ this._renderFull();
1224
+ }, this._onUp = () => {
1225
+ this._zoom.endDrag() && (t.style.cursor = this._hoverPoint ? "pointer" : "default", this._bus.emit("zoom", this._zoom.state));
1226
+ }, this._onLeave = () => {
1227
+ this._hoverRatio = null, this._hoverZone = null, this._hoverPoint = null, this._bus.emit("hover", null), this._renderFull();
1228
+ }, this._onDbl = () => {
1229
+ this.zoomReset(), this._bus.emit("zoom", this._zoom.state);
1230
+ }, t.addEventListener("wheel", this._onWheel, { passive: !1 }), t.addEventListener("mousedown", this._onDown), t.addEventListener("mousemove", this._onMove), t.addEventListener("mouseleave", this._onLeave), t.addEventListener("dblclick", this._onDbl), window.addEventListener("mouseup", this._onUp), t.style.cursor = "default";
1231
+ }
1232
+ _observeResize() {
1233
+ typeof ResizeObserver > "u" || (this._ro = new ResizeObserver(() => {
1234
+ this._syncCanvas(), this._renderFull();
1235
+ }), this._ro.observe(this._el));
1236
+ }
1237
+ _syncCanvas() {
1238
+ const t = window.devicePixelRatio || 1, e = this._el.clientWidth || 300, o = this._el.clientHeight || 300;
1239
+ this._cssW = e, this._cssH = o, this._canvas.width = Math.round(e * t), this._canvas.height = Math.round(o * t);
1240
+ }
1241
+ _dims() {
1242
+ var a;
1243
+ const t = this._cssW, e = this._cssH, o = ((a = this._opt) == null ? void 0 : a.grid) || {};
1244
+ if (!(o.left !== void 0 || o.right !== void 0 || o.top !== void 0 || o.bottom !== void 0)) {
1245
+ const r = Math.min(t, e);
1246
+ return { W: t, H: e, S: r, cx: t / 2, cy: e / 2, R: r * 0.385 };
1247
+ }
1248
+ const i = ct(t, e, o, 0), l = Math.min(i.availW, i.availH) / 2, h = l / 0.385;
1249
+ return { W: t, H: e, S: h, cx: i.cx, cy: i.cy, R: l };
1250
+ }
1251
+ _render() {
1252
+ this._hoverRatio = null, this._hoverZone = null, this._hoverPoint = null, this._renderFull();
1253
+ }
1254
+ /**
1255
+ * 核心渲染方法,绘制所有可见元素
1256
+ * @private
1257
+ */
1258
+ _renderFull() {
1259
+ var y;
1260
+ const t = this._ctx;
1261
+ if (!t) return;
1262
+ const e = window.devicePixelRatio || 1, { W: o, H: s, S: i, cx: n, cy: l, R: h } = this._dims(), a = this._theme, r = this._opt.gasOrder, c = this._opt.zone, d = this._opt.vertex;
1263
+ t.setTransform(e, 0, 0, e, 0, 0), t.clearRect(0, 0, o, s);
1264
+ const f = this._opt.backgroundColor || a.backgroundColor || "transparent";
1265
+ f !== "transparent" && (t.fillStyle = f, t.fillRect(0, 0, o, s)), t.save(), this._zoom.applyTransform(t), pt.draw(t, c, a, n, l, h, i), Xt.draw(t, d, a, n, l, h, i, this._opt.grid);
1266
+ const g = [];
1267
+ for (const u of this._opt.series || []) {
1268
+ const b = Yt.draw(t, u, a, n, l, h, i, r, c, this._hoverPoint);
1269
+ Array.isArray(b) && b.forEach((w) => {
1270
+ g.push({ series: u, ...w });
1271
+ });
1272
+ }
1273
+ this._drawnResults = g;
1274
+ const p = this._opt.tooltip || {};
1275
+ if (p.show !== !1 && this._hoverRatio) {
1276
+ let u = 0, b = 0;
1277
+ (this._hoverPoint || p.showDiagnostic !== !1) && ([u, b] = W.polyToCanvas(this._hoverRatio, n, l, h));
1278
+ const w = u * this._zoom.zoom + this._zoom.panX, S = b * this._zoom.zoom + this._zoom.panY;
1279
+ let x = "";
1280
+ typeof p.formatter == "function" ? x = p.formatter({
1281
+ ratio: this._hoverRatio,
1282
+ zone: this._hoverZone,
1283
+ point: (y = this._hoverPoint) == null ? void 0 : y.series,
1284
+ gasOrder: r
1285
+ }) : x = this._defaultTooltipHTML(this._hoverRatio, this._hoverZone, a, r, this._hoverPoint), this._tooltipRenderer.show(x, w, S, p, a, this._hoverZone);
1286
+ } else
1287
+ this._tooltipRenderer.hide();
1288
+ t.restore(), g.length > 0 && this._bus.emit("diagnose", g);
1289
+ }
1290
+ _defaultTooltipHTML(t, e, o, s, i) {
1291
+ var d;
1292
+ const n = ((d = this._opt.vertex) == null ? void 0 : d.data) || [], l = i == null ? void 0 : i.rawData;
1293
+ let h = "";
1294
+ i && i.name && (h = `<div style="font-size:14px; font-weight:bold; margin-bottom:4px; color:#fff;">${i.name}</div>`);
1295
+ const a = e ? `${e.name} ${e.title}` : "Outside", r = e ? e.color : "#fff";
1296
+ let c = `
1297
+ ${h}
1298
+ <div style="color:${r}; font-size:13px; font-weight:bold; padding-bottom:8px; margin-bottom:8px; border-bottom:1px solid rgba(255,255,255,0.07);">
1299
+ ${a}
1300
+ </div>
1301
+ `;
1302
+ return s.forEach((f, g) => {
1303
+ var y, u, b, w;
1304
+ const p = ((u = (y = n[g]) == null ? void 0 : y.labelStyle) == null ? void 0 : u.color) || ((w = (b = o.vertex) == null ? void 0 : b.labelStyle) == null ? void 0 : w.color) || "#fff";
1305
+ let m = "-";
1306
+ if (l)
1307
+ if (Array.isArray(l)) {
1308
+ const S = l[g];
1309
+ if (S && typeof S == "object") {
1310
+ const x = l.find((C) => C.name === f);
1311
+ m = x && x.value !== void 0 ? x.value : "-";
1312
+ } else
1313
+ m = l[g] !== void 0 ? l[g] : "-";
1314
+ } else typeof l == "object" && (m = l[f] !== void 0 ? l[f] : "-");
1315
+ c += `
1316
+ <div style="display:flex; align-items:center; margin-bottom:6px; font-size:13px;">
1317
+ <span style="display:inline-block; width:8px; height:8px; border-radius:50%; background-color:${p}; margin-right:8px;"></span>
1318
+ <span style="color:#cbd5e1; flex-grow:1;">${f}</span>
1319
+ <span style="color:#fff; font-weight:bold; margin-left:20px;">${m}</span>
1320
+ </div>
1321
+ `;
1322
+ }), c;
1323
+ }
1324
+ };
1325
+ K(G, "DEFAULT_ZONES", it), K(G, "DEFAULTS", {
1326
+ theme: "dark",
1327
+ vertex: {
1328
+ show: !0,
1329
+ data: ["H2", "C2H2", "C2H4", "CH4", "C2H6"]
1330
+ },
1331
+ zone: null,
1332
+ series: [],
1333
+ grid: {
1334
+ show: !1
1335
+ },
1336
+ zoom: { min: 0.3, max: 6, step: 0.12 },
1337
+ tooltip: {
1338
+ show: !0,
1339
+ showDiagnostic: !1,
1340
+ showPoint: !0
1341
+ }
1342
+ });
1343
+ let vt = G;
1344
+ const at = Object.freeze({
1345
+ zone: { data: Pt },
1346
+ backgroundColor: "#050d1a",
1347
+ triFill: "rgba(8,20,50,0)",
1348
+ grid: {
1349
+ show: !0,
1350
+ steps: 10,
1351
+ majorEvery: 2,
1352
+ lineStyle: {
1353
+ color: "rgba(255,255,255,0)",
1354
+ width: 1,
1355
+ type: "solid"
1356
+ },
1357
+ majorLineStyle: {
1358
+ color: "rgba(255,255,255,0)",
1359
+ width: 1,
1360
+ type: "solid"
1361
+ },
1362
+ labelStyle: {
1363
+ color: "rgba(200,220,255,0.8)",
1364
+ fontSize: 12,
1365
+ fontWeight: "normal"
1366
+ }
1367
+ },
1368
+ side: {
1369
+ show: !0,
1370
+ data: ["CH4", "C2H2", "C2H4"],
1371
+ labelStyle: {
1372
+ color: "#00e5ff",
1373
+ fontSize: 14,
1374
+ fontWeight: "bold",
1375
+ offset: 40
1376
+ },
1377
+ tickStyle: {
1378
+ show: !0,
1379
+ color: "rgba(200,220,255)",
1380
+ fontSize: 14,
1381
+ offset: 15,
1382
+ length: 6,
1383
+ lineColor: "rgba(0,0,0,0.2)"
1384
+ },
1385
+ lineStyle: {
1386
+ color: "rgba(180,210,255,0.1)",
1387
+ width: 1.5,
1388
+ type: "solid"
1389
+ }
1390
+ },
1391
+ tooltip: {
1392
+ show: !0,
1393
+ backgroundColor: "rgba(5,13,26,0.95)",
1394
+ borderColor: "#00e5ff",
1395
+ padding: 10,
1396
+ textStyle: {
1397
+ color: "#c8d8e8",
1398
+ fontSize: 12
1399
+ }
1400
+ },
1401
+ pointStyle: {
1402
+ itemStyle: {
1403
+ shape: "circle",
1404
+ radius: 6,
1405
+ color: "#ff4081",
1406
+ borderWidth: 1.5,
1407
+ borderColor: "rgba(255,255,255,0.7)"
1408
+ },
1409
+ textStyle: {
1410
+ show: !0,
1411
+ fontSize: 12,
1412
+ color: "#00e5ff",
1413
+ position: "top"
1414
+ }
1415
+ }
1416
+ });
1417
+ class D {
1418
+ /** 计算等边三角形在给定视口下的顶点 */
1419
+ static computeTri(t) {
1420
+ const { availW: e, availH: o, cx: s, cy: i } = t, n = Math.max(0, Math.min(e, o / Math.sin(Math.PI / 3))), l = n * Math.sin(Math.PI / 3), h = s - n / 2, a = i - l / 2;
1421
+ return {
1422
+ top: { x: s, y: a },
1423
+ left: { x: h, y: a + l },
1424
+ right: { x: h + n, y: a + l }
1425
+ };
1426
+ }
1427
+ /** 三元坐标(a,b,c)转笛卡尔坐标(x,y) */
1428
+ static t2c(t, e, o, s) {
1429
+ const { top: i, left: n, right: l } = s;
1430
+ return {
1431
+ x: t * i.x + e * n.x + o * l.x,
1432
+ y: t * i.y + e * n.y + o * l.y
1433
+ };
1434
+ }
1435
+ /** 笛卡尔坐标(x,y)转三元坐标(a,b,c) */
1436
+ static c2t(t, e, o) {
1437
+ const { top: s, left: i, right: n } = o, l = (i.y - n.y) * (s.x - n.x) + (n.x - i.x) * (s.y - n.y), h = ((i.y - n.y) * (t - n.x) + (n.x - i.x) * (e - n.y)) / l, a = ((n.y - s.y) * (t - n.x) + (s.x - n.x) * (e - n.y)) / l;
1438
+ return { a: h, b: a, c: 1 - h - a };
1439
+ }
1440
+ /** 计算多边形像素面积 */
1441
+ static polyArea(t) {
1442
+ let e = 0;
1443
+ for (let o = 0, s = t.length; o < s; o++) {
1444
+ const i = (o + 1) % s;
1445
+ e += t[o].x * t[i].y - t[i].x * t[o].y;
1446
+ }
1447
+ return Math.abs(e) / 2;
1448
+ }
1449
+ /** 计算多边形质心 */
1450
+ static polyCentroid(t) {
1451
+ const e = t.length;
1452
+ let o = 0, s = 0, i = 0;
1453
+ for (let n = 0; n < e; n++) {
1454
+ const l = (n + 1) % e, h = t[n].x * t[l].y - t[l].x * t[n].y;
1455
+ o += h, s += (t[n].x + t[l].x) * h, i += (t[n].y + t[l].y) * h;
1456
+ }
1457
+ return o /= 2, { x: s / (6 * o), y: i / (6 * o) };
1458
+ }
1459
+ /**
1460
+ * 解析并归一化数据点 (支持对象数组或原始数值数组)
1461
+ * 返回 [a, b, c] 比例数组,保证 a+b+c = 1
1462
+ */
1463
+ static resolveData(t, e) {
1464
+ let o = null;
1465
+ if (Array.isArray(t) ? t.length >= 3 && (typeof t[0] == "object" && t[0] !== null ? e ? o = e.map((h) => {
1466
+ const a = t.find((r) => r && r.name === h);
1467
+ return a ? a.value : 0;
1468
+ }) : o = [t[0].value, t[1].value, t[2].value] : o = [t[0], t[1], t[2]]) : t && t.value && Array.isArray(t.value) && t.value.length >= 3 && (o = [t.value[0], t.value[1], t.value[2]]), !o || o.some((h) => typeof h != "number" || isNaN(h))) return null;
1469
+ const [s, i, n] = o.map((h) => Math.max(0, h || 0)), l = s + i + n;
1470
+ return l <= 1e-9 ? [0.3333, 0.3333, 0.3333] : [s / l, i / l, n / l];
1471
+ }
1472
+ }
1473
+ class Rt {
1474
+ constructor(t) {
1475
+ this.ctx = t;
1476
+ }
1477
+ /** 全量渲染入口 */
1478
+ render(t) {
1479
+ const e = this.ctx, { W: o, H: s, dpr: i, scale: n, tx: l, ty: h, option: a, tri: r, zones: c, hoveredPoint: d } = t;
1480
+ e.setTransform(1, 0, 0, 1, 0, 0), e.clearRect(0, 0, o * i, s * i), e.fillStyle = a.backgroundColor, e.fillRect(0, 0, o * i, s * i), e.setTransform(n * i, 0, 0, n * i, l * i, h * i), this.drawTriFill(r), this.drawZones(c, r, a), this.drawGrid(a, r), this.drawBorder(a, r), this.drawSideLabels(a, r), this.drawSeries(a, r, d), e.setTransform(1, 0, 0, 1, 0, 0);
1481
+ }
1482
+ drawTriFill(t) {
1483
+ const e = this.ctx, { top: o, left: s, right: i } = t;
1484
+ e.beginPath(), e.moveTo(o.x, o.y), e.lineTo(s.x, s.y), e.lineTo(i.x, i.y), e.closePath(), e.fillStyle = at.triFill, e.fill();
1485
+ }
1486
+ drawZones(t, e, o) {
1487
+ var r, c, d, f;
1488
+ const s = this.ctx, i = this.ctx.getTransform().a / (window.devicePixelRatio || 1);
1489
+ t.forEach((g) => {
1490
+ !g.points || !g.points.length || (s.beginPath(), g.points.forEach(([p, m, y], u) => {
1491
+ const b = D.t2c(p, m, y, e);
1492
+ u === 0 ? s.moveTo(b.x, b.y) : s.lineTo(b.x, b.y);
1493
+ }), s.closePath(), s.fillStyle = g.color || "transparent", s.fill());
1494
+ });
1495
+ const n = ((r = o.zone) == null ? void 0 : r.borderStyle) || {};
1496
+ if (t.forEach((g) => {
1497
+ const p = E(E({}, n), g.borderStyle || {});
1498
+ p.show === !1 || !g.points || !g.points.length || (s.beginPath(), g.points.forEach(([m, y, u], b) => {
1499
+ const w = D.t2c(m, y, u, e);
1500
+ b === 0 ? s.moveTo(w.x, w.y) : s.lineTo(w.x, w.y);
1501
+ }), s.closePath(), s.strokeStyle = p.color || g.borderColor || "rgba(255,255,255,0.2)", s.lineWidth = (p.width ?? p.stroke ?? g.borderWidth ?? 1) * i, p.type === "dashed" ? s.setLineDash([4, 4]) : p.type === "dotted" ? s.setLineDash([2, 4]) : s.setLineDash([]), s.stroke());
1502
+ }), s.setLineDash([]), !(o.showZoneLabel !== !1)) return;
1503
+ const h = ((d = (c = o.grid) == null ? void 0 : c.labelStyle) == null ? void 0 : d.fontFamily) || "Microsoft YaHei UI, monospace", a = ((f = o.zone) == null ? void 0 : f.labelStyle) || {};
1504
+ t.forEach((g) => {
1505
+ const p = E(E({}, a), g.labelStyle || {});
1506
+ if (p.show === !1 || !g.id) return;
1507
+ const m = g.labelPos;
1508
+ if (!m) return;
1509
+ const y = D.t2c(m.a, m.b, m.c, e), u = Math.round((p.fontSize || 11) * i), b = p.fontStyle || "bold";
1510
+ s.font = `${b} ${u}px ${h}`, s.textAlign = "center", s.textBaseline = "middle";
1511
+ const w = g.id, S = s.measureText(w).width, x = u;
1512
+ let C = y.x, z = y.y;
1513
+ if (p.backgroundColor && p.backgroundColor !== "transparent") {
1514
+ let _ = 4, A = 4;
1515
+ Array.isArray(p.padding) ? (A = p.padding[0], _ = p.padding[1] !== void 0 ? p.padding[1] : A) : typeof p.padding == "number" && (_ = A = p.padding), _ *= i, A *= i;
1516
+ const Y = (p.borderRadius || 3) * i, P = S + _ * 2, k = x + A * 2, M = C - P / 2, L = z - k / 2;
1517
+ s.fillStyle = p.backgroundColor, s.beginPath(), s.roundRect ? s.roundRect(M, L, P, k, Y) : s.rect(M, L, P, k), s.fill();
1518
+ }
1519
+ p.textShadow && p.textShadow !== "none" ? (s.shadowColor = p.textShadow, s.shadowBlur = 4) : (s.shadowColor = "transparent", s.shadowBlur = 0), s.fillStyle = p.color || g.labelColor || "#fff", s.fillText(w, C, z), s.shadowBlur = 0, s.shadowColor = "transparent";
1520
+ }), s.textBaseline = "alphabetic";
1521
+ }
1522
+ drawBadge(t, e, o, s, i) {
1523
+ const n = this.ctx, { badgePadding: l, badgeHeight: h, badgeRadius: a } = at.ZONE_VIS, r = o + l * 2, c = t - r / 2, d = e - h / 2;
1524
+ n.beginPath(), n.roundRect ? n.roundRect(c, d, r, h, a) : n.rect(c, d, r, h), n.fillStyle = i, n.fill();
1525
+ }
1526
+ drawArrow(t, e, o, s, i) {
1527
+ const n = this.ctx, l = o - t, h = s - e, a = Math.hypot(l, h);
1528
+ if (a < 1) return;
1529
+ const r = l / a, c = h / a, d = 7;
1530
+ n.beginPath(), n.moveTo(o, s), n.lineTo(o - r * d + c * d * 0.5, s - c * d - r * d * 0.5), n.lineTo(o - r * d - c * d * 0.5, s - c * d + r * d * 0.5), n.closePath(), n.fillStyle = i, n.fill();
1531
+ }
1532
+ drawGrid(t, e) {
1533
+ if (!t.grid || !t.grid.show) return;
1534
+ const o = this.ctx, s = t.grid, i = s.steps || 10, n = s.majorEvery || 2, l = s.lineStyle || { color: "rgba(255,255,255,0.1)", width: 1, type: "solid" }, h = s.majorLineStyle || { color: "rgba(255,255,255,0.2)", width: 1, type: "solid" }, a = this.ctx.getTransform().a / (window.devicePixelRatio || 1), r = (p, m, y) => {
1535
+ let u = m.x - p.x, b = m.y - p.y;
1536
+ const w = Math.hypot(u, b);
1537
+ u /= w, b /= w;
1538
+ const S = { x: -b, y: u }, x = { x: b, y: -u };
1539
+ return (y.x - p.x) * S.x + (y.y - p.y) * S.y > 0 ? S : x;
1540
+ }, { top: c, left: d, right: f } = e, g = {
1541
+ bottom: r(d, f, c),
1542
+ left: r(d, c, f),
1543
+ right: r(f, c, d)
1544
+ };
1545
+ for (let p = 1; p < i; p++) {
1546
+ const m = p / i, y = p % n === 0, u = y ? h : l;
1547
+ o.strokeStyle = u.color || "transparent", o.lineWidth = (u.width ?? 1) * a, u.type === "dashed" ? o.setLineDash([4, 4]) : u.type === "dotted" ? o.setLineDash([2, 4]) : o.setLineDash([]);
1548
+ const b = (w, S) => {
1549
+ o.beginPath(), o.moveTo(w.x, w.y), o.lineTo(S.x, S.y), o.stroke();
1550
+ };
1551
+ b(D.t2c(m, 1 - m, 0, e), D.t2c(m, 0, 1 - m, e)), b(D.t2c(1 - m, m, 0, e), D.t2c(0, m, 1 - m, e)), b(D.t2c(1 - m, 0, m, e), D.t2c(0, 1 - m, m, e)), this.drawSideTick(p, i, m, t, e, y, g);
1552
+ }
1553
+ }
1554
+ drawSideTick(t, e, o, s, i, n, l) {
1555
+ const a = (s.side || {}).tickStyle || {};
1556
+ if (a.show === !1) return;
1557
+ const r = this.ctx, c = Math.round(t * 100 / e);
1558
+ r.textAlign = "center", r.textBaseline = "middle";
1559
+ const d = a.length || 6, f = a.lineColor || "rgba(0,0,0,0.2)", g = a.color || "rgba(200,220,255)", p = a.offset !== void 0 ? a.offset : 15, m = a.fontFamily || "Microsoft YaHei UI, sans-serif", y = a.fontSize || 14, b = `${a.fontWeight || "normal"} ${y}px ${m}`, w = (z, _, A) => {
1560
+ r.beginPath(), r.moveTo(z.x, z.y), r.lineTo(z.x + _ * d, z.y + A * d), r.strokeStyle = f, r.lineWidth = 1.5, r.stroke();
1561
+ }, S = D.t2c(o, 1 - o, 0, i);
1562
+ w(S, l.left.x, l.left.y), n && (r.fillStyle = g, r.font = b, r.save(), r.translate(S.x - p, S.y - 8), r.rotate(-Math.PI / 3), r.fillText(c + "", 0, 0), r.restore());
1563
+ const x = D.t2c(1 - o, 0, o, i);
1564
+ w(x, l.right.x, l.right.y), n && (r.fillStyle = g, r.font = b, r.save(), r.translate(x.x + p, x.y - 8), r.rotate(Math.PI / 3), r.fillText(c + "", 0, 0), r.restore());
1565
+ const C = D.t2c(0, o, 1 - o, i);
1566
+ w(C, l.bottom.x, l.bottom.y), n && (r.fillStyle = g, r.font = b, r.fillText(c + "", C.x, C.y + p));
1567
+ }
1568
+ drawBorder(t, e) {
1569
+ const o = this.ctx, { top: s, left: i, right: n } = e, h = (t.side || {}).lineStyle || { color: "rgba(180,210,255,0.1)", width: 1.5, type: "solid" };
1570
+ [
1571
+ { f: s, t: i },
1572
+ { f: s, t: n },
1573
+ { f: i, t: n }
1574
+ ].forEach(({ f: r, t: c }) => {
1575
+ o.beginPath(), o.moveTo(r.x, r.y), o.lineTo(c.x, c.y), o.strokeStyle = h.color || "transparent", o.lineWidth = h.width || 1, h.type === "dashed" ? o.setLineDash([4, 4]) : h.type === "dotted" ? o.setLineDash([2, 4]) : o.setLineDash([]), o.stroke();
1576
+ }), o.setLineDash([]);
1577
+ }
1578
+ drawSideLabels(t, e) {
1579
+ var C;
1580
+ if (((C = t.side) == null ? void 0 : C.show) === !1) return;
1581
+ const o = this.ctx, { top: s, left: i, right: n } = e, l = t.side || {}, h = l.data || ["A", "B", "C"], a = l.labelStyle || {}, r = a.fontFamily || "Microsoft YaHei UI, sans-serif", c = a.fontSize || 14, d = a.fontWeight || "bold", f = a.color || "#00e5ff", g = a.offset !== void 0 ? a.offset : 40;
1582
+ o.textBaseline = "middle", o.textAlign = "center", o.fillStyle = f, o.font = `${d} ${c}px ${r}`;
1583
+ const p = { x: (s.x + i.x) / 2, y: (s.y + i.y) / 2 }, m = i.x - s.x, y = i.y - s.y, u = Math.hypot(m, y);
1584
+ o.save(), o.translate(p.x + -y / u * g, p.y + m / u * g), o.rotate(Math.atan2(y, m) + Math.PI), o.fillText((h[1] || "B") + " (%)", 0, 0), o.restore();
1585
+ const b = { x: (s.x + n.x) / 2, y: (s.y + n.y) / 2 }, w = n.x - s.x, S = n.y - s.y, x = Math.hypot(w, S);
1586
+ o.save(), o.translate(b.x + S / x * g, b.y + -w / x * g), o.rotate(Math.atan2(S, w)), o.fillText((h[2] || "C") + " (%)", 0, 0), o.restore(), o.save(), o.translate((i.x + n.x) / 2, (i.y + n.y) / 2 + g), o.fillText((h[0] || "A") + " (%)", 0, 0), o.restore();
1587
+ }
1588
+ drawSeries(t, e, o) {
1589
+ var h;
1590
+ const s = this.ctx, i = this.ctx.getTransform().a / (window.devicePixelRatio || 1), n = "Microsoft YaHei UI, sans-serif", l = (h = t.side) == null ? void 0 : h.data;
1591
+ (t.series || []).forEach((a) => {
1592
+ const r = a.data;
1593
+ if (!r || r.length === 0) return;
1594
+ const c = a.name, d = D.resolveData(r, l);
1595
+ if (!d) return;
1596
+ const f = D.t2c(d[0], d[1], d[2], e), g = f.x, p = f.y, m = o && o.series === a, y = a.shape || "circle", u = a.color || "#409eff";
1597
+ let b = a.size !== void 0 ? a.size : 5;
1598
+ m && (b *= 1.5);
1599
+ const w = a.itemStyle || {}, S = w.borderColor || "#fff", x = w.borderWidth !== void 0 ? w.borderWidth : 1, C = w.opacity !== void 0 ? w.opacity : 1, z = a.textStyle || {}, _ = z.show !== void 0 ? z.show : !0, A = z.color || u, Y = z.fontSize !== void 0 ? z.fontSize : 12, P = z.fontWeight || "normal", k = z.position || "top", M = z.offset || [0, 0], L = a.glowStyle || {}, Q = L.show !== void 0 ? L.show : !1, N = L.colors, st = L.blur !== void 0 ? L.blur : 15, Z = L.startColor || u, tt = L.endColor || "transparent", H = L.count !== void 0 ? L.count : 3, dt = L.glowDistance !== void 0 ? L.glowDistance : 2;
1600
+ if (s.save(), s.globalAlpha = C, Q) {
1601
+ s.shadowColor = N ? N[0] : Z, s.shadowBlur = st;
1602
+ let X = [], I = H;
1603
+ if (Array.isArray(N) && N.length > 0)
1604
+ X = N, I = X.length;
1605
+ else
1606
+ for (let R = 0; R < I; R++) {
1607
+ const U = I > 1 ? R / (I - 1) : 0;
1608
+ X.push($t(Z, tt, U));
1609
+ }
1610
+ for (let R = I - 1; R >= 0; R--) {
1611
+ const U = X[R];
1612
+ s.save(), s.fillStyle = U, s.beginPath(), nt(s, g, p, y, b, i, (R + 1) * dt), s.fill(), s.restore();
1613
+ }
1614
+ }
1615
+ if (s.beginPath(), nt(s, g, p, y, b, i, 0), y === "ring" ? (s.strokeStyle = u, s.lineWidth = x * i, s.stroke()) : (s.fillStyle = u, s.fill(), x > 0 && (s.strokeStyle = S, s.lineWidth = x * i, s.stroke())), s.restore(), _ && c) {
1616
+ s.save(), s.globalAlpha = C, s.font = `${P} ${Math.round(Y * i)}px ${n}`, s.fillStyle = A;
1617
+ let X = "center", I = "middle", R = g + M[0] * i, U = p + M[1] * i, V = 6 * i;
1618
+ y === "circle" || y === "ring" || y === "star" || y === "triangle" ? V += b * i : y === "square" && (V += b * i / 2), k === "top" ? (X = "center", I = "bottom", U -= V) : k === "bottom" ? (X = "center", I = "top", U += V) : k === "left" ? (X = "right", I = "middle", R -= V) : k === "right" ? (X = "left", I = "middle", R += V) : k === "center" && (X = "center", I = "middle"), s.textAlign = X, s.textBaseline = I, s.fillText(c, R, U), s.restore();
1619
+ }
1620
+ });
1621
+ }
1622
+ }
1623
+ class Gt {
1624
+ constructor(t, e = {}) {
1625
+ this.initDOM(t), this.renderer = new Rt(this.ctx), this.state = {
1626
+ W: 0,
1627
+ H: 0,
1628
+ dpr: 1,
1629
+ scale: 1,
1630
+ tx: 0,
1631
+ ty: 0,
1632
+ option: {},
1633
+ tri: {},
1634
+ zones: [],
1635
+ hoveredPoint: null
1636
+ }, this._zoom = new ut(e.zoom), this.events = { click: null, viewChange: null, hover: null }, this._initTooltip(), this.bindEvents(), this.ro = new ResizeObserver(() => this.fitCanvas()), this.ro.observe(this.container), this.fitCanvas(), Object.keys(e).length && this.setOption(e);
1637
+ }
1638
+ initDOM(t) {
1639
+ let e = typeof t == "string" ? document.getElementById(t) : t;
1640
+ if (!e) throw new Error("DuvalTriangle: container not found");
1641
+ this.container = e.tagName.toLowerCase() === "canvas" && e.parentElement || e, this.canvas = e.tagName.toLowerCase() === "canvas" ? e : document.createElement("canvas"), e.tagName.toLowerCase() !== "canvas" && (this.container.style.position = this.container.style.position || "relative", this.canvas.style.cssText = "display:block;width:100%;height:100%;cursor:default;", this.container.appendChild(this.canvas)), this.ctx = this.canvas.getContext("2d");
1642
+ }
1643
+ _initTooltip() {
1644
+ var e;
1645
+ const t = this.state.option.tooltip || at.tooltip;
1646
+ this._tooltip = new yt(this.container, {
1647
+ tooltipBg: t.backgroundColor || "rgba(5,13,26,0.95)",
1648
+ tooltipTextColor: ((e = t.textStyle) == null ? void 0 : e.color) || "#c8d8e8",
1649
+ tooltipPadding: t.padding || 10,
1650
+ zoneBorderColor: t.borderColor || "#00e5ff",
1651
+ fontFamily: "monospace"
1652
+ }), this._tooltip.el.style.whiteSpace = "nowrap", this._tooltip.el.style.lineHeight = "1.6";
1653
+ }
1654
+ setOption(t) {
1655
+ !this.state.option || !Object.keys(this.state.option).length ? this.state.option = E(E({}, at), t) : E(this.state.option, t), this._normalizeOptions(), this.computeGeometry(), this.buildZonePaths(), this.render();
1656
+ }
1657
+ _normalizeOptions() {
1658
+ const t = this.state.option;
1659
+ t.vertex && !t.side && (t.side = t.vertex, delete t.vertex), t.axes && Array.isArray(t.axes) && (t.side || (t.side = {}), t.side.data = t.axes.map((e) => typeof e == "object" ? e.name : e), delete t.axes), t.axisStyle && (t.side || (t.side = {}), E(t.side, t.axisStyle), delete t.axisStyle), t.side || (t.side = {}), (!t.side.data || t.side.data.length < 3) && (t.side.data = ["A", "B", "C"]), t.zones && Array.isArray(t.zones) && (t.zone || (t.zone = {}), t.zone.data = t.zones, delete t.zones), t.showTooltip !== void 0 && (t.tooltip || (t.tooltip = {}), t.tooltip.show = t.showTooltip);
1660
+ }
1661
+ computeGeometry() {
1662
+ const t = window.devicePixelRatio || 1;
1663
+ this.state.W = this.canvas.width / t, this.state.H = this.canvas.height / t, this.state.dpr = t;
1664
+ const e = this.state.option.padding ?? 45, o = this.state.option.grid || {}, s = ct(this.state.W, this.state.H, o, e);
1665
+ this.state.tri = D.computeTri(s);
1666
+ }
1667
+ buildZonePaths() {
1668
+ var s;
1669
+ const { option: t, tri: e } = this.state, o = ((s = t.zone) == null ? void 0 : s.data) || [];
1670
+ this.state.zones = o.map((i) => {
1671
+ const n = { ...i }, l = new Path2D();
1672
+ if (i.points.forEach(([h, a, r], c) => {
1673
+ const d = D.t2c(h, a, r, e);
1674
+ c === 0 ? l.moveTo(d.x, d.y) : l.lineTo(d.x, d.y);
1675
+ }), l.closePath(), n.path = l, i.labelAt)
1676
+ n.labelPos = { a: i.labelAt[0], b: i.labelAt[1], c: i.labelAt[2] };
1677
+ else {
1678
+ const h = i.points.map((c) => D.t2c(c[0], c[1], c[2], e)), a = D.polyCentroid(h), r = D.c2t(a.x, a.y, e);
1679
+ n.labelPos = { a: r.a, b: r.b, c: r.c };
1680
+ }
1681
+ return n;
1682
+ });
1683
+ }
1684
+ fitCanvas() {
1685
+ const t = window.devicePixelRatio || 1, e = this.container.clientWidth || 400, o = this.container.clientHeight || 400;
1686
+ this.canvas.width = Math.round(e * t), this.canvas.height = Math.round(o * t), this.canvas.style.width = e + "px", this.canvas.style.height = o + "px", this.state.scale = 1, this.state.tx = 0, this.state.ty = 0, this._zoom && this._zoom.reset(), Object.keys(this.state.option).length && (this.computeGeometry(), this.buildZonePaths(), this.render());
1687
+ }
1688
+ render() {
1689
+ this.state.scale = this._zoom.zoom, this.state.tx = this._zoom.panX, this.state.ty = this._zoom.panY, this.renderer.render(this.state);
1690
+ }
1691
+ bindEvents() {
1692
+ const t = this.canvas;
1693
+ this._onWheel = (e) => {
1694
+ e.preventDefault();
1695
+ const o = t.getBoundingClientRect(), s = (e.clientX - o.left) * (this.state.W / o.width), i = (e.clientY - o.top) * (this.state.H / o.height);
1696
+ this._zoom.onWheel(e.deltaY, s, i), typeof this.events.viewChange == "function" && this.events.viewChange(this._zoom.state), this.render();
1697
+ }, this._onDown = (e) => {
1698
+ if (e.button !== 0) return;
1699
+ const o = t.getBoundingClientRect(), s = this.state.W / o.width, i = this.state.H / o.height;
1700
+ this._zoom.startDrag(e.clientX * s, e.clientY * i), t.style.cursor = "grabbing";
1701
+ }, this._onMove = (e) => {
1702
+ const o = t.getBoundingClientRect(), s = this.state.W / o.width, i = this.state.H / o.height;
1703
+ if (this._zoom.moveDrag(e.clientX * s, e.clientY * i, 1)) {
1704
+ this.render();
1705
+ return;
1706
+ }
1707
+ this.handleMouseMove(e);
1708
+ }, this._onUp = () => {
1709
+ this._zoom.endDrag() && (t.style.cursor = this.state.hoveredPoint ? "pointer" : "default", typeof this.events.viewChange == "function" && this.events.viewChange(this._zoom.state));
1710
+ }, this._onLeave = () => {
1711
+ this.hideTooltip(), this.state.hoveredPoint = null, typeof this.events.hover == "function" && this.events.hover(null), this.render();
1712
+ }, this._onDbl = () => {
1713
+ this._zoom.reset(), typeof this.events.viewChange == "function" && this.events.viewChange(this._zoom.state), this.render();
1714
+ }, t.addEventListener("wheel", this._onWheel, { passive: !1 }), t.addEventListener("mousedown", this._onDown), t.addEventListener("mousemove", this._onMove), t.addEventListener("mouseleave", this._onLeave), t.addEventListener("dblclick", this._onDbl), t.addEventListener("click", this.handleClick.bind(this)), window.addEventListener("mouseup", this._onUp);
1715
+ }
1716
+ handleMouseMove(t) {
1717
+ var p;
1718
+ const e = this.canvas.getBoundingClientRect(), o = this.state.W / e.width, s = this.state.H / e.height, i = (t.clientX - e.left) * o, n = (t.clientY - e.top) * s, l = (i - this._zoom.panX) / this._zoom.zoom, h = (n - this._zoom.panY) / this._zoom.zoom, { a, b: r, c } = D.c2t(l, h, this.state.tri);
1719
+ if (a < -1e-7 || r < -1e-7 || c < -1e-7) {
1720
+ this.hideTooltip(), this.state.hoveredPoint !== null && (this.state.hoveredPoint = null, this.canvas.style.cursor = "default", this.render());
1721
+ return;
1722
+ }
1723
+ let d = null, f = 14;
1724
+ const g = (p = this.state.option.side) == null ? void 0 : p.data;
1725
+ (this.state.option.series || []).forEach((m) => {
1726
+ const y = m.data;
1727
+ if (!y) return;
1728
+ const u = D.resolveData(y, g);
1729
+ if (!u) return;
1730
+ const b = D.t2c(...u, this.state.tri), w = Math.hypot(b.x - l, b.y - h);
1731
+ w < f && (f = w, d = { series: m, raw: u });
1732
+ }), d !== this.state.hoveredPoint && (this.state.hoveredPoint = d, this.canvas.style.cursor = d ? "pointer" : "default", this.render()), this.showTooltip(l, h, a, r, c);
1733
+ }
1734
+ handleClick(t) {
1735
+ if (this._zoom.isDragging) return;
1736
+ const e = this.canvas.getBoundingClientRect(), o = this.state.W / e.width, s = this.state.H / e.height, i = (t.clientX - e.left) * o, n = (t.clientY - e.top) * s, l = (i - this._zoom.panX) / this._zoom.zoom, h = (n - this._zoom.panY) / this._zoom.zoom, { a, b: r, c } = D.c2t(l, h, this.state.tri);
1737
+ if (a < -1e-7 || r < -1e-7 || c < -1e-7) return;
1738
+ const d = this.getZoneAt(a, r, c);
1739
+ typeof this.events.click == "function" && this.events.click({ a, b: r, c, zone: d }), this.canvas.dispatchEvent(
1740
+ new CustomEvent("triangle:click", { detail: { a, b: r, c, zone: d }, bubbles: !0 })
1741
+ );
1742
+ }
1743
+ showTooltip(t, e, o, s, i) {
1744
+ var y, u;
1745
+ const n = this.state.option.tooltip || {};
1746
+ if (n.show === !1 || !this.state.hoveredPoint && n.showDiagnostic === !1) {
1747
+ this.hideTooltip();
1748
+ return;
1749
+ }
1750
+ const l = this.getZoneAt(o, s, i), a = (this.state.option.side || {}).data || ["A", "B", "C"];
1751
+ if (typeof this.events.hover == "function" && this.events.hover({
1752
+ ratio: [o, s, i],
1753
+ zone: l,
1754
+ point: ((y = this.state.hoveredPoint) == null ? void 0 : y.series) || null
1755
+ }), n.formatter) {
1756
+ const b = n.formatter({
1757
+ a: o,
1758
+ b: s,
1759
+ c: i,
1760
+ sNames: a,
1761
+ zone: l,
1762
+ point: (u = this.state.hoveredPoint) == null ? void 0 : u.series
1763
+ }), w = t * this._zoom.zoom + this._zoom.panX, S = e * this._zoom.zoom + this._zoom.panY;
1764
+ this._tooltip.show(b, w, S, n, {}, l);
1765
+ return;
1766
+ }
1767
+ const r = this._defaultTooltipHTML(o, s, i, a, l), c = t * this._zoom.zoom + this._zoom.panX, d = e * this._zoom.zoom + this._zoom.panY, f = this.canvas.getBoundingClientRect(), g = this.container.getBoundingClientRect(), p = f.left - g.left, m = f.top - g.top;
1768
+ this._tooltip.show(r, c + p, d + m, n, {}, l);
1769
+ }
1770
+ hideTooltip() {
1771
+ this._tooltip && this._tooltip.hide();
1772
+ }
1773
+ getZoneAt(t, e, o) {
1774
+ const s = D.t2c(t, e, o, this.state.tri), i = this.ctx;
1775
+ i.save(), i.setTransform(1, 0, 0, 1, 0, 0);
1776
+ const n = (this.state.zones || []).find((l) => l.path && i.isPointInPath(l.path, s.x, s.y));
1777
+ return i.restore(), n;
1778
+ }
1779
+ resetZoom() {
1780
+ this.state.scale = 1, this.state.tx = 0, this.state.ty = 0, this.render(), typeof this.events.viewChange == "function" && this.events.viewChange({ scale: this.state.scale, tx: this.state.tx, ty: this.state.ty });
1781
+ }
1782
+ dispose() {
1783
+ var t, e, o;
1784
+ (t = this.ro) == null || t.disconnect(), (e = this._tooltip) == null || e.dispose(), (o = this.canvas) == null || o.remove();
1785
+ }
1786
+ /**
1787
+ * 默认 tooltip HTML 生成
1788
+ * @private
1789
+ */
1790
+ _defaultTooltipHTML(t, e, o, s, i) {
1791
+ var m, y;
1792
+ const n = this.state.hoveredPoint, l = this.state.option.tooltip || {}, h = l.showPoint !== !1, a = l.showDiagnostic !== !1;
1793
+ let r = "";
1794
+ if (n && h) {
1795
+ let u = ((m = n.series) == null ? void 0 : m.name) || "";
1796
+ u && (r = `<div style="font-size:14px; font-weight:bold; margin-bottom:4px; color:#fff;">${u}</div>`);
1797
+ }
1798
+ const c = i ? `${i.name || i.id} ${i.desc || i.title || ""}` : "Outside", d = i && ((y = i.color) == null ? void 0 : y.replace(/[\d.]+\)$/, "1)")) || "#fff";
1799
+ let f = `
1800
+ ${r}
1801
+ ${c ? `<div style="color:${d}; font-size:13px; font-weight:bold; padding-bottom:8px; margin-bottom:8px; border-bottom:1px solid rgba(255,255,255,0.07);">${c}</div>` : ""}
1802
+ `;
1803
+ const g = ["#00e5ff", "#ff6b35", "#ffcc02"], p = n == null ? void 0 : n.item;
1804
+ return (h || !h && !a) && s.forEach((u, b) => {
1805
+ const w = g[b % 3];
1806
+ let S = "-";
1807
+ p && (Array.isArray(p) ? S = p[b] !== void 0 ? p[b] : "-" : typeof p == "object" && (p.value && Array.isArray(p.value) ? S = p.value[b] !== void 0 ? p.value[b] : "-" : p[u] !== void 0 && (S = p[u]))), f += `
1808
+ <div style="display:flex; align-items:center; margin-bottom:6px; font-size:13px;">
1809
+ <span style="display:inline-block; width:8px; height:8px; border-radius:50%; background-color:${w}; margin-right:8px;"></span>
1810
+ <span style="color:#cbd5e1; flex-grow:1;">${u}</span>
1811
+ <span style="color:#fff; font-weight:bold; margin-left:20px;">${S}</span>
1812
+ </div>
1813
+ `;
1814
+ }), f;
1815
+ }
1816
+ }
1817
+ function St(v) {
1818
+ const t = v.trim().toLowerCase();
1819
+ if (t.startsWith("#")) {
1820
+ let o = t.slice(1);
1821
+ o.length === 3 && (o = o[0] + o[0] + o[1] + o[1] + o[2] + o[2]);
1822
+ const s = parseInt(o.substring(0, 2), 16), i = parseInt(o.substring(2, 4), 16), n = parseInt(o.substring(4, 6), 16), l = o.length === 8 ? parseInt(o.substring(6, 8), 16) / 255 : 1;
1823
+ return [s, i, n, l];
1824
+ }
1825
+ const e = t.match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\)/);
1826
+ return e ? [
1827
+ parseInt(e[1], 10),
1828
+ parseInt(e[2], 10),
1829
+ parseInt(e[3], 10),
1830
+ e[4] !== void 0 ? parseFloat(e[4]) : 1
1831
+ ] : t === "transparent" ? [0, 0, 0, 0] : [255, 255, 255, 1];
1832
+ }
1833
+ function $t(v, t, e) {
1834
+ const [o, s, i, n] = St(v), [l, h, a, r] = St(t), c = Math.round(o + (l - o) * e), d = Math.round(s + (h - s) * e), f = Math.round(i + (a - i) * e), g = n + (r - n) * e;
1835
+ return `rgba(${c},${d},${f},${g})`;
1836
+ }
1837
+ const T = Object.freeze({
1838
+ // 故障区域定义(用于诊断逻辑与 3D/2D 绘图)
1839
+ ZONES: kt,
1840
+ // 坐标轴固定配置(X: C2H4/C2H6, Y: CH4/H2, Z: C2H2/C2H4)
1841
+ AXES: {
1842
+ x: { color: "#ff9a3c", label: "X (C₂H₄/C₂H₆)" },
1843
+ y: { color: "#4ac8ff", label: "Y (CH₄/H₂)" },
1844
+ z: { color: "#70e870", label: "Z (C₂H₂/C₂H₄)" }
1845
+ },
1846
+ // 绘图主题配置(深浅两色)
1847
+ THEMES: {
1848
+ dark: {
1849
+ wallFillAlpha: 0.05,
1850
+ // 立方体墙面填充透明度
1851
+ wallGridAlpha: "40",
1852
+ // 墙面网格线 Alpha (Hex)
1853
+ wallEdgeAlpha: "50",
1854
+ // 墙面边缘 Alpha (Hex)
1855
+ outerGrid: "rgba(100,150,220,0.10)",
1856
+ // 外部辅助网格
1857
+ plane2dGrid: "rgba(100,150,220,0.20)",
1858
+ // 2D 投影网格
1859
+ plane2dAxis: "rgba(120,160,220,0.50)",
1860
+ // 2D 投影轴线
1861
+ plane2dLabel: "rgba(150,180,220,0.60)",
1862
+ // 2D 区域文字标签颜色
1863
+ tickAlpha: "cc",
1864
+ // 刻度文字 Alpha
1865
+ pointStroke: "rgba(255,255,255,0.55)"
1866
+ // 样本点边缘描边
1867
+ },
1868
+ light: {
1869
+ wallFillAlpha: 0.06,
1870
+ wallGridAlpha: "28",
1871
+ wallEdgeAlpha: "55",
1872
+ outerGrid: "rgba(80,120,200,0.12)",
1873
+ plane2dGrid: "rgba(80,120,200,0.18)",
1874
+ plane2dAxis: "rgba(80,120,200,0.45)",
1875
+ plane2dLabel: "rgba(60,100,180,0.65)",
1876
+ tickAlpha: "bb",
1877
+ pointStroke: "rgba(0,0,0,0.25)"
1878
+ }
1879
+ },
1880
+ // 2D 投影平面视角配置
1881
+ PLANES: {
1882
+ xz: {
1883
+ hAxis: "x",
1884
+ vAxis: "z",
1885
+ hLabel: "X C₂H₄/C₂H₆(热故障)",
1886
+ vLabel: "Z C₂H₂/C₂H₄(高能放电)",
1887
+ bgColor: {
1888
+ dark: "rgba(180,120,60,0.06)",
1889
+ light: "rgba(180,100,40,0.05)"
1890
+ }
1891
+ },
1892
+ yz: {
1893
+ hAxis: "y",
1894
+ vAxis: "z",
1895
+ hLabel: "Y CH₄/H₂(低能放电)",
1896
+ vLabel: "Z C₂H₂/C₂H₄(高能放电)",
1897
+ bgColor: {
1898
+ dark: "rgba(60,160,180,0.06)",
1899
+ light: "rgba(40,140,160,0.05)"
1900
+ }
1901
+ },
1902
+ xy: {
1903
+ hAxis: "x",
1904
+ vAxis: "y",
1905
+ hLabel: "X C₂H₄/C₂H₆(热故障)",
1906
+ vLabel: "Y CH₄/H₂(低能放电)",
1907
+ bgColor: { dark: "rgba(60,100,200,0.06)", light: "rgba(40,80,180,0.05)" }
1908
+ }
1909
+ },
1910
+ TICKS: { vals: [0, 1 / 3, 2 / 3, 1], labels: ["0", "0.1", "1.0", "10"] },
1911
+ // 刻度映射
1912
+ CAM: { elev: -20, yaw: 115 },
1913
+ // 初始相机仰角、偏航角
1914
+ PROJ: { fov: 4, scaleK: 0.45, cx: 0.48, cy: 0.52 },
1915
+ // 投影及中心偏移参数
1916
+ PAD2D: { l: 70, r: 30, t: 50, b: 60 },
1917
+ // 2D 投影边距
1918
+ DRAG: {
1919
+ rotYSens: 0.45,
1920
+ rotXSens: 0.28,
1921
+ rotXMin: -70,
1922
+ rotXMax: 85,
1923
+ zoomMin: 0.3,
1924
+ zoomMax: 4,
1925
+ zoomIn: 1.08,
1926
+ zoomOut: 0.92
1927
+ },
1928
+ // 交互灵敏度与限制
1929
+ TWEEN: { step: 0.045 },
1930
+ // 视角切换动画步长
1931
+ POINT: {
1932
+ defaultSize: 7,
1933
+ defaultColor: "#aaaaaa",
1934
+ glowAlpha: 0.25,
1935
+ glowRadius: 2.2,
1936
+ hlOffset: 0.35
1937
+ },
1938
+ // 样本点视觉参数
1939
+ ZONE_VIS: { fillAlpha: 0.25, labelAlpha: 0.9 },
1940
+ // 3D 区域填充透明度(玻璃块效果)
1941
+ UNKNOWN: { name: "未分类(需综合判断)", color: "#888899" },
1942
+ // 无法匹配诊断规则时的默认项
1943
+ TEXT_STYLE: {
1944
+ fontSize: 14,
1945
+ fontFamily: "Segoe UI, Courier New",
1946
+ fontWeight: "normal"
1947
+ }
1948
+ });
1949
+ class F {
1950
+ /**
1951
+ * 将原始三比值数值转换为 0-1 的归一化坐标 (非等比例分段对数变换)
1952
+ * 变换规则:[0, 0.1]->[0, 1/3], [0.1, 1]->[1/3, 2/3], [1, 10]->[2/3, 1]
1953
+ */
1954
+ static realToU(t) {
1955
+ return t <= 0 ? 0 : t <= 0.1 ? t / 0.3 : t <= 1 ? 1 / 3 + (Math.log10(t) + 1) / 3 : t <= 10 ? 2 / 3 + Math.log10(t) / 3 : 1;
1956
+ }
1957
+ /** 将归一化单位值还原为原始比值 */
1958
+ static uToReal(t) {
1959
+ return t <= 0 ? 0 : t <= 1 / 3 ? t * 0.3 : t <= 2 / 3 ? Math.pow(10, (t - 1 / 3) * 3 - 1) : Math.pow(10, (t - 2 / 3) * 3);
1960
+ }
1961
+ /** 格式化数值输出 */
1962
+ static formatVal(t) {
1963
+ return t < 0.01 ? t.toFixed(4) : t.toFixed(3);
1964
+ }
1965
+ }
1966
+ class It {
1967
+ constructor(t, e, o, s = {}) {
1968
+ this.ctx = t, this.opts = s, this.layout = s.layout ?? "fill", this.resize(e, o), this.updateOptions(s);
1969
+ }
1970
+ /** 更新渲染配置 */
1971
+ updateOptions(t = {}) {
1972
+ this.opts = { ...this.opts, ...t }, (t.layout !== void 0 || t.grid !== void 0) && (t.layout !== void 0 && (this.layout = t.layout), this.resize(this.W, this.H));
1973
+ const e = this.opts.theme ?? "dark";
1974
+ this.theme = T.THEMES[e] ?? T.THEMES.dark, this.themeName = e, this.zone = this.processZones(this.opts.zone ?? T.ZONES);
1975
+ const o = {
1976
+ show: !0,
1977
+ fill: { show: !0, alpha: this.theme.wallFillAlpha, colors: { xy: void 0, xz: void 0, yz: void 0 } },
1978
+ grid: { show: !0, lineStyle: { lineWidth: 0.6, alpha: parseInt(this.theme.wallGridAlpha, 16) / 255, type: "solid" } },
1979
+ border: { show: !0, lineStyle: { lineWidth: 0.8, alpha: parseInt(this.theme.wallEdgeAlpha, 16) / 255, type: "solid" } }
1980
+ }, s = {
1981
+ show: !0,
1982
+ lineStyle: { lineWidth: 1.8, arrowSize: 9 },
1983
+ labelStyle: { show: !0, fontSize: 14, fontWeight: "bold", distance: 16 },
1984
+ tickLabelStyle: { show: !0, fontSize: 12, color: "rgba(255, 255, 255, 0.8)" },
1985
+ data: {
1986
+ x: { name: T.AXES.x.label, color: T.AXES.x.color },
1987
+ y: { name: T.AXES.y.label, color: T.AXES.y.color },
1988
+ z: { name: T.AXES.z.label, color: T.AXES.z.color }
1989
+ }
1990
+ }, i = {
1991
+ show: !0,
1992
+ fade3DAlpha: 0.03,
1993
+ grid: {
1994
+ show: !0,
1995
+ backgroundColor: void 0,
1996
+ lineStyle: { lineWidth: 0.5, alpha: 0.2, type: "solid" }
1997
+ },
1998
+ axis: {
1999
+ show: !0,
2000
+ lineStyle: { lineWidth: 1.5, alpha: 0.9 },
2001
+ labelStyle: { show: !0, fontSize: 13, distance: 25 },
2002
+ tickLabelStyle: { show: !0, fontSize: 11, distance: 8 }
2003
+ },
2004
+ zone: {
2005
+ show: !0,
2006
+ alpha: 0.45,
2007
+ borderStyle: { show: !0, lineWidth: 1.4 }
2008
+ }
2009
+ };
2010
+ this.opts.wall = E(o, this.opts.wall || {}), this.opts.axis = E(s, this.opts.axis || {}), this.opts.plane2D = E(i, this.opts.plane2D || {});
2011
+ }
2012
+ /** 预计算区域数据 */
2013
+ processZones(t) {
2014
+ let e = [], o = {};
2015
+ return Array.isArray(t) ? e = t : t && typeof t == "object" && Array.isArray(t.data) ? (e = t.data, o = t.labelStyle || {}) : e = T.ZONES, e.map((s) => {
2016
+ const [i, n, l] = ht(s.fill || "#ffffff"), h = s.labelStyle || o, a = h.color || s.fill;
2017
+ let r = [];
2018
+ h.fontWeight && r.push(h.fontWeight), h.fontSize && r.push(h.fontSize + "px"), h.fontFamily && r.push(h.fontFamily);
2019
+ const c = r.length > 0 ? r.join(" ") : null;
2020
+ let d = s.edgeColor || s.fill;
2021
+ return s.edgeAlpha !== void 0 && (d = _t(d, s.edgeAlpha)), {
2022
+ ...s,
2023
+ fillBase: `rgba(${i},${n},${l},`,
2024
+ edgeStr: d,
2025
+ x0: F.realToU(s.p1[0]),
2026
+ x1: F.realToU(s.p2[0]),
2027
+ y0: F.realToU(s.p1[1]),
2028
+ y1: F.realToU(s.p2[1]),
2029
+ z0: F.realToU(s.p1[2]),
2030
+ z1: F.realToU(s.p2[2]),
2031
+ labelColor: a,
2032
+ labelFontStr: c
2033
+ };
2034
+ });
2035
+ }
2036
+ /** 获取配置的字体样式 */
2037
+ getFont(t) {
2038
+ var l;
2039
+ const e = T.TEXT_STYLE, o = ((l = this.opts.textStyle) == null ? void 0 : l[t]) ?? this.opts.textStyle ?? {}, s = o.fontSize ?? e.fontSize, i = o.fontFamily ?? e.fontFamily;
2040
+ return `${o.fontWeight ?? (t === "axis" || t === "zone" ? "bold" : e.fontWeight)} ${s}px ${i}`;
2041
+ }
2042
+ /** 更新渲染器主题 */
2043
+ setTheme(t) {
2044
+ this.updateOptions({ theme: t });
2045
+ }
2046
+ /** 画布尺寸更新回调 */
2047
+ resize(t, e) {
2048
+ this.W = t, this.H = e;
2049
+ const o = this.opts.grid;
2050
+ if (o && (o.left !== void 0 || o.right !== void 0 || o.top !== void 0 || o.bottom !== void 0)) {
2051
+ const i = ct(t, e, o, 0);
2052
+ this.renderW = i.availW, this.renderH = i.availH, this.offsetX = i.left, this.offsetY = i.top;
2053
+ } else if (this.layout === "square") {
2054
+ const i = Math.min(t, e);
2055
+ this.renderW = i, this.renderH = i, this.offsetX = (t - i) / 2, this.offsetY = (e - i) / 2;
2056
+ } else
2057
+ this.renderW = t, this.renderH = e, this.offsetX = 0, this.offsetY = 0;
2058
+ this.CX = this.offsetX + this.renderW * T.PROJ.cx, this.CY = this.offsetY + this.renderH * T.PROJ.cy;
2059
+ }
2060
+ /**
2061
+ * 核心投影函数:将 0-1 坐标系的 3D 点映射为 2D 屏幕画布坐标
2062
+ * 逻辑:平移中心 -> 执行绕 X, Y 轴旋转矩阵 -> 应用视场角(FOV)进行透视缩放 -> 映射至屏幕中心
2063
+ */
2064
+ proj(t, e, o) {
2065
+ const s = t - 0.5, i = e - 0.5, n = o - 0.5, l = this.cam.rotX * Math.PI / 180, h = this.cam.rotY * Math.PI / 180, a = Math.cos(l), r = Math.sin(l), c = Math.cos(h), d = Math.sin(h), f = s * c + i * d, g = -s * d + i * c, p = n * a - g * r, m = n * r + g * a, y = Math.min(this.renderW, this.renderH) * T.PROJ.scaleK * this.cam.zoomFactor, u = T.PROJ.fov, b = m + u;
2066
+ return {
2067
+ x: this.CX + f / b * y * u,
2068
+ y: this.CY - p / b * y * u,
2069
+ depth: m
2070
+ };
2071
+ }
2072
+ /** 判断法向量是否背向相机 (Backface Culling) */
2073
+ isBackface(t, e, o) {
2074
+ const s = this.cam.rotX * Math.PI / 180, i = this.cam.rotY * Math.PI / 180, n = Math.cos(s), l = Math.sin(s), h = Math.cos(i), a = Math.sin(i), r = -t * a + e * h;
2075
+ return o * l + r * n > 0;
2076
+ }
2077
+ /**
2078
+ * 渲染主循环
2079
+ * @param {Object} cam 相机状态对象
2080
+ * @param {Array} points 样本点数组
2081
+ * @param {string} view 当前视图 ID ('3d', 'xz' 等)
2082
+ * @param {number} flat 扁平化程度 (0-1), 用于 3D 转换 2D 平面的视觉过度
2083
+ */
2084
+ draw(t, e, o, s) {
2085
+ var a;
2086
+ const i = this.ctx;
2087
+ i.clearRect(0, 0, this.W, this.H), this.cam = t;
2088
+ const n = ((a = this.opts.plane2D) == null ? void 0 : a.fade3DAlpha) ?? 0.03, l = 1 - s * (1 - n);
2089
+ i.globalAlpha = l, this.drawWalls(l), this.drawGrid(l), this.drawZones(l), this.drawAxes(l), this.drawTickLabels(l);
2090
+ const h = Array.isArray(e) ? e : [];
2091
+ [...h].sort(
2092
+ (r, c) => this.proj(F.realToU(r.position.x), F.realToU(r.position.y), F.realToU(r.position.z)).depth - this.proj(F.realToU(c.position.x), F.realToU(c.position.y), F.realToU(c.position.z)).depth
2093
+ ).forEach((r) => this.drawPoint3D(r, l)), i.globalAlpha = 1, s > 0 && this.opts.plane2D.show && this.draw2DOverlay(o, s, h);
2094
+ }
2095
+ // 基础绘制
2096
+ face(t, e, o) {
2097
+ const s = this.ctx, i = t.map((n) => this.proj(...n));
2098
+ s.beginPath(), s.moveTo(i[0].x, i[0].y);
2099
+ for (let n = 1; n < i.length; n++) s.lineTo(i[n].x, i[n].y);
2100
+ s.closePath(), e && (s.fillStyle = e, s.fill()), o && (s.strokeStyle = o, s.lineWidth = 0.8, s.stroke());
2101
+ }
2102
+ line(t, e) {
2103
+ const o = this.ctx;
2104
+ o.beginPath(), o.moveTo(t.x, t.y), o.lineTo(e.x, e.y), o.stroke();
2105
+ }
2106
+ box(t, e, o, s, i, n, l, h) {
2107
+ [
2108
+ { f: [[t, o, i], [e, o, i], [e, s, i], [t, s, i]], n: [0, 0, -1] },
2109
+ { f: [[t, o, n], [e, o, n], [e, s, n], [t, s, n]], n: [0, 0, 1] },
2110
+ { f: [[t, o, i], [e, o, i], [e, o, n], [t, o, n]], n: [0, -1, 0] },
2111
+ { f: [[t, s, i], [e, s, i], [e, s, n], [t, s, n]], n: [0, 1, 0] },
2112
+ { f: [[t, o, i], [t, s, i], [t, s, n], [t, o, n]], n: [-1, 0, 0] },
2113
+ { f: [[e, o, i], [e, s, i], [e, s, n], [e, o, n]], n: [1, 0, 0] }
2114
+ ].filter(({ n: r }) => !this.isBackface(r[0], r[1], r[2])).map(({ f: r }) => ({
2115
+ f: r,
2116
+ d: r.reduce((c, d) => c + this.proj(...d).depth, 0) / r.length
2117
+ })).sort((r, c) => r.d - c.d).forEach(({ f: r }) => this.face(r, l, h));
2118
+ }
2119
+ drawWalls(t = 1) {
2120
+ const e = this.ctx, o = this.opts.wall;
2121
+ if (!o.show) return;
2122
+ const s = this.opts.axis.data, i = T.TICKS.vals, n = [
2123
+ {
2124
+ // X-Z 面 (底层底面通常认为是 z=0 或 y=0)
2125
+ pts: [[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1]],
2126
+ color: o.fill.colors.xz || s.x.color,
2127
+ segs: (l) => [[this.proj(l, 0, 0), this.proj(l, 0, 1)], [this.proj(0, 0, l), this.proj(1, 0, l)]],
2128
+ gridColor: s.x.color
2129
+ },
2130
+ {
2131
+ // Y-Z 面
2132
+ pts: [[0, 0, 0], [0, 1, 0], [0, 1, 1], [0, 0, 1]],
2133
+ color: o.fill.colors.yz || s.y.color,
2134
+ segs: (l) => [[this.proj(0, l, 0), this.proj(0, l, 1)], [this.proj(0, 0, l), this.proj(0, 1, l)]],
2135
+ gridColor: s.y.color
2136
+ },
2137
+ {
2138
+ // X-Y 面
2139
+ pts: [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]],
2140
+ color: o.fill.colors.xy || s.z.color,
2141
+ segs: (l) => [[this.proj(l, 0, 0), this.proj(l, 1, 0)], [this.proj(0, l, 0), this.proj(1, l, 0)]],
2142
+ gridColor: s.z.color
2143
+ }
2144
+ ];
2145
+ o.fill.show && (e.globalAlpha = o.fill.alpha * t, n.forEach((l) => this.face(l.pts, l.color)), e.globalAlpha = t), o.grid.show && (e.lineWidth = o.grid.lineStyle.lineWidth, e.globalAlpha = o.grid.lineStyle.alpha * t, o.grid.lineStyle.type === "dashed" ? e.setLineDash([4, 4]) : o.grid.lineStyle.type === "dotted" ? e.setLineDash([2, 2]) : e.setLineDash([]), n.forEach(({ gridColor: l, segs: h }) => {
2146
+ e.strokeStyle = l, i.forEach((a) => h(a).forEach(([r, c]) => this.line(r, c)));
2147
+ }), e.setLineDash([]), e.globalAlpha = t), o.border.show && (e.lineWidth = o.border.lineStyle.lineWidth, e.globalAlpha = o.border.lineStyle.alpha * t, o.border.lineStyle.type === "dashed" ? e.setLineDash([4, 4]) : o.border.lineStyle.type === "dotted" ? e.setLineDash([2, 2]) : e.setLineDash([]), n.forEach(({ pts: l, gridColor: h }) => {
2148
+ e.strokeStyle = h, l.forEach((a, r) => this.line(this.proj(...a), this.proj(...l[(r + 1) % l.length])));
2149
+ }), e.setLineDash([]), e.globalAlpha = t);
2150
+ }
2151
+ drawGrid(t = 1) {
2152
+ const e = this.ctx;
2153
+ e.globalAlpha = t, e.strokeStyle = this.theme.outerGrid, e.lineWidth = 0.4, T.TICKS.vals.forEach((o) => {
2154
+ this.line(this.proj(1, o, 0), this.proj(1, o, 1)), this.line(this.proj(1, 0, o), this.proj(1, 1, o));
2155
+ });
2156
+ }
2157
+ drawZones(t) {
2158
+ const e = this.ctx, o = T.ZONE_VIS;
2159
+ [...this.zone].sort(
2160
+ (s, i) => this.proj((s.x0 + s.x1) / 2, (s.y0 + s.y1) / 2, (s.z0 + s.z1) / 2).depth - this.proj((i.x0 + i.x1) / 2, (i.y0 + i.y1) / 2, (i.z0 + i.z1) / 2).depth
2161
+ ).forEach((s) => {
2162
+ e.globalAlpha = t;
2163
+ const i = s.fillAlpha !== void 0 ? s.fillAlpha : o.fillAlpha;
2164
+ if (this.box(s.x0, s.x1, s.y0, s.y1, s.z0, s.z1, s.fillBase + i + ")", s.edgeStr), t > 0.05) {
2165
+ e.globalAlpha = t * o.labelAlpha;
2166
+ const n = this.proj((s.x0 + s.x1) / 2, (s.y0 + s.y1) / 2, (s.z0 + s.z1) / 2);
2167
+ e.font = s.labelFontStr || this.getFont("zone"), e.textAlign = "center", e.fillStyle = s.labelColor, e.fillText(s.name, n.x, n.y);
2168
+ }
2169
+ e.globalAlpha = t;
2170
+ });
2171
+ }
2172
+ drawAxes(t = 1) {
2173
+ const e = this.ctx;
2174
+ e.globalAlpha = t;
2175
+ const o = this.opts.axis;
2176
+ o.show && [
2177
+ { from: [0, 0, 0], to: [1.18, 0, 0], lp: [1.22, 0, 0], ...o.data.x },
2178
+ { from: [0, 0, 0], to: [0, 1.18, 0], lp: [0, 1.22, 0], ...o.data.y },
2179
+ { from: [0, 0, 0], to: [0, 0, 1.22], lp: [0, 0, 1.28], ...o.data.z }
2180
+ ].forEach((s) => {
2181
+ var l;
2182
+ const i = this.proj(...s.from), n = this.proj(...s.to);
2183
+ if (e.beginPath(), e.moveTo(i.x, i.y), e.lineTo(n.x, n.y), e.strokeStyle = s.color, e.lineWidth = o.lineStyle.lineWidth, e.stroke(), o.lineStyle.arrowSize > 0) {
2184
+ const h = n.x - i.x, a = n.y - i.y, r = Math.hypot(h, a) || 1, c = h / r, d = a / r, f = o.lineStyle.arrowSize;
2185
+ e.beginPath(), e.moveTo(n.x, n.y), e.lineTo(n.x - c * f + d * (f / 2.25), n.y - d * f - c * (f / 2.25)), e.lineTo(n.x - c * f - d * (f / 2.25), n.y - d * f + c * (f / 2.25)), e.closePath(), e.fillStyle = s.color, e.fill();
2186
+ }
2187
+ if (o.labelStyle.show) {
2188
+ const h = n.x - i.x, a = n.y - i.y, r = Math.hypot(h, a) || 1, c = n.x + h / r * o.labelStyle.distance, d = n.y + a / r * o.labelStyle.distance;
2189
+ e.fillStyle = s.color, e.font = `${o.labelStyle.fontWeight} ${o.labelStyle.fontSize}px ${((l = this.opts.textStyle) == null ? void 0 : l.fontFamily) || T.TEXT_STYLE.fontFamily}`, e.textAlign = "center", e.textBaseline = "middle", e.fillText(s.name, c, d);
2190
+ }
2191
+ });
2192
+ }
2193
+ drawTickLabels(t = 1) {
2194
+ const e = this.ctx;
2195
+ e.globalAlpha = t;
2196
+ const { vals: o, labels: s } = T.TICKS, i = this.theme.tickAlpha;
2197
+ e.font = this.getFont("tick"), o.forEach((n, l) => {
2198
+ let h = this.proj(n, 0, 0);
2199
+ e.fillStyle = T.AXES.x.color + i, e.textAlign = "center", e.fillText(s[l], h.x, h.y + 13), h = this.proj(0, n, 0), e.fillStyle = T.AXES.y.color + i, e.textAlign = "left", e.fillText(s[l], h.x + 7, h.y + 4), h = this.proj(0, 0, n), e.fillStyle = T.AXES.z.color + i, e.textAlign = "right", e.fillText(s[l], h.x - 7, h.y + 4);
2200
+ }), e.textAlign = "center";
2201
+ }
2202
+ drawPoint3D(t, e) {
2203
+ const o = F.realToU(t.position.x), s = F.realToU(t.position.y), i = F.realToU(t.position.z);
2204
+ this.drawPointAt(this.proj(o, s, i), t, e);
2205
+ }
2206
+ drawPointAt(t, e, o = 1) {
2207
+ var p, m;
2208
+ const s = this.ctx, i = T.POINT, n = t.x ?? t.cx, l = t.y ?? t.cy, h = ((p = e.itemStyle) == null ? void 0 : p.radius) ?? i.defaultSize, a = ((m = e.itemStyle) == null ? void 0 : m.color) ?? e.color, r = e.name, c = e.textStyle || {}, d = e.glowStyle !== void 0, f = e.glowStyle || {};
2209
+ if (d && f.show !== !1) {
2210
+ let y = [], u = 3, b = f.glowDistance !== void 0 ? f.glowDistance : 4;
2211
+ const w = f.color ?? a;
2212
+ if (Array.isArray(f.colors) && f.colors.length > 0)
2213
+ y = f.colors, u = y.length;
2214
+ else {
2215
+ const S = f.startColor || _t(w, 0.15), x = f.endColor || "transparent";
2216
+ u = f.count !== void 0 ? parseInt(f.count, 10) : 3, y = [];
2217
+ for (let C = 0; C < u; C++) {
2218
+ const z = u > 1 ? C / (u - 1) : 0;
2219
+ y.push(Ht(S, x, z));
2220
+ }
2221
+ }
2222
+ for (let S = u - 1; S >= 0; S--) {
2223
+ const x = y[S];
2224
+ s.save(), s.fillStyle = x, s.beginPath(), s.arc(n, l, h + (S + 1) * b, 0, Math.PI * 2), s.fill(), s.restore();
2225
+ }
2226
+ }
2227
+ s.globalAlpha = o, s.beginPath(), s.arc(n, l, h, 0, Math.PI * 2);
2228
+ const g = s.createRadialGradient(n - h * i.hlOffset, l - h * i.hlOffset, 1, n, l, h);
2229
+ g.addColorStop(0, "rgba(255,255,255,0.9)"), g.addColorStop(0.4, a + "ee"), g.addColorStop(1, a + "88"), s.fillStyle = g, s.fill(), s.strokeStyle = this.theme.pointStroke, s.lineWidth = 1.3, s.stroke(), s.restore(), r && (s.font = c.bold ? `bold ${c.fontSize || 12}px ${c.fontFamily || "sans-serif"}` : `${c.fontSize || 12}px ${c.fontFamily || "sans-serif"}`, s.fillStyle = c.color ?? e.color, s.textAlign = "left", s.fillText(r, n + h + 3, l - 2));
2230
+ }
2231
+ draw2DOverlay(t, e, o) {
2232
+ var z;
2233
+ const s = T.PLANES[t];
2234
+ if (!s) return;
2235
+ const i = this.ctx, n = this.theme, l = this.opts.plane2D, h = this.opts.axis.data;
2236
+ i.save(), i.globalAlpha = e;
2237
+ let a = this.offsetX, r = this.offsetY, c = this.offsetX + this.renderW, d = this.offsetY + this.renderH;
2238
+ const f = this.opts.grid || {};
2239
+ if (!(f.left !== void 0 || f.right !== void 0 || f.top !== void 0 || f.bottom !== void 0)) {
2240
+ const _ = T.PAD2D || { l: 70, r: 30, t: 50, b: 60 };
2241
+ a = _.l, r = _.t, c = this.W - _.r, d = this.H - _.b;
2242
+ }
2243
+ const p = c - a, m = d - r, y = Math.min(p, m), u = a + p / 2, b = r + m / 2;
2244
+ a = u - y / 2, c = u + y / 2, r = b - y / 2, d = b + y / 2;
2245
+ const { vals: w, labels: S } = T.TICKS, x = (_, A) => ({
2246
+ cx: a + _ * (c - a),
2247
+ cy: d - A * (d - r)
2248
+ }), C = this.themeName ?? "dark";
2249
+ if (l.grid.show && (i.fillStyle = l.grid.backgroundColor ?? s.bgColor[C] ?? s.bgColor.dark, i.fillRect(a, r, c - a, d - r)), l.zone.show && this.zone.forEach((_) => {
2250
+ const [A, Y] = [_[s.hAxis + "0"], _[s.hAxis + "1"]], [P, k] = [_[s.vAxis + "0"], _[s.vAxis + "1"]], M = x(A, P), L = x(Y, k), Q = L.cx - M.cx, N = M.cy - L.cy, st = _.fillAlpha !== void 0 ? _.fillAlpha : l.zone.alpha;
2251
+ i.fillStyle = _.fillBase + st + ")", i.fillRect(M.cx, L.cy, Q, N), l.zone.borderStyle.show && (i.strokeStyle = _.edgeStr, i.lineWidth = l.zone.borderStyle.lineWidth, i.strokeRect(M.cx, L.cy, Q, N));
2252
+ const Z = (M.cx + L.cx) / 2, tt = (M.cy + L.cy) / 2;
2253
+ i.font = _.labelFontStr || this.getFont("zone"), i.textAlign = "center", i.fillStyle = _.labelColor, i.fillText(_.name, Z, tt + 4);
2254
+ }), l.grid.show && (i.strokeStyle = l.grid.lineStyle.color || n.plane2dGrid, i.lineWidth = l.grid.lineStyle.lineWidth, i.globalAlpha = e * l.grid.lineStyle.alpha, l.grid.lineStyle.type === "dashed" ? i.setLineDash([4, 4]) : l.grid.lineStyle.type === "dotted" ? i.setLineDash([2, 2]) : i.setLineDash([]), w.forEach((_) => {
2255
+ const A = x(_, 0).cx, Y = x(0, _).cy;
2256
+ i.beginPath(), i.moveTo(A, r), i.lineTo(A, d), i.stroke(), i.beginPath(), i.moveTo(a, Y), i.lineTo(c, Y), i.stroke();
2257
+ }), i.setLineDash([]), i.globalAlpha = e), l.axis.show) {
2258
+ const _ = h[s.hAxis].color, A = h[s.vAxis].color;
2259
+ i.lineWidth = l.axis.lineStyle.lineWidth, i.globalAlpha = e * l.axis.lineStyle.alpha, i.strokeStyle = _, i.beginPath(), i.moveTo(a, d), i.lineTo(c + 10, d), i.stroke(), i.strokeStyle = A, i.beginPath(), i.moveTo(a, d), i.lineTo(a, r - 10), i.stroke(), i.globalAlpha = e;
2260
+ const Y = ((z = this.opts.textStyle) == null ? void 0 : z.fontFamily) || T.TEXT_STYLE.fontFamily;
2261
+ if (l.axis.tickLabelStyle.show) {
2262
+ i.font = `${l.axis.tickLabelStyle.fontSize}px ${Y}`;
2263
+ const P = l.axis.tickLabelStyle.distance;
2264
+ w.forEach((k, M) => {
2265
+ i.fillStyle = _, i.textAlign = "center", i.fillText(S[M], x(k, 0).cx, d + P + l.axis.tickLabelStyle.fontSize / 2), i.fillStyle = A, i.textAlign = "right", i.fillText(S[M], a - P + 2, x(0, k).cy + l.axis.tickLabelStyle.fontSize / 3);
2266
+ });
2267
+ }
2268
+ if (l.axis.labelStyle.show) {
2269
+ i.font = `bold ${l.axis.labelStyle.fontSize}px ${Y}`;
2270
+ const P = l.axis.labelStyle.distance;
2271
+ i.textAlign = "center", i.fillStyle = _, i.fillText(h[s.hAxis].name, (a + c) / 2, d + P + l.axis.labelStyle.fontSize), i.save(), i.translate(a - P - l.axis.labelStyle.fontSize, (r + d) / 2), i.rotate(-Math.PI / 2), i.fillStyle = A, i.fillText(h[s.vAxis].name, 0, 0), i.restore();
2272
+ }
2273
+ }
2274
+ o.forEach((_) => {
2275
+ const A = x(F.realToU(_.position[s.hAxis]), F.realToU(_.position[s.vAxis]));
2276
+ this.drawPointAt(A, _, e);
2277
+ }), i.restore();
2278
+ }
2279
+ }
2280
+ const ot = class ot {
2281
+ /**
2282
+ * 构造函数
2283
+ * @param {Object} opts 配置项
2284
+ * @param {string|HTMLElement} opts.container 容器选择器或元素
2285
+ * @param {string} opts.initialView 初始视角 (默认 '3d')
2286
+ * @param {string} opts.theme 初始主题 ('dark' | 'light')
2287
+ */
2288
+ constructor(t = {}) {
2289
+ this.series = [], this.opts = t, this.cam = {
2290
+ rotX: T.CAM.elev,
2291
+ rotY: T.CAM.yaw,
2292
+ zoomFactor: 1
2293
+ }, this.view = t.initialView ?? "3d", this.layout = t.layout ?? "fill", this.drag = { active: !1, lastX: 0, lastY: 0 }, this.tween = {
2294
+ from: { rotX: 0, rotY: 0 },
2295
+ to: { rotX: 0, rotY: 0 },
2296
+ t: 1
2297
+ }, this.animId = null, this.pinchDist = null, this.events = { viewChange: null, dataChange: null };
2298
+ const e = typeof t.container == "string" ? document.querySelector(t.container) : t.container;
2299
+ e && this.buildDOM(e), this.renderer = new It(this.ctx, this.W, this.H, t), this.bindEvents(), this.applyView(), this.render();
2300
+ }
2301
+ /** 静态工厂方法,简化初始化调用 */
2302
+ static init(t, e = {}) {
2303
+ return new ot({ container: t, ...e });
2304
+ }
2305
+ /**
2306
+ * 设置图表配置(主要用于更新数据或视角)
2307
+ * @param {Object} opt
2308
+ */
2309
+ setOption(t) {
2310
+ if (t) {
2311
+ if (this.opts = { ...this.opts, ...t }, (t.zone || t.textStyle || t.theme || t.wallColors || t.layout !== void 0 || t.grid !== void 0 || t.axis !== void 0 || t.wall !== void 0 || t.plane2D !== void 0) && this.renderer.updateOptions({
2312
+ zone: this.opts.zone,
2313
+ textStyle: this.opts.textStyle,
2314
+ theme: this.opts.theme,
2315
+ wallColors: this.opts.wallColors,
2316
+ layout: this.opts.layout,
2317
+ grid: this.opts.grid,
2318
+ axis: this.opts.axis,
2319
+ wall: this.opts.wall,
2320
+ plane2D: this.opts.plane2D
2321
+ }), t.series !== void 0) {
2322
+ const e = Array.isArray(t.series) ? t.series : [t.series];
2323
+ this.series = e.map((o) => ({
2324
+ name: o.name ?? "",
2325
+ color: o.color ?? T.POINT.defaultColor,
2326
+ itemStyle: o.itemStyle ?? {},
2327
+ textStyle: o.textStyle ?? {},
2328
+ glowStyle: o.glowStyle,
2329
+ position: o.position ?? { x: 0, y: 0, z: 0 }
2330
+ })), this.emit("dataChange", [...this.series]), this.render();
2331
+ }
2332
+ t.view && t.view !== this.view && this.setView(t.view);
2333
+ }
2334
+ }
2335
+ /**
2336
+ * 切换视图角度(包含平滑补间动画)
2337
+ * @param {string} v 视图 ID
2338
+ */
2339
+ setView(t) {
2340
+ if (!ot.VIEWS[t]) return;
2341
+ this.view = t, cancelAnimationFrame(this.animId);
2342
+ const e = this.getViewTarget(t);
2343
+ this.tween = {
2344
+ from: { rotX: this.cam.rotX, rotY: this.cam.rotY },
2345
+ to: e,
2346
+ t: 0
2347
+ }, this.cv.style.cursor = t === "3d" ? "grab" : "default", this.runTween(), this.emit("viewChange", t);
2348
+ }
2349
+ /** 切换主题渲染 */
2350
+ setTheme(t) {
2351
+ this.renderer.setTheme(t), this.render();
2352
+ }
2353
+ /**
2354
+ * 诊断逻辑:根据输入的三比值 X, Y, Z 判断所属故障区域
2355
+ * @returns {Array} 匹配到的诊断区域信息数组
2356
+ */
2357
+ diagnose(t, e, o) {
2358
+ if (!this.renderer) return [{ ...this.opts.unknown ?? T.UNKNOWN }];
2359
+ const s = this.renderer.zone.filter((i) => t >= i.p1[0] && t < i.p2[0] && e >= i.p1[1] && e < i.p2[1] && o >= i.p1[2] && o < i.p2[2]).map((i) => ({ name: i.name, title: i.title, color: i.edgeColor || i.fill }));
2360
+ return s.length ? s : [{ ...this.opts.unknown ?? T.UNKNOWN }];
2361
+ }
2362
+ on(t, e) {
2363
+ t in this.events && (this.events[t] = e);
2364
+ }
2365
+ emit(t, ...e) {
2366
+ typeof this.events[t] == "function" && this.events[t](...e);
2367
+ }
2368
+ render() {
2369
+ !this.renderer || !this.ctx || this.renderer.draw(this.cam, this.series, this.view, this.flatness());
2370
+ }
2371
+ destroy() {
2372
+ var t, e;
2373
+ cancelAnimationFrame(this.animId), (t = this.resizeObs) == null || t.disconnect(), (e = this.cv) == null || e.remove(), window.removeEventListener("mousemove", this.onMouseMove), window.removeEventListener("mouseup", this.onMouseUp);
2374
+ }
2375
+ // 内部方法
2376
+ getViewTarget(t) {
2377
+ const e = ot.VIEWS[t];
2378
+ return {
2379
+ rotX: typeof e.rotX == "function" ? e.rotX() : e.rotX,
2380
+ rotY: typeof e.rotY == "function" ? e.rotY() : e.rotY
2381
+ };
2382
+ }
2383
+ applyView() {
2384
+ if (this.view !== "3d") {
2385
+ const t = this.getViewTarget(this.view);
2386
+ this.cam.rotX = t.rotX, this.cam.rotY = t.rotY, this.cv.style.cursor = "default";
2387
+ }
2388
+ }
2389
+ flatness() {
2390
+ if (this.view === "3d") return 0;
2391
+ const t = this.getViewTarget(this.view);
2392
+ return Math.max(0, 1 - (Math.abs(this.cam.rotX - t.rotX) + Math.abs(this.cam.rotY - t.rotY)) / 30);
2393
+ }
2394
+ runTween() {
2395
+ this.tween.t = Math.min(1, this.tween.t + T.TWEEN.step);
2396
+ const t = ((e) => e < 0.5 ? 2 * e * e : 1 - Math.pow(-2 * e + 2, 2) / 2)(this.tween.t);
2397
+ this.cam.rotX = this.tween.from.rotX + (this.tween.to.rotX - this.tween.from.rotX) * t, this.cam.rotY = this.tween.from.rotY + (this.tween.to.rotY - this.tween.from.rotY) * t, this.render(), this.tween.t < 1 && (this.animId = requestAnimationFrame(() => this.runTween()));
2398
+ }
2399
+ buildDOM(t) {
2400
+ const e = t.getBoundingClientRect();
2401
+ this.W = e.width > 0 ? Math.round(e.width) : 600, this.H = e.height > 0 ? Math.round(e.height) : 540, this.cv = document.createElement("canvas"), this.cv.className = "trc-canvas", this.cv.width = this.W, this.cv.height = this.H, this.cv.style.cssText = "width:100%;height:100%;display:block;touch-action:none;", this.ctx = this.cv.getContext("2d"), t.appendChild(this.cv), this.resizeObs = new ResizeObserver((o) => {
2402
+ var n;
2403
+ const { width: s, height: i } = o[0].contentRect;
2404
+ s > 0 && i > 0 && (this.W = Math.round(s), this.H = Math.round(i), this.cv.width = this.W, this.cv.height = this.H, (n = this.renderer) == null || n.resize(this.W, this.H), this.render());
2405
+ }), this.resizeObs.observe(t);
2406
+ }
2407
+ bindEvents() {
2408
+ const t = T.DRAG, e = this.cv;
2409
+ e.addEventListener("mousedown", (o) => {
2410
+ this.view === "3d" && (this.drag = { active: !0, lastX: o.clientX, lastY: o.clientY }, e.style.cursor = "grabbing", cancelAnimationFrame(this.animId));
2411
+ }), this.onMouseMove = (o) => {
2412
+ !this.drag.active || this.view !== "3d" || (this.cam.rotY += (o.clientX - this.drag.lastX) * t.rotYSens, this.cam.rotX = Math.max(
2413
+ t.rotXMin,
2414
+ Math.min(t.rotXMax, this.cam.rotX + (o.clientY - this.drag.lastY) * t.rotXSens)
2415
+ ), this.drag.lastX = o.clientX, this.drag.lastY = o.clientY, this.render());
2416
+ }, this.onMouseUp = () => {
2417
+ this.drag.active = !1, this.view === "3d" && (e.style.cursor = "grab");
2418
+ }, window.addEventListener("mousemove", this.onMouseMove), window.addEventListener("mouseup", this.onMouseUp), e.addEventListener(
2419
+ "touchstart",
2420
+ (o) => {
2421
+ this.view === "3d" && (this.drag = {
2422
+ active: !0,
2423
+ lastX: o.touches[0].clientX,
2424
+ lastY: o.touches[0].clientY
2425
+ }, o.touches.length === 2 && (this.pinchDist = Math.hypot(
2426
+ o.touches[0].clientX - o.touches[1].clientX,
2427
+ o.touches[0].clientY - o.touches[1].clientY
2428
+ )));
2429
+ },
2430
+ { passive: !0 }
2431
+ ), e.addEventListener(
2432
+ "touchmove",
2433
+ (o) => {
2434
+ if (this.view === "3d")
2435
+ if (o.touches.length === 2 && this.pinchDist !== null) {
2436
+ const s = Math.hypot(
2437
+ o.touches[0].clientX - o.touches[1].clientX,
2438
+ o.touches[0].clientY - o.touches[1].clientY
2439
+ );
2440
+ this.cam.zoomFactor = Math.max(
2441
+ t.zoomMin,
2442
+ Math.min(t.zoomMax, this.cam.zoomFactor * s / this.pinchDist)
2443
+ ), this.pinchDist = s, this.render();
2444
+ } else this.drag.active && o.touches.length === 1 && (this.cam.rotY += (o.touches[0].clientX - this.drag.lastX) * t.rotYSens, this.cam.rotX = Math.max(
2445
+ t.rotXMin,
2446
+ Math.min(t.rotXMax, this.cam.rotX + (o.touches[0].clientY - this.drag.lastY) * t.rotXSens)
2447
+ ), this.drag.lastX = o.touches[0].clientX, this.drag.lastY = o.touches[0].clientY, this.render());
2448
+ },
2449
+ { passive: !0 }
2450
+ ), e.addEventListener(
2451
+ "touchend",
2452
+ (o) => {
2453
+ o.touches.length < 2 && (this.pinchDist = null), o.touches.length === 0 && (this.drag.active = !1);
2454
+ },
2455
+ { passive: !0 }
2456
+ ), e.addEventListener(
2457
+ "wheel",
2458
+ (o) => {
2459
+ this.view === "3d" && (o.preventDefault(), this.cam.zoomFactor = Math.max(
2460
+ t.zoomMin,
2461
+ Math.min(t.zoomMax, this.cam.zoomFactor * (o.deltaY > 0 ? t.zoomOut : t.zoomIn))
2462
+ ), this.render());
2463
+ },
2464
+ { passive: !1 }
2465
+ );
2466
+ }
2467
+ };
2468
+ K(ot, "VIEWS", {
2469
+ "3d": { rotX: () => T.CAM.elev, rotY: () => T.CAM.yaw },
2470
+ xz: { rotX: 0, rotY: 0 },
2471
+ yz: { rotX: 0, rotY: 90 },
2472
+ xy: { rotX: 90, rotY: 0 }
2473
+ });
2474
+ let xt = ot;
2475
+ function ht(v) {
2476
+ const t = v.trim().toLowerCase();
2477
+ if (t.startsWith("#")) {
2478
+ let o = t.slice(1);
2479
+ o.length === 3 && (o = o[0] + o[0] + o[1] + o[1] + o[2] + o[2]);
2480
+ const s = parseInt(o.substring(0, 2), 16), i = parseInt(o.substring(2, 4), 16), n = parseInt(o.substring(4, 6), 16), l = o.length === 8 ? parseInt(o.substring(6, 8), 16) / 255 : 1;
2481
+ return [s, i, n, l];
2482
+ }
2483
+ const e = t.match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\)/);
2484
+ return e ? [
2485
+ parseInt(e[1], 10),
2486
+ parseInt(e[2], 10),
2487
+ parseInt(e[3], 10),
2488
+ e[4] !== void 0 ? parseFloat(e[4]) : 1
2489
+ ] : t === "transparent" ? [0, 0, 0, 0] : [255, 255, 255, 1];
2490
+ }
2491
+ function _t(v, t) {
2492
+ const [e, o, s, i] = ht(v);
2493
+ return `rgba(${e},${o},${s},${t !== void 0 ? t : i})`;
2494
+ }
2495
+ function Ht(v, t, e) {
2496
+ const [o, s, i, n] = ht(v), [l, h, a, r] = ht(t), c = Math.round(o + (l - o) * e), d = Math.round(s + (h - s) * e), f = Math.round(i + (a - i) * e), g = n + (r - n) * e;
2497
+ return `rgba(${c},${d},${f},${g})`;
2498
+ }
2499
+ const jt = {
2500
+ theme: "light",
2501
+ backgroundColor: "transparent",
2502
+ grid: {
2503
+ left: 72,
2504
+ right: 20,
2505
+ top: 20,
2506
+ bottom: 56,
2507
+ lineStyle: { type: "solid", width: 0.4, color: null },
2508
+ majorLineStyle: { type: "solid", width: 0.8, color: null }
2509
+ },
2510
+ zone: {
2511
+ data: Wt,
2512
+ labelStyle: { show: !0, fontSize: 12, borderRadius: 4 },
2513
+ borderStyle: { show: !0, stroke: 1, type: "solid", color: null }
2514
+ },
2515
+ xAxis: {
2516
+ title: "",
2517
+ min: -2,
2518
+ max: 3,
2519
+ // log10 range
2520
+ labelStyle: { fontSize: 11, fontWeight: "normal", offsetX: 0, offsetY: 0, color: null },
2521
+ lineStyle: { show: !0, stroke: 1.5, type: "solid", color: null },
2522
+ titleStyle: { fontSize: 13, color: null, fontWeight: "normal", align: "center", offsetX: 0, offsetY: 0 }
2523
+ },
2524
+ yAxis: {
2525
+ title: "",
2526
+ min: -3,
2527
+ max: 3,
2528
+ // log10 range
2529
+ labelStyle: { fontSize: 11, fontWeight: "normal", offsetX: 0, offsetY: 0, color: null },
2530
+ lineStyle: { show: !0, stroke: 1.5, type: "solid", color: null },
2531
+ titleStyle: { fontSize: 13, color: null, fontWeight: "normal", align: "center", offsetX: 0, offsetY: 0 }
2532
+ },
2533
+ tooltip: { show: !0, formatter: null },
2534
+ series: []
2535
+ }, Ct = {
2536
+ light: {
2537
+ backgroundColor: "#ffffff",
2538
+ text: "#333333",
2539
+ textSecondary: "#666666",
2540
+ gridLine: "rgba(0,0,0,0.12)",
2541
+ gridLineMajor: "rgba(0,0,0,0.22)",
2542
+ axisLine: "rgba(0,0,0,0.5)",
2543
+ zoneBorder: "rgba(0,0,0,0.35)",
2544
+ zoneLabelBg: "rgba(255,255,255,0.75)",
2545
+ tooltipBg: "rgba(255,255,255,0.95)",
2546
+ tooltipBorder: "rgba(0,0,0,0.15)",
2547
+ tooltipTextColor: "#222222"
2548
+ },
2549
+ dark: {
2550
+ backgroundColor: "#1a1a2e",
2551
+ text: "rgba(255,255,255,0.85)",
2552
+ textSecondary: "rgba(255,255,255,0.5)",
2553
+ gridLine: "rgba(255,255,255,0.08)",
2554
+ gridLineMajor: "rgba(255,255,255,0.18)",
2555
+ axisLine: "rgba(255,255,255,0.55)",
2556
+ zoneBorder: "rgba(255,255,255,0.3)",
2557
+ zoneLabelBg: "rgba(0,0,0,0.5)",
2558
+ tooltipBg: "rgba(20,20,40,0.95)",
2559
+ tooltipBorder: "rgba(255,255,255,0.15)",
2560
+ tooltipTextColor: "rgba(255,255,255,0.9)"
2561
+ }
2562
+ };
2563
+ function Tt(v) {
2564
+ const t = Math.round(v);
2565
+ return "10" + String(t).split("").map(
2566
+ (o) => ({ "-": "⁻", 0: "⁰", 1: "¹", 2: "²", 3: "³", 4: "⁴", 5: "⁵", 6: "⁶", 7: "⁷", 8: "⁸", 9: "⁹" })[o] || o
2567
+ ).join("");
2568
+ }
2569
+ class zt {
2570
+ constructor(t, e = {}) {
2571
+ if (typeof t == "string" && (t = document.querySelector(t)), !t) throw new Error("[ETRAChart] Container element not found");
2572
+ this._container = t, this._opt = E(E({}, jt), e), this._bus = new At(), this._initDOM(), this._zoom = new ut(this._opt.zoom || {}), this._tooltipRenderer = new yt(this._container, this._theme), this._hoverZone = null, this._hoverPoint = null, typeof ResizeObserver < "u" && (this._ro = new ResizeObserver(() => this.resize()), this._ro.observe(this._container)), this._onWheel = (s) => {
2573
+ s.preventDefault();
2574
+ const i = this._canvas.getBoundingClientRect(), n = s.clientX - i.left, l = s.clientY - i.top;
2575
+ this._zoom.onWheel(s.deltaY, n, l), this._bus.emit("zoom", this._zoom.state), this._render();
2576
+ }, this._onDown = (s) => {
2577
+ s.button === 0 && (this._zoom.startDrag(s.clientX, s.clientY), this._canvas.style.cursor = "grabbing");
2578
+ }, this._onMove = (s) => {
2579
+ const i = this._canvas.getBoundingClientRect();
2580
+ if (this._zoom.moveDrag(s.clientX, s.clientY, 1)) {
2581
+ this._render();
2582
+ return;
2583
+ }
2584
+ if (!this._coordMap || !this._drawnPoints) return;
2585
+ const n = s.clientX - i.left, l = s.clientY - i.top, { panX: h, panY: a, zoom: r } = this._zoom, c = (n - h) / r, d = (l - a) / r;
2586
+ let f = null, g = 1 / 0;
2587
+ for (const p of this._drawnPoints) {
2588
+ const m = Math.hypot(c - p.px, d - p.py), y = p.series.size || 6;
2589
+ m < y * 2 + 5 && m < g && (g = m, f = p);
2590
+ }
2591
+ f !== this._hoverPoint && (this._hoverPoint = f, this._render(), f ? (this._canvas.style.cursor = "pointer", this._bus.emit("hover", f)) : (this._canvas.style.cursor = "default", this._bus.emit("hover", null)));
2592
+ }, this._onUp = () => {
2593
+ this._zoom.endDrag() && (this._canvas.style.cursor = this._hoverPoint ? "pointer" : "default", this._bus.emit("zoom", this._zoom.state));
2594
+ }, this._onLeave = () => {
2595
+ this._hoverPoint && (this._hoverPoint = null, this._canvas.style.cursor = "default", this._render(), this._bus.emit("hover", null));
2596
+ }, this._onDbl = () => {
2597
+ this._zoom.reset(), this._bus.emit("zoom", this._zoom.state), this._render();
2598
+ };
2599
+ const o = this._canvas;
2600
+ o.addEventListener("wheel", this._onWheel, { passive: !1 }), o.addEventListener("mousedown", this._onDown), o.addEventListener("mousemove", this._onMove), o.addEventListener("mouseleave", this._onLeave), o.addEventListener("dblclick", this._onDbl), window.addEventListener("mouseup", this._onUp), this._render();
2601
+ }
2602
+ static init(t, e) {
2603
+ return new zt(t, e);
2604
+ }
2605
+ get _theme() {
2606
+ return Ct[this._opt.theme] || Ct.light;
2607
+ }
2608
+ _initDOM() {
2609
+ this._container.style.position = "relative", this._container.style.overflow = "hidden", this._canvas = document.createElement("canvas"), this._canvas.style.display = "block", this._canvas.style.width = "100%", this._canvas.style.height = "100%", this._container.appendChild(this._canvas), this._ctx = this._canvas.getContext("2d");
2610
+ }
2611
+ setOption(t) {
2612
+ return this._opt = E(this._opt, t), this._render(), this;
2613
+ }
2614
+ on(t, e) {
2615
+ return this._bus.on(t, e), this;
2616
+ }
2617
+ off(t, e) {
2618
+ return this._bus.off(t, e), this;
2619
+ }
2620
+ resize() {
2621
+ return this._render(), this;
2622
+ }
2623
+ dispose() {
2624
+ this._ro && this._ro.disconnect(), this._tooltipRenderer.dispose(), this._canvas && this._canvas.parentNode && this._canvas.parentNode.removeChild(this._canvas), this._bus.dispose(), window.removeEventListener("mouseup", this._onUp);
2625
+ }
2626
+ _dims() {
2627
+ const t = this._container.getBoundingClientRect(), e = t.width || 600, o = t.height || 400, s = window.devicePixelRatio || 1;
2628
+ (this._canvas.width !== Math.round(e * s) || this._canvas.height !== Math.round(o * s)) && (this._canvas.width = Math.round(e * s), this._canvas.height = Math.round(o * s));
2629
+ const i = ct(e, o, this._opt.grid, 0);
2630
+ return { W: e, H: o, box: i, dpr: s };
2631
+ }
2632
+ _render() {
2633
+ const { W: t, H: e, box: o, dpr: s } = this._dims(), i = this._ctx;
2634
+ if (!i) return;
2635
+ const n = this._theme, l = this._opt;
2636
+ i.setTransform(s, 0, 0, s, 0, 0), i.clearRect(0, 0, t, e);
2637
+ const h = l.backgroundColor || n.backgroundColor || "transparent";
2638
+ h !== "transparent" && (i.fillStyle = h, i.fillRect(0, 0, t, e));
2639
+ const a = l.xAxis.min, r = l.xAxis.max, c = l.yAxis.min, d = l.yAxis.max, f = o.availW, g = o.availH, p = o.left, m = o.top, y = (w) => p + (w - a) / (r - a) * f, u = (w) => m + (d - w) / (d - c) * g;
2640
+ this._coordMap = { xMin: a, xMax: r, yMin: c, yMax: d, plotW: f, plotH: g, gL: p, gT: m, toPixX: y, toPixY: u }, i.save(), this._zoom.applyTransform(i), this._drawGrid(i, y, u, n, l), this._drawZones(i, y, u, n, l);
2641
+ const b = this._drawSeries(i, y, u, n, l);
2642
+ if (this._drawAxes(i, y, u, n, l, t, e, p, m, f, g), i.restore(), l.tooltip.show && this._hoverPoint) {
2643
+ const w = this._hoverPoint, S = y(w.logX) * this._zoom.zoom + this._zoom.panX, x = u(w.logY) * this._zoom.zoom + this._zoom.panY;
2644
+ let C = "";
2645
+ typeof l.tooltip.formatter == "function" ? C = l.tooltip.formatter({
2646
+ series: w.series,
2647
+ logX: w.logX,
2648
+ logY: w.logY,
2649
+ rawX: Math.pow(10, w.logX),
2650
+ rawY: Math.pow(10, w.logY),
2651
+ zone: w.zone
2652
+ }) : C = this._defaultTooltipHTML(w, l), this._tooltipRenderer.show(C, S, x, l.tooltip, n, w.zone);
2653
+ } else
2654
+ this._tooltipRenderer.hide();
2655
+ b.length > 0 && this._bus.emit("diagnose", b);
2656
+ }
2657
+ _drawGrid(t, e, o, s, i) {
2658
+ const n = i.xAxis.min, l = i.xAxis.max, h = i.yAxis.min, a = i.yAxis.max, r = this._coordMap.gL, c = this._coordMap.gT, d = this._coordMap.plotW, f = this._coordMap.plotH, g = i.grid.lineStyle || {}, p = g.color || s.gridLineMajor, m = s.gridLine;
2659
+ for (let y = Math.ceil(n); y <= Math.floor(l); y++) {
2660
+ const u = e(y);
2661
+ t.beginPath(), t.moveTo(u, c), t.lineTo(u, c + f), t.strokeStyle = p, t.lineWidth = g.width || 0.4, g.type === "dashed" ? t.setLineDash([4, 3]) : t.setLineDash([]), t.stroke(), t.setLineDash([]), t.strokeStyle = m, t.lineWidth = 0.25;
2662
+ for (let b = 2; b <= 9; b++) {
2663
+ const w = y + Math.log10(b);
2664
+ if (w > l) break;
2665
+ const S = e(w);
2666
+ t.beginPath(), t.moveTo(S, c), t.lineTo(S, c + f), t.stroke();
2667
+ }
2668
+ }
2669
+ for (let y = Math.ceil(h); y <= Math.floor(a); y++) {
2670
+ const u = o(y);
2671
+ t.beginPath(), t.moveTo(r, u), t.lineTo(r + d, u), t.strokeStyle = p, t.lineWidth = g.width || 0.4, g.type === "dashed" ? t.setLineDash([4, 3]) : t.setLineDash([]), t.stroke(), t.setLineDash([]), t.strokeStyle = m, t.lineWidth = 0.25;
2672
+ for (let b = 2; b <= 9; b++) {
2673
+ const w = y + Math.log10(b);
2674
+ if (w > a) break;
2675
+ const S = o(w);
2676
+ t.beginPath(), t.moveTo(r, S), t.lineTo(r + d, S), t.stroke();
2677
+ }
2678
+ }
2679
+ }
2680
+ _drawZones(t, e, o, s, i) {
2681
+ const n = i.zone;
2682
+ if (!(!n || !n.data)) {
2683
+ for (const l of n.data)
2684
+ if (!(!l.poly || l.poly.length < 3) && (t.beginPath(), l.poly.forEach((h, a) => {
2685
+ const r = e(h[0]), c = o(h[1]);
2686
+ a === 0 ? t.moveTo(r, c) : t.lineTo(r, c);
2687
+ }), t.closePath(), t.fillStyle = l.color || "rgba(128,128,128,0.2)", t.fill(), n.borderStyle.show && (t.strokeStyle = n.borderStyle.color || l.color || s.zoneBorder, t.lineWidth = n.borderStyle.stroke || 1, n.borderStyle.type === "dashed" ? t.setLineDash([5, 3]) : t.setLineDash([]), t.stroke(), t.setLineDash([])), n.labelStyle.show && (l.title || l.name))) {
2688
+ let h = 0, a = 0;
2689
+ l.poly.forEach((b) => {
2690
+ h += e(b[0]), a += o(b[1]);
2691
+ });
2692
+ const r = h / l.poly.length, c = a / l.poly.length, d = this._coordMap.gL, f = this._coordMap.gT, g = this._coordMap.plotW, p = this._coordMap.plotH, m = Math.max(d + 4, Math.min(d + g - 4, r)), y = Math.max(f + 4, Math.min(f + p - 4, c)), u = n.labelStyle.fontSize || 12;
2693
+ if (t.textAlign = "center", t.textBaseline = "middle", l.title && l.name && l.name !== l.title)
2694
+ t.font = `600 ${u + 1}px system-ui, sans-serif`, t.fillStyle = l.labelColor || s.text, t.fillText(l.name, m, y - u * 0.7), t.font = `${u - 1}px system-ui, sans-serif`, t.fillStyle = l.labelColor || s.textSecondary, t.fillText(l.title, m, y + u * 0.9);
2695
+ else {
2696
+ const b = l.title || l.name;
2697
+ t.font = `500 ${u}px system-ui, sans-serif`, t.fillStyle = l.labelColor || s.text, t.fillText(b, m, y);
2698
+ }
2699
+ }
2700
+ }
2701
+ }
2702
+ _drawAxes(t, e, o, s, i, n, l, h, a, r, c) {
2703
+ const d = i.xAxis.min, f = i.xAxis.max, g = i.yAxis.min, p = i.yAxis.max;
2704
+ t.beginPath(), t.rect(h, a, r, c), t.strokeStyle = s.axisLine, t.lineWidth = 1, t.stroke();
2705
+ const m = i.xAxis.labelStyle.color || s.textSecondary, y = i.yAxis.labelStyle.color || s.textSecondary;
2706
+ t.textAlign = "center", t.textBaseline = "middle";
2707
+ for (let u = Math.ceil(d); u <= Math.floor(f); u++) {
2708
+ const b = e(u), w = i.xAxis.labelStyle;
2709
+ t.font = `${w.fontWeight || "normal"} ${w.fontSize || 11}px system-ui, sans-serif`, t.fillStyle = m, t.fillText(Tt(u), b + (w.offsetX || 0), a + c + 16 + (w.offsetY || 0));
2710
+ }
2711
+ t.textAlign = "right";
2712
+ for (let u = Math.ceil(g); u <= Math.floor(p); u++) {
2713
+ const b = o(u), w = i.yAxis.labelStyle;
2714
+ t.font = `${w.fontWeight || "normal"} ${w.fontSize || 11}px system-ui, sans-serif`, t.fillStyle = y, t.fillText(Tt(u), h - 6 + (w.offsetX || 0), b + (w.offsetY || 0));
2715
+ }
2716
+ if (i.xAxis.title) {
2717
+ const u = i.xAxis.titleStyle, b = { left: h, center: h + r / 2, right: h + r }, w = (b[u.align] || b.center) + (u.offsetX || 0), S = a + c + 38 + (u.offsetY || 0);
2718
+ t.textAlign = u.align === "left" ? "left" : u.align === "right" ? "right" : "center", t.font = `${u.fontWeight || "normal"} ${u.fontSize || 13}px system-ui, sans-serif`, t.fillStyle = u.color || s.text, t.fillText(i.xAxis.title, w, S);
2719
+ }
2720
+ if (i.yAxis.title) {
2721
+ const u = i.yAxis.titleStyle, b = { left: a + c, center: a + c / 2, right: a }, w = b[u.align] || b.center, S = 14 + (u.offsetX || 0), x = w + (u.offsetY || 0);
2722
+ t.save(), t.translate(S, x), t.rotate(-Math.PI / 2), t.textAlign = u.align === "left" ? "right" : u.align === "right" ? "left" : "center", t.font = `${u.fontWeight || "normal"} ${u.fontSize || 13}px system-ui, sans-serif`, t.fillStyle = u.color || s.text, t.fillText(i.yAxis.title, 0, 0), t.restore();
2723
+ }
2724
+ }
2725
+ _drawSeries(t, e, o, s, i) {
2726
+ var l, h, a;
2727
+ const n = [];
2728
+ for (const r of i.series || []) {
2729
+ let c = 0, d = 0;
2730
+ if (Array.isArray(r.data) && r.data.length >= 2) {
2731
+ const x = typeof r.data[0] == "object" ? r.data[0].value : r.data[0], C = typeof r.data[1] == "object" ? r.data[1].value : r.data[1];
2732
+ c = r.logScale === !1 ? x : Math.log10(x || 1e-9), d = r.logScale === !1 ? C : Math.log10(C || 1e-9);
2733
+ } else if (r.dataX !== void 0 && r.dataY !== void 0)
2734
+ c = r.logScale === !1 ? r.dataX : Math.log10(r.dataX || 1e-9), d = r.logScale === !1 ? r.dataY : Math.log10(r.dataY || 1e-9);
2735
+ else
2736
+ continue;
2737
+ const f = e(c), g = o(d);
2738
+ let p = null;
2739
+ if (i.zone && i.zone.data) {
2740
+ for (const x of i.zone.data)
2741
+ if (x.poly && gt(c, d, x.poly)) {
2742
+ p = x;
2743
+ break;
2744
+ }
2745
+ }
2746
+ n.push({ series: r, zone: p, logX: c, logY: d, px: f, py: g });
2747
+ const m = r.color || "#00e5ff", y = r.size || 6, u = r.shape || "circle", b = this._hoverPoint && this._hoverPoint.series === r;
2748
+ t.save(), t.translate(f, g);
2749
+ const w = r.glowStyle || {};
2750
+ (w.show || b && w.show !== !1) && (t.shadowColor = w.color || Lt(m, 0.8), t.shadowBlur = w.blur || 15), t.fillStyle = m, t.strokeStyle = ((l = r.itemStyle) == null ? void 0 : l.borderColor) || "none", t.lineWidth = ((h = r.itemStyle) == null ? void 0 : h.borderWidth) || 0, (t.strokeStyle === "none" || !((a = r.itemStyle) != null && a.borderColor)) && (t.lineWidth = 0), t.beginPath(), nt(t, 0, 0, u, y, 1, 0), t.fill(), t.lineWidth > 0 && t.stroke();
2751
+ const S = r.textStyle;
2752
+ if (S && S.show && r.name) {
2753
+ t.shadowBlur = 0;
2754
+ const x = {
2755
+ top: [0, -(y + 6)],
2756
+ bottom: [0, y + 12],
2757
+ left: [-(y + 6), 4],
2758
+ right: [y + 6, 4]
2759
+ }, [C, z] = x[S.position] || x.top;
2760
+ t.textAlign = S.position === "left" ? "right" : S.position === "right" ? "left" : "center", t.textBaseline = "middle", t.font = `${S.fontWeight || "normal"} ${S.fontSize || 12}px system-ui, sans-serif`, t.fillStyle = S.color || m, t.fillText(r.name, C, z);
2761
+ }
2762
+ t.restore();
2763
+ }
2764
+ return this._drawnPoints = n, n;
2765
+ }
2766
+ _defaultTooltipHTML(t, e) {
2767
+ const o = t.series, s = Math.pow(10, t.logX).toPrecision(4), i = Math.pow(10, t.logY).toPrecision(4), n = e.xAxis.title || "X", l = e.yAxis.title || "Y", h = t.zone ? t.zone.title || t.zone.name : "Outside", a = t.zone && t.zone.color || "#fff";
2768
+ return `
2769
+ <div style="font-weight:bold; font-size:14px; margin-bottom:6px; color:#fff;">${o.name || "Data Point"}</div>
2770
+ <div style="font-size:13px; font-weight:bold; color:${a}; border-bottom:1px solid rgba(255,255,255,0.1); padding-bottom:6px; margin-bottom:8px;">${h}</div>
2771
+ <div style="font-size:13px; color:#cbd5e1; display:flex; justify-content:space-between; margin-bottom:4px;">
2772
+ <span>${n}:</span><span style="font-weight:bold; color:#fff; margin-left:12px;">${s}</span>
2773
+ </div>
2774
+ <div style="font-size:13px; color:#cbd5e1; display:flex; justify-content:space-between;">
2775
+ <span>${l}:</span><span style="font-weight:bold; color:#fff; margin-left:12px;">${i}</span>
2776
+ </div>
2777
+ `;
2778
+ }
2779
+ }
2780
+ export {
2781
+ Ut as DiagnosticTools,
2782
+ vt as DuvalPentagon,
2783
+ Gt as DuvalTriangle,
2784
+ zt as ETRAChart,
2785
+ Wt as ETRA_ZONES_A,
2786
+ Zt as ETRA_ZONES_B,
2787
+ it as PENTAGON_ZONES_1,
2788
+ lt as PENTAGON_ZONES_2,
2789
+ kt as THREE_RADIO_ZONES,
2790
+ Pt as TRIANGLE_ZONES_1,
2791
+ Ot as TRIANGLE_ZONES_4,
2792
+ Nt as TRIANGLE_ZONES_5,
2793
+ xt as ThreeRatioChart,
2794
+ ft as computedPercent
2795
+ };
2796
+ //# sourceMappingURL=index.js.map