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