squarified 0.3.7 → 0.4.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.
@@ -0,0 +1,1712 @@
1
+ "use strict";
2
+
3
+ //#region src/etoile/native/matrix.ts
4
+ const DEG_TO_RAD = Math.PI / 180;
5
+ const PI_2 = Math.PI * 2;
6
+ const DEFAULT_MATRIX_LOC = {
7
+ a: 1,
8
+ b: 0,
9
+ c: 0,
10
+ d: 1,
11
+ e: 0,
12
+ f: 0
13
+ };
14
+ var Matrix2D = class {
15
+ a;
16
+ b;
17
+ c;
18
+ d;
19
+ e;
20
+ f;
21
+ constructor(loc = {}) {
22
+ this.a = loc.a || 1;
23
+ this.b = loc.b || 0;
24
+ this.c = loc.c || 0;
25
+ this.d = loc.d || 1;
26
+ this.e = loc.e || 0;
27
+ this.f = loc.f || 0;
28
+ }
29
+ create(loc) {
30
+ Object.assign(this, loc);
31
+ return this;
32
+ }
33
+ transform(x, y, scaleX, scaleY, rotation, skewX, skewY) {
34
+ this.scale(scaleX, scaleY).translation(x, y);
35
+ if (skewX || skewY) this.skew(skewX, skewY);
36
+ else this.roate(rotation);
37
+ return this;
38
+ }
39
+ translation(x, y) {
40
+ this.e += x;
41
+ this.f += y;
42
+ return this;
43
+ }
44
+ scale(a, d) {
45
+ this.a *= a;
46
+ this.d *= d;
47
+ return this;
48
+ }
49
+ skew(x, y) {
50
+ const tanX = Math.tan(x * DEG_TO_RAD);
51
+ const tanY = Math.tan(y * DEG_TO_RAD);
52
+ const a = this.a + this.b * tanX;
53
+ const b = this.b + this.a * tanY;
54
+ const c = this.c + this.d * tanX;
55
+ const d = this.d + this.c * tanY;
56
+ this.a = a;
57
+ this.b = b;
58
+ this.c = c;
59
+ this.d = d;
60
+ return this;
61
+ }
62
+ roate(rotation) {
63
+ if (rotation > 0) {
64
+ const rad = rotation * DEG_TO_RAD;
65
+ const cosTheta = Math.cos(rad);
66
+ const sinTheta = Math.sin(rad);
67
+ const a = this.a * cosTheta - this.b * sinTheta;
68
+ const b = this.a * sinTheta + this.b * cosTheta;
69
+ const c = this.c * cosTheta - this.d * sinTheta;
70
+ const d = this.c * sinTheta + this.d * cosTheta;
71
+ this.a = a;
72
+ this.b = b;
73
+ this.c = c;
74
+ this.d = d;
75
+ }
76
+ return this;
77
+ }
78
+ };
79
+
80
+ //#endregion
81
+ //#region src/etoile/graph/display.ts
82
+ const SELF_ID = {
83
+ id: 0,
84
+ get() {
85
+ return this.id++;
86
+ }
87
+ };
88
+ let DisplayType = /* @__PURE__ */ function(DisplayType$1) {
89
+ DisplayType$1["Graph"] = "Graph";
90
+ DisplayType$1["Box"] = "Box";
91
+ DisplayType$1["Text"] = "Text";
92
+ DisplayType$1["RoundRect"] = "RoundRect";
93
+ DisplayType$1["Bitmap"] = "Bitmap";
94
+ return DisplayType$1;
95
+ }({});
96
+ var Display = class {
97
+ parent;
98
+ id;
99
+ matrix;
100
+ constructor() {
101
+ this.parent = null;
102
+ this.id = SELF_ID.get();
103
+ this.matrix = new Matrix2D();
104
+ }
105
+ destory() {}
106
+ };
107
+ const ASSIGN_MAPPINGS = {
108
+ fillStyle: 1,
109
+ strokeStyle: 2,
110
+ font: 4,
111
+ lineWidth: 8,
112
+ textAlign: 16,
113
+ textBaseline: 32
114
+ };
115
+ const ASSIGN_MAPPINGS_MODE = ASSIGN_MAPPINGS.fillStyle | ASSIGN_MAPPINGS.strokeStyle | ASSIGN_MAPPINGS.font | ASSIGN_MAPPINGS.lineWidth | ASSIGN_MAPPINGS.textAlign | ASSIGN_MAPPINGS.textBaseline;
116
+ const CALL_MAPPINGS_MODE = 0;
117
+ function createInstruction() {
118
+ return {
119
+ mods: [],
120
+ fillStyle(...args) {
121
+ this.mods.push({
122
+ mod: ["fillStyle", args],
123
+ type: ASSIGN_MAPPINGS.fillStyle
124
+ });
125
+ },
126
+ fillRect(...args) {
127
+ this.mods.push({
128
+ mod: ["fillRect", args],
129
+ type: CALL_MAPPINGS_MODE
130
+ });
131
+ },
132
+ strokeStyle(...args) {
133
+ this.mods.push({
134
+ mod: ["strokeStyle", args],
135
+ type: ASSIGN_MAPPINGS.strokeStyle
136
+ });
137
+ },
138
+ lineWidth(...args) {
139
+ this.mods.push({
140
+ mod: ["lineWidth", args],
141
+ type: ASSIGN_MAPPINGS.lineWidth
142
+ });
143
+ },
144
+ strokeRect(...args) {
145
+ this.mods.push({
146
+ mod: ["strokeRect", args],
147
+ type: CALL_MAPPINGS_MODE
148
+ });
149
+ },
150
+ fillText(...args) {
151
+ this.mods.push({
152
+ mod: ["fillText", args],
153
+ type: CALL_MAPPINGS_MODE
154
+ });
155
+ },
156
+ font(...args) {
157
+ this.mods.push({
158
+ mod: ["font", args],
159
+ type: ASSIGN_MAPPINGS.font
160
+ });
161
+ },
162
+ textBaseline(...args) {
163
+ this.mods.push({
164
+ mod: ["textBaseline", args],
165
+ type: ASSIGN_MAPPINGS.textBaseline
166
+ });
167
+ },
168
+ textAlign(...args) {
169
+ this.mods.push({
170
+ mod: ["textAlign", args],
171
+ type: ASSIGN_MAPPINGS.textAlign
172
+ });
173
+ },
174
+ beginPath() {
175
+ this.mods.push({
176
+ mod: ["beginPath", []],
177
+ type: CALL_MAPPINGS_MODE
178
+ });
179
+ },
180
+ moveTo(...args) {
181
+ this.mods.push({
182
+ mod: ["moveTo", args],
183
+ type: CALL_MAPPINGS_MODE
184
+ });
185
+ },
186
+ arcTo(...args) {
187
+ this.mods.push({
188
+ mod: ["arcTo", args],
189
+ type: CALL_MAPPINGS_MODE
190
+ });
191
+ },
192
+ closePath() {
193
+ this.mods.push({
194
+ mod: ["closePath", []],
195
+ type: CALL_MAPPINGS_MODE
196
+ });
197
+ },
198
+ fill() {
199
+ this.mods.push({
200
+ mod: ["fill", []],
201
+ type: CALL_MAPPINGS_MODE
202
+ });
203
+ },
204
+ stroke() {
205
+ this.mods.push({
206
+ mod: ["stroke", []],
207
+ type: CALL_MAPPINGS_MODE
208
+ });
209
+ },
210
+ drawImage(...args) {
211
+ this.mods.push({
212
+ mod: ["drawImage", args],
213
+ type: CALL_MAPPINGS_MODE
214
+ });
215
+ }
216
+ };
217
+ }
218
+ var S = class extends Display {
219
+ width;
220
+ height;
221
+ x;
222
+ y;
223
+ scaleX;
224
+ scaleY;
225
+ rotation;
226
+ skewX;
227
+ skewY;
228
+ constructor(options = {}) {
229
+ super();
230
+ this.width = options.width || 0;
231
+ this.height = options.height || 0;
232
+ this.x = options.x || 0;
233
+ this.y = options.y || 0;
234
+ this.scaleX = options.scaleX || 1;
235
+ this.scaleY = options.scaleY || 1;
236
+ this.rotation = options.rotation || 0;
237
+ this.skewX = options.skewX || 0;
238
+ this.skewY = options.skewY || 0;
239
+ }
240
+ };
241
+ var Graph = class extends S {
242
+ instruction;
243
+ __options__;
244
+ __widget__;
245
+ constructor(options = {}) {
246
+ super(options);
247
+ this.instruction = createInstruction();
248
+ this.__options__ = options;
249
+ this.__widget__ = null;
250
+ }
251
+ render(ctx) {
252
+ this.create();
253
+ const cap = this.instruction.mods.length;
254
+ for (let i = 0; i < cap; i++) {
255
+ const { mod, type } = this.instruction.mods[i];
256
+ const [direct, ...args] = mod;
257
+ if (type & ASSIGN_MAPPINGS_MODE) {
258
+ ctx[direct] = args[0];
259
+ continue;
260
+ }
261
+ ctx[direct].apply(ctx, ...args);
262
+ }
263
+ }
264
+ get __instanceOf__() {
265
+ return DisplayType.Graph;
266
+ }
267
+ };
268
+
269
+ //#endregion
270
+ //#region src/etoile/graph/types.ts
271
+ function isGraph(display) {
272
+ return display.__instanceOf__ === DisplayType.Graph;
273
+ }
274
+ function isBox(display) {
275
+ return display.__instanceOf__ === DisplayType.Box;
276
+ }
277
+ function isRoundRect(display) {
278
+ return isGraph(display) && display.__shape__ === DisplayType.RoundRect;
279
+ }
280
+ function isText(display) {
281
+ return isGraph(display) && display.__shape__ === DisplayType.Text;
282
+ }
283
+ function isBitmap(display) {
284
+ return isGraph(display) && display.__shape__ === DisplayType.Bitmap;
285
+ }
286
+ const asserts = {
287
+ isGraph,
288
+ isBox,
289
+ isText,
290
+ isRoundRect,
291
+ isBitmap
292
+ };
293
+
294
+ //#endregion
295
+ //#region src/etoile/graph/box.ts
296
+ var C = class extends Display {
297
+ elements;
298
+ constructor() {
299
+ super();
300
+ this.elements = [];
301
+ }
302
+ add(...elements) {
303
+ const cap = elements.length;
304
+ for (let i = 0; i < cap; i++) {
305
+ const element = elements[i];
306
+ if (element.parent) {}
307
+ this.elements.push(element);
308
+ element.parent = this;
309
+ }
310
+ }
311
+ remove(...elements) {
312
+ const cap = elements.length;
313
+ for (let i = 0; i < cap; i++) for (let j = this.elements.length - 1; j >= 0; j--) {
314
+ const element = this.elements[j];
315
+ if (element.id === elements[i].id) {
316
+ this.elements.splice(j, 1);
317
+ element.parent = null;
318
+ }
319
+ }
320
+ }
321
+ destory() {
322
+ this.elements.forEach((element) => element.parent = null);
323
+ this.elements.length = 0;
324
+ }
325
+ };
326
+ var Box = class Box extends C {
327
+ elements;
328
+ constructor() {
329
+ super();
330
+ this.elements = [];
331
+ }
332
+ add(...elements) {
333
+ const cap = elements.length;
334
+ for (let i = 0; i < cap; i++) {
335
+ const element = elements[i];
336
+ if (element.parent) {}
337
+ this.elements.push(element);
338
+ element.parent = this;
339
+ }
340
+ }
341
+ remove(...elements) {
342
+ const cap = elements.length;
343
+ for (let i = 0; i < cap; i++) for (let j = this.elements.length - 1; j >= 0; j--) {
344
+ const element = this.elements[j];
345
+ if (element.id === elements[i].id) {
346
+ this.elements.splice(j, 1);
347
+ element.parent = null;
348
+ }
349
+ }
350
+ }
351
+ destory() {
352
+ this.elements.forEach((element) => element.parent = null);
353
+ this.elements.length = 0;
354
+ }
355
+ get __instanceOf__() {
356
+ return DisplayType.Box;
357
+ }
358
+ clone() {
359
+ const box = new Box();
360
+ if (this.elements.length) {
361
+ const stack = [{
362
+ elements: this.elements,
363
+ parent: box
364
+ }];
365
+ while (stack.length > 0) {
366
+ const { elements, parent } = stack.pop();
367
+ const cap = elements.length;
368
+ for (let i = 0; i < cap; i++) {
369
+ const element = elements[i];
370
+ if (asserts.isBox(element)) {
371
+ const newBox = new Box();
372
+ newBox.parent = parent;
373
+ parent.add(newBox);
374
+ stack.push({
375
+ elements: element.elements,
376
+ parent: newBox
377
+ });
378
+ } else if (asserts.isGraph(element)) {
379
+ const el = element.clone();
380
+ el.parent = parent;
381
+ parent.add(el);
382
+ }
383
+ }
384
+ }
385
+ }
386
+ return box;
387
+ }
388
+ };
389
+
390
+ //#endregion
391
+ //#region src/etoile/native/runtime.ts
392
+ function decodeHLS(meta) {
393
+ const { h, l, s, a } = meta;
394
+ if ("a" in meta) return `hsla(${h}deg, ${s}%, ${l}%, ${a})`;
395
+ return `hsl(${h}deg, ${s}%, ${l}%)`;
396
+ }
397
+ function decodeRGB(meta) {
398
+ const { r, g, b, a } = meta;
399
+ if ("a" in meta) return `rgba(${r}, ${g}, ${b}, ${a})`;
400
+ return `rgb(${r}, ${g}, ${b})`;
401
+ }
402
+ function decodeColor(meta) {
403
+ return meta.mode === "rgb" ? decodeRGB(meta.desc) : decodeHLS(meta.desc);
404
+ }
405
+ function evaluateFillStyle(primitive, opacity = 1) {
406
+ const descibe = {
407
+ mode: primitive.mode,
408
+ desc: {
409
+ ...primitive.desc,
410
+ a: opacity
411
+ }
412
+ };
413
+ return decodeColor(descibe);
414
+ }
415
+ const runtime = { evaluateFillStyle };
416
+
417
+ //#endregion
418
+ //#region src/etoile/graph/rect.ts
419
+ var RoundRect = class RoundRect extends Graph {
420
+ style;
421
+ constructor(options = {}) {
422
+ super(options);
423
+ this.style = options.style || Object.create(null);
424
+ }
425
+ get __shape__() {
426
+ return DisplayType.RoundRect;
427
+ }
428
+ create() {
429
+ const padding = this.style.padding;
430
+ const x = 0;
431
+ const y = 0;
432
+ const width = this.width - padding * 2;
433
+ const height = this.height - padding * 2;
434
+ const radius = this.style.radius || 0;
435
+ this.instruction.beginPath();
436
+ this.instruction.moveTo(x + radius, y);
437
+ this.instruction.arcTo(x + width, y, x + width, y + height, radius);
438
+ this.instruction.arcTo(x + width, y + height, x, y + height, radius);
439
+ this.instruction.arcTo(x, y + height, x, y, radius);
440
+ this.instruction.arcTo(x, y, x + width, y, radius);
441
+ this.instruction.closePath();
442
+ if (this.style.fill) {
443
+ this.instruction.closePath();
444
+ this.instruction.fillStyle(runtime.evaluateFillStyle(this.style.fill, this.style.opacity));
445
+ this.instruction.fill();
446
+ }
447
+ if (this.style.stroke) {
448
+ if (typeof this.style.lineWidth === "number") this.instruction.lineWidth(this.style.lineWidth);
449
+ this.instruction.strokeStyle(this.style.stroke);
450
+ this.instruction.stroke();
451
+ }
452
+ }
453
+ clone() {
454
+ return new RoundRect({
455
+ ...this.style,
456
+ ...this.__options__
457
+ });
458
+ }
459
+ };
460
+
461
+ //#endregion
462
+ //#region src/etoile/graph/text.ts
463
+ var Text = class Text extends Graph {
464
+ text;
465
+ style;
466
+ constructor(options = {}) {
467
+ super(options);
468
+ this.text = options.text || "";
469
+ this.style = options.style || Object.create(null);
470
+ }
471
+ create() {
472
+ if (this.style.fill) {
473
+ this.instruction.font(this.style.font);
474
+ this.instruction.lineWidth(this.style.lineWidth);
475
+ this.instruction.textBaseline(this.style.baseline);
476
+ this.instruction.textAlign(this.style.textAlign);
477
+ this.instruction.fillStyle(this.style.fill);
478
+ this.instruction.fillText(this.text, 0, 0);
479
+ }
480
+ }
481
+ clone() {
482
+ return new Text({
483
+ ...this.style,
484
+ ...this.__options__
485
+ });
486
+ }
487
+ get __shape__() {
488
+ return DisplayType.Text;
489
+ }
490
+ };
491
+
492
+ //#endregion
493
+ //#region src/etoile/etoile.ts
494
+ function traverse(graphs, handler) {
495
+ const len = graphs.length;
496
+ for (let i = 0; i < len; i++) {
497
+ const graph = graphs[i];
498
+ if (asserts.isGraph(graph)) handler(graph);
499
+ else if (asserts.isBox(graph)) traverse(graph.elements, handler);
500
+ }
501
+ }
502
+
503
+ //#endregion
504
+ //#region src/etoile/native/easing.ts
505
+ const easing = {
506
+ linear: (k) => k,
507
+ quadraticIn: (k) => k * k,
508
+ quadraticOut: (k) => k * (2 - k),
509
+ quadraticInOut: (k) => {
510
+ if ((k *= 2) < 1) return .5 * k * k;
511
+ return -.5 * (--k * (k - 2) - 1);
512
+ },
513
+ cubicIn: (k) => k * k * k,
514
+ cubicOut: (k) => {
515
+ if ((k *= 2) < 1) return .5 * k * k * k;
516
+ return .5 * ((k -= 2) * k * k + 2);
517
+ },
518
+ cubicInOut: (k) => {
519
+ if ((k *= 2) < 1) return .5 * k * k * k;
520
+ return .5 * ((k -= 2) * k * k + 2);
521
+ }
522
+ };
523
+
524
+ //#endregion
525
+ //#region src/etoile/native/event.ts
526
+ var Event = class {
527
+ eventCollections;
528
+ constructor() {
529
+ this.eventCollections = Object.create(null);
530
+ }
531
+ on(evt, handler, c) {
532
+ if (!(evt in this.eventCollections)) this.eventCollections[evt] = [];
533
+ const data = {
534
+ name: evt,
535
+ handler,
536
+ ctx: c || this,
537
+ silent: false
538
+ };
539
+ this.eventCollections[evt].push(data);
540
+ }
541
+ off(evt, handler) {
542
+ if (evt in this.eventCollections) {
543
+ if (!handler) {
544
+ this.eventCollections[evt] = [];
545
+ return;
546
+ }
547
+ this.eventCollections[evt] = this.eventCollections[evt].filter((d) => d.handler !== handler);
548
+ }
549
+ }
550
+ silent(evt, handler) {
551
+ if (!(evt in this.eventCollections)) return;
552
+ this.eventCollections[evt].forEach((d) => {
553
+ if (!handler || d.handler === handler) d.silent = true;
554
+ });
555
+ }
556
+ active(evt, handler) {
557
+ if (!(evt in this.eventCollections)) return;
558
+ this.eventCollections[evt].forEach((d) => {
559
+ if (!handler || d.handler === handler) d.silent = false;
560
+ });
561
+ }
562
+ emit(evt, ...args) {
563
+ if (!this.eventCollections[evt]) return;
564
+ const handlers = this.eventCollections[evt];
565
+ if (handlers.length) handlers.forEach((d) => {
566
+ if (d.silent) return;
567
+ d.handler.call(d.ctx, ...args);
568
+ });
569
+ }
570
+ bindWithContext(c) {
571
+ return (evt, handler) => this.on(evt, handler, c);
572
+ }
573
+ };
574
+
575
+ //#endregion
576
+ //#region src/etoile/native/dom.ts
577
+ function getOffset(el) {
578
+ let e = 0;
579
+ let f = 0;
580
+ if (document.documentElement.getBoundingClientRect && el.getBoundingClientRect) {
581
+ const { top, left } = el.getBoundingClientRect();
582
+ e = top;
583
+ f = left;
584
+ } else for (let elt = el; elt; elt = el.offsetParent) {
585
+ e += el.offsetLeft;
586
+ f += el.offsetTop;
587
+ }
588
+ return [e + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft), f + Math.max(document.documentElement.scrollTop, document.body.scrollTop)];
589
+ }
590
+ function captureBoxXY(c, evt, a, d, translateX, translateY) {
591
+ const boundingClientRect = c.getBoundingClientRect();
592
+ if (evt instanceof MouseEvent) {
593
+ const [e, f] = getOffset(c);
594
+ return {
595
+ x: (evt.clientX - boundingClientRect.left - e - translateX) / a,
596
+ y: (evt.clientY - boundingClientRect.top - f - translateY) / d
597
+ };
598
+ }
599
+ return {
600
+ x: 0,
601
+ y: 0
602
+ };
603
+ }
604
+ function createEffectRun(c) {
605
+ return (fn) => {
606
+ const effect = () => {
607
+ const done = fn();
608
+ if (!done) c.animationFrameID = raf(effect);
609
+ };
610
+ if (!c.animationFrameID) c.animationFrameID = raf(effect);
611
+ };
612
+ }
613
+ function createEffectStop(c) {
614
+ return () => {
615
+ if (c.animationFrameID) {
616
+ window.cancelAnimationFrame(c.animationFrameID);
617
+ c.animationFrameID = null;
618
+ }
619
+ };
620
+ }
621
+ function createSmoothFrame() {
622
+ const c = { animationFrameID: null };
623
+ const run = createEffectRun(c);
624
+ const stop = createEffectStop(c);
625
+ return {
626
+ run,
627
+ stop
628
+ };
629
+ }
630
+
631
+ //#endregion
632
+ //#region src/shared/index.ts
633
+ function hashCode(str) {
634
+ let hash = 0;
635
+ for (let i = 0; i < str.length; i++) {
636
+ const code = str.charCodeAt(i);
637
+ hash = (hash << 5) - hash + code;
638
+ hash = hash & hash;
639
+ }
640
+ return hash;
641
+ }
642
+ function perferNumeric(s) {
643
+ if (typeof s === "number") return true;
644
+ return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
645
+ }
646
+ function noop() {}
647
+ function createRoundBlock(x, y, width, height, style) {
648
+ return new RoundRect({
649
+ width,
650
+ height,
651
+ x,
652
+ y,
653
+ style: { ...style }
654
+ });
655
+ }
656
+ function createTitleText(text, x, y, font, color) {
657
+ return new Text({
658
+ text,
659
+ x,
660
+ y,
661
+ style: {
662
+ fill: color,
663
+ textAlign: "center",
664
+ baseline: "middle",
665
+ font,
666
+ lineWidth: 1
667
+ }
668
+ });
669
+ }
670
+ const raf = window.requestAnimationFrame;
671
+ function createCanvasElement() {
672
+ return document.createElement("canvas");
673
+ }
674
+ function applyCanvasTransform(ctx, matrix, dpr) {
675
+ ctx.setTransform(matrix.a * dpr, matrix.b * dpr, matrix.c * dpr, matrix.d * dpr, matrix.e * dpr, matrix.f * dpr);
676
+ }
677
+ function mixin(app, methods) {
678
+ methods.forEach(({ name, fn }) => {
679
+ Object.defineProperty(app, name, {
680
+ value: fn(app),
681
+ writable: false
682
+ });
683
+ });
684
+ return app;
685
+ }
686
+ function mixinWithParams(app, methods) {
687
+ methods.forEach(({ name, fn }) => {
688
+ Object.defineProperty(app, name, {
689
+ value: fn(app),
690
+ writable: false,
691
+ enumerable: true
692
+ });
693
+ });
694
+ return app;
695
+ }
696
+ function prettyStrJoin(...s) {
697
+ return s.join("");
698
+ }
699
+ function isMacOS() {
700
+ return /Mac OS X/.test(navigator.userAgent);
701
+ }
702
+ function typedForIn(obj, callback) {
703
+ for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) callback(key, obj[key]);
704
+ }
705
+ function stackMatrixTransform(graph, e, f, scale) {
706
+ graph.x = graph.x * scale + e;
707
+ graph.y = graph.y * scale + f;
708
+ graph.scaleX = scale;
709
+ graph.scaleY = scale;
710
+ }
711
+ function stackMatrixTransformWithGraphAndLayer(graphs, e, f, scale) {
712
+ traverse(graphs, (graph) => stackMatrixTransform(graph, e, f, scale));
713
+ }
714
+ function smoothFrame(callback, opts) {
715
+ const frame = createSmoothFrame();
716
+ const startTime = Date.now();
717
+ const condtion = (process) => {
718
+ if (Array.isArray(opts.deps)) return opts.deps.some((dep) => dep());
719
+ return process >= 1;
720
+ };
721
+ frame.run(() => {
722
+ const elapsed = Date.now() - startTime;
723
+ const progress = Math.min(elapsed / opts.duration, 1);
724
+ if (condtion(progress)) {
725
+ frame.stop();
726
+ if (opts.onStop) opts.onStop();
727
+ return true;
728
+ }
729
+ return callback(progress, frame.stop);
730
+ });
731
+ }
732
+ function isScrollWheelOrRightButtonOnMouseupAndDown(e) {
733
+ return e.which === 2 || e.which === 3;
734
+ }
735
+ var DefaultMap = class extends Map {
736
+ defaultFactory;
737
+ constructor(defaultFactory, entries) {
738
+ super(entries);
739
+ this.defaultFactory = defaultFactory;
740
+ }
741
+ get(key) {
742
+ if (!super.has(key)) return this.defaultFactory();
743
+ return super.get(key);
744
+ }
745
+ getOrInsert(key, value) {
746
+ if (!super.has(key)) {
747
+ const defaultValue = value || this.defaultFactory();
748
+ super.set(key, defaultValue);
749
+ return defaultValue;
750
+ }
751
+ return super.get(key);
752
+ }
753
+ };
754
+
755
+ //#endregion
756
+ //#region src/shared/logger.ts
757
+ const createLogger = (namespace) => {
758
+ return {
759
+ error: (message) => {
760
+ return console.error(`[${namespace}] ${message}`);
761
+ },
762
+ panic: (message) => {
763
+ throw new Error(`[${namespace}] ${message}`);
764
+ }
765
+ };
766
+ };
767
+ function assertExists(value, logger$1, message) {
768
+ if (value === null || value === void 0) logger$1.panic(message);
769
+ }
770
+
771
+ //#endregion
772
+ //#region src/etoile/native/log.ts
773
+ const NAME_SPACE = "etoile";
774
+ const log = createLogger(NAME_SPACE);
775
+
776
+ //#endregion
777
+ //#region src/etoile/schedule/render.ts
778
+ function writeBoundingRectForCanvas(c, w, h, dpr) {
779
+ c.width = w * dpr;
780
+ c.height = h * dpr;
781
+ c.style.cssText = `width: ${w}px; height: ${h}px`;
782
+ }
783
+ var Canvas = class {
784
+ canvas;
785
+ ctx;
786
+ constructor(options) {
787
+ this.canvas = createCanvasElement();
788
+ this.setOptions(options);
789
+ this.ctx = this.canvas.getContext("2d");
790
+ }
791
+ setOptions(options) {
792
+ writeBoundingRectForCanvas(this.canvas, options.width, options.height, options.devicePixelRatio);
793
+ }
794
+ };
795
+ var Render = class {
796
+ options;
797
+ container;
798
+ constructor(to, options) {
799
+ this.container = new Canvas(options);
800
+ this.options = options;
801
+ this.initOptions(options);
802
+ if (!options.shaow) to.appendChild(this.container.canvas);
803
+ }
804
+ clear(width, height) {
805
+ this.ctx.clearRect(0, 0, width, height);
806
+ }
807
+ get canvas() {
808
+ return this.container.canvas;
809
+ }
810
+ get ctx() {
811
+ return this.container.ctx;
812
+ }
813
+ initOptions(userOptions = {}) {
814
+ Object.assign(this.options, userOptions);
815
+ this.container.setOptions(this.options);
816
+ }
817
+ destory() {}
818
+ };
819
+
820
+ //#endregion
821
+ //#region src/etoile/schedule/index.ts
822
+ function drawGraphIntoCanvas(graph, opts) {
823
+ const { ctx, dpr } = opts;
824
+ ctx.save();
825
+ if (asserts.isBox(graph)) {
826
+ const elements = graph.elements;
827
+ const cap = elements.length;
828
+ for (let i = 0; i < cap; i++) {
829
+ const element = elements[i];
830
+ drawGraphIntoCanvas(element, opts);
831
+ }
832
+ }
833
+ if (asserts.isGraph(graph)) {
834
+ const matrix = graph.matrix.create({
835
+ a: 1,
836
+ b: 0,
837
+ c: 0,
838
+ d: 1,
839
+ e: 0,
840
+ f: 0
841
+ });
842
+ matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
843
+ applyCanvasTransform(ctx, matrix, dpr);
844
+ graph.render(ctx);
845
+ }
846
+ ctx.restore();
847
+ }
848
+ var Schedule = class extends Box {
849
+ render;
850
+ to;
851
+ event;
852
+ constructor(to, renderOptions = {}) {
853
+ super();
854
+ this.to = typeof to === "string" ? document.querySelector(to) : to;
855
+ if (!this.to) log.panic("The element to bind is not found.");
856
+ const { width, height } = this.to.getBoundingClientRect();
857
+ Object.assign(renderOptions, {
858
+ width,
859
+ height
860
+ }, { devicePixelRatio: window.devicePixelRatio || 1 });
861
+ this.event = new Event();
862
+ this.render = new Render(this.to, renderOptions);
863
+ }
864
+ update() {
865
+ this.render.clear(this.render.options.width, this.render.options.height);
866
+ this.execute(this.render, this);
867
+ const matrix = this.matrix.create({
868
+ a: 1,
869
+ b: 0,
870
+ c: 0,
871
+ d: 1,
872
+ e: 0,
873
+ f: 0
874
+ });
875
+ applyCanvasTransform(this.render.ctx, matrix, this.render.options.devicePixelRatio);
876
+ }
877
+ execute(render, graph = this) {
878
+ drawGraphIntoCanvas(graph, {
879
+ c: render.canvas,
880
+ ctx: render.ctx,
881
+ dpr: render.options.devicePixelRatio
882
+ });
883
+ }
884
+ };
885
+
886
+ //#endregion
887
+ //#region src/primitives/struct.ts
888
+ function sortChildrenByKey(data, ...keys) {
889
+ return data.sort((a, b) => {
890
+ for (const key of keys) {
891
+ const v = a[key];
892
+ const v2 = b[key];
893
+ if (perferNumeric(v) && perferNumeric(v2)) {
894
+ if (v2 > v) return 1;
895
+ if (v2 < v) return -1;
896
+ continue;
897
+ }
898
+ const comparison = ("" + v).localeCompare("" + v2);
899
+ if (comparison !== 0) return comparison;
900
+ }
901
+ return 0;
902
+ });
903
+ }
904
+ function c2m(data, key, modifier) {
905
+ if (Array.isArray(data.groups)) data.groups = sortChildrenByKey(data.groups.map((d) => c2m(d, key, modifier)), "weight");
906
+ const obj = {
907
+ ...data,
908
+ weight: data[key]
909
+ };
910
+ if (modifier) Object.assign(obj, modifier(obj));
911
+ return obj;
912
+ }
913
+ function flatten(data) {
914
+ const result = [];
915
+ for (let i = 0; i < data.length; i++) {
916
+ const { groups,...rest } = data[i];
917
+ result.push(rest);
918
+ if (groups) result.push(...flatten(groups));
919
+ }
920
+ return result;
921
+ }
922
+ function bindParentForModule(modules, parent) {
923
+ return modules.map((module$1) => {
924
+ const next = { ...module$1 };
925
+ next.parent = parent;
926
+ if (next.groups && Array.isArray(next.groups)) next.groups = bindParentForModule(next.groups, next);
927
+ return next;
928
+ });
929
+ }
930
+ function getNodeDepth(node) {
931
+ let depth = 0;
932
+ while (node.parent) {
933
+ node = node.parent;
934
+ depth++;
935
+ }
936
+ return depth;
937
+ }
938
+ function visit(data, fn) {
939
+ if (!data) return null;
940
+ for (const d of data) {
941
+ if (d.children) {
942
+ const result = visit(d.children, fn);
943
+ if (result) return result;
944
+ }
945
+ const stop = fn(d);
946
+ if (stop) return d;
947
+ }
948
+ return null;
949
+ }
950
+ function findRelativeNode(p, layoutNodes) {
951
+ return visit(layoutNodes, (node) => {
952
+ const [x, y, w, h] = node.layout;
953
+ if (p.x >= x && p.y >= y && p.x < x + w && p.y < y + h) return true;
954
+ });
955
+ }
956
+ function findRelativeNodeById(id, layoutNodes) {
957
+ return visit(layoutNodes, (node) => {
958
+ if (node.node.id === id) return true;
959
+ });
960
+ }
961
+
962
+ //#endregion
963
+ //#region src/primitives/squarify.ts
964
+ function generateStableCombinedNodeId(weight, nodes) {
965
+ const name = nodes.map((node) => node.id).sort().join("-");
966
+ return Math.abs(hashCode(name)) + "-" + weight;
967
+ }
968
+ function processSquarifyData(data, totalArea, minNodeSize, minNodeArea) {
969
+ if (!data || !data.length) return [];
970
+ const totalWeight = data.reduce((sum, node) => sum + node.weight, 0);
971
+ if (totalWeight <= 0) return [];
972
+ const processedNodes = [];
973
+ const tooSmallNodes = [];
974
+ data.forEach((node) => {
975
+ const nodeArea = node.weight / totalWeight * totalArea;
976
+ const estimatedSize = Math.sqrt(nodeArea);
977
+ if (estimatedSize < minNodeSize || nodeArea < minNodeArea) tooSmallNodes.push({ ...node });
978
+ else processedNodes.push({ ...node });
979
+ });
980
+ if (tooSmallNodes.length > 0) {
981
+ const combinedWeight = tooSmallNodes.reduce((sum, node) => sum + node.weight, 0);
982
+ if (combinedWeight > 0 && combinedWeight / totalWeight * totalArea >= minNodeArea) {
983
+ const combinedNode = {
984
+ id: `combined-node-${generateStableCombinedNodeId(combinedWeight, tooSmallNodes)}`,
985
+ weight: combinedWeight,
986
+ isCombinedNode: true,
987
+ originalNodeCount: tooSmallNodes.length,
988
+ parent: null,
989
+ groups: [],
990
+ originalNodes: tooSmallNodes
991
+ };
992
+ processedNodes.push(combinedNode);
993
+ }
994
+ }
995
+ return processedNodes;
996
+ }
997
+ function squarify(data, rect, config, scale = 1) {
998
+ const result = [];
999
+ if (!data.length) return result;
1000
+ const totalArea = rect.w * rect.h;
1001
+ const containerSize = Math.min(rect.w, rect.h);
1002
+ const scaleFactor = Math.max(.5, Math.min(1, containerSize / 800));
1003
+ const minRenderableSize = Math.max(20, containerSize * .05) / scale;
1004
+ const minRenderableArea = minRenderableSize * minRenderableSize;
1005
+ const scaledGap = config.rectGap * scaleFactor;
1006
+ const scaledRadius = config.rectRadius * scaleFactor;
1007
+ const processedData = processSquarifyData(data, totalArea, minRenderableSize, minRenderableArea);
1008
+ if (!processedData.length) return result;
1009
+ rect = {
1010
+ x: rect.x + scaledGap / 2,
1011
+ y: rect.y + scaledGap / 2,
1012
+ w: rect.w - scaledGap,
1013
+ h: rect.h - scaledGap
1014
+ };
1015
+ const worst = (start, end, shortestSide, totalWeight, aspectRatio) => {
1016
+ const max = processedData[start].weight * aspectRatio;
1017
+ const min = processedData[end].weight * aspectRatio;
1018
+ return Math.max(shortestSide * shortestSide * max / (totalWeight * totalWeight), totalWeight * totalWeight / (shortestSide * shortestSide * min));
1019
+ };
1020
+ const recursion = (start, rect$1, depth = 0) => {
1021
+ const depthFactor = Math.max(.4, 1 - depth * .15);
1022
+ const currentGap = scaledGap * depthFactor;
1023
+ const currentRadius = scaledRadius * depthFactor;
1024
+ while (start < processedData.length) {
1025
+ let totalWeight = 0;
1026
+ for (let i = start; i < processedData.length; i++) totalWeight += processedData[i].weight;
1027
+ const shortestSide = Math.min(rect$1.w, rect$1.h);
1028
+ const aspectRatio = rect$1.w * rect$1.h / totalWeight;
1029
+ let end = start;
1030
+ let areaInRun = 0;
1031
+ let oldWorst = 0;
1032
+ while (end < processedData.length) {
1033
+ const area = processedData[end].weight * aspectRatio || 0;
1034
+ const newWorst = worst(start, end, shortestSide, areaInRun + area, aspectRatio);
1035
+ if (end > start && oldWorst < newWorst) break;
1036
+ areaInRun += area;
1037
+ oldWorst = newWorst;
1038
+ end++;
1039
+ }
1040
+ const splited = Math.round(areaInRun / shortestSide);
1041
+ let areaInLayout = 0;
1042
+ const isHorizontalLayout = rect$1.w >= rect$1.h;
1043
+ for (let i = start; i < end; i++) {
1044
+ const isFirst = i === start;
1045
+ const isLast = i === end - 1;
1046
+ const children = processedData[i];
1047
+ const area = children.weight * aspectRatio;
1048
+ const lower = Math.round(shortestSide * areaInLayout / areaInRun);
1049
+ const upper = Math.round(shortestSide * (areaInLayout + area) / areaInRun);
1050
+ let x, y, w, h;
1051
+ if (isHorizontalLayout) {
1052
+ x = rect$1.x;
1053
+ y = rect$1.y + lower;
1054
+ w = splited;
1055
+ h = upper - lower;
1056
+ } else {
1057
+ x = rect$1.x + lower;
1058
+ y = rect$1.y;
1059
+ w = upper - lower;
1060
+ h = splited;
1061
+ }
1062
+ const edgeGap = currentGap / 2;
1063
+ if (!isFirst) if (isHorizontalLayout) {
1064
+ y += edgeGap;
1065
+ h -= edgeGap;
1066
+ } else {
1067
+ x += edgeGap;
1068
+ w -= edgeGap;
1069
+ }
1070
+ if (!isLast) if (isHorizontalLayout) h -= edgeGap;
1071
+ else w -= edgeGap;
1072
+ const nodeDepth = getNodeDepth(children) || 1;
1073
+ const { titleAreaHeight } = config;
1074
+ const diff = titleAreaHeight.max / nodeDepth;
1075
+ const titleHeight = diff < titleAreaHeight.min ? titleAreaHeight.min : diff;
1076
+ w = Math.max(2, w);
1077
+ h = Math.max(2, h);
1078
+ let childrenLayout = [];
1079
+ const hasValidChildren = children.groups && children.groups.length > 0;
1080
+ if (hasValidChildren) {
1081
+ const childRect = {
1082
+ x: x + currentGap,
1083
+ y: y + titleHeight,
1084
+ w: Math.max(0, w - currentGap * 2),
1085
+ h: Math.max(0, h - titleHeight - currentGap)
1086
+ };
1087
+ if (childRect.w > currentRadius * 2 && childRect.h > currentRadius * 2) childrenLayout = squarify(children.groups || [], childRect, {
1088
+ ...config,
1089
+ rectGap: currentGap,
1090
+ rectRadius: currentRadius
1091
+ }, scale);
1092
+ }
1093
+ result.push({
1094
+ layout: [
1095
+ x,
1096
+ y,
1097
+ w,
1098
+ h
1099
+ ],
1100
+ node: children,
1101
+ children: childrenLayout,
1102
+ config: {
1103
+ titleAreaHeight: titleHeight,
1104
+ rectGap: currentGap,
1105
+ rectRadius: currentRadius
1106
+ }
1107
+ });
1108
+ areaInLayout += area;
1109
+ }
1110
+ start = end;
1111
+ if (isHorizontalLayout) {
1112
+ rect$1.x += splited + currentGap;
1113
+ rect$1.w -= splited + currentGap;
1114
+ } else {
1115
+ rect$1.y += splited + currentGap;
1116
+ rect$1.h -= splited + currentGap;
1117
+ }
1118
+ }
1119
+ };
1120
+ recursion(0, rect);
1121
+ return result;
1122
+ }
1123
+
1124
+ //#endregion
1125
+ //#region src/shared/plugin-driver.ts
1126
+ function definePlugin(plugin) {
1127
+ return plugin;
1128
+ }
1129
+ var PluginDriver = class {
1130
+ plugins = new Map();
1131
+ pluginContext;
1132
+ constructor(component) {
1133
+ this.pluginContext = {
1134
+ resolveModuleById(id) {
1135
+ return findRelativeNodeById(id, component.layoutNodes);
1136
+ },
1137
+ getPluginMetadata: (pluginName) => {
1138
+ return this.getPluginMetadata(pluginName);
1139
+ },
1140
+ get instance() {
1141
+ return component;
1142
+ }
1143
+ };
1144
+ }
1145
+ use(plugin) {
1146
+ if (!plugin.name) {
1147
+ logger.error("Plugin name is required");
1148
+ return;
1149
+ }
1150
+ if (this.plugins.has(plugin.name)) logger.panic(`Plugin ${plugin.name} is already registered`);
1151
+ this.plugins.set(plugin.name, plugin);
1152
+ }
1153
+ runHook(hookName, ...args) {
1154
+ this.plugins.forEach((plugin) => {
1155
+ const hook = plugin[hookName];
1156
+ if (hook) hook.apply(this.pluginContext, args);
1157
+ });
1158
+ }
1159
+ cascadeHook(hookName, ...args) {
1160
+ const finalResult = {};
1161
+ this.plugins.forEach((plugin) => {
1162
+ const hook = plugin[hookName];
1163
+ if (hook) {
1164
+ const hookResult = hook.call(this.pluginContext, ...args);
1165
+ if (hookResult) Object.assign(finalResult, hookResult);
1166
+ }
1167
+ });
1168
+ return finalResult;
1169
+ }
1170
+ getPluginMetadata(pluginName) {
1171
+ const plugin = this.plugins.get(pluginName);
1172
+ return plugin?.meta || null;
1173
+ }
1174
+ };
1175
+
1176
+ //#endregion
1177
+ //#region src/component.ts
1178
+ const logger = createLogger("Treemap");
1179
+ const DEFAULT_RECT_FILL_DESC = {
1180
+ mode: "rgb",
1181
+ desc: {
1182
+ r: 0,
1183
+ g: 0,
1184
+ b: 0
1185
+ }
1186
+ };
1187
+ const DEFAULT_TITLE_AREA_HEIGHT = {
1188
+ min: 30,
1189
+ max: 60
1190
+ };
1191
+ const DEFAULT_RECT_GAP = 4;
1192
+ const DEFAULT_RECT_BORDER_RADIUS = 4;
1193
+ const DEFAULT_FONT_SIZE = {
1194
+ max: 70,
1195
+ min: 12
1196
+ };
1197
+ const DEFAULT_FONT_FAMILY = "sans-serif";
1198
+ const DEFAULT_FONT_COLOR = "#000";
1199
+ var Component = class extends Schedule {
1200
+ pluginDriver;
1201
+ data;
1202
+ colorMappings;
1203
+ rectLayer;
1204
+ textLayer;
1205
+ layoutNodes;
1206
+ config;
1207
+ caches;
1208
+ constructor(config, ...args) {
1209
+ super(...args);
1210
+ this.data = [];
1211
+ this.config = config;
1212
+ this.colorMappings = {};
1213
+ this.pluginDriver = new PluginDriver(this);
1214
+ this.rectLayer = new Box();
1215
+ this.textLayer = new Box();
1216
+ this.caches = new DefaultMap(() => 14);
1217
+ this.layoutNodes = [];
1218
+ }
1219
+ drawBroundRect(node) {
1220
+ const [x, y, w, h] = node.layout;
1221
+ const { rectRadius } = node.config;
1222
+ const effectiveRadius = Math.min(rectRadius, w / 4, h / 4);
1223
+ const fill = this.colorMappings[node.node.id] || DEFAULT_RECT_FILL_DESC;
1224
+ const rect = createRoundBlock(x, y, w, h, {
1225
+ fill,
1226
+ padding: 0,
1227
+ radius: effectiveRadius
1228
+ });
1229
+ rect.__widget__ = node;
1230
+ this.rectLayer.add(rect);
1231
+ for (const child of node.children) this.drawBroundRect(child);
1232
+ }
1233
+ drawText(node) {
1234
+ if (!node.node.label && !node.node.isCombinedNode) return;
1235
+ const [x, y, w, h] = node.layout;
1236
+ const { titleAreaHeight } = node.config;
1237
+ const content = node.node.isCombinedNode ? `+ ${node.node.originalNodeCount} Modules` : node.node.label;
1238
+ const availableHeight = node.children && node.children.length > 0 ? titleAreaHeight - DEFAULT_RECT_GAP * 2 : h - DEFAULT_RECT_GAP * 2;
1239
+ const availableWidth = w - DEFAULT_RECT_GAP * 2;
1240
+ if (availableWidth <= 0 || availableHeight <= 0) return;
1241
+ const config = {
1242
+ fontSize: this.config.font?.fontSize || DEFAULT_FONT_SIZE,
1243
+ family: this.config.font?.family || DEFAULT_FONT_FAMILY,
1244
+ color: this.config.font?.color || DEFAULT_FONT_COLOR
1245
+ };
1246
+ const optimalFontSize = this.caches.getOrInsert(node.node.id, evaluateOptimalFontSize(this.render.ctx, content, config, availableWidth, availableHeight));
1247
+ const font = `${optimalFontSize}px ${config.family}`;
1248
+ this.render.ctx.font = font;
1249
+ const result = getTextLayout(this.render.ctx, content, availableWidth, availableHeight);
1250
+ if (!result.valid) return;
1251
+ const { text } = result;
1252
+ const textX = x + Math.round(w / 2);
1253
+ const textY = y + (node.children && node.children.length > 0 ? Math.round(titleAreaHeight / 2) : Math.round(h / 2));
1254
+ const textComponent = createTitleText(text, textX, textY, font, config.color);
1255
+ this.textLayer.add(textComponent);
1256
+ for (const child of node.children) this.drawText(child);
1257
+ }
1258
+ draw(flush = true, update = true) {
1259
+ const { width, height } = this.render.options;
1260
+ if (update) this.layoutNodes = this.calculateLayoutNodes(this.data, {
1261
+ w: width,
1262
+ h: height,
1263
+ x: 0,
1264
+ y: 0
1265
+ });
1266
+ if (flush) {
1267
+ const result = this.pluginDriver.cascadeHook("onModuleInit", this.layoutNodes);
1268
+ if (result) this.colorMappings = result.colorMappings || {};
1269
+ }
1270
+ for (const node of this.layoutNodes) this.drawBroundRect(node);
1271
+ for (const node of this.layoutNodes) this.drawText(node);
1272
+ this.add(this.rectLayer, this.textLayer);
1273
+ if (update) this.update();
1274
+ }
1275
+ cleanup() {
1276
+ this.remove(this.rectLayer, this.textLayer);
1277
+ this.rectLayer.destory();
1278
+ this.textLayer.destory();
1279
+ }
1280
+ calculateLayoutNodes(data, rect, scale = 1) {
1281
+ const config = {
1282
+ titleAreaHeight: this.config.layout?.titleAreaHeight || DEFAULT_TITLE_AREA_HEIGHT,
1283
+ rectRadius: this.config.layout?.rectRadius || DEFAULT_RECT_BORDER_RADIUS,
1284
+ rectGap: this.config.layout?.rectGap || DEFAULT_RECT_GAP
1285
+ };
1286
+ return squarify(data, rect, config, scale);
1287
+ }
1288
+ };
1289
+ function evaluateOptimalFontSize(c, text, config, desiredW, desiredH) {
1290
+ desiredW = Math.floor(desiredW);
1291
+ desiredH = Math.floor(desiredH);
1292
+ const { fontSize, family } = config;
1293
+ let min = fontSize.min;
1294
+ let max = fontSize.max;
1295
+ const cache = new Map();
1296
+ while (max - min >= 1) {
1297
+ const current = min + (max - min) / 2;
1298
+ if (!cache.has(current)) {
1299
+ c.font = `${current}px ${family}`;
1300
+ const metrics = c.measureText(text);
1301
+ const width$1 = metrics.width;
1302
+ const height$1 = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
1303
+ cache.set(current, {
1304
+ width: width$1,
1305
+ height: height$1
1306
+ });
1307
+ }
1308
+ const { width, height } = cache.get(current);
1309
+ if (width > desiredW || height > desiredH) max = current;
1310
+ else min = current;
1311
+ }
1312
+ return Math.floor(min);
1313
+ }
1314
+ function getTextLayout(c, text, width, height) {
1315
+ const ellipsisWidth = measureTextWidth(c, "...");
1316
+ if (width < ellipsisWidth) {
1317
+ if (height > ellipsisWidth) return {
1318
+ valid: true,
1319
+ text: "...",
1320
+ direction: "vertical",
1321
+ width: ellipsisWidth / 3
1322
+ };
1323
+ return {
1324
+ valid: false,
1325
+ text: "",
1326
+ direction: "horizontal",
1327
+ width: 0
1328
+ };
1329
+ }
1330
+ const textWidth = measureTextWidth(c, text);
1331
+ if (textWidth < width) return {
1332
+ valid: true,
1333
+ text,
1334
+ direction: "horizontal",
1335
+ width: textWidth
1336
+ };
1337
+ return {
1338
+ valid: true,
1339
+ text: "...",
1340
+ direction: "horizontal",
1341
+ width: ellipsisWidth
1342
+ };
1343
+ }
1344
+ function measureTextWidth(c, text) {
1345
+ return c.measureText(text).width;
1346
+ }
1347
+
1348
+ //#endregion
1349
+ //#region src/dom-event.ts
1350
+ const DOM_EVENTS = [
1351
+ "click",
1352
+ "mousedown",
1353
+ "mousemove",
1354
+ "mouseup",
1355
+ "mouseover",
1356
+ "mouseout",
1357
+ "wheel",
1358
+ "contextmenu"
1359
+ ];
1360
+ const STATE_TRANSITION = {
1361
+ IDLE: "IDLE",
1362
+ PRESSED: "PRESSED",
1363
+ DRAGGING: "DRAGGING",
1364
+ CLICK_POTENTIAL: "CLICK_POTENTIAL",
1365
+ ZOOMING: "ZOOMING",
1366
+ MOVE: "MOVE",
1367
+ SCALING: "SCALING"
1368
+ };
1369
+ var StateManager = class {
1370
+ current;
1371
+ constructor() {
1372
+ this.current = STATE_TRANSITION.IDLE;
1373
+ }
1374
+ canTransition(to) {
1375
+ switch (this.current) {
1376
+ case "IDLE": return to === "PRESSED" || to === "MOVE" || to === "SCALING" || to === "ZOOMING";
1377
+ case "PRESSED": return to === "DRAGGING" || to === "IDLE";
1378
+ case "DRAGGING": return to === "IDLE";
1379
+ case "MOVE": return to === "PRESSED" || to === "IDLE";
1380
+ case "SCALING": return to === "IDLE";
1381
+ case "ZOOMING": return to === "IDLE";
1382
+ default: return false;
1383
+ }
1384
+ }
1385
+ transition(to) {
1386
+ const valid = this.canTransition(to);
1387
+ if (valid) this.current = to;
1388
+ return valid;
1389
+ }
1390
+ reset() {
1391
+ this.current = STATE_TRANSITION.IDLE;
1392
+ }
1393
+ isInState(state) {
1394
+ return this.current === state;
1395
+ }
1396
+ };
1397
+ function isWheelEvent(metadata) {
1398
+ return metadata.kind === "wheel";
1399
+ }
1400
+ function isMouseEvent(metadata) {
1401
+ return [
1402
+ "mousedown",
1403
+ "mouseup",
1404
+ "mousemove"
1405
+ ].includes(metadata.kind);
1406
+ }
1407
+ function isClickEvent(metadata) {
1408
+ return metadata.kind === "click";
1409
+ }
1410
+ function isContextMenuEvent(metadata) {
1411
+ return metadata.kind === "contextmenu";
1412
+ }
1413
+ function bindDOMEvent(el, evt, dom) {
1414
+ const handler = (e) => {
1415
+ const data = { native: e };
1416
+ Object.defineProperty(data, "kind", {
1417
+ value: evt,
1418
+ enumerable: true,
1419
+ configurable: false,
1420
+ writable: false
1421
+ });
1422
+ dom.emit(evt, data);
1423
+ };
1424
+ el.addEventListener(evt, handler);
1425
+ return {
1426
+ evt,
1427
+ handler
1428
+ };
1429
+ }
1430
+ var DOMEvent = class extends Event {
1431
+ domEvents;
1432
+ el;
1433
+ currentModule;
1434
+ component;
1435
+ matrix;
1436
+ stateManager;
1437
+ constructor(component) {
1438
+ super();
1439
+ this.component = component;
1440
+ this.el = component.render.canvas;
1441
+ this.matrix = new Matrix2D();
1442
+ this.currentModule = null;
1443
+ this.stateManager = new StateManager();
1444
+ this.domEvents = DOM_EVENTS.map((evt) => bindDOMEvent(this.el, evt, this));
1445
+ DOM_EVENTS.forEach((evt) => {
1446
+ this.on(evt, (e) => {
1447
+ this.dispatch(evt, e);
1448
+ });
1449
+ });
1450
+ }
1451
+ destory() {
1452
+ if (this.el) {
1453
+ this.domEvents.forEach(({ evt, handler }) => this.el?.removeEventListener(evt, handler));
1454
+ this.domEvents = [];
1455
+ for (const evt in this.eventCollections) this.off(evt);
1456
+ this.matrix.create(DEFAULT_MATRIX_LOC);
1457
+ }
1458
+ }
1459
+ dispatch(kind, e) {
1460
+ const node = this.findRelativeNode(e);
1461
+ this.component.pluginDriver.runHook("onDOMEventTriggered", kind, e, node, this);
1462
+ this.emit("__exposed__", kind, {
1463
+ native: e.native,
1464
+ module: node
1465
+ });
1466
+ }
1467
+ findRelativeNode(e) {
1468
+ return findRelativeNode(captureBoxXY(this.el, e.native, this.matrix.a, this.matrix.d, this.matrix.e, this.matrix.f), this.component.layoutNodes);
1469
+ }
1470
+ };
1471
+
1472
+ //#endregion
1473
+ Object.defineProperty(exports, 'Component', {
1474
+ enumerable: true,
1475
+ get: function () {
1476
+ return Component;
1477
+ }
1478
+ });
1479
+ Object.defineProperty(exports, 'DEFAULT_MATRIX_LOC', {
1480
+ enumerable: true,
1481
+ get: function () {
1482
+ return DEFAULT_MATRIX_LOC;
1483
+ }
1484
+ });
1485
+ Object.defineProperty(exports, 'DOMEvent', {
1486
+ enumerable: true,
1487
+ get: function () {
1488
+ return DOMEvent;
1489
+ }
1490
+ });
1491
+ Object.defineProperty(exports, 'DefaultMap', {
1492
+ enumerable: true,
1493
+ get: function () {
1494
+ return DefaultMap;
1495
+ }
1496
+ });
1497
+ Object.defineProperty(exports, 'Event', {
1498
+ enumerable: true,
1499
+ get: function () {
1500
+ return Event;
1501
+ }
1502
+ });
1503
+ Object.defineProperty(exports, 'PI_2', {
1504
+ enumerable: true,
1505
+ get: function () {
1506
+ return PI_2;
1507
+ }
1508
+ });
1509
+ Object.defineProperty(exports, 'Schedule', {
1510
+ enumerable: true,
1511
+ get: function () {
1512
+ return Schedule;
1513
+ }
1514
+ });
1515
+ Object.defineProperty(exports, 'applyCanvasTransform', {
1516
+ enumerable: true,
1517
+ get: function () {
1518
+ return applyCanvasTransform;
1519
+ }
1520
+ });
1521
+ Object.defineProperty(exports, 'assertExists', {
1522
+ enumerable: true,
1523
+ get: function () {
1524
+ return assertExists;
1525
+ }
1526
+ });
1527
+ Object.defineProperty(exports, 'bindParentForModule', {
1528
+ enumerable: true,
1529
+ get: function () {
1530
+ return bindParentForModule;
1531
+ }
1532
+ });
1533
+ Object.defineProperty(exports, 'c2m', {
1534
+ enumerable: true,
1535
+ get: function () {
1536
+ return c2m;
1537
+ }
1538
+ });
1539
+ Object.defineProperty(exports, 'createCanvasElement', {
1540
+ enumerable: true,
1541
+ get: function () {
1542
+ return createCanvasElement;
1543
+ }
1544
+ });
1545
+ Object.defineProperty(exports, 'createRoundBlock', {
1546
+ enumerable: true,
1547
+ get: function () {
1548
+ return createRoundBlock;
1549
+ }
1550
+ });
1551
+ Object.defineProperty(exports, 'createTitleText', {
1552
+ enumerable: true,
1553
+ get: function () {
1554
+ return createTitleText;
1555
+ }
1556
+ });
1557
+ Object.defineProperty(exports, 'definePlugin', {
1558
+ enumerable: true,
1559
+ get: function () {
1560
+ return definePlugin;
1561
+ }
1562
+ });
1563
+ Object.defineProperty(exports, 'easing', {
1564
+ enumerable: true,
1565
+ get: function () {
1566
+ return easing;
1567
+ }
1568
+ });
1569
+ Object.defineProperty(exports, 'findRelativeNode', {
1570
+ enumerable: true,
1571
+ get: function () {
1572
+ return findRelativeNode;
1573
+ }
1574
+ });
1575
+ Object.defineProperty(exports, 'findRelativeNodeById', {
1576
+ enumerable: true,
1577
+ get: function () {
1578
+ return findRelativeNodeById;
1579
+ }
1580
+ });
1581
+ Object.defineProperty(exports, 'flatten', {
1582
+ enumerable: true,
1583
+ get: function () {
1584
+ return flatten;
1585
+ }
1586
+ });
1587
+ Object.defineProperty(exports, 'getNodeDepth', {
1588
+ enumerable: true,
1589
+ get: function () {
1590
+ return getNodeDepth;
1591
+ }
1592
+ });
1593
+ Object.defineProperty(exports, 'hashCode', {
1594
+ enumerable: true,
1595
+ get: function () {
1596
+ return hashCode;
1597
+ }
1598
+ });
1599
+ Object.defineProperty(exports, 'isClickEvent', {
1600
+ enumerable: true,
1601
+ get: function () {
1602
+ return isClickEvent;
1603
+ }
1604
+ });
1605
+ Object.defineProperty(exports, 'isContextMenuEvent', {
1606
+ enumerable: true,
1607
+ get: function () {
1608
+ return isContextMenuEvent;
1609
+ }
1610
+ });
1611
+ Object.defineProperty(exports, 'isMacOS', {
1612
+ enumerable: true,
1613
+ get: function () {
1614
+ return isMacOS;
1615
+ }
1616
+ });
1617
+ Object.defineProperty(exports, 'isMouseEvent', {
1618
+ enumerable: true,
1619
+ get: function () {
1620
+ return isMouseEvent;
1621
+ }
1622
+ });
1623
+ Object.defineProperty(exports, 'isScrollWheelOrRightButtonOnMouseupAndDown', {
1624
+ enumerable: true,
1625
+ get: function () {
1626
+ return isScrollWheelOrRightButtonOnMouseupAndDown;
1627
+ }
1628
+ });
1629
+ Object.defineProperty(exports, 'isWheelEvent', {
1630
+ enumerable: true,
1631
+ get: function () {
1632
+ return isWheelEvent;
1633
+ }
1634
+ });
1635
+ Object.defineProperty(exports, 'logger', {
1636
+ enumerable: true,
1637
+ get: function () {
1638
+ return logger;
1639
+ }
1640
+ });
1641
+ Object.defineProperty(exports, 'mixin', {
1642
+ enumerable: true,
1643
+ get: function () {
1644
+ return mixin;
1645
+ }
1646
+ });
1647
+ Object.defineProperty(exports, 'mixinWithParams', {
1648
+ enumerable: true,
1649
+ get: function () {
1650
+ return mixinWithParams;
1651
+ }
1652
+ });
1653
+ Object.defineProperty(exports, 'noop', {
1654
+ enumerable: true,
1655
+ get: function () {
1656
+ return noop;
1657
+ }
1658
+ });
1659
+ Object.defineProperty(exports, 'perferNumeric', {
1660
+ enumerable: true,
1661
+ get: function () {
1662
+ return perferNumeric;
1663
+ }
1664
+ });
1665
+ Object.defineProperty(exports, 'prettyStrJoin', {
1666
+ enumerable: true,
1667
+ get: function () {
1668
+ return prettyStrJoin;
1669
+ }
1670
+ });
1671
+ Object.defineProperty(exports, 'raf', {
1672
+ enumerable: true,
1673
+ get: function () {
1674
+ return raf;
1675
+ }
1676
+ });
1677
+ Object.defineProperty(exports, 'smoothFrame', {
1678
+ enumerable: true,
1679
+ get: function () {
1680
+ return smoothFrame;
1681
+ }
1682
+ });
1683
+ Object.defineProperty(exports, 'sortChildrenByKey', {
1684
+ enumerable: true,
1685
+ get: function () {
1686
+ return sortChildrenByKey;
1687
+ }
1688
+ });
1689
+ Object.defineProperty(exports, 'stackMatrixTransform', {
1690
+ enumerable: true,
1691
+ get: function () {
1692
+ return stackMatrixTransform;
1693
+ }
1694
+ });
1695
+ Object.defineProperty(exports, 'stackMatrixTransformWithGraphAndLayer', {
1696
+ enumerable: true,
1697
+ get: function () {
1698
+ return stackMatrixTransformWithGraphAndLayer;
1699
+ }
1700
+ });
1701
+ Object.defineProperty(exports, 'typedForIn', {
1702
+ enumerable: true,
1703
+ get: function () {
1704
+ return typedForIn;
1705
+ }
1706
+ });
1707
+ Object.defineProperty(exports, 'visit', {
1708
+ enumerable: true,
1709
+ get: function () {
1710
+ return visit;
1711
+ }
1712
+ });