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/README.md +42 -8
- package/dist/index.d.mts +87 -67
- package/dist/index.d.ts +87 -67
- package/dist/index.js +502 -272
- package/dist/index.mjs +502 -272
- package/package.json +7 -13
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
|
-
|
|
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:
|
|
108
|
-
strokeStyle:
|
|
109
|
-
font:
|
|
110
|
-
lineWidth:
|
|
111
|
-
textAlign:
|
|
112
|
-
textBaseline:
|
|
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 (
|
|
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
|
|
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
|
|
257
|
-
|
|
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
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
303
|
+
parent.add(el);
|
|
270
304
|
}
|
|
271
305
|
}
|
|
272
|
-
|
|
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$
|
|
306
|
-
var __defNormalProp$
|
|
307
|
-
var __publicField$
|
|
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$
|
|
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$
|
|
336
|
-
var __defNormalProp$
|
|
337
|
-
var __publicField$
|
|
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$
|
|
342
|
-
__publicField$
|
|
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$
|
|
364
|
-
var __defNormalProp$
|
|
365
|
-
var __publicField$
|
|
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$
|
|
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$
|
|
413
|
-
var __defNormalProp$
|
|
414
|
-
var __publicField$
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
|
|
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$
|
|
451
|
-
__publicField$
|
|
452
|
-
__publicField$
|
|
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.
|
|
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.
|
|
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.
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
642
|
+
Schedule,
|
|
519
643
|
traverse
|
|
520
644
|
};
|
|
521
645
|
|
|
@@ -544,27 +668,14 @@ const easing = {
|
|
|
544
668
|
}
|
|
545
669
|
};
|
|
546
670
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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(
|
|
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
|
|
920
|
+
const { self } = c;
|
|
801
921
|
const currentNode = self.currentNode;
|
|
802
922
|
if (currentNode) {
|
|
803
|
-
const
|
|
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
|
-
|
|
939
|
+
self.highlight.highlight.add(mask);
|
|
940
|
+
self.highlight.setDisplayLayerForHighlight("1");
|
|
817
941
|
applyForOpacity(mask, 0.4, 0.4, easedProgress);
|
|
818
|
-
|
|
819
|
-
|
|
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
|
-
|
|
825
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1073
|
+
stackMatrixTransformWithGraphAndLayer(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
|
|
944
1074
|
this.treemap.update();
|
|
945
1075
|
}
|
|
946
|
-
ondragend(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
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
|
-
|
|
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, "
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1237
|
-
this.
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
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.
|
|
1452
|
+
this.add(this.bgLayer, this.fgBox);
|
|
1245
1453
|
}
|
|
1246
1454
|
get api() {
|
|
1247
1455
|
return {
|
|
1248
1456
|
zoom: (node) => {
|
|
1249
|
-
this.event.emit(
|
|
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(
|
|
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:
|
|
1560
|
+
color: { mappings: evaluateColorMappings(app.data) }
|
|
1343
1561
|
});
|
|
1344
1562
|
}
|
|
1345
|
-
function
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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
|
-
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
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 (
|
|
1387
|
-
|
|
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
|
|
1619
|
+
return colorMappings;
|
|
1390
1620
|
}
|
|
1391
1621
|
|
|
1392
1622
|
export { TreemapLayout, c2m, createTreemap, defaultFontOptions, defaultLayoutOptions, findRelativeNode, findRelativeNodeById, flatten as flattenModule, getNodeDepth, presetDecorator, sortChildrenByKey, visit };
|