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.
@@ -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
- constructor(){
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.parent) ;
383
- this.elements.push(element);
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
- getOrInsert(key, value) {
867
+ getOrCreate(key, value) {
800
868
  if (!super.has(key)) {
801
- const defaultValue = value || this.defaultFactory();
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
- // First cleanup canvas
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
- const cap = elements.length;
879
- for(let i = 0; i < cap; i++){
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
- ctx.restore();
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
- this.render.clear(this.render.options.width, this.render.options.height);
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
- const matrix = this.matrix.create({
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, matrix, this.render.options.devicePixelRatio);
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
- // execute all graph elements
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
- if (d.children) {
1015
- const result = visit(d.children, fn);
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
- drawBroundRect(node) {
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
- this.rectLayer.add(rect);
1410
- for (const child of node.children){
1411
- this.drawBroundRect(child);
1412
- }
1413
- }
1414
- drawText(node) {
1415
- if (!node.node.label && !node.node.isCombinedNode) {
1416
- return;
1417
- }
1418
- const [x, y, w, h] = node.layout;
1419
- const { titleAreaHeight } = node.config;
1420
- const content = node.node.isCombinedNode ? `+ ${node.node.originalNodeCount} Modules` : node.node.label;
1421
- const availableHeight = node.children && node.children.length > 0 ? titleAreaHeight - DEFAULT_RECT_GAP * 2 : h - DEFAULT_RECT_GAP * 2;
1422
- const availableWidth = w - DEFAULT_RECT_GAP * 2;
1423
- if (availableWidth <= 0 || availableHeight <= 0) {
1424
- return;
1425
- }
1426
- const config = {
1427
- fontSize: this.config.font?.fontSize || DEFAULT_FONT_SIZE,
1428
- family: this.config.font?.family || DEFAULT_FONT_FAMILY,
1429
- color: this.config.font?.color || DEFAULT_FONT_COLOR
1430
- };
1431
- const optimalFontSize = this.caches.getOrInsert(node.node.id, evaluateOptimalFontSize(this.render.ctx, content, config, availableWidth, availableHeight));
1432
- const font = `${optimalFontSize}px ${config.family}`;
1433
- this.render.ctx.font = font;
1434
- const result = getTextLayout(this.render.ctx, content, availableWidth, availableHeight);
1435
- if (!result.valid) {
1436
- return;
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.drawText(child);
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.drawBroundRect(node);
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.remove(this.rectLayer, this.textLayer);
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 node = this.findRelativeNode(e);
1695
- this.component.pluginDriver.runHook('onDOMEventTriggered', kind, e, node, 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: node
1864
+ module: graphic
1699
1865
  });
1700
1866
  }
1701
- findRelativeNode(e) {
1702
- return findRelativeNode(captureBoxXY(this.el, e.native, 1, 1, this.matrix.e, this.matrix.f), this.component.layoutNodes);
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 { stackMatrixTransformWithGraphAndLayer as A, smoothFrame as B, Component as C, DOMEvent as D, Event as E, isScrollWheelOrRightButtonOnMouseupAndDown as F, DefaultMap as G, DEFAULT_MATRIX_LOC as H, PI_2 as P, Schedule as S, 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, hashCode as o, perferNumeric as p, noop as q, createRoundBlock as r, sortChildrenByKey as s, createTitleText as t, raf as u, visit as v, createCanvasElement as w, applyCanvasTransform as x, typedForIn as y, stackMatrixTransform as z };
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 };