squarified 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -18,11 +18,7 @@ class Matrix2D {
18
18
  this.f = loc.f || 0;
19
19
  }
20
20
  create(loc) {
21
- for (const { key, value } of new Iter(loc)) {
22
- if (Object.hasOwnProperty.call(this, key)) {
23
- this[key] = value;
24
- }
25
- }
21
+ Object.assign(this, loc);
26
22
  return this;
27
23
  }
28
24
  transform(x, y, scaleX, scaleY, rotation, skewX, skewY) {
@@ -89,6 +85,7 @@ var DisplayType = /* @__PURE__ */ ((DisplayType2) => {
89
85
  DisplayType2["Box"] = "Box";
90
86
  DisplayType2["Rect"] = "Rect";
91
87
  DisplayType2["Text"] = "Text";
88
+ DisplayType2["Layer"] = "Layer";
92
89
  return DisplayType2;
93
90
  })(DisplayType || {});
94
91
  class Display {
@@ -104,42 +101,44 @@ class Display {
104
101
  }
105
102
  }
106
103
  const ASSIGN_MAPPINGS = {
107
- fillStyle: true,
108
- strokeStyle: true,
109
- font: true,
110
- lineWidth: true,
111
- textAlign: true,
112
- textBaseline: true
104
+ fillStyle: 1,
105
+ strokeStyle: 2,
106
+ font: 4,
107
+ lineWidth: 8,
108
+ textAlign: 16,
109
+ textBaseline: 32
113
110
  };
111
+ const ASSIGN_MAPPINGS_MODE = ASSIGN_MAPPINGS.fillStyle | ASSIGN_MAPPINGS.strokeStyle | ASSIGN_MAPPINGS.font | ASSIGN_MAPPINGS.lineWidth | ASSIGN_MAPPINGS.textAlign | ASSIGN_MAPPINGS.textBaseline;
112
+ const CALL_MAPPINGS_MODE = 0;
114
113
  function createInstruction() {
115
114
  return {
116
115
  mods: [],
117
116
  fillStyle(...args) {
118
- this.mods.push(["fillStyle", args]);
117
+ this.mods.push({ mod: ["fillStyle", args], type: ASSIGN_MAPPINGS.fillStyle });
119
118
  },
120
119
  fillRect(...args) {
121
- this.mods.push(["fillRect", args]);
120
+ this.mods.push({ mod: ["fillRect", args], type: CALL_MAPPINGS_MODE });
122
121
  },
123
122
  strokeStyle(...args) {
124
- this.mods.push(["strokeStyle", args]);
123
+ this.mods.push({ mod: ["strokeStyle", args], type: ASSIGN_MAPPINGS.strokeStyle });
125
124
  },
126
125
  lineWidth(...args) {
127
- this.mods.push(["lineWidth", args]);
126
+ this.mods.push({ mod: ["lineWidth", args], type: ASSIGN_MAPPINGS.lineWidth });
128
127
  },
129
128
  strokeRect(...args) {
130
- this.mods.push(["strokeRect", args]);
129
+ this.mods.push({ mod: ["strokeRect", args], type: CALL_MAPPINGS_MODE });
131
130
  },
132
131
  fillText(...args) {
133
- this.mods.push(["fillText", args]);
132
+ this.mods.push({ mod: ["fillText", args], type: CALL_MAPPINGS_MODE });
134
133
  },
135
134
  font(...args) {
136
- this.mods.push(["font", args]);
135
+ this.mods.push({ mod: ["font", args], type: ASSIGN_MAPPINGS.font });
137
136
  },
138
137
  textBaseline(...args) {
139
- this.mods.push(["textBaseline", args]);
138
+ this.mods.push({ mod: ["textBaseline", args], type: ASSIGN_MAPPINGS.textBaseline });
140
139
  },
141
140
  textAlign(...args) {
142
- this.mods.push(["textAlign", args]);
141
+ this.mods.push({ mod: ["textAlign", args], type: ASSIGN_MAPPINGS.textAlign });
143
142
  }
144
143
  };
145
144
  }
@@ -170,19 +169,17 @@ class Graph extends S {
170
169
  constructor(options = {}) {
171
170
  super(options);
172
171
  __publicField$9(this, "instruction");
173
- __publicField$9(this, "__refresh__");
174
172
  __publicField$9(this, "__options__");
175
173
  this.instruction = createInstruction();
176
- this.__refresh__ = true;
177
174
  this.__options__ = options;
178
175
  }
179
176
  render(ctx) {
180
177
  this.create();
181
178
  const cap = this.instruction.mods.length;
182
179
  for (let i = 0; i < cap; i++) {
183
- const mod = this.instruction.mods[i];
180
+ const { mod, type } = this.instruction.mods[i];
184
181
  const [direct, ...args] = mod;
185
- if (direct in ASSIGN_MAPPINGS) {
182
+ if (type & ASSIGN_MAPPINGS_MODE) {
186
183
  ctx[direct] = args[0];
187
184
  continue;
188
185
  }
@@ -206,17 +203,53 @@ function isRect(display) {
206
203
  function isText(display) {
207
204
  return isGraph(display) && display.__shape__ === DisplayType.Text;
208
205
  }
206
+ function isLayer(display) {
207
+ return display.__instanceOf__ === DisplayType.Layer;
208
+ }
209
209
  const asserts = {
210
210
  isGraph,
211
211
  isBox,
212
212
  isRect,
213
- isText
213
+ isText,
214
+ isLayer
214
215
  };
215
216
 
216
217
  var __defProp$8 = Object.defineProperty;
217
218
  var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
218
- var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, key + "" , value);
219
- class Box extends Display {
219
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
220
+ class C extends Display {
221
+ constructor() {
222
+ super();
223
+ __publicField$8(this, "elements");
224
+ this.elements = [];
225
+ }
226
+ add(...elements) {
227
+ const cap = elements.length;
228
+ for (let i = 0; i < cap; i++) {
229
+ const element = elements[i];
230
+ if (element.parent) ;
231
+ this.elements.push(element);
232
+ element.parent = this;
233
+ }
234
+ }
235
+ remove(...elements) {
236
+ const cap = elements.length;
237
+ for (let i = 0; i < cap; i++) {
238
+ for (let j = this.elements.length - 1; j >= 0; j--) {
239
+ const element = this.elements[j];
240
+ if (element.id === elements[i].id) {
241
+ this.elements.splice(j, 1);
242
+ element.parent = null;
243
+ }
244
+ }
245
+ }
246
+ }
247
+ destory() {
248
+ this.elements.forEach((element) => element.parent = null);
249
+ this.elements.length = 0;
250
+ }
251
+ }
252
+ class Box extends C {
220
253
  constructor() {
221
254
  super();
222
255
  __publicField$8(this, "elements");
@@ -253,30 +286,149 @@ class Box extends Display {
253
286
  clone() {
254
287
  const box = new Box();
255
288
  if (this.elements.length) {
256
- const traverse = (elements, parent) => {
257
- const els = [];
289
+ const stack = [{ elements: this.elements, parent: box }];
290
+ while (stack.length > 0) {
291
+ const { elements, parent } = stack.pop();
258
292
  const cap = elements.length;
259
293
  for (let i = 0; i < cap; i++) {
260
294
  const element = elements[i];
261
295
  if (asserts.isBox(element)) {
262
- const box2 = new Box();
263
- box2.parent = parent;
264
- box2.add(...traverse(element.elements, box2));
265
- els.push(box2);
296
+ const newBox = new Box();
297
+ newBox.parent = parent;
298
+ parent.add(newBox);
299
+ stack.push({ elements: element.elements, parent: newBox });
266
300
  } else if (asserts.isGraph(element)) {
267
301
  const el = element.clone();
268
302
  el.parent = parent;
269
- els.push(el);
303
+ parent.add(el);
270
304
  }
271
305
  }
272
- return els;
273
- };
274
- box.add(...traverse(this.elements, box));
306
+ }
275
307
  }
276
308
  return box;
277
309
  }
278
310
  }
279
311
 
312
+ var __defProp$7 = Object.defineProperty;
313
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
314
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
315
+ function writeBoundingRectForCanvas(c, w, h, dpr) {
316
+ c.width = w * dpr;
317
+ c.height = h * dpr;
318
+ c.style.cssText = `width: ${w}px; height: ${h}px`;
319
+ }
320
+ class Canvas {
321
+ constructor(options) {
322
+ __publicField$7(this, "canvas");
323
+ __publicField$7(this, "ctx");
324
+ this.canvas = createCanvasElement();
325
+ writeBoundingRectForCanvas(this.canvas, options.width, options.height, options.devicePixelRatio);
326
+ this.ctx = this.canvas.getContext("2d");
327
+ }
328
+ get c() {
329
+ return { canvas: this.canvas, ctx: this.ctx };
330
+ }
331
+ }
332
+ class Render {
333
+ constructor(to, options) {
334
+ __publicField$7(this, "c");
335
+ __publicField$7(this, "options");
336
+ this.c = new Canvas(options);
337
+ this.options = options;
338
+ this.initOptions(options);
339
+ !options.shaow && to.appendChild(this.canvas);
340
+ }
341
+ clear(width, height) {
342
+ this.ctx.clearRect(0, 0, width, height);
343
+ }
344
+ get canvas() {
345
+ return this.c.c.canvas;
346
+ }
347
+ get ctx() {
348
+ return this.c.c.ctx;
349
+ }
350
+ initOptions(userOptions = {}) {
351
+ Object.assign(this.options, userOptions);
352
+ writeBoundingRectForCanvas(this.canvas, this.options.width, this.options.height, this.options.devicePixelRatio);
353
+ }
354
+ destory() {
355
+ }
356
+ }
357
+
358
+ var __defProp$6 = Object.defineProperty;
359
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
360
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
361
+ class Layer extends C {
362
+ constructor(options = {}) {
363
+ super();
364
+ __publicField$6(this, "c");
365
+ __publicField$6(this, "__refresh__");
366
+ __publicField$6(this, "options");
367
+ __publicField$6(this, "width");
368
+ __publicField$6(this, "height");
369
+ __publicField$6(this, "x");
370
+ __publicField$6(this, "y");
371
+ __publicField$6(this, "scaleX");
372
+ __publicField$6(this, "scaleY");
373
+ __publicField$6(this, "rotation");
374
+ __publicField$6(this, "skewX");
375
+ __publicField$6(this, "skewY");
376
+ this.c = new Canvas({ width: 0, height: 0, devicePixelRatio: 1 });
377
+ this.__refresh__ = false;
378
+ this.options = /* @__PURE__ */ Object.create(null);
379
+ this.width = options.width || 0;
380
+ this.height = options.height || 0;
381
+ this.x = options.x || 0;
382
+ this.y = options.y || 0;
383
+ this.scaleX = options.scaleX || 1;
384
+ this.scaleY = options.scaleY || 1;
385
+ this.rotation = options.rotation || 0;
386
+ this.skewX = options.skewX || 0;
387
+ this.skewY = options.skewY || 0;
388
+ }
389
+ get __instanceOf__() {
390
+ return DisplayType.Layer;
391
+ }
392
+ setCanvasOptions(options = {}) {
393
+ Object.assign(this.options, options);
394
+ writeBoundingRectForCanvas(this.c.c.canvas, options.width || 0, options.height || 0, options.devicePixelRatio || 1);
395
+ }
396
+ cleanCacheSnapshot() {
397
+ const dpr = this.options.devicePixelRatio || 1;
398
+ const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
399
+ this.ctx.clearRect(0, 0, this.options.width, this.options.height);
400
+ return { dpr, matrix };
401
+ }
402
+ setCacheSnapshot(c) {
403
+ const { matrix, dpr } = this.cleanCacheSnapshot();
404
+ matrix.transform(this.x, this.y, this.scaleX, this.scaleY, this.rotation, this.skewX, this.skewY);
405
+ applyCanvasTransform(this.ctx, matrix, dpr);
406
+ this.ctx.drawImage(c, 0, 0, this.options.width / dpr, this.options.height / dpr);
407
+ this.__refresh__ = true;
408
+ }
409
+ initLoc(options = {}) {
410
+ this.x = options.x || 0;
411
+ this.y = options.y || 0;
412
+ this.scaleX = options.scaleX || 1;
413
+ this.scaleY = options.scaleY || 1;
414
+ this.rotation = options.rotation || 0;
415
+ this.skewX = options.skewX || 0;
416
+ this.skewY = options.skewY || 0;
417
+ }
418
+ draw(ctx) {
419
+ const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
420
+ matrix.transform(this.x, this.y, this.scaleX, this.scaleY, this.rotation, this.skewX, this.skewY);
421
+ applyCanvasTransform(ctx, matrix, this.options.devicePixelRatio || 1);
422
+ ctx.drawImage(this.canvas, 0, 0);
423
+ }
424
+ get canvas() {
425
+ return this.c.c.canvas;
426
+ }
427
+ get ctx() {
428
+ return this.c.c.ctx;
429
+ }
430
+ }
431
+
280
432
  function decodeHLS(meta) {
281
433
  const { h, l, s, a } = meta;
282
434
  if ("a" in meta) {
@@ -302,13 +454,13 @@ const runtime = {
302
454
  evaluateFillStyle
303
455
  };
304
456
 
305
- var __defProp$7 = Object.defineProperty;
306
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
307
- var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, key + "" , value);
457
+ var __defProp$5 = Object.defineProperty;
458
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
459
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
308
460
  class Rect extends Graph {
309
461
  constructor(options = {}) {
310
462
  super(options);
311
- __publicField$7(this, "style");
463
+ __publicField$5(this, "style");
312
464
  this.style = options.style || /* @__PURE__ */ Object.create(null);
313
465
  }
314
466
  get __shape__() {
@@ -332,14 +484,14 @@ class Rect extends Graph {
332
484
  }
333
485
  }
334
486
 
335
- var __defProp$6 = Object.defineProperty;
336
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
337
- var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
487
+ var __defProp$4 = Object.defineProperty;
488
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
489
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
338
490
  class Text extends Graph {
339
491
  constructor(options = {}) {
340
492
  super(options);
341
- __publicField$6(this, "text");
342
- __publicField$6(this, "style");
493
+ __publicField$4(this, "text");
494
+ __publicField$4(this, "style");
343
495
  this.text = options.text || "";
344
496
  this.style = options.style || /* @__PURE__ */ Object.create(null);
345
497
  }
@@ -360,12 +512,12 @@ class Text extends Graph {
360
512
  }
361
513
  }
362
514
 
363
- var __defProp$5 = Object.defineProperty;
364
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
365
- var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, key + "" , value);
515
+ var __defProp$3 = Object.defineProperty;
516
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
517
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
366
518
  class Event {
367
519
  constructor() {
368
- __publicField$5(this, "eventCollections");
520
+ __publicField$3(this, "eventCollections");
369
521
  this.eventCollections = /* @__PURE__ */ Object.create(null);
370
522
  }
371
523
  on(evt, handler, c) {
@@ -409,47 +561,39 @@ const log = {
409
561
  }
410
562
  };
411
563
 
412
- var __defProp$4 = Object.defineProperty;
413
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
414
- var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
415
- class Render {
416
- constructor(to, options) {
417
- __publicField$4(this, "canvas");
418
- __publicField$4(this, "ctx");
419
- __publicField$4(this, "options");
420
- this.canvas = document.createElement("canvas");
421
- this.ctx = this.canvas.getContext("2d");
422
- this.options = options;
423
- this.initOptions(options);
424
- to.appendChild(this.canvas);
425
- }
426
- clear(width, height) {
427
- this.ctx.clearRect(0, 0, width, height);
428
- }
429
- initOptions(userOptions = {}) {
430
- Object.assign(this.options, userOptions);
431
- const { options } = this;
432
- this.canvas.width = options.width * options.devicePixelRatio;
433
- this.canvas.height = options.height * options.devicePixelRatio;
434
- this.canvas.style.cssText = `width: ${options.width}px; height: ${options.height}px`;
435
- }
436
- update(schedule) {
437
- this.clear(this.options.width, this.options.height);
438
- schedule.execute(this);
564
+ var __defProp$2 = Object.defineProperty;
565
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
566
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
567
+ function drawGraphIntoCanvas(graph, opts, callback) {
568
+ const { ctx, dpr } = opts;
569
+ ctx.save();
570
+ if (asserts.isLayer(graph) && graph.__refresh__) {
571
+ callback(opts, graph);
572
+ return;
573
+ }
574
+ if (asserts.isLayer(graph) || asserts.isBox(graph)) {
575
+ const elements = graph.elements;
576
+ const cap = elements.length;
577
+ for (let i = 0; i < cap; i++) {
578
+ const element = elements[i];
579
+ drawGraphIntoCanvas(element, opts, callback);
580
+ }
581
+ callback(opts, graph);
439
582
  }
440
- destory() {
583
+ if (asserts.isGraph(graph)) {
584
+ const matrix = graph.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
585
+ matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
586
+ applyCanvasTransform(ctx, matrix, dpr);
587
+ graph.render(ctx);
441
588
  }
589
+ ctx.restore();
442
590
  }
443
-
444
- var __defProp$3 = Object.defineProperty;
445
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
446
- var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
447
- let Schedule$1 = class Schedule extends Box {
591
+ class Schedule extends Box {
448
592
  constructor(to, renderOptions = {}) {
449
593
  super();
450
- __publicField$3(this, "render");
451
- __publicField$3(this, "to");
452
- __publicField$3(this, "event");
594
+ __publicField$2(this, "render");
595
+ __publicField$2(this, "to");
596
+ __publicField$2(this, "event");
453
597
  this.to = typeof to === "string" ? document.querySelector(to) : to;
454
598
  if (!this.to) {
455
599
  throw new Error(log.error("The element to bind is not found."));
@@ -459,63 +603,43 @@ let Schedule$1 = class Schedule extends Box {
459
603
  this.event = new Event();
460
604
  this.render = new Render(this.to, renderOptions);
461
605
  }
462
- applyTransform(matrix) {
463
- const pixel = this.render.options.devicePixelRatio;
464
- this.render.ctx.setTransform(
465
- matrix.a * pixel,
466
- matrix.b * pixel,
467
- matrix.c * pixel,
468
- matrix.d * pixel,
469
- matrix.e * pixel,
470
- matrix.f * pixel
471
- );
472
- }
473
606
  update() {
474
- this.render.update(this);
607
+ this.render.clear(this.render.options.width, this.render.options.height);
608
+ this.execute(this.render, this);
475
609
  const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
476
- this.applyTransform(matrix);
610
+ applyCanvasTransform(this.render.ctx, matrix, this.render.options.devicePixelRatio);
477
611
  }
478
612
  // execute all graph elements
479
613
  execute(render, graph = this) {
480
- render.ctx.save();
481
- if (asserts.isBox(graph)) {
482
- const elements = graph.elements;
483
- const cap = elements.length;
484
- const matrices = new Array(cap);
485
- for (let i = 0; i < cap; i++) {
486
- const element = elements[i];
487
- if (asserts.isGraph(element)) {
488
- matrices[i] = element.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
489
- matrices[i].transform(element.x, element.y, element.scaleX, element.scaleY, element.rotation, element.skewX, element.skewY);
614
+ drawGraphIntoCanvas(graph, { c: render.canvas, ctx: render.ctx, dpr: render.options.devicePixelRatio }, (opts, graph2) => {
615
+ if (asserts.isLayer(graph2)) {
616
+ if (graph2.__refresh__) {
617
+ graph2.draw(opts.ctx);
618
+ } else {
619
+ graph2.setCacheSnapshot(opts.c);
490
620
  }
491
621
  }
492
- for (let i = 0; i < cap; i++) {
493
- const element = elements[i];
494
- this.execute(render, element);
495
- }
496
- }
497
- if (asserts.isGraph(graph)) {
498
- const matrix = graph.matrix;
499
- this.applyTransform(matrix);
500
- graph.render(render.ctx);
501
- }
502
- render.ctx.restore();
622
+ });
503
623
  }
504
- };
624
+ }
505
625
 
506
626
  function traverse(graphs, handler) {
507
627
  const len = graphs.length;
508
628
  for (let i = 0; i < len; i++) {
509
629
  const graph = graphs[i];
510
- if (asserts.isBox(graph)) {
511
- traverse(graph.elements, handler);
512
- } else if (asserts.isGraph(graph)) {
630
+ if (asserts.isLayer(graph) && graph.__refresh__) {
513
631
  handler(graph);
632
+ continue;
633
+ }
634
+ if (asserts.isGraph(graph)) {
635
+ handler(graph);
636
+ } else if (asserts.isBox(graph) || asserts.isLayer(graph)) {
637
+ traverse(graph.elements, handler);
514
638
  }
515
639
  }
516
640
  }
517
641
  const etoile = {
518
- Schedule: Schedule$1,
642
+ Schedule,
519
643
  traverse
520
644
  };
521
645
 
@@ -544,27 +668,14 @@ const easing = {
544
668
  }
545
669
  };
546
670
 
547
- var __defProp$2 = Object.defineProperty;
548
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
549
- var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
550
- class Iter {
551
- constructor(data) {
552
- __publicField$2(this, "keys");
553
- __publicField$2(this, "data");
554
- this.data = data;
555
- this.keys = Object.keys(data);
556
- }
557
- // dprint-ignore
558
- *[Symbol.iterator]() {
559
- for (let i = 0; i < this.keys.length; i++) {
560
- yield {
561
- key: this.keys[i],
562
- value: this.data[this.keys[i]],
563
- index: i,
564
- peek: () => this.keys[i + 1]
565
- };
566
- }
567
- }
671
+ function hashCode(str) {
672
+ let hash = 0;
673
+ for (let i = 0; i < str.length; i++) {
674
+ const code = str.charCodeAt(i);
675
+ hash = (hash << 5) - hash + code;
676
+ hash = hash & hash;
677
+ }
678
+ return hash;
568
679
  }
569
680
  function perferNumeric(s) {
570
681
  if (typeof s === "number") return true;
@@ -582,6 +693,20 @@ function createTitleText(text, x, y, font, color) {
582
693
  });
583
694
  }
584
695
  const raf = window.requestAnimationFrame;
696
+ function createCanvasElement() {
697
+ return document.createElement("canvas");
698
+ }
699
+ function applyCanvasTransform(ctx, matrix, dpr) {
700
+ ctx.setTransform(matrix.a * dpr, matrix.b * dpr, matrix.c * dpr, matrix.d * dpr, matrix.e * dpr, matrix.f * dpr);
701
+ }
702
+ function mixin(app, methods) {
703
+ methods.forEach(({ name, fn }) => {
704
+ Object.defineProperty(app, name, {
705
+ value: fn(app),
706
+ writable: false
707
+ });
708
+ });
709
+ }
585
710
 
586
711
  function sortChildrenByKey(data, ...keys) {
587
712
  return data.sort((a, b) => {
@@ -648,7 +773,7 @@ function visit(data, fn) {
648
773
  }
649
774
  return null;
650
775
  }
651
- function findRelativeNode(c, p, layoutNodes) {
776
+ function findRelativeNode(p, layoutNodes) {
652
777
  return visit(layoutNodes, (node) => {
653
778
  const [x, y, w, h] = node.layout;
654
779
  if (p.x >= x && p.y >= y && p.x < x + w && p.y < y + h) {
@@ -746,9 +871,7 @@ function createEffectRun(c) {
746
871
  return (fn) => {
747
872
  const effect = () => {
748
873
  const done = fn();
749
- if (done) {
750
- c.animationFrameID = null;
751
- } else {
874
+ if (!done) {
752
875
  c.animationFrameID = raf(effect);
753
876
  }
754
877
  };
@@ -775,14 +898,6 @@ function createEffectScope() {
775
898
  }
776
899
 
777
900
  class RegisterModule {
778
- static mixin(app, methods) {
779
- methods.forEach(({ name, fn }) => {
780
- Object.defineProperty(app, name, {
781
- value: fn(app),
782
- writable: false
783
- });
784
- });
785
- }
786
901
  }
787
902
  function registerModuleForSchedule(mod) {
788
903
  if (mod instanceof RegisterModule) {
@@ -795,39 +910,45 @@ var __defProp$1 = Object.defineProperty;
795
910
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
796
911
  var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
797
912
  const primitiveEvents = ["click", "mousedown", "mousemove", "mouseup", "mouseover", "mouseout"];
913
+ const internalEventMappings = {
914
+ CLEAN_UP: "self:cleanup",
915
+ ON_LOAD: "self:onload",
916
+ ON_ZOOM: "zoom"
917
+ };
798
918
  const fill = { desc: { r: 255, g: 255, b: 255 }, mode: "rgb" };
799
919
  function smoothDrawing(c) {
800
- const { self, treemap } = c;
920
+ const { self } = c;
801
921
  const currentNode = self.currentNode;
802
922
  if (currentNode) {
803
- const { run, stop } = createEffectScope();
923
+ const effect = createEffectScope();
804
924
  const startTime = Date.now();
805
925
  const animationDuration = 300;
806
926
  const [x, y, w, h] = currentNode.layout;
807
- run(() => {
808
- if (self.forceDestroy) {
809
- stop();
810
- return true;
811
- }
927
+ effect.run(() => {
812
928
  const elapsed = Date.now() - startTime;
813
929
  const progress = Math.min(elapsed / animationDuration, 1);
930
+ if (self.forceDestroy || progress >= 1) {
931
+ effect.stop();
932
+ self.highlight.reset();
933
+ self.highlight.setDisplayLayerForHighlight();
934
+ return true;
935
+ }
814
936
  const easedProgress = easing.cubicInOut(progress);
937
+ self.highlight.reset();
815
938
  const mask = createFillBlock(x, y, w, h, { fill, opacity: 0.4 });
816
- treemap.reset();
939
+ self.highlight.highlight.add(mask);
940
+ self.highlight.setDisplayLayerForHighlight("1");
817
941
  applyForOpacity(mask, 0.4, 0.4, easedProgress);
818
- treemap.bgBox.add(mask);
819
- applyGraphTransform(treemap.elements, self.translateX, self.translateY, self.scaleRatio);
820
- treemap.update();
821
- return progress >= 1;
942
+ stackMatrixTransform(mask, self.translateX, self.translateY, self.scaleRatio);
943
+ self.highlight.highlight.update();
822
944
  });
823
945
  } else {
824
- treemap.reset();
825
- applyGraphTransform(treemap.elements, self.translateX, self.translateY, self.scaleRatio);
826
- treemap.update();
946
+ self.highlight.reset();
947
+ self.highlight.setDisplayLayerForHighlight();
827
948
  }
828
949
  }
829
950
  function applyZoomEvent(ctx) {
830
- ctx.treemap.event.on("zoom", (node) => {
951
+ ctx.treemap.event.on(internalEventMappings.ON_ZOOM, (node) => {
831
952
  const root = null;
832
953
  if (ctx.self.isDragging) return;
833
954
  onZoom(ctx, node, root);
@@ -862,9 +983,8 @@ function captureBoxXY(c, evt, a, d, translateX, translateY) {
862
983
  }
863
984
  return { x: 0, y: 0 };
864
985
  }
865
- function bindPrimitiveEvent(ctx, evt, bus) {
986
+ function bindPrimitiveEvent(c, ctx, evt, bus) {
866
987
  const { treemap, self } = ctx;
867
- const c = treemap.render.canvas;
868
988
  const handler = (e) => {
869
989
  const { x, y } = captureBoxXY(
870
990
  c,
@@ -876,7 +996,7 @@ function bindPrimitiveEvent(ctx, evt, bus) {
876
996
  );
877
997
  const event = {
878
998
  native: e,
879
- module: findRelativeNode(c, { x, y }, treemap.layoutNodes)
999
+ module: findRelativeNode({ x, y }, treemap.layoutNodes)
880
1000
  };
881
1001
  bus.emit(evt, event);
882
1002
  };
@@ -896,6 +1016,9 @@ class SelfEvent extends RegisterModule {
896
1016
  __publicField$1(this, "isDragging");
897
1017
  __publicField$1(this, "draggingState");
898
1018
  __publicField$1(this, "event");
1019
+ __publicField$1(this, "triggerZoom");
1020
+ // eslint-disable-next-line no-use-before-define
1021
+ __publicField$1(this, "highlight");
899
1022
  this.currentNode = null;
900
1023
  this.forceDestroy = false;
901
1024
  this.isDragging = false;
@@ -906,6 +1029,8 @@ class SelfEvent extends RegisterModule {
906
1029
  this.layoutHeight = 0;
907
1030
  this.draggingState = { x: 0, y: 0 };
908
1031
  this.event = new Event();
1032
+ this.triggerZoom = false;
1033
+ this.highlight = createHighlight();
909
1034
  }
910
1035
  ondragstart(metadata) {
911
1036
  const { native } = metadata;
@@ -927,8 +1052,10 @@ class SelfEvent extends RegisterModule {
927
1052
  }
928
1053
  return;
929
1054
  }
1055
+ this.self.highlight.reset();
1056
+ this.self.highlight.setDisplayLayerForHighlight();
930
1057
  this.self.event.off("mousemove", this.self.onmousemove);
931
- this.treemap.event.off("zoom");
1058
+ this.treemap.event.off(internalEventMappings.ON_ZOOM);
932
1059
  this.self.forceDestroy = true;
933
1060
  const { native } = metadata;
934
1061
  const x = native.offsetX;
@@ -939,23 +1066,25 @@ class SelfEvent extends RegisterModule {
939
1066
  this.self.translateX += drawX;
940
1067
  this.self.translateY += drawY;
941
1068
  this.self.draggingState = { x, y };
1069
+ if (this.self.triggerZoom) {
1070
+ refreshBackgroundLayer(this);
1071
+ }
942
1072
  this.treemap.reset();
943
- applyGraphTransform(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
1073
+ stackMatrixTransformWithGraphAndLayer(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
944
1074
  this.treemap.update();
945
1075
  }
946
- ondragend(metadata) {
1076
+ ondragend() {
947
1077
  if (!this.self.isDragging) {
948
1078
  return;
949
1079
  }
950
1080
  this.self.isDragging = false;
951
1081
  this.self.draggingState = { x: 0, y: 0 };
1082
+ this.self.highlight.reset();
1083
+ this.self.highlight.setDisplayLayerForHighlight();
952
1084
  this.self.event.bindWithContext(this)("mousemove", this.self.onmousemove);
953
1085
  }
954
1086
  onmousemove(metadata) {
955
1087
  const { self } = this;
956
- if (self.isDragging) {
957
- return;
958
- }
959
1088
  const { module: node } = metadata;
960
1089
  self.forceDestroy = false;
961
1090
  if (self.currentNode !== node) {
@@ -967,7 +1096,6 @@ class SelfEvent extends RegisterModule {
967
1096
  const { self } = this;
968
1097
  self.currentNode = null;
969
1098
  self.forceDestroy = true;
970
- self.isDragging = false;
971
1099
  smoothDrawing(this);
972
1100
  }
973
1101
  onwheel(metadata) {
@@ -980,7 +1108,12 @@ class SelfEvent extends RegisterModule {
980
1108
  return;
981
1109
  }
982
1110
  self.forceDestroy = true;
1111
+ if (self.triggerZoom) {
1112
+ refreshBackgroundLayer(this);
1113
+ }
983
1114
  treemap.reset();
1115
+ this.self.highlight.reset();
1116
+ this.self.highlight.setDisplayLayerForHighlight();
984
1117
  const factor = absWheelDelta > 3 ? 1.4 : absWheelDelta > 1 ? 1.2 : 1.1;
985
1118
  const delta = wheelDelta > 0 ? factor : 1 / factor;
986
1119
  self.scaleRatio *= delta;
@@ -988,11 +1121,11 @@ class SelfEvent extends RegisterModule {
988
1121
  const translateY = offsetY - (offsetY - self.translateY) * delta;
989
1122
  self.translateX = translateX;
990
1123
  self.translateY = translateY;
991
- applyGraphTransform(treemap.elements, self.translateX, self.translateY, self.scaleRatio);
1124
+ stackMatrixTransformWithGraphAndLayer(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
992
1125
  treemap.update();
993
1126
  self.forceDestroy = false;
994
1127
  }
995
- init(app, treemap, render) {
1128
+ init(app, treemap) {
996
1129
  const event = this.event;
997
1130
  const nativeEvents = [];
998
1131
  const methods = [
@@ -1009,20 +1142,31 @@ class SelfEvent extends RegisterModule {
1009
1142
  fn: () => event.emit.bind(event)
1010
1143
  }
1011
1144
  ];
1012
- RegisterModule.mixin(app, methods);
1145
+ mixin(app, methods);
1013
1146
  const selfEvents = [...primitiveEvents, "wheel"];
1014
1147
  selfEvents.forEach((evt) => {
1015
- nativeEvents.push(bindPrimitiveEvent({ treemap, self: this }, evt, event));
1148
+ nativeEvents.push(bindPrimitiveEvent(treemap.render.canvas, { treemap, self: this }, evt, event));
1016
1149
  });
1017
1150
  const selfEvt = event.bindWithContext({ treemap, self: this });
1018
1151
  selfEvt("mousedown", this.ondragstart);
1019
1152
  selfEvt("mousemove", this.ondragmove);
1020
1153
  selfEvt("mouseup", this.ondragend);
1021
- selfEvt("mousemove", this.onmousemove);
1022
- selfEvt("mouseout", this.onmouseout);
1023
1154
  selfEvt("wheel", this.onwheel);
1024
1155
  applyZoomEvent({ treemap, self: this });
1025
- treemap.event.on("cleanup:selfevent", () => {
1156
+ let installHightlightEvent = false;
1157
+ treemap.event.on(internalEventMappings.ON_LOAD, (width, height, root) => {
1158
+ this.highlight.init(width, height, root);
1159
+ if (!installHightlightEvent) {
1160
+ bindPrimitiveEvent(this.highlight.highlight.render.canvas, { treemap, self: this }, "mousemove", event);
1161
+ bindPrimitiveEvent(this.highlight.highlight.render.canvas, { treemap, self: this }, "mouseout", event);
1162
+ selfEvt("mousemove", this.onmousemove);
1163
+ selfEvt("mouseout", this.onmouseout);
1164
+ installHightlightEvent = true;
1165
+ this.highlight.setDisplayLayerForHighlight();
1166
+ }
1167
+ this.highlight.reset();
1168
+ });
1169
+ treemap.event.on(internalEventMappings.CLEAN_UP, () => {
1026
1170
  this.currentNode = null;
1027
1171
  this.scaleRatio = 1;
1028
1172
  this.translateX = 0;
@@ -1030,6 +1174,7 @@ class SelfEvent extends RegisterModule {
1030
1174
  this.layoutWidth = treemap.render.canvas.width;
1031
1175
  this.layoutHeight = treemap.render.canvas.height;
1032
1176
  this.isDragging = false;
1177
+ this.triggerZoom = false;
1033
1178
  this.draggingState = { x: 0, y: 0 };
1034
1179
  });
1035
1180
  }
@@ -1058,20 +1203,26 @@ function estimateZoomingArea(node, root, w, h) {
1058
1203
  const scaleFactor = Math.max(minScaleFactor, Math.min(maxScaleFactor, Math.sqrt(area / viewArea)));
1059
1204
  return [w * scaleFactor, h * scaleFactor];
1060
1205
  }
1061
- function applyGraphTransform(graphs, translateX, translateY, scale) {
1062
- etoile.traverse(graphs, (graph) => {
1063
- graph.x = graph.x * scale + translateX;
1064
- graph.y = graph.y * scale + translateY;
1065
- graph.scaleX = scale;
1066
- graph.scaleY = scale;
1067
- });
1206
+ function stackMatrixTransform(graph, e, f, scale) {
1207
+ graph.x = graph.x * scale + e;
1208
+ graph.y = graph.y * scale + f;
1209
+ graph.scaleX = scale;
1210
+ graph.scaleY = scale;
1211
+ }
1212
+ function stackMatrixTransformWithGraphAndLayer(graphs, e, f, scale) {
1213
+ etoile.traverse(graphs, (graph) => stackMatrixTransform(graph, e, f, scale));
1068
1214
  }
1069
1215
  function onZoom(ctx, node, root) {
1070
1216
  if (!node) return;
1071
1217
  const { treemap, self } = ctx;
1218
+ self.forceDestroy = true;
1072
1219
  const c = treemap.render.canvas;
1073
1220
  const boundingClientRect = c.getBoundingClientRect();
1074
1221
  const [w, h] = estimateZoomingArea(node, root, boundingClientRect.width, boundingClientRect.height);
1222
+ if (self.layoutHeight !== w || self.layoutHeight !== h) {
1223
+ delete treemap.fontsCaches[node.node.id];
1224
+ delete treemap.ellispsisWidthCache[node.node.id];
1225
+ }
1075
1226
  resetLayout(treemap, w, h);
1076
1227
  const module = findRelativeNodeById(node.node.id, treemap.layoutNodes);
1077
1228
  if (module) {
@@ -1084,18 +1235,18 @@ function onZoom(ctx, node, root) {
1084
1235
  const initialTranslateY = self.translateY;
1085
1236
  const startTime = Date.now();
1086
1237
  const animationDuration = 300;
1087
- if (self.layoutHeight !== w || self.layoutHeight !== h) {
1088
- delete treemap.fontsCaches[module.node.id];
1089
- delete treemap.ellispsisWidthCache[module.node.id];
1090
- }
1091
1238
  const { run, stop } = createEffectScope();
1092
1239
  run(() => {
1093
1240
  const elapsed = Date.now() - startTime;
1094
1241
  const progress = Math.min(elapsed / animationDuration, 1);
1242
+ treemap.backgroundLayer.__refresh__ = false;
1095
1243
  if (progress >= 1) {
1096
1244
  stop();
1097
1245
  self.layoutWidth = w;
1098
1246
  self.layoutHeight = h;
1247
+ self.forceDestroy = false;
1248
+ self.triggerZoom = true;
1249
+ return true;
1099
1250
  }
1100
1251
  const easedProgress = easing.cubicInOut(progress);
1101
1252
  const scaleRatio = initialScale + (scale - initialScale) * easedProgress;
@@ -1103,9 +1254,8 @@ function onZoom(ctx, node, root) {
1103
1254
  self.translateY = initialTranslateY + (translateY - initialTranslateY) * easedProgress;
1104
1255
  self.scaleRatio = scaleRatio;
1105
1256
  treemap.reset();
1106
- applyGraphTransform(treemap.elements, self.translateX, self.translateY, scaleRatio);
1257
+ stackMatrixTransformWithGraphAndLayer(treemap.elements, self.translateX, self.translateY, scaleRatio);
1107
1258
  treemap.update();
1108
- return progress >= 1;
1109
1259
  });
1110
1260
  }
1111
1261
  root = node;
@@ -1113,6 +1263,55 @@ function onZoom(ctx, node, root) {
1113
1263
  function isScrollWheelOrRightButtonOnMouseupAndDown(e) {
1114
1264
  return e.which === 2 || e.which === 3;
1115
1265
  }
1266
+ function createHighlight() {
1267
+ let s = null;
1268
+ const setDisplayLayerForHighlight = (layer = "-1") => {
1269
+ if (!s) return;
1270
+ const c = s.render.canvas;
1271
+ c.style.zIndex = layer;
1272
+ };
1273
+ const init = (w, h, root) => {
1274
+ if (!s) {
1275
+ s = new Schedule(root, { width: w, height: h });
1276
+ }
1277
+ setDisplayLayerForHighlight();
1278
+ s.render.canvas.style.position = "absolute";
1279
+ s.render.canvas.style.pointerEvents = "none";
1280
+ };
1281
+ const reset = () => {
1282
+ if (!s) return;
1283
+ s.destory();
1284
+ s.update();
1285
+ };
1286
+ return {
1287
+ init,
1288
+ reset,
1289
+ setDisplayLayerForHighlight,
1290
+ get highlight() {
1291
+ return s;
1292
+ }
1293
+ };
1294
+ }
1295
+ function refreshBackgroundLayer(c) {
1296
+ const { treemap, self } = c;
1297
+ const { backgroundLayer, render } = treemap;
1298
+ const { canvas, ctx, options: { width: ow, height: oh } } = render;
1299
+ const { layoutWidth: sw, layoutHeight: sh, scaleRatio: ss } = self;
1300
+ const capture = sw * ss >= ow && sh * ss >= oh;
1301
+ backgroundLayer.__refresh__ = false;
1302
+ if (!capture && !self.forceDestroy) {
1303
+ resetLayout(treemap, sw * ss, sh * ss);
1304
+ render.clear(ow, oh);
1305
+ const { dpr } = backgroundLayer.cleanCacheSnapshot();
1306
+ drawGraphIntoCanvas(backgroundLayer, { c: canvas, ctx, dpr }, (opts, graph) => {
1307
+ if (asserts.isLayer(graph) && !graph.__refresh__) {
1308
+ graph.setCacheSnapshot(opts.c);
1309
+ }
1310
+ });
1311
+ self.triggerZoom = false;
1312
+ return true;
1313
+ }
1314
+ }
1116
1315
 
1117
1316
  var __defProp = Object.defineProperty;
1118
1317
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -1167,33 +1366,32 @@ function getSafeText(c, text, width, cache) {
1167
1366
  }
1168
1367
  function resetLayout(treemap, w, h) {
1169
1368
  treemap.layoutNodes = squarify(treemap.data, { w, h, x: 0, y: 0 }, treemap.decorator.layout);
1170
- treemap.reset();
1171
- }
1172
- class Schedule extends etoile.Schedule {
1369
+ treemap.reset(true);
1173
1370
  }
1174
- class TreemapLayout extends Schedule {
1371
+ class TreemapLayout extends etoile.Schedule {
1175
1372
  constructor(...args) {
1176
1373
  super(...args);
1177
1374
  __publicField(this, "data");
1178
1375
  __publicField(this, "layoutNodes");
1179
1376
  __publicField(this, "decorator");
1180
- __publicField(this, "bgBox");
1377
+ __publicField(this, "bgLayer");
1181
1378
  __publicField(this, "fgBox");
1182
1379
  __publicField(this, "fontsCaches");
1183
1380
  __publicField(this, "ellispsisWidthCache");
1184
1381
  this.data = [];
1185
1382
  this.layoutNodes = [];
1186
- this.bgBox = new Box();
1383
+ this.bgLayer = new Layer();
1187
1384
  this.fgBox = new Box();
1188
1385
  this.decorator = /* @__PURE__ */ Object.create(null);
1189
1386
  this.fontsCaches = /* @__PURE__ */ Object.create(null);
1190
1387
  this.ellispsisWidthCache = /* @__PURE__ */ Object.create(null);
1388
+ this.bgLayer.setCanvasOptions(this.render.options);
1191
1389
  }
1192
1390
  drawBackgroundNode(node) {
1193
1391
  const [x, y, w, h] = node.layout;
1194
1392
  const fill = this.decorator.color.mappings[node.node.id];
1195
1393
  const s = createFillBlock(x, y, w, h, { fill });
1196
- this.bgBox.add(s);
1394
+ this.bgLayer.add(s);
1197
1395
  for (const child of node.children) {
1198
1396
  this.drawBackgroundNode(child);
1199
1397
  }
@@ -1210,7 +1408,7 @@ class TreemapLayout extends Schedule {
1210
1408
  } else {
1211
1409
  optimalFontSize = evaluateOptimalFontSize(
1212
1410
  this.render.ctx,
1213
- node.node.id,
1411
+ node.node.label,
1214
1412
  {
1215
1413
  range: fontSize,
1216
1414
  family: fontFamily
@@ -1221,7 +1419,7 @@ class TreemapLayout extends Schedule {
1221
1419
  this.fontsCaches[node.node.id] = optimalFontSize;
1222
1420
  }
1223
1421
  this.render.ctx.font = `${optimalFontSize}px ${fontFamily}`;
1224
- const result = getSafeText(this.render.ctx, node.node.id, w - rectGap * 2, this.ellispsisWidthCache);
1422
+ const result = getSafeText(this.render.ctx, node.node.label, w - rectGap * 2, this.ellispsisWidthCache);
1225
1423
  if (!result) return;
1226
1424
  if (result.width >= w || optimalFontSize >= h) return;
1227
1425
  const { text, width } = result;
@@ -1232,24 +1430,37 @@ class TreemapLayout extends Schedule {
1232
1430
  this.drawForegroundNode(child);
1233
1431
  }
1234
1432
  }
1235
- reset() {
1236
- this.bgBox.destory();
1237
- this.fgBox.destory();
1238
- this.remove(this.bgBox, this.fgBox);
1239
- this.render.ctx.textBaseline = "middle";
1240
- for (const node of this.layoutNodes) {
1241
- this.drawBackgroundNode(node);
1242
- this.drawForegroundNode(node);
1433
+ reset(refresh = false) {
1434
+ this.remove(this.bgLayer, this.fgBox);
1435
+ if (!this.bgLayer.__refresh__) {
1436
+ this.bgLayer.destory();
1437
+ for (const node of this.layoutNodes) {
1438
+ this.drawBackgroundNode(node);
1439
+ }
1440
+ } else {
1441
+ this.bgLayer.initLoc();
1442
+ }
1443
+ if (!this.fgBox.elements.length || refresh) {
1444
+ this.render.ctx.textBaseline = "middle";
1445
+ this.fgBox.destory();
1446
+ for (const node of this.layoutNodes) {
1447
+ this.drawForegroundNode(node);
1448
+ }
1449
+ } else {
1450
+ this.fgBox = this.fgBox.clone();
1243
1451
  }
1244
- this.add(this.bgBox, this.fgBox);
1452
+ this.add(this.bgLayer, this.fgBox);
1245
1453
  }
1246
1454
  get api() {
1247
1455
  return {
1248
1456
  zoom: (node) => {
1249
- this.event.emit("zoom", node);
1457
+ this.event.emit(internalEventMappings.ON_ZOOM, node);
1250
1458
  }
1251
1459
  };
1252
1460
  }
1461
+ get backgroundLayer() {
1462
+ return this.bgLayer;
1463
+ }
1253
1464
  }
1254
1465
  function createTreemap() {
1255
1466
  let treemap = null;
@@ -1267,6 +1478,13 @@ function createTreemap() {
1267
1478
  function init(el) {
1268
1479
  treemap = new TreemapLayout(el);
1269
1480
  root = el;
1481
+ root.style.position = "relative";
1482
+ if (!installed) {
1483
+ for (const registry of defaultRegistries) {
1484
+ registry(context, treemap, treemap.render);
1485
+ }
1486
+ installed = true;
1487
+ }
1270
1488
  }
1271
1489
  function dispose() {
1272
1490
  if (root && treemap) {
@@ -1279,9 +1497,15 @@ function createTreemap() {
1279
1497
  function resize() {
1280
1498
  if (!treemap || !root) return;
1281
1499
  const { width, height } = root.getBoundingClientRect();
1500
+ treemap.backgroundLayer.__refresh__ = false;
1282
1501
  treemap.render.initOptions({ height, width, devicePixelRatio: window.devicePixelRatio });
1502
+ treemap.render.canvas.style.position = "absolute";
1503
+ treemap.backgroundLayer.setCanvasOptions(treemap.render.options);
1504
+ treemap.backgroundLayer.initLoc();
1505
+ treemap.backgroundLayer.matrix = treemap.backgroundLayer.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
1283
1506
  treemap.fontsCaches = /* @__PURE__ */ Object.create(null);
1284
- treemap.event.emit("cleanup:selfevent");
1507
+ treemap.event.emit(internalEventMappings.CLEAN_UP);
1508
+ treemap.event.emit(internalEventMappings.ON_LOAD, width, height, root);
1285
1509
  resetLayout(treemap, width, height);
1286
1510
  treemap.update();
1287
1511
  }
@@ -1290,12 +1514,6 @@ function createTreemap() {
1290
1514
  throw new Error("Treemap not initialized");
1291
1515
  }
1292
1516
  treemap.data = bindParentForModule(options.data || []);
1293
- if (!installed) {
1294
- for (const registry of defaultRegistries) {
1295
- registry(context, treemap, treemap.render);
1296
- }
1297
- installed = true;
1298
- }
1299
1517
  for (const use2 of uses) {
1300
1518
  use2(treemap);
1301
1519
  }
@@ -1339,54 +1557,66 @@ function presetDecorator(app) {
1339
1557
  Object.assign(app.decorator, {
1340
1558
  layout: defaultLayoutOptions,
1341
1559
  font: defaultFontOptions,
1342
- color: colorMappings(app)
1560
+ color: { mappings: evaluateColorMappings(app.data) }
1343
1561
  });
1344
1562
  }
1345
- function colorDecorator(node, state) {
1346
- const depth = getNodeDepth(node);
1347
- let baseHue = 0;
1348
- let sweepAngle = Math.PI * 2;
1349
- const totalHueRange = Math.PI;
1350
- if (node.parent) {
1351
- sweepAngle = node.weight / node.parent.weight * sweepAngle;
1352
- baseHue = state.hue + sweepAngle / Math.PI * 180;
1353
- }
1354
- baseHue += sweepAngle;
1355
- const depthHueOffset = depth + totalHueRange / 10;
1356
- const finalHue = baseHue + depthHueOffset / 2;
1357
- const saturation = 0.6 + 0.4 * Math.max(0, Math.cos(finalHue));
1358
- const lightness = 0.5 + 0.2 * Math.max(0, Math.cos(finalHue + Math.PI * 2 / 3));
1359
- state.hue = baseHue;
1360
- return {
1361
- mode: "hsl",
1362
- desc: {
1363
- h: finalHue,
1364
- s: Math.round(saturation * 100),
1365
- l: Math.round(lightness * 100)
1366
- }
1563
+ function evaluateColorMappings(data) {
1564
+ const colorMappings = {};
1565
+ const hashToHue = (id) => {
1566
+ const hash = Math.abs(hashCode(id));
1567
+ return hash % 360;
1367
1568
  };
1368
- }
1369
- function evaluateColorMappingByNode(node, state) {
1370
- const colorMappings2 = {};
1371
- if (node.groups && Array.isArray(node.groups)) {
1372
- for (const child of node.groups) {
1373
- Object.assign(colorMappings2, evaluateColorMappingByNode(child, state));
1569
+ const lightScale = (depth) => 70 - depth * 5;
1570
+ const baseSaturation = 40;
1571
+ const siblingHueShift = 20;
1572
+ const rc = 0.2126;
1573
+ const gc = 0.7152;
1574
+ const bc = 0.0722;
1575
+ const hslToRgb = (h, s, l) => {
1576
+ const a = s * Math.min(l, 1 - l);
1577
+ const f = (n) => {
1578
+ const k = (n + h / 30) % 12;
1579
+ return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1580
+ };
1581
+ return { r: f(0), g: f(8), b: f(4) };
1582
+ };
1583
+ const calculateLuminance = (r, g, b) => {
1584
+ return rc * r + gc * g + bc * b;
1585
+ };
1586
+ const calculateColor = (module, depth, parentHue, siblingIndex, totalSiblings) => {
1587
+ const nodeHue = hashToHue(module.id);
1588
+ const hue = parentHue !== null ? (parentHue + siblingHueShift * siblingIndex / totalSiblings) % 360 : nodeHue;
1589
+ const lightness = lightScale(depth);
1590
+ const hslColor = {
1591
+ h: hue,
1592
+ s: baseSaturation,
1593
+ l: lightness / 100
1594
+ };
1595
+ const { r, g, b } = hslToRgb(hslColor.h, hslColor.s / 100, hslColor.l);
1596
+ const luminance = calculateLuminance(r, g, b);
1597
+ if (luminance < 0.6) {
1598
+ hslColor.l += 0.2;
1599
+ } else if (luminance > 0.8) {
1600
+ hslColor.l -= 0.1;
1601
+ }
1602
+ hslColor.l *= 100;
1603
+ colorMappings[module.id] = {
1604
+ mode: "hsl",
1605
+ desc: hslColor
1606
+ };
1607
+ if (module.groups && Array.isArray(module.groups)) {
1608
+ const totalChildren = module.groups.length;
1609
+ for (let i = 0; i < totalChildren; i++) {
1610
+ const child = module.groups[i];
1611
+ calculateColor(child, depth + 1, hue, i, totalChildren);
1612
+ }
1374
1613
  }
1375
- }
1376
- if (node.id) {
1377
- colorMappings2[node.id] = colorDecorator(node, state);
1378
- }
1379
- return colorMappings2;
1380
- }
1381
- function colorMappings(app) {
1382
- const colorMappings2 = {};
1383
- const state = {
1384
- hue: 0
1385
1614
  };
1386
- for (const node of app.data) {
1387
- Object.assign(colorMappings2, evaluateColorMappingByNode(node, state));
1615
+ for (let i = 0; i < data.length; i++) {
1616
+ const module = data[i];
1617
+ calculateColor(module, 0, null, i, data.length);
1388
1618
  }
1389
- return { mappings: colorMappings2 };
1619
+ return colorMappings;
1390
1620
  }
1391
1621
 
1392
1622
  export { TreemapLayout, c2m, createTreemap, defaultFontOptions, defaultLayoutOptions, findRelativeNode, findRelativeNodeById, flatten as flattenModule, getNodeDepth, presetDecorator, sortChildrenByKey, visit };