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