squarified 0.6.2 → 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.
@@ -38,6 +38,12 @@ class Matrix2D {
38
38
  }
39
39
  return this;
40
40
  }
41
+ transformPoint(x, y) {
42
+ return {
43
+ x: this.a * x + this.c * y + this.e,
44
+ y: this.b * x + this.d * y + this.f
45
+ };
46
+ }
41
47
  translation(x, y) {
42
48
  this.e += x;
43
49
  this.f += y;
@@ -96,10 +102,12 @@ class Display {
96
102
  parent;
97
103
  id;
98
104
  matrix;
99
- constructor(){
105
+ __widget__;
106
+ constructor(id, widget){
100
107
  this.parent = null;
101
- this.id = SELF_ID.get();
108
+ this.id = id ?? SELF_ID.get();
102
109
  this.matrix = new Matrix2D();
110
+ this.__widget__ = widget;
103
111
  }
104
112
  destory() {
105
113
  //
@@ -276,7 +284,7 @@ class S extends Display {
276
284
  skewX;
277
285
  skewY;
278
286
  constructor(options = {}){
279
- super();
287
+ super(options.__id__);
280
288
  this.width = options.width || 0;
281
289
  this.height = options.height || 0;
282
290
  this.x = options.x || 0;
@@ -292,12 +300,14 @@ class S extends Display {
292
300
  class Graph extends S {
293
301
  instruction;
294
302
  __options__;
295
- constructor(options = {}){
303
+ constructor(options = {}, widget){
296
304
  super(options);
297
305
  this.instruction = createInstruction();
298
306
  this.__options__ = options;
307
+ this.__widget__ = widget;
299
308
  }
300
309
  render(ctx) {
310
+ this.instruction.mods.length = 0;
301
311
  this.create();
302
312
  const cap = this.instruction.mods.length;
303
313
  for(let i = 0; i < cap; i++){
@@ -341,8 +351,8 @@ const asserts = {
341
351
 
342
352
  class C extends Display {
343
353
  elements;
344
- constructor(){
345
- super();
354
+ constructor(id){
355
+ super(id);
346
356
  this.elements = [];
347
357
  }
348
358
  add(...elements) {
@@ -373,16 +383,45 @@ class C extends Display {
373
383
  }
374
384
  class Box extends C {
375
385
  elements;
376
- constructor(){
377
- super();
386
+ constructor(id, widget){
387
+ super(id);
378
388
  this.elements = [];
389
+ this.__widget__ = widget;
379
390
  }
380
391
  add(...elements) {
381
392
  const cap = elements.length;
382
393
  for(let i = 0; i < cap; i++){
383
394
  const element = elements[i];
384
- if (element.parent) ;
385
- this.elements.push(element);
395
+ if (element === this) {
396
+ console.warn('skip adding element: cannot add self as child');
397
+ continue;
398
+ }
399
+ let parent = this.parent ?? null;
400
+ while(parent){
401
+ if (parent === element) {
402
+ throw new Error('Cannot add an ancestor as a child (would create a cycle).');
403
+ }
404
+ parent = parent.parent ?? null;
405
+ }
406
+ if (element.parent) {
407
+ if (element.parent === this) {
408
+ const idx = this.elements.indexOf(element);
409
+ if (idx === -1) {
410
+ this.elements.push(element);
411
+ }
412
+ element.parent = this;
413
+ continue;
414
+ }
415
+ const prev = element.parent;
416
+ if (prev && asserts.isBox(prev)) {
417
+ prev.remove(element);
418
+ } else {
419
+ element.parent = null;
420
+ }
421
+ }
422
+ if (this.elements.indexOf(element) === -1) {
423
+ this.elements.push(element);
424
+ }
386
425
  element.parent = this;
387
426
  }
388
427
  }
@@ -406,7 +445,7 @@ class Box extends C {
406
445
  return DisplayType.Box;
407
446
  }
408
447
  clone() {
409
- const box = new Box();
448
+ const box = new Box(this.id, this.__widget__);
410
449
  if (this.elements.length) {
411
450
  const stack = [
412
451
  {
@@ -420,7 +459,7 @@ class Box extends C {
420
459
  for(let i = 0; i < cap; i++){
421
460
  const element = elements[i];
422
461
  if (asserts.isBox(element)) {
423
- const newBox = new Box();
462
+ const newBox = new Box(undefined, element.__widget__);
424
463
  newBox.parent = parent;
425
464
  parent.add(newBox);
426
465
  stack.push({
@@ -473,8 +512,8 @@ const runtime = {
473
512
 
474
513
  class RoundRect extends Graph {
475
514
  style;
476
- constructor(options = {}){
477
- super(options);
515
+ constructor(options = {}, widget){
516
+ super(options, widget);
478
517
  this.style = options.style || Object.create(null);
479
518
  }
480
519
  get __shape__() {
@@ -510,16 +549,17 @@ class RoundRect extends Graph {
510
549
  clone() {
511
550
  return new RoundRect({
512
551
  ...this.style,
513
- ...this.__options__
514
- });
552
+ ...this.__options__,
553
+ __id__: this.id
554
+ }, this.__widget__);
515
555
  }
516
556
  }
517
557
 
518
558
  class Text extends Graph {
519
559
  text;
520
560
  style;
521
- constructor(options = {}){
522
- super(options);
561
+ constructor(options = {}, widget){
562
+ super(options, widget);
523
563
  this.text = options.text || '';
524
564
  this.style = options.style || Object.create(null);
525
565
  }
@@ -536,8 +576,9 @@ class Text extends Graph {
536
576
  clone() {
537
577
  return new Text({
538
578
  ...this.style,
539
- ...this.__options__
540
- });
579
+ ...this.__options__,
580
+ __id__: this.id
581
+ }, this.__widget__);
541
582
  }
542
583
  get __shape__() {
543
584
  return DisplayType.Text;
@@ -556,6 +597,33 @@ function traverse(graphs, handler) {
556
597
  }
557
598
  }
558
599
 
600
+ // Currently, etoile is an internal module, so we won't need too much easing functions.
601
+ // And the animation logic is implemented by user code.
602
+ const easing = {
603
+ linear: (k)=>k,
604
+ quadraticIn: (k)=>k * k,
605
+ quadraticOut: (k)=>k * (2 - k),
606
+ quadraticInOut: (k)=>{
607
+ if ((k *= 2) < 1) {
608
+ return 0.5 * k * k;
609
+ }
610
+ return -0.5 * (--k * (k - 2) - 1);
611
+ },
612
+ cubicIn: (k)=>k * k * k,
613
+ cubicOut: (k)=>{
614
+ if ((k *= 2) < 1) {
615
+ return 0.5 * k * k * k;
616
+ }
617
+ return 0.5 * ((k -= 2) * k * k + 2);
618
+ },
619
+ cubicInOut: (k)=>{
620
+ if ((k *= 2) < 1) {
621
+ return 0.5 * k * k * k;
622
+ }
623
+ return 0.5 * ((k -= 2) * k * k + 2);
624
+ }
625
+ };
626
+
559
627
  class Event {
560
628
  eventCollections;
561
629
  constructor(){
@@ -703,7 +771,7 @@ function perferNumeric(s) {
703
771
  return s.charCodeAt(0) >= 48 && s.charCodeAt(0) <= 57;
704
772
  }
705
773
  function noop() {}
706
- function createRoundBlock(x, y, width, height, style) {
774
+ function createRoundBlock(x, y, width, height, style, widget) {
707
775
  return new RoundRect({
708
776
  width,
709
777
  height,
@@ -712,9 +780,9 @@ function createRoundBlock(x, y, width, height, style) {
712
780
  style: {
713
781
  ...style
714
782
  }
715
- });
783
+ }, widget);
716
784
  }
717
- function createTitleText(text, x, y, font, color) {
785
+ function createTitleText(text, x, y, font, color, widget) {
718
786
  return new Text({
719
787
  text,
720
788
  x,
@@ -726,7 +794,7 @@ function createTitleText(text, x, y, font, color) {
726
794
  font,
727
795
  lineWidth: 1
728
796
  }
729
- });
797
+ }, widget);
730
798
  }
731
799
  const raf = window.requestAnimationFrame;
732
800
  function createCanvasElement() {
@@ -798,9 +866,9 @@ class DefaultMap extends Map {
798
866
  }
799
867
  return super.get(key);
800
868
  }
801
- getOrInsert(key, value) {
869
+ getOrCreate(key, value) {
802
870
  if (!super.has(key)) {
803
- const defaultValue = value || this.defaultFactory();
871
+ const defaultValue = value ? value() : this.defaultFactory();
804
872
  super.set(key, defaultValue);
805
873
  return defaultValue;
806
874
  }
@@ -871,19 +939,20 @@ class Render {
871
939
  destory() {}
872
940
  }
873
941
 
874
- // First cleanup canvas
875
- function drawGraphIntoCanvas(graph, opts) {
942
+ function drawGraphIntoCanvas(graph, opts, visibleSet) {
876
943
  const { ctx, dpr } = opts;
877
- ctx.save();
878
944
  if (asserts.isBox(graph)) {
879
945
  const elements = graph.elements;
880
- const cap = elements.length;
881
- for(let i = 0; i < cap; i++){
882
- const element = elements[i];
883
- drawGraphIntoCanvas(element, opts);
946
+ for(let i = 0; i < elements.length; i++){
947
+ drawGraphIntoCanvas(elements[i], opts, visibleSet);
884
948
  }
949
+ return;
885
950
  }
886
951
  if (asserts.isGraph(graph)) {
952
+ if (visibleSet && !visibleSet.has(graph.id)) {
953
+ return;
954
+ }
955
+ ctx.save();
887
956
  const matrix = graph.matrix.create({
888
957
  a: 1,
889
958
  b: 0,
@@ -895,13 +964,36 @@ function drawGraphIntoCanvas(graph, opts) {
895
964
  matrix.transform(graph.x, graph.y, graph.scaleX, graph.scaleY, graph.rotation, graph.skewX, graph.skewY);
896
965
  applyCanvasTransform(ctx, matrix, dpr);
897
966
  graph.render(ctx);
967
+ ctx.restore();
968
+ }
969
+ }
970
+ function collectSpatialEntries(graph, out) {
971
+ if (asserts.isBox(graph)) {
972
+ const elements = graph.elements;
973
+ for(let i = 0; i < elements.length; i++){
974
+ collectSpatialEntries(elements[i], out);
975
+ }
976
+ return;
977
+ }
978
+ if (asserts.isGraph(graph)) {
979
+ out.push({
980
+ id: graph.id,
981
+ x: graph.x,
982
+ y: graph.y,
983
+ w: graph.width,
984
+ h: graph.height
985
+ });
898
986
  }
899
- ctx.restore();
987
+ }
988
+ function intersects(b, dr) {
989
+ 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;
900
990
  }
901
991
  class Schedule extends Box {
902
992
  render;
903
993
  to;
904
994
  event;
995
+ _overlays;
996
+ _spatialIndex;
905
997
  constructor(to, renderOptions = {}){
906
998
  super();
907
999
  this.to = typeof to === 'string' ? document.querySelector(to) : to;
@@ -917,11 +1009,30 @@ class Schedule extends Box {
917
1009
  });
918
1010
  this.event = new Event();
919
1011
  this.render = new Render(this.to, renderOptions);
1012
+ this._overlays = [];
1013
+ this._spatialIndex = [];
1014
+ }
1015
+ addOverlay(...elements) {
1016
+ for (const el of elements){
1017
+ this._overlays.push(el);
1018
+ }
1019
+ }
1020
+ clearOverlay() {
1021
+ this._overlays.length = 0;
920
1022
  }
921
- update() {
922
- this.render.clear(this.render.options.width, this.render.options.height);
1023
+ /** Full redraw: clear canvas, draw all elements and overlay. Rebuilds spatial index. */ update() {
1024
+ const { width, height, devicePixelRatio: dpr } = this.render.options;
1025
+ this.render.clear(width, height);
1026
+ const drawOpts = {
1027
+ c: this.render.canvas,
1028
+ ctx: this.render.ctx,
1029
+ dpr
1030
+ };
923
1031
  this.execute(this.render, this);
924
- const matrix = this.matrix.create({
1032
+ for(let i = 0; i < this._overlays.length; i++){
1033
+ drawGraphIntoCanvas(this._overlays[i], drawOpts);
1034
+ }
1035
+ const identity = this.matrix.create({
925
1036
  a: 1,
926
1037
  b: 0,
927
1038
  c: 0,
@@ -929,15 +1040,62 @@ class Schedule extends Box {
929
1040
  e: 0,
930
1041
  f: 0
931
1042
  });
932
- applyCanvasTransform(this.render.ctx, matrix, this.render.options.devicePixelRatio);
1043
+ applyCanvasTransform(this.render.ctx, identity, dpr);
1044
+ // Rebuild spatial index after full draw (positions are now finalised).
1045
+ this._spatialIndex.length = 0;
1046
+ collectSpatialEntries(this, this._spatialIndex);
1047
+ }
1048
+ updateDirty(rects) {
1049
+ // Partial redraw: for each dirty rect, clip → clear → redraw only the elements
1050
+ // that spatially intersect that rect → redraw overlay within the clip.
1051
+ // Vastly cheaper than a full update for small regions like hover highlights.
1052
+ if (rects.length === 0) {
1053
+ return;
1054
+ }
1055
+ const { devicePixelRatio: dpr } = this.render.options;
1056
+ const ctx = this.render.ctx;
1057
+ const drawOpts = {
1058
+ c: this.render.canvas,
1059
+ ctx,
1060
+ dpr
1061
+ };
1062
+ const identity = this.matrix.create({
1063
+ a: 1,
1064
+ b: 0,
1065
+ c: 0,
1066
+ d: 1,
1067
+ e: 0,
1068
+ f: 0
1069
+ });
1070
+ applyCanvasTransform(ctx, identity, dpr);
1071
+ for (const dr of rects){
1072
+ // Build a culled visible-set: only leaf-graph IDs whose bbox overlaps dr.
1073
+ const visibleSet = new Set();
1074
+ for(let i = 0; i < this._spatialIndex.length; i++){
1075
+ if (intersects(this._spatialIndex[i], dr)) {
1076
+ visibleSet.add(this._spatialIndex[i].id);
1077
+ }
1078
+ }
1079
+ ctx.save();
1080
+ ctx.beginPath();
1081
+ ctx.rect(dr.x, dr.y, dr.width, dr.height);
1082
+ ctx.clip();
1083
+ ctx.clearRect(dr.x, dr.y, dr.width, dr.height);
1084
+ this.execute(this.render, this, visibleSet);
1085
+ for(let i = 0; i < this._overlays.length; i++){
1086
+ drawGraphIntoCanvas(this._overlays[i], drawOpts);
1087
+ }
1088
+ ctx.restore();
1089
+ }
1090
+ applyCanvasTransform(ctx, identity, dpr);
933
1091
  }
934
- // execute all graph elements
935
- execute(render, graph = this) {
1092
+ // Execute (draw) graph elements; pass visibleSet to skip non-intersecting leaves.
1093
+ execute(render, graph = this, visibleSet) {
936
1094
  drawGraphIntoCanvas(graph, {
937
1095
  c: render.canvas,
938
1096
  ctx: render.ctx,
939
1097
  dpr: render.options.devicePixelRatio
940
- });
1098
+ }, visibleSet);
941
1099
  }
942
1100
  }
943
1101
 
@@ -1008,13 +1166,14 @@ function getNodeDepth(node) {
1008
1166
  }
1009
1167
  return depth;
1010
1168
  }
1011
- function visit(data, fn) {
1169
+ function visit(data, fn, getChildren = (d)=>d.children) {
1012
1170
  if (!data) {
1013
1171
  return null;
1014
1172
  }
1015
1173
  for (const d of data){
1016
- if (d.children) {
1017
- const result = visit(d.children, fn);
1174
+ const children = getChildren(d);
1175
+ if (children) {
1176
+ const result = visit(children, fn, getChildren);
1018
1177
  if (result) {
1019
1178
  return result;
1020
1179
  }
@@ -1041,6 +1200,15 @@ function findRelativeNodeById(id, layoutNodes) {
1041
1200
  }
1042
1201
  });
1043
1202
  }
1203
+ function findRelativeGraphicNode(bbox, graphics) {
1204
+ return visit(graphics, (graphic)=>{
1205
+ const widget = graphic.__widget__;
1206
+ if (Array.isArray(widget?.layout)) {
1207
+ const [x, y, w, h] = widget.layout;
1208
+ return bbox.x >= x && bbox.y >= y && bbox.x < x + w && bbox.y < y + h;
1209
+ }
1210
+ }, (graphic)=>graphic.elements);
1211
+ }
1044
1212
 
1045
1213
  function generateStableCombinedNodeId(weight, nodes) {
1046
1214
  const name = nodes.map((node)=>node.id).sort().join('-');
@@ -1323,8 +1491,6 @@ class Component extends Schedule {
1323
1491
  pluginDriver;
1324
1492
  data;
1325
1493
  colorMappings;
1326
- rectLayer;
1327
- textLayer;
1328
1494
  layoutNodes;
1329
1495
  config;
1330
1496
  caches;
@@ -1334,8 +1500,6 @@ class Component extends Schedule {
1334
1500
  this.config = config;
1335
1501
  this.colorMappings = {};
1336
1502
  this.pluginDriver = new PluginDriver(this);
1337
- this.rectLayer = new Box();
1338
- this.textLayer = new Box();
1339
1503
  this.caches = new DefaultMap(()=>14);
1340
1504
  this.layoutNodes = [];
1341
1505
  }
@@ -1398,52 +1562,58 @@ class Component extends Schedule {
1398
1562
  isAABBIntersecting(a, b) {
1399
1563
  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);
1400
1564
  }
1401
- drawBroundRect(node) {
1565
+ drawNode(node, box) {
1402
1566
  const [x, y, w, h] = node.layout;
1403
1567
  const { rectRadius } = node.config;
1404
1568
  const effectiveRadius = Math.min(rectRadius, w / 4, h / 4);
1405
1569
  const fill = this.colorMappings[node.node.id] || DEFAULT_RECT_FILL_DESC;
1570
+ const graphic = new Box(undefined, node);
1571
+ if (box) {
1572
+ box.add(graphic);
1573
+ } else {
1574
+ this.add(graphic);
1575
+ }
1406
1576
  const rect = createRoundBlock(x, y, w, h, {
1407
1577
  fill,
1408
1578
  padding: 0,
1409
1579
  radius: effectiveRadius
1580
+ }, {
1581
+ x,
1582
+ y,
1583
+ w,
1584
+ h
1410
1585
  });
1411
- this.rectLayer.add(rect);
1412
- for (const child of node.children){
1413
- this.drawBroundRect(child);
1414
- }
1415
- }
1416
- drawText(node) {
1417
- if (!node.node.label && !node.node.isCombinedNode) {
1418
- return;
1419
- }
1420
- const [x, y, w, h] = node.layout;
1421
- const { titleAreaHeight } = node.config;
1422
- const content = node.node.isCombinedNode ? `+ ${node.node.originalNodeCount} Modules` : node.node.label;
1423
- const availableHeight = node.children && node.children.length > 0 ? titleAreaHeight - DEFAULT_RECT_GAP * 2 : h - DEFAULT_RECT_GAP * 2;
1424
- const availableWidth = w - DEFAULT_RECT_GAP * 2;
1425
- if (availableWidth <= 0 || availableHeight <= 0) {
1426
- return;
1427
- }
1428
- const config = {
1429
- fontSize: this.config.font?.fontSize || DEFAULT_FONT_SIZE,
1430
- family: this.config.font?.family || DEFAULT_FONT_FAMILY,
1431
- color: this.config.font?.color || DEFAULT_FONT_COLOR
1432
- };
1433
- const optimalFontSize = this.caches.getOrInsert(node.node.id, evaluateOptimalFontSize(this.render.ctx, content, config, availableWidth, availableHeight));
1434
- const font = `${optimalFontSize}px ${config.family}`;
1435
- this.render.ctx.font = font;
1436
- const result = getTextLayout(this.render.ctx, content, availableWidth, availableHeight);
1437
- if (!result.valid) {
1438
- return;
1586
+ graphic.add(rect);
1587
+ if (node.node.label || node.node.isCombinedNode) {
1588
+ const content = node.node.isCombinedNode ? `+ ${node.node.originalNodeCount} Modules` : node.node.label;
1589
+ const { titleAreaHeight } = node.config;
1590
+ const availableHeight = node.children && node.children.length > 0 ? titleAreaHeight - DEFAULT_RECT_GAP * 2 : h - DEFAULT_RECT_GAP * 2;
1591
+ const availableWidth = w - DEFAULT_RECT_GAP * 2;
1592
+ if (availableWidth > 0 && availableHeight > 0) {
1593
+ const config = {
1594
+ fontSize: this.config.font?.fontSize || DEFAULT_FONT_SIZE,
1595
+ family: this.config.font?.family || DEFAULT_FONT_FAMILY,
1596
+ color: this.config.font?.color || DEFAULT_FONT_COLOR
1597
+ };
1598
+ const optimalFontSize = this.caches.getOrCreate(node.node.id, ()=>evaluateOptimalFontSize(this.render.ctx, content, config, availableWidth, availableHeight));
1599
+ const font = `${optimalFontSize}px ${config.family}`;
1600
+ this.render.ctx.font = font;
1601
+ const result = getTextLayout(this.render.ctx, content, availableWidth, availableHeight);
1602
+ if (!result.valid) {
1603
+ return;
1604
+ }
1605
+ const { text } = result;
1606
+ const textX = x + Math.round(w / 2);
1607
+ const textY = y + (node.children && node.children.length > 0 ? Math.round(titleAreaHeight / 2) : Math.round(h / 2));
1608
+ const textComponent = createTitleText(text, textX, textY, font, config.color, {
1609
+ textX,
1610
+ textY
1611
+ });
1612
+ graphic.add(textComponent);
1613
+ }
1439
1614
  }
1440
- const { text } = result;
1441
- const textX = x + Math.round(w / 2);
1442
- const textY = y + (node.children && node.children.length > 0 ? Math.round(titleAreaHeight / 2) : Math.round(h / 2));
1443
- const textComponent = createTitleText(text, textX, textY, font, config.color);
1444
- this.textLayer.add(textComponent);
1445
1615
  for (const child of node.children){
1446
- this.drawText(child);
1616
+ this.drawNode(child, graphic);
1447
1617
  }
1448
1618
  }
1449
1619
  draw(flush = true, update = true) {
@@ -1464,20 +1634,14 @@ class Component extends Schedule {
1464
1634
  }
1465
1635
  }
1466
1636
  for (const node of this.layoutNodes){
1467
- this.drawBroundRect(node);
1468
- }
1469
- for (const node of this.layoutNodes){
1470
- this.drawText(node);
1637
+ this.drawNode(node, null);
1471
1638
  }
1472
- this.add(this.rectLayer, this.textLayer);
1473
1639
  if (update) {
1474
1640
  this.update();
1475
1641
  }
1476
1642
  }
1477
1643
  cleanup() {
1478
- this.remove(this.rectLayer, this.textLayer);
1479
- this.rectLayer.destory();
1480
- this.textLayer.destory();
1644
+ this.destory();
1481
1645
  }
1482
1646
  calculateLayoutNodes(data, rect, scale = 1) {
1483
1647
  const config = {
@@ -1514,8 +1678,8 @@ function evaluateOptimalFontSize(c, text, config, desiredW, desiredH) {
1514
1678
  return Math.floor(min);
1515
1679
  }
1516
1680
  function getTextLayout(c, text, width, height) {
1517
- const textWidth = c.measureText(text).width;
1518
1681
  const metrics = c.measureText(text);
1682
+ const textWidth = metrics.width;
1519
1683
  const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
1520
1684
  if (textHeight > height) {
1521
1685
  return {
@@ -1693,42 +1857,58 @@ class DOMEvent extends Event {
1693
1857
  }
1694
1858
  }
1695
1859
  dispatch(kind, e) {
1696
- const node = this.findRelativeNode(e);
1697
- this.component.pluginDriver.runHook('onDOMEventTriggered', kind, e, node, this);
1860
+ const { native } = e;
1861
+ const bbox = captureBoxXY(this.el, native, 1, 1, this.matrix.e, this.matrix.f);
1862
+ const graphic = findRelativeGraphicNode(bbox, this.component.elements);
1863
+ this.component.pluginDriver.runHook('onDOMEventTriggered', kind, e, graphic, this);
1698
1864
  this.emit('__exposed__', kind, {
1699
1865
  native: e.native,
1700
- module: node
1866
+ module: graphic
1701
1867
  });
1702
1868
  }
1703
- findRelativeNode(e) {
1704
- return findRelativeNode(captureBoxXY(this.el, e.native, 1, 1, this.matrix.e, this.matrix.f), this.component.layoutNodes);
1869
+ findRelativeGraphicNode(metadata) {
1870
+ const { native } = metadata;
1871
+ const bbox = captureBoxXY(this.el, native, 1, 1, this.matrix.e, this.matrix.f);
1872
+ return findRelativeGraphicNode(bbox, this.component.elements);
1705
1873
  }
1706
1874
  }
1707
1875
 
1876
+ exports.Box = Box;
1877
+ exports.Canvas = Canvas;
1708
1878
  exports.Component = Component;
1709
1879
  exports.DEFAULT_MATRIX_LOC = DEFAULT_MATRIX_LOC;
1710
1880
  exports.DOMEvent = DOMEvent;
1711
1881
  exports.DefaultMap = DefaultMap;
1712
1882
  exports.Event = Event;
1713
1883
  exports.PI_2 = PI_2;
1884
+ exports.Render = Render;
1885
+ exports.RoundRect = RoundRect;
1714
1886
  exports.Schedule = Schedule;
1887
+ exports.Text = Text;
1715
1888
  exports.applyCanvasTransform = applyCanvasTransform;
1716
1889
  exports.assertExists = assertExists;
1890
+ exports.asserts = asserts;
1717
1891
  exports.bindParentForModule = bindParentForModule;
1718
1892
  exports.c2m = c2m;
1719
1893
  exports.createCanvasElement = createCanvasElement;
1720
1894
  exports.createRoundBlock = createRoundBlock;
1721
1895
  exports.createTitleText = createTitleText;
1722
1896
  exports.definePlugin = definePlugin;
1897
+ exports.drawGraphIntoCanvas = drawGraphIntoCanvas;
1898
+ exports.easing = easing;
1723
1899
  exports.findRelativeNode = findRelativeNode;
1724
1900
  exports.findRelativeNodeById = findRelativeNodeById;
1725
1901
  exports.flatten = flatten;
1726
1902
  exports.getNodeDepth = getNodeDepth;
1727
1903
  exports.hashCode = hashCode;
1904
+ exports.isBox = isBox;
1728
1905
  exports.isClickEvent = isClickEvent;
1729
1906
  exports.isContextMenuEvent = isContextMenuEvent;
1907
+ exports.isGraph = isGraph;
1730
1908
  exports.isMouseEvent = isMouseEvent;
1909
+ exports.isRoundRect = isRoundRect;
1731
1910
  exports.isScrollWheelOrRightButtonOnMouseupAndDown = isScrollWheelOrRightButtonOnMouseupAndDown;
1911
+ exports.isText = isText;
1732
1912
  exports.isWheelEvent = isWheelEvent;
1733
1913
  exports.logger = logger;
1734
1914
  exports.mixin = mixin;
@@ -1739,5 +1919,7 @@ exports.smoothFrame = smoothFrame;
1739
1919
  exports.sortChildrenByKey = sortChildrenByKey;
1740
1920
  exports.stackMatrixTransform = stackMatrixTransform;
1741
1921
  exports.stackMatrixTransformWithGraphAndLayer = stackMatrixTransformWithGraphAndLayer;
1922
+ exports.traverse = traverse;
1742
1923
  exports.typedForIn = typedForIn;
1743
1924
  exports.visit = visit;
1925
+ exports.writeBoundingRectForCanvas = writeBoundingRectForCanvas;