squarified 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -11
- package/dist/index.d.mts +312 -0
- package/dist/index.d.ts +73 -52
- package/dist/index.js +1464 -1303
- package/dist/index.mjs +1464 -1303
- package/package.json +11 -15
package/dist/index.mjs
CHANGED
|
@@ -1,1439 +1,1600 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
keys;
|
|
5
|
-
data;
|
|
6
|
-
constructor(data){
|
|
7
|
-
this.data = data;
|
|
8
|
-
this.keys = Object.keys(data);
|
|
9
|
-
}
|
|
10
|
-
// dprint-ignore
|
|
11
|
-
*[_computedKey]() {
|
|
12
|
-
for(let i = 0; i < this.keys.length; i++){
|
|
13
|
-
yield {
|
|
14
|
-
key: this.keys[i],
|
|
15
|
-
value: this.data[this.keys[i]],
|
|
16
|
-
index: i,
|
|
17
|
-
peek: ()=>this.keys[i + 1]
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
// For strings we only check the first character to determine if it's a number (I think it's enough)
|
|
23
|
-
function perferNumeric(s) {
|
|
24
|
-
if (typeof s === 'number') return true;
|
|
25
|
-
return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
|
|
26
|
-
}
|
|
27
|
-
|
|
1
|
+
var __defProp$a = Object.defineProperty;
|
|
2
|
+
var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
28
4
|
const DEG_TO_RAD = Math.PI / 180;
|
|
29
5
|
class Matrix2D {
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.d = d;
|
|
97
|
-
}
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
6
|
+
constructor(loc = {}) {
|
|
7
|
+
__publicField$a(this, "a");
|
|
8
|
+
__publicField$a(this, "b");
|
|
9
|
+
__publicField$a(this, "c");
|
|
10
|
+
__publicField$a(this, "d");
|
|
11
|
+
__publicField$a(this, "e");
|
|
12
|
+
__publicField$a(this, "f");
|
|
13
|
+
this.a = loc.a || 1;
|
|
14
|
+
this.b = loc.b || 0;
|
|
15
|
+
this.c = loc.c || 0;
|
|
16
|
+
this.d = loc.d || 1;
|
|
17
|
+
this.e = loc.e || 0;
|
|
18
|
+
this.f = loc.f || 0;
|
|
19
|
+
}
|
|
20
|
+
create(loc) {
|
|
21
|
+
Object.assign(this, loc);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
transform(x, y, scaleX, scaleY, rotation, skewX, skewY) {
|
|
25
|
+
this.scale(scaleX, scaleY).translation(x, y);
|
|
26
|
+
if (skewX || skewY) {
|
|
27
|
+
this.skew(skewX, skewY);
|
|
28
|
+
} else {
|
|
29
|
+
this.roate(rotation);
|
|
30
|
+
}
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
translation(x, y) {
|
|
34
|
+
this.e += x;
|
|
35
|
+
this.f += y;
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
scale(a, d) {
|
|
39
|
+
this.a *= a;
|
|
40
|
+
this.d *= d;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
skew(x, y) {
|
|
44
|
+
const tanX = Math.tan(x * DEG_TO_RAD);
|
|
45
|
+
const tanY = Math.tan(y * DEG_TO_RAD);
|
|
46
|
+
const a = this.a + this.b * tanX;
|
|
47
|
+
const b = this.b + this.a * tanY;
|
|
48
|
+
const c = this.c + this.d * tanX;
|
|
49
|
+
const d = this.d + this.c * tanY;
|
|
50
|
+
this.a = a;
|
|
51
|
+
this.b = b;
|
|
52
|
+
this.c = c;
|
|
53
|
+
this.d = d;
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
roate(rotation) {
|
|
57
|
+
if (rotation > 0) {
|
|
58
|
+
const rad = rotation * DEG_TO_RAD;
|
|
59
|
+
const cosTheta = Math.cos(rad);
|
|
60
|
+
const sinTheta = Math.sin(rad);
|
|
61
|
+
const a = this.a * cosTheta - this.b * sinTheta;
|
|
62
|
+
const b = this.a * sinTheta + this.b * cosTheta;
|
|
63
|
+
const c = this.c * cosTheta - this.d * sinTheta;
|
|
64
|
+
const d = this.c * sinTheta + this.d * cosTheta;
|
|
65
|
+
this.a = a;
|
|
66
|
+
this.b = b;
|
|
67
|
+
this.c = c;
|
|
68
|
+
this.d = d;
|
|
69
|
+
}
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
100
72
|
}
|
|
101
73
|
|
|
74
|
+
var __defProp$9 = Object.defineProperty;
|
|
75
|
+
var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
76
|
+
var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
102
77
|
const SELF_ID = {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
78
|
+
id: 0,
|
|
79
|
+
get() {
|
|
80
|
+
return this.id++;
|
|
81
|
+
}
|
|
107
82
|
};
|
|
83
|
+
var DisplayType = /* @__PURE__ */ ((DisplayType2) => {
|
|
84
|
+
DisplayType2["Graph"] = "Graph";
|
|
85
|
+
DisplayType2["Box"] = "Box";
|
|
86
|
+
DisplayType2["Rect"] = "Rect";
|
|
87
|
+
DisplayType2["Text"] = "Text";
|
|
88
|
+
DisplayType2["Layer"] = "Layer";
|
|
89
|
+
return DisplayType2;
|
|
90
|
+
})(DisplayType || {});
|
|
108
91
|
class Display {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
92
|
+
constructor() {
|
|
93
|
+
__publicField$9(this, "parent");
|
|
94
|
+
__publicField$9(this, "id");
|
|
95
|
+
__publicField$9(this, "matrix");
|
|
96
|
+
this.parent = null;
|
|
97
|
+
this.id = SELF_ID.get();
|
|
98
|
+
this.matrix = new Matrix2D();
|
|
99
|
+
}
|
|
100
|
+
destory() {
|
|
101
|
+
}
|
|
120
102
|
}
|
|
121
103
|
const ASSIGN_MAPPINGS = {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
104
|
+
fillStyle: true,
|
|
105
|
+
strokeStyle: true,
|
|
106
|
+
font: true,
|
|
107
|
+
lineWidth: true,
|
|
108
|
+
textAlign: true,
|
|
109
|
+
textBaseline: true
|
|
128
110
|
};
|
|
129
111
|
function createInstruction() {
|
|
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
|
-
fillText (...args) {
|
|
163
|
-
this.mods.push([
|
|
164
|
-
'fillText',
|
|
165
|
-
args
|
|
166
|
-
]);
|
|
167
|
-
},
|
|
168
|
-
font (...args) {
|
|
169
|
-
this.mods.push([
|
|
170
|
-
'font',
|
|
171
|
-
args
|
|
172
|
-
]);
|
|
173
|
-
},
|
|
174
|
-
textBaseline (...args) {
|
|
175
|
-
this.mods.push([
|
|
176
|
-
'textBaseline',
|
|
177
|
-
args
|
|
178
|
-
]);
|
|
179
|
-
},
|
|
180
|
-
textAlign (...args) {
|
|
181
|
-
this.mods.push([
|
|
182
|
-
'textAlign',
|
|
183
|
-
args
|
|
184
|
-
]);
|
|
185
|
-
}
|
|
186
|
-
};
|
|
112
|
+
return {
|
|
113
|
+
mods: [],
|
|
114
|
+
fillStyle(...args) {
|
|
115
|
+
this.mods.push(["fillStyle", args]);
|
|
116
|
+
},
|
|
117
|
+
fillRect(...args) {
|
|
118
|
+
this.mods.push(["fillRect", args]);
|
|
119
|
+
},
|
|
120
|
+
strokeStyle(...args) {
|
|
121
|
+
this.mods.push(["strokeStyle", args]);
|
|
122
|
+
},
|
|
123
|
+
lineWidth(...args) {
|
|
124
|
+
this.mods.push(["lineWidth", args]);
|
|
125
|
+
},
|
|
126
|
+
strokeRect(...args) {
|
|
127
|
+
this.mods.push(["strokeRect", args]);
|
|
128
|
+
},
|
|
129
|
+
fillText(...args) {
|
|
130
|
+
this.mods.push(["fillText", args]);
|
|
131
|
+
},
|
|
132
|
+
font(...args) {
|
|
133
|
+
this.mods.push(["font", args]);
|
|
134
|
+
},
|
|
135
|
+
textBaseline(...args) {
|
|
136
|
+
this.mods.push(["textBaseline", args]);
|
|
137
|
+
},
|
|
138
|
+
textAlign(...args) {
|
|
139
|
+
this.mods.push(["textAlign", args]);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
187
142
|
}
|
|
188
143
|
class S extends Display {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
144
|
+
constructor(options = {}) {
|
|
145
|
+
super();
|
|
146
|
+
__publicField$9(this, "width");
|
|
147
|
+
__publicField$9(this, "height");
|
|
148
|
+
__publicField$9(this, "x");
|
|
149
|
+
__publicField$9(this, "y");
|
|
150
|
+
__publicField$9(this, "scaleX");
|
|
151
|
+
__publicField$9(this, "scaleY");
|
|
152
|
+
__publicField$9(this, "rotation");
|
|
153
|
+
__publicField$9(this, "skewX");
|
|
154
|
+
__publicField$9(this, "skewY");
|
|
155
|
+
this.width = options.width || 0;
|
|
156
|
+
this.height = options.height || 0;
|
|
157
|
+
this.x = options.x || 0;
|
|
158
|
+
this.y = options.y || 0;
|
|
159
|
+
this.scaleX = options.scaleX || 1;
|
|
160
|
+
this.scaleY = options.scaleY || 1;
|
|
161
|
+
this.rotation = options.rotation || 0;
|
|
162
|
+
this.skewX = options.skewX || 0;
|
|
163
|
+
this.skewY = options.skewY || 0;
|
|
164
|
+
}
|
|
210
165
|
}
|
|
211
166
|
class Graph extends S {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
167
|
+
constructor(options = {}) {
|
|
168
|
+
super(options);
|
|
169
|
+
__publicField$9(this, "instruction");
|
|
170
|
+
__publicField$9(this, "__options__");
|
|
171
|
+
this.instruction = createInstruction();
|
|
172
|
+
this.__options__ = options;
|
|
173
|
+
}
|
|
174
|
+
render(ctx) {
|
|
175
|
+
this.create();
|
|
176
|
+
const cap = this.instruction.mods.length;
|
|
177
|
+
for (let i = 0; i < cap; i++) {
|
|
178
|
+
const mod = this.instruction.mods[i];
|
|
179
|
+
const [direct, ...args] = mod;
|
|
180
|
+
if (direct in ASSIGN_MAPPINGS) {
|
|
181
|
+
ctx[direct] = args[0];
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
ctx[direct].apply(ctx, ...args);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
get __instanceOf__() {
|
|
188
|
+
return "Graph" /* Graph */;
|
|
189
|
+
}
|
|
230
190
|
}
|
|
231
191
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
192
|
+
function isGraph(display) {
|
|
193
|
+
return display.__instanceOf__ === DisplayType.Graph;
|
|
194
|
+
}
|
|
195
|
+
function isBox(display) {
|
|
196
|
+
return display.__instanceOf__ === DisplayType.Box;
|
|
197
|
+
}
|
|
198
|
+
function isRect(display) {
|
|
199
|
+
return isGraph(display) && display.__shape__ === DisplayType.Rect;
|
|
200
|
+
}
|
|
201
|
+
function isText(display) {
|
|
202
|
+
return isGraph(display) && display.__shape__ === DisplayType.Text;
|
|
203
|
+
}
|
|
204
|
+
function isLayer(display) {
|
|
205
|
+
return display.__instanceOf__ === DisplayType.Layer;
|
|
206
|
+
}
|
|
207
|
+
const asserts = {
|
|
208
|
+
isGraph,
|
|
209
|
+
isBox,
|
|
210
|
+
isRect,
|
|
211
|
+
isText,
|
|
212
|
+
isLayer
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
var __defProp$8 = Object.defineProperty;
|
|
216
|
+
var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
217
|
+
var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, key + "" , value);
|
|
218
|
+
class C extends Display {
|
|
219
|
+
constructor() {
|
|
220
|
+
super();
|
|
221
|
+
__publicField$8(this, "elements");
|
|
222
|
+
this.elements = [];
|
|
223
|
+
}
|
|
224
|
+
add(...elements) {
|
|
225
|
+
const cap = elements.length;
|
|
226
|
+
for (let i = 0; i < cap; i++) {
|
|
227
|
+
const element = elements[i];
|
|
228
|
+
if (element.parent) ;
|
|
229
|
+
this.elements.push(element);
|
|
230
|
+
element.parent = this;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
remove(...elements) {
|
|
234
|
+
const cap = elements.length;
|
|
235
|
+
for (let i = 0; i < cap; i++) {
|
|
236
|
+
for (let j = this.elements.length - 1; j >= 0; j--) {
|
|
237
|
+
const element = this.elements[j];
|
|
238
|
+
if (element.id === elements[i].id) {
|
|
239
|
+
this.elements.splice(j, 1);
|
|
240
|
+
element.parent = null;
|
|
245
241
|
}
|
|
242
|
+
}
|
|
246
243
|
}
|
|
247
|
-
|
|
244
|
+
}
|
|
245
|
+
destory() {
|
|
246
|
+
this.elements.forEach((element) => element.parent = null);
|
|
247
|
+
this.elements.length = 0;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
class Box extends C {
|
|
251
|
+
constructor() {
|
|
252
|
+
super();
|
|
253
|
+
__publicField$8(this, "elements");
|
|
254
|
+
this.elements = [];
|
|
255
|
+
}
|
|
256
|
+
add(...elements) {
|
|
257
|
+
const cap = elements.length;
|
|
258
|
+
for (let i = 0; i < cap; i++) {
|
|
259
|
+
const element = elements[i];
|
|
260
|
+
if (element.parent) ;
|
|
261
|
+
this.elements.push(element);
|
|
262
|
+
element.parent = this;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
remove(...elements) {
|
|
266
|
+
const cap = elements.length;
|
|
267
|
+
for (let i = 0; i < cap; i++) {
|
|
268
|
+
for (let j = this.elements.length - 1; j >= 0; j--) {
|
|
269
|
+
const element = this.elements[j];
|
|
270
|
+
if (element.id === elements[i].id) {
|
|
271
|
+
this.elements.splice(j, 1);
|
|
272
|
+
element.parent = null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
destory() {
|
|
278
|
+
this.elements.forEach((element) => element.parent = null);
|
|
279
|
+
this.elements.length = 0;
|
|
280
|
+
}
|
|
281
|
+
get __instanceOf__() {
|
|
282
|
+
return DisplayType.Box;
|
|
283
|
+
}
|
|
284
|
+
clone() {
|
|
285
|
+
const box = new Box();
|
|
286
|
+
if (this.elements.length) {
|
|
287
|
+
const traverse = (elements, parent) => {
|
|
288
|
+
const els = [];
|
|
248
289
|
const cap = elements.length;
|
|
249
|
-
for(let i = 0; i < cap; i++){
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
290
|
+
for (let i = 0; i < cap; i++) {
|
|
291
|
+
const element = elements[i];
|
|
292
|
+
if (asserts.isBox(element)) {
|
|
293
|
+
const box2 = new Box();
|
|
294
|
+
box2.parent = parent;
|
|
295
|
+
box2.add(...traverse(element.elements, box2));
|
|
296
|
+
els.push(box2);
|
|
297
|
+
} else if (asserts.isGraph(element)) {
|
|
298
|
+
const el = element.clone();
|
|
299
|
+
el.parent = parent;
|
|
300
|
+
els.push(el);
|
|
301
|
+
}
|
|
257
302
|
}
|
|
303
|
+
return els;
|
|
304
|
+
};
|
|
305
|
+
box.add(...traverse(this.elements, box));
|
|
258
306
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
307
|
+
return box;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
var __defProp$7 = Object.defineProperty;
|
|
312
|
+
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
313
|
+
var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
314
|
+
function writeBoundingRectForCanvas(c, w, h, dpr) {
|
|
315
|
+
c.width = w * dpr;
|
|
316
|
+
c.height = h * dpr;
|
|
317
|
+
c.style.cssText = `width: ${w}px; height: ${h}px`;
|
|
318
|
+
}
|
|
319
|
+
class Canvas {
|
|
320
|
+
constructor(options) {
|
|
321
|
+
__publicField$7(this, "canvas");
|
|
322
|
+
__publicField$7(this, "ctx");
|
|
323
|
+
this.canvas = createCanvasElement();
|
|
324
|
+
writeBoundingRectForCanvas(this.canvas, options.width, options.height, options.devicePixelRatio);
|
|
325
|
+
this.ctx = this.canvas.getContext("2d");
|
|
326
|
+
}
|
|
327
|
+
get c() {
|
|
328
|
+
return { canvas: this.canvas, ctx: this.ctx };
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
class Render {
|
|
332
|
+
constructor(to, options) {
|
|
333
|
+
__publicField$7(this, "c");
|
|
334
|
+
__publicField$7(this, "options");
|
|
335
|
+
this.c = new Canvas(options);
|
|
336
|
+
this.options = options;
|
|
337
|
+
this.initOptions(options);
|
|
338
|
+
!options.shaow && to.appendChild(this.canvas);
|
|
339
|
+
}
|
|
340
|
+
clear(width, height) {
|
|
341
|
+
this.ctx.clearRect(0, 0, width, height);
|
|
342
|
+
}
|
|
343
|
+
get canvas() {
|
|
344
|
+
return this.c.c.canvas;
|
|
345
|
+
}
|
|
346
|
+
get ctx() {
|
|
347
|
+
return this.c.c.ctx;
|
|
348
|
+
}
|
|
349
|
+
initOptions(userOptions = {}) {
|
|
350
|
+
Object.assign(this.options, userOptions);
|
|
351
|
+
writeBoundingRectForCanvas(this.canvas, this.options.width, this.options.height, this.options.devicePixelRatio);
|
|
352
|
+
}
|
|
353
|
+
update(schedule) {
|
|
354
|
+
this.clear(this.options.width, this.options.height);
|
|
355
|
+
schedule.execute(this);
|
|
356
|
+
}
|
|
357
|
+
destory() {
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
var __defProp$6 = Object.defineProperty;
|
|
362
|
+
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
363
|
+
var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
364
|
+
class Layer extends C {
|
|
365
|
+
constructor(options = {}) {
|
|
366
|
+
super();
|
|
367
|
+
__publicField$6(this, "c");
|
|
368
|
+
__publicField$6(this, "__refresh__");
|
|
369
|
+
__publicField$6(this, "options");
|
|
370
|
+
__publicField$6(this, "width");
|
|
371
|
+
__publicField$6(this, "height");
|
|
372
|
+
__publicField$6(this, "x");
|
|
373
|
+
__publicField$6(this, "y");
|
|
374
|
+
__publicField$6(this, "scaleX");
|
|
375
|
+
__publicField$6(this, "scaleY");
|
|
376
|
+
__publicField$6(this, "rotation");
|
|
377
|
+
__publicField$6(this, "skewX");
|
|
378
|
+
__publicField$6(this, "skewY");
|
|
379
|
+
this.c = new Canvas({ width: 0, height: 0, devicePixelRatio: 1 });
|
|
380
|
+
this.__refresh__ = false;
|
|
381
|
+
this.options = /* @__PURE__ */ Object.create(null);
|
|
382
|
+
this.width = options.width || 0;
|
|
383
|
+
this.height = options.height || 0;
|
|
384
|
+
this.x = options.x || 0;
|
|
385
|
+
this.y = options.y || 0;
|
|
386
|
+
this.scaleX = options.scaleX || 1;
|
|
387
|
+
this.scaleY = options.scaleY || 1;
|
|
388
|
+
this.rotation = options.rotation || 0;
|
|
389
|
+
this.skewX = options.skewX || 0;
|
|
390
|
+
this.skewY = options.skewY || 0;
|
|
391
|
+
}
|
|
392
|
+
get __instanceOf__() {
|
|
393
|
+
return DisplayType.Layer;
|
|
394
|
+
}
|
|
395
|
+
setCanvasOptions(options = {}) {
|
|
396
|
+
Object.assign(this.options, options);
|
|
397
|
+
writeBoundingRectForCanvas(this.c.c.canvas, options.width || 0, options.height || 0, options.devicePixelRatio || 1);
|
|
398
|
+
}
|
|
399
|
+
setCacheSnapshot(c) {
|
|
400
|
+
const dpr = this.options.devicePixelRatio || 1;
|
|
401
|
+
const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
|
|
402
|
+
this.ctx.clearRect(0, 0, this.options.width, this.options.height);
|
|
403
|
+
matrix.transform(this.x, this.y, this.scaleX, this.scaleY, this.rotation, this.skewX, this.skewY);
|
|
404
|
+
applyCanvasTransform(this.ctx, matrix, dpr);
|
|
405
|
+
this.ctx.drawImage(c, 0, 0, this.options.width / dpr, this.options.height / dpr);
|
|
406
|
+
this.__refresh__ = true;
|
|
407
|
+
}
|
|
408
|
+
initLoc(options = {}) {
|
|
409
|
+
this.x = options.x || 0;
|
|
410
|
+
this.y = options.y || 0;
|
|
411
|
+
this.scaleX = options.scaleX || 1;
|
|
412
|
+
this.scaleY = options.scaleY || 1;
|
|
413
|
+
this.rotation = options.rotation || 0;
|
|
414
|
+
this.skewX = options.skewX || 0;
|
|
415
|
+
this.skewY = options.skewY || 0;
|
|
416
|
+
}
|
|
417
|
+
draw(ctx) {
|
|
418
|
+
const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
|
|
419
|
+
matrix.transform(this.x, this.y, this.scaleX, this.scaleY, this.rotation, this.skewX, this.skewY);
|
|
420
|
+
applyCanvasTransform(ctx, matrix, this.options.devicePixelRatio || 1);
|
|
421
|
+
ctx.drawImage(this.canvas, 0, 0);
|
|
422
|
+
}
|
|
423
|
+
get canvas() {
|
|
424
|
+
return this.c.c.canvas;
|
|
425
|
+
}
|
|
426
|
+
get ctx() {
|
|
427
|
+
return this.c.c.ctx;
|
|
428
|
+
}
|
|
263
429
|
}
|
|
264
430
|
|
|
265
|
-
// Runtime is designed for graph element
|
|
266
431
|
function decodeHLS(meta) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
432
|
+
const { h, l, s, a } = meta;
|
|
433
|
+
if ("a" in meta) {
|
|
434
|
+
return `hsla(${h}deg, ${s}%, ${l}%, ${a})`;
|
|
435
|
+
}
|
|
436
|
+
return `hsl(${h}deg, ${s}%, ${l}%)`;
|
|
272
437
|
}
|
|
273
438
|
function decodeRGB(meta) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
439
|
+
const { r, g, b, a } = meta;
|
|
440
|
+
if ("a" in meta) {
|
|
441
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
442
|
+
}
|
|
443
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
279
444
|
}
|
|
280
445
|
function decodeColor(meta) {
|
|
281
|
-
|
|
446
|
+
return meta.mode === "rgb" ? decodeRGB(meta.desc) : decodeHLS(meta.desc);
|
|
282
447
|
}
|
|
283
448
|
function evaluateFillStyle(primitive, opacity = 1) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
desc: {
|
|
287
|
-
...primitive.desc,
|
|
288
|
-
a: opacity
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
return decodeColor(descibe);
|
|
449
|
+
const descibe = { mode: primitive.mode, desc: { ...primitive.desc, a: opacity } };
|
|
450
|
+
return decodeColor(descibe);
|
|
292
451
|
}
|
|
293
452
|
const runtime = {
|
|
294
|
-
|
|
453
|
+
evaluateFillStyle
|
|
295
454
|
};
|
|
296
455
|
|
|
456
|
+
var __defProp$5 = Object.defineProperty;
|
|
457
|
+
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
458
|
+
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, key + "" , value);
|
|
297
459
|
class Rect extends Graph {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
460
|
+
constructor(options = {}) {
|
|
461
|
+
super(options);
|
|
462
|
+
__publicField$5(this, "style");
|
|
463
|
+
this.style = options.style || /* @__PURE__ */ Object.create(null);
|
|
464
|
+
}
|
|
465
|
+
get __shape__() {
|
|
466
|
+
return DisplayType.Rect;
|
|
467
|
+
}
|
|
468
|
+
create() {
|
|
469
|
+
if (this.style.fill) {
|
|
470
|
+
this.instruction.fillStyle(runtime.evaluateFillStyle(this.style.fill, this.style.opacity));
|
|
471
|
+
this.instruction.fillRect(0, 0, this.width, this.height);
|
|
472
|
+
}
|
|
473
|
+
if (this.style.stroke) {
|
|
474
|
+
this.instruction.strokeStyle(this.style.stroke);
|
|
475
|
+
if (typeof this.style.lineWidth === "number") {
|
|
476
|
+
this.instruction.lineWidth(this.style.lineWidth);
|
|
477
|
+
}
|
|
478
|
+
this.instruction.strokeRect(0, 0, this.width, this.height);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
clone() {
|
|
482
|
+
return new Rect({ ...this.style, ...this.__options__ });
|
|
483
|
+
}
|
|
316
484
|
}
|
|
317
485
|
|
|
486
|
+
var __defProp$4 = Object.defineProperty;
|
|
487
|
+
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
488
|
+
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
318
489
|
class Text extends Graph {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
490
|
+
constructor(options = {}) {
|
|
491
|
+
super(options);
|
|
492
|
+
__publicField$4(this, "text");
|
|
493
|
+
__publicField$4(this, "style");
|
|
494
|
+
this.text = options.text || "";
|
|
495
|
+
this.style = options.style || /* @__PURE__ */ Object.create(null);
|
|
496
|
+
}
|
|
497
|
+
create() {
|
|
498
|
+
if (this.style.fill) {
|
|
499
|
+
this.instruction.font(this.style.font);
|
|
500
|
+
this.instruction.lineWidth(this.style.lineWidth);
|
|
501
|
+
this.instruction.textBaseline(this.style.baseline);
|
|
502
|
+
this.instruction.fillStyle(this.style.fill);
|
|
503
|
+
this.instruction.fillText(this.text, 0, 0);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
clone() {
|
|
507
|
+
return new Text({ ...this.style, ...this.__options__ });
|
|
508
|
+
}
|
|
509
|
+
get __shape__() {
|
|
510
|
+
return DisplayType.Text;
|
|
511
|
+
}
|
|
335
512
|
}
|
|
336
513
|
|
|
514
|
+
var __defProp$3 = Object.defineProperty;
|
|
515
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
516
|
+
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, key + "" , value);
|
|
337
517
|
class Event {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
518
|
+
constructor() {
|
|
519
|
+
__publicField$3(this, "eventCollections");
|
|
520
|
+
this.eventCollections = /* @__PURE__ */ Object.create(null);
|
|
521
|
+
}
|
|
522
|
+
on(evt, handler, c) {
|
|
523
|
+
if (!(evt in this.eventCollections)) {
|
|
524
|
+
this.eventCollections[evt] = [];
|
|
525
|
+
}
|
|
526
|
+
const data = {
|
|
527
|
+
name: evt,
|
|
528
|
+
handler,
|
|
529
|
+
ctx: c || this
|
|
530
|
+
};
|
|
531
|
+
this.eventCollections[evt].push(data);
|
|
532
|
+
}
|
|
533
|
+
off(evt, handler) {
|
|
534
|
+
if (evt in this.eventCollections) {
|
|
535
|
+
if (!handler) {
|
|
536
|
+
this.eventCollections[evt] = [];
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
this.eventCollections[evt] = this.eventCollections[evt].filter((d) => d.handler !== handler);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
emit(evt, ...args) {
|
|
543
|
+
if (!this.eventCollections[evt]) return;
|
|
544
|
+
const handlers = this.eventCollections[evt];
|
|
545
|
+
if (handlers.length) {
|
|
546
|
+
handlers.forEach((d) => {
|
|
547
|
+
d.handler.call(d.ctx, ...args);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
bindWithContext(c) {
|
|
552
|
+
return (evt, handler) => this.on(evt, handler, c);
|
|
553
|
+
}
|
|
374
554
|
}
|
|
375
555
|
|
|
376
|
-
const NAME_SPACE =
|
|
556
|
+
const NAME_SPACE = "etoile";
|
|
377
557
|
const log = {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
558
|
+
error: (message) => {
|
|
559
|
+
return `[${NAME_SPACE}] ${message}`;
|
|
560
|
+
}
|
|
381
561
|
};
|
|
382
562
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
563
|
+
var __defProp$2 = Object.defineProperty;
|
|
564
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
565
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
566
|
+
function drawGraphIntoCanvas(graph, opts, callback) {
|
|
567
|
+
const { ctx, dpr } = opts;
|
|
568
|
+
ctx.save();
|
|
569
|
+
if (asserts.isLayer(graph) && graph.__refresh__) {
|
|
570
|
+
callback(opts, graph);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (asserts.isLayer(graph) || asserts.isBox(graph)) {
|
|
574
|
+
const elements = graph.elements;
|
|
575
|
+
const cap = elements.length;
|
|
576
|
+
for (let i = 0; i < cap; i++) {
|
|
577
|
+
const element = elements[i];
|
|
578
|
+
drawGraphIntoCanvas(element, opts, callback);
|
|
579
|
+
}
|
|
580
|
+
callback(opts, graph);
|
|
581
|
+
}
|
|
582
|
+
if (asserts.isGraph(graph)) {
|
|
583
|
+
const matrix = graph.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
|
|
584
|
+
matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
|
|
585
|
+
applyCanvasTransform(ctx, matrix, dpr);
|
|
586
|
+
graph.render(ctx);
|
|
587
|
+
}
|
|
588
|
+
ctx.restore();
|
|
409
589
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
a: 1,
|
|
439
|
-
b: 0,
|
|
440
|
-
c: 0,
|
|
441
|
-
d: 1,
|
|
442
|
-
e: 0,
|
|
443
|
-
f: 0
|
|
444
|
-
});
|
|
445
|
-
this.applyTransform(matrix);
|
|
446
|
-
}
|
|
447
|
-
// execute all graph elements
|
|
448
|
-
execute(render, graph = this) {
|
|
449
|
-
render.ctx.save();
|
|
450
|
-
let matrix = graph.matrix;
|
|
451
|
-
this.applyTransform(matrix);
|
|
452
|
-
if (graph instanceof Box) {
|
|
453
|
-
const cap = graph.elements.length;
|
|
454
|
-
for(let i = 0; i < cap; i++){
|
|
455
|
-
const element = graph.elements[i];
|
|
456
|
-
matrix = element.matrix.create({
|
|
457
|
-
a: 1,
|
|
458
|
-
b: 0,
|
|
459
|
-
c: 0,
|
|
460
|
-
d: 1,
|
|
461
|
-
e: 0,
|
|
462
|
-
f: 0
|
|
463
|
-
});
|
|
464
|
-
if (element instanceof Graph) {
|
|
465
|
-
matrix.transform(element.x, element.y, element.scaleX, element.scaleY, element.rotation, element.skewX, element.skewY);
|
|
466
|
-
}
|
|
467
|
-
this.execute(render, element);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
if (graph instanceof Graph) {
|
|
471
|
-
graph.render(render.ctx);
|
|
590
|
+
class Schedule extends Box {
|
|
591
|
+
constructor(to, renderOptions = {}) {
|
|
592
|
+
super();
|
|
593
|
+
__publicField$2(this, "render");
|
|
594
|
+
__publicField$2(this, "to");
|
|
595
|
+
__publicField$2(this, "event");
|
|
596
|
+
this.to = typeof to === "string" ? document.querySelector(to) : to;
|
|
597
|
+
if (!this.to) {
|
|
598
|
+
throw new Error(log.error("The element to bind is not found."));
|
|
599
|
+
}
|
|
600
|
+
const { width, height } = this.to.getBoundingClientRect();
|
|
601
|
+
Object.assign(renderOptions, { width, height }, { devicePixelRatio: window.devicePixelRatio || 1 });
|
|
602
|
+
this.event = new Event();
|
|
603
|
+
this.render = new Render(this.to, renderOptions);
|
|
604
|
+
}
|
|
605
|
+
update() {
|
|
606
|
+
this.render.update(this);
|
|
607
|
+
const matrix = this.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
|
|
608
|
+
applyCanvasTransform(this.render.ctx, matrix, this.render.options.devicePixelRatio);
|
|
609
|
+
}
|
|
610
|
+
// execute all graph elements
|
|
611
|
+
execute(render, graph = this) {
|
|
612
|
+
drawGraphIntoCanvas(graph, { c: render.canvas, ctx: render.ctx, dpr: render.options.devicePixelRatio }, (opts, graph2) => {
|
|
613
|
+
if (asserts.isLayer(graph2)) {
|
|
614
|
+
if (graph2.__refresh__) {
|
|
615
|
+
graph2.draw(opts.ctx);
|
|
616
|
+
} else {
|
|
617
|
+
graph2.setCacheSnapshot(opts.c);
|
|
472
618
|
}
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
}
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}
|
|
476
623
|
|
|
477
624
|
function traverse(graphs, handler) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
625
|
+
const len = graphs.length;
|
|
626
|
+
for (let i = 0; i < len; i++) {
|
|
627
|
+
const graph = graphs[i];
|
|
628
|
+
if (asserts.isLayer(graph) && graph.__refresh__) {
|
|
629
|
+
handler(graph);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
if (asserts.isGraph(graph)) {
|
|
633
|
+
handler(graph);
|
|
634
|
+
} else if (asserts.isBox(graph) || asserts.isLayer(graph)) {
|
|
635
|
+
traverse(graph.elements, handler);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
485
638
|
}
|
|
486
639
|
const etoile = {
|
|
487
|
-
|
|
488
|
-
|
|
640
|
+
Schedule,
|
|
641
|
+
traverse
|
|
489
642
|
};
|
|
490
643
|
|
|
491
|
-
// Currently, etoile is an internal module, so we won't need too much easing functions.
|
|
492
|
-
// And the animation logic is implemented by user code.
|
|
493
644
|
const easing = {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
645
|
+
linear: (k) => k,
|
|
646
|
+
quadraticIn: (k) => k * k,
|
|
647
|
+
quadraticOut: (k) => k * (2 - k),
|
|
648
|
+
quadraticInOut: (k) => {
|
|
649
|
+
if ((k *= 2) < 1) {
|
|
650
|
+
return 0.5 * k * k;
|
|
651
|
+
}
|
|
652
|
+
return -0.5 * (--k * (k - 2) - 1);
|
|
653
|
+
},
|
|
654
|
+
cubicIn: (k) => k * k * k,
|
|
655
|
+
cubicOut: (k) => {
|
|
656
|
+
if ((k *= 2) < 1) {
|
|
657
|
+
return 0.5 * k * k * k;
|
|
658
|
+
}
|
|
659
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
660
|
+
},
|
|
661
|
+
cubicInOut: (k) => {
|
|
662
|
+
if ((k *= 2) < 1) {
|
|
663
|
+
return 0.5 * k * k * k;
|
|
664
|
+
}
|
|
665
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
666
|
+
}
|
|
516
667
|
};
|
|
517
668
|
|
|
518
|
-
function
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
669
|
+
function hashCode(str) {
|
|
670
|
+
let hash = 0;
|
|
671
|
+
for (let i = 0; i < str.length; i++) {
|
|
672
|
+
const code = str.charCodeAt(i);
|
|
673
|
+
hash = (hash << 5) - hash + code;
|
|
674
|
+
hash = hash & hash;
|
|
675
|
+
}
|
|
676
|
+
return hash;
|
|
677
|
+
}
|
|
678
|
+
function perferNumeric(s) {
|
|
679
|
+
if (typeof s === "number") return true;
|
|
680
|
+
return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
|
|
681
|
+
}
|
|
682
|
+
function createFillBlock(x, y, width, height, style) {
|
|
683
|
+
return new Rect({ width, height, x, y, style });
|
|
684
|
+
}
|
|
685
|
+
function createTitleText(text, x, y, font, color) {
|
|
686
|
+
return new Text({
|
|
687
|
+
text,
|
|
688
|
+
x,
|
|
689
|
+
y,
|
|
690
|
+
style: { fill: color, textAlign: "center", baseline: "middle", font, lineWidth: 1 }
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const raf = window.requestAnimationFrame;
|
|
694
|
+
function createCanvasElement() {
|
|
695
|
+
return document.createElement("canvas");
|
|
696
|
+
}
|
|
697
|
+
function applyCanvasTransform(ctx, matrix, dpr) {
|
|
698
|
+
ctx.setTransform(matrix.a * dpr, matrix.b * dpr, matrix.c * dpr, matrix.d * dpr, matrix.e * dpr, matrix.f * dpr);
|
|
699
|
+
}
|
|
700
|
+
function mixin(app, methods) {
|
|
701
|
+
methods.forEach(({ name, fn }) => {
|
|
702
|
+
Object.defineProperty(app, name, {
|
|
703
|
+
value: fn(app),
|
|
704
|
+
writable: false
|
|
533
705
|
});
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function sortChildrenByKey(data, ...keys) {
|
|
710
|
+
return data.sort((a, b) => {
|
|
711
|
+
for (const key of keys) {
|
|
712
|
+
const v = a[key];
|
|
713
|
+
const v2 = b[key];
|
|
714
|
+
if (perferNumeric(v) && perferNumeric(v2)) {
|
|
715
|
+
if (v2 > v) return 1;
|
|
716
|
+
if (v2 < v) return -1;
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
const comparison = ("" + v).localeCompare("" + v2);
|
|
720
|
+
if (comparison !== 0) return comparison;
|
|
721
|
+
}
|
|
722
|
+
return 0;
|
|
723
|
+
});
|
|
534
724
|
}
|
|
535
725
|
function c2m(data, key, modifier) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
};
|
|
543
|
-
if (modifier) return modifier(obj);
|
|
544
|
-
return obj;
|
|
726
|
+
if (Array.isArray(data.groups)) {
|
|
727
|
+
data.groups = sortChildrenByKey(data.groups.map((d) => c2m(d, key, modifier)), "weight");
|
|
728
|
+
}
|
|
729
|
+
const obj = { ...data, weight: data[key] };
|
|
730
|
+
if (modifier) return modifier(obj);
|
|
731
|
+
return obj;
|
|
545
732
|
}
|
|
546
733
|
function flatten(data) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
734
|
+
const result = [];
|
|
735
|
+
for (let i = 0; i < data.length; i++) {
|
|
736
|
+
const { groups, ...rest } = data[i];
|
|
737
|
+
result.push(rest);
|
|
738
|
+
if (groups) {
|
|
739
|
+
result.push(...flatten(groups));
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return result;
|
|
556
743
|
}
|
|
557
744
|
function bindParentForModule(modules, parent) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
return next;
|
|
567
|
-
});
|
|
745
|
+
return modules.map((module) => {
|
|
746
|
+
const next = { ...module };
|
|
747
|
+
next.parent = parent;
|
|
748
|
+
if (next.groups && Array.isArray(next.groups)) {
|
|
749
|
+
next.groups = bindParentForModule(next.groups, next);
|
|
750
|
+
}
|
|
751
|
+
return next;
|
|
752
|
+
});
|
|
568
753
|
}
|
|
569
754
|
function getNodeDepth(node) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
755
|
+
let depth = 0;
|
|
756
|
+
while (node.parent) {
|
|
757
|
+
node = node.parent;
|
|
758
|
+
depth++;
|
|
759
|
+
}
|
|
760
|
+
return depth;
|
|
576
761
|
}
|
|
577
762
|
function visit(data, fn) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
763
|
+
if (!data) return null;
|
|
764
|
+
for (const d of data) {
|
|
765
|
+
if (d.children) {
|
|
766
|
+
const result = visit(d.children, fn);
|
|
767
|
+
if (result) return result;
|
|
768
|
+
}
|
|
769
|
+
const stop = fn(d);
|
|
770
|
+
if (stop) return d;
|
|
771
|
+
}
|
|
772
|
+
return null;
|
|
588
773
|
}
|
|
589
774
|
function findRelativeNode(c, p, layoutNodes) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
775
|
+
return visit(layoutNodes, (node) => {
|
|
776
|
+
const [x, y, w, h] = node.layout;
|
|
777
|
+
if (p.x >= x && p.y >= y && p.x < x + w && p.y < y + h) {
|
|
778
|
+
return true;
|
|
779
|
+
}
|
|
780
|
+
});
|
|
596
781
|
}
|
|
597
782
|
function findRelativeNodeById(id, layoutNodes) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
783
|
+
return visit(layoutNodes, (node) => {
|
|
784
|
+
if (node.node.id === id) {
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
787
|
+
});
|
|
603
788
|
}
|
|
604
789
|
|
|
605
790
|
function squarify(data, rect, layoutDecorator) {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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
|
-
start = end;
|
|
677
|
-
if (rect.w >= rect.h) {
|
|
678
|
-
rect.x += splited;
|
|
679
|
-
rect.w -= splited;
|
|
680
|
-
} else {
|
|
681
|
-
rect.y += splited;
|
|
682
|
-
rect.h -= splited;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
};
|
|
686
|
-
recursion(0, rect);
|
|
687
|
-
return result;
|
|
791
|
+
const result = [];
|
|
792
|
+
if (!data.length) return result;
|
|
793
|
+
const worst = (start, end, shortestSide, totalWeight, aspectRatio) => {
|
|
794
|
+
const max = data[start].weight * aspectRatio;
|
|
795
|
+
const min = data[end].weight * aspectRatio;
|
|
796
|
+
return Math.max(
|
|
797
|
+
shortestSide * shortestSide * max / (totalWeight * totalWeight),
|
|
798
|
+
totalWeight * totalWeight / (shortestSide * shortestSide * min)
|
|
799
|
+
);
|
|
800
|
+
};
|
|
801
|
+
const recursion = (start, rect2) => {
|
|
802
|
+
while (start < data.length) {
|
|
803
|
+
let totalWeight = 0;
|
|
804
|
+
for (let i = start; i < data.length; i++) {
|
|
805
|
+
totalWeight += data[i].weight;
|
|
806
|
+
}
|
|
807
|
+
const shortestSide = Math.min(rect2.w, rect2.h);
|
|
808
|
+
const aspectRatio = rect2.w * rect2.h / totalWeight;
|
|
809
|
+
let end = start;
|
|
810
|
+
let areaInRun = 0;
|
|
811
|
+
let oldWorst = 0;
|
|
812
|
+
while (end < data.length) {
|
|
813
|
+
const area = data[end].weight * aspectRatio;
|
|
814
|
+
const newWorst = worst(start, end, shortestSide, areaInRun + area, aspectRatio);
|
|
815
|
+
if (end > start && oldWorst < newWorst) break;
|
|
816
|
+
areaInRun += area;
|
|
817
|
+
oldWorst = newWorst;
|
|
818
|
+
end++;
|
|
819
|
+
}
|
|
820
|
+
const splited = Math.round(areaInRun / shortestSide);
|
|
821
|
+
let areaInLayout = 0;
|
|
822
|
+
for (let i = start; i < end; i++) {
|
|
823
|
+
const children = data[i];
|
|
824
|
+
const area = children.weight * aspectRatio;
|
|
825
|
+
const lower = Math.round(shortestSide * areaInLayout / areaInRun);
|
|
826
|
+
const upper = Math.round(shortestSide * (areaInLayout + area) / areaInRun);
|
|
827
|
+
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];
|
|
828
|
+
const depth = getNodeDepth(children) || 1;
|
|
829
|
+
const { titleAreaHeight, rectGap } = layoutDecorator;
|
|
830
|
+
const diff = titleAreaHeight.max / depth;
|
|
831
|
+
const hh = diff < titleAreaHeight.min ? titleAreaHeight.min : diff;
|
|
832
|
+
result.push({
|
|
833
|
+
layout: [x, y, w, h],
|
|
834
|
+
node: children,
|
|
835
|
+
decorator: {
|
|
836
|
+
...layoutDecorator,
|
|
837
|
+
titleHeight: hh
|
|
838
|
+
},
|
|
839
|
+
children: w > rectGap * 2 && h > hh + rectGap ? squarify(children.groups || [], {
|
|
840
|
+
x: x + rectGap,
|
|
841
|
+
y: y + hh,
|
|
842
|
+
w: w - rectGap * 2,
|
|
843
|
+
h: h - hh - rectGap
|
|
844
|
+
}, layoutDecorator) : []
|
|
845
|
+
});
|
|
846
|
+
areaInLayout += area;
|
|
847
|
+
}
|
|
848
|
+
start = end;
|
|
849
|
+
if (rect2.w >= rect2.h) {
|
|
850
|
+
rect2.x += splited;
|
|
851
|
+
rect2.w -= splited;
|
|
852
|
+
} else {
|
|
853
|
+
rect2.y += splited;
|
|
854
|
+
rect2.h -= splited;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
recursion(0, rect);
|
|
859
|
+
return result;
|
|
688
860
|
}
|
|
689
861
|
|
|
690
862
|
function applyForOpacity(graph, lastState, nextState, easedProgress) {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
863
|
+
const alpha = lastState + (nextState - lastState) * easedProgress;
|
|
864
|
+
if (asserts.isRect(graph)) {
|
|
865
|
+
graph.style.opacity = alpha;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function createEffectRun(c) {
|
|
869
|
+
return (fn) => {
|
|
870
|
+
const effect = () => {
|
|
871
|
+
const done = fn();
|
|
872
|
+
if (!done) {
|
|
873
|
+
c.animationFrameID = raf(effect);
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
if (!c.animationFrameID) {
|
|
877
|
+
c.animationFrameID = raf(effect);
|
|
694
878
|
}
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function createEffectStop(c) {
|
|
882
|
+
return () => {
|
|
883
|
+
if (c.animationFrameID) {
|
|
884
|
+
window.cancelAnimationFrame(c.animationFrameID);
|
|
885
|
+
c.animationFrameID = null;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function createEffectScope() {
|
|
890
|
+
const c = {
|
|
891
|
+
animationFrameID: null
|
|
892
|
+
};
|
|
893
|
+
const run = createEffectRun(c);
|
|
894
|
+
const stop = createEffectStop(c);
|
|
895
|
+
return { run, stop };
|
|
695
896
|
}
|
|
696
897
|
|
|
697
898
|
class RegisterModule {
|
|
698
|
-
static mixin(app, methods) {
|
|
699
|
-
methods.forEach(({ name, fn })=>{
|
|
700
|
-
Object.defineProperty(app, name, {
|
|
701
|
-
value: fn(app),
|
|
702
|
-
writable: false
|
|
703
|
-
});
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
899
|
}
|
|
707
900
|
function registerModuleForSchedule(mod) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
901
|
+
if (mod instanceof RegisterModule) {
|
|
902
|
+
return (app, treemap, render) => mod.init(app, treemap, render);
|
|
903
|
+
}
|
|
904
|
+
throw new Error(log.error("The module is not a valid RegisterScheduleModule."));
|
|
712
905
|
}
|
|
713
906
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
const
|
|
719
|
-
'click',
|
|
720
|
-
'mousedown',
|
|
721
|
-
'mousemove',
|
|
722
|
-
'mouseup',
|
|
723
|
-
'mouseover',
|
|
724
|
-
'mouseout'
|
|
725
|
-
];
|
|
907
|
+
var __defProp$1 = Object.defineProperty;
|
|
908
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
909
|
+
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
910
|
+
const primitiveEvents = ["click", "mousedown", "mousemove", "mouseup", "mouseover", "mouseout"];
|
|
911
|
+
const fill = { desc: { r: 255, g: 255, b: 255 }, mode: "rgb" };
|
|
726
912
|
function smoothDrawing(c) {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
if (lloc.has(key)) {
|
|
757
|
-
applyForOpacity(graph, 1, 0.7, easedProgress);
|
|
758
|
-
if (progress < 1) {
|
|
759
|
-
allTasksCompleted = false;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
});
|
|
763
|
-
applyGraphTransform(treemap.elements, self.translateX, self.translateY, self.scaleRatio);
|
|
764
|
-
treemap.update();
|
|
765
|
-
if (!allTasksCompleted) {
|
|
766
|
-
window.requestAnimationFrame(draw);
|
|
767
|
-
}
|
|
768
|
-
};
|
|
769
|
-
if (!self.isAnimating) {
|
|
770
|
-
self.isAnimating = true;
|
|
771
|
-
window.requestAnimationFrame(draw);
|
|
772
|
-
}
|
|
773
|
-
} else {
|
|
774
|
-
treemap.reset();
|
|
775
|
-
applyGraphTransform(treemap.elements, self.translateX, self.translateY, self.scaleRatio);
|
|
776
|
-
treemap.update();
|
|
777
|
-
}
|
|
913
|
+
const { self } = c;
|
|
914
|
+
const currentNode = self.currentNode;
|
|
915
|
+
if (currentNode) {
|
|
916
|
+
const effect = createEffectScope();
|
|
917
|
+
const startTime = Date.now();
|
|
918
|
+
const animationDuration = 300;
|
|
919
|
+
const [x, y, w, h] = currentNode.layout;
|
|
920
|
+
effect.run(() => {
|
|
921
|
+
const elapsed = Date.now() - startTime;
|
|
922
|
+
const progress = Math.min(elapsed / animationDuration, 1);
|
|
923
|
+
if (self.forceDestroy || progress >= 1) {
|
|
924
|
+
effect.stop();
|
|
925
|
+
self.highlight.reset();
|
|
926
|
+
self.highlight.setDisplayLayerForHighlight();
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
const easedProgress = easing.cubicInOut(progress);
|
|
930
|
+
self.highlight.reset();
|
|
931
|
+
const mask = createFillBlock(x, y, w, h, { fill, opacity: 0.4 });
|
|
932
|
+
self.highlight.highlight.add(mask);
|
|
933
|
+
self.highlight.setDisplayLayerForHighlight("1");
|
|
934
|
+
applyForOpacity(mask, 0.4, 0.4, easedProgress);
|
|
935
|
+
stackMatrixTransform(mask, self.translateX, self.translateY, self.scaleRatio);
|
|
936
|
+
self.highlight.highlight.update();
|
|
937
|
+
});
|
|
938
|
+
} else {
|
|
939
|
+
self.highlight.reset();
|
|
940
|
+
self.highlight.setDisplayLayerForHighlight();
|
|
941
|
+
}
|
|
778
942
|
}
|
|
779
943
|
function applyZoomEvent(ctx) {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
944
|
+
ctx.treemap.event.on("zoom", (node) => {
|
|
945
|
+
const root = null;
|
|
946
|
+
if (ctx.self.isDragging) return;
|
|
947
|
+
onZoom(ctx, node, root);
|
|
948
|
+
});
|
|
785
949
|
}
|
|
786
950
|
function getOffset(el) {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
951
|
+
let e = 0;
|
|
952
|
+
let f = 0;
|
|
953
|
+
if (document.documentElement.getBoundingClientRect && el.getBoundingClientRect) {
|
|
954
|
+
const { top, left } = el.getBoundingClientRect();
|
|
955
|
+
e = top;
|
|
956
|
+
f = left;
|
|
957
|
+
} else {
|
|
958
|
+
for (let elt = el; elt; elt = el.offsetParent) {
|
|
959
|
+
e += el.offsetLeft;
|
|
960
|
+
f += el.offsetTop;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return [
|
|
964
|
+
e + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft),
|
|
965
|
+
f + Math.max(document.documentElement.scrollTop, document.body.scrollTop)
|
|
966
|
+
];
|
|
803
967
|
}
|
|
804
968
|
function captureBoxXY(c, evt, a, d, translateX, translateY) {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
return {
|
|
809
|
-
x: (evt.clientX - boundingClientRect.left - e - translateX) / a,
|
|
810
|
-
y: (evt.clientY - boundingClientRect.top - f - translateY) / d
|
|
811
|
-
};
|
|
812
|
-
}
|
|
969
|
+
const boundingClientRect = c.getBoundingClientRect();
|
|
970
|
+
if (evt instanceof MouseEvent) {
|
|
971
|
+
const [e, f] = getOffset(c);
|
|
813
972
|
return {
|
|
814
|
-
|
|
815
|
-
|
|
973
|
+
x: (evt.clientX - boundingClientRect.left - e - translateX) / a,
|
|
974
|
+
y: (evt.clientY - boundingClientRect.top - f - translateY) / d
|
|
816
975
|
};
|
|
976
|
+
}
|
|
977
|
+
return { x: 0, y: 0 };
|
|
817
978
|
}
|
|
818
|
-
function bindPrimitiveEvent(ctx, evt, bus) {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
979
|
+
function bindPrimitiveEvent(c, ctx, evt, bus) {
|
|
980
|
+
const { treemap, self } = ctx;
|
|
981
|
+
const handler = (e) => {
|
|
982
|
+
const { x, y } = captureBoxXY(
|
|
983
|
+
c,
|
|
984
|
+
e,
|
|
985
|
+
self.scaleRatio,
|
|
986
|
+
self.scaleRatio,
|
|
987
|
+
self.translateX,
|
|
988
|
+
self.translateY
|
|
989
|
+
);
|
|
990
|
+
const event = {
|
|
991
|
+
native: e,
|
|
992
|
+
module: findRelativeNode(c, { x, y }, treemap.layoutNodes)
|
|
832
993
|
};
|
|
833
|
-
|
|
834
|
-
|
|
994
|
+
bus.emit(evt, event);
|
|
995
|
+
};
|
|
996
|
+
c.addEventListener(evt, handler);
|
|
997
|
+
return handler;
|
|
835
998
|
}
|
|
836
999
|
class SelfEvent extends RegisterModule {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
if (!
|
|
880
|
-
|
|
881
|
-
const condit = this.treemap.event.eventCollections.zoom.length > 0;
|
|
882
|
-
if (!condit) {
|
|
883
|
-
applyZoomEvent(this);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
return;
|
|
887
|
-
}
|
|
888
|
-
// @ts-expect-error
|
|
889
|
-
this.self.event.off('mousemove', this.self.onmousemove);
|
|
890
|
-
this.treemap.event.off('zoom');
|
|
891
|
-
this.self.forceDestroy = true;
|
|
892
|
-
const { native } = metadata;
|
|
893
|
-
const x = native.offsetX;
|
|
894
|
-
const y = native.offsetY;
|
|
895
|
-
const { x: lastX, y: lastY } = this.self.draggingState;
|
|
896
|
-
const drawX = x - lastX;
|
|
897
|
-
const drawY = y - lastY;
|
|
898
|
-
this.self.translateX += drawX;
|
|
899
|
-
this.self.translateY += drawY;
|
|
900
|
-
this.self.draggingState = {
|
|
901
|
-
x,
|
|
902
|
-
y
|
|
903
|
-
};
|
|
904
|
-
this.treemap.reset();
|
|
905
|
-
applyGraphTransform(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
|
|
906
|
-
this.treemap.update();
|
|
907
|
-
}
|
|
908
|
-
ondragend(metadata) {
|
|
909
|
-
if (!this.self.isDragging) {
|
|
910
|
-
return;
|
|
911
|
-
}
|
|
912
|
-
this.self.isDragging = false;
|
|
913
|
-
this.self.draggingState = {
|
|
914
|
-
x: 0,
|
|
915
|
-
y: 0
|
|
916
|
-
};
|
|
917
|
-
this.self.event.bindWithContext(this)('mousemove', this.self.onmousemove);
|
|
918
|
-
}
|
|
919
|
-
onmousemove(metadata) {
|
|
920
|
-
const { self } = this;
|
|
921
|
-
if (self.isDragging) {
|
|
922
|
-
return;
|
|
1000
|
+
constructor() {
|
|
1001
|
+
super();
|
|
1002
|
+
__publicField$1(this, "currentNode");
|
|
1003
|
+
__publicField$1(this, "forceDestroy");
|
|
1004
|
+
__publicField$1(this, "scaleRatio");
|
|
1005
|
+
__publicField$1(this, "translateX");
|
|
1006
|
+
__publicField$1(this, "translateY");
|
|
1007
|
+
__publicField$1(this, "layoutWidth");
|
|
1008
|
+
__publicField$1(this, "layoutHeight");
|
|
1009
|
+
__publicField$1(this, "isDragging");
|
|
1010
|
+
__publicField$1(this, "draggingState");
|
|
1011
|
+
__publicField$1(this, "event");
|
|
1012
|
+
__publicField$1(this, "triggerZoom");
|
|
1013
|
+
// eslint-disable-next-line no-use-before-define
|
|
1014
|
+
__publicField$1(this, "highlight");
|
|
1015
|
+
this.currentNode = null;
|
|
1016
|
+
this.forceDestroy = false;
|
|
1017
|
+
this.isDragging = false;
|
|
1018
|
+
this.scaleRatio = 1;
|
|
1019
|
+
this.translateX = 0;
|
|
1020
|
+
this.translateY = 0;
|
|
1021
|
+
this.layoutWidth = 0;
|
|
1022
|
+
this.layoutHeight = 0;
|
|
1023
|
+
this.draggingState = { x: 0, y: 0 };
|
|
1024
|
+
this.event = new Event();
|
|
1025
|
+
this.triggerZoom = false;
|
|
1026
|
+
this.highlight = createHighlight();
|
|
1027
|
+
}
|
|
1028
|
+
ondragstart(metadata) {
|
|
1029
|
+
const { native } = metadata;
|
|
1030
|
+
if (isScrollWheelOrRightButtonOnMouseupAndDown(native)) {
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const x = native.offsetX;
|
|
1034
|
+
const y = native.offsetY;
|
|
1035
|
+
this.self.isDragging = true;
|
|
1036
|
+
this.self.draggingState = { x, y };
|
|
1037
|
+
}
|
|
1038
|
+
ondragmove(metadata) {
|
|
1039
|
+
if (!this.self.isDragging) {
|
|
1040
|
+
if ("zoom" in this.treemap.event.eventCollections) {
|
|
1041
|
+
const condit = this.treemap.event.eventCollections.zoom.length > 0;
|
|
1042
|
+
if (!condit) {
|
|
1043
|
+
applyZoomEvent(this);
|
|
923
1044
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
selfEvents.forEach((evt)=>{
|
|
987
|
-
nativeEvents.push(bindPrimitiveEvent({
|
|
988
|
-
treemap,
|
|
989
|
-
self: this
|
|
990
|
-
}, evt, event));
|
|
991
|
-
});
|
|
992
|
-
const selfEvt = event.bindWithContext({
|
|
993
|
-
treemap,
|
|
994
|
-
self: this
|
|
995
|
-
});
|
|
996
|
-
selfEvt('mousedown', this.ondragstart);
|
|
997
|
-
selfEvt('mousemove', this.ondragmove);
|
|
998
|
-
selfEvt('mouseup', this.ondragend);
|
|
999
|
-
// highlight
|
|
1000
|
-
selfEvt('mousemove', this.onmousemove);
|
|
1001
|
-
selfEvt('mouseout', this.onmouseout);
|
|
1002
|
-
// wheel
|
|
1003
|
-
selfEvt('wheel', this.onwheel);
|
|
1004
|
-
applyZoomEvent({
|
|
1005
|
-
treemap,
|
|
1006
|
-
self: this
|
|
1007
|
-
});
|
|
1008
|
-
treemap.event.on('cleanup:selfevent', ()=>{
|
|
1009
|
-
this.currentNode = null;
|
|
1010
|
-
this.isAnimating = false;
|
|
1011
|
-
this.scaleRatio = 1;
|
|
1012
|
-
this.translateX = 0;
|
|
1013
|
-
this.translateY = 0;
|
|
1014
|
-
this.layoutWidth = treemap.render.canvas.width;
|
|
1015
|
-
this.layoutHeight = treemap.render.canvas.height;
|
|
1016
|
-
this.isDragging = false;
|
|
1017
|
-
this.draggingState = {
|
|
1018
|
-
x: 0,
|
|
1019
|
-
y: 0
|
|
1020
|
-
};
|
|
1021
|
-
});
|
|
1045
|
+
}
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
this.self.highlight.reset();
|
|
1049
|
+
this.self.highlight.setDisplayLayerForHighlight();
|
|
1050
|
+
this.self.event.off("mousemove", this.self.onmousemove);
|
|
1051
|
+
this.treemap.event.off("zoom");
|
|
1052
|
+
this.self.forceDestroy = true;
|
|
1053
|
+
const { native } = metadata;
|
|
1054
|
+
const x = native.offsetX;
|
|
1055
|
+
const y = native.offsetY;
|
|
1056
|
+
const { x: lastX, y: lastY } = this.self.draggingState;
|
|
1057
|
+
const drawX = x - lastX;
|
|
1058
|
+
const drawY = y - lastY;
|
|
1059
|
+
this.self.translateX += drawX;
|
|
1060
|
+
this.self.translateY += drawY;
|
|
1061
|
+
this.self.draggingState = { x, y };
|
|
1062
|
+
if (this.self.triggerZoom) {
|
|
1063
|
+
refreshBackgroundLayer(this);
|
|
1064
|
+
}
|
|
1065
|
+
this.treemap.reset();
|
|
1066
|
+
stackMatrixTransform(this.treemap.backgroundLayer, 0, 0, 0);
|
|
1067
|
+
stackMatrixTransformWithGraphAndLayer(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
|
|
1068
|
+
this.treemap.update();
|
|
1069
|
+
}
|
|
1070
|
+
ondragend() {
|
|
1071
|
+
if (!this.self.isDragging) {
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
this.self.isDragging = false;
|
|
1075
|
+
this.self.draggingState = { x: 0, y: 0 };
|
|
1076
|
+
this.self.highlight.reset();
|
|
1077
|
+
this.self.highlight.setDisplayLayerForHighlight();
|
|
1078
|
+
this.self.event.bindWithContext(this)("mousemove", this.self.onmousemove);
|
|
1079
|
+
}
|
|
1080
|
+
onmousemove(metadata) {
|
|
1081
|
+
const { self } = this;
|
|
1082
|
+
const { module: node } = metadata;
|
|
1083
|
+
self.forceDestroy = false;
|
|
1084
|
+
if (self.currentNode !== node) {
|
|
1085
|
+
self.currentNode = node;
|
|
1086
|
+
}
|
|
1087
|
+
smoothDrawing(this);
|
|
1088
|
+
}
|
|
1089
|
+
onmouseout() {
|
|
1090
|
+
const { self } = this;
|
|
1091
|
+
self.currentNode = null;
|
|
1092
|
+
self.forceDestroy = true;
|
|
1093
|
+
smoothDrawing(this);
|
|
1094
|
+
}
|
|
1095
|
+
onwheel(metadata) {
|
|
1096
|
+
const { self, treemap } = this;
|
|
1097
|
+
const wheelDelta = metadata.native.wheelDelta;
|
|
1098
|
+
const absWheelDelta = Math.abs(wheelDelta);
|
|
1099
|
+
const offsetX = metadata.native.offsetX;
|
|
1100
|
+
const offsetY = metadata.native.offsetY;
|
|
1101
|
+
if (wheelDelta === 0) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
self.forceDestroy = true;
|
|
1105
|
+
if (self.triggerZoom) {
|
|
1106
|
+
refreshBackgroundLayer(this);
|
|
1022
1107
|
}
|
|
1108
|
+
treemap.reset();
|
|
1109
|
+
this.self.highlight.reset();
|
|
1110
|
+
this.self.highlight.setDisplayLayerForHighlight();
|
|
1111
|
+
stackMatrixTransform(this.treemap.backgroundLayer, 0, 0, 0);
|
|
1112
|
+
const factor = absWheelDelta > 3 ? 1.4 : absWheelDelta > 1 ? 1.2 : 1.1;
|
|
1113
|
+
const delta = wheelDelta > 0 ? factor : 1 / factor;
|
|
1114
|
+
self.scaleRatio *= delta;
|
|
1115
|
+
const translateX = offsetX - (offsetX - self.translateX) * delta;
|
|
1116
|
+
const translateY = offsetY - (offsetY - self.translateY) * delta;
|
|
1117
|
+
self.translateX = translateX;
|
|
1118
|
+
self.translateY = translateY;
|
|
1119
|
+
stackMatrixTransformWithGraphAndLayer(this.treemap.elements, this.self.translateX, this.self.translateY, this.self.scaleRatio);
|
|
1120
|
+
treemap.update();
|
|
1121
|
+
self.forceDestroy = false;
|
|
1122
|
+
}
|
|
1123
|
+
init(app, treemap) {
|
|
1124
|
+
const event = this.event;
|
|
1125
|
+
const nativeEvents = [];
|
|
1126
|
+
const methods = [
|
|
1127
|
+
{
|
|
1128
|
+
name: "on",
|
|
1129
|
+
fn: () => event.bindWithContext(treemap.api).bind(event)
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "off",
|
|
1133
|
+
fn: () => event.off.bind(event)
|
|
1134
|
+
},
|
|
1135
|
+
{
|
|
1136
|
+
name: "emit",
|
|
1137
|
+
fn: () => event.emit.bind(event)
|
|
1138
|
+
}
|
|
1139
|
+
];
|
|
1140
|
+
mixin(app, methods);
|
|
1141
|
+
const selfEvents = [...primitiveEvents, "wheel"];
|
|
1142
|
+
selfEvents.forEach((evt) => {
|
|
1143
|
+
nativeEvents.push(bindPrimitiveEvent(treemap.render.canvas, { treemap, self: this }, evt, event));
|
|
1144
|
+
});
|
|
1145
|
+
const selfEvt = event.bindWithContext({ treemap, self: this });
|
|
1146
|
+
selfEvt("mousedown", this.ondragstart);
|
|
1147
|
+
selfEvt("mousemove", this.ondragmove);
|
|
1148
|
+
selfEvt("mouseup", this.ondragend);
|
|
1149
|
+
selfEvt("wheel", this.onwheel);
|
|
1150
|
+
applyZoomEvent({ treemap, self: this });
|
|
1151
|
+
let installHightlightEvent = false;
|
|
1152
|
+
treemap.event.on("onload:selfevent", ({ width, height, root }) => {
|
|
1153
|
+
this.highlight.init(width, height, root);
|
|
1154
|
+
if (!installHightlightEvent) {
|
|
1155
|
+
bindPrimitiveEvent(this.highlight.highlight.render.canvas, { treemap, self: this }, "mousemove", event);
|
|
1156
|
+
bindPrimitiveEvent(this.highlight.highlight.render.canvas, { treemap, self: this }, "mouseout", event);
|
|
1157
|
+
selfEvt("mousemove", this.onmousemove);
|
|
1158
|
+
selfEvt("mouseout", this.onmouseout);
|
|
1159
|
+
installHightlightEvent = true;
|
|
1160
|
+
this.highlight.setDisplayLayerForHighlight();
|
|
1161
|
+
}
|
|
1162
|
+
this.highlight.reset();
|
|
1163
|
+
});
|
|
1164
|
+
treemap.event.on("cleanup:selfevent", () => {
|
|
1165
|
+
this.currentNode = null;
|
|
1166
|
+
this.scaleRatio = 1;
|
|
1167
|
+
this.translateX = 0;
|
|
1168
|
+
this.translateY = 0;
|
|
1169
|
+
this.layoutWidth = treemap.render.canvas.width;
|
|
1170
|
+
this.layoutHeight = treemap.render.canvas.height;
|
|
1171
|
+
this.isDragging = false;
|
|
1172
|
+
this.triggerZoom = false;
|
|
1173
|
+
this.draggingState = { x: 0, y: 0 };
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1023
1176
|
}
|
|
1024
1177
|
function estimateZoomingArea(node, root, w, h) {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
let
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
const maxScaleFactor = 2.5;
|
|
1048
|
-
const minScaleFactor = 0.3;
|
|
1049
|
-
const scaleFactor = Math.max(minScaleFactor, Math.min(maxScaleFactor, Math.sqrt(area / viewArea)));
|
|
1050
|
-
return [
|
|
1051
|
-
w * scaleFactor,
|
|
1052
|
-
h * scaleFactor
|
|
1053
|
-
];
|
|
1178
|
+
const defaultSizes = [w, h, 1];
|
|
1179
|
+
if (root === node) {
|
|
1180
|
+
return defaultSizes;
|
|
1181
|
+
}
|
|
1182
|
+
const viewArea = w * h;
|
|
1183
|
+
let area = viewArea;
|
|
1184
|
+
let parent = node.node.parent;
|
|
1185
|
+
let totalWeight = node.node.weight;
|
|
1186
|
+
while (parent) {
|
|
1187
|
+
const siblings = parent.groups || [];
|
|
1188
|
+
let siblingWeightSum = 0;
|
|
1189
|
+
for (const sibling of siblings) {
|
|
1190
|
+
siblingWeightSum += sibling.weight;
|
|
1191
|
+
}
|
|
1192
|
+
area *= siblingWeightSum / totalWeight;
|
|
1193
|
+
totalWeight = parent.weight;
|
|
1194
|
+
parent = parent.parent;
|
|
1195
|
+
}
|
|
1196
|
+
const maxScaleFactor = 2.5;
|
|
1197
|
+
const minScaleFactor = 0.3;
|
|
1198
|
+
const scaleFactor = Math.max(minScaleFactor, Math.min(maxScaleFactor, Math.sqrt(area / viewArea)));
|
|
1199
|
+
return [w * scaleFactor, h * scaleFactor];
|
|
1054
1200
|
}
|
|
1055
|
-
function
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1201
|
+
function stackMatrixTransform(graph, e, f, scale) {
|
|
1202
|
+
graph.x = graph.x * scale + e;
|
|
1203
|
+
graph.y = graph.y * scale + f;
|
|
1204
|
+
graph.scaleX = scale;
|
|
1205
|
+
graph.scaleY = scale;
|
|
1206
|
+
}
|
|
1207
|
+
function stackMatrixTransformWithGraphAndLayer(graphs, e, f, scale) {
|
|
1208
|
+
etoile.traverse(graphs, (graph) => stackMatrixTransform(graph, e, f, scale));
|
|
1062
1209
|
}
|
|
1063
1210
|
function onZoom(ctx, node, root) {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
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
|
-
|
|
1211
|
+
if (!node) return;
|
|
1212
|
+
const { treemap, self } = ctx;
|
|
1213
|
+
self.forceDestroy = true;
|
|
1214
|
+
const c = treemap.render.canvas;
|
|
1215
|
+
const boundingClientRect = c.getBoundingClientRect();
|
|
1216
|
+
const [w, h] = estimateZoomingArea(node, root, boundingClientRect.width, boundingClientRect.height);
|
|
1217
|
+
resetLayout(treemap, w, h);
|
|
1218
|
+
const module = findRelativeNodeById(node.node.id, treemap.layoutNodes);
|
|
1219
|
+
if (module) {
|
|
1220
|
+
const [mx, my, mw, mh] = module.layout;
|
|
1221
|
+
const scale = Math.min(boundingClientRect.width / mw, boundingClientRect.height / mh);
|
|
1222
|
+
const translateX = boundingClientRect.width / 2 - (mx + mw / 2) * scale;
|
|
1223
|
+
const translateY = boundingClientRect.height / 2 - (my + mh / 2) * scale;
|
|
1224
|
+
const initialScale = self.scaleRatio;
|
|
1225
|
+
const initialTranslateX = self.translateX;
|
|
1226
|
+
const initialTranslateY = self.translateY;
|
|
1227
|
+
const startTime = Date.now();
|
|
1228
|
+
const animationDuration = 300;
|
|
1229
|
+
if (self.layoutHeight !== w || self.layoutHeight !== h) {
|
|
1230
|
+
delete treemap.fontsCaches[module.node.id];
|
|
1231
|
+
delete treemap.ellispsisWidthCache[module.node.id];
|
|
1232
|
+
}
|
|
1233
|
+
const { run, stop } = createEffectScope();
|
|
1234
|
+
run(() => {
|
|
1235
|
+
const elapsed = Date.now() - startTime;
|
|
1236
|
+
const progress = Math.min(elapsed / animationDuration, 1);
|
|
1237
|
+
treemap.backgroundLayer.__refresh__ = false;
|
|
1238
|
+
if (progress >= 1) {
|
|
1239
|
+
stop();
|
|
1240
|
+
self.layoutWidth = w;
|
|
1241
|
+
self.layoutHeight = h;
|
|
1242
|
+
self.forceDestroy = false;
|
|
1243
|
+
self.triggerZoom = true;
|
|
1244
|
+
return true;
|
|
1245
|
+
}
|
|
1246
|
+
const easedProgress = easing.cubicInOut(progress);
|
|
1247
|
+
const scaleRatio = initialScale + (scale - initialScale) * easedProgress;
|
|
1248
|
+
self.translateX = initialTranslateX + (translateX - initialTranslateX) * easedProgress;
|
|
1249
|
+
self.translateY = initialTranslateY + (translateY - initialTranslateY) * easedProgress;
|
|
1250
|
+
self.scaleRatio = scaleRatio;
|
|
1251
|
+
treemap.reset();
|
|
1252
|
+
stackMatrixTransformWithGraphAndLayer(treemap.elements, self.translateX, self.translateY, scaleRatio);
|
|
1253
|
+
treemap.update();
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
root = node;
|
|
1107
1257
|
}
|
|
1108
|
-
// Only works for mouseup and mousedown events
|
|
1109
1258
|
function isScrollWheelOrRightButtonOnMouseupAndDown(e) {
|
|
1110
|
-
|
|
1259
|
+
return e.which === 2 || e.which === 3;
|
|
1260
|
+
}
|
|
1261
|
+
function createHighlight() {
|
|
1262
|
+
let s = null;
|
|
1263
|
+
const setDisplayLayerForHighlight = (layer = "-1") => {
|
|
1264
|
+
if (!s) return;
|
|
1265
|
+
const c = s.render.canvas;
|
|
1266
|
+
c.style.zIndex = layer;
|
|
1267
|
+
};
|
|
1268
|
+
const init = (w, h, root) => {
|
|
1269
|
+
if (!s) {
|
|
1270
|
+
s = new Schedule(root, { width: w, height: h });
|
|
1271
|
+
}
|
|
1272
|
+
setDisplayLayerForHighlight();
|
|
1273
|
+
s.render.canvas.style.position = "absolute";
|
|
1274
|
+
s.render.canvas.style.pointerEvents = "none";
|
|
1275
|
+
};
|
|
1276
|
+
const reset = () => {
|
|
1277
|
+
if (!s) return;
|
|
1278
|
+
s.destory();
|
|
1279
|
+
s.update();
|
|
1280
|
+
};
|
|
1281
|
+
return {
|
|
1282
|
+
init,
|
|
1283
|
+
reset,
|
|
1284
|
+
setDisplayLayerForHighlight,
|
|
1285
|
+
get highlight() {
|
|
1286
|
+
return s;
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
function refreshBackgroundLayer(c) {
|
|
1291
|
+
const { treemap } = c;
|
|
1292
|
+
const { backgroundLayer } = treemap;
|
|
1293
|
+
backgroundLayer.__refresh__ = false;
|
|
1111
1294
|
}
|
|
1112
1295
|
|
|
1296
|
+
var __defProp = Object.defineProperty;
|
|
1297
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1298
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1113
1299
|
const defaultRegistries = [
|
|
1114
|
-
|
|
1300
|
+
registerModuleForSchedule(new SelfEvent())
|
|
1115
1301
|
];
|
|
1116
|
-
function
|
|
1117
|
-
|
|
1118
|
-
}
|
|
1119
|
-
function evaluateOptimalFontSize(c, text, width, fontRange, fontFamily, height) {
|
|
1120
|
-
height = Math.floor(height);
|
|
1121
|
-
let optimalFontSize = fontRange.min;
|
|
1122
|
-
for(let fontSize = fontRange.min; fontSize <= fontRange.max; fontSize++){
|
|
1123
|
-
c.font = `${fontSize}px ${fontFamily}`;
|
|
1124
|
-
let textWidth = 0;
|
|
1125
|
-
const textHeight = fontSize;
|
|
1126
|
-
let i = 0;
|
|
1127
|
-
while(i < text.length){
|
|
1128
|
-
const codePointWidth = charCodeWidth(c, text.charCodeAt(i));
|
|
1129
|
-
textWidth += codePointWidth;
|
|
1130
|
-
i++;
|
|
1131
|
-
}
|
|
1132
|
-
if (textWidth >= width) {
|
|
1133
|
-
const overflow = textWidth - width;
|
|
1134
|
-
const ratio = overflow / textWidth;
|
|
1135
|
-
const newFontSize = Math.abs(Math.floor(fontSize - fontSize * ratio));
|
|
1136
|
-
optimalFontSize = newFontSize || fontRange.min;
|
|
1137
|
-
break;
|
|
1138
|
-
}
|
|
1139
|
-
if (textHeight >= height) {
|
|
1140
|
-
const overflow = textHeight - height;
|
|
1141
|
-
const ratio = overflow / textHeight;
|
|
1142
|
-
const newFontSize = Math.abs(Math.floor(fontSize - fontSize * ratio));
|
|
1143
|
-
optimalFontSize = newFontSize || fontRange.min;
|
|
1144
|
-
break;
|
|
1145
|
-
}
|
|
1146
|
-
optimalFontSize = fontSize;
|
|
1147
|
-
}
|
|
1148
|
-
return optimalFontSize;
|
|
1302
|
+
function measureTextWidth(c, text) {
|
|
1303
|
+
return c.measureText(text).width;
|
|
1149
1304
|
}
|
|
1150
|
-
function
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1305
|
+
function evaluateOptimalFontSize(c, text, font, desiredW, desiredH) {
|
|
1306
|
+
desiredW = Math.floor(desiredW);
|
|
1307
|
+
desiredH = Math.floor(desiredH);
|
|
1308
|
+
const { range, family } = font;
|
|
1309
|
+
let min = range.min;
|
|
1310
|
+
let max = range.max;
|
|
1311
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1312
|
+
while (max - min >= 1) {
|
|
1313
|
+
const current = min + (max - min) / 2;
|
|
1314
|
+
if (!cache.has(current)) {
|
|
1315
|
+
c.font = `${current}px ${family}`;
|
|
1316
|
+
const metrics = c.measureText(text);
|
|
1317
|
+
const width2 = metrics.width;
|
|
1318
|
+
const height2 = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
1319
|
+
cache.set(current, { width: width2, height: height2 });
|
|
1320
|
+
}
|
|
1321
|
+
const { width, height } = cache.get(current);
|
|
1322
|
+
if (width > desiredW || height > desiredH) {
|
|
1323
|
+
max = current;
|
|
1324
|
+
} else {
|
|
1325
|
+
min = current;
|
|
1167
1326
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
width: ellipsisWidth
|
|
1171
|
-
};
|
|
1327
|
+
}
|
|
1328
|
+
return Math.floor(min);
|
|
1172
1329
|
}
|
|
1173
|
-
function
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
return
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
y,
|
|
1190
|
-
style: {
|
|
1191
|
-
fill: color,
|
|
1192
|
-
textAlign: 'center',
|
|
1193
|
-
baseline: 'middle',
|
|
1194
|
-
font,
|
|
1195
|
-
lineWidth: 1
|
|
1196
|
-
}
|
|
1197
|
-
});
|
|
1330
|
+
function getSafeText(c, text, width, cache) {
|
|
1331
|
+
let ellipsisWidth = 0;
|
|
1332
|
+
if (text in cache) {
|
|
1333
|
+
ellipsisWidth = cache[text];
|
|
1334
|
+
} else {
|
|
1335
|
+
ellipsisWidth = measureTextWidth(c, "...");
|
|
1336
|
+
cache[text] = ellipsisWidth;
|
|
1337
|
+
}
|
|
1338
|
+
if (width < ellipsisWidth) {
|
|
1339
|
+
return false;
|
|
1340
|
+
}
|
|
1341
|
+
const textWidth = measureTextWidth(c, text);
|
|
1342
|
+
if (textWidth < width) {
|
|
1343
|
+
return { text, width: textWidth };
|
|
1344
|
+
}
|
|
1345
|
+
return { text: "...", width: ellipsisWidth };
|
|
1198
1346
|
}
|
|
1199
1347
|
function resetLayout(treemap, w, h) {
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
h,
|
|
1203
|
-
x: 0,
|
|
1204
|
-
y: 0
|
|
1205
|
-
}, treemap.decorator.layout);
|
|
1206
|
-
treemap.reset();
|
|
1348
|
+
treemap.layoutNodes = squarify(treemap.data, { w, h, x: 0, y: 0 }, treemap.decorator.layout);
|
|
1349
|
+
treemap.reset(true);
|
|
1207
1350
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
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
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
this.add(this.bgBox, this.fgBox);
|
|
1287
|
-
}
|
|
1288
|
-
get api() {
|
|
1289
|
-
return {
|
|
1290
|
-
zoom: (node)=>{
|
|
1291
|
-
this.event.emit('zoom', node);
|
|
1292
|
-
}
|
|
1293
|
-
};
|
|
1351
|
+
class TreemapLayout extends etoile.Schedule {
|
|
1352
|
+
constructor(...args) {
|
|
1353
|
+
super(...args);
|
|
1354
|
+
__publicField(this, "data");
|
|
1355
|
+
__publicField(this, "layoutNodes");
|
|
1356
|
+
__publicField(this, "decorator");
|
|
1357
|
+
__publicField(this, "bgLayer");
|
|
1358
|
+
__publicField(this, "fgBox");
|
|
1359
|
+
__publicField(this, "fontsCaches");
|
|
1360
|
+
__publicField(this, "ellispsisWidthCache");
|
|
1361
|
+
this.data = [];
|
|
1362
|
+
this.layoutNodes = [];
|
|
1363
|
+
this.bgLayer = new Layer();
|
|
1364
|
+
this.fgBox = new Box();
|
|
1365
|
+
this.decorator = /* @__PURE__ */ Object.create(null);
|
|
1366
|
+
this.fontsCaches = /* @__PURE__ */ Object.create(null);
|
|
1367
|
+
this.ellispsisWidthCache = /* @__PURE__ */ Object.create(null);
|
|
1368
|
+
this.bgLayer.setCanvasOptions(this.render.options);
|
|
1369
|
+
}
|
|
1370
|
+
drawBackgroundNode(node) {
|
|
1371
|
+
const [x, y, w, h] = node.layout;
|
|
1372
|
+
const fill = this.decorator.color.mappings[node.node.id];
|
|
1373
|
+
const s = createFillBlock(x, y, w, h, { fill });
|
|
1374
|
+
this.bgLayer.add(s);
|
|
1375
|
+
for (const child of node.children) {
|
|
1376
|
+
this.drawBackgroundNode(child);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
drawForegroundNode(node) {
|
|
1380
|
+
const [x, y, w, h] = node.layout;
|
|
1381
|
+
if (!w || !h) return;
|
|
1382
|
+
const { rectBorderWidth, titleHeight, rectGap } = node.decorator;
|
|
1383
|
+
const { fontSize, fontFamily, color } = this.decorator.font;
|
|
1384
|
+
this.fgBox.add(createFillBlock(x + 0.5, y + 0.5, w, h, { stroke: "#222", lineWidth: rectBorderWidth }));
|
|
1385
|
+
let optimalFontSize;
|
|
1386
|
+
if (node.node.id in this.fontsCaches) {
|
|
1387
|
+
optimalFontSize = this.fontsCaches[node.node.id];
|
|
1388
|
+
} else {
|
|
1389
|
+
optimalFontSize = evaluateOptimalFontSize(
|
|
1390
|
+
this.render.ctx,
|
|
1391
|
+
node.node.label,
|
|
1392
|
+
{
|
|
1393
|
+
range: fontSize,
|
|
1394
|
+
family: fontFamily
|
|
1395
|
+
},
|
|
1396
|
+
w - rectGap * 2,
|
|
1397
|
+
node.children.length ? Math.round(titleHeight / 2) + rectGap : h
|
|
1398
|
+
);
|
|
1399
|
+
this.fontsCaches[node.node.id] = optimalFontSize;
|
|
1400
|
+
}
|
|
1401
|
+
this.render.ctx.font = `${optimalFontSize}px ${fontFamily}`;
|
|
1402
|
+
const result = getSafeText(this.render.ctx, node.node.label, w - rectGap * 2, this.ellispsisWidthCache);
|
|
1403
|
+
if (!result) return;
|
|
1404
|
+
if (result.width >= w || optimalFontSize >= h) return;
|
|
1405
|
+
const { text, width } = result;
|
|
1406
|
+
const textX = x + Math.round((w - width) / 2);
|
|
1407
|
+
const textY = y + (node.children.length ? Math.round(titleHeight / 2) : Math.round(h / 2));
|
|
1408
|
+
this.fgBox.add(createTitleText(text, textX, textY, `${optimalFontSize}px ${fontFamily}`, color));
|
|
1409
|
+
for (const child of node.children) {
|
|
1410
|
+
this.drawForegroundNode(child);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
reset(refresh = false) {
|
|
1414
|
+
this.remove(this.bgLayer, this.fgBox);
|
|
1415
|
+
if (!this.bgLayer.__refresh__) {
|
|
1416
|
+
this.bgLayer.destory();
|
|
1417
|
+
for (const node of this.layoutNodes) {
|
|
1418
|
+
this.drawBackgroundNode(node);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
if (!this.fgBox.elements.length || refresh) {
|
|
1422
|
+
this.render.ctx.textBaseline = "middle";
|
|
1423
|
+
this.fgBox.destory();
|
|
1424
|
+
for (const node of this.layoutNodes) {
|
|
1425
|
+
this.drawForegroundNode(node);
|
|
1426
|
+
}
|
|
1427
|
+
} else {
|
|
1428
|
+
this.fgBox = this.fgBox.clone();
|
|
1294
1429
|
}
|
|
1430
|
+
this.add(this.bgLayer, this.fgBox);
|
|
1431
|
+
}
|
|
1432
|
+
get api() {
|
|
1433
|
+
return {
|
|
1434
|
+
zoom: (node) => {
|
|
1435
|
+
this.event.emit("zoom", node);
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
get backgroundLayer() {
|
|
1440
|
+
return this.bgLayer;
|
|
1441
|
+
}
|
|
1295
1442
|
}
|
|
1296
1443
|
function createTreemap() {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1444
|
+
let treemap = null;
|
|
1445
|
+
let root = null;
|
|
1446
|
+
let installed = false;
|
|
1447
|
+
const uses = [];
|
|
1448
|
+
const context = {
|
|
1449
|
+
init,
|
|
1450
|
+
dispose,
|
|
1451
|
+
setOptions,
|
|
1452
|
+
resize,
|
|
1453
|
+
use,
|
|
1454
|
+
zoom
|
|
1455
|
+
};
|
|
1456
|
+
function init(el) {
|
|
1457
|
+
treemap = new TreemapLayout(el);
|
|
1458
|
+
root = el;
|
|
1459
|
+
root.style.position = "relative";
|
|
1460
|
+
if (!installed) {
|
|
1461
|
+
for (const registry of defaultRegistries) {
|
|
1462
|
+
registry(context, treemap, treemap.render);
|
|
1463
|
+
}
|
|
1464
|
+
installed = true;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function dispose() {
|
|
1468
|
+
if (root && treemap) {
|
|
1469
|
+
treemap.destory();
|
|
1470
|
+
root.removeChild(root.firstChild);
|
|
1471
|
+
root = null;
|
|
1472
|
+
treemap = null;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
function resize() {
|
|
1476
|
+
if (!treemap || !root) return;
|
|
1477
|
+
const { width, height } = root.getBoundingClientRect();
|
|
1478
|
+
treemap.backgroundLayer.__refresh__ = false;
|
|
1479
|
+
treemap.render.initOptions({ height, width, devicePixelRatio: window.devicePixelRatio });
|
|
1480
|
+
treemap.render.canvas.style.position = "absolute";
|
|
1481
|
+
treemap.backgroundLayer.setCanvasOptions(treemap.render.options);
|
|
1482
|
+
treemap.backgroundLayer.initLoc();
|
|
1483
|
+
treemap.backgroundLayer.matrix = treemap.backgroundLayer.matrix.create({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 });
|
|
1484
|
+
treemap.fontsCaches = /* @__PURE__ */ Object.create(null);
|
|
1485
|
+
treemap.event.emit("cleanup:selfevent");
|
|
1486
|
+
treemap.event.emit("onload:selfevent", { width, height, root });
|
|
1487
|
+
resetLayout(treemap, width, height);
|
|
1488
|
+
treemap.update();
|
|
1489
|
+
}
|
|
1490
|
+
function setOptions(options) {
|
|
1491
|
+
if (!treemap) {
|
|
1492
|
+
throw new Error("Treemap not initialized");
|
|
1493
|
+
}
|
|
1494
|
+
treemap.data = bindParentForModule(options.data || []);
|
|
1495
|
+
for (const use2 of uses) {
|
|
1496
|
+
use2(treemap);
|
|
1497
|
+
}
|
|
1498
|
+
resize();
|
|
1499
|
+
}
|
|
1500
|
+
function use(key, register) {
|
|
1501
|
+
switch (key) {
|
|
1502
|
+
case "decorator":
|
|
1503
|
+
uses.push((treemap2) => register(treemap2));
|
|
1504
|
+
break;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
function zoom(id) {
|
|
1508
|
+
if (!treemap) {
|
|
1509
|
+
throw new Error("treemap don't init.");
|
|
1510
|
+
}
|
|
1511
|
+
const node = findRelativeNodeById(id, treemap.layoutNodes);
|
|
1512
|
+
node && treemap.api.zoom(node);
|
|
1513
|
+
}
|
|
1514
|
+
return context;
|
|
1364
1515
|
}
|
|
1365
1516
|
|
|
1366
1517
|
const defaultLayoutOptions = {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1518
|
+
titleAreaHeight: {
|
|
1519
|
+
max: 80,
|
|
1520
|
+
min: 20
|
|
1521
|
+
},
|
|
1522
|
+
rectGap: 5,
|
|
1523
|
+
rectBorderRadius: 0.5,
|
|
1524
|
+
rectBorderWidth: 1.5
|
|
1374
1525
|
};
|
|
1375
1526
|
const defaultFontOptions = {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1527
|
+
color: "#000",
|
|
1528
|
+
fontSize: {
|
|
1529
|
+
max: 38,
|
|
1530
|
+
min: 7
|
|
1531
|
+
},
|
|
1532
|
+
fontFamily: "sans-serif"
|
|
1382
1533
|
};
|
|
1383
1534
|
function presetDecorator(app) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1535
|
+
Object.assign(app.decorator, {
|
|
1536
|
+
layout: defaultLayoutOptions,
|
|
1537
|
+
font: defaultFontOptions,
|
|
1538
|
+
color: { mappings: evaluateColorMappings(app.data) }
|
|
1539
|
+
});
|
|
1389
1540
|
}
|
|
1390
|
-
function
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
const
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
desc: {
|
|
1408
|
-
h: finalHue,
|
|
1409
|
-
s: Math.round(saturation * 100),
|
|
1410
|
-
l: Math.round(lightness * 100)
|
|
1411
|
-
}
|
|
1541
|
+
function evaluateColorMappings(data) {
|
|
1542
|
+
const colorMappings = {};
|
|
1543
|
+
const hashToHue = (id) => {
|
|
1544
|
+
const hash = Math.abs(hashCode(id));
|
|
1545
|
+
return hash % 360;
|
|
1546
|
+
};
|
|
1547
|
+
const lightScale = (depth) => 70 - depth * 5;
|
|
1548
|
+
const baseSaturation = 40;
|
|
1549
|
+
const siblingHueShift = 20;
|
|
1550
|
+
const rc = 0.2126;
|
|
1551
|
+
const gc = 0.7152;
|
|
1552
|
+
const bc = 0.0722;
|
|
1553
|
+
const hslToRgb = (h, s, l) => {
|
|
1554
|
+
const a = s * Math.min(l, 1 - l);
|
|
1555
|
+
const f = (n) => {
|
|
1556
|
+
const k = (n + h / 30) % 12;
|
|
1557
|
+
return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
1412
1558
|
};
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
function colorMappings(app) {
|
|
1427
|
-
const colorMappings = {};
|
|
1428
|
-
const state = {
|
|
1429
|
-
hue: 0
|
|
1559
|
+
return { r: f(0), g: f(8), b: f(4) };
|
|
1560
|
+
};
|
|
1561
|
+
const calculateLuminance = (r, g, b) => {
|
|
1562
|
+
return rc * r + gc * g + bc * b;
|
|
1563
|
+
};
|
|
1564
|
+
const calculateColor = (module, depth, parentHue, siblingIndex, totalSiblings) => {
|
|
1565
|
+
const nodeHue = hashToHue(module.id);
|
|
1566
|
+
const hue = parentHue !== null ? (parentHue + siblingHueShift * siblingIndex / totalSiblings) % 360 : nodeHue;
|
|
1567
|
+
const lightness = lightScale(depth);
|
|
1568
|
+
const hslColor = {
|
|
1569
|
+
h: hue,
|
|
1570
|
+
s: baseSaturation,
|
|
1571
|
+
l: lightness / 100
|
|
1430
1572
|
};
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1573
|
+
const { r, g, b } = hslToRgb(hslColor.h, hslColor.s / 100, hslColor.l);
|
|
1574
|
+
const luminance = calculateLuminance(r, g, b);
|
|
1575
|
+
if (luminance < 0.6) {
|
|
1576
|
+
hslColor.l += 0.2;
|
|
1577
|
+
} else if (luminance > 0.8) {
|
|
1578
|
+
hslColor.l -= 0.1;
|
|
1579
|
+
}
|
|
1580
|
+
hslColor.l *= 100;
|
|
1581
|
+
colorMappings[module.id] = {
|
|
1582
|
+
mode: "hsl",
|
|
1583
|
+
desc: hslColor
|
|
1436
1584
|
};
|
|
1585
|
+
if (module.groups && Array.isArray(module.groups)) {
|
|
1586
|
+
const totalChildren = module.groups.length;
|
|
1587
|
+
for (let i = 0; i < totalChildren; i++) {
|
|
1588
|
+
const child = module.groups[i];
|
|
1589
|
+
calculateColor(child, depth + 1, hue, i, totalChildren);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
for (let i = 0; i < data.length; i++) {
|
|
1594
|
+
const module = data[i];
|
|
1595
|
+
calculateColor(module, 0, null, i, data.length);
|
|
1596
|
+
}
|
|
1597
|
+
return colorMappings;
|
|
1437
1598
|
}
|
|
1438
1599
|
|
|
1439
1600
|
export { TreemapLayout, c2m, createTreemap, defaultFontOptions, defaultLayoutOptions, findRelativeNode, findRelativeNodeById, flatten as flattenModule, getNodeDepth, presetDecorator, sortChildrenByKey, visit };
|