squarified 0.3.5 → 0.3.7
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 +1 -1
- package/dist/index.d.mts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +1761 -1482
- package/dist/index.mjs +1761 -1482
- package/package.json +39 -17
- package/.jiek-production-tag +0 -0
package/dist/index.js
CHANGED
|
@@ -1,1697 +1,1976 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var __defProp$c = Object.defineProperty;
|
|
4
|
-
var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __publicField$c = (obj, key, value) => __defNormalProp$c(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
3
|
const DEG_TO_RAD = Math.PI / 180;
|
|
7
4
|
class Matrix2D {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
5
|
+
a;
|
|
6
|
+
b;
|
|
7
|
+
c;
|
|
8
|
+
d;
|
|
9
|
+
e;
|
|
10
|
+
f;
|
|
11
|
+
constructor(loc = {}){
|
|
12
|
+
this.a = loc.a || 1;
|
|
13
|
+
this.b = loc.b || 0;
|
|
14
|
+
this.c = loc.c || 0;
|
|
15
|
+
this.d = loc.d || 1;
|
|
16
|
+
this.e = loc.e || 0;
|
|
17
|
+
this.f = loc.f || 0;
|
|
18
|
+
}
|
|
19
|
+
create(loc) {
|
|
20
|
+
Object.assign(this, loc);
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
transform(x, y, scaleX, scaleY, rotation, skewX, skewY) {
|
|
24
|
+
this.scale(scaleX, scaleY).translation(x, y);
|
|
25
|
+
if (skewX || skewY) {
|
|
26
|
+
this.skew(skewX, skewY);
|
|
27
|
+
} else {
|
|
28
|
+
this.roate(rotation);
|
|
29
|
+
}
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
translation(x, y) {
|
|
33
|
+
this.e += x;
|
|
34
|
+
this.f += y;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
scale(a, d) {
|
|
38
|
+
this.a *= a;
|
|
39
|
+
this.d *= d;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
skew(x, y) {
|
|
43
|
+
const tanX = Math.tan(x * DEG_TO_RAD);
|
|
44
|
+
const tanY = Math.tan(y * DEG_TO_RAD);
|
|
45
|
+
const a = this.a + this.b * tanX;
|
|
46
|
+
const b = this.b + this.a * tanY;
|
|
47
|
+
const c = this.c + this.d * tanX;
|
|
48
|
+
const d = this.d + this.c * tanY;
|
|
49
|
+
this.a = a;
|
|
50
|
+
this.b = b;
|
|
51
|
+
this.c = c;
|
|
52
|
+
this.d = d;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
roate(rotation) {
|
|
56
|
+
if (rotation > 0) {
|
|
57
|
+
const rad = rotation * DEG_TO_RAD;
|
|
58
|
+
const cosTheta = Math.cos(rad);
|
|
59
|
+
const sinTheta = Math.sin(rad);
|
|
60
|
+
const a = this.a * cosTheta - this.b * sinTheta;
|
|
61
|
+
const b = this.a * sinTheta + this.b * cosTheta;
|
|
62
|
+
const c = this.c * cosTheta - this.d * sinTheta;
|
|
63
|
+
const d = this.c * sinTheta + this.d * cosTheta;
|
|
64
|
+
this.a = a;
|
|
65
|
+
this.b = b;
|
|
66
|
+
this.c = c;
|
|
67
|
+
this.d = d;
|
|
68
|
+
}
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
74
71
|
}
|
|
75
72
|
|
|
76
|
-
var __defProp$b = Object.defineProperty;
|
|
77
|
-
var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
78
|
-
var __publicField$b = (obj, key, value) => __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
79
73
|
const SELF_ID = {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
id: 0,
|
|
75
|
+
get () {
|
|
76
|
+
return this.id++;
|
|
77
|
+
}
|
|
84
78
|
};
|
|
85
|
-
var DisplayType =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
79
|
+
var DisplayType = /*#__PURE__*/ function(DisplayType) {
|
|
80
|
+
DisplayType["Graph"] = "Graph";
|
|
81
|
+
DisplayType["Box"] = "Box";
|
|
82
|
+
DisplayType["Text"] = "Text";
|
|
83
|
+
DisplayType["RoundRect"] = "RoundRect";
|
|
84
|
+
DisplayType["Bitmap"] = "Bitmap";
|
|
85
|
+
return DisplayType;
|
|
86
|
+
}({});
|
|
93
87
|
class Display {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
88
|
+
parent;
|
|
89
|
+
id;
|
|
90
|
+
matrix;
|
|
91
|
+
constructor(){
|
|
92
|
+
this.parent = null;
|
|
93
|
+
this.id = SELF_ID.get();
|
|
94
|
+
this.matrix = new Matrix2D();
|
|
95
|
+
}
|
|
96
|
+
destory() {
|
|
97
|
+
//
|
|
98
|
+
}
|
|
104
99
|
}
|
|
105
100
|
const ASSIGN_MAPPINGS = {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
fillStyle: 0o1,
|
|
102
|
+
strokeStyle: 0o2,
|
|
103
|
+
font: 0o4,
|
|
104
|
+
lineWidth: 0o10,
|
|
105
|
+
textAlign: 0o20,
|
|
106
|
+
textBaseline: 0o40
|
|
112
107
|
};
|
|
113
108
|
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 =
|
|
109
|
+
const CALL_MAPPINGS_MODE = 0o0;
|
|
115
110
|
function createInstruction() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
111
|
+
return {
|
|
112
|
+
mods: [],
|
|
113
|
+
fillStyle (...args) {
|
|
114
|
+
this.mods.push({
|
|
115
|
+
mod: [
|
|
116
|
+
'fillStyle',
|
|
117
|
+
args
|
|
118
|
+
],
|
|
119
|
+
type: ASSIGN_MAPPINGS.fillStyle
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
fillRect (...args) {
|
|
123
|
+
this.mods.push({
|
|
124
|
+
mod: [
|
|
125
|
+
'fillRect',
|
|
126
|
+
args
|
|
127
|
+
],
|
|
128
|
+
type: CALL_MAPPINGS_MODE
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
strokeStyle (...args) {
|
|
132
|
+
this.mods.push({
|
|
133
|
+
mod: [
|
|
134
|
+
'strokeStyle',
|
|
135
|
+
args
|
|
136
|
+
],
|
|
137
|
+
type: ASSIGN_MAPPINGS.strokeStyle
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
lineWidth (...args) {
|
|
141
|
+
this.mods.push({
|
|
142
|
+
mod: [
|
|
143
|
+
'lineWidth',
|
|
144
|
+
args
|
|
145
|
+
],
|
|
146
|
+
type: ASSIGN_MAPPINGS.lineWidth
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
strokeRect (...args) {
|
|
150
|
+
this.mods.push({
|
|
151
|
+
mod: [
|
|
152
|
+
'strokeRect',
|
|
153
|
+
args
|
|
154
|
+
],
|
|
155
|
+
type: CALL_MAPPINGS_MODE
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
fillText (...args) {
|
|
159
|
+
this.mods.push({
|
|
160
|
+
mod: [
|
|
161
|
+
'fillText',
|
|
162
|
+
args
|
|
163
|
+
],
|
|
164
|
+
type: CALL_MAPPINGS_MODE
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
font (...args) {
|
|
168
|
+
this.mods.push({
|
|
169
|
+
mod: [
|
|
170
|
+
'font',
|
|
171
|
+
args
|
|
172
|
+
],
|
|
173
|
+
type: ASSIGN_MAPPINGS.font
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
textBaseline (...args) {
|
|
177
|
+
this.mods.push({
|
|
178
|
+
mod: [
|
|
179
|
+
'textBaseline',
|
|
180
|
+
args
|
|
181
|
+
],
|
|
182
|
+
type: ASSIGN_MAPPINGS.textBaseline
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
textAlign (...args) {
|
|
186
|
+
this.mods.push({
|
|
187
|
+
mod: [
|
|
188
|
+
'textAlign',
|
|
189
|
+
args
|
|
190
|
+
],
|
|
191
|
+
type: ASSIGN_MAPPINGS.textAlign
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
beginPath () {
|
|
195
|
+
this.mods.push({
|
|
196
|
+
mod: [
|
|
197
|
+
'beginPath',
|
|
198
|
+
[]
|
|
199
|
+
],
|
|
200
|
+
type: CALL_MAPPINGS_MODE
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
moveTo (...args) {
|
|
204
|
+
this.mods.push({
|
|
205
|
+
mod: [
|
|
206
|
+
'moveTo',
|
|
207
|
+
args
|
|
208
|
+
],
|
|
209
|
+
type: CALL_MAPPINGS_MODE
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
arcTo (...args) {
|
|
213
|
+
this.mods.push({
|
|
214
|
+
mod: [
|
|
215
|
+
'arcTo',
|
|
216
|
+
args
|
|
217
|
+
],
|
|
218
|
+
type: CALL_MAPPINGS_MODE
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
closePath () {
|
|
222
|
+
this.mods.push({
|
|
223
|
+
mod: [
|
|
224
|
+
'closePath',
|
|
225
|
+
[]
|
|
226
|
+
],
|
|
227
|
+
type: CALL_MAPPINGS_MODE
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
fill () {
|
|
231
|
+
this.mods.push({
|
|
232
|
+
mod: [
|
|
233
|
+
'fill',
|
|
234
|
+
[]
|
|
235
|
+
],
|
|
236
|
+
type: CALL_MAPPINGS_MODE
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
stroke () {
|
|
240
|
+
this.mods.push({
|
|
241
|
+
mod: [
|
|
242
|
+
'stroke',
|
|
243
|
+
[]
|
|
244
|
+
],
|
|
245
|
+
type: CALL_MAPPINGS_MODE
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
drawImage (...args) {
|
|
249
|
+
// @ts-expect-error safe
|
|
250
|
+
this.mods.push({
|
|
251
|
+
mod: [
|
|
252
|
+
'drawImage',
|
|
253
|
+
args
|
|
254
|
+
],
|
|
255
|
+
type: CALL_MAPPINGS_MODE
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
167
259
|
}
|
|
168
260
|
class S extends Display {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
261
|
+
width;
|
|
262
|
+
height;
|
|
263
|
+
x;
|
|
264
|
+
y;
|
|
265
|
+
scaleX;
|
|
266
|
+
scaleY;
|
|
267
|
+
rotation;
|
|
268
|
+
skewX;
|
|
269
|
+
skewY;
|
|
270
|
+
constructor(options = {}){
|
|
271
|
+
super();
|
|
272
|
+
this.width = options.width || 0;
|
|
273
|
+
this.height = options.height || 0;
|
|
274
|
+
this.x = options.x || 0;
|
|
275
|
+
this.y = options.y || 0;
|
|
276
|
+
this.scaleX = options.scaleX || 1;
|
|
277
|
+
this.scaleY = options.scaleY || 1;
|
|
278
|
+
this.rotation = options.rotation || 0;
|
|
279
|
+
this.skewX = options.skewX || 0;
|
|
280
|
+
this.skewY = options.skewY || 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// For performance. we need impl AABB Check for render.
|
|
191
284
|
class Graph extends S {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
285
|
+
instruction;
|
|
286
|
+
__options__;
|
|
287
|
+
__widget__;
|
|
288
|
+
constructor(options = {}){
|
|
289
|
+
super(options);
|
|
290
|
+
this.instruction = createInstruction();
|
|
291
|
+
this.__options__ = options;
|
|
292
|
+
this.__widget__ = null;
|
|
293
|
+
}
|
|
294
|
+
render(ctx) {
|
|
295
|
+
this.create();
|
|
296
|
+
const cap = this.instruction.mods.length;
|
|
297
|
+
for(let i = 0; i < cap; i++){
|
|
298
|
+
const { mod, type } = this.instruction.mods[i];
|
|
299
|
+
const [direct, ...args] = mod;
|
|
300
|
+
if (type & ASSIGN_MAPPINGS_MODE) {
|
|
301
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
302
|
+
// @ts-expect-error
|
|
303
|
+
ctx[direct] = args[0];
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
307
|
+
// @ts-expect-error
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
309
|
+
ctx[direct].apply(ctx, ...args);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
get __instanceOf__() {
|
|
313
|
+
return "Graph";
|
|
314
|
+
}
|
|
217
315
|
}
|
|
218
316
|
|
|
219
317
|
function isGraph(display) {
|
|
220
|
-
|
|
318
|
+
return display.__instanceOf__ === DisplayType.Graph;
|
|
221
319
|
}
|
|
222
320
|
function isBox(display) {
|
|
223
|
-
|
|
321
|
+
return display.__instanceOf__ === DisplayType.Box;
|
|
224
322
|
}
|
|
225
323
|
function isRoundRect(display) {
|
|
226
|
-
|
|
324
|
+
return isGraph(display) && display.__shape__ === DisplayType.RoundRect;
|
|
227
325
|
}
|
|
228
326
|
function isText(display) {
|
|
229
|
-
|
|
327
|
+
return isGraph(display) && display.__shape__ === DisplayType.Text;
|
|
230
328
|
}
|
|
231
329
|
function isBitmap(display) {
|
|
232
|
-
|
|
330
|
+
return isGraph(display) && display.__shape__ === DisplayType.Bitmap;
|
|
233
331
|
}
|
|
234
332
|
const asserts = {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
333
|
+
isGraph,
|
|
334
|
+
isBox,
|
|
335
|
+
isText,
|
|
336
|
+
isRoundRect,
|
|
337
|
+
isBitmap
|
|
240
338
|
};
|
|
241
339
|
|
|
242
|
-
var __defProp$a = Object.defineProperty;
|
|
243
|
-
var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
244
|
-
var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
245
340
|
class C extends Display {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
341
|
+
elements;
|
|
342
|
+
constructor(){
|
|
343
|
+
super();
|
|
344
|
+
this.elements = [];
|
|
345
|
+
}
|
|
346
|
+
add(...elements) {
|
|
347
|
+
const cap = elements.length;
|
|
348
|
+
for(let i = 0; i < cap; i++){
|
|
349
|
+
const element = elements[i];
|
|
350
|
+
if (element.parent) ;
|
|
351
|
+
this.elements.push(element);
|
|
352
|
+
element.parent = this;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
remove(...elements) {
|
|
356
|
+
const cap = elements.length;
|
|
357
|
+
for(let i = 0; i < cap; i++){
|
|
358
|
+
for(let j = this.elements.length - 1; j >= 0; j--){
|
|
359
|
+
const element = this.elements[j];
|
|
360
|
+
if (element.id === elements[i].id) {
|
|
361
|
+
this.elements.splice(j, 1);
|
|
362
|
+
element.parent = null;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
destory() {
|
|
368
|
+
this.elements.forEach((element)=>element.parent = null);
|
|
369
|
+
this.elements.length = 0;
|
|
370
|
+
}
|
|
276
371
|
}
|
|
277
372
|
class Box extends C {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const cap = elements.length;
|
|
285
|
-
for (let i = 0; i < cap; i++) {
|
|
286
|
-
const element = elements[i];
|
|
287
|
-
if (element.parent) ;
|
|
288
|
-
this.elements.push(element);
|
|
289
|
-
element.parent = this;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
remove(...elements) {
|
|
293
|
-
const cap = elements.length;
|
|
294
|
-
for (let i = 0; i < cap; i++) {
|
|
295
|
-
for (let j = this.elements.length - 1; j >= 0; j--) {
|
|
296
|
-
const element = this.elements[j];
|
|
297
|
-
if (element.id === elements[i].id) {
|
|
298
|
-
this.elements.splice(j, 1);
|
|
299
|
-
element.parent = null;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
destory() {
|
|
305
|
-
this.elements.forEach((element) => element.parent = null);
|
|
306
|
-
this.elements.length = 0;
|
|
307
|
-
}
|
|
308
|
-
get __instanceOf__() {
|
|
309
|
-
return DisplayType.Box;
|
|
310
|
-
}
|
|
311
|
-
clone() {
|
|
312
|
-
const box = new Box();
|
|
313
|
-
if (this.elements.length) {
|
|
314
|
-
const stack = [{ elements: this.elements, parent: box }];
|
|
315
|
-
while (stack.length > 0) {
|
|
316
|
-
const { elements, parent } = stack.pop();
|
|
373
|
+
elements;
|
|
374
|
+
constructor(){
|
|
375
|
+
super();
|
|
376
|
+
this.elements = [];
|
|
377
|
+
}
|
|
378
|
+
add(...elements) {
|
|
317
379
|
const cap = elements.length;
|
|
318
|
-
for
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
380
|
+
for(let i = 0; i < cap; i++){
|
|
381
|
+
const element = elements[i];
|
|
382
|
+
if (element.parent) ;
|
|
383
|
+
this.elements.push(element);
|
|
384
|
+
element.parent = this;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
remove(...elements) {
|
|
388
|
+
const cap = elements.length;
|
|
389
|
+
for(let i = 0; i < cap; i++){
|
|
390
|
+
for(let j = this.elements.length - 1; j >= 0; j--){
|
|
391
|
+
const element = this.elements[j];
|
|
392
|
+
if (element.id === elements[i].id) {
|
|
393
|
+
this.elements.splice(j, 1);
|
|
394
|
+
element.parent = null;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
destory() {
|
|
400
|
+
this.elements.forEach((element)=>element.parent = null);
|
|
401
|
+
this.elements.length = 0;
|
|
402
|
+
}
|
|
403
|
+
get __instanceOf__() {
|
|
404
|
+
return DisplayType.Box;
|
|
405
|
+
}
|
|
406
|
+
clone() {
|
|
407
|
+
const box = new Box();
|
|
408
|
+
if (this.elements.length) {
|
|
409
|
+
const stack = [
|
|
410
|
+
{
|
|
411
|
+
elements: this.elements,
|
|
412
|
+
parent: box
|
|
413
|
+
}
|
|
414
|
+
];
|
|
415
|
+
while(stack.length > 0){
|
|
416
|
+
const { elements, parent } = stack.pop();
|
|
417
|
+
const cap = elements.length;
|
|
418
|
+
for(let i = 0; i < cap; i++){
|
|
419
|
+
const element = elements[i];
|
|
420
|
+
if (asserts.isBox(element)) {
|
|
421
|
+
const newBox = new Box();
|
|
422
|
+
newBox.parent = parent;
|
|
423
|
+
parent.add(newBox);
|
|
424
|
+
stack.push({
|
|
425
|
+
elements: element.elements,
|
|
426
|
+
parent: newBox
|
|
427
|
+
});
|
|
428
|
+
} else if (asserts.isGraph(element)) {
|
|
429
|
+
const el = element.clone();
|
|
430
|
+
el.parent = parent;
|
|
431
|
+
parent.add(el);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return box;
|
|
437
|
+
}
|
|
335
438
|
}
|
|
336
439
|
|
|
337
|
-
var __defProp$9 = Object.defineProperty;
|
|
338
|
-
var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
339
|
-
var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
340
440
|
class Bitmap extends Graph {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
441
|
+
bitmap;
|
|
442
|
+
style;
|
|
443
|
+
dpi;
|
|
444
|
+
constructor(options = {}){
|
|
445
|
+
super(options);
|
|
446
|
+
this.bitmap = options.bitmap || null;
|
|
447
|
+
this.style = options.style || Object.create(null);
|
|
448
|
+
this.dpi = options.dpi || 1;
|
|
449
|
+
}
|
|
450
|
+
create() {
|
|
451
|
+
if (this.bitmap) {
|
|
452
|
+
this.instruction.drawImage(this.bitmap, 0, 0, this.bitmap.width / this.dpi, this.bitmap.height / this.dpi);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
clone() {
|
|
456
|
+
return new Bitmap({
|
|
457
|
+
...this.style,
|
|
458
|
+
...this.__options__
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
get __shape__() {
|
|
462
|
+
return DisplayType.Bitmap;
|
|
463
|
+
}
|
|
361
464
|
}
|
|
362
465
|
|
|
466
|
+
// Runtime is designed for graph element
|
|
363
467
|
function decodeHLS(meta) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
468
|
+
const { h, l, s, a } = meta;
|
|
469
|
+
if ('a' in meta) {
|
|
470
|
+
return `hsla(${h}deg, ${s}%, ${l}%, ${a})`;
|
|
471
|
+
}
|
|
472
|
+
return `hsl(${h}deg, ${s}%, ${l}%)`;
|
|
369
473
|
}
|
|
370
474
|
function decodeRGB(meta) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
475
|
+
const { r, g, b, a } = meta;
|
|
476
|
+
if ('a' in meta) {
|
|
477
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
478
|
+
}
|
|
479
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
376
480
|
}
|
|
377
481
|
function decodeColor(meta) {
|
|
378
|
-
|
|
482
|
+
return meta.mode === 'rgb' ? decodeRGB(meta.desc) : decodeHLS(meta.desc);
|
|
379
483
|
}
|
|
380
484
|
function evaluateFillStyle(primitive, opacity = 1) {
|
|
381
|
-
|
|
382
|
-
|
|
485
|
+
const descibe = {
|
|
486
|
+
mode: primitive.mode,
|
|
487
|
+
desc: {
|
|
488
|
+
...primitive.desc,
|
|
489
|
+
a: opacity
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
return decodeColor(descibe);
|
|
383
493
|
}
|
|
384
494
|
const runtime = {
|
|
385
|
-
|
|
495
|
+
evaluateFillStyle
|
|
386
496
|
};
|
|
387
497
|
|
|
388
|
-
var __defProp$8 = Object.defineProperty;
|
|
389
|
-
var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
390
|
-
var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
391
498
|
class RoundRect extends Graph {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
499
|
+
style;
|
|
500
|
+
constructor(options = {}){
|
|
501
|
+
super(options);
|
|
502
|
+
this.style = options.style || Object.create(null);
|
|
503
|
+
}
|
|
504
|
+
get __shape__() {
|
|
505
|
+
return DisplayType.RoundRect;
|
|
506
|
+
}
|
|
507
|
+
create() {
|
|
508
|
+
const padding = this.style.padding;
|
|
509
|
+
const x = 0;
|
|
510
|
+
const y = 0;
|
|
511
|
+
const width = this.width - padding * 2;
|
|
512
|
+
const height = this.height - padding * 2;
|
|
513
|
+
const radius = this.style.radius || 0;
|
|
514
|
+
this.instruction.beginPath();
|
|
515
|
+
this.instruction.moveTo(x + radius, y);
|
|
516
|
+
this.instruction.arcTo(x + width, y, x + width, y + height, radius);
|
|
517
|
+
this.instruction.arcTo(x + width, y + height, x, y + height, radius);
|
|
518
|
+
this.instruction.arcTo(x, y + height, x, y, radius);
|
|
519
|
+
this.instruction.arcTo(x, y, x + width, y, radius);
|
|
520
|
+
this.instruction.closePath();
|
|
521
|
+
if (this.style.fill) {
|
|
522
|
+
this.instruction.closePath();
|
|
523
|
+
this.instruction.fillStyle(runtime.evaluateFillStyle(this.style.fill, this.style.opacity));
|
|
524
|
+
this.instruction.fill();
|
|
525
|
+
}
|
|
526
|
+
if (this.style.stroke) {
|
|
527
|
+
if (typeof this.style.lineWidth === 'number') {
|
|
528
|
+
this.instruction.lineWidth(this.style.lineWidth);
|
|
529
|
+
}
|
|
530
|
+
this.instruction.strokeStyle(this.style.stroke);
|
|
531
|
+
this.instruction.stroke();
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
clone() {
|
|
535
|
+
return new RoundRect({
|
|
536
|
+
...this.style,
|
|
537
|
+
...this.__options__
|
|
538
|
+
});
|
|
539
|
+
}
|
|
430
540
|
}
|
|
431
541
|
|
|
432
|
-
var __defProp$7 = Object.defineProperty;
|
|
433
|
-
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
434
|
-
var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
435
542
|
class Text extends Graph {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
543
|
+
text;
|
|
544
|
+
style;
|
|
545
|
+
constructor(options = {}){
|
|
546
|
+
super(options);
|
|
547
|
+
this.text = options.text || '';
|
|
548
|
+
this.style = options.style || Object.create(null);
|
|
549
|
+
}
|
|
550
|
+
create() {
|
|
551
|
+
if (this.style.fill) {
|
|
552
|
+
this.instruction.font(this.style.font);
|
|
553
|
+
this.instruction.lineWidth(this.style.lineWidth);
|
|
554
|
+
this.instruction.textBaseline(this.style.baseline);
|
|
555
|
+
this.instruction.fillStyle(this.style.fill);
|
|
556
|
+
this.instruction.fillText(this.text, 0, 0);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
clone() {
|
|
560
|
+
return new Text({
|
|
561
|
+
...this.style,
|
|
562
|
+
...this.__options__
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
get __shape__() {
|
|
566
|
+
return DisplayType.Text;
|
|
567
|
+
}
|
|
458
568
|
}
|
|
459
569
|
|
|
460
570
|
function traverse(graphs, handler) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
571
|
+
const len = graphs.length;
|
|
572
|
+
for(let i = 0; i < len; i++){
|
|
573
|
+
const graph = graphs[i];
|
|
574
|
+
if (asserts.isGraph(graph)) {
|
|
575
|
+
handler(graph);
|
|
576
|
+
} else if (asserts.isBox(graph)) {
|
|
577
|
+
traverse(graph.elements, handler);
|
|
578
|
+
}
|
|
468
579
|
}
|
|
469
|
-
}
|
|
470
580
|
}
|
|
581
|
+
// https://jhildenbiddle.github.io/canvas-size/#/?id=maxheight
|
|
471
582
|
function getCanvasBoundarySize() {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
583
|
+
const ua = navigator.userAgent;
|
|
584
|
+
let size = 16384;
|
|
585
|
+
if (/Firefox\/(\d+)/.test(ua)) {
|
|
586
|
+
const version = parseInt(RegExp.$1, 10);
|
|
587
|
+
if (version >= 122) {
|
|
588
|
+
size = 23168;
|
|
589
|
+
} else {
|
|
590
|
+
size = 11180;
|
|
591
|
+
}
|
|
480
592
|
}
|
|
481
|
-
|
|
482
|
-
|
|
593
|
+
return {
|
|
594
|
+
size
|
|
595
|
+
};
|
|
483
596
|
}
|
|
484
597
|
const canvasBoundarySize = getCanvasBoundarySize();
|
|
485
598
|
|
|
599
|
+
// Currently, etoile is an internal module, so we won't need too much easing functions.
|
|
600
|
+
// And the animation logic is implemented by user code.
|
|
486
601
|
const easing = {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
602
|
+
linear: (k)=>k,
|
|
603
|
+
quadraticIn: (k)=>k * k,
|
|
604
|
+
quadraticOut: (k)=>k * (2 - k),
|
|
605
|
+
quadraticInOut: (k)=>{
|
|
606
|
+
if ((k *= 2) < 1) {
|
|
607
|
+
return 0.5 * k * k;
|
|
608
|
+
}
|
|
609
|
+
return -0.5 * (--k * (k - 2) - 1);
|
|
610
|
+
},
|
|
611
|
+
cubicIn: (k)=>k * k * k,
|
|
612
|
+
cubicOut: (k)=>{
|
|
613
|
+
if ((k *= 2) < 1) {
|
|
614
|
+
return 0.5 * k * k * k;
|
|
615
|
+
}
|
|
616
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
617
|
+
},
|
|
618
|
+
cubicInOut: (k)=>{
|
|
619
|
+
if ((k *= 2) < 1) {
|
|
620
|
+
return 0.5 * k * k * k;
|
|
621
|
+
}
|
|
622
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
623
|
+
}
|
|
509
624
|
};
|
|
510
625
|
|
|
511
|
-
var __defProp$6 = Object.defineProperty;
|
|
512
|
-
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
513
|
-
var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
514
626
|
class Event {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
on(evt, handler, c) {
|
|
520
|
-
if (!(evt in this.eventCollections)) {
|
|
521
|
-
this.eventCollections[evt] = [];
|
|
522
|
-
}
|
|
523
|
-
const data = {
|
|
524
|
-
name: evt,
|
|
525
|
-
handler,
|
|
526
|
-
ctx: c || this,
|
|
527
|
-
silent: false
|
|
528
|
-
};
|
|
529
|
-
this.eventCollections[evt].push(data);
|
|
530
|
-
}
|
|
531
|
-
off(evt, handler) {
|
|
532
|
-
if (evt in this.eventCollections) {
|
|
533
|
-
if (!handler) {
|
|
534
|
-
this.eventCollections[evt] = [];
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
this.eventCollections[evt] = this.eventCollections[evt].filter((d) => d.handler !== handler);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
silent(evt, handler) {
|
|
541
|
-
if (!(evt in this.eventCollections)) {
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
this.eventCollections[evt].forEach((d) => {
|
|
545
|
-
if (!handler || d.handler === handler) {
|
|
546
|
-
d.silent = true;
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
active(evt, handler) {
|
|
551
|
-
if (!(evt in this.eventCollections)) {
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
this.eventCollections[evt].forEach((d) => {
|
|
555
|
-
if (!handler || d.handler === handler) {
|
|
556
|
-
d.silent = false;
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
emit(evt, ...args) {
|
|
561
|
-
if (!this.eventCollections[evt]) {
|
|
562
|
-
return;
|
|
627
|
+
eventCollections;
|
|
628
|
+
constructor(){
|
|
629
|
+
this.eventCollections = Object.create(null);
|
|
563
630
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
631
|
+
on(evt, handler, c) {
|
|
632
|
+
if (!(evt in this.eventCollections)) {
|
|
633
|
+
this.eventCollections[evt] = [];
|
|
634
|
+
}
|
|
635
|
+
const data = {
|
|
636
|
+
name: evt,
|
|
637
|
+
handler,
|
|
638
|
+
ctx: c || this,
|
|
639
|
+
silent: false
|
|
640
|
+
};
|
|
641
|
+
this.eventCollections[evt].push(data);
|
|
642
|
+
}
|
|
643
|
+
off(evt, handler) {
|
|
644
|
+
if (evt in this.eventCollections) {
|
|
645
|
+
if (!handler) {
|
|
646
|
+
this.eventCollections[evt] = [];
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
this.eventCollections[evt] = this.eventCollections[evt].filter((d)=>d.handler !== handler);
|
|
569
650
|
}
|
|
570
|
-
d.handler.call(d.ctx, ...args);
|
|
571
|
-
});
|
|
572
651
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
652
|
+
silent(evt, handler) {
|
|
653
|
+
if (!(evt in this.eventCollections)) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
this.eventCollections[evt].forEach((d)=>{
|
|
657
|
+
if (!handler || d.handler === handler) {
|
|
658
|
+
d.silent = true;
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
active(evt, handler) {
|
|
663
|
+
if (!(evt in this.eventCollections)) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
this.eventCollections[evt].forEach((d)=>{
|
|
667
|
+
if (!handler || d.handler === handler) {
|
|
668
|
+
d.silent = false;
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
emit(evt, ...args) {
|
|
673
|
+
if (!this.eventCollections[evt]) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
const handlers = this.eventCollections[evt];
|
|
677
|
+
if (handlers.length) {
|
|
678
|
+
handlers.forEach((d)=>{
|
|
679
|
+
if (d.silent) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
d.handler.call(d.ctx, ...args);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
bindWithContext(c) {
|
|
687
|
+
return (evt, handler)=>this.on(evt, handler, c);
|
|
688
|
+
}
|
|
577
689
|
}
|
|
578
690
|
|
|
579
691
|
function hashCode(str) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
692
|
+
let hash = 0;
|
|
693
|
+
for(let i = 0; i < str.length; i++){
|
|
694
|
+
const code = str.charCodeAt(i);
|
|
695
|
+
hash = (hash << 5) - hash + code;
|
|
696
|
+
hash = hash & hash;
|
|
697
|
+
}
|
|
698
|
+
return hash;
|
|
587
699
|
}
|
|
700
|
+
// For strings we only check the first character to determine if it's a number (I think it's enough)
|
|
588
701
|
function perferNumeric(s) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
702
|
+
if (typeof s === 'number') {
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
705
|
+
return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
|
|
593
706
|
}
|
|
594
707
|
function createRoundBlock(x, y, width, height, style) {
|
|
595
|
-
|
|
708
|
+
return new RoundRect({
|
|
709
|
+
width,
|
|
710
|
+
height,
|
|
711
|
+
x,
|
|
712
|
+
y,
|
|
713
|
+
style: {
|
|
714
|
+
...style
|
|
715
|
+
}
|
|
716
|
+
});
|
|
596
717
|
}
|
|
597
718
|
function createTitleText(text, x, y, font, color) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
719
|
+
return new Text({
|
|
720
|
+
text,
|
|
721
|
+
x,
|
|
722
|
+
y,
|
|
723
|
+
style: {
|
|
724
|
+
fill: color,
|
|
725
|
+
textAlign: 'center',
|
|
726
|
+
baseline: 'middle',
|
|
727
|
+
font,
|
|
728
|
+
lineWidth: 1
|
|
729
|
+
}
|
|
730
|
+
});
|
|
604
731
|
}
|
|
605
732
|
const raf = window.requestAnimationFrame;
|
|
606
733
|
function createCanvasElement() {
|
|
607
|
-
|
|
734
|
+
return document.createElement('canvas');
|
|
608
735
|
}
|
|
609
736
|
function applyCanvasTransform(ctx, matrix, dpr) {
|
|
610
|
-
|
|
737
|
+
ctx.setTransform(matrix.a * dpr, matrix.b * dpr, matrix.c * dpr, matrix.d * dpr, matrix.e * dpr, matrix.f * dpr);
|
|
611
738
|
}
|
|
612
739
|
function mixin(app, methods) {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
740
|
+
methods.forEach(({ name, fn })=>{
|
|
741
|
+
Object.defineProperty(app, name, {
|
|
742
|
+
value: fn(app),
|
|
743
|
+
writable: false
|
|
744
|
+
});
|
|
617
745
|
});
|
|
618
|
-
});
|
|
619
746
|
}
|
|
620
747
|
function prettyStrJoin(...s) {
|
|
621
|
-
|
|
748
|
+
return s.join('');
|
|
622
749
|
}
|
|
623
750
|
|
|
624
|
-
const NAME_SPACE =
|
|
751
|
+
const NAME_SPACE = 'etoile';
|
|
625
752
|
const log = {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
753
|
+
error: (message)=>{
|
|
754
|
+
return `[${NAME_SPACE}] ${message}`;
|
|
755
|
+
}
|
|
629
756
|
};
|
|
630
757
|
|
|
631
|
-
var __defProp$5 = Object.defineProperty;
|
|
632
|
-
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
633
|
-
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
634
758
|
function writeBoundingRectForCanvas(c, w, h, dpr) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
759
|
+
c.width = w * dpr;
|
|
760
|
+
c.height = h * dpr;
|
|
761
|
+
c.style.cssText = `width: ${w}px; height: ${h}px`;
|
|
638
762
|
}
|
|
639
763
|
class Canvas {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
764
|
+
canvas;
|
|
765
|
+
ctx;
|
|
766
|
+
constructor(options){
|
|
767
|
+
this.canvas = createCanvasElement();
|
|
768
|
+
this.setOptions(options);
|
|
769
|
+
this.ctx = this.canvas.getContext('2d');
|
|
770
|
+
}
|
|
771
|
+
setOptions(options) {
|
|
772
|
+
writeBoundingRectForCanvas(this.canvas, options.width, options.height, options.devicePixelRatio);
|
|
773
|
+
}
|
|
650
774
|
}
|
|
651
775
|
class Render {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
776
|
+
options;
|
|
777
|
+
container;
|
|
778
|
+
constructor(to, options){
|
|
779
|
+
this.container = new Canvas(options);
|
|
780
|
+
this.options = options;
|
|
781
|
+
this.initOptions(options);
|
|
782
|
+
if (!options.shaow) {
|
|
783
|
+
to.appendChild(this.container.canvas);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
clear(width, height) {
|
|
787
|
+
this.ctx.clearRect(0, 0, width, height);
|
|
788
|
+
}
|
|
789
|
+
get canvas() {
|
|
790
|
+
return this.container.canvas;
|
|
791
|
+
}
|
|
792
|
+
get ctx() {
|
|
793
|
+
return this.container.ctx;
|
|
794
|
+
}
|
|
795
|
+
initOptions(userOptions = {}) {
|
|
796
|
+
Object.assign(this.options, userOptions);
|
|
797
|
+
this.container.setOptions(this.options);
|
|
798
|
+
}
|
|
799
|
+
destory() {}
|
|
677
800
|
}
|
|
678
801
|
|
|
679
|
-
|
|
680
|
-
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
681
|
-
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
802
|
+
// First cleanup canvas
|
|
682
803
|
function drawGraphIntoCanvas(graph, opts) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
804
|
+
const { ctx, dpr } = opts;
|
|
805
|
+
ctx.save();
|
|
806
|
+
if (asserts.isBox(graph)) {
|
|
807
|
+
const elements = graph.elements;
|
|
808
|
+
const cap = elements.length;
|
|
809
|
+
for(let i = 0; i < cap; i++){
|
|
810
|
+
const element = elements[i];
|
|
811
|
+
drawGraphIntoCanvas(element, opts);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (asserts.isGraph(graph)) {
|
|
815
|
+
const matrix = graph.matrix.create({
|
|
816
|
+
a: 1,
|
|
817
|
+
b: 0,
|
|
818
|
+
c: 0,
|
|
819
|
+
d: 1,
|
|
820
|
+
e: 0,
|
|
821
|
+
f: 0
|
|
822
|
+
});
|
|
823
|
+
matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
|
|
824
|
+
if (asserts.isRoundRect(graph)) {
|
|
825
|
+
const effectiveWidth = graph.width - graph.style.padding * 2;
|
|
826
|
+
const effectiveHeight = graph.height - graph.style.padding * 2;
|
|
827
|
+
if (effectiveWidth <= 0 || effectiveHeight <= 0) {
|
|
828
|
+
ctx.restore();
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
if (graph.style.radius >= effectiveHeight / 2 || graph.style.radius >= effectiveWidth / 2) {
|
|
832
|
+
ctx.restore();
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
applyCanvasTransform(ctx, matrix, dpr);
|
|
837
|
+
graph.render(ctx);
|
|
838
|
+
}
|
|
839
|
+
ctx.restore();
|
|
712
840
|
}
|
|
713
841
|
class Schedule extends Box {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
842
|
+
render;
|
|
843
|
+
to;
|
|
844
|
+
event;
|
|
845
|
+
constructor(to, renderOptions = {}){
|
|
846
|
+
super();
|
|
847
|
+
this.to = typeof to === 'string' ? document.querySelector(to) : to;
|
|
848
|
+
if (!this.to) {
|
|
849
|
+
throw new Error(log.error('The element to bind is not found.'));
|
|
850
|
+
}
|
|
851
|
+
const { width, height } = this.to.getBoundingClientRect();
|
|
852
|
+
Object.assign(renderOptions, {
|
|
853
|
+
width,
|
|
854
|
+
height
|
|
855
|
+
}, {
|
|
856
|
+
devicePixelRatio: window.devicePixelRatio || 1
|
|
857
|
+
});
|
|
858
|
+
this.event = new Event();
|
|
859
|
+
this.render = new Render(this.to, renderOptions);
|
|
860
|
+
}
|
|
861
|
+
update() {
|
|
862
|
+
this.render.clear(this.render.options.width, this.render.options.height);
|
|
863
|
+
this.execute(this.render, this);
|
|
864
|
+
const matrix = this.matrix.create({
|
|
865
|
+
a: 1,
|
|
866
|
+
b: 0,
|
|
867
|
+
c: 0,
|
|
868
|
+
d: 1,
|
|
869
|
+
e: 0,
|
|
870
|
+
f: 0
|
|
871
|
+
});
|
|
872
|
+
applyCanvasTransform(this.render.ctx, matrix, this.render.options.devicePixelRatio);
|
|
873
|
+
}
|
|
874
|
+
// execute all graph elements
|
|
875
|
+
execute(render, graph = this) {
|
|
876
|
+
drawGraphIntoCanvas(graph, {
|
|
877
|
+
c: render.canvas,
|
|
878
|
+
ctx: render.ctx,
|
|
879
|
+
dpr: render.options.devicePixelRatio
|
|
880
|
+
});
|
|
881
|
+
}
|
|
738
882
|
}
|
|
739
883
|
|
|
740
|
-
var __defProp$3 = Object.defineProperty;
|
|
741
|
-
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
742
|
-
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
743
884
|
class RenderCache extends Canvas {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
885
|
+
key;
|
|
886
|
+
$memory;
|
|
887
|
+
constructor(opts){
|
|
888
|
+
super(opts);
|
|
889
|
+
this.key = 'render-cache';
|
|
890
|
+
this.$memory = false;
|
|
891
|
+
}
|
|
892
|
+
get state() {
|
|
893
|
+
return this.$memory;
|
|
894
|
+
}
|
|
895
|
+
flush(treemap, matrix = new Matrix2D()) {
|
|
896
|
+
const { devicePixelRatio, width, height } = treemap.render.options;
|
|
897
|
+
const { a, d } = matrix;
|
|
898
|
+
const { size } = canvasBoundarySize;
|
|
899
|
+
// Check outof boundary
|
|
900
|
+
if (width * a >= size || height * d >= size) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
if (width * a * height * d >= size * size) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
907
|
+
this.setOptions({
|
|
908
|
+
width: width * a,
|
|
909
|
+
height: height * d,
|
|
910
|
+
devicePixelRatio
|
|
911
|
+
});
|
|
912
|
+
resetLayout(treemap, width * a, height * d);
|
|
913
|
+
drawGraphIntoCanvas(treemap, {
|
|
914
|
+
c: this.canvas,
|
|
915
|
+
ctx: this.ctx,
|
|
916
|
+
dpr: devicePixelRatio
|
|
917
|
+
});
|
|
918
|
+
this.$memory = true;
|
|
919
|
+
}
|
|
920
|
+
destroy() {
|
|
921
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
922
|
+
this.$memory = false;
|
|
923
|
+
}
|
|
774
924
|
}
|
|
775
925
|
class FontCache {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
926
|
+
key;
|
|
927
|
+
fonts;
|
|
928
|
+
ellispsis;
|
|
929
|
+
constructor(){
|
|
930
|
+
this.key = 'font-cache';
|
|
931
|
+
this.fonts = {};
|
|
932
|
+
this.ellispsis = {};
|
|
933
|
+
}
|
|
934
|
+
get state() {
|
|
935
|
+
return true;
|
|
936
|
+
}
|
|
937
|
+
flush(treemap, matrix = new Matrix2D()) {
|
|
938
|
+
const { width, height } = treemap.render.options;
|
|
939
|
+
const { a, d } = matrix;
|
|
940
|
+
const zoomedWidth = width * a;
|
|
941
|
+
const zoomedHeight = height * d;
|
|
942
|
+
if (zoomedWidth <= width || zoomedHeight <= height) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
traverse([
|
|
946
|
+
treemap.elements[0]
|
|
947
|
+
], (graph)=>{
|
|
948
|
+
if (asserts.isRoundRect(graph)) {
|
|
949
|
+
const { x, y, height: graphHeight, width: graphWidth } = graph;
|
|
950
|
+
if (!graphHeight || !graphWidth) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (x >= 0 && y >= 0 && x + graphWidth <= width && y + graphHeight <= height) {
|
|
954
|
+
if (graph.__widget__) {
|
|
955
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
956
|
+
const node = graph.__widget__.node;
|
|
957
|
+
delete this.fonts[node.id];
|
|
958
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
959
|
+
delete this.ellispsis[node.label];
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
destroy() {
|
|
966
|
+
this.fonts = {};
|
|
967
|
+
this.ellispsis = {};
|
|
968
|
+
}
|
|
969
|
+
queryFontById(id, byDefault) {
|
|
970
|
+
if (!(id in this.fonts)) {
|
|
971
|
+
this.fonts[id] = byDefault();
|
|
972
|
+
}
|
|
973
|
+
return this.fonts[id];
|
|
974
|
+
}
|
|
821
975
|
}
|
|
822
976
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
977
|
+
// primitive types
|
|
978
|
+
const DOM_EVENTS = [
|
|
979
|
+
'click',
|
|
980
|
+
'mousedown',
|
|
981
|
+
'mousemove',
|
|
982
|
+
'mouseup',
|
|
983
|
+
'mouseover',
|
|
984
|
+
'mouseout',
|
|
985
|
+
'wheel'
|
|
986
|
+
];
|
|
827
987
|
function getOffset(el) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
988
|
+
let e = 0;
|
|
989
|
+
let f = 0;
|
|
990
|
+
if (document.documentElement.getBoundingClientRect && el.getBoundingClientRect) {
|
|
991
|
+
const { top, left } = el.getBoundingClientRect();
|
|
992
|
+
e = top;
|
|
993
|
+
f = left;
|
|
994
|
+
} else {
|
|
995
|
+
for(let elt = el; elt; elt = el.offsetParent){
|
|
996
|
+
e += el.offsetLeft;
|
|
997
|
+
f += el.offsetTop;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return [
|
|
1001
|
+
e + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft),
|
|
1002
|
+
f + Math.max(document.documentElement.scrollTop, document.body.scrollTop)
|
|
1003
|
+
];
|
|
844
1004
|
}
|
|
845
1005
|
function captureBoxXY(c, evt, a, d, translateX, translateY) {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1006
|
+
const boundingClientRect = c.getBoundingClientRect();
|
|
1007
|
+
if (evt instanceof MouseEvent) {
|
|
1008
|
+
const [e, f] = getOffset(c);
|
|
1009
|
+
return {
|
|
1010
|
+
x: (evt.clientX - boundingClientRect.left - e - translateX) / a,
|
|
1011
|
+
y: (evt.clientY - boundingClientRect.top - f - translateY) / d
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
849
1014
|
return {
|
|
850
|
-
|
|
851
|
-
|
|
1015
|
+
x: 0,
|
|
1016
|
+
y: 0
|
|
852
1017
|
};
|
|
853
|
-
}
|
|
854
|
-
return { x: 0, y: 0 };
|
|
855
1018
|
}
|
|
856
1019
|
function createEffectRun(c) {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1020
|
+
return (fn)=>{
|
|
1021
|
+
const effect = ()=>{
|
|
1022
|
+
const done = fn();
|
|
1023
|
+
if (!done) {
|
|
1024
|
+
c.animationFrameID = raf(effect);
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
if (!c.animationFrameID) {
|
|
1028
|
+
c.animationFrameID = raf(effect);
|
|
1029
|
+
}
|
|
863
1030
|
};
|
|
864
|
-
if (!c.animationFrameID) {
|
|
865
|
-
c.animationFrameID = raf(effect);
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
1031
|
}
|
|
869
1032
|
function createEffectStop(c) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1033
|
+
return ()=>{
|
|
1034
|
+
if (c.animationFrameID) {
|
|
1035
|
+
window.cancelAnimationFrame(c.animationFrameID);
|
|
1036
|
+
c.animationFrameID = null;
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
876
1039
|
}
|
|
877
1040
|
function createSmoothFrame() {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1041
|
+
const c = {
|
|
1042
|
+
animationFrameID: null
|
|
1043
|
+
};
|
|
1044
|
+
const run = createEffectRun(c);
|
|
1045
|
+
const stop = createEffectStop(c);
|
|
1046
|
+
return {
|
|
1047
|
+
run,
|
|
1048
|
+
stop
|
|
1049
|
+
};
|
|
884
1050
|
}
|
|
1051
|
+
// Some thoughts DOMEvent was designed this way intentionally. I don't have any idea of splitting the general libray yet.
|
|
1052
|
+
// The follow captureBoxXy matrix a and d be 1 is because of the scaled canvas (without zoomed) is with a new layout.
|
|
885
1053
|
function bindDOMEvent(el, evt, dom) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1054
|
+
const handler = (e)=>{
|
|
1055
|
+
const { x, y } = captureBoxXY(el, e, 1, 1, dom.matrix.e, dom.matrix.f);
|
|
1056
|
+
// @ts-expect-error safe
|
|
1057
|
+
dom.emit(evt, {
|
|
1058
|
+
native: e,
|
|
1059
|
+
loc: {
|
|
1060
|
+
x,
|
|
1061
|
+
y
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
};
|
|
1065
|
+
el.addEventListener(evt, handler);
|
|
1066
|
+
return handler;
|
|
892
1067
|
}
|
|
893
1068
|
class DOMEvent extends Event {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1069
|
+
el;
|
|
1070
|
+
events;
|
|
1071
|
+
matrix;
|
|
1072
|
+
constructor(el){
|
|
1073
|
+
super();
|
|
1074
|
+
this.el = el;
|
|
1075
|
+
this.matrix = new Matrix2D();
|
|
1076
|
+
this.events = DOM_EVENTS.map((evt)=>bindDOMEvent(this.el, evt, this));
|
|
1077
|
+
}
|
|
903
1078
|
}
|
|
904
1079
|
|
|
1080
|
+
// Note: I won't decide to support mobile devices.
|
|
1081
|
+
// So don't create any reporting issues about mobile devices.
|
|
1082
|
+
// Notte: this only work at wheel event.
|
|
905
1083
|
function useMagicTrackPad(event) {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1084
|
+
if (event.cancelable !== false) {
|
|
1085
|
+
event.preventDefault();
|
|
1086
|
+
}
|
|
1087
|
+
!event.ctrlKey;
|
|
910
1088
|
}
|
|
911
1089
|
|
|
912
1090
|
function sortChildrenByKey(data, ...keys) {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1091
|
+
return data.sort((a, b)=>{
|
|
1092
|
+
for (const key of keys){
|
|
1093
|
+
const v = a[key];
|
|
1094
|
+
const v2 = b[key];
|
|
1095
|
+
if (perferNumeric(v) && perferNumeric(v2)) {
|
|
1096
|
+
if (v2 > v) {
|
|
1097
|
+
return 1;
|
|
1098
|
+
}
|
|
1099
|
+
if (v2 < v) {
|
|
1100
|
+
return -1;
|
|
1101
|
+
}
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
// Not numeric, compare as string
|
|
1105
|
+
const comparison = ('' + v).localeCompare('' + v2);
|
|
1106
|
+
if (comparison !== 0) {
|
|
1107
|
+
return comparison;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return 0;
|
|
1111
|
+
});
|
|
933
1112
|
}
|
|
934
1113
|
function c2m(data, key, modifier) {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1114
|
+
if (Array.isArray(data.groups)) {
|
|
1115
|
+
data.groups = sortChildrenByKey(data.groups.map((d)=>c2m(d, key, modifier)), 'weight');
|
|
1116
|
+
}
|
|
1117
|
+
const obj = {
|
|
1118
|
+
...data,
|
|
1119
|
+
weight: data[key]
|
|
1120
|
+
};
|
|
1121
|
+
if (modifier) {
|
|
1122
|
+
return modifier(obj);
|
|
1123
|
+
}
|
|
1124
|
+
return obj;
|
|
943
1125
|
}
|
|
944
1126
|
function flatten(data) {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1127
|
+
const result = [];
|
|
1128
|
+
for(let i = 0; i < data.length; i++){
|
|
1129
|
+
const { groups, ...rest } = data[i];
|
|
1130
|
+
result.push(rest);
|
|
1131
|
+
if (groups) {
|
|
1132
|
+
result.push(...flatten(groups));
|
|
1133
|
+
}
|
|
951
1134
|
}
|
|
952
|
-
|
|
953
|
-
return result;
|
|
1135
|
+
return result;
|
|
954
1136
|
}
|
|
955
1137
|
function bindParentForModule(modules, parent) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1138
|
+
return modules.map((module)=>{
|
|
1139
|
+
const next = {
|
|
1140
|
+
...module
|
|
1141
|
+
};
|
|
1142
|
+
next.parent = parent;
|
|
1143
|
+
if (next.groups && Array.isArray(next.groups)) {
|
|
1144
|
+
next.groups = bindParentForModule(next.groups, next);
|
|
1145
|
+
}
|
|
1146
|
+
return next;
|
|
1147
|
+
});
|
|
964
1148
|
}
|
|
965
1149
|
function getNodeDepth(node) {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1150
|
+
let depth = 0;
|
|
1151
|
+
while(node.parent){
|
|
1152
|
+
node = node.parent;
|
|
1153
|
+
depth++;
|
|
1154
|
+
}
|
|
1155
|
+
return depth;
|
|
972
1156
|
}
|
|
973
1157
|
function visit(data, fn) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1158
|
+
if (!data) {
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
for (const d of data){
|
|
1162
|
+
if (d.children) {
|
|
1163
|
+
const result = visit(d.children, fn);
|
|
1164
|
+
if (result) {
|
|
1165
|
+
return result;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
const stop = fn(d);
|
|
1169
|
+
if (stop) {
|
|
1170
|
+
return d;
|
|
1171
|
+
}
|
|
987
1172
|
}
|
|
988
|
-
|
|
989
|
-
return null;
|
|
1173
|
+
return null;
|
|
990
1174
|
}
|
|
991
1175
|
function findRelativeNode(p, layoutNodes) {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1176
|
+
return visit(layoutNodes, (node)=>{
|
|
1177
|
+
const [x, y, w, h] = node.layout;
|
|
1178
|
+
if (p.x >= x && p.y >= y && p.x < x + w && p.y < y + h) {
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
998
1182
|
}
|
|
999
1183
|
function findRelativeNodeById(id, layoutNodes) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1184
|
+
return visit(layoutNodes, (node)=>{
|
|
1185
|
+
if (node.node.id === id) {
|
|
1186
|
+
return true;
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1005
1189
|
}
|
|
1006
1190
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1191
|
+
// Because of the cache system. scale factor is not needed to apply.
|
|
1192
|
+
// Eg. Only use scale factor when the layout is changed.
|
|
1010
1193
|
function createTreemapEventState() {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1194
|
+
return {
|
|
1195
|
+
isDragging: false,
|
|
1196
|
+
isWheeling: false,
|
|
1197
|
+
isZooming: false,
|
|
1198
|
+
currentNode: null,
|
|
1199
|
+
forceDestroy: false,
|
|
1200
|
+
dragX: 0,
|
|
1201
|
+
dragY: 0
|
|
1202
|
+
};
|
|
1020
1203
|
}
|
|
1021
1204
|
const INTERNAL_EVENT_MAPPINGS = {
|
|
1022
|
-
|
|
1023
|
-
|
|
1205
|
+
ON_ZOOM: 0o1,
|
|
1206
|
+
ON_CLEANUP: 0o3
|
|
1024
1207
|
};
|
|
1025
1208
|
const ANIMATION_DURATION = 300;
|
|
1026
|
-
const fill = {
|
|
1209
|
+
const fill = {
|
|
1210
|
+
desc: {
|
|
1211
|
+
r: 255,
|
|
1212
|
+
g: 255,
|
|
1213
|
+
b: 255
|
|
1214
|
+
},
|
|
1215
|
+
mode: 'rgb'
|
|
1216
|
+
};
|
|
1027
1217
|
function smoothFrame(callback, opts) {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1218
|
+
const frame = createSmoothFrame();
|
|
1219
|
+
const startTime = Date.now();
|
|
1220
|
+
const condtion = (process)=>{
|
|
1221
|
+
if (Array.isArray(opts.deps)) {
|
|
1222
|
+
return opts.deps.some((dep)=>dep());
|
|
1223
|
+
}
|
|
1224
|
+
return process >= 1;
|
|
1225
|
+
};
|
|
1226
|
+
frame.run(()=>{
|
|
1227
|
+
const elapsed = Date.now() - startTime;
|
|
1228
|
+
const progress = Math.min(elapsed / opts.duration, 1);
|
|
1229
|
+
if (condtion(progress)) {
|
|
1230
|
+
frame.stop();
|
|
1231
|
+
if (opts.onStop) {
|
|
1232
|
+
opts.onStop();
|
|
1233
|
+
}
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1236
|
+
return callback(progress, frame.stop);
|
|
1237
|
+
});
|
|
1048
1238
|
}
|
|
1049
1239
|
const HIGH_LIGHT_OPACITY = 0.3;
|
|
1050
1240
|
function drawHighlight(treemap, evt) {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1241
|
+
const { highlight } = treemap;
|
|
1242
|
+
const { currentNode } = evt.state;
|
|
1243
|
+
if (currentNode) {
|
|
1244
|
+
const [x, y, w, h] = currentNode.layout;
|
|
1245
|
+
smoothFrame((_, cleanup)=>{
|
|
1246
|
+
cleanup();
|
|
1247
|
+
highlight.reset();
|
|
1248
|
+
const mask = createRoundBlock(x, y, w, h, {
|
|
1249
|
+
fill,
|
|
1250
|
+
opacity: HIGH_LIGHT_OPACITY,
|
|
1251
|
+
radius: 4,
|
|
1252
|
+
padding: 2
|
|
1253
|
+
});
|
|
1254
|
+
highlight.add(mask);
|
|
1255
|
+
highlight.setZIndexForHighlight('1');
|
|
1256
|
+
stackMatrixTransform(mask, evt.matrix.e, evt.matrix.f, 1);
|
|
1257
|
+
highlight.update();
|
|
1258
|
+
if (!evt.state.currentNode) {
|
|
1259
|
+
return true;
|
|
1260
|
+
}
|
|
1261
|
+
}, {
|
|
1262
|
+
duration: ANIMATION_DURATION,
|
|
1263
|
+
deps: [
|
|
1264
|
+
()=>evt.state.isDragging,
|
|
1265
|
+
()=>evt.state.isWheeling,
|
|
1266
|
+
()=>evt.state.isZooming
|
|
1267
|
+
]
|
|
1268
|
+
});
|
|
1269
|
+
} else {
|
|
1270
|
+
highlight.reset();
|
|
1271
|
+
highlight.setZIndexForHighlight();
|
|
1272
|
+
}
|
|
1074
1273
|
}
|
|
1274
|
+
// TODO: Do we need turn off internal events?
|
|
1075
1275
|
class TreemapEvent extends DOMEvent {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1276
|
+
exposedEvent;
|
|
1277
|
+
state;
|
|
1278
|
+
zoom;
|
|
1279
|
+
constructor(app, treemap){
|
|
1280
|
+
super(treemap.render.canvas);
|
|
1281
|
+
this.exposedEvent = new Event();
|
|
1282
|
+
this.state = createTreemapEventState();
|
|
1283
|
+
const exposedMethods = [
|
|
1284
|
+
{
|
|
1285
|
+
name: 'on',
|
|
1286
|
+
fn: ()=>this.exposedEvent.bindWithContext(treemap.api)
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
name: 'off',
|
|
1290
|
+
fn: ()=>this.exposedEvent.off.bind(this.exposedEvent)
|
|
1291
|
+
}
|
|
1292
|
+
];
|
|
1293
|
+
DOM_EVENTS.forEach((evt)=>{
|
|
1294
|
+
this.on(evt, (metadata)=>{
|
|
1295
|
+
// if (evt === 'wheel' && macOS) {
|
|
1296
|
+
// this.dispatch({ type: 'macOSWheel', treemap }, metadata)
|
|
1297
|
+
// return
|
|
1298
|
+
// }
|
|
1299
|
+
this.dispatch({
|
|
1300
|
+
type: evt,
|
|
1301
|
+
treemap
|
|
1302
|
+
}, metadata);
|
|
1303
|
+
});
|
|
1304
|
+
});
|
|
1305
|
+
mixin(app, exposedMethods);
|
|
1306
|
+
treemap.event.on(INTERNAL_EVENT_MAPPINGS.ON_CLEANUP, ()=>{
|
|
1307
|
+
this.matrix.create({
|
|
1308
|
+
a: 1,
|
|
1309
|
+
b: 0,
|
|
1310
|
+
c: 0,
|
|
1311
|
+
d: 1,
|
|
1312
|
+
e: 0,
|
|
1313
|
+
f: 0
|
|
1314
|
+
});
|
|
1315
|
+
this.state = createTreemapEventState();
|
|
1316
|
+
});
|
|
1317
|
+
this.zoom = createOnZoom(treemap, this);
|
|
1318
|
+
treemap.event.on(INTERNAL_EVENT_MAPPINGS.ON_ZOOM, this.zoom);
|
|
1319
|
+
}
|
|
1320
|
+
dispatch(ctx, metadata) {
|
|
1321
|
+
const node = findRelativeNode(metadata.loc, ctx.treemap.layoutNodes);
|
|
1322
|
+
const fn = prettyStrJoin('on', ctx.type);
|
|
1323
|
+
// @ts-expect-error safe
|
|
1324
|
+
if (typeof this[fn] === 'function') {
|
|
1325
|
+
// @ts-expect-error safe
|
|
1326
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
1327
|
+
this[fn](ctx, metadata, node);
|
|
1328
|
+
}
|
|
1329
|
+
// note: onmouseup event will trigger click event together
|
|
1330
|
+
if (ctx.type === 'mousemove') {
|
|
1331
|
+
if (this.state.isDragging) {
|
|
1332
|
+
this.exposedEvent.silent('click');
|
|
1333
|
+
} else {
|
|
1334
|
+
this.exposedEvent.active('click');
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
// For macOS
|
|
1338
|
+
this.exposedEvent.emit(ctx.type === 'macOSWheel' ? 'wheel' : ctx.type, {
|
|
1339
|
+
native: metadata.native,
|
|
1340
|
+
module: node
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
onmousemove(ctx, metadata, node) {
|
|
1344
|
+
if (!this.state.isDragging) {
|
|
1345
|
+
if (this.state.currentNode !== node || !node) {
|
|
1346
|
+
this.state.currentNode = node;
|
|
1347
|
+
}
|
|
1348
|
+
drawHighlight(ctx.treemap, this);
|
|
1349
|
+
} else {
|
|
1350
|
+
// for drag
|
|
1351
|
+
const { treemap } = ctx;
|
|
1352
|
+
smoothFrame((_, cleanup)=>{
|
|
1353
|
+
cleanup();
|
|
1354
|
+
const { offsetX: x, offsetY: y } = metadata.native;
|
|
1355
|
+
const { dragX: lastX, dragY: lastY } = this.state;
|
|
1356
|
+
const drawX = x - lastX;
|
|
1357
|
+
const drawY = y - lastY;
|
|
1358
|
+
treemap.highlight.reset();
|
|
1359
|
+
treemap.highlight.setZIndexForHighlight();
|
|
1360
|
+
treemap.reset();
|
|
1361
|
+
this.matrix.translation(drawX, drawY);
|
|
1362
|
+
Object.assign(this.state, {
|
|
1363
|
+
isDragging: true,
|
|
1364
|
+
dragX: x,
|
|
1365
|
+
dragY: y
|
|
1366
|
+
});
|
|
1367
|
+
stackMatrixTransformWithGraphAndLayer(treemap.elements, this.matrix.e, this.matrix.f, 1);
|
|
1368
|
+
treemap.update();
|
|
1369
|
+
return true;
|
|
1370
|
+
}, {
|
|
1371
|
+
duration: ANIMATION_DURATION,
|
|
1372
|
+
deps: [
|
|
1373
|
+
()=>this.state.forceDestroy
|
|
1374
|
+
],
|
|
1375
|
+
onStop: ()=>{
|
|
1376
|
+
this.state.isDragging = false;
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
onmouseout(ctx) {
|
|
1382
|
+
this.state.currentNode = null;
|
|
1383
|
+
drawHighlight(ctx.treemap, this);
|
|
1384
|
+
}
|
|
1385
|
+
onmousedown(ctx, metadata) {
|
|
1386
|
+
if (isScrollWheelOrRightButtonOnMouseupAndDown(metadata.native)) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
this.state.isDragging = true;
|
|
1390
|
+
this.state.dragX = metadata.native.offsetX;
|
|
1391
|
+
this.state.dragY = metadata.native.offsetY;
|
|
1392
|
+
this.state.forceDestroy = false;
|
|
1393
|
+
if (!ctx.treemap.renderCache.state) {
|
|
1394
|
+
this.exposedEvent.silent('mousemove');
|
|
1395
|
+
this.silent('mousemove');
|
|
1396
|
+
ctx.treemap.renderCache.flush(ctx.treemap, this.matrix);
|
|
1397
|
+
this.active('mousemove');
|
|
1398
|
+
this.exposedEvent.active('mousemove');
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
onmouseup(ctx) {
|
|
1402
|
+
if (!this.state.isDragging) {
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
this.state.forceDestroy = true;
|
|
1406
|
+
this.state.isDragging = false;
|
|
1407
|
+
const { treemap } = ctx;
|
|
1129
1408
|
treemap.highlight.reset();
|
|
1130
1409
|
treemap.highlight.setZIndexForHighlight();
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const targetScaleRatio = this.matrix.a * delta;
|
|
1192
|
-
const translateX = offsetX - (offsetX - this.matrix.e) * delta;
|
|
1193
|
-
const translateY = offsetY - (offsetY - this.matrix.f) * delta;
|
|
1194
|
-
smoothFrame((progress, cleanup) => {
|
|
1195
|
-
this.exposedEvent.silent("mousemove");
|
|
1196
|
-
this.silent("mousemove");
|
|
1197
|
-
this.silent("click");
|
|
1198
|
-
this.exposedEvent.silent("click");
|
|
1199
|
-
treemap.highlight.reset();
|
|
1200
|
-
treemap.highlight.setZIndexForHighlight();
|
|
1201
|
-
treemap.fontCache.flush(treemap, this.matrix);
|
|
1202
|
-
this.state.isWheeling = true;
|
|
1203
|
-
const easedProgress = easing.cubicInOut(progress);
|
|
1204
|
-
const scale = (targetScaleRatio - this.matrix.a) * easedProgress;
|
|
1205
|
-
this.matrix.a += scale;
|
|
1206
|
-
this.matrix.d += scale;
|
|
1207
|
-
this.matrix.translation((translateX - this.matrix.e) * easedProgress, (translateY - this.matrix.f) * easedProgress);
|
|
1208
|
-
resetLayout(
|
|
1209
|
-
treemap,
|
|
1210
|
-
treemap.render.canvas.width * this.matrix.a / treemap.render.options.devicePixelRatio,
|
|
1211
|
-
treemap.render.canvas.height * this.matrix.d / treemap.render.options.devicePixelRatio
|
|
1212
|
-
);
|
|
1213
|
-
stackMatrixTransformWithGraphAndLayer(treemap.elements, this.matrix.e, this.matrix.f, 1);
|
|
1214
|
-
treemap.update();
|
|
1215
|
-
cleanup();
|
|
1216
|
-
}, {
|
|
1217
|
-
duration: ANIMATION_DURATION,
|
|
1218
|
-
onStop: () => {
|
|
1219
|
-
this.state.forceDestroy = false;
|
|
1220
|
-
this.state.isWheeling = false;
|
|
1221
|
-
this.active("mousemove");
|
|
1222
|
-
this.exposedEvent.active("mousemove");
|
|
1223
|
-
this.active("click");
|
|
1224
|
-
this.exposedEvent.active("click");
|
|
1225
|
-
treemap.event.active(INTERNAL_EVENT_MAPPINGS.ON_ZOOM);
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
onmacOSWheel(ctx, metadata) {
|
|
1230
|
-
useMagicTrackPad(metadata.native);
|
|
1231
|
-
}
|
|
1410
|
+
}
|
|
1411
|
+
onwheel(ctx, metadata) {
|
|
1412
|
+
ctx.treemap.renderCache.destroy();
|
|
1413
|
+
ctx.treemap.event.silent(INTERNAL_EVENT_MAPPINGS.ON_ZOOM);
|
|
1414
|
+
const { native } = metadata;
|
|
1415
|
+
const { treemap } = ctx;
|
|
1416
|
+
// @ts-expect-error safe
|
|
1417
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1418
|
+
const wheelDelta = native.wheelDelta;
|
|
1419
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1420
|
+
const absWheelDelta = Math.abs(wheelDelta);
|
|
1421
|
+
const offsetX = native.offsetX;
|
|
1422
|
+
const offsetY = native.offsetY;
|
|
1423
|
+
if (wheelDelta === 0) {
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
this.state.forceDestroy = true;
|
|
1427
|
+
const factor = absWheelDelta > 3 ? 1.4 : absWheelDelta > 1 ? 1.2 : 1.1;
|
|
1428
|
+
const delta = wheelDelta > 0 ? factor : 1 / factor;
|
|
1429
|
+
const targetScaleRatio = this.matrix.a * delta;
|
|
1430
|
+
const translateX = offsetX - (offsetX - this.matrix.e) * delta;
|
|
1431
|
+
const translateY = offsetY - (offsetY - this.matrix.f) * delta;
|
|
1432
|
+
smoothFrame((progress, cleanup)=>{
|
|
1433
|
+
this.exposedEvent.silent('mousemove');
|
|
1434
|
+
this.silent('mousemove');
|
|
1435
|
+
this.silent('click');
|
|
1436
|
+
this.exposedEvent.silent('click');
|
|
1437
|
+
treemap.highlight.reset();
|
|
1438
|
+
treemap.highlight.setZIndexForHighlight();
|
|
1439
|
+
treemap.fontCache.flush(treemap, this.matrix);
|
|
1440
|
+
this.state.isWheeling = true;
|
|
1441
|
+
const easedProgress = easing.cubicInOut(progress);
|
|
1442
|
+
const scale = (targetScaleRatio - this.matrix.a) * easedProgress;
|
|
1443
|
+
this.matrix.a += scale;
|
|
1444
|
+
this.matrix.d += scale;
|
|
1445
|
+
this.matrix.translation((translateX - this.matrix.e) * easedProgress, (translateY - this.matrix.f) * easedProgress);
|
|
1446
|
+
// Each shape will scale by schedule phase. (According the dpi)
|
|
1447
|
+
// So that if the DPI is more than 1. we need to shrink first. ( w / dpi , h / dpi )
|
|
1448
|
+
// Schedule will scale it back to the original size.
|
|
1449
|
+
resetLayout(treemap, treemap.render.canvas.width * this.matrix.a / treemap.render.options.devicePixelRatio, treemap.render.canvas.height * this.matrix.d / treemap.render.options.devicePixelRatio);
|
|
1450
|
+
stackMatrixTransformWithGraphAndLayer(treemap.elements, this.matrix.e, this.matrix.f, 1);
|
|
1451
|
+
treemap.update();
|
|
1452
|
+
cleanup();
|
|
1453
|
+
}, {
|
|
1454
|
+
duration: ANIMATION_DURATION,
|
|
1455
|
+
onStop: ()=>{
|
|
1456
|
+
this.state.forceDestroy = false;
|
|
1457
|
+
this.state.isWheeling = false;
|
|
1458
|
+
// this.active('mousedown')
|
|
1459
|
+
this.active('mousemove');
|
|
1460
|
+
this.exposedEvent.active('mousemove');
|
|
1461
|
+
this.active('click');
|
|
1462
|
+
this.exposedEvent.active('click');
|
|
1463
|
+
treemap.event.active(INTERNAL_EVENT_MAPPINGS.ON_ZOOM);
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
onmacOSWheel(ctx, metadata) {
|
|
1468
|
+
useMagicTrackPad(metadata.native);
|
|
1469
|
+
}
|
|
1232
1470
|
}
|
|
1233
1471
|
function stackMatrixTransform(graph, e, f, scale) {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1472
|
+
graph.x = graph.x * scale + e;
|
|
1473
|
+
graph.y = graph.y * scale + f;
|
|
1474
|
+
graph.scaleX = scale;
|
|
1475
|
+
graph.scaleY = scale;
|
|
1238
1476
|
}
|
|
1239
1477
|
function stackMatrixTransformWithGraphAndLayer(graphs, e, f, scale) {
|
|
1240
|
-
|
|
1478
|
+
traverse(graphs, (graph)=>stackMatrixTransform(graph, e, f, scale));
|
|
1241
1479
|
}
|
|
1480
|
+
// Only works for mouseup and mousedown events
|
|
1242
1481
|
function isScrollWheelOrRightButtonOnMouseupAndDown(e) {
|
|
1243
|
-
|
|
1482
|
+
return e.which === 2 || e.which === 3;
|
|
1244
1483
|
}
|
|
1245
1484
|
function createOnZoom(treemap, evt) {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
evt.active("mousemove");
|
|
1279
|
-
evt.exposedEvent.active("mousemove");
|
|
1485
|
+
return (node)=>{
|
|
1486
|
+
treemap.renderCache.destroy();
|
|
1487
|
+
evt.state.isZooming = true;
|
|
1488
|
+
const c = treemap.render.canvas;
|
|
1489
|
+
const boundingClientRect = c.getBoundingClientRect();
|
|
1490
|
+
if (node) {
|
|
1491
|
+
const [mx, my, mw, mh] = node.layout;
|
|
1492
|
+
const factor = Math.min(boundingClientRect.width / mw, boundingClientRect.height / mh);
|
|
1493
|
+
const targetScale = factor * evt.matrix.a;
|
|
1494
|
+
const translateX = boundingClientRect.width / 2 - (mx + mw / 2) * factor;
|
|
1495
|
+
const translateY = boundingClientRect.height / 2 - (my + mh / 2) * factor;
|
|
1496
|
+
smoothFrame((progress, cleanup)=>{
|
|
1497
|
+
cleanup();
|
|
1498
|
+
evt.silent('mousemove');
|
|
1499
|
+
evt.exposedEvent.silent('mousemove');
|
|
1500
|
+
treemap.fontCache.flush(treemap, evt.matrix);
|
|
1501
|
+
const easedProgress = easing.cubicInOut(progress);
|
|
1502
|
+
const scale = (targetScale - evt.matrix.a) * easedProgress;
|
|
1503
|
+
evt.matrix.a += scale;
|
|
1504
|
+
evt.matrix.d += scale;
|
|
1505
|
+
evt.matrix.translation((translateX - evt.matrix.e) * easedProgress, (translateY - evt.matrix.f) * easedProgress);
|
|
1506
|
+
resetLayout(treemap, treemap.render.canvas.width * evt.matrix.a / treemap.render.options.devicePixelRatio, treemap.render.canvas.height * evt.matrix.d / treemap.render.options.devicePixelRatio);
|
|
1507
|
+
stackMatrixTransformWithGraphAndLayer(treemap.elements, evt.matrix.e, evt.matrix.f, 1);
|
|
1508
|
+
treemap.update();
|
|
1509
|
+
}, {
|
|
1510
|
+
duration: ANIMATION_DURATION,
|
|
1511
|
+
onStop: ()=>{
|
|
1512
|
+
evt.state.isZooming = false;
|
|
1513
|
+
evt.active('mousemove');
|
|
1514
|
+
evt.exposedEvent.active('mousemove');
|
|
1515
|
+
}
|
|
1516
|
+
});
|
|
1280
1517
|
}
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1283
|
-
};
|
|
1518
|
+
};
|
|
1284
1519
|
}
|
|
1285
1520
|
|
|
1286
1521
|
function register(Mod) {
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1522
|
+
return (app, treemap)=>{
|
|
1523
|
+
new Mod(app, treemap);
|
|
1524
|
+
};
|
|
1290
1525
|
}
|
|
1291
1526
|
|
|
1292
1527
|
function squarify(data, rect, layoutDecorator) {
|
|
1293
|
-
|
|
1294
|
-
|
|
1528
|
+
const result = [];
|
|
1529
|
+
if (!data.length) {
|
|
1530
|
+
return result;
|
|
1531
|
+
}
|
|
1532
|
+
const worst = (start, end, shortestSide, totalWeight, aspectRatio)=>{
|
|
1533
|
+
const max = data[start].weight * aspectRatio;
|
|
1534
|
+
const min = data[end].weight * aspectRatio;
|
|
1535
|
+
return Math.max(shortestSide * shortestSide * max / (totalWeight * totalWeight), totalWeight * totalWeight / (shortestSide * shortestSide * min));
|
|
1536
|
+
};
|
|
1537
|
+
const recursion = (start, rect)=>{
|
|
1538
|
+
while(start < data.length){
|
|
1539
|
+
let totalWeight = 0;
|
|
1540
|
+
for(let i = start; i < data.length; i++){
|
|
1541
|
+
totalWeight += data[i].weight;
|
|
1542
|
+
}
|
|
1543
|
+
const shortestSide = Math.min(rect.w, rect.h);
|
|
1544
|
+
const aspectRatio = rect.w * rect.h / totalWeight;
|
|
1545
|
+
let end = start;
|
|
1546
|
+
let areaInRun = 0;
|
|
1547
|
+
let oldWorst = 0;
|
|
1548
|
+
// find the best split
|
|
1549
|
+
while(end < data.length){
|
|
1550
|
+
const area = data[end].weight * aspectRatio;
|
|
1551
|
+
const newWorst = worst(start, end, shortestSide, areaInRun + area, aspectRatio);
|
|
1552
|
+
if (end > start && oldWorst < newWorst) {
|
|
1553
|
+
break;
|
|
1554
|
+
}
|
|
1555
|
+
areaInRun += area;
|
|
1556
|
+
oldWorst = newWorst;
|
|
1557
|
+
end++;
|
|
1558
|
+
}
|
|
1559
|
+
const splited = Math.round(areaInRun / shortestSide);
|
|
1560
|
+
let areaInLayout = 0;
|
|
1561
|
+
for(let i = start; i < end; i++){
|
|
1562
|
+
const children = data[i];
|
|
1563
|
+
const area = children.weight * aspectRatio;
|
|
1564
|
+
const lower = Math.round(shortestSide * areaInLayout / areaInRun);
|
|
1565
|
+
const upper = Math.round(shortestSide * (areaInLayout + area) / areaInRun);
|
|
1566
|
+
const [x, y, w, h] = rect.w >= rect.h ? [
|
|
1567
|
+
rect.x,
|
|
1568
|
+
rect.y + lower,
|
|
1569
|
+
splited,
|
|
1570
|
+
upper - lower
|
|
1571
|
+
] : [
|
|
1572
|
+
rect.x + lower,
|
|
1573
|
+
rect.y,
|
|
1574
|
+
upper - lower,
|
|
1575
|
+
splited
|
|
1576
|
+
];
|
|
1577
|
+
const depth = getNodeDepth(children) || 1;
|
|
1578
|
+
const { titleAreaHeight, rectGap } = layoutDecorator;
|
|
1579
|
+
const diff = titleAreaHeight.max / depth;
|
|
1580
|
+
const hh = diff < titleAreaHeight.min ? titleAreaHeight.min : diff;
|
|
1581
|
+
result.push({
|
|
1582
|
+
layout: [
|
|
1583
|
+
x,
|
|
1584
|
+
y,
|
|
1585
|
+
w,
|
|
1586
|
+
h
|
|
1587
|
+
],
|
|
1588
|
+
node: children,
|
|
1589
|
+
decorator: {
|
|
1590
|
+
...layoutDecorator,
|
|
1591
|
+
titleHeight: hh
|
|
1592
|
+
},
|
|
1593
|
+
children: w > rectGap * 2 && h > hh + rectGap ? squarify(children.groups || [], {
|
|
1594
|
+
x: x + rectGap,
|
|
1595
|
+
y: y + hh,
|
|
1596
|
+
w: w - rectGap * 2,
|
|
1597
|
+
h: h - hh - rectGap
|
|
1598
|
+
}, layoutDecorator) : []
|
|
1599
|
+
});
|
|
1600
|
+
areaInLayout += area;
|
|
1601
|
+
}
|
|
1602
|
+
start = end;
|
|
1603
|
+
if (rect.w >= rect.h) {
|
|
1604
|
+
rect.x += splited;
|
|
1605
|
+
rect.w -= splited;
|
|
1606
|
+
} else {
|
|
1607
|
+
rect.y += splited;
|
|
1608
|
+
rect.h -= splited;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
recursion(0, rect);
|
|
1295
1613
|
return result;
|
|
1296
|
-
}
|
|
1297
|
-
const worst = (start, end, shortestSide, totalWeight, aspectRatio) => {
|
|
1298
|
-
const max = data[start].weight * aspectRatio;
|
|
1299
|
-
const min = data[end].weight * aspectRatio;
|
|
1300
|
-
return Math.max(
|
|
1301
|
-
shortestSide * shortestSide * max / (totalWeight * totalWeight),
|
|
1302
|
-
totalWeight * totalWeight / (shortestSide * shortestSide * min)
|
|
1303
|
-
);
|
|
1304
|
-
};
|
|
1305
|
-
const recursion = (start, rect2) => {
|
|
1306
|
-
while (start < data.length) {
|
|
1307
|
-
let totalWeight = 0;
|
|
1308
|
-
for (let i = start; i < data.length; i++) {
|
|
1309
|
-
totalWeight += data[i].weight;
|
|
1310
|
-
}
|
|
1311
|
-
const shortestSide = Math.min(rect2.w, rect2.h);
|
|
1312
|
-
const aspectRatio = rect2.w * rect2.h / totalWeight;
|
|
1313
|
-
let end = start;
|
|
1314
|
-
let areaInRun = 0;
|
|
1315
|
-
let oldWorst = 0;
|
|
1316
|
-
while (end < data.length) {
|
|
1317
|
-
const area = data[end].weight * aspectRatio;
|
|
1318
|
-
const newWorst = worst(start, end, shortestSide, areaInRun + area, aspectRatio);
|
|
1319
|
-
if (end > start && oldWorst < newWorst) {
|
|
1320
|
-
break;
|
|
1321
|
-
}
|
|
1322
|
-
areaInRun += area;
|
|
1323
|
-
oldWorst = newWorst;
|
|
1324
|
-
end++;
|
|
1325
|
-
}
|
|
1326
|
-
const splited = Math.round(areaInRun / shortestSide);
|
|
1327
|
-
let areaInLayout = 0;
|
|
1328
|
-
for (let i = start; i < end; i++) {
|
|
1329
|
-
const children = data[i];
|
|
1330
|
-
const area = children.weight * aspectRatio;
|
|
1331
|
-
const lower = Math.round(shortestSide * areaInLayout / areaInRun);
|
|
1332
|
-
const upper = Math.round(shortestSide * (areaInLayout + area) / areaInRun);
|
|
1333
|
-
const [x, y, w, h] = rect2.w >= rect2.h ? [rect2.x, rect2.y + lower, splited, upper - lower] : [rect2.x + lower, rect2.y, upper - lower, splited];
|
|
1334
|
-
const depth = getNodeDepth(children) || 1;
|
|
1335
|
-
const { titleAreaHeight, rectGap } = layoutDecorator;
|
|
1336
|
-
const diff = titleAreaHeight.max / depth;
|
|
1337
|
-
const hh = diff < titleAreaHeight.min ? titleAreaHeight.min : diff;
|
|
1338
|
-
result.push({
|
|
1339
|
-
layout: [x, y, w, h],
|
|
1340
|
-
node: children,
|
|
1341
|
-
decorator: {
|
|
1342
|
-
...layoutDecorator,
|
|
1343
|
-
titleHeight: hh
|
|
1344
|
-
},
|
|
1345
|
-
children: w > rectGap * 2 && h > hh + rectGap ? squarify(children.groups || [], {
|
|
1346
|
-
x: x + rectGap,
|
|
1347
|
-
y: y + hh,
|
|
1348
|
-
w: w - rectGap * 2,
|
|
1349
|
-
h: h - hh - rectGap
|
|
1350
|
-
}, layoutDecorator) : []
|
|
1351
|
-
});
|
|
1352
|
-
areaInLayout += area;
|
|
1353
|
-
}
|
|
1354
|
-
start = end;
|
|
1355
|
-
if (rect2.w >= rect2.h) {
|
|
1356
|
-
rect2.x += splited;
|
|
1357
|
-
rect2.w -= splited;
|
|
1358
|
-
} else {
|
|
1359
|
-
rect2.y += splited;
|
|
1360
|
-
rect2.h -= splited;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
};
|
|
1364
|
-
recursion(0, rect);
|
|
1365
|
-
return result;
|
|
1366
1614
|
}
|
|
1367
1615
|
|
|
1368
|
-
var __defProp = Object.defineProperty;
|
|
1369
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1370
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1371
1616
|
function measureTextWidth(c, text) {
|
|
1372
|
-
|
|
1617
|
+
return c.measureText(text).width;
|
|
1373
1618
|
}
|
|
1374
1619
|
function evaluateOptimalFontSize(c, text, font, desiredW, desiredH) {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1620
|
+
desiredW = Math.floor(desiredW);
|
|
1621
|
+
desiredH = Math.floor(desiredH);
|
|
1622
|
+
const { range, family } = font;
|
|
1623
|
+
let min = range.min;
|
|
1624
|
+
let max = range.max;
|
|
1625
|
+
const cache = new Map();
|
|
1626
|
+
while(max - min >= 1){
|
|
1627
|
+
const current = min + (max - min) / 2;
|
|
1628
|
+
if (!cache.has(current)) {
|
|
1629
|
+
c.font = `${current}px ${family}`;
|
|
1630
|
+
const metrics = c.measureText(text);
|
|
1631
|
+
const width = metrics.width;
|
|
1632
|
+
const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
1633
|
+
cache.set(current, {
|
|
1634
|
+
width,
|
|
1635
|
+
height
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
const { width, height } = cache.get(current);
|
|
1639
|
+
if (width > desiredW || height > desiredH) {
|
|
1640
|
+
max = current;
|
|
1641
|
+
} else {
|
|
1642
|
+
min = current;
|
|
1643
|
+
}
|
|
1395
1644
|
}
|
|
1396
|
-
|
|
1397
|
-
return Math.floor(min);
|
|
1645
|
+
return Math.floor(min);
|
|
1398
1646
|
}
|
|
1399
1647
|
function getSafeText(c, text, width, cache) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1648
|
+
let ellipsisWidth = 0;
|
|
1649
|
+
if (text in cache) {
|
|
1650
|
+
ellipsisWidth = cache[text];
|
|
1651
|
+
} else {
|
|
1652
|
+
ellipsisWidth = measureTextWidth(c, '...');
|
|
1653
|
+
cache[text] = ellipsisWidth;
|
|
1654
|
+
}
|
|
1655
|
+
if (width < ellipsisWidth) {
|
|
1656
|
+
return false;
|
|
1657
|
+
}
|
|
1658
|
+
const textWidth = measureTextWidth(c, text);
|
|
1659
|
+
if (textWidth < width) {
|
|
1660
|
+
return {
|
|
1661
|
+
text,
|
|
1662
|
+
width: textWidth
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1665
|
+
return {
|
|
1666
|
+
text: '...',
|
|
1667
|
+
width: ellipsisWidth
|
|
1668
|
+
};
|
|
1415
1669
|
}
|
|
1416
1670
|
function resetLayout(treemap, w, h) {
|
|
1417
|
-
|
|
1418
|
-
|
|
1671
|
+
treemap.layoutNodes = squarify(treemap.data, {
|
|
1672
|
+
w,
|
|
1673
|
+
h,
|
|
1674
|
+
x: 0,
|
|
1675
|
+
y: 0
|
|
1676
|
+
}, treemap.decorator.layout);
|
|
1677
|
+
treemap.reset(true);
|
|
1419
1678
|
}
|
|
1420
1679
|
class Highlight extends Schedule {
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1680
|
+
reset() {
|
|
1681
|
+
this.destory();
|
|
1682
|
+
this.update();
|
|
1683
|
+
}
|
|
1684
|
+
get canvas() {
|
|
1685
|
+
return this.render.canvas;
|
|
1686
|
+
}
|
|
1687
|
+
setZIndexForHighlight(zIndex = '-1') {
|
|
1688
|
+
this.canvas.style.zIndex = zIndex;
|
|
1689
|
+
}
|
|
1690
|
+
init() {
|
|
1691
|
+
this.setZIndexForHighlight();
|
|
1692
|
+
this.canvas.style.position = 'absolute';
|
|
1693
|
+
this.canvas.style.pointerEvents = 'none';
|
|
1694
|
+
}
|
|
1436
1695
|
}
|
|
1437
1696
|
class TreemapLayout extends Schedule {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
rect.__widget__ = node;
|
|
1466
|
-
this.bgBox.add(rect);
|
|
1467
|
-
for (const child of node.children) {
|
|
1468
|
-
this.drawBackgroundNode(child);
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
drawForegroundNode(node) {
|
|
1472
|
-
const [x, y, w, h] = node.layout;
|
|
1473
|
-
if (!w || !h) {
|
|
1474
|
-
return;
|
|
1475
|
-
}
|
|
1476
|
-
const { titleHeight, rectGap } = node.decorator;
|
|
1477
|
-
const { fontSize, fontFamily, color } = this.decorator.font;
|
|
1478
|
-
const optimalFontSize = this.fontCache.queryFontById(node.node.id, () => evaluateOptimalFontSize(
|
|
1479
|
-
this.render.ctx,
|
|
1480
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1481
|
-
node.node.label,
|
|
1482
|
-
{
|
|
1483
|
-
range: fontSize,
|
|
1484
|
-
family: fontFamily
|
|
1485
|
-
},
|
|
1486
|
-
w - rectGap * 2,
|
|
1487
|
-
node.children.length ? Math.round(titleHeight / 2) + rectGap : h
|
|
1488
|
-
));
|
|
1489
|
-
this.render.ctx.font = `${optimalFontSize}px ${fontFamily}`;
|
|
1490
|
-
const result = getSafeText(this.render.ctx, node.node.label, w - rectGap * 2, this.fontCache.ellispsis);
|
|
1491
|
-
if (!result) {
|
|
1492
|
-
return;
|
|
1493
|
-
}
|
|
1494
|
-
if (result.width >= w || optimalFontSize >= h) {
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
const { text, width } = result;
|
|
1498
|
-
const textX = x + Math.round((w - width) / 2);
|
|
1499
|
-
const textY = y + (node.children.length ? Math.round(titleHeight / 2) : Math.round(h / 2));
|
|
1500
|
-
this.fgBox.add(createTitleText(text, textX, textY, `${optimalFontSize}px ${fontFamily}`, color));
|
|
1501
|
-
for (const child of node.children) {
|
|
1502
|
-
this.drawForegroundNode(child);
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
reset(refresh = false) {
|
|
1506
|
-
this.remove(this.bgBox, this.fgBox);
|
|
1507
|
-
this.bgBox.destory();
|
|
1508
|
-
if (this.renderCache.state) {
|
|
1509
|
-
this.fgBox.destory();
|
|
1510
|
-
this.bgBox.add(new Bitmap({ bitmap: this.renderCache.canvas, dpi: this.render.options.devicePixelRatio }));
|
|
1511
|
-
} else {
|
|
1512
|
-
for (const node of this.layoutNodes) {
|
|
1513
|
-
this.drawBackgroundNode(node);
|
|
1514
|
-
}
|
|
1515
|
-
if (!this.fgBox.elements.length || refresh) {
|
|
1516
|
-
this.render.ctx.textBaseline = "middle";
|
|
1517
|
-
this.fgBox.destory();
|
|
1518
|
-
for (const node of this.layoutNodes) {
|
|
1519
|
-
this.drawForegroundNode(node);
|
|
1520
|
-
}
|
|
1521
|
-
} else {
|
|
1522
|
-
this.fgBox = this.fgBox.clone();
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
this.add(this.bgBox, this.fgBox);
|
|
1526
|
-
}
|
|
1527
|
-
get api() {
|
|
1528
|
-
return {
|
|
1529
|
-
zoom: (node) => {
|
|
1530
|
-
if (!node) {
|
|
1531
|
-
return;
|
|
1697
|
+
data;
|
|
1698
|
+
layoutNodes;
|
|
1699
|
+
decorator;
|
|
1700
|
+
bgBox;
|
|
1701
|
+
fgBox;
|
|
1702
|
+
highlight;
|
|
1703
|
+
renderCache;
|
|
1704
|
+
fontCache;
|
|
1705
|
+
constructor(...args){
|
|
1706
|
+
super(...args);
|
|
1707
|
+
this.data = [];
|
|
1708
|
+
this.layoutNodes = [];
|
|
1709
|
+
this.bgBox = new Box();
|
|
1710
|
+
this.fgBox = new Box();
|
|
1711
|
+
this.decorator = Object.create(null);
|
|
1712
|
+
this.highlight = new Highlight(this.to, {
|
|
1713
|
+
width: this.render.options.width,
|
|
1714
|
+
height: this.render.options.height
|
|
1715
|
+
});
|
|
1716
|
+
this.renderCache = new RenderCache(this.render.options);
|
|
1717
|
+
this.fontCache = new FontCache();
|
|
1718
|
+
}
|
|
1719
|
+
drawBackgroundNode(node) {
|
|
1720
|
+
const [x, y, w, h] = node.layout;
|
|
1721
|
+
const padding = 2;
|
|
1722
|
+
if (w - padding * 2 <= 0 || h - padding * 2 <= 0) {
|
|
1723
|
+
return;
|
|
1532
1724
|
}
|
|
1533
|
-
this.
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1725
|
+
const fill = this.decorator.color.mappings[node.node.id];
|
|
1726
|
+
const rect = createRoundBlock(x, y, w, h, {
|
|
1727
|
+
fill,
|
|
1728
|
+
padding,
|
|
1729
|
+
radius: 4
|
|
1730
|
+
});
|
|
1731
|
+
rect.__widget__ = node;
|
|
1732
|
+
this.bgBox.add(rect);
|
|
1733
|
+
for (const child of node.children){
|
|
1734
|
+
this.drawBackgroundNode(child);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
drawForegroundNode(node) {
|
|
1738
|
+
const [x, y, w, h] = node.layout;
|
|
1739
|
+
if (!w || !h) {
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
const { titleHeight, rectGap } = node.decorator;
|
|
1743
|
+
const { fontSize, fontFamily, color } = this.decorator.font;
|
|
1744
|
+
const optimalFontSize = this.fontCache.queryFontById(node.node.id, ()=>evaluateOptimalFontSize(this.render.ctx, // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1745
|
+
node.node.label, {
|
|
1746
|
+
range: fontSize,
|
|
1747
|
+
family: fontFamily
|
|
1748
|
+
}, w - rectGap * 2, node.children.length ? Math.round(titleHeight / 2) + rectGap : h));
|
|
1749
|
+
this.render.ctx.font = `${optimalFontSize}px ${fontFamily}`;
|
|
1750
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1751
|
+
const result = getSafeText(this.render.ctx, node.node.label, w - rectGap * 2, this.fontCache.ellispsis);
|
|
1752
|
+
if (!result) {
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
if (result.width >= w || optimalFontSize >= h) {
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
const { text, width } = result;
|
|
1759
|
+
const textX = x + Math.round((w - width) / 2);
|
|
1760
|
+
const textY = y + (node.children.length ? Math.round(titleHeight / 2) : Math.round(h / 2));
|
|
1761
|
+
this.fgBox.add(createTitleText(text, textX, textY, `${optimalFontSize}px ${fontFamily}`, color));
|
|
1762
|
+
for (const child of node.children){
|
|
1763
|
+
this.drawForegroundNode(child);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
reset(refresh = false) {
|
|
1767
|
+
this.remove(this.bgBox, this.fgBox);
|
|
1768
|
+
this.bgBox.destory();
|
|
1769
|
+
if (this.renderCache.state) {
|
|
1770
|
+
this.fgBox.destory();
|
|
1771
|
+
this.bgBox.add(new Bitmap({
|
|
1772
|
+
bitmap: this.renderCache.canvas,
|
|
1773
|
+
dpi: this.render.options.devicePixelRatio
|
|
1774
|
+
}));
|
|
1775
|
+
} else {
|
|
1776
|
+
for (const node of this.layoutNodes){
|
|
1777
|
+
this.drawBackgroundNode(node);
|
|
1778
|
+
}
|
|
1779
|
+
if (!this.fgBox.elements.length || refresh) {
|
|
1780
|
+
this.render.ctx.textBaseline = 'middle';
|
|
1781
|
+
this.fgBox.destory();
|
|
1782
|
+
for (const node of this.layoutNodes){
|
|
1783
|
+
this.drawForegroundNode(node);
|
|
1784
|
+
}
|
|
1785
|
+
} else {
|
|
1786
|
+
this.fgBox = this.fgBox.clone();
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
this.add(this.bgBox, this.fgBox);
|
|
1790
|
+
}
|
|
1791
|
+
get api() {
|
|
1792
|
+
return {
|
|
1793
|
+
zoom: (node)=>{
|
|
1794
|
+
if (!node) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
this.event.emit(INTERNAL_EVENT_MAPPINGS.ON_ZOOM, node);
|
|
1798
|
+
}
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1537
1801
|
}
|
|
1538
1802
|
function createTreemap() {
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
|
|
1803
|
+
let treemap = null;
|
|
1804
|
+
let root = null;
|
|
1805
|
+
let installed = false;
|
|
1806
|
+
const uses = [];
|
|
1807
|
+
const context = {
|
|
1808
|
+
init,
|
|
1809
|
+
dispose,
|
|
1810
|
+
setOptions,
|
|
1811
|
+
resize,
|
|
1812
|
+
use,
|
|
1813
|
+
zoom
|
|
1814
|
+
};
|
|
1815
|
+
function init(el) {
|
|
1816
|
+
treemap = new TreemapLayout(el);
|
|
1817
|
+
root = el;
|
|
1818
|
+
root.style.position = 'relative';
|
|
1819
|
+
if (!installed) {
|
|
1820
|
+
register(TreemapEvent)(context, treemap);
|
|
1821
|
+
installed = true;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function dispose() {
|
|
1825
|
+
if (root && treemap) {
|
|
1826
|
+
treemap.destory();
|
|
1827
|
+
root.removeChild(root.firstChild);
|
|
1828
|
+
root = null;
|
|
1829
|
+
treemap = null;
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
function resize() {
|
|
1833
|
+
if (!treemap || !root) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
treemap.renderCache.destroy();
|
|
1837
|
+
treemap.fontCache.destroy();
|
|
1838
|
+
const { width, height } = root.getBoundingClientRect();
|
|
1839
|
+
treemap.render.initOptions({
|
|
1840
|
+
height,
|
|
1841
|
+
width,
|
|
1842
|
+
devicePixelRatio: window.devicePixelRatio
|
|
1843
|
+
});
|
|
1844
|
+
treemap.render.canvas.style.position = 'absolute';
|
|
1845
|
+
treemap.event.emit(INTERNAL_EVENT_MAPPINGS.ON_CLEANUP);
|
|
1846
|
+
treemap.highlight.render.initOptions({
|
|
1847
|
+
height,
|
|
1848
|
+
width,
|
|
1849
|
+
devicePixelRatio: window.devicePixelRatio
|
|
1850
|
+
});
|
|
1851
|
+
treemap.highlight.reset();
|
|
1852
|
+
treemap.highlight.init();
|
|
1853
|
+
resetLayout(treemap, width, height);
|
|
1854
|
+
treemap.update();
|
|
1855
|
+
treemap.renderCache.flush(treemap, treemap.matrix);
|
|
1856
|
+
}
|
|
1857
|
+
function setOptions(options) {
|
|
1858
|
+
if (!treemap) {
|
|
1859
|
+
throw new Error(log.error('Treemap not initialized'));
|
|
1860
|
+
}
|
|
1861
|
+
treemap.data = bindParentForModule(options.data || []);
|
|
1862
|
+
for (const use of uses){
|
|
1863
|
+
use(treemap);
|
|
1864
|
+
}
|
|
1865
|
+
resize();
|
|
1866
|
+
}
|
|
1867
|
+
function use(key, register) {
|
|
1868
|
+
switch(key){
|
|
1869
|
+
case 'decorator':
|
|
1870
|
+
uses.push((treemap)=>register(treemap));
|
|
1871
|
+
break;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
function zoom(id) {
|
|
1875
|
+
if (!treemap) {
|
|
1876
|
+
throw new Error(log.error("treemap don't init."));
|
|
1877
|
+
}
|
|
1878
|
+
const node = findRelativeNodeById(id, treemap.layoutNodes);
|
|
1879
|
+
if (node) {
|
|
1880
|
+
treemap.api.zoom(node);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return context;
|
|
1612
1884
|
}
|
|
1613
1885
|
|
|
1614
1886
|
const defaultLayoutOptions = {
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1887
|
+
titleAreaHeight: {
|
|
1888
|
+
max: 60,
|
|
1889
|
+
min: 30
|
|
1890
|
+
},
|
|
1891
|
+
rectGap: 5,
|
|
1892
|
+
rectBorderRadius: 0.5,
|
|
1893
|
+
rectBorderWidth: 1.5
|
|
1622
1894
|
};
|
|
1623
1895
|
const defaultFontOptions = {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1896
|
+
color: '#000',
|
|
1897
|
+
fontSize: {
|
|
1898
|
+
max: 70,
|
|
1899
|
+
min: 0
|
|
1900
|
+
},
|
|
1901
|
+
fontFamily: 'sans-serif'
|
|
1630
1902
|
};
|
|
1631
1903
|
function presetDecorator(app) {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1904
|
+
Object.assign(app.decorator, {
|
|
1905
|
+
layout: defaultLayoutOptions,
|
|
1906
|
+
font: defaultFontOptions,
|
|
1907
|
+
color: {
|
|
1908
|
+
mappings: evaluateColorMappings(app.data)
|
|
1909
|
+
}
|
|
1910
|
+
});
|
|
1637
1911
|
}
|
|
1638
1912
|
function evaluateColorMappings(data) {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
};
|
|
1644
|
-
const lightScale = (depth) => 50 - depth * 5;
|
|
1645
|
-
const baseSaturation = 80;
|
|
1646
|
-
const siblingHueShift = 30;
|
|
1647
|
-
const rc = 0.2126;
|
|
1648
|
-
const gc = 0.7152;
|
|
1649
|
-
const bc = 0.0722;
|
|
1650
|
-
const hslToRgb = (h, s, l) => {
|
|
1651
|
-
const a = s * Math.min(l, 1 - l);
|
|
1652
|
-
const f = (n) => {
|
|
1653
|
-
const k = (n + h / 30) % 12;
|
|
1654
|
-
return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
1913
|
+
const colorMappings = {};
|
|
1914
|
+
const hashToHue = (id)=>{
|
|
1915
|
+
const hash = Math.abs(hashCode(id));
|
|
1916
|
+
return hash % 360;
|
|
1655
1917
|
};
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1918
|
+
const lightScale = (depth)=>50 - depth * 5;
|
|
1919
|
+
const baseSaturation = 80;
|
|
1920
|
+
const siblingHueShift = 30;
|
|
1921
|
+
const rc = 0.2126;
|
|
1922
|
+
const gc = 0.7152;
|
|
1923
|
+
const bc = 0.0722;
|
|
1924
|
+
const hslToRgb = (h, s, l)=>{
|
|
1925
|
+
const a = s * Math.min(l, 1 - l);
|
|
1926
|
+
const f = (n)=>{
|
|
1927
|
+
const k = (n + h / 30) % 12;
|
|
1928
|
+
return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
1929
|
+
};
|
|
1930
|
+
return {
|
|
1931
|
+
r: f(0),
|
|
1932
|
+
g: f(8),
|
|
1933
|
+
b: f(4)
|
|
1934
|
+
};
|
|
1669
1935
|
};
|
|
1670
|
-
const
|
|
1671
|
-
|
|
1672
|
-
if (luminance < 0.6) {
|
|
1673
|
-
hslColor.l += 0.2;
|
|
1674
|
-
} else if (luminance > 0.8) {
|
|
1675
|
-
hslColor.l -= 0.1;
|
|
1676
|
-
}
|
|
1677
|
-
hslColor.l *= 100;
|
|
1678
|
-
colorMappings[module.id] = {
|
|
1679
|
-
mode: "hsl",
|
|
1680
|
-
desc: hslColor
|
|
1936
|
+
const calculateLuminance = (r, g, b)=>{
|
|
1937
|
+
return rc * r + gc * g + bc * b;
|
|
1681
1938
|
};
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
const
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1939
|
+
const calculateColor = (module, depth, parentHue, siblingIndex, totalSiblings)=>{
|
|
1940
|
+
const nodeHue = hashToHue(module.id);
|
|
1941
|
+
const hue = parentHue !== null ? (parentHue + siblingHueShift * siblingIndex / totalSiblings) % 360 : nodeHue;
|
|
1942
|
+
const lightness = lightScale(depth);
|
|
1943
|
+
const hslColor = {
|
|
1944
|
+
h: hue,
|
|
1945
|
+
s: baseSaturation,
|
|
1946
|
+
l: lightness / 100
|
|
1947
|
+
};
|
|
1948
|
+
const { r, g, b } = hslToRgb(hslColor.h, hslColor.s / 100, hslColor.l);
|
|
1949
|
+
const luminance = calculateLuminance(r, g, b);
|
|
1950
|
+
if (luminance < 0.6) {
|
|
1951
|
+
hslColor.l += 0.2;
|
|
1952
|
+
} else if (luminance > 0.8) {
|
|
1953
|
+
hslColor.l -= 0.1;
|
|
1954
|
+
}
|
|
1955
|
+
hslColor.l *= 100;
|
|
1956
|
+
colorMappings[module.id] = {
|
|
1957
|
+
mode: 'hsl',
|
|
1958
|
+
desc: hslColor
|
|
1959
|
+
};
|
|
1960
|
+
if (module.groups && Array.isArray(module.groups)) {
|
|
1961
|
+
const totalChildren = module.groups.length;
|
|
1962
|
+
for(let i = 0; i < totalChildren; i++){
|
|
1963
|
+
const child = module.groups[i];
|
|
1964
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1965
|
+
calculateColor(child, depth + 1, hue, i, totalChildren);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
};
|
|
1969
|
+
for(let i = 0; i < data.length; i++){
|
|
1970
|
+
const module = data[i];
|
|
1971
|
+
calculateColor(module, 0, null, i, data.length);
|
|
1972
|
+
}
|
|
1973
|
+
return colorMappings;
|
|
1695
1974
|
}
|
|
1696
1975
|
|
|
1697
1976
|
exports.TreemapLayout = TreemapLayout;
|