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