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