rendx-engine 0.2.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/main.cjs ADDED
@@ -0,0 +1,3017 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __typeError = (msg) => {
9
+ throw TypeError(msg);
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
33
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
34
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
35
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
36
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
37
+
38
+ // src/main.ts
39
+ var main_exports = {};
40
+ __export(main_exports, {
41
+ App: () => App,
42
+ ArcShape: () => ArcShape,
43
+ ArcTransform: () => ArcTransform,
44
+ AreaShape: () => AreaShape,
45
+ AttributeTransform: () => AttributeTransform,
46
+ Attributes: () => Attributes,
47
+ BaseTransform: () => BaseTransform,
48
+ CircleShape: () => CircleShape,
49
+ ClipBoxTransform: () => ClipBoxTransform,
50
+ CurveShape: () => CurveShape,
51
+ EventDispatcher: () => EventDispatcher,
52
+ EventObserver: () => EventObserver,
53
+ EventTarget: () => EventTarget,
54
+ Graphics: () => Graphics,
55
+ GraphicsTransform: () => GraphicsTransform,
56
+ Group: () => Group,
57
+ ImageShape: () => ImageShape,
58
+ Layer: () => Layer,
59
+ LineShape: () => LineShape,
60
+ Node: () => Node,
61
+ PathShape: () => PathShape,
62
+ PolygonShape: () => PolygonShape,
63
+ RectShape: () => RectShape,
64
+ Renderer: () => Renderer,
65
+ RoundShape: () => RoundShape,
66
+ Scene: () => Scene,
67
+ SectorShape: () => SectorShape,
68
+ SectorTransform: () => SectorTransform,
69
+ Shape: () => Shape,
70
+ SimulatedEvent: () => SimulatedEvent,
71
+ SymbolShape: () => SymbolShape,
72
+ TextShape: () => TextShape,
73
+ createShape: () => createShape8,
74
+ deserialize: () => deserialize,
75
+ imageLoader: () => imageLoader,
76
+ isHit: () => isHit,
77
+ serialize: () => serialize,
78
+ serializeLayer: () => serializeLayer,
79
+ setCanvasRenderingContext2StrokeAttrs: () => setCanvasRenderingContext2StrokeAttrs
80
+ });
81
+ module.exports = __toCommonJS(main_exports);
82
+
83
+ // src/core/graphics.ts
84
+ var import_gl_matrix = require("gl-matrix");
85
+ var import_rendx_core2 = require("rendx-core");
86
+
87
+ // src/transforms/base.ts
88
+ var import_rendx_ease = require("rendx-ease");
89
+ var BaseTransform = class {
90
+ constructor() {
91
+ this.status = "start";
92
+ this._duration = 0;
93
+ this._delay = 0;
94
+ this._easing = "linear";
95
+ this._repeat = false;
96
+ this._time = -1;
97
+ }
98
+ /** 是否仍在活跃状态(未结束) */
99
+ get active() {
100
+ return this.status !== "end";
101
+ }
102
+ duration(time) {
103
+ this._duration = time;
104
+ return this;
105
+ }
106
+ delay(time) {
107
+ this._delay = time;
108
+ return this;
109
+ }
110
+ easing(easing) {
111
+ this._easing = easing;
112
+ return this;
113
+ }
114
+ repeat(repeat) {
115
+ this._repeat = repeat;
116
+ return this;
117
+ }
118
+ /** 动画结束时的清理,子类可覆盖 */
119
+ onEnd() {
120
+ }
121
+ interpolate(time) {
122
+ if (this.status === "end") return;
123
+ if (this.status === "last") {
124
+ if (this._repeat) {
125
+ this.status = "start";
126
+ this._time = -1;
127
+ } else {
128
+ this.status = "end";
129
+ this.onEnd();
130
+ return;
131
+ }
132
+ }
133
+ if (this._time === -1) this._time = time;
134
+ const elapsed = time - this._time;
135
+ if (elapsed < this._delay) {
136
+ this.status = "waiting";
137
+ return;
138
+ }
139
+ this.status = elapsed > this._delay + this._duration ? "last" : "running";
140
+ const ease = import_rendx_ease.easeMap[this._easing] ?? import_rendx_ease.easeMap["linear"];
141
+ const raw = this._duration > 0 ? (elapsed - this._delay) / this._duration : 1;
142
+ const t = ease(Math.max(0, Math.min(1, raw)));
143
+ this.apply(t);
144
+ }
145
+ };
146
+
147
+ // src/transforms/graphics.ts
148
+ var GraphicsTransform = class extends BaseTransform {
149
+ constructor(values) {
150
+ super();
151
+ this.attrs = {};
152
+ this.values = {};
153
+ this.V = values;
154
+ }
155
+ translate(x, y) {
156
+ if (!this.attrs.translate) {
157
+ this.attrs.translate = [this.V.tx, this.V.ty, x, y];
158
+ } else {
159
+ const [, , tx2, ty2] = this.attrs.translate;
160
+ this.attrs.translate = [tx2, ty2, x, y];
161
+ }
162
+ this.status = "start";
163
+ this._time = -1;
164
+ return this;
165
+ }
166
+ rotate(r) {
167
+ if (!this.attrs.rotate) {
168
+ this.attrs.rotate = [this.V.rotate, r];
169
+ } else {
170
+ const [, r2] = this.attrs.rotate;
171
+ this.attrs.rotate = [r2, r];
172
+ }
173
+ this.status = "start";
174
+ this._time = -1;
175
+ return this;
176
+ }
177
+ scale(x, y) {
178
+ if (!this.attrs.scale) {
179
+ this.attrs.scale = [this.V.sx, this.V.sy, x, y];
180
+ } else {
181
+ const [, , sx2, sy2] = this.attrs.scale;
182
+ this.attrs.scale = [sx2, sy2, x, y];
183
+ }
184
+ this.status = "start";
185
+ this._time = -1;
186
+ return this;
187
+ }
188
+ apply(t) {
189
+ const { translate, scale, rotate } = this.attrs;
190
+ if (translate) {
191
+ this.values.tx = translate[0] + (translate[2] - translate[0]) * t;
192
+ this.values.ty = translate[1] + (translate[3] - translate[1]) * t;
193
+ }
194
+ if (scale) {
195
+ this.values.sx = scale[0] + (scale[2] - scale[0]) * t;
196
+ this.values.sy = scale[1] + (scale[3] - scale[1]) * t;
197
+ }
198
+ if (rotate) {
199
+ this.values.rotate = rotate[0] + (rotate[1] - rotate[0]) * t;
200
+ }
201
+ }
202
+ onEnd() {
203
+ this.attrs = {};
204
+ }
205
+ };
206
+
207
+ // src/transforms/attributes.ts
208
+ var import_rendx_interpolate = require("rendx-interpolate");
209
+ var AttributeTransform = class extends BaseTransform {
210
+ constructor(values) {
211
+ super();
212
+ this.attrs = {};
213
+ this.V = values;
214
+ }
215
+ /** 设置属性动画目标值(属性应在调用前已设置初始值) */
216
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
+ attr(key, value) {
218
+ this.attrs[key] = [this.V[key] ?? value, value];
219
+ this.status = "start";
220
+ this._time = -1;
221
+ return this;
222
+ }
223
+ apply(t) {
224
+ const { opacity, fill, fillOpacity, stroke, strokeOpacity } = this.attrs;
225
+ if (opacity) this.V.opacity = opacity[0] + (opacity[1] - opacity[0]) * t;
226
+ if (fill) this.V.fill = (0, import_rendx_interpolate.interpolateColor)(fill[0], fill[1])(t);
227
+ if (fillOpacity) this.V.fillOpacity = fillOpacity[0] + (fillOpacity[1] - fillOpacity[0]) * t;
228
+ if (stroke) this.V.stroke = (0, import_rendx_interpolate.interpolateColor)(stroke[0], stroke[1])(t);
229
+ if (strokeOpacity) this.V.strokeOpacity = strokeOpacity[0] + (strokeOpacity[1] - strokeOpacity[0]) * t;
230
+ }
231
+ };
232
+
233
+ // src/transforms/clip.ts
234
+ var import_rendx_ease2 = require("rendx-ease");
235
+ var import_rendx_path = require("rendx-path");
236
+ var _path, _ClipBoxTransform_instances, generatePath_fn;
237
+ var ClipBoxTransform = class extends BaseTransform {
238
+ constructor(clipPath) {
239
+ super();
240
+ __privateAdd(this, _ClipBoxTransform_instances);
241
+ this.type = void 0;
242
+ this.boundingBox = null;
243
+ __privateAdd(this, _path, null);
244
+ this.clipPath = clipPath;
245
+ }
246
+ direction(type) {
247
+ this.type = type;
248
+ return this;
249
+ }
250
+ box(box) {
251
+ this.boundingBox = box;
252
+ this.status = "start";
253
+ this._time = -1;
254
+ return this;
255
+ }
256
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
257
+ apply(_t) {
258
+ }
259
+ interpolate(time) {
260
+ if (this.status === "end") return;
261
+ if (this._time === -1) this._time = time;
262
+ const elapsed = time - this._time;
263
+ if (elapsed < this._delay) {
264
+ if (this.status === "init" || this.status === "waiting") {
265
+ this.status = "waiting";
266
+ return;
267
+ }
268
+ __privateMethod(this, _ClipBoxTransform_instances, generatePath_fn).call(this, 0);
269
+ this.clipPath.path = __privateGet(this, _path).toString();
270
+ this.status = "init";
271
+ return;
272
+ }
273
+ if (elapsed - 16 > this._delay + this._duration) {
274
+ if (this.status === "running") this.status = "clear";
275
+ else if (this.status === "clear") this.status = "end";
276
+ return;
277
+ }
278
+ this.status = "running";
279
+ const ease = import_rendx_ease2.easeMap[this._easing] ?? import_rendx_ease2.easeMap["linear"];
280
+ const t = ease(Math.max(0, Math.min(1, (elapsed - this._delay) / this._duration)));
281
+ __privateMethod(this, _ClipBoxTransform_instances, generatePath_fn).call(this, t);
282
+ this.clipPath.path = __privateGet(this, _path).toString();
283
+ }
284
+ };
285
+ _path = new WeakMap();
286
+ _ClipBoxTransform_instances = new WeakSet();
287
+ generatePath_fn = function(t) {
288
+ if (!this.boundingBox) return;
289
+ if (!__privateGet(this, _path)) __privateSet(this, _path, new import_rendx_path.Path());
290
+ else __privateGet(this, _path).clear();
291
+ const { x, y, width, height } = this.boundingBox;
292
+ const x0 = x, y0 = y, x1 = x + width, y1 = y + height;
293
+ if (this.type === "lr") {
294
+ const px = x0 + (x1 - x0) * t;
295
+ __privateGet(this, _path).M(px, y0);
296
+ __privateGet(this, _path).L(px, y1);
297
+ __privateGet(this, _path).L(x0, y1);
298
+ __privateGet(this, _path).L(x0, y0);
299
+ __privateGet(this, _path).Z();
300
+ } else if (this.type === "rl") {
301
+ const px = x1 + (x0 - x1) * t;
302
+ __privateGet(this, _path).M(px, y1);
303
+ __privateGet(this, _path).L(px, y0);
304
+ __privateGet(this, _path).L(x1, y0);
305
+ __privateGet(this, _path).L(x1, y1);
306
+ __privateGet(this, _path).Z();
307
+ } else if (this.type === "tb") {
308
+ const py = y0 + (y1 - y0) * t;
309
+ __privateGet(this, _path).M(x0, py);
310
+ __privateGet(this, _path).L(x1, py);
311
+ __privateGet(this, _path).L(x1, y0);
312
+ __privateGet(this, _path).L(x0, y0);
313
+ __privateGet(this, _path).Z();
314
+ } else if (this.type === "bt") {
315
+ const py = y1 + (y0 - y1) * t;
316
+ __privateGet(this, _path).M(x1, py);
317
+ __privateGet(this, _path).L(x0, py);
318
+ __privateGet(this, _path).L(x0, y1);
319
+ __privateGet(this, _path).L(x1, y1);
320
+ __privateGet(this, _path).Z();
321
+ }
322
+ };
323
+
324
+ // src/transforms/shape/arc.ts
325
+ var ArcTransform = class extends BaseTransform {
326
+ constructor(values) {
327
+ super();
328
+ this.attrs = {};
329
+ this.values = {};
330
+ this.V = values;
331
+ }
332
+ startAngle(a) {
333
+ if (!this.attrs.startAngle) {
334
+ this.attrs.startAngle = [this.V.startAngle, a];
335
+ } else {
336
+ this.attrs.startAngle = [this.attrs.startAngle[0], a];
337
+ }
338
+ this.status = "start";
339
+ this._time = -1;
340
+ return this;
341
+ }
342
+ endAngle(a) {
343
+ if (!this.attrs.endAngle) {
344
+ this.attrs.endAngle = [this.V.endAngle, a];
345
+ } else {
346
+ this.attrs.endAngle = [this.attrs.endAngle[0], a];
347
+ }
348
+ this.status = "start";
349
+ this._time = -1;
350
+ return this;
351
+ }
352
+ apply(t) {
353
+ const { startAngle, endAngle } = this.attrs;
354
+ if (startAngle) this.values.startAngle = startAngle[0] + (startAngle[1] - startAngle[0]) * t;
355
+ if (endAngle) this.values.endAngle = endAngle[0] + (endAngle[1] - endAngle[0]) * t;
356
+ }
357
+ onEnd() {
358
+ this.attrs = {};
359
+ }
360
+ };
361
+
362
+ // src/transforms/shape/sector.ts
363
+ var SectorTransform = class extends BaseTransform {
364
+ constructor(values) {
365
+ super();
366
+ this.attrs = {};
367
+ this.values = {};
368
+ this.V = values;
369
+ }
370
+ startAngle(a) {
371
+ if (!this.attrs.startAngle) {
372
+ this.attrs.startAngle = [this.V.startAngle, a];
373
+ } else {
374
+ this.attrs.startAngle = [this.attrs.startAngle[0], a];
375
+ }
376
+ this.status = "start";
377
+ this._time = -1;
378
+ return this;
379
+ }
380
+ endAngle(a) {
381
+ if (!this.attrs.endAngle) {
382
+ this.attrs.endAngle = [this.V.endAngle, a];
383
+ } else {
384
+ this.attrs.endAngle = [this.attrs.endAngle[0], a];
385
+ }
386
+ this.status = "start";
387
+ this._time = -1;
388
+ return this;
389
+ }
390
+ innerRadius(r) {
391
+ if (!this.attrs.innerRadius) {
392
+ this.attrs.innerRadius = [this.V.innerRadius, r];
393
+ } else {
394
+ this.attrs.innerRadius = [this.attrs.innerRadius[0], r];
395
+ }
396
+ this.status = "start";
397
+ this._time = -1;
398
+ return this;
399
+ }
400
+ outerRadius(r) {
401
+ if (!this.attrs.outerRadius) {
402
+ this.attrs.outerRadius = [this.V.outerRadius, r];
403
+ } else {
404
+ this.attrs.outerRadius = [this.attrs.outerRadius[0], r];
405
+ }
406
+ this.status = "start";
407
+ this._time = -1;
408
+ return this;
409
+ }
410
+ apply(t) {
411
+ const { startAngle, endAngle, innerRadius, outerRadius } = this.attrs;
412
+ if (startAngle) this.values.startAngle = startAngle[0] + (startAngle[1] - startAngle[0]) * t;
413
+ if (endAngle) this.values.endAngle = endAngle[0] + (endAngle[1] - endAngle[0]) * t;
414
+ if (innerRadius) this.values.innerRadius = innerRadius[0] + (innerRadius[1] - innerRadius[0]) * t;
415
+ if (outerRadius) this.values.outerRadius = outerRadius[0] + (outerRadius[1] - outerRadius[0]) * t;
416
+ }
417
+ onEnd() {
418
+ this.attrs = {};
419
+ }
420
+ };
421
+
422
+ // src/events/target.ts
423
+ var import_eventemitter3 = __toESM(require("eventemitter3"), 1);
424
+ var import_rendx_core = require("rendx-core");
425
+ var _emitter, _EventTarget_instances, getEmitter_fn;
426
+ var EventTarget = class {
427
+ constructor() {
428
+ __privateAdd(this, _EventTarget_instances);
429
+ __privateAdd(this, _emitter, null);
430
+ this.dispatcher = null;
431
+ }
432
+ setDispatcher(dispatcher) {
433
+ this.dispatcher = dispatcher;
434
+ }
435
+ on(event, listener, options) {
436
+ const { once = false, capture } = options || {};
437
+ if (capture) event = `capture-${event}`;
438
+ const emitter = __privateMethod(this, _EventTarget_instances, getEmitter_fn).call(this);
439
+ if (once) emitter.once(event, listener);
440
+ else emitter.on(event, listener);
441
+ }
442
+ off(event, listener, options) {
443
+ if (!__privateGet(this, _emitter)) return;
444
+ const { capture } = options || {};
445
+ if (capture) event = `capture-${event}`;
446
+ __privateGet(this, _emitter).off(event, listener);
447
+ }
448
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
449
+ emit(event, payload) {
450
+ if (!__privateGet(this, _emitter)) return;
451
+ __privateGet(this, _emitter).emit(event, payload);
452
+ }
453
+ eventNames() {
454
+ return __privateGet(this, _emitter) ? __privateGet(this, _emitter).eventNames() : [];
455
+ }
456
+ eventTypes() {
457
+ return this.eventNames().filter((name) => (0, import_rendx_core.isStr)(name)).map((name) => {
458
+ return name.startsWith("capture-") ? name.slice(8) : name;
459
+ });
460
+ }
461
+ listeners(event) {
462
+ return __privateGet(this, _emitter) ? __privateGet(this, _emitter).listeners(event) : [];
463
+ }
464
+ hasEvent(event) {
465
+ return __privateGet(this, _emitter) ? __privateGet(this, _emitter).listenerCount(event) > 0 : false;
466
+ }
467
+ dispatchEvent(evt) {
468
+ this.dispatcher?.process(evt);
469
+ }
470
+ };
471
+ _emitter = new WeakMap();
472
+ _EventTarget_instances = new WeakSet();
473
+ getEmitter_fn = function() {
474
+ if (!__privateGet(this, _emitter)) __privateSet(this, _emitter, new import_eventemitter3.default());
475
+ return __privateGet(this, _emitter);
476
+ };
477
+
478
+ // src/core/graphics.ts
479
+ var _nameMap, _classlist, _Graphics_instances, removeFromNameMap_fn, updateMat2d_fn, updateWorldMatrix_fn, updateEZ_fn;
480
+ var Graphics = class extends EventTarget {
481
+ constructor() {
482
+ super(...arguments);
483
+ __privateAdd(this, _Graphics_instances);
484
+ this.type = 0;
485
+ this.uid = (0, import_rendx_core2.uid8)();
486
+ this.name = "";
487
+ this.className = "";
488
+ this.parent = null;
489
+ this.children = [];
490
+ __privateAdd(this, _nameMap, /* @__PURE__ */ new Map());
491
+ this.z = 0;
492
+ this.visible = true;
493
+ this.display = true;
494
+ this.pointerEvents = true;
495
+ // 决定是否收到父级的影响
496
+ this.autoVisible = true;
497
+ this.autoDisplay = true;
498
+ this.autoPointerEvents = true;
499
+ this.autoNeedUpdate = true;
500
+ this.autoWorldMatrixNeedUpdate = true;
501
+ this.needUpdate = true;
502
+ this.worldMatrixNeedUpdate = true;
503
+ this.data = {};
504
+ this.ez = 0;
505
+ this.dirty = true;
506
+ __privateAdd(this, _classlist, []);
507
+ this._translate = import_gl_matrix.vec2.fromValues(0, 0);
508
+ this._rotate = 0;
509
+ this._scale = import_gl_matrix.vec2.fromValues(1, 1);
510
+ this.matrix = import_gl_matrix.mat2d.create();
511
+ this.worldMatrix = import_gl_matrix.mat2d.create();
512
+ this.transform = null;
513
+ }
514
+ /** 当前平移值 [tx, ty](只读) */
515
+ get translation() {
516
+ return this._translate;
517
+ }
518
+ /** 当前旋转弧度(只读) */
519
+ get rotation() {
520
+ return this._rotate;
521
+ }
522
+ /** 当前缩放值 [sx, sy](只读) */
523
+ get scaling() {
524
+ return this._scale;
525
+ }
526
+ setName(name) {
527
+ this.name = name;
528
+ return this;
529
+ }
530
+ setClassName(className) {
531
+ this.className = className;
532
+ __privateSet(this, _classlist, (0, import_rendx_core2.uniqueArray)(className.split(" ").filter(Boolean)));
533
+ return this;
534
+ }
535
+ addClassName(className) {
536
+ if (__privateGet(this, _classlist).includes(className)) return this;
537
+ __privateGet(this, _classlist).push(className);
538
+ this.className = __privateGet(this, _classlist).join(" ");
539
+ return this;
540
+ }
541
+ hasClassName(className) {
542
+ return __privateGet(this, _classlist).includes(className);
543
+ }
544
+ setVisible(visible, bySelf = true) {
545
+ if (!bySelf && !this.autoVisible) return this;
546
+ this.visible = visible;
547
+ if (bySelf) this.autoVisible = false;
548
+ if (this.children.length) {
549
+ for (let i = 0; i < this.children.length; i++) {
550
+ this.children[i].setVisible(visible, false);
551
+ }
552
+ }
553
+ this.setDirty(true);
554
+ return this;
555
+ }
556
+ setDisplay(display, bySelf = true) {
557
+ if (!bySelf && !this.autoDisplay) return this;
558
+ this.display = display;
559
+ if (bySelf) this.autoDisplay = false;
560
+ if (this.children.length) {
561
+ for (let i = 0; i < this.children.length; i++) {
562
+ this.children[i].setDisplay(display, false);
563
+ }
564
+ }
565
+ this.setDirty(true);
566
+ return this;
567
+ }
568
+ setPointerEvents(pointerEvents, bySelf = true) {
569
+ if (!bySelf && !this.autoPointerEvents) return this;
570
+ this.pointerEvents = pointerEvents;
571
+ if (bySelf) this.autoPointerEvents = false;
572
+ if (this.children.length) {
573
+ for (let i = 0; i < this.children.length; i++) {
574
+ this.children[i].setPointerEvents(pointerEvents, false);
575
+ }
576
+ }
577
+ return this;
578
+ }
579
+ setDirty(dirty) {
580
+ this.dirty = dirty;
581
+ if (this.parent && this.dirty) this.parent.setDirty(this.dirty);
582
+ if (!this.dirty) this.children.forEach((child) => child.setDirty(this.dirty));
583
+ return this;
584
+ }
585
+ /**
586
+ * 添加子节点。若 child 已有 parent 会先移除。
587
+ * @param child - 要添加的场景图节点
588
+ */
589
+ add(child) {
590
+ if (child.parent) child.parent.remove(child);
591
+ child.parent = this;
592
+ this.children.push(child);
593
+ if (__privateGet(this, _nameMap).has(child.name)) throw new Error(`The name "${child.name}" is already used.`);
594
+ if (child.name) __privateGet(this, _nameMap).set(child.name, child);
595
+ this.setDirty(true);
596
+ return this;
597
+ }
598
+ unshift(child) {
599
+ if (child.parent) child.parent.remove(child);
600
+ child.parent = this;
601
+ this.children.unshift(child);
602
+ __privateMethod(this, _Graphics_instances, removeFromNameMap_fn).call(this, child);
603
+ this.setDirty(true);
604
+ return this;
605
+ }
606
+ remove(child) {
607
+ const index = this.children.indexOf(child);
608
+ if (index !== -1) {
609
+ const node = this.children[index];
610
+ this.children.splice(index, 1);
611
+ __privateMethod(this, _Graphics_instances, removeFromNameMap_fn).call(this, node);
612
+ this.setDirty(true);
613
+ }
614
+ return this;
615
+ }
616
+ removeChildren() {
617
+ this.children.forEach((child) => child.parent = null);
618
+ this.children = [];
619
+ __privateGet(this, _nameMap).clear();
620
+ this.setDirty(true);
621
+ return this;
622
+ }
623
+ is(name) {
624
+ return this.name === name;
625
+ }
626
+ equals(target) {
627
+ return this.uid === target.uid;
628
+ }
629
+ /**
630
+ * 按名称查找子节点
631
+ * @param name - 节点名称
632
+ * @param deep - 是否递归搜索子树(默认 false 仅搜索直接children)
633
+ */
634
+ find(name, deep = false) {
635
+ let node = __privateGet(this, _nameMap).get(name);
636
+ if (node) return node;
637
+ if (deep) {
638
+ const queue = [...this.children];
639
+ while (queue.length > 0) {
640
+ const current = queue.shift();
641
+ node = __privateGet(current, _nameMap).get(name);
642
+ if (node) return node;
643
+ queue.push(...current.children);
644
+ }
645
+ }
646
+ return null;
647
+ }
648
+ /**
649
+ * 按 className 查询节点列表
650
+ * @param className - CSS 风格的类名
651
+ * @param deep - 是否递归搜索子树
652
+ */
653
+ query(className, deep = false) {
654
+ const result = [];
655
+ const queue = [...this.children];
656
+ while (queue.length > 0) {
657
+ const node = queue.shift();
658
+ if (node.hasClassName(className)) result.push(node);
659
+ if (deep) queue.push(...node.children);
660
+ }
661
+ return result;
662
+ }
663
+ has(name, deep = false) {
664
+ return this.find(name, deep) != null;
665
+ }
666
+ root() {
667
+ return this.parent ? this.parent.root() : this;
668
+ }
669
+ /** 根到当前节点的完整路径(从 root 到 this) */
670
+ path() {
671
+ return this.parent ? this.parent.path().concat(this) : [this];
672
+ }
673
+ source(target) {
674
+ return this.path().includes(target);
675
+ }
676
+ /** 深度优先遍历子树,包含自身 */
677
+ traverse(fn) {
678
+ fn(this);
679
+ for (let i = 0; i < this.children.length; i++) {
680
+ this.children[i].traverse(fn);
681
+ }
682
+ }
683
+ setZ(z) {
684
+ this.z = z;
685
+ return this;
686
+ }
687
+ getZIndex() {
688
+ return this.ez;
689
+ }
690
+ /**
691
+ * 设置本地矩阵(直接覆盖 translate/rotate/scale 计算的结果)
692
+ * @param matrix - [a, b, c, d, e, f] 2x3 仿射矩阵
693
+ * @param needUpdate - 是否触发世界矩阵更新(默认 true)
694
+ */
695
+ setMatrix(matrix, needUpdate = true) {
696
+ this.matrix = import_gl_matrix.mat2d.fromValues(...matrix);
697
+ this.needUpdate = needUpdate;
698
+ return this;
699
+ }
700
+ setWorldMatrix(matrix, needUpdate = true) {
701
+ this.worldMatrix = import_gl_matrix.mat2d.fromValues(...matrix);
702
+ this.worldMatrixNeedUpdate = needUpdate;
703
+ return this;
704
+ }
705
+ /**
706
+ * 设置平移
707
+ * @param tx - X 方向平移量(像素)
708
+ * @param ty - Y 方向平移量(像素)
709
+ */
710
+ translate(tx, ty) {
711
+ this._translate = import_gl_matrix.vec2.fromValues(tx, ty);
712
+ if (this.transform) {
713
+ this.transform.V.tx = tx;
714
+ this.transform.V.ty = ty;
715
+ }
716
+ if (this.autoNeedUpdate) this.needUpdate = true;
717
+ return this;
718
+ }
719
+ translateX(tx) {
720
+ this._translate[0] += tx;
721
+ if (this.transform) this.transform.V.tx = this._translate[0];
722
+ if (this.autoNeedUpdate) this.needUpdate = true;
723
+ return this;
724
+ }
725
+ translateY(ty) {
726
+ this._translate[1] += ty;
727
+ if (this.transform) this.transform.V.ty = this._translate[1];
728
+ if (this.autoNeedUpdate) this.needUpdate = true;
729
+ return this;
730
+ }
731
+ translateXY(tx, ty) {
732
+ this._translate[0] += tx;
733
+ this._translate[1] += ty;
734
+ if (this.transform) {
735
+ this.transform.V.tx = this._translate[0];
736
+ this.transform.V.ty = this._translate[1];
737
+ }
738
+ if (this.autoNeedUpdate) this.needUpdate = true;
739
+ return this;
740
+ }
741
+ rotate(radian) {
742
+ this._rotate = radian;
743
+ if (this.transform) this.transform.V.rotate = radian;
744
+ if (this.autoNeedUpdate) this.needUpdate = true;
745
+ return this;
746
+ }
747
+ rotateZ(radian) {
748
+ this._rotate += radian;
749
+ if (this.transform) this.transform.V.rotate = this._rotate;
750
+ if (this.autoNeedUpdate) this.needUpdate = true;
751
+ return this;
752
+ }
753
+ scale(sx, sy) {
754
+ this._scale = import_gl_matrix.vec2.fromValues(sx, sy);
755
+ if (this.transform) {
756
+ this.transform.V.sx = sx;
757
+ this.transform.V.sy = sy;
758
+ }
759
+ if (this.autoNeedUpdate) this.needUpdate = true;
760
+ return this;
761
+ }
762
+ scaleX(sx) {
763
+ this._scale[0] *= sx;
764
+ if (this.transform) this.transform.V.sx = this._scale[0];
765
+ if (this.autoNeedUpdate) this.needUpdate = true;
766
+ return this;
767
+ }
768
+ scaleY(sy) {
769
+ this._scale[1] *= sy;
770
+ if (this.transform) this.transform.V.sy = this._scale[1];
771
+ if (this.autoNeedUpdate) this.needUpdate = true;
772
+ return this;
773
+ }
774
+ scaleXY(sx, sy) {
775
+ this._scale[0] *= sx;
776
+ this._scale[1] *= sy;
777
+ if (this.transform) {
778
+ this.transform.V.sx = this._scale[0];
779
+ this.transform.V.sy = this._scale[1];
780
+ }
781
+ if (this.autoNeedUpdate) this.needUpdate = true;
782
+ return this;
783
+ }
784
+ /** 启用几何变换动画(GraphicsTransform),可链式配置 duration/delay/easing */
785
+ useTransform() {
786
+ if (this.transform) return this;
787
+ const [tx, ty] = this._translate;
788
+ const [sx, sy] = this._scale;
789
+ const rotate = this._rotate;
790
+ this.transform = new GraphicsTransform({ tx, ty, sx, sy, rotate });
791
+ return this;
792
+ }
793
+ renderable() {
794
+ return this.visible && this.display;
795
+ }
796
+ /** 检查是否需要重绘(自身或子树有脏标记/更新标记) */
797
+ sign() {
798
+ if (!this.display) return false;
799
+ if (this.dirty || this.needUpdate || this.worldMatrixNeedUpdate) return true;
800
+ for (let i = 0; i < this.children.length; i++) if (this.children[i].sign()) return true;
801
+ return false;
802
+ }
803
+ tick(time) {
804
+ if (!this.display) return;
805
+ if (this.transform) {
806
+ this.transform.interpolate(time);
807
+ if (this.transform.status === "running" || this.transform.status === "last") {
808
+ const { tx, ty, sx, sy, rotate } = this.transform.values;
809
+ if (!(0, import_rendx_core2.isNil)(tx) && !(0, import_rendx_core2.isNil)(ty)) this.translate(tx, ty);
810
+ if (!(0, import_rendx_core2.isNil)(rotate)) this.rotate(rotate);
811
+ if (!(0, import_rendx_core2.isNil)(sx) && !(0, import_rendx_core2.isNil)(sy)) this.scale(sx, sy);
812
+ }
813
+ }
814
+ for (let i = 0; i < this.children.length; i++) {
815
+ this.children[i].tick(time);
816
+ }
817
+ }
818
+ update() {
819
+ if (!this.display) return;
820
+ const needUpdateWorldMatrix = this.needUpdate || this.worldMatrixNeedUpdate;
821
+ __privateMethod(this, _Graphics_instances, updateMat2d_fn).call(this);
822
+ __privateMethod(this, _Graphics_instances, updateWorldMatrix_fn).call(this);
823
+ __privateMethod(this, _Graphics_instances, updateEZ_fn).call(this);
824
+ for (let i = 0; i < this.children.length; i++) {
825
+ const child = this.children[i];
826
+ child.worldMatrixNeedUpdate = needUpdateWorldMatrix;
827
+ child.update();
828
+ }
829
+ }
830
+ clear() {
831
+ this.data = {};
832
+ this.removeChildren();
833
+ }
834
+ dispose() {
835
+ this.clear();
836
+ this.parent = null;
837
+ }
838
+ };
839
+ _nameMap = new WeakMap();
840
+ _classlist = new WeakMap();
841
+ _Graphics_instances = new WeakSet();
842
+ removeFromNameMap_fn = function(g) {
843
+ if (__privateGet(this, _nameMap).has(g.name)) __privateGet(this, _nameMap).delete(g.name);
844
+ };
845
+ updateMat2d_fn = function() {
846
+ if (!this.needUpdate) return;
847
+ import_gl_matrix.mat2d.identity(this.matrix);
848
+ import_gl_matrix.mat2d.translate(this.matrix, this.matrix, this._translate);
849
+ import_gl_matrix.mat2d.rotate(this.matrix, this.matrix, this._rotate);
850
+ import_gl_matrix.mat2d.scale(this.matrix, this.matrix, this._scale);
851
+ this.needUpdate = false;
852
+ this.worldMatrixNeedUpdate = true;
853
+ };
854
+ updateWorldMatrix_fn = function() {
855
+ if (!this.worldMatrixNeedUpdate) return;
856
+ if (this.parent) import_gl_matrix.mat2d.multiply(this.worldMatrix, this.parent.worldMatrix, this.matrix);
857
+ else import_gl_matrix.mat2d.copy(this.worldMatrix, this.matrix);
858
+ this.worldMatrixNeedUpdate = false;
859
+ };
860
+ updateEZ_fn = function() {
861
+ this.ez = this.parent ? this.parent.ez + this.z : this.z;
862
+ };
863
+
864
+ // src/core/shape.ts
865
+ var import_rendx_bounding = require("rendx-bounding");
866
+ var import_rendx_core3 = require("rendx-core");
867
+ var Shape = class {
868
+ constructor() {
869
+ this.uid = (0, import_rendx_core3.uid8)();
870
+ this.type = 0;
871
+ this.name = "";
872
+ this.command = "";
873
+ this.boundingBox = new import_rendx_bounding.BoundingBox();
874
+ this.creator = null;
875
+ this.d = "";
876
+ this.p = null;
877
+ this.autoNeedUpdate = true;
878
+ this.needUpdate = true;
879
+ }
880
+ setBox(box) {
881
+ this.boundingBox = box;
882
+ }
883
+ /** 按属性名列表获取值(序列化用),避免 as any */
884
+ getProps(keys) {
885
+ const self = this;
886
+ return keys.map((k) => self[k]);
887
+ }
888
+ /** 接收节点属性(子类按需 override,如 TextShape 用于文本测量) */
889
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
890
+ setAttrs(_attrs2) {
891
+ }
892
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
893
+ options(..._args) {
894
+ }
895
+ /** 子类覆写此方法设置形状参数(如 CircleShape.from(cx, cy, r)) */
896
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
897
+ from(..._args) {
898
+ }
899
+ /** 构建形状:计算包围盒和路径数据,仅在 needUpdate 时执行 */
900
+ build() {
901
+ if (!this.needUpdate) return;
902
+ this.box();
903
+ this.needUpdate = false;
904
+ }
905
+ /** 返回 SVG 路径字符串(d 属性) */
906
+ path() {
907
+ return this.d;
908
+ }
909
+ /** 返回缓存的 Path2D 对象(用于 Canvas 命中检测) */
910
+ path2d() {
911
+ if (!this.p) this.p = new Path2D(this.d);
912
+ return this.p;
913
+ }
914
+ box() {
915
+ return this.boundingBox;
916
+ }
917
+ useTransform() {
918
+ return this;
919
+ }
920
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
921
+ tick(_time) {
922
+ }
923
+ /**
924
+ * 点命中检测(默认使用包围盒,子类可覆写用 path2d 精确检测)
925
+ * @param point - 本地坐标 [x, y]
926
+ */
927
+ hit(point) {
928
+ if (!this.boundingBox) this.box();
929
+ if (!this.boundingBox) return false;
930
+ return this.boundingBox.containsPoint(point[0], point[1]);
931
+ }
932
+ clear() {
933
+ this.needUpdate = true;
934
+ this.autoNeedUpdate = true;
935
+ }
936
+ dispose() {
937
+ this.clear();
938
+ }
939
+ };
940
+
941
+ // src/core/attributes.ts
942
+ var import_rendx_core4 = require("rendx-core");
943
+ var _boundingBox, _Attributes_instances, updateBoundingBoxForGradient_fn;
944
+ var Attributes = class {
945
+ constructor() {
946
+ __privateAdd(this, _Attributes_instances);
947
+ this.uid = (0, import_rendx_core4.uid8)();
948
+ this.name = "";
949
+ this.values = {};
950
+ this.autoNeedUpdate = true;
951
+ this.needUpdate = true;
952
+ this.transform = null;
953
+ this.clipBoxTransform = null;
954
+ __privateAdd(this, _boundingBox, null);
955
+ }
956
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
957
+ set(key, value) {
958
+ this.values[key] = value;
959
+ if (this.autoNeedUpdate) this.needUpdate = true;
960
+ return this;
961
+ }
962
+ get(key) {
963
+ return this.values[key];
964
+ }
965
+ /** 从对象批量设置属性(替换全部) */
966
+ from(attrs) {
967
+ this.values = attrs;
968
+ if (this.autoNeedUpdate) this.needUpdate = true;
969
+ return this;
970
+ }
971
+ /** 合并属性(保留已有值,追加新值) */
972
+ merge(attrs) {
973
+ Object.entries(attrs ?? {}).forEach(([key, value]) => this.values[key] = value);
974
+ if (this.autoNeedUpdate) this.needUpdate = true;
975
+ return this;
976
+ }
977
+ /** 关联渐变配置 */
978
+ gradient(gradientOptions) {
979
+ this.gradientOptions = gradientOptions;
980
+ if ((0, import_rendx_core4.isNil)(this.gradientOptions.id)) this.gradientOptions.id = this.uid;
981
+ this.values.fill = `url(#${this.gradientOptions.id})`;
982
+ if (this.autoNeedUpdate) this.needUpdate = true;
983
+ return this;
984
+ }
985
+ /** 关联裁剪路径 */
986
+ clip(clipPath) {
987
+ this.clipPath = clipPath;
988
+ if ((0, import_rendx_core4.isNil)(this.clipPath.id)) this.clipPath.id = this.uid;
989
+ this.values.clipPath = `url(#${this.clipPath.id})`;
990
+ if (this.autoNeedUpdate) this.needUpdate = true;
991
+ return this;
992
+ }
993
+ setBox(box) {
994
+ __privateSet(this, _boundingBox, box);
995
+ return this;
996
+ }
997
+ /** 启用属性动画(可对 opacity/fill/stroke 等做插值动画) */
998
+ useTransform() {
999
+ if (this.transform) return this;
1000
+ this.transform = new AttributeTransform(this.values);
1001
+ return this;
1002
+ }
1003
+ /** 启用裁剪框动画(lr/rl/tb/bt 方向的揭露动效) */
1004
+ useClipBoxTransform() {
1005
+ if (this.clipBoxTransform) return this;
1006
+ this.clip({ id: this.uid, path: "" });
1007
+ this.set("clipPath", `url(#${this.uid})`);
1008
+ this.clipBoxTransform = new ClipBoxTransform(this.clipPath);
1009
+ return this;
1010
+ }
1011
+ tick(time) {
1012
+ if (this.transform) {
1013
+ this.transform.interpolate(time);
1014
+ if (this.transform.status === "running" || this.transform.status === "last") this.needUpdate = true;
1015
+ }
1016
+ if (this.clipBoxTransform) {
1017
+ this.clipBoxTransform.interpolate(time);
1018
+ const { status } = this.clipBoxTransform;
1019
+ if (status === "init" || status === "running") this.needUpdate = true;
1020
+ if (status === "clear") {
1021
+ this.clipPath = void 0;
1022
+ delete this.values.clipPath;
1023
+ this.needUpdate = true;
1024
+ }
1025
+ }
1026
+ return this;
1027
+ }
1028
+ update() {
1029
+ if (!this.needUpdate) return;
1030
+ __privateMethod(this, _Attributes_instances, updateBoundingBoxForGradient_fn).call(this);
1031
+ this.needUpdate = false;
1032
+ }
1033
+ clear() {
1034
+ this.values = {};
1035
+ this.gradientOptions = void 0;
1036
+ this.clipPath = void 0;
1037
+ return this;
1038
+ }
1039
+ dispose() {
1040
+ this.clear();
1041
+ }
1042
+ };
1043
+ _boundingBox = new WeakMap();
1044
+ _Attributes_instances = new WeakSet();
1045
+ updateBoundingBoxForGradient_fn = function() {
1046
+ if (!__privateGet(this, _boundingBox)) return;
1047
+ if (!this.gradientOptions) return;
1048
+ if (this.gradientOptions.region) return;
1049
+ const { x, y, width, height } = __privateGet(this, _boundingBox);
1050
+ this.gradientOptions.region = [x, y, width, height];
1051
+ };
1052
+
1053
+ // src/core/canvas-hit.ts
1054
+ var import_rendx_core5 = require("rendx-core");
1055
+ var isEmptyOrNone = (v) => (0, import_rendx_core5.isEmpty)(v) || (0, import_rendx_core5.isNone)(v);
1056
+ function setCanvasRenderingContext2StrokeAttrs(ctx, attributes) {
1057
+ const { strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterlimit, strokeDasharray, strokeDashoffset } = attributes;
1058
+ if ((0, import_rendx_core5.isNum)(strokeWidth)) ctx.lineWidth = strokeWidth;
1059
+ if ((0, import_rendx_core5.isStr)(strokeLinecap)) ctx.lineCap = strokeLinecap;
1060
+ if ((0, import_rendx_core5.isStr)(strokeLinejoin)) ctx.lineJoin = strokeLinejoin;
1061
+ if ((0, import_rendx_core5.isNum)(strokeMiterlimit)) ctx.miterLimit = strokeMiterlimit;
1062
+ if ((0, import_rendx_core5.isNum)(strokeDashoffset)) ctx.lineDashOffset = strokeDashoffset;
1063
+ if ((0, import_rendx_core5.isStr)(strokeDasharray)) ctx.setLineDash(strokeDasharray.split(",").map((x) => Number(x.trim())));
1064
+ }
1065
+ var _ctx = null;
1066
+ var getCtx = () => {
1067
+ if (!_ctx && typeof OffscreenCanvas !== "undefined") {
1068
+ _ctx = new OffscreenCanvas(1, 1).getContext("2d");
1069
+ }
1070
+ return _ctx;
1071
+ };
1072
+ var checkHit = (method, path, point, style, strokeAttrs) => {
1073
+ const ctx = getCtx();
1074
+ if (!isEmptyOrNone(style) && ctx) {
1075
+ if (method === "isPointInPath") return ctx.isPointInPath(path, point[0], point[1]);
1076
+ if (method === "isPointInStroke") {
1077
+ ctx.save();
1078
+ if (strokeAttrs) setCanvasRenderingContext2StrokeAttrs(ctx, strokeAttrs);
1079
+ const flag = ctx.isPointInStroke(path, point[0], point[1]);
1080
+ ctx.restore();
1081
+ return flag;
1082
+ }
1083
+ }
1084
+ return false;
1085
+ };
1086
+ var isHit = (path, point, fill, stroke, strokeAttrs) => {
1087
+ if (!getCtx()) return false;
1088
+ if (checkHit("isPointInPath", path, point, fill)) return true;
1089
+ return checkHit("isPointInStroke", path, point, stroke, strokeAttrs);
1090
+ };
1091
+
1092
+ // src/core/image-loader.ts
1093
+ var _cache, _ImageLoader_instances, createEntry_fn;
1094
+ var ImageLoader = class {
1095
+ constructor() {
1096
+ __privateAdd(this, _ImageLoader_instances);
1097
+ __privateAdd(this, _cache, /* @__PURE__ */ new Map());
1098
+ /** 全局回调:任何图片加载完成时触发(用于重启渲染循环) */
1099
+ this.onChange = null;
1100
+ }
1101
+ load(src, onReady) {
1102
+ let entry = __privateGet(this, _cache).get(src);
1103
+ if (!entry) {
1104
+ entry = __privateMethod(this, _ImageLoader_instances, createEntry_fn).call(this, src);
1105
+ __privateGet(this, _cache).set(src, entry);
1106
+ }
1107
+ if (onReady && !entry.ready) entry.listeners.add(onReady);
1108
+ return entry.source;
1109
+ }
1110
+ get(src) {
1111
+ return __privateGet(this, _cache).get(src)?.source ?? null;
1112
+ }
1113
+ has(src) {
1114
+ return __privateGet(this, _cache).get(src)?.ready ?? false;
1115
+ }
1116
+ clear() {
1117
+ __privateGet(this, _cache).clear();
1118
+ }
1119
+ };
1120
+ _cache = new WeakMap();
1121
+ _ImageLoader_instances = new WeakSet();
1122
+ createEntry_fn = function(src) {
1123
+ const listeners = /* @__PURE__ */ new Set();
1124
+ const entry = { source: null, ready: false, listeners };
1125
+ const img = new Image();
1126
+ img.crossOrigin = "anonymous";
1127
+ img.onload = () => {
1128
+ entry.source = img;
1129
+ entry.ready = true;
1130
+ listeners.forEach((fn) => fn());
1131
+ listeners.clear();
1132
+ this.onChange?.();
1133
+ };
1134
+ img.src = src;
1135
+ return entry;
1136
+ };
1137
+ var imageLoader = new ImageLoader();
1138
+
1139
+ // src/scene/scene.ts
1140
+ var import_gl_matrix2 = require("gl-matrix");
1141
+ var _queue, _invertWorldMatrix, _layerMap;
1142
+ var Scene = class extends Graphics {
1143
+ constructor() {
1144
+ super(...arguments);
1145
+ this.type = 1;
1146
+ __privateAdd(this, _queue, []);
1147
+ __privateAdd(this, _invertWorldMatrix, null);
1148
+ /** 有序层列表(按 layerIndex 排序) */
1149
+ this.layers = [];
1150
+ /** 层名称 → Layer 快速查找 */
1151
+ __privateAdd(this, _layerMap, /* @__PURE__ */ new Map());
1152
+ }
1153
+ /** 注册一个 Layer(由 App 调用) */
1154
+ registerLayer(layer) {
1155
+ __privateGet(this, _layerMap).set(layer.layerName, layer);
1156
+ this.layers.push(layer);
1157
+ this.layers.sort((a, b) => a.layerIndex - b.layerIndex);
1158
+ super.add(layer);
1159
+ }
1160
+ /** 按名称获取 Layer */
1161
+ getLayer(name) {
1162
+ return __privateGet(this, _layerMap).get(name);
1163
+ }
1164
+ /** 移除 Layer(事件层不可移除) */
1165
+ removeLayer(name) {
1166
+ const layer = __privateGet(this, _layerMap).get(name);
1167
+ if (!layer || layer.isEventLayer) return;
1168
+ __privateGet(this, _layerMap).delete(name);
1169
+ this.layers = this.layers.filter((l) => l !== layer);
1170
+ super.remove(layer);
1171
+ layer.dispose();
1172
+ }
1173
+ /**
1174
+ * 默认 add:添加到 default 层(向下兼容)
1175
+ * 如果没有 layer,退回原行为(直接加到 Scene children)
1176
+ */
1177
+ add(child) {
1178
+ const defaultLayer = __privateGet(this, _layerMap).get("default");
1179
+ if (defaultLayer) {
1180
+ defaultLayer.add(child);
1181
+ } else {
1182
+ super.add(child);
1183
+ }
1184
+ return this;
1185
+ }
1186
+ /** 收集所有可渲染节点(type=3),按 ez 排序,带脏标记缓存 */
1187
+ getQueue() {
1188
+ if (this.dirty) {
1189
+ const queue = [];
1190
+ if (this.layers.length > 0) {
1191
+ for (const layer of this.layers) {
1192
+ if (!layer.isEventLayer) {
1193
+ queue.push(...layer.getQueue());
1194
+ }
1195
+ }
1196
+ } else {
1197
+ this.traverse((node) => {
1198
+ if (node.type === 3) queue.push(node);
1199
+ });
1200
+ }
1201
+ queue.sort((a, b) => a.ez - b.ez);
1202
+ this.setDirty(false);
1203
+ __privateSet(this, _queue, queue);
1204
+ }
1205
+ return __privateGet(this, _queue);
1206
+ }
1207
+ /** 跨层命中检测:从最高层向下搜索 */
1208
+ pick(point) {
1209
+ if (this.layers.length > 0) {
1210
+ for (let i = this.layers.length - 1; i >= 0; i--) {
1211
+ const layer = this.layers[i];
1212
+ if (layer.isEventLayer) continue;
1213
+ const queue = layer.getQueue();
1214
+ for (let j = queue.length - 1; j >= 0; j--) {
1215
+ const node = queue[j];
1216
+ if (node.hit(point)) return node;
1217
+ }
1218
+ }
1219
+ return void 0;
1220
+ }
1221
+ for (let i = __privateGet(this, _queue).length - 1; i >= 0; i--) {
1222
+ const node = __privateGet(this, _queue)[i];
1223
+ if (node.hit(point)) return node;
1224
+ }
1225
+ return void 0;
1226
+ }
1227
+ /**
1228
+ * 屏幕坐标 → 场景坐标(通过逆 worldMatrix 变换,缓存逆矩阵)
1229
+ * @param point - 画布像素坐标 [x, y]
1230
+ */
1231
+ position(point) {
1232
+ if (!__privateGet(this, _invertWorldMatrix)) __privateSet(this, _invertWorldMatrix, import_gl_matrix2.mat2d.invert(import_gl_matrix2.mat2d.create(), this.worldMatrix));
1233
+ return import_gl_matrix2.vec2.transformMat2d(import_gl_matrix2.vec2.create(), point, __privateGet(this, _invertWorldMatrix));
1234
+ }
1235
+ setMatrix(matrix, needUpdate) {
1236
+ __privateSet(this, _invertWorldMatrix, null);
1237
+ return super.setMatrix(matrix, needUpdate);
1238
+ }
1239
+ };
1240
+ _queue = new WeakMap();
1241
+ _invertWorldMatrix = new WeakMap();
1242
+ _layerMap = new WeakMap();
1243
+
1244
+ // src/scene/group.ts
1245
+ var Group = class extends Graphics {
1246
+ constructor() {
1247
+ super(...arguments);
1248
+ this.type = 2;
1249
+ }
1250
+ };
1251
+
1252
+ // src/scene/node.ts
1253
+ var import_gl_matrix3 = require("gl-matrix");
1254
+ var import_rendx_bounding15 = require("rendx-bounding");
1255
+
1256
+ // src/shapes/symbol.ts
1257
+ var import_rendx_bounding2 = require("rendx-bounding");
1258
+ var import_rendx_shape = require("rendx-shape");
1259
+ var import_rendx_path2 = require("rendx-path");
1260
+ var SymbolShape = class extends Shape {
1261
+ constructor() {
1262
+ super(...arguments);
1263
+ this.command = "path";
1264
+ this.r = 1;
1265
+ this.symbol = "circle";
1266
+ }
1267
+ options(symbol) {
1268
+ this.symbol = symbol;
1269
+ if (this.autoNeedUpdate) this.needUpdate = true;
1270
+ }
1271
+ from(r) {
1272
+ this.r = r;
1273
+ if (this.autoNeedUpdate) this.needUpdate = true;
1274
+ }
1275
+ build() {
1276
+ if (!this.needUpdate) return;
1277
+ if (!this.creator) this.creator = new import_rendx_path2.Path();
1278
+ else this.creator.clear();
1279
+ (0, import_rendx_shape.createSymbol)(this.creator, this.symbol, { cx: 0, cy: 0, r: this.r });
1280
+ this.d = this.creator.toString();
1281
+ this.p = null;
1282
+ this.box();
1283
+ this.needUpdate = false;
1284
+ }
1285
+ path() {
1286
+ return this.d;
1287
+ }
1288
+ box() {
1289
+ const { r } = this;
1290
+ this.boundingBox = import_rendx_bounding2.BoundingBox.fromPoints(-r, -r, r, r);
1291
+ return this.boundingBox;
1292
+ }
1293
+ };
1294
+
1295
+ // src/shapes/round.ts
1296
+ var import_rendx_bounding3 = require("rendx-bounding");
1297
+ var import_rendx_shape2 = require("rendx-shape");
1298
+ var import_rendx_path3 = require("rendx-path");
1299
+ var RoundShape = class extends Shape {
1300
+ constructor() {
1301
+ super(...arguments);
1302
+ this.command = "path";
1303
+ this.x = 0;
1304
+ this.y = 0;
1305
+ this.width = 0;
1306
+ this.height = 0;
1307
+ this.rx = void 0;
1308
+ this.ry = void 0;
1309
+ }
1310
+ options(rx, ry) {
1311
+ this.rx = rx;
1312
+ this.ry = ry ?? rx;
1313
+ if (this.autoNeedUpdate) this.needUpdate = true;
1314
+ }
1315
+ from(x, y, width, height) {
1316
+ this.x = x;
1317
+ this.y = y;
1318
+ this.width = width;
1319
+ this.height = height;
1320
+ if (this.autoNeedUpdate) this.needUpdate = true;
1321
+ }
1322
+ build() {
1323
+ if (!this.needUpdate) return;
1324
+ if (!this.creator) this.creator = new import_rendx_path3.Path();
1325
+ else this.creator.clear();
1326
+ const { x, y, width, height, rx, ry } = this;
1327
+ (0, import_rendx_shape2.createShape)(this.creator, "rect", { x, y, width, height, rx, ry });
1328
+ this.d = this.creator.toString();
1329
+ this.p = null;
1330
+ this.box();
1331
+ this.needUpdate = false;
1332
+ }
1333
+ path() {
1334
+ return this.d;
1335
+ }
1336
+ box() {
1337
+ const { x, y, width, height } = this;
1338
+ this.boundingBox = import_rendx_bounding3.BoundingBox.fromRect(x, y, width, height);
1339
+ return this.boundingBox;
1340
+ }
1341
+ };
1342
+
1343
+ // src/shapes/curve.ts
1344
+ var import_rendx_bounding4 = require("rendx-bounding");
1345
+ var import_rendx_shape3 = require("rendx-shape");
1346
+ var import_rendx_core6 = require("rendx-core");
1347
+ var import_rendx_path4 = require("rendx-path");
1348
+ var CurveShape = class extends Shape {
1349
+ constructor() {
1350
+ super(...arguments);
1351
+ this.command = "path";
1352
+ this.segments = [];
1353
+ this.curve = "linear";
1354
+ this.closed = false;
1355
+ }
1356
+ options(curve, closed) {
1357
+ this.curve = curve;
1358
+ this.closed = closed;
1359
+ if (this.autoNeedUpdate) this.needUpdate = true;
1360
+ }
1361
+ from(segments) {
1362
+ this.segments = segments;
1363
+ if (this.autoNeedUpdate) this.needUpdate = true;
1364
+ }
1365
+ build() {
1366
+ if (!this.needUpdate) return;
1367
+ if (!this.creator) this.creator = new import_rendx_path4.Path();
1368
+ else this.creator.clear();
1369
+ const { segments, curve, closed } = this;
1370
+ (0, import_rendx_shape3.createShape)(this.creator, "segmentLine", { segments, curve, closed });
1371
+ this.d = this.creator.toString();
1372
+ this.p = null;
1373
+ this.box();
1374
+ this.needUpdate = false;
1375
+ }
1376
+ path() {
1377
+ return this.d;
1378
+ }
1379
+ box() {
1380
+ const segments = this.segments.flat();
1381
+ const [x0, x1] = (0, import_rendx_core6.extent)(segments.map(([x]) => x));
1382
+ const [y0, y1] = (0, import_rendx_core6.extent)(segments.map(([, y]) => y));
1383
+ this.boundingBox = import_rendx_bounding4.BoundingBox.fromPoints(x0, y0, x1, y1);
1384
+ return this.boundingBox;
1385
+ }
1386
+ };
1387
+
1388
+ // src/shapes/area.ts
1389
+ var import_rendx_bounding5 = require("rendx-bounding");
1390
+ var import_rendx_shape4 = require("rendx-shape");
1391
+ var import_rendx_core7 = require("rendx-core");
1392
+ var import_rendx_path5 = require("rendx-path");
1393
+ var AreaShape = class extends Shape {
1394
+ constructor() {
1395
+ super(...arguments);
1396
+ this.command = "path";
1397
+ this.upperSegments = [];
1398
+ this.lowerSegments = [];
1399
+ this.curve = "linear";
1400
+ }
1401
+ options(curve) {
1402
+ this.curve = curve;
1403
+ if (this.autoNeedUpdate) this.needUpdate = true;
1404
+ }
1405
+ from(upperSegments, lowerSegments) {
1406
+ this.upperSegments = upperSegments;
1407
+ this.lowerSegments = lowerSegments;
1408
+ if (this.autoNeedUpdate) this.needUpdate = true;
1409
+ }
1410
+ build() {
1411
+ if (!this.needUpdate) return;
1412
+ if (!this.creator) this.creator = new import_rendx_path5.Path();
1413
+ else this.creator.clear();
1414
+ const { upperSegments, lowerSegments, curve } = this;
1415
+ (0, import_rendx_shape4.createShape)(this.creator, "segmentArea", { upperSegments, lowerSegments, curve });
1416
+ this.d = this.creator.toString();
1417
+ this.p = null;
1418
+ this.box();
1419
+ this.needUpdate = false;
1420
+ }
1421
+ path() {
1422
+ return this.d;
1423
+ }
1424
+ box() {
1425
+ const { upperSegments, lowerSegments } = this;
1426
+ const U = upperSegments.flat();
1427
+ const L = lowerSegments.flat();
1428
+ const P = U.concat(L);
1429
+ const [x0, x1] = (0, import_rendx_core7.extent)(P.map(([x]) => x));
1430
+ const [y0, y1] = (0, import_rendx_core7.extent)(P.map(([, y]) => y));
1431
+ this.boundingBox = import_rendx_bounding5.BoundingBox.fromPoints(x0, y0, x1, y1);
1432
+ return this.boundingBox;
1433
+ }
1434
+ };
1435
+
1436
+ // src/shapes/polygon.ts
1437
+ var import_rendx_bounding6 = require("rendx-bounding");
1438
+ var import_rendx_shape5 = require("rendx-shape");
1439
+ var import_rendx_core8 = require("rendx-core");
1440
+ var import_rendx_path6 = require("rendx-path");
1441
+ var PolygonShape = class extends Shape {
1442
+ constructor() {
1443
+ super(...arguments);
1444
+ this.command = "path";
1445
+ this.points = [];
1446
+ this.curve = "linear";
1447
+ this.closed = true;
1448
+ }
1449
+ options(curve, closed = true) {
1450
+ this.curve = curve;
1451
+ this.closed = closed;
1452
+ if (this.autoNeedUpdate) this.needUpdate = true;
1453
+ }
1454
+ from(points) {
1455
+ this.points = points;
1456
+ if (this.autoNeedUpdate) this.needUpdate = true;
1457
+ }
1458
+ build() {
1459
+ if (!this.needUpdate) return;
1460
+ if (!this.creator) this.creator = new import_rendx_path6.Path();
1461
+ else this.creator.clear();
1462
+ const { points, curve, closed } = this;
1463
+ (0, import_rendx_shape5.createShape)(this.creator, "line", { points, curve, closed });
1464
+ this.d = this.creator.toString();
1465
+ this.p = null;
1466
+ this.box();
1467
+ this.needUpdate = false;
1468
+ }
1469
+ path() {
1470
+ return this.d;
1471
+ }
1472
+ box() {
1473
+ const { points } = this;
1474
+ const [x0, x1] = (0, import_rendx_core8.extent)(points.map(([x]) => x));
1475
+ const [y0, y1] = (0, import_rendx_core8.extent)(points.map(([, y]) => y));
1476
+ this.boundingBox = import_rendx_bounding6.BoundingBox.fromPoints(x0, y0, x1, y1);
1477
+ return this.boundingBox;
1478
+ }
1479
+ };
1480
+
1481
+ // src/shapes/sector.ts
1482
+ var import_rendx_bounding7 = require("rendx-bounding");
1483
+ var import_rendx_shape6 = require("rendx-shape");
1484
+ var import_rendx_path7 = require("rendx-path");
1485
+ var SectorShape = class extends Shape {
1486
+ constructor() {
1487
+ super(...arguments);
1488
+ this.command = "path";
1489
+ this.r = 1;
1490
+ this.startAngle = 0;
1491
+ this.endAngle = Math.PI * 2;
1492
+ this.padAngle = void 0;
1493
+ this.innerRadius = 0;
1494
+ this.outerRadius = 1;
1495
+ this.rc = void 0;
1496
+ this.transform = null;
1497
+ }
1498
+ options(rc) {
1499
+ this.rc = rc;
1500
+ if (this.autoNeedUpdate) this.needUpdate = true;
1501
+ }
1502
+ from(r, startAngle, endAngle, innerRadius, outerRadius, padAngle) {
1503
+ this.r = r;
1504
+ this.startAngle = startAngle;
1505
+ this.endAngle = endAngle;
1506
+ this.innerRadius = innerRadius;
1507
+ this.outerRadius = outerRadius;
1508
+ this.padAngle = padAngle;
1509
+ if (this.transform) {
1510
+ this.transform.V.startAngle = startAngle;
1511
+ this.transform.V.endAngle = endAngle;
1512
+ this.transform.V.innerRadius = innerRadius;
1513
+ this.transform.V.outerRadius = outerRadius;
1514
+ }
1515
+ if (this.autoNeedUpdate) this.needUpdate = true;
1516
+ }
1517
+ build() {
1518
+ if (!this.needUpdate) return;
1519
+ if (!this.creator) this.creator = new import_rendx_path7.Path();
1520
+ else this.creator.clear();
1521
+ const { r, startAngle, endAngle, innerRadius, outerRadius, padAngle, rc } = this;
1522
+ (0, import_rendx_shape6.createShape)(this.creator, "sector", { cx: 0, cy: 0, r, startAngle, endAngle, innerRadius, outerRadius, padAngle, rc });
1523
+ this.d = this.creator.toString();
1524
+ this.p = null;
1525
+ this.box();
1526
+ this.needUpdate = false;
1527
+ }
1528
+ path() {
1529
+ return this.d;
1530
+ }
1531
+ box() {
1532
+ const { r, startAngle, endAngle, innerRadius, outerRadius } = this;
1533
+ const points = [];
1534
+ const r0 = innerRadius * r;
1535
+ const r1 = outerRadius * r;
1536
+ points.push([0, 0]);
1537
+ points.push([r1 * Math.cos(startAngle), r1 * Math.sin(startAngle)]);
1538
+ points.push([r1 * Math.cos(endAngle), r1 * Math.sin(endAngle)]);
1539
+ points.push([r0 * Math.cos(startAngle), r0 * Math.sin(startAngle)]);
1540
+ points.push([r0 * Math.cos(endAngle), r0 * Math.sin(endAngle)]);
1541
+ if (startAngle <= Math.PI && endAngle >= Math.PI) points.push([-r1, 0]);
1542
+ if (startAngle <= 0 && endAngle >= 0) points.push([r1, 0]);
1543
+ if (startAngle <= 1.5 * Math.PI && endAngle >= 1.5 * Math.PI) points.push([0, -r1]);
1544
+ if (startAngle <= 0.5 * Math.PI && endAngle >= 0.5 * Math.PI) points.push([0, r1]);
1545
+ const X = points.map(([x]) => x);
1546
+ const Y = points.map(([, y]) => y);
1547
+ const x0 = Math.min(...X);
1548
+ const x1 = Math.max(...X);
1549
+ const y0 = Math.min(...Y);
1550
+ const y1 = Math.max(...Y);
1551
+ this.boundingBox = import_rendx_bounding7.BoundingBox.fromPoints(x0, y0, x1, y1);
1552
+ return this.boundingBox;
1553
+ }
1554
+ useTransform() {
1555
+ if (this.transform) return this;
1556
+ const { startAngle, endAngle, innerRadius, outerRadius } = this;
1557
+ this.transform = new SectorTransform({ startAngle, endAngle, innerRadius, outerRadius });
1558
+ return this;
1559
+ }
1560
+ tick(time) {
1561
+ if (this.transform) {
1562
+ this.transform.interpolate(time);
1563
+ if (this.transform.status === "running" || this.transform.status === "last") {
1564
+ const { startAngle, endAngle, innerRadius, outerRadius } = this.transform.values;
1565
+ if (startAngle) this.startAngle = startAngle;
1566
+ if (endAngle) this.endAngle = endAngle;
1567
+ if (innerRadius) this.innerRadius = innerRadius;
1568
+ if (outerRadius) this.outerRadius = outerRadius;
1569
+ if (startAngle || endAngle || innerRadius || outerRadius) this.needUpdate = true;
1570
+ }
1571
+ }
1572
+ return this;
1573
+ }
1574
+ };
1575
+
1576
+ // src/shapes/arc.ts
1577
+ var import_rendx_bounding8 = require("rendx-bounding");
1578
+ var import_rendx_shape7 = require("rendx-shape");
1579
+ var import_rendx_core9 = require("rendx-core");
1580
+ var import_rendx_path8 = require("rendx-path");
1581
+ var ArcShape = class extends Shape {
1582
+ constructor() {
1583
+ super(...arguments);
1584
+ this.command = "path";
1585
+ this.r = 1;
1586
+ this.startAngle = 0;
1587
+ this.endAngle = Math.PI * 2;
1588
+ this.radius = 1;
1589
+ this.transform = null;
1590
+ }
1591
+ from(r, startAngle, endAngle, radius) {
1592
+ this.r = r;
1593
+ this.startAngle = startAngle;
1594
+ this.endAngle = endAngle;
1595
+ this.radius = radius;
1596
+ if (this.transform) {
1597
+ this.transform.V.startAngle = startAngle;
1598
+ this.transform.V.endAngle = endAngle;
1599
+ }
1600
+ if (this.autoNeedUpdate) this.needUpdate = true;
1601
+ }
1602
+ build() {
1603
+ if (!this.needUpdate) return;
1604
+ if (!this.creator) this.creator = new import_rendx_path8.Path();
1605
+ else this.creator.clear();
1606
+ const { r, startAngle, endAngle, radius } = this;
1607
+ (0, import_rendx_shape7.createShape)(this.creator, "arc", { cx: 0, cy: 0, r, startAngle, endAngle, radius });
1608
+ this.d = this.creator.toString();
1609
+ this.p = null;
1610
+ this.box();
1611
+ this.needUpdate = false;
1612
+ }
1613
+ path() {
1614
+ return this.d;
1615
+ }
1616
+ box() {
1617
+ const { r, startAngle, endAngle, radius } = this;
1618
+ const points = [];
1619
+ const r1 = r * radius;
1620
+ const midAngle = (startAngle + endAngle) / 2;
1621
+ points.push([r1 * Math.cos(startAngle), r1 * Math.sin(startAngle)]);
1622
+ points.push([r1 * Math.cos(midAngle), r1 * Math.sin(midAngle)]);
1623
+ points.push([r1 * Math.cos(endAngle), r1 * Math.sin(endAngle)]);
1624
+ const X = points.map(([x]) => x);
1625
+ const Y = points.map(([, y]) => y);
1626
+ const [x0, x1] = (0, import_rendx_core9.extent)(X);
1627
+ const [y0, y1] = (0, import_rendx_core9.extent)(Y);
1628
+ this.boundingBox = import_rendx_bounding8.BoundingBox.fromPoints(x0, y0, x1, y1);
1629
+ return this.boundingBox;
1630
+ }
1631
+ useTransform() {
1632
+ if (this.transform) return this;
1633
+ this.transform = new ArcTransform({ startAngle: this.startAngle, endAngle: this.endAngle });
1634
+ return this;
1635
+ }
1636
+ tick(time) {
1637
+ if (this.transform) {
1638
+ this.transform.interpolate(time);
1639
+ if (this.transform.status === "running" || this.transform.status === "last") {
1640
+ const { startAngle, endAngle } = this.transform.values;
1641
+ if (startAngle) this.startAngle = startAngle;
1642
+ if (endAngle) this.endAngle = endAngle;
1643
+ if (startAngle || endAngle) this.needUpdate = true;
1644
+ }
1645
+ }
1646
+ return this;
1647
+ }
1648
+ };
1649
+
1650
+ // src/shapes/path.ts
1651
+ var PathShape = class extends Shape {
1652
+ constructor() {
1653
+ super(...arguments);
1654
+ this.command = "path";
1655
+ }
1656
+ from(d) {
1657
+ this.d = d;
1658
+ this.p = null;
1659
+ }
1660
+ };
1661
+
1662
+ // src/shapes/text.ts
1663
+ var import_rendx_bounding9 = require("rendx-bounding");
1664
+ var _attrs;
1665
+ var _TextShape = class _TextShape extends Shape {
1666
+ constructor() {
1667
+ super(...arguments);
1668
+ this.command = "text";
1669
+ this.x = 0;
1670
+ this.y = 0;
1671
+ this.text = "";
1672
+ /** 实例级文本测量函数,优先于 `defaultMeasure` */
1673
+ this.measure = null;
1674
+ /** 当前绑定的属性(Node.update → shape.setAttrs 注入,供测量函数读取字体信息) */
1675
+ __privateAdd(this, _attrs, {});
1676
+ }
1677
+ setAttrs(attrs) {
1678
+ __privateSet(this, _attrs, attrs);
1679
+ }
1680
+ from(text, x, y) {
1681
+ this.x = x;
1682
+ this.y = y;
1683
+ this.text = text;
1684
+ if (this.autoNeedUpdate) this.needUpdate = true;
1685
+ }
1686
+ build() {
1687
+ if (!this.needUpdate) return;
1688
+ this.box();
1689
+ this.needUpdate = false;
1690
+ }
1691
+ box() {
1692
+ const measureFn = this.measure ?? _TextShape.defaultMeasure;
1693
+ if (measureFn && this.text) {
1694
+ const bb = measureFn(this.text, __privateGet(this, _attrs));
1695
+ if (bb) {
1696
+ this.boundingBox = import_rendx_bounding9.BoundingBox.fromRect(this.x, this.y - bb.height, bb.width, bb.height);
1697
+ return this.boundingBox;
1698
+ }
1699
+ }
1700
+ return this.boundingBox;
1701
+ }
1702
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1703
+ hit(_point) {
1704
+ if (this.boundingBox && !this.boundingBox.empty) {
1705
+ return this.boundingBox.containsPoint(_point[0], _point[1]);
1706
+ }
1707
+ return false;
1708
+ }
1709
+ };
1710
+ _attrs = new WeakMap();
1711
+ /**
1712
+ * 全局默认文本测量函数。
1713
+ * 使用者通过 `TextShape.defaultMeasure = fn` 注入,
1714
+ * 所有 TextShape 实例默认使用此函数(除非实例级覆盖)。
1715
+ *
1716
+ * @example
1717
+ * ```ts
1718
+ * import {getTextBoundingBox} from 'rendx-dom';
1719
+ * TextShape.defaultMeasure = (text, attrs) =>
1720
+ * getTextBoundingBox({fontSize: attrs.fontSize, fontFamily: attrs.fontFamily}, text);
1721
+ * ```
1722
+ */
1723
+ _TextShape.defaultMeasure = null;
1724
+ var TextShape = _TextShape;
1725
+
1726
+ // src/shapes/line.ts
1727
+ var import_rendx_bounding10 = require("rendx-bounding");
1728
+ var LineShape = class extends Shape {
1729
+ constructor() {
1730
+ super(...arguments);
1731
+ this.command = "line";
1732
+ this.x1 = 0;
1733
+ this.y1 = 0;
1734
+ this.x2 = 1;
1735
+ this.y2 = 1;
1736
+ }
1737
+ /**
1738
+ * 设置线段端点
1739
+ * @param x1 - 起点 X
1740
+ * @param y1 - 起点 Y
1741
+ * @param x2 - 终点 X
1742
+ * @param y2 - 终点 Y
1743
+ */
1744
+ from(x1, y1, x2, y2) {
1745
+ this.x1 = x1;
1746
+ this.y1 = y1;
1747
+ this.x2 = x2;
1748
+ this.y2 = y2;
1749
+ this.d = `M${x1} ${y1} L${x2} ${y2}`;
1750
+ this.p = null;
1751
+ if (this.autoNeedUpdate) this.needUpdate = true;
1752
+ }
1753
+ path2d() {
1754
+ if (!this.p) this.p = new Path2D(this.d);
1755
+ return this.p;
1756
+ }
1757
+ box() {
1758
+ const { x1, y1, x2, y2 } = this;
1759
+ this.boundingBox = import_rendx_bounding10.BoundingBox.fromPoints(x1, y1, x2, y2);
1760
+ return this.boundingBox;
1761
+ }
1762
+ };
1763
+
1764
+ // src/shapes/rect.ts
1765
+ var import_rendx_bounding11 = require("rendx-bounding");
1766
+ var RectShape = class extends Shape {
1767
+ constructor() {
1768
+ super(...arguments);
1769
+ this.command = "rect";
1770
+ this.x = 0;
1771
+ this.y = 0;
1772
+ this.width = 1;
1773
+ this.height = 1;
1774
+ }
1775
+ /**
1776
+ * 设置矩形参数
1777
+ * @param x - 左上角 X
1778
+ * @param y - 左上角 Y
1779
+ * @param width - 宽度
1780
+ * @param height - 高度
1781
+ */
1782
+ from(x, y, width, height) {
1783
+ this.x = x;
1784
+ this.y = y;
1785
+ this.width = width;
1786
+ this.height = height;
1787
+ }
1788
+ hit(point) {
1789
+ const [px, py] = point;
1790
+ const { x, y, width, height } = this;
1791
+ return x <= px && px <= x + width && y <= py && py <= y + height;
1792
+ }
1793
+ box() {
1794
+ const { x, y, width, height } = this;
1795
+ this.boundingBox = import_rendx_bounding11.BoundingBox.fromRect(x, y, width, height);
1796
+ return this.boundingBox;
1797
+ }
1798
+ };
1799
+
1800
+ // src/shapes/circle.ts
1801
+ var import_rendx_bounding12 = require("rendx-bounding");
1802
+ var CircleShape = class extends Shape {
1803
+ constructor() {
1804
+ super(...arguments);
1805
+ this.command = "circle";
1806
+ this.cx = 0;
1807
+ this.cy = 0;
1808
+ this.r = 1;
1809
+ }
1810
+ /**
1811
+ * 设置圆形参数
1812
+ * @param cx - 圆心 X
1813
+ * @param cy - 圆心 Y
1814
+ * @param r - 半径
1815
+ */
1816
+ from(cx, cy, r) {
1817
+ this.cx = cx;
1818
+ this.cy = cy;
1819
+ this.r = r;
1820
+ }
1821
+ hit(point) {
1822
+ const dx = point[0] - this.cx;
1823
+ const dy = point[1] - this.cy;
1824
+ return Math.sqrt(dx * dx + dy * dy) <= this.r;
1825
+ }
1826
+ box() {
1827
+ const { cx, cy, r } = this;
1828
+ this.boundingBox = import_rendx_bounding12.BoundingBox.fromPoints(cx - r, cy - r, cx + r, cy + r);
1829
+ return this.boundingBox;
1830
+ }
1831
+ };
1832
+
1833
+ // src/shapes/image.ts
1834
+ var import_rendx_bounding13 = require("rendx-bounding");
1835
+ var ImageShape = class extends Shape {
1836
+ constructor() {
1837
+ super(...arguments);
1838
+ this.command = "image";
1839
+ this.src = "";
1840
+ this.x = 0;
1841
+ this.y = 0;
1842
+ this.width = 0;
1843
+ this.height = 0;
1844
+ this.source = null;
1845
+ }
1846
+ from(src, x, y, width, height) {
1847
+ this.x = x;
1848
+ this.y = y;
1849
+ this.width = width;
1850
+ this.height = height;
1851
+ if (src !== this.src) {
1852
+ this.src = src;
1853
+ this.source = imageLoader.load(src, () => {
1854
+ this.source = imageLoader.get(src);
1855
+ this.needUpdate = true;
1856
+ });
1857
+ }
1858
+ if (this.autoNeedUpdate) this.needUpdate = true;
1859
+ return this;
1860
+ }
1861
+ /** 直接传入已加载的图片对象(跳过 loader) */
1862
+ fromElement(el, x, y, width, height) {
1863
+ this.source = el;
1864
+ this.x = x;
1865
+ this.y = y;
1866
+ this.width = width;
1867
+ this.height = height;
1868
+ if (this.autoNeedUpdate) this.needUpdate = true;
1869
+ return this;
1870
+ }
1871
+ hit(point) {
1872
+ const [px, py] = point;
1873
+ const { x, y, width, height } = this;
1874
+ return x <= px && px <= x + width && y <= py && py <= y + height;
1875
+ }
1876
+ box() {
1877
+ const { x, y, width, height } = this;
1878
+ this.boundingBox = import_rendx_bounding13.BoundingBox.fromRect(x, y, width, height);
1879
+ return this.boundingBox;
1880
+ }
1881
+ };
1882
+
1883
+ // src/shapes/rect-buffer.ts
1884
+ var import_rendx_bounding14 = require("rendx-bounding");
1885
+ var import_rendx_shape8 = require("rendx-shape");
1886
+ var import_rendx_path9 = require("rendx-path");
1887
+ var RectBufferShape = class extends Shape {
1888
+ constructor() {
1889
+ super(...arguments);
1890
+ this.type = 3;
1891
+ this.command = "path";
1892
+ this.mode = "render";
1893
+ this.buffer = new Float32Array(0);
1894
+ this.hitIndex = -1;
1895
+ }
1896
+ from(buffer) {
1897
+ this.buffer = buffer;
1898
+ if (this.autoNeedUpdate) this.needUpdate = true;
1899
+ }
1900
+ build() {
1901
+ if (!this.needUpdate) return;
1902
+ if (this.mode === "render") {
1903
+ if (!this.creator) this.creator = new import_rendx_path9.Path();
1904
+ else this.creator.clear();
1905
+ const { buffer } = this;
1906
+ for (let i = 0; i < buffer.length; i += 4) {
1907
+ const x = buffer[i];
1908
+ const y = buffer[i + 1];
1909
+ const width = buffer[i + 2];
1910
+ const height = buffer[i + 3];
1911
+ (0, import_rendx_shape8.createShape)(this.creator, "rect", { x, y, width, height });
1912
+ }
1913
+ this.d = this.creator.toString();
1914
+ this.p = null;
1915
+ }
1916
+ this.needUpdate = false;
1917
+ }
1918
+ hit(point) {
1919
+ const [px, py] = point;
1920
+ const { buffer } = this;
1921
+ for (let i = 0; i < buffer.length; i += 4) {
1922
+ const x = buffer[i];
1923
+ const y = buffer[i + 1];
1924
+ const width = buffer[i + 2];
1925
+ const height = buffer[i + 3];
1926
+ if (x <= px && px <= x + width && y <= py && py <= y + height) {
1927
+ this.hitIndex = Math.floor(i / 4);
1928
+ return true;
1929
+ }
1930
+ }
1931
+ this.hitIndex = -1;
1932
+ return false;
1933
+ }
1934
+ box() {
1935
+ const { buffer } = this;
1936
+ let x0 = Infinity;
1937
+ let y0 = Infinity;
1938
+ let x1 = -Infinity;
1939
+ let y1 = -Infinity;
1940
+ for (let i = 0; i < buffer.length; i += 4) {
1941
+ const x = buffer[i];
1942
+ const y = buffer[i + 1];
1943
+ const width = buffer[i + 2];
1944
+ const height = buffer[i + 3];
1945
+ x0 = Math.min(x0, x);
1946
+ y0 = Math.min(y0, y);
1947
+ x1 = Math.max(x1, x + width);
1948
+ y1 = Math.max(y1, y + height);
1949
+ }
1950
+ this.boundingBox = import_rendx_bounding14.BoundingBox.fromPoints(x0, y0, x1, y1);
1951
+ return this.boundingBox;
1952
+ }
1953
+ };
1954
+
1955
+ // src/shapes/shape.ts
1956
+ var shapes = {
1957
+ text: TextShape,
1958
+ circle: CircleShape,
1959
+ rect: RectShape,
1960
+ line: LineShape,
1961
+ path: PathShape,
1962
+ curve: CurveShape,
1963
+ area: AreaShape,
1964
+ polygon: PolygonShape,
1965
+ sector: SectorShape,
1966
+ arc: ArcShape,
1967
+ symbol: SymbolShape,
1968
+ round: RoundShape,
1969
+ rectBuffer: RectBufferShape,
1970
+ image: ImageShape
1971
+ };
1972
+ var createShape8 = (type) => {
1973
+ const Ctor = shapes[type];
1974
+ if (!Ctor) throw new Error(`Unknown shape type: ${type}`);
1975
+ return new Ctor();
1976
+ };
1977
+
1978
+ // src/scene/node.ts
1979
+ var _invertWorldMatrix2;
1980
+ var _Node = class _Node extends Graphics {
1981
+ constructor(shape, attrs) {
1982
+ super();
1983
+ this.type = 3;
1984
+ /** Shape 注册类型名(如 'rect', 'circle' 等),序列化时使用 */
1985
+ this.shapeType = "";
1986
+ __privateAdd(this, _invertWorldMatrix2, null);
1987
+ this.shape = shape;
1988
+ this.attrs = attrs;
1989
+ }
1990
+ /**
1991
+ * 创建指定类型的节点(推荐使用此工厂方法而非直接 new)
1992
+ * @param type - 形状类型:'circle' | 'rect' | 'line' | 'path' | 'text' | 'image'
1993
+ * @param values - 视觉属性(fill/stroke/opacity/fontSize 等)
1994
+ */
1995
+ static create(type, values = {}) {
1996
+ const shape = createShape8(type);
1997
+ const attrs = new Attributes().from(values);
1998
+ const node = new _Node(shape, attrs);
1999
+ node.shapeType = type;
2000
+ return node;
2001
+ }
2002
+ tick(time) {
2003
+ if (!this.display) return;
2004
+ this.shape.tick(time);
2005
+ this.attrs.tick(time);
2006
+ super.tick(time);
2007
+ }
2008
+ update() {
2009
+ super.update();
2010
+ this.shape.setAttrs(this.attrs.values);
2011
+ this.shape.build();
2012
+ this.attrs.setBox(this.shape.boundingBox);
2013
+ this.attrs.update();
2014
+ __privateSet(this, _invertWorldMatrix2, null);
2015
+ }
2016
+ sign() {
2017
+ return super.sign() || this.shape.needUpdate || this.attrs.needUpdate;
2018
+ }
2019
+ /**
2020
+ * 计算节点在世界坐标系中的轴对齐包围盒 (AABB)。
2021
+ * 通过 worldMatrix 变换本地 boundingBox 的四个角点,
2022
+ * 返回变换后的包围盒。若本地包围盒不可用,返回 null。
2023
+ */
2024
+ getWorldBBox() {
2025
+ const bb = this.shape.boundingBox;
2026
+ if (!bb || bb.empty) return null;
2027
+ const m = this.worldMatrix;
2028
+ const x0 = bb.x, y0 = bb.y, x1 = bb.right, y1 = bb.bottom;
2029
+ let wx, wy;
2030
+ let minX, maxX, minY, maxY;
2031
+ wx = m[0] * x0 + m[2] * y0 + m[4];
2032
+ wy = m[1] * x0 + m[3] * y0 + m[5];
2033
+ minX = maxX = wx;
2034
+ minY = maxY = wy;
2035
+ wx = m[0] * x1 + m[2] * y0 + m[4];
2036
+ wy = m[1] * x1 + m[3] * y0 + m[5];
2037
+ if (wx < minX) minX = wx;
2038
+ if (wx > maxX) maxX = wx;
2039
+ if (wy < minY) minY = wy;
2040
+ if (wy > maxY) maxY = wy;
2041
+ wx = m[0] * x1 + m[2] * y1 + m[4];
2042
+ wy = m[1] * x1 + m[3] * y1 + m[5];
2043
+ if (wx < minX) minX = wx;
2044
+ if (wx > maxX) maxX = wx;
2045
+ if (wy < minY) minY = wy;
2046
+ if (wy > maxY) maxY = wy;
2047
+ wx = m[0] * x0 + m[2] * y1 + m[4];
2048
+ wy = m[1] * x0 + m[3] * y1 + m[5];
2049
+ if (wx < minX) minX = wx;
2050
+ if (wx > maxX) maxX = wx;
2051
+ if (wy < minY) minY = wy;
2052
+ if (wy > maxY) maxY = wy;
2053
+ return import_rendx_bounding15.BoundingBox.fromPoints(minX, minY, maxX, maxY);
2054
+ }
2055
+ /**
2056
+ * 命中检测:将屏幕坐标通过逆世界矩阵变换为本地坐标,然后检测是否命中
2057
+ * @param point - 场景坐标 [x, y]
2058
+ * @returns 命中时返回自身,否则 undefined
2059
+ */
2060
+ hit(point) {
2061
+ if (!this.display || !this.pointerEvents) return;
2062
+ if (!__privateGet(this, _invertWorldMatrix2)) __privateSet(this, _invertWorldMatrix2, import_gl_matrix3.mat2d.invert(import_gl_matrix3.mat2d.create(), this.worldMatrix));
2063
+ const local = import_gl_matrix3.vec2.transformMat2d(import_gl_matrix3.vec2.create(), import_gl_matrix3.vec2.fromValues(...point), __privateGet(this, _invertWorldMatrix2));
2064
+ let flag = this.shape.hit(local);
2065
+ const { type, command } = this.shape;
2066
+ if (type === 0 && (command === "path" || command === "line")) {
2067
+ const { fill, stroke } = this.attrs.values;
2068
+ flag = isHit(this.shape.path2d(), local, fill, stroke, this.attrs.values);
2069
+ }
2070
+ return flag ? this : void 0;
2071
+ }
2072
+ };
2073
+ _invertWorldMatrix2 = new WeakMap();
2074
+ var Node = _Node;
2075
+
2076
+ // src/renderers/renderer.ts
2077
+ var import_gl_matrix4 = require("gl-matrix");
2078
+ var import_rendx_core10 = require("rendx-core");
2079
+ var import_rendx_canvas = require("rendx-canvas");
2080
+ var import_rendx_svg = require("rendx-svg");
2081
+ var DEFAULT_CONFIG = {
2082
+ width: 800,
2083
+ height: 600,
2084
+ renderer: "canvas"
2085
+ };
2086
+ var drawText = (r, n) => {
2087
+ const { x, y, text } = n.shape;
2088
+ r.text(text, x, y);
2089
+ };
2090
+ var drawCircle = (r, n) => {
2091
+ const { cx, cy, r: radius } = n.shape;
2092
+ r.circle(cx, cy, radius);
2093
+ };
2094
+ var drawRect = (r, n) => {
2095
+ const { x, y, width, height } = n.shape;
2096
+ r.rect(x, y, width, height);
2097
+ };
2098
+ var drawLine = (r, n) => {
2099
+ const { x1, y1, x2, y2 } = n.shape;
2100
+ r.line(x1, y1, x2, y2);
2101
+ };
2102
+ var drawPath = (r, n) => {
2103
+ r.path(n.shape.path());
2104
+ };
2105
+ var drawImage = (r, n) => {
2106
+ const { source, x, y, width, height } = n.shape;
2107
+ if (!source) return;
2108
+ r.image(source, x, y, width, height);
2109
+ };
2110
+ var DRAW_MAP = {
2111
+ text: drawText,
2112
+ circle: drawCircle,
2113
+ rect: drawRect,
2114
+ line: drawLine,
2115
+ path: drawPath,
2116
+ image: drawImage
2117
+ };
2118
+ var _renderer, _Renderer_instances, createRenderer_fn, computeViewMatrix_fn;
2119
+ var Renderer = class {
2120
+ constructor(cfg) {
2121
+ __privateAdd(this, _Renderer_instances);
2122
+ __privateAdd(this, _renderer);
2123
+ this.viewMatrix = import_gl_matrix4.mat2d.create();
2124
+ this.cfg = (0, import_rendx_core10.defaultsDeep)(cfg, [DEFAULT_CONFIG]);
2125
+ __privateSet(this, _renderer, __privateMethod(this, _Renderer_instances, createRenderer_fn).call(this));
2126
+ __privateMethod(this, _Renderer_instances, computeViewMatrix_fn).call(this);
2127
+ }
2128
+ get el() {
2129
+ return __privateGet(this, _renderer).el;
2130
+ }
2131
+ /** 客户端坐标(clientX/Y) → 画布局部坐标 */
2132
+ position(point) {
2133
+ const rect = __privateGet(this, _renderer).el.getBoundingClientRect();
2134
+ return [point[0] - rect.left, point[1] - rect.top];
2135
+ }
2136
+ resize(size) {
2137
+ __privateGet(this, _renderer).resize(size);
2138
+ this.cfg.width = size.width;
2139
+ this.cfg.height = size.height;
2140
+ __privateMethod(this, _Renderer_instances, computeViewMatrix_fn).call(this);
2141
+ }
2142
+ /** 绘制渲染队列 */
2143
+ draw(queue) {
2144
+ const r = __privateGet(this, _renderer);
2145
+ r.clear();
2146
+ for (let i = 0; i < queue.length; i++) {
2147
+ const node = queue[i];
2148
+ if (!node.renderable()) continue;
2149
+ r.save();
2150
+ const { attrs } = node;
2151
+ if (attrs.gradientOptions) r.gradient(attrs.gradientOptions);
2152
+ if (attrs.clipPath) r.clipPath(attrs.clipPath);
2153
+ r.setTransform(...node.worldMatrix);
2154
+ r.setAttributes(attrs.values);
2155
+ const draw = DRAW_MAP[node.shape.command];
2156
+ if (draw) draw(r, node);
2157
+ r.restore();
2158
+ }
2159
+ }
2160
+ clear() {
2161
+ __privateGet(this, _renderer).clear();
2162
+ }
2163
+ dispose() {
2164
+ __privateGet(this, _renderer).dispose();
2165
+ }
2166
+ };
2167
+ _renderer = new WeakMap();
2168
+ _Renderer_instances = new WeakSet();
2169
+ createRenderer_fn = function() {
2170
+ const { width, height, renderer } = this.cfg;
2171
+ if (renderer && typeof renderer === "object") return renderer;
2172
+ return renderer === "svg" ? new import_rendx_svg.SvgRenderer({ width, height }) : new import_rendx_canvas.CanvasRenderer({ width, height });
2173
+ };
2174
+ computeViewMatrix_fn = function() {
2175
+ const { width, height } = this.cfg;
2176
+ const [x, y, w, h] = this.cfg.viewport ?? [0, 0, width, height];
2177
+ const sx = width / w;
2178
+ const sy = height / h;
2179
+ this.viewMatrix = import_gl_matrix4.mat2d.fromValues(sx, 0, 0, sy, -x * sx, -y * sy);
2180
+ };
2181
+
2182
+ // src/scene/layer.ts
2183
+ var _queue2, _culledQueue, _Layer_instances, cullViewport_fn;
2184
+ var Layer = class extends Group {
2185
+ constructor(name, index, cfg, isEventLayer = false) {
2186
+ super();
2187
+ __privateAdd(this, _Layer_instances);
2188
+ this.type = 4;
2189
+ __privateAdd(this, _queue2, []);
2190
+ __privateAdd(this, _culledQueue, []);
2191
+ this.layerName = name;
2192
+ this.layerIndex = index;
2193
+ this.isEventLayer = isEventLayer;
2194
+ this.culling = !isEventLayer;
2195
+ this.renderer = new Renderer(cfg);
2196
+ const el = this.renderer.el;
2197
+ el.style.position = "absolute";
2198
+ el.style.left = "0";
2199
+ el.style.top = "0";
2200
+ el.style.zIndex = String(index);
2201
+ if (isEventLayer) {
2202
+ el.style.background = "transparent";
2203
+ } else {
2204
+ el.style.pointerEvents = "none";
2205
+ }
2206
+ }
2207
+ /** 获取当前层的渲染队列(仅 type=3 的 Node) */
2208
+ getQueue() {
2209
+ if (this.dirty) {
2210
+ const queue = [];
2211
+ this.traverse((node) => {
2212
+ if (node.type === 3) queue.push(node);
2213
+ });
2214
+ queue.sort((a, b) => a.ez - b.ez);
2215
+ this.setDirty(false);
2216
+ __privateSet(this, _queue2, queue);
2217
+ }
2218
+ return __privateGet(this, _queue2);
2219
+ }
2220
+ /** 层级是否需要重绘 */
2221
+ sign() {
2222
+ if (this.isEventLayer) return false;
2223
+ return super.sign();
2224
+ }
2225
+ /** 绘制本层 */
2226
+ draw() {
2227
+ if (this.isEventLayer) return;
2228
+ this.update();
2229
+ const queue = this.getQueue();
2230
+ this.renderer.draw(this.culling ? __privateMethod(this, _Layer_instances, cullViewport_fn).call(this, queue) : queue);
2231
+ }
2232
+ resize(size) {
2233
+ this.renderer.resize(size);
2234
+ }
2235
+ clear() {
2236
+ super.clear();
2237
+ __privateSet(this, _queue2, []);
2238
+ this.renderer.clear();
2239
+ }
2240
+ dispose() {
2241
+ super.dispose();
2242
+ __privateSet(this, _queue2, []);
2243
+ this.renderer.dispose();
2244
+ }
2245
+ };
2246
+ _queue2 = new WeakMap();
2247
+ _culledQueue = new WeakMap();
2248
+ _Layer_instances = new WeakSet();
2249
+ /**
2250
+ * 视口裁剪:过滤掉 worldBBox 完全在画布外的节点,减少 draw call。
2251
+ * 没有有效 boundingBox 的节点(如 Text)不会被剔除。
2252
+ */
2253
+ cullViewport_fn = function(queue) {
2254
+ const { width, height } = this.renderer.cfg;
2255
+ const culled = __privateGet(this, _culledQueue);
2256
+ culled.length = 0;
2257
+ for (let i = 0; i < queue.length; i++) {
2258
+ const node = queue[i];
2259
+ const bb = node.shape.boundingBox;
2260
+ if (!bb || bb.empty) {
2261
+ culled.push(node);
2262
+ continue;
2263
+ }
2264
+ const m = node.worldMatrix;
2265
+ const x0 = bb.x, y0 = bb.y, x1 = bb.right, y1 = bb.bottom;
2266
+ let wx, wy;
2267
+ let minX, maxX, minY, maxY;
2268
+ wx = m[0] * x0 + m[2] * y0 + m[4];
2269
+ wy = m[1] * x0 + m[3] * y0 + m[5];
2270
+ minX = maxX = wx;
2271
+ minY = maxY = wy;
2272
+ wx = m[0] * x1 + m[2] * y0 + m[4];
2273
+ wy = m[1] * x1 + m[3] * y0 + m[5];
2274
+ if (wx < minX) minX = wx;
2275
+ if (wx > maxX) maxX = wx;
2276
+ if (wy < minY) minY = wy;
2277
+ if (wy > maxY) maxY = wy;
2278
+ wx = m[0] * x1 + m[2] * y1 + m[4];
2279
+ wy = m[1] * x1 + m[3] * y1 + m[5];
2280
+ if (wx < minX) minX = wx;
2281
+ if (wx > maxX) maxX = wx;
2282
+ if (wy < minY) minY = wy;
2283
+ if (wy > maxY) maxY = wy;
2284
+ wx = m[0] * x0 + m[2] * y1 + m[4];
2285
+ wy = m[1] * x0 + m[3] * y1 + m[5];
2286
+ if (wx < minX) minX = wx;
2287
+ if (wx > maxX) maxX = wx;
2288
+ if (wy < minY) minY = wy;
2289
+ if (wy > maxY) maxY = wy;
2290
+ if (maxX > 0 && minX < width && maxY > 0 && minY < height) {
2291
+ culled.push(node);
2292
+ }
2293
+ }
2294
+ return culled;
2295
+ };
2296
+
2297
+ // src/events/event.ts
2298
+ var _path2;
2299
+ var _SimulatedEvent = class _SimulatedEvent {
2300
+ constructor(type, target, nativeEvent) {
2301
+ this.eventPhase = 0;
2302
+ this.bubbles = true;
2303
+ this.timestamp = Date.now();
2304
+ this.offsetX = 0;
2305
+ this.offsetY = 0;
2306
+ this.worldX = 0;
2307
+ this.worldY = 0;
2308
+ this.truth = true;
2309
+ __privateAdd(this, _path2, null);
2310
+ this.type = type;
2311
+ this.target = target;
2312
+ this.currentTarget = target;
2313
+ this.nativeEvent = nativeEvent;
2314
+ }
2315
+ get captureType() {
2316
+ return `capture-${this.type}`;
2317
+ }
2318
+ stopPropagation() {
2319
+ this.bubbles = false;
2320
+ }
2321
+ /** 返回从 target 到 root 的路径(缓存) */
2322
+ composedPath() {
2323
+ if (!__privateGet(this, _path2)) __privateSet(this, _path2, this.target.path().reverse());
2324
+ return __privateGet(this, _path2);
2325
+ }
2326
+ copy() {
2327
+ const event = new _SimulatedEvent(this.type, this.target, this.nativeEvent);
2328
+ event.currentTarget = this.currentTarget;
2329
+ event.eventPhase = this.eventPhase;
2330
+ event.bubbles = this.bubbles;
2331
+ event.timestamp = this.timestamp;
2332
+ event.offsetX = this.offsetX;
2333
+ event.offsetY = this.offsetY;
2334
+ event.worldX = this.worldX;
2335
+ event.worldY = this.worldY;
2336
+ __privateSet(event, _path2, __privateGet(this, _path2));
2337
+ return event;
2338
+ }
2339
+ };
2340
+ _path2 = new WeakMap();
2341
+ var SimulatedEvent = _SimulatedEvent;
2342
+
2343
+ // src/events/dispatcher.ts
2344
+ var POINTERENTER = ["capture-pointerenter", "pointerenter"];
2345
+ var POINTERLEAVE = ["capture-pointerleave", "pointerleave"];
2346
+ var POINTEROVER = ["capture-pointerover", "pointerover"];
2347
+ var POINTEROUT = ["capture-pointerout", "pointerout"];
2348
+ var EventDispatcher = class {
2349
+ constructor() {
2350
+ this.last = null;
2351
+ this.eventMap = {};
2352
+ this.eventMap = Object.fromEntries([
2353
+ ["click", this.normal],
2354
+ ["pointerenter", this.onPointerEnter],
2355
+ ["pointerleave", this.onPointerLeave],
2356
+ ["pointerover", this.onPointerOver],
2357
+ ["pointerout", this.onPointerOut],
2358
+ ["pointerdown", this.normal],
2359
+ ["pointermove", this.normal],
2360
+ ["pointerup", this.normal],
2361
+ ["pointercancel", this.normal]
2362
+ ]);
2363
+ }
2364
+ exec(event, node) {
2365
+ if (node === event.target && event.eventPhase !== 2) return;
2366
+ const evt = event.copy();
2367
+ evt.currentTarget = node;
2368
+ const handler = this.eventMap[evt.type];
2369
+ if (handler) handler.bind(this)(evt);
2370
+ else this.normal(evt);
2371
+ }
2372
+ capture(event) {
2373
+ event.eventPhase = 1;
2374
+ const path = event.composedPath();
2375
+ for (let i = path.length - 1; i >= 0; i--) this.exec(event, path[i]);
2376
+ }
2377
+ target(event) {
2378
+ event.eventPhase = 2;
2379
+ this.exec(event, event.target);
2380
+ }
2381
+ bubble(event) {
2382
+ event.eventPhase = 3;
2383
+ if (!event.bubbles) return;
2384
+ const path = event.composedPath();
2385
+ for (let i = 0; i < path.length; i++) this.exec(event, path[i]);
2386
+ }
2387
+ flow(event) {
2388
+ this.capture(event);
2389
+ this.target(event);
2390
+ this.bubble(event);
2391
+ }
2392
+ process(event) {
2393
+ this.simulateOut(event);
2394
+ this.simulateLeave(event);
2395
+ this.simulateOver(event);
2396
+ this.simulateEnter(event);
2397
+ this.flow(event);
2398
+ this.last = event;
2399
+ }
2400
+ simulateEnter(event) {
2401
+ if (event.type !== "pointermove") return;
2402
+ const { target, nativeEvent } = event;
2403
+ const evt = new SimulatedEvent("pointerenter", target, nativeEvent);
2404
+ evt.stopPropagation();
2405
+ evt.truth = false;
2406
+ this.flow(evt);
2407
+ }
2408
+ simulateLeave(event) {
2409
+ if (event.type !== "pointermove") return;
2410
+ const { target: last } = this.last || {};
2411
+ const { target: hit } = event;
2412
+ if (last && !hit.equals(last)) {
2413
+ const evt = new SimulatedEvent("pointerleave", last, event.nativeEvent);
2414
+ evt.stopPropagation();
2415
+ evt.truth = false;
2416
+ this.flow(evt);
2417
+ }
2418
+ }
2419
+ simulateOver(event) {
2420
+ if (event.type !== "pointermove") return;
2421
+ const { target, nativeEvent } = event;
2422
+ const evt = new SimulatedEvent("pointerover", target, nativeEvent);
2423
+ evt.truth = false;
2424
+ this.flow(evt);
2425
+ }
2426
+ simulateOut(event) {
2427
+ if (event.type !== "pointermove") return;
2428
+ const { target: last } = this.last || {};
2429
+ const { target: hit } = event;
2430
+ if (last && !hit.equals(last)) {
2431
+ const evt = new SimulatedEvent("pointerout", last, event.nativeEvent);
2432
+ evt.truth = false;
2433
+ this.flow(evt);
2434
+ }
2435
+ }
2436
+ normal(event) {
2437
+ const { type, captureType, eventPhase, currentTarget } = event;
2438
+ const name = eventPhase === 1 ? captureType : type;
2439
+ if (currentTarget.hasEvent(name)) currentTarget.emit(name, event);
2440
+ }
2441
+ onPointerEnter(event) {
2442
+ const [t0, t1] = POINTERENTER;
2443
+ const { eventPhase, currentTarget: cur } = event;
2444
+ const name = eventPhase === 1 ? t0 : t1;
2445
+ if (cur.hasEvent(name)) {
2446
+ const { target: last } = this.last || {};
2447
+ const { target: hit } = event;
2448
+ if ((!last || !hit.equals(last)) && hit.equals(cur)) {
2449
+ cur.emit(name, event);
2450
+ }
2451
+ }
2452
+ }
2453
+ onPointerLeave(event) {
2454
+ const [t0, t1] = POINTERLEAVE;
2455
+ const { eventPhase, currentTarget: cur } = event;
2456
+ const name = eventPhase === 1 ? t0 : t1;
2457
+ if (cur.hasEvent(name)) {
2458
+ const { target: hit } = event;
2459
+ if (hit.equals(cur)) {
2460
+ cur.emit(name, event);
2461
+ }
2462
+ }
2463
+ }
2464
+ onPointerOver(event) {
2465
+ const [t0, t1] = POINTEROVER;
2466
+ const { eventPhase, currentTarget: cur } = event;
2467
+ const name = eventPhase === 1 ? t0 : t1;
2468
+ if (cur.hasEvent(name)) {
2469
+ const { target: last } = this.last || {};
2470
+ const { target: hit } = event;
2471
+ if ((!last || !last.equals(hit)) && hit.source(cur)) {
2472
+ cur.emit(name, event);
2473
+ }
2474
+ }
2475
+ }
2476
+ onPointerOut(event) {
2477
+ const [t0, t1] = POINTEROUT;
2478
+ const { eventPhase, currentTarget: cur } = event;
2479
+ const name = eventPhase === 1 ? t0 : t1;
2480
+ if (cur.hasEvent(name)) {
2481
+ const { target: hit } = event;
2482
+ if (hit.source(cur)) {
2483
+ cur.emit(name, event);
2484
+ }
2485
+ }
2486
+ }
2487
+ clear() {
2488
+ this.last = null;
2489
+ }
2490
+ dispose() {
2491
+ this.clear();
2492
+ this.eventMap = {};
2493
+ }
2494
+ };
2495
+
2496
+ // src/events/observer.ts
2497
+ var FEAT_NATIVE_EVENTS = {
2498
+ move: ["pointermove"],
2499
+ click: ["pointerdown", "pointerup", "click"],
2500
+ wheel: ["wheel"]
2501
+ };
2502
+ var PASSIVE_EVENTS = /* @__PURE__ */ new Set(["pointermove", "wheel"]);
2503
+ var _bound, _cleanups, _EventObserver_instances, createListener_fn;
2504
+ var EventObserver = class {
2505
+ constructor(scene, renderer) {
2506
+ __privateAdd(this, _EventObserver_instances);
2507
+ this.feats = { move: true, click: true, wheel: true };
2508
+ this.dispatcher = new EventDispatcher();
2509
+ __privateAdd(this, _bound, false);
2510
+ __privateAdd(this, _cleanups, []);
2511
+ this.scene = scene;
2512
+ this.renderer = renderer;
2513
+ }
2514
+ /** 幂等绑定:每种原生事件只注册一次 */
2515
+ bindEvents() {
2516
+ if (__privateGet(this, _bound)) return;
2517
+ __privateSet(this, _bound, true);
2518
+ const el = this.renderer.el;
2519
+ const nativeTypes = /* @__PURE__ */ new Set();
2520
+ for (const [feat, enabled] of Object.entries(this.feats)) {
2521
+ if (!enabled) continue;
2522
+ for (const type of FEAT_NATIVE_EVENTS[feat]) {
2523
+ nativeTypes.add(type);
2524
+ }
2525
+ }
2526
+ for (const nativeType of nativeTypes) {
2527
+ const listener = __privateMethod(this, _EventObserver_instances, createListener_fn).call(this, nativeType);
2528
+ const passive = PASSIVE_EVENTS.has(nativeType);
2529
+ const options = passive ? { passive: true } : void 0;
2530
+ el.addEventListener(nativeType, listener, options);
2531
+ __privateGet(this, _cleanups).push(() => el.removeEventListener(nativeType, listener, options));
2532
+ }
2533
+ }
2534
+ unbindEvents() {
2535
+ for (const fn of __privateGet(this, _cleanups)) fn();
2536
+ __privateSet(this, _cleanups, []);
2537
+ __privateSet(this, _bound, false);
2538
+ }
2539
+ dispose() {
2540
+ this.unbindEvents();
2541
+ this.dispatcher.dispose();
2542
+ }
2543
+ };
2544
+ _bound = new WeakMap();
2545
+ _cleanups = new WeakMap();
2546
+ _EventObserver_instances = new WeakSet();
2547
+ createListener_fn = function(type) {
2548
+ return (evt) => {
2549
+ const { clientX, clientY } = evt;
2550
+ const offset = this.renderer.position([clientX, clientY]);
2551
+ const world = this.scene.position(offset);
2552
+ const target = this.scene.pick(offset) || this.scene;
2553
+ target.setDispatcher(this.dispatcher);
2554
+ const event = new SimulatedEvent(type, target, evt);
2555
+ event.offsetX = offset[0];
2556
+ event.offsetY = offset[1];
2557
+ event.worldX = world[0];
2558
+ event.worldY = world[1];
2559
+ target.dispatchEvent(event);
2560
+ };
2561
+ };
2562
+
2563
+ // src/serialization.ts
2564
+ var SHAPE_FROM_KEYS = {
2565
+ text: ["text", "x", "y"],
2566
+ circle: ["cx", "cy", "r"],
2567
+ rect: ["x", "y", "width", "height"],
2568
+ line: ["x1", "y1", "x2", "y2"],
2569
+ path: ["d"],
2570
+ curve: ["segments"],
2571
+ area: ["upperSegments", "lowerSegments"],
2572
+ polygon: ["points"],
2573
+ sector: ["r", "startAngle", "endAngle", "innerRadius", "outerRadius", "padAngle"],
2574
+ arc: ["r", "startAngle", "endAngle", "radius"],
2575
+ symbol: ["r"],
2576
+ round: ["x", "y", "width", "height"],
2577
+ image: ["src", "x", "y", "width", "height"]
2578
+ };
2579
+ var SHAPE_OPTIONS_KEYS = {
2580
+ curve: ["curve", "closed"],
2581
+ area: ["curve"],
2582
+ polygon: ["curve", "closed"],
2583
+ sector: ["rc"],
2584
+ symbol: ["symbol"],
2585
+ round: ["rx", "ry"]
2586
+ };
2587
+ function serializeGraphicsProps(g) {
2588
+ const json = {};
2589
+ if (g.name) json.name = g.name;
2590
+ if (g.className) json.className = g.className;
2591
+ if (g.z !== 0) json.z = g.z;
2592
+ if (!g.visible) json.visible = false;
2593
+ if (!g.display) json.display = false;
2594
+ const [tx, ty] = g._translate;
2595
+ if (tx !== 0 || ty !== 0) json.translate = [tx, ty];
2596
+ if (g._rotate !== 0) json.rotate = g._rotate;
2597
+ const [sx, sy] = g._scale;
2598
+ if (sx !== 1 || sy !== 1) json.scale = [sx, sy];
2599
+ if (Object.keys(g.data).length > 0) json.data = { ...g.data };
2600
+ return json;
2601
+ }
2602
+ function serializeNode(node) {
2603
+ const shapeType = node.shapeType;
2604
+ if (!shapeType || shapeType === "rectBuffer") return null;
2605
+ const fromKeys = SHAPE_FROM_KEYS[shapeType];
2606
+ if (!fromKeys) return null;
2607
+ const args = node.shape.getProps(fromKeys);
2608
+ const json = {
2609
+ type: "node",
2610
+ shapeType,
2611
+ args,
2612
+ ...serializeGraphicsProps(node)
2613
+ };
2614
+ const optKeys = SHAPE_OPTIONS_KEYS[shapeType];
2615
+ if (optKeys) {
2616
+ const opts = node.shape.getProps(optKeys);
2617
+ if (opts.some((v) => v !== void 0)) {
2618
+ json.options = opts;
2619
+ }
2620
+ }
2621
+ const attrKeys = Object.keys(node.attrs.values);
2622
+ if (attrKeys.length > 0) {
2623
+ json.attrs = { ...node.attrs.values };
2624
+ }
2625
+ if (node.attrs.gradientOptions) {
2626
+ const { id, ...rest } = node.attrs.gradientOptions;
2627
+ json.gradient = { ...rest };
2628
+ }
2629
+ if (node.attrs.clipPath) {
2630
+ const { id, ...rest } = node.attrs.clipPath;
2631
+ json.clipPath = { ...rest };
2632
+ }
2633
+ return json;
2634
+ }
2635
+ function serializeChild(g) {
2636
+ if (g.type === 3) return serializeNode(g);
2637
+ if (g.type === 2) return serializeGroup(g);
2638
+ return null;
2639
+ }
2640
+ function serializeGroup(g) {
2641
+ const children = [];
2642
+ for (const child of g.children) {
2643
+ const c = serializeChild(child);
2644
+ if (c) children.push(c);
2645
+ }
2646
+ return {
2647
+ type: "group",
2648
+ ...serializeGraphicsProps(g),
2649
+ children
2650
+ };
2651
+ }
2652
+ function serializeLayer(layer) {
2653
+ const json = {
2654
+ name: layer.layerName,
2655
+ index: layer.layerIndex,
2656
+ children: []
2657
+ };
2658
+ if (!layer.culling) json.culling = false;
2659
+ for (const child of layer.children) {
2660
+ const c = serializeChild(child);
2661
+ if (c) json.children.push(c);
2662
+ }
2663
+ return json;
2664
+ }
2665
+ function serialize(layers, width, height) {
2666
+ const layerJSONs = [];
2667
+ for (const layer of layers) {
2668
+ if (layer.isEventLayer) continue;
2669
+ layerJSONs.push(serializeLayer(layer));
2670
+ }
2671
+ return {
2672
+ version: 1,
2673
+ width,
2674
+ height,
2675
+ layers: layerJSONs
2676
+ };
2677
+ }
2678
+ function deserializeGraphicsProps(g, json) {
2679
+ if (json.name) g.setName(json.name);
2680
+ if (json.className) g.setClassName(json.className);
2681
+ if (json.z !== void 0) g.setZ(json.z);
2682
+ if (json.visible === false) g.setVisible(false);
2683
+ if (json.display === false) g.setDisplay(false);
2684
+ if (json.translate) g.translate(json.translate[0], json.translate[1]);
2685
+ if (json.rotate !== void 0) g.rotate(json.rotate);
2686
+ if (json.scale) g.scale(json.scale[0], json.scale[1]);
2687
+ if (json.data) g.data = { ...json.data };
2688
+ }
2689
+ function deserializeNode(json) {
2690
+ const node = Node.create(json.shapeType, json.attrs ?? {});
2691
+ node.shape.from(...json.args);
2692
+ if (json.options) node.shape.options(...json.options);
2693
+ if (json.gradient) node.attrs.gradient({ ...json.gradient });
2694
+ if (json.clipPath) node.attrs.clip({ ...json.clipPath });
2695
+ deserializeGraphicsProps(node, json);
2696
+ return node;
2697
+ }
2698
+ function deserializeChild(json) {
2699
+ if (json.type === "node") return deserializeNode(json);
2700
+ return deserializeGroup(json);
2701
+ }
2702
+ function deserializeGroup(json) {
2703
+ const group = new Group();
2704
+ deserializeGraphicsProps(group, json);
2705
+ for (const child of json.children) {
2706
+ group.add(deserializeChild(child));
2707
+ }
2708
+ return group;
2709
+ }
2710
+ function deserialize(json, cfg) {
2711
+ const layers = [];
2712
+ for (const layerJSON of json.layers) {
2713
+ const layer = new Layer(layerJSON.name, layerJSON.index, cfg);
2714
+ if (layerJSON.culling === false) layer.culling = false;
2715
+ for (const child of layerJSON.children) {
2716
+ layer.add(deserializeChild(child));
2717
+ }
2718
+ layers.push(layer);
2719
+ }
2720
+ return layers;
2721
+ }
2722
+
2723
+ // src/app.ts
2724
+ var _rafId, _mounted, _container, _eventLayer, _resizeObserver, _plugins, _App_instances, tick_fn;
2725
+ var _App = class _App {
2726
+ /**
2727
+ * @param cfg - 引擎配置(width/height/layers/autoResize 等)
2728
+ */
2729
+ constructor(cfg = {}) {
2730
+ __privateAdd(this, _App_instances);
2731
+ __privateAdd(this, _rafId, null);
2732
+ __privateAdd(this, _mounted, false);
2733
+ __privateAdd(this, _container, null);
2734
+ __privateAdd(this, _eventLayer);
2735
+ __privateAdd(this, _resizeObserver, null);
2736
+ __privateAdd(this, _plugins, []);
2737
+ this.cfg = cfg;
2738
+ this.scene = new Scene();
2739
+ __privateSet(this, _eventLayer, new Layer("__event__", 99999, this.cfg, true));
2740
+ this.scene.registerLayer(__privateGet(this, _eventLayer));
2741
+ this.scene.registerLayer(new Layer("default", 0, this.cfg));
2742
+ if (cfg.layers) {
2743
+ cfg.layers.forEach((name, i) => {
2744
+ if (name === "default") return;
2745
+ this.scene.registerLayer(new Layer(name, i + 1, this.cfg));
2746
+ });
2747
+ }
2748
+ this.observer = new EventObserver(this.scene, __privateGet(this, _eventLayer).renderer);
2749
+ imageLoader.onChange = () => this.requestRender();
2750
+ }
2751
+ /** 挂载容器(供插件访问) */
2752
+ get container() {
2753
+ return __privateGet(this, _container);
2754
+ }
2755
+ /** 是否已挂载 */
2756
+ get mounted() {
2757
+ return __privateGet(this, _mounted);
2758
+ }
2759
+ /**
2760
+ * 挂载到 DOM 容器,初始化渲染层并绑定事件。必须在 render() 之前调用。
2761
+ * @param container - 目标 DOM 元素,引擎会在其中创建 Canvas 元素
2762
+ */
2763
+ mount(container) {
2764
+ if (__privateGet(this, _mounted)) return this;
2765
+ __privateSet(this, _container, document.createElement("div"));
2766
+ __privateGet(this, _container).style.position = "relative";
2767
+ __privateGet(this, _container).style.width = `${this.cfg.width ?? 800}px`;
2768
+ __privateGet(this, _container).style.height = `${this.cfg.height ?? 600}px`;
2769
+ __privateGet(this, _container).style.overflow = "hidden";
2770
+ container.appendChild(__privateGet(this, _container));
2771
+ const viewMatrix = __privateGet(this, _eventLayer).renderer.viewMatrix;
2772
+ for (const layer of this.scene.layers) {
2773
+ __privateGet(this, _container).appendChild(layer.renderer.el);
2774
+ layer.setMatrix(viewMatrix);
2775
+ }
2776
+ this.scene.setMatrix(viewMatrix);
2777
+ this.observer.bindEvents();
2778
+ __privateSet(this, _mounted, true);
2779
+ if (this.cfg.autoResize) {
2780
+ __privateSet(this, _resizeObserver, new ResizeObserver((entries) => {
2781
+ const entry = entries[0];
2782
+ if (!entry) return;
2783
+ const { width, height } = entry.contentRect;
2784
+ if (width > 0 && height > 0) {
2785
+ this.resize(width, height);
2786
+ }
2787
+ }));
2788
+ __privateGet(this, _resizeObserver).observe(container);
2789
+ }
2790
+ return this;
2791
+ }
2792
+ /** 添加渲染层 */
2793
+ addLayer(name, index) {
2794
+ if (this.scene.getLayer(name)) {
2795
+ throw new Error(`Layer "${name}" already exists.`);
2796
+ }
2797
+ const layer = new Layer(name, index, this.cfg);
2798
+ this.scene.registerLayer(layer);
2799
+ if (__privateGet(this, _mounted) && __privateGet(this, _container)) {
2800
+ const viewMatrix = __privateGet(this, _eventLayer).renderer.viewMatrix;
2801
+ layer.setMatrix(viewMatrix);
2802
+ __privateGet(this, _container).insertBefore(layer.renderer.el, __privateGet(this, _eventLayer).renderer.el);
2803
+ }
2804
+ return layer;
2805
+ }
2806
+ /** 获取层 */
2807
+ getLayer(name) {
2808
+ return this.scene.getLayer(name);
2809
+ }
2810
+ /**
2811
+ * 注册插件(同名插件不会重复注册)
2812
+ * @param plugin - 实现 Plugin 接口的插件实例
2813
+ */
2814
+ use(plugin) {
2815
+ if (__privateGet(this, _plugins).some((p) => p.name === plugin.name)) {
2816
+ console.warn(`Plugin "${plugin.name}" is already registered.`);
2817
+ return this;
2818
+ }
2819
+ __privateGet(this, _plugins).push(plugin);
2820
+ plugin.install(this);
2821
+ return this;
2822
+ }
2823
+ /** 获取已注册的插件 */
2824
+ getPlugin(name) {
2825
+ return __privateGet(this, _plugins).find((p) => p.name === name);
2826
+ }
2827
+ /** 同步渲染一帧。适用于静态内容,仅重绘脏层 */
2828
+ render() {
2829
+ for (const layer of this.scene.layers) {
2830
+ if (layer.sign()) {
2831
+ layer.draw();
2832
+ }
2833
+ }
2834
+ }
2835
+ /** 请求异步渲染循环(rAF),有动画时自动继续,无变化时停止 */
2836
+ requestRender() {
2837
+ if (__privateGet(this, _rafId) !== null) return;
2838
+ __privateSet(this, _rafId, requestAnimationFrame((t) => __privateMethod(this, _App_instances, tick_fn).call(this, t)));
2839
+ }
2840
+ /**
2841
+ * 调整画布尺寸,同步更新所有层、容器和视口矩阵
2842
+ * @param width - 新宽度(像素)
2843
+ * @param height - 新高度(像素)
2844
+ */
2845
+ resize(width, height) {
2846
+ this.cfg.width = width;
2847
+ this.cfg.height = height;
2848
+ for (const layer of this.scene.layers) {
2849
+ layer.resize({ width, height });
2850
+ }
2851
+ if (__privateGet(this, _container)) {
2852
+ __privateGet(this, _container).style.width = `${width}px`;
2853
+ __privateGet(this, _container).style.height = `${height}px`;
2854
+ }
2855
+ const viewMatrix = __privateGet(this, _eventLayer).renderer.viewMatrix;
2856
+ this.scene.setMatrix(viewMatrix);
2857
+ for (const layer of this.scene.layers) {
2858
+ layer.setMatrix(viewMatrix);
2859
+ }
2860
+ for (const plugin of __privateGet(this, _plugins)) {
2861
+ plugin.resize?.(width, height);
2862
+ }
2863
+ }
2864
+ clear() {
2865
+ if (__privateGet(this, _rafId) !== null) {
2866
+ cancelAnimationFrame(__privateGet(this, _rafId));
2867
+ __privateSet(this, _rafId, null);
2868
+ }
2869
+ for (const layer of this.scene.layers) {
2870
+ layer.clear();
2871
+ }
2872
+ }
2873
+ dispose() {
2874
+ this.clear();
2875
+ for (const plugin of __privateGet(this, _plugins)) {
2876
+ plugin.dispose?.();
2877
+ }
2878
+ __privateSet(this, _plugins, []);
2879
+ if (__privateGet(this, _resizeObserver)) {
2880
+ __privateGet(this, _resizeObserver).disconnect();
2881
+ __privateSet(this, _resizeObserver, null);
2882
+ }
2883
+ for (const layer of this.scene.layers) {
2884
+ layer.dispose();
2885
+ }
2886
+ this.observer.dispose();
2887
+ this.scene.dispose();
2888
+ if (__privateGet(this, _container)) {
2889
+ __privateGet(this, _container).remove();
2890
+ __privateSet(this, _container, null);
2891
+ }
2892
+ }
2893
+ // ========================
2894
+ // Export & Serialization
2895
+ // ========================
2896
+ /** 将所有渲染层合成到一个 Canvas 上并返回 */
2897
+ toCanvas() {
2898
+ this.render();
2899
+ const width = this.cfg.width ?? 800;
2900
+ const height = this.cfg.height ?? 600;
2901
+ const canvas = document.createElement("canvas");
2902
+ canvas.width = width;
2903
+ canvas.height = height;
2904
+ const ctx = canvas.getContext("2d");
2905
+ for (const layer of this.scene.layers) {
2906
+ if (layer.isEventLayer) continue;
2907
+ ctx.drawImage(layer.renderer.el, 0, 0);
2908
+ }
2909
+ return canvas;
2910
+ }
2911
+ /** 序列化所有渲染层的场景图为 JSON,可用于保存/回放 */
2912
+ toJSON() {
2913
+ return serialize(this.scene.layers, this.cfg.width ?? 800, this.cfg.height ?? 600);
2914
+ }
2915
+ /**
2916
+ * 从 JSON 快照创建新的 App 实例(静态工厂方法)
2917
+ * @param json - 由 toJSON() 生成的场景快照
2918
+ * @param cfg - 可选的额外配置(会与 json 中的 width/height 合并)
2919
+ */
2920
+ static fromJSON(json, cfg = {}) {
2921
+ const merged = {
2922
+ ...cfg,
2923
+ width: json.width,
2924
+ height: json.height
2925
+ };
2926
+ const app = new _App(merged);
2927
+ app.scene.removeLayer("default");
2928
+ const layers = deserialize(json, merged);
2929
+ for (const layer of layers) {
2930
+ app.scene.registerLayer(layer);
2931
+ }
2932
+ return app;
2933
+ }
2934
+ /**
2935
+ * 将 JSON 快照恢复到当前 App 实例(就地替换所有渲染层内容)。
2936
+ * 与静态 fromJSON 不同,此方法不创建新 App,保留挂载状态和插件。
2937
+ */
2938
+ restoreFromJSON(json) {
2939
+ const names = this.scene.layers.filter((l) => !l.isEventLayer).map((l) => l.layerName);
2940
+ for (const name of names) {
2941
+ this.scene.removeLayer(name);
2942
+ }
2943
+ const layers = deserialize(json, this.cfg);
2944
+ const viewMatrix = __privateGet(this, _eventLayer).renderer.viewMatrix;
2945
+ for (const layer of layers) {
2946
+ this.scene.registerLayer(layer);
2947
+ if (__privateGet(this, _mounted) && __privateGet(this, _container)) {
2948
+ layer.setMatrix(viewMatrix);
2949
+ __privateGet(this, _container).insertBefore(layer.renderer.el, __privateGet(this, _eventLayer).renderer.el);
2950
+ }
2951
+ }
2952
+ }
2953
+ };
2954
+ _rafId = new WeakMap();
2955
+ _mounted = new WeakMap();
2956
+ _container = new WeakMap();
2957
+ _eventLayer = new WeakMap();
2958
+ _resizeObserver = new WeakMap();
2959
+ _plugins = new WeakMap();
2960
+ _App_instances = new WeakSet();
2961
+ tick_fn = function(time) {
2962
+ __privateSet(this, _rafId, null);
2963
+ this.scene.tick(time);
2964
+ let anyDirty = false;
2965
+ for (const layer of this.scene.layers) {
2966
+ if (layer.sign()) {
2967
+ layer.draw();
2968
+ anyDirty = true;
2969
+ }
2970
+ }
2971
+ if (anyDirty) {
2972
+ this.requestRender();
2973
+ }
2974
+ };
2975
+ var App = _App;
2976
+ // Annotate the CommonJS export names for ESM import in node:
2977
+ 0 && (module.exports = {
2978
+ App,
2979
+ ArcShape,
2980
+ ArcTransform,
2981
+ AreaShape,
2982
+ AttributeTransform,
2983
+ Attributes,
2984
+ BaseTransform,
2985
+ CircleShape,
2986
+ ClipBoxTransform,
2987
+ CurveShape,
2988
+ EventDispatcher,
2989
+ EventObserver,
2990
+ EventTarget,
2991
+ Graphics,
2992
+ GraphicsTransform,
2993
+ Group,
2994
+ ImageShape,
2995
+ Layer,
2996
+ LineShape,
2997
+ Node,
2998
+ PathShape,
2999
+ PolygonShape,
3000
+ RectShape,
3001
+ Renderer,
3002
+ RoundShape,
3003
+ Scene,
3004
+ SectorShape,
3005
+ SectorTransform,
3006
+ Shape,
3007
+ SimulatedEvent,
3008
+ SymbolShape,
3009
+ TextShape,
3010
+ createShape,
3011
+ deserialize,
3012
+ imageLoader,
3013
+ isHit,
3014
+ serialize,
3015
+ serializeLayer,
3016
+ setCanvasRenderingContext2StrokeAttrs
3017
+ });