squarified 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{dom-event-ClwTQnot.js → dom-event-BkRCiIWB.js} +279 -97
- package/dist/{dom-event-DrYYfglv.mjs → dom-event-CBrOg7CX.mjs} +266 -98
- package/dist/{index-Bks7tGiV.d.ts → index-C0Hd4N0X.d.ts} +85 -28
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -2
- package/dist/index.mjs +3 -4
- package/dist/plugin.d.mts +33 -19
- package/dist/plugin.d.ts +33 -19
- package/dist/plugin.js +295 -155
- package/dist/plugin.mjs +294 -154
- package/package.json +3 -3
|
@@ -36,6 +36,12 @@ class Matrix2D {
|
|
|
36
36
|
}
|
|
37
37
|
return this;
|
|
38
38
|
}
|
|
39
|
+
transformPoint(x, y) {
|
|
40
|
+
return {
|
|
41
|
+
x: this.a * x + this.c * y + this.e,
|
|
42
|
+
y: this.b * x + this.d * y + this.f
|
|
43
|
+
};
|
|
44
|
+
}
|
|
39
45
|
translation(x, y) {
|
|
40
46
|
this.e += x;
|
|
41
47
|
this.f += y;
|
|
@@ -94,10 +100,12 @@ class Display {
|
|
|
94
100
|
parent;
|
|
95
101
|
id;
|
|
96
102
|
matrix;
|
|
97
|
-
|
|
103
|
+
__widget__;
|
|
104
|
+
constructor(id, widget){
|
|
98
105
|
this.parent = null;
|
|
99
|
-
this.id = SELF_ID.get();
|
|
106
|
+
this.id = id ?? SELF_ID.get();
|
|
100
107
|
this.matrix = new Matrix2D();
|
|
108
|
+
this.__widget__ = widget;
|
|
101
109
|
}
|
|
102
110
|
destory() {
|
|
103
111
|
//
|
|
@@ -274,7 +282,7 @@ class S extends Display {
|
|
|
274
282
|
skewX;
|
|
275
283
|
skewY;
|
|
276
284
|
constructor(options = {}){
|
|
277
|
-
super();
|
|
285
|
+
super(options.__id__);
|
|
278
286
|
this.width = options.width || 0;
|
|
279
287
|
this.height = options.height || 0;
|
|
280
288
|
this.x = options.x || 0;
|
|
@@ -290,12 +298,14 @@ class S extends Display {
|
|
|
290
298
|
class Graph extends S {
|
|
291
299
|
instruction;
|
|
292
300
|
__options__;
|
|
293
|
-
constructor(options = {}){
|
|
301
|
+
constructor(options = {}, widget){
|
|
294
302
|
super(options);
|
|
295
303
|
this.instruction = createInstruction();
|
|
296
304
|
this.__options__ = options;
|
|
305
|
+
this.__widget__ = widget;
|
|
297
306
|
}
|
|
298
307
|
render(ctx) {
|
|
308
|
+
this.instruction.mods.length = 0;
|
|
299
309
|
this.create();
|
|
300
310
|
const cap = this.instruction.mods.length;
|
|
301
311
|
for(let i = 0; i < cap; i++){
|
|
@@ -339,8 +349,8 @@ const asserts = {
|
|
|
339
349
|
|
|
340
350
|
class C extends Display {
|
|
341
351
|
elements;
|
|
342
|
-
constructor(){
|
|
343
|
-
super();
|
|
352
|
+
constructor(id){
|
|
353
|
+
super(id);
|
|
344
354
|
this.elements = [];
|
|
345
355
|
}
|
|
346
356
|
add(...elements) {
|
|
@@ -371,16 +381,45 @@ class C extends Display {
|
|
|
371
381
|
}
|
|
372
382
|
class Box extends C {
|
|
373
383
|
elements;
|
|
374
|
-
constructor(){
|
|
375
|
-
super();
|
|
384
|
+
constructor(id, widget){
|
|
385
|
+
super(id);
|
|
376
386
|
this.elements = [];
|
|
387
|
+
this.__widget__ = widget;
|
|
377
388
|
}
|
|
378
389
|
add(...elements) {
|
|
379
390
|
const cap = elements.length;
|
|
380
391
|
for(let i = 0; i < cap; i++){
|
|
381
392
|
const element = elements[i];
|
|
382
|
-
if (element
|
|
383
|
-
|
|
393
|
+
if (element === this) {
|
|
394
|
+
console.warn('skip adding element: cannot add self as child');
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
let parent = this.parent ?? null;
|
|
398
|
+
while(parent){
|
|
399
|
+
if (parent === element) {
|
|
400
|
+
throw new Error('Cannot add an ancestor as a child (would create a cycle).');
|
|
401
|
+
}
|
|
402
|
+
parent = parent.parent ?? null;
|
|
403
|
+
}
|
|
404
|
+
if (element.parent) {
|
|
405
|
+
if (element.parent === this) {
|
|
406
|
+
const idx = this.elements.indexOf(element);
|
|
407
|
+
if (idx === -1) {
|
|
408
|
+
this.elements.push(element);
|
|
409
|
+
}
|
|
410
|
+
element.parent = this;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const prev = element.parent;
|
|
414
|
+
if (prev && asserts.isBox(prev)) {
|
|
415
|
+
prev.remove(element);
|
|
416
|
+
} else {
|
|
417
|
+
element.parent = null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (this.elements.indexOf(element) === -1) {
|
|
421
|
+
this.elements.push(element);
|
|
422
|
+
}
|
|
384
423
|
element.parent = this;
|
|
385
424
|
}
|
|
386
425
|
}
|
|
@@ -404,7 +443,7 @@ class Box extends C {
|
|
|
404
443
|
return DisplayType.Box;
|
|
405
444
|
}
|
|
406
445
|
clone() {
|
|
407
|
-
const box = new Box();
|
|
446
|
+
const box = new Box(this.id, this.__widget__);
|
|
408
447
|
if (this.elements.length) {
|
|
409
448
|
const stack = [
|
|
410
449
|
{
|
|
@@ -418,7 +457,7 @@ class Box extends C {
|
|
|
418
457
|
for(let i = 0; i < cap; i++){
|
|
419
458
|
const element = elements[i];
|
|
420
459
|
if (asserts.isBox(element)) {
|
|
421
|
-
const newBox = new Box();
|
|
460
|
+
const newBox = new Box(undefined, element.__widget__);
|
|
422
461
|
newBox.parent = parent;
|
|
423
462
|
parent.add(newBox);
|
|
424
463
|
stack.push({
|
|
@@ -471,8 +510,8 @@ const runtime = {
|
|
|
471
510
|
|
|
472
511
|
class RoundRect extends Graph {
|
|
473
512
|
style;
|
|
474
|
-
constructor(options = {}){
|
|
475
|
-
super(options);
|
|
513
|
+
constructor(options = {}, widget){
|
|
514
|
+
super(options, widget);
|
|
476
515
|
this.style = options.style || Object.create(null);
|
|
477
516
|
}
|
|
478
517
|
get __shape__() {
|
|
@@ -508,16 +547,17 @@ class RoundRect extends Graph {
|
|
|
508
547
|
clone() {
|
|
509
548
|
return new RoundRect({
|
|
510
549
|
...this.style,
|
|
511
|
-
...this.__options__
|
|
512
|
-
|
|
550
|
+
...this.__options__,
|
|
551
|
+
__id__: this.id
|
|
552
|
+
}, this.__widget__);
|
|
513
553
|
}
|
|
514
554
|
}
|
|
515
555
|
|
|
516
556
|
class Text extends Graph {
|
|
517
557
|
text;
|
|
518
558
|
style;
|
|
519
|
-
constructor(options = {}){
|
|
520
|
-
super(options);
|
|
559
|
+
constructor(options = {}, widget){
|
|
560
|
+
super(options, widget);
|
|
521
561
|
this.text = options.text || '';
|
|
522
562
|
this.style = options.style || Object.create(null);
|
|
523
563
|
}
|
|
@@ -534,8 +574,9 @@ class Text extends Graph {
|
|
|
534
574
|
clone() {
|
|
535
575
|
return new Text({
|
|
536
576
|
...this.style,
|
|
537
|
-
...this.__options__
|
|
538
|
-
|
|
577
|
+
...this.__options__,
|
|
578
|
+
__id__: this.id
|
|
579
|
+
}, this.__widget__);
|
|
539
580
|
}
|
|
540
581
|
get __shape__() {
|
|
541
582
|
return DisplayType.Text;
|
|
@@ -554,6 +595,33 @@ function traverse(graphs, handler) {
|
|
|
554
595
|
}
|
|
555
596
|
}
|
|
556
597
|
|
|
598
|
+
// Currently, etoile is an internal module, so we won't need too much easing functions.
|
|
599
|
+
// And the animation logic is implemented by user code.
|
|
600
|
+
const easing = {
|
|
601
|
+
linear: (k)=>k,
|
|
602
|
+
quadraticIn: (k)=>k * k,
|
|
603
|
+
quadraticOut: (k)=>k * (2 - k),
|
|
604
|
+
quadraticInOut: (k)=>{
|
|
605
|
+
if ((k *= 2) < 1) {
|
|
606
|
+
return 0.5 * k * k;
|
|
607
|
+
}
|
|
608
|
+
return -0.5 * (--k * (k - 2) - 1);
|
|
609
|
+
},
|
|
610
|
+
cubicIn: (k)=>k * k * k,
|
|
611
|
+
cubicOut: (k)=>{
|
|
612
|
+
if ((k *= 2) < 1) {
|
|
613
|
+
return 0.5 * k * k * k;
|
|
614
|
+
}
|
|
615
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
616
|
+
},
|
|
617
|
+
cubicInOut: (k)=>{
|
|
618
|
+
if ((k *= 2) < 1) {
|
|
619
|
+
return 0.5 * k * k * k;
|
|
620
|
+
}
|
|
621
|
+
return 0.5 * ((k -= 2) * k * k + 2);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
557
625
|
class Event {
|
|
558
626
|
eventCollections;
|
|
559
627
|
constructor(){
|
|
@@ -701,7 +769,7 @@ function perferNumeric(s) {
|
|
|
701
769
|
return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
|
|
702
770
|
}
|
|
703
771
|
function noop() {}
|
|
704
|
-
function createRoundBlock(x, y, width, height, style) {
|
|
772
|
+
function createRoundBlock(x, y, width, height, style, widget) {
|
|
705
773
|
return new RoundRect({
|
|
706
774
|
width,
|
|
707
775
|
height,
|
|
@@ -710,9 +778,9 @@ function createRoundBlock(x, y, width, height, style) {
|
|
|
710
778
|
style: {
|
|
711
779
|
...style
|
|
712
780
|
}
|
|
713
|
-
});
|
|
781
|
+
}, widget);
|
|
714
782
|
}
|
|
715
|
-
function createTitleText(text, x, y, font, color) {
|
|
783
|
+
function createTitleText(text, x, y, font, color, widget) {
|
|
716
784
|
return new Text({
|
|
717
785
|
text,
|
|
718
786
|
x,
|
|
@@ -724,7 +792,7 @@ function createTitleText(text, x, y, font, color) {
|
|
|
724
792
|
font,
|
|
725
793
|
lineWidth: 1
|
|
726
794
|
}
|
|
727
|
-
});
|
|
795
|
+
}, widget);
|
|
728
796
|
}
|
|
729
797
|
const raf = window.requestAnimationFrame;
|
|
730
798
|
function createCanvasElement() {
|
|
@@ -796,9 +864,9 @@ class DefaultMap extends Map {
|
|
|
796
864
|
}
|
|
797
865
|
return super.get(key);
|
|
798
866
|
}
|
|
799
|
-
|
|
867
|
+
getOrCreate(key, value) {
|
|
800
868
|
if (!super.has(key)) {
|
|
801
|
-
const defaultValue = value
|
|
869
|
+
const defaultValue = value ? value() : this.defaultFactory();
|
|
802
870
|
super.set(key, defaultValue);
|
|
803
871
|
return defaultValue;
|
|
804
872
|
}
|
|
@@ -869,19 +937,20 @@ class Render {
|
|
|
869
937
|
destory() {}
|
|
870
938
|
}
|
|
871
939
|
|
|
872
|
-
|
|
873
|
-
function drawGraphIntoCanvas(graph, opts) {
|
|
940
|
+
function drawGraphIntoCanvas(graph, opts, visibleSet) {
|
|
874
941
|
const { ctx, dpr } = opts;
|
|
875
|
-
ctx.save();
|
|
876
942
|
if (asserts.isBox(graph)) {
|
|
877
943
|
const elements = graph.elements;
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
const element = elements[i];
|
|
881
|
-
drawGraphIntoCanvas(element, opts);
|
|
944
|
+
for(let i = 0; i < elements.length; i++){
|
|
945
|
+
drawGraphIntoCanvas(elements[i], opts, visibleSet);
|
|
882
946
|
}
|
|
947
|
+
return;
|
|
883
948
|
}
|
|
884
949
|
if (asserts.isGraph(graph)) {
|
|
950
|
+
if (visibleSet && !visibleSet.has(graph.id)) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
ctx.save();
|
|
885
954
|
const matrix = graph.matrix.create({
|
|
886
955
|
a: 1,
|
|
887
956
|
b: 0,
|
|
@@ -893,13 +962,36 @@ function drawGraphIntoCanvas(graph, opts) {
|
|
|
893
962
|
matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
|
|
894
963
|
applyCanvasTransform(ctx, matrix, dpr);
|
|
895
964
|
graph.render(ctx);
|
|
965
|
+
ctx.restore();
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function collectSpatialEntries(graph, out) {
|
|
969
|
+
if (asserts.isBox(graph)) {
|
|
970
|
+
const elements = graph.elements;
|
|
971
|
+
for(let i = 0; i < elements.length; i++){
|
|
972
|
+
collectSpatialEntries(elements[i], out);
|
|
973
|
+
}
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
if (asserts.isGraph(graph)) {
|
|
977
|
+
out.push({
|
|
978
|
+
id: graph.id,
|
|
979
|
+
x: graph.x,
|
|
980
|
+
y: graph.y,
|
|
981
|
+
w: graph.width,
|
|
982
|
+
h: graph.height
|
|
983
|
+
});
|
|
896
984
|
}
|
|
897
|
-
|
|
985
|
+
}
|
|
986
|
+
function intersects(b, dr) {
|
|
987
|
+
return b.x < dr.x + dr.width && b.x + b.w > dr.x && b.y < dr.y + dr.height && b.y + b.h > dr.y;
|
|
898
988
|
}
|
|
899
989
|
class Schedule extends Box {
|
|
900
990
|
render;
|
|
901
991
|
to;
|
|
902
992
|
event;
|
|
993
|
+
_overlays;
|
|
994
|
+
_spatialIndex;
|
|
903
995
|
constructor(to, renderOptions = {}){
|
|
904
996
|
super();
|
|
905
997
|
this.to = typeof to === 'string' ? document.querySelector(to) : to;
|
|
@@ -915,11 +1007,30 @@ class Schedule extends Box {
|
|
|
915
1007
|
});
|
|
916
1008
|
this.event = new Event();
|
|
917
1009
|
this.render = new Render(this.to, renderOptions);
|
|
1010
|
+
this._overlays = [];
|
|
1011
|
+
this._spatialIndex = [];
|
|
1012
|
+
}
|
|
1013
|
+
addOverlay(...elements) {
|
|
1014
|
+
for (const el of elements){
|
|
1015
|
+
this._overlays.push(el);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
clearOverlay() {
|
|
1019
|
+
this._overlays.length = 0;
|
|
918
1020
|
}
|
|
919
|
-
update() {
|
|
920
|
-
|
|
1021
|
+
/** Full redraw: clear canvas, draw all elements and overlay. Rebuilds spatial index. */ update() {
|
|
1022
|
+
const { width, height, devicePixelRatio: dpr } = this.render.options;
|
|
1023
|
+
this.render.clear(width, height);
|
|
1024
|
+
const drawOpts = {
|
|
1025
|
+
c: this.render.canvas,
|
|
1026
|
+
ctx: this.render.ctx,
|
|
1027
|
+
dpr
|
|
1028
|
+
};
|
|
921
1029
|
this.execute(this.render, this);
|
|
922
|
-
|
|
1030
|
+
for(let i = 0; i < this._overlays.length; i++){
|
|
1031
|
+
drawGraphIntoCanvas(this._overlays[i], drawOpts);
|
|
1032
|
+
}
|
|
1033
|
+
const identity = this.matrix.create({
|
|
923
1034
|
a: 1,
|
|
924
1035
|
b: 0,
|
|
925
1036
|
c: 0,
|
|
@@ -927,15 +1038,62 @@ class Schedule extends Box {
|
|
|
927
1038
|
e: 0,
|
|
928
1039
|
f: 0
|
|
929
1040
|
});
|
|
930
|
-
applyCanvasTransform(this.render.ctx,
|
|
1041
|
+
applyCanvasTransform(this.render.ctx, identity, dpr);
|
|
1042
|
+
// Rebuild spatial index after full draw (positions are now finalised).
|
|
1043
|
+
this._spatialIndex.length = 0;
|
|
1044
|
+
collectSpatialEntries(this, this._spatialIndex);
|
|
1045
|
+
}
|
|
1046
|
+
updateDirty(rects) {
|
|
1047
|
+
// Partial redraw: for each dirty rect, clip → clear → redraw only the elements
|
|
1048
|
+
// that spatially intersect that rect → redraw overlay within the clip.
|
|
1049
|
+
// Vastly cheaper than a full update for small regions like hover highlights.
|
|
1050
|
+
if (rects.length === 0) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const { devicePixelRatio: dpr } = this.render.options;
|
|
1054
|
+
const ctx = this.render.ctx;
|
|
1055
|
+
const drawOpts = {
|
|
1056
|
+
c: this.render.canvas,
|
|
1057
|
+
ctx,
|
|
1058
|
+
dpr
|
|
1059
|
+
};
|
|
1060
|
+
const identity = this.matrix.create({
|
|
1061
|
+
a: 1,
|
|
1062
|
+
b: 0,
|
|
1063
|
+
c: 0,
|
|
1064
|
+
d: 1,
|
|
1065
|
+
e: 0,
|
|
1066
|
+
f: 0
|
|
1067
|
+
});
|
|
1068
|
+
applyCanvasTransform(ctx, identity, dpr);
|
|
1069
|
+
for (const dr of rects){
|
|
1070
|
+
// Build a culled visible-set: only leaf-graph IDs whose bbox overlaps dr.
|
|
1071
|
+
const visibleSet = new Set();
|
|
1072
|
+
for(let i = 0; i < this._spatialIndex.length; i++){
|
|
1073
|
+
if (intersects(this._spatialIndex[i], dr)) {
|
|
1074
|
+
visibleSet.add(this._spatialIndex[i].id);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
ctx.save();
|
|
1078
|
+
ctx.beginPath();
|
|
1079
|
+
ctx.rect(dr.x, dr.y, dr.width, dr.height);
|
|
1080
|
+
ctx.clip();
|
|
1081
|
+
ctx.clearRect(dr.x, dr.y, dr.width, dr.height);
|
|
1082
|
+
this.execute(this.render, this, visibleSet);
|
|
1083
|
+
for(let i = 0; i < this._overlays.length; i++){
|
|
1084
|
+
drawGraphIntoCanvas(this._overlays[i], drawOpts);
|
|
1085
|
+
}
|
|
1086
|
+
ctx.restore();
|
|
1087
|
+
}
|
|
1088
|
+
applyCanvasTransform(ctx, identity, dpr);
|
|
931
1089
|
}
|
|
932
|
-
//
|
|
933
|
-
execute(render, graph = this) {
|
|
1090
|
+
// Execute (draw) graph elements; pass visibleSet to skip non-intersecting leaves.
|
|
1091
|
+
execute(render, graph = this, visibleSet) {
|
|
934
1092
|
drawGraphIntoCanvas(graph, {
|
|
935
1093
|
c: render.canvas,
|
|
936
1094
|
ctx: render.ctx,
|
|
937
1095
|
dpr: render.options.devicePixelRatio
|
|
938
|
-
});
|
|
1096
|
+
}, visibleSet);
|
|
939
1097
|
}
|
|
940
1098
|
}
|
|
941
1099
|
|
|
@@ -1006,13 +1164,14 @@ function getNodeDepth(node) {
|
|
|
1006
1164
|
}
|
|
1007
1165
|
return depth;
|
|
1008
1166
|
}
|
|
1009
|
-
function visit(data, fn) {
|
|
1167
|
+
function visit(data, fn, getChildren = (d)=>d.children) {
|
|
1010
1168
|
if (!data) {
|
|
1011
1169
|
return null;
|
|
1012
1170
|
}
|
|
1013
1171
|
for (const d of data){
|
|
1014
|
-
|
|
1015
|
-
|
|
1172
|
+
const children = getChildren(d);
|
|
1173
|
+
if (children) {
|
|
1174
|
+
const result = visit(children, fn, getChildren);
|
|
1016
1175
|
if (result) {
|
|
1017
1176
|
return result;
|
|
1018
1177
|
}
|
|
@@ -1039,6 +1198,15 @@ function findRelativeNodeById(id, layoutNodes) {
|
|
|
1039
1198
|
}
|
|
1040
1199
|
});
|
|
1041
1200
|
}
|
|
1201
|
+
function findRelativeGraphicNode(bbox, graphics) {
|
|
1202
|
+
return visit(graphics, (graphic)=>{
|
|
1203
|
+
const widget = graphic.__widget__;
|
|
1204
|
+
if (Array.isArray(widget?.layout)) {
|
|
1205
|
+
const [x, y, w, h] = widget.layout;
|
|
1206
|
+
return bbox.x >= x && bbox.y >= y && bbox.x < x + w && bbox.y < y + h;
|
|
1207
|
+
}
|
|
1208
|
+
}, (graphic)=>graphic.elements);
|
|
1209
|
+
}
|
|
1042
1210
|
|
|
1043
1211
|
function generateStableCombinedNodeId(weight, nodes) {
|
|
1044
1212
|
const name = nodes.map((node)=>node.id).sort().join('-');
|
|
@@ -1321,8 +1489,6 @@ class Component extends Schedule {
|
|
|
1321
1489
|
pluginDriver;
|
|
1322
1490
|
data;
|
|
1323
1491
|
colorMappings;
|
|
1324
|
-
rectLayer;
|
|
1325
|
-
textLayer;
|
|
1326
1492
|
layoutNodes;
|
|
1327
1493
|
config;
|
|
1328
1494
|
caches;
|
|
@@ -1332,8 +1498,6 @@ class Component extends Schedule {
|
|
|
1332
1498
|
this.config = config;
|
|
1333
1499
|
this.colorMappings = {};
|
|
1334
1500
|
this.pluginDriver = new PluginDriver(this);
|
|
1335
|
-
this.rectLayer = new Box();
|
|
1336
|
-
this.textLayer = new Box();
|
|
1337
1501
|
this.caches = new DefaultMap(()=>14);
|
|
1338
1502
|
this.layoutNodes = [];
|
|
1339
1503
|
}
|
|
@@ -1396,52 +1560,58 @@ class Component extends Schedule {
|
|
|
1396
1560
|
isAABBIntersecting(a, b) {
|
|
1397
1561
|
return !(a.x + a.width < b.x || b.x + b.width < a.x || a.y + a.height < b.y || b.y + b.height < a.y);
|
|
1398
1562
|
}
|
|
1399
|
-
|
|
1563
|
+
drawNode(node, box) {
|
|
1400
1564
|
const [x, y, w, h] = node.layout;
|
|
1401
1565
|
const { rectRadius } = node.config;
|
|
1402
1566
|
const effectiveRadius = Math.min(rectRadius, w / 4, h / 4);
|
|
1403
1567
|
const fill = this.colorMappings[node.node.id] || DEFAULT_RECT_FILL_DESC;
|
|
1568
|
+
const graphic = new Box(undefined, node);
|
|
1569
|
+
if (box) {
|
|
1570
|
+
box.add(graphic);
|
|
1571
|
+
} else {
|
|
1572
|
+
this.add(graphic);
|
|
1573
|
+
}
|
|
1404
1574
|
const rect = createRoundBlock(x, y, w, h, {
|
|
1405
1575
|
fill,
|
|
1406
1576
|
padding: 0,
|
|
1407
1577
|
radius: effectiveRadius
|
|
1578
|
+
}, {
|
|
1579
|
+
x,
|
|
1580
|
+
y,
|
|
1581
|
+
w,
|
|
1582
|
+
h
|
|
1408
1583
|
});
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1584
|
+
graphic.add(rect);
|
|
1585
|
+
if (node.node.label || node.node.isCombinedNode) {
|
|
1586
|
+
const content = node.node.isCombinedNode ? `+ ${node.node.originalNodeCount} Modules` : node.node.label;
|
|
1587
|
+
const { titleAreaHeight } = node.config;
|
|
1588
|
+
const availableHeight = node.children && node.children.length > 0 ? titleAreaHeight - DEFAULT_RECT_GAP * 2 : h - DEFAULT_RECT_GAP * 2;
|
|
1589
|
+
const availableWidth = w - DEFAULT_RECT_GAP * 2;
|
|
1590
|
+
if (availableWidth > 0 && availableHeight > 0) {
|
|
1591
|
+
const config = {
|
|
1592
|
+
fontSize: this.config.font?.fontSize || DEFAULT_FONT_SIZE,
|
|
1593
|
+
family: this.config.font?.family || DEFAULT_FONT_FAMILY,
|
|
1594
|
+
color: this.config.font?.color || DEFAULT_FONT_COLOR
|
|
1595
|
+
};
|
|
1596
|
+
const optimalFontSize = this.caches.getOrCreate(node.node.id, ()=>evaluateOptimalFontSize(this.render.ctx, content, config, availableWidth, availableHeight));
|
|
1597
|
+
const font = `${optimalFontSize}px ${config.family}`;
|
|
1598
|
+
this.render.ctx.font = font;
|
|
1599
|
+
const result = getTextLayout(this.render.ctx, content, availableWidth, availableHeight);
|
|
1600
|
+
if (!result.valid) {
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
const { text } = result;
|
|
1604
|
+
const textX = x + Math.round(w / 2);
|
|
1605
|
+
const textY = y + (node.children && node.children.length > 0 ? Math.round(titleAreaHeight / 2) : Math.round(h / 2));
|
|
1606
|
+
const textComponent = createTitleText(text, textX, textY, font, config.color, {
|
|
1607
|
+
textX,
|
|
1608
|
+
textY
|
|
1609
|
+
});
|
|
1610
|
+
graphic.add(textComponent);
|
|
1611
|
+
}
|
|
1437
1612
|
}
|
|
1438
|
-
const { text } = result;
|
|
1439
|
-
const textX = x + Math.round(w / 2);
|
|
1440
|
-
const textY = y + (node.children && node.children.length > 0 ? Math.round(titleAreaHeight / 2) : Math.round(h / 2));
|
|
1441
|
-
const textComponent = createTitleText(text, textX, textY, font, config.color);
|
|
1442
|
-
this.textLayer.add(textComponent);
|
|
1443
1613
|
for (const child of node.children){
|
|
1444
|
-
this.
|
|
1614
|
+
this.drawNode(child, graphic);
|
|
1445
1615
|
}
|
|
1446
1616
|
}
|
|
1447
1617
|
draw(flush = true, update = true) {
|
|
@@ -1462,20 +1632,14 @@ class Component extends Schedule {
|
|
|
1462
1632
|
}
|
|
1463
1633
|
}
|
|
1464
1634
|
for (const node of this.layoutNodes){
|
|
1465
|
-
this.
|
|
1466
|
-
}
|
|
1467
|
-
for (const node of this.layoutNodes){
|
|
1468
|
-
this.drawText(node);
|
|
1635
|
+
this.drawNode(node, null);
|
|
1469
1636
|
}
|
|
1470
|
-
this.add(this.rectLayer, this.textLayer);
|
|
1471
1637
|
if (update) {
|
|
1472
1638
|
this.update();
|
|
1473
1639
|
}
|
|
1474
1640
|
}
|
|
1475
1641
|
cleanup() {
|
|
1476
|
-
this.
|
|
1477
|
-
this.rectLayer.destory();
|
|
1478
|
-
this.textLayer.destory();
|
|
1642
|
+
this.destory();
|
|
1479
1643
|
}
|
|
1480
1644
|
calculateLayoutNodes(data, rect, scale = 1) {
|
|
1481
1645
|
const config = {
|
|
@@ -1512,8 +1676,8 @@ function evaluateOptimalFontSize(c, text, config, desiredW, desiredH) {
|
|
|
1512
1676
|
return Math.floor(min);
|
|
1513
1677
|
}
|
|
1514
1678
|
function getTextLayout(c, text, width, height) {
|
|
1515
|
-
const textWidth = c.measureText(text).width;
|
|
1516
1679
|
const metrics = c.measureText(text);
|
|
1680
|
+
const textWidth = metrics.width;
|
|
1517
1681
|
const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
1518
1682
|
if (textHeight > height) {
|
|
1519
1683
|
return {
|
|
@@ -1691,16 +1855,20 @@ class DOMEvent extends Event {
|
|
|
1691
1855
|
}
|
|
1692
1856
|
}
|
|
1693
1857
|
dispatch(kind, e) {
|
|
1694
|
-
const
|
|
1695
|
-
this.
|
|
1858
|
+
const { native } = e;
|
|
1859
|
+
const bbox = captureBoxXY(this.el, native, 1, 1, this.matrix.e, this.matrix.f);
|
|
1860
|
+
const graphic = findRelativeGraphicNode(bbox, this.component.elements);
|
|
1861
|
+
this.component.pluginDriver.runHook('onDOMEventTriggered', kind, e, graphic, this);
|
|
1696
1862
|
this.emit('__exposed__', kind, {
|
|
1697
1863
|
native: e.native,
|
|
1698
|
-
module:
|
|
1864
|
+
module: graphic
|
|
1699
1865
|
});
|
|
1700
1866
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1867
|
+
findRelativeGraphicNode(metadata) {
|
|
1868
|
+
const { native } = metadata;
|
|
1869
|
+
const bbox = captureBoxXY(this.el, native, 1, 1, this.matrix.e, this.matrix.f);
|
|
1870
|
+
return findRelativeGraphicNode(bbox, this.component.elements);
|
|
1703
1871
|
}
|
|
1704
1872
|
}
|
|
1705
1873
|
|
|
1706
|
-
export {
|
|
1874
|
+
export { Render as A, Box as B, Component as C, DOMEvent as D, Event as E, hashCode as F, perferNumeric as G, noop as H, createRoundBlock as I, createTitleText as J, raf as K, createCanvasElement as L, applyCanvasTransform as M, typedForIn as N, stackMatrixTransform as O, stackMatrixTransformWithGraphAndLayer as P, smoothFrame as Q, RoundRect as R, Schedule as S, Text as T, isScrollWheelOrRightButtonOnMouseupAndDown as U, DefaultMap as V, DEFAULT_MATRIX_LOC as W, PI_2 as X, assertExists as a, bindParentForModule as b, c2m as c, findRelativeNodeById as d, flatten as e, findRelativeNode as f, getNodeDepth as g, definePlugin as h, isClickEvent as i, isContextMenuEvent as j, isMouseEvent as k, logger as l, mixin as m, isWheelEvent as n, isGraph as o, isBox as p, isRoundRect as q, isText as r, sortChildrenByKey as s, traverse as t, asserts as u, visit as v, easing as w, drawGraphIntoCanvas as x, writeBoundingRectForCanvas as y, Canvas as z };
|