polly-graph 0.1.14 → 0.1.16

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.cjs CHANGED
@@ -4761,7 +4761,18 @@ function getShortenedSourcePoint(link, style) {
4761
4761
  const dx = targetX - sourceX;
4762
4762
  const dy = targetY - sourceY;
4763
4763
  const distance = Math.sqrt(dx * dx + dy * dy) || 1;
4764
- const sourceRadius = source.style?.radius ?? 12;
4764
+ let sourceRadius = source.style?.radius ?? 12;
4765
+ if (typeof document !== "undefined") {
4766
+ const circles = Array.from(document.querySelectorAll("circle"));
4767
+ for (const circle of circles) {
4768
+ const boundData = circle.__data__;
4769
+ if (boundData && boundData.id === source.id) {
4770
+ const currentRadius = parseFloat(circle.getAttribute("r") || "12");
4771
+ sourceRadius = currentRadius;
4772
+ break;
4773
+ }
4774
+ }
4775
+ }
4765
4776
  const sourceStrokeWidth = source.style?.strokeWidth ?? 1.5;
4766
4777
  const linkStrokeCompensation = style.strokeWidth / 2;
4767
4778
  const nodeStrokeOffset = sourceStrokeWidth / 2;
@@ -4782,7 +4793,18 @@ function getShortenedTargetPoint(link, style) {
4782
4793
  const dx = targetX - sourceX;
4783
4794
  const dy = targetY - sourceY;
4784
4795
  const distance = Math.sqrt(dx * dx + dy * dy) || 1;
4785
- const targetRadius = target.style?.radius ?? 12;
4796
+ let targetRadius = target.style?.radius ?? 12;
4797
+ if (typeof document !== "undefined") {
4798
+ const circles = Array.from(document.querySelectorAll("circle"));
4799
+ for (const circle of circles) {
4800
+ const boundData = circle.__data__;
4801
+ if (boundData && boundData.id === target.id) {
4802
+ const currentRadius = parseFloat(circle.getAttribute("r") || "12");
4803
+ targetRadius = currentRadius;
4804
+ break;
4805
+ }
4806
+ }
4807
+ }
4786
4808
  const targetStrokeWidth = target.style?.strokeWidth ?? 1.5;
4787
4809
  const arrowLength = style.arrow.enabled ? style.arrow.size * 2 : 0;
4788
4810
  const linkStrokeCompensation = style.strokeWidth / 2;
@@ -4868,10 +4890,7 @@ function renderLinkLabels(params, links) {
4868
4890
  const labelSelection = params.root.select('[data-layer="link-labels"]').selectAll(".link-label").data(renderableLinks, (item) => getLinkKey2(item.link)).join("g").attr("class", "link-label").style("opacity", (item) => {
4869
4891
  const visibility = item.style.label.visibility ?? "always";
4870
4892
  return visibility === "always" ? 1 : 0;
4871
- }).style("pointer-events", (item) => {
4872
- const visibility = item.style.label.visibility ?? "always";
4873
- return visibility === "always" ? "auto" : "none";
4874
- }).style("cursor", "pointer");
4893
+ }).style("pointer-events", "none").style("cursor", "pointer");
4875
4894
  labelSelection.selectAll("rect").data((item) => [item]).join("rect").attr("rx", (item) => item.style.label.borderRadius).attr("ry", (item) => item.style.label.borderRadius).attr("fill", (item) => item.style.label.backgroundFill).attr("stroke", (item) => item.style.label.borderColor).attr("stroke-width", (item) => item.style.label.borderWidth);
4876
4895
  const textSelection = labelSelection.selectAll("text").data((item) => [item]).join("text").attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("font-size", (item) => item.style.label.fontSize).attr("fill", (item) => item.style.label.textColor).text((item) => item.link.label ?? "");
4877
4896
  textSelection.each(function(item) {
@@ -5410,48 +5429,38 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5410
5429
  const svgElement = firstNode.ownerSVGElement;
5411
5430
  if (!svgElement) return;
5412
5431
  const root2 = select_default2(svgElement);
5432
+ const elevatedElements = /* @__PURE__ */ new Set();
5413
5433
  function clearAllHoverLayers() {
5414
- const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
5415
- const nodesLayer = root2.select('[data-layer="nodes"]').node();
5416
- if (hoverNodesLayer && nodesLayer) {
5417
- while (hoverNodesLayer.firstChild) {
5418
- nodesLayer.appendChild(hoverNodesLayer.firstChild);
5419
- }
5420
- }
5421
- const hoverNodeLabelsLayer = root2.select('[data-layer="hover-node-labels"]').node();
5422
- const nodeLabelsLayer = root2.select('[data-layer="node-labels"]').node();
5423
- if (hoverNodeLabelsLayer && nodeLabelsLayer) {
5424
- while (hoverNodeLabelsLayer.firstChild) {
5425
- nodeLabelsLayer.appendChild(hoverNodeLabelsLayer.firstChild);
5426
- }
5427
- }
5428
- const hoverLinksLayer = root2.select('[data-layer="hover-links"]').node();
5429
- const linksLayer = root2.select('[data-layer="links"]').node();
5430
- if (hoverLinksLayer && linksLayer) {
5431
- while (hoverLinksLayer.firstChild) {
5432
- const linkElement = hoverLinksLayer.firstChild;
5433
- linksLayer.appendChild(linkElement);
5434
- const event = new MouseEvent("mouseleave", {
5435
- bubbles: true,
5436
- cancelable: false,
5437
- view: window
5438
- });
5439
- linkElement.dispatchEvent(event);
5440
- }
5441
- }
5442
- const hoverLinkLabelsLayer = root2.select('[data-layer="hover-link-labels"]').node();
5443
- const linkLabelsLayer = root2.select('[data-layer="link-labels"]').node();
5444
- if (hoverLinkLabelsLayer && linkLabelsLayer) {
5445
- while (hoverLinkLabelsLayer.firstChild) {
5446
- const labelElement = hoverLinkLabelsLayer.firstChild;
5447
- const labelData = labelElement.__data__;
5448
- if (labelData && labelData.style.label.visibility === "hover" && !labelElement.classList.contains("label-selection-pinned")) {
5449
- labelElement.style.opacity = "0";
5450
- labelElement.style.pointerEvents = "none";
5434
+ elevatedElements.forEach((element) => {
5435
+ element.classList.remove("pg-hover-elevated");
5436
+ element.style.removeProperty("filter");
5437
+ if (element.tagName === "circle") {
5438
+ element.removeAttribute("data-hover-elevated");
5439
+ }
5440
+ if (element.classList.contains("link-label")) {
5441
+ const labelData = element.__data__;
5442
+ if (labelData && labelData.style.label.visibility === "hover" && !element.classList.contains("label-selection-pinned")) {
5443
+ element.style.opacity = "0";
5444
+ element.style.pointerEvents = "none";
5451
5445
  }
5452
- linkLabelsLayer.appendChild(labelElement);
5453
5446
  }
5454
- }
5447
+ });
5448
+ elevatedElements.clear();
5449
+ root2.selectAll("line[data-hover-elevated]").each(function() {
5450
+ const linkElement = this;
5451
+ linkElement.removeAttribute("data-hover-elevated");
5452
+ const event = new MouseEvent("mouseleave", {
5453
+ bubbles: true,
5454
+ cancelable: false,
5455
+ view: window
5456
+ });
5457
+ linkElement.dispatchEvent(event);
5458
+ });
5459
+ }
5460
+ function elevateElement(element) {
5461
+ element.classList.add("pg-hover-elevated");
5462
+ element.style.filter = "drop-shadow(0 2px 4px rgba(0,0,0,0.15))";
5463
+ elevatedElements.add(element);
5455
5464
  }
5456
5465
  nodeSelection.on("mouseenter.links", function(_event, hoveredNode) {
5457
5466
  const hoveredNodeElement = this;
@@ -5462,16 +5471,11 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5462
5471
  return;
5463
5472
  }
5464
5473
  clearAllHoverLayers();
5465
- const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
5466
- if (hoverNodesLayer) {
5467
- hoverNodesLayer.appendChild(hoveredNodeElement);
5468
- }
5474
+ elevateElement(hoveredNodeElement);
5475
+ hoveredNodeElement.setAttribute("data-hover-elevated", "true");
5469
5476
  root2.selectAll("text").filter((d) => d.id === hoveredNode.id).each(function() {
5470
5477
  const labelElement = this;
5471
- const hoverNodeLabelsLayer = root2.select('[data-layer="hover-node-labels"]').node();
5472
- if (hoverNodeLabelsLayer) {
5473
- hoverNodeLabelsLayer.appendChild(labelElement);
5474
- }
5478
+ elevateElement(labelElement);
5475
5479
  });
5476
5480
  const connectedLinks = root2.selectAll("line:not(.link-hit-area)").filter((renderableLink) => {
5477
5481
  const source = renderableLink.link.source;
@@ -5480,10 +5484,8 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5480
5484
  });
5481
5485
  connectedLinks.each(function(_renderableLink) {
5482
5486
  const linkElement = this;
5483
- const hoverLinksLayer = root2.select('[data-layer="hover-links"]').node();
5484
- if (hoverLinksLayer) {
5485
- hoverLinksLayer.appendChild(linkElement);
5486
- }
5487
+ elevateElement(linkElement);
5488
+ linkElement.setAttribute("data-hover-elevated", "true");
5487
5489
  const event = new MouseEvent("mouseenter", {
5488
5490
  bubbles: true,
5489
5491
  cancelable: false,
@@ -5497,13 +5499,10 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5497
5499
  return source.id === hoveredNode.id || target.id === hoveredNode.id;
5498
5500
  }).each(function(item) {
5499
5501
  const labelElement = this;
5500
- const hoverLinkLabelsLayer = root2.select('[data-layer="hover-link-labels"]').node();
5501
- if (hoverLinkLabelsLayer) {
5502
- hoverLinkLabelsLayer.appendChild(labelElement);
5503
- if (item.style.label.visibility === "hover") {
5504
- labelElement.style.opacity = "1";
5505
- labelElement.style.pointerEvents = "auto";
5506
- }
5502
+ elevateElement(labelElement);
5503
+ if (item.style.label.visibility === "hover") {
5504
+ labelElement.style.opacity = "1";
5505
+ labelElement.style.pointerEvents = "auto";
5507
5506
  }
5508
5507
  });
5509
5508
  }).on("mouseleave.links", function(_event, _hoveredNode) {
@@ -5579,7 +5578,7 @@ function createLinkHover(linkSelection, hoverStyle) {
5579
5578
  }
5580
5579
  }
5581
5580
  const labelSelection2 = root2.select('[data-layer="link-labels"]').selectAll(".link-label");
5582
- labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1).style("pointer-events", "auto");
5581
+ labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1);
5583
5582
  }).on("mouseleave.hover", function(_event, renderableLink) {
5584
5583
  const hoveredElement = this;
5585
5584
  let targetLinkElement;
@@ -5876,7 +5875,55 @@ function getDefaultContent(node) {
5876
5875
 
5877
5876
  // src/utils/node-link-selection.utils.ts
5878
5877
  function createLinkHitArea(root2, linkSelection) {
5879
- return root2.select('[data-layer="links"]').selectAll("line.link-hit-area").data(linkSelection.data()).join("line").attr("class", "link-hit-area").attr("stroke", "rgba(0,0,0,0)").attr("stroke-width", (item) => item.style.arrow.size * 4).style("pointer-events", "stroke").style("cursor", "pointer").attr("opacity", 0);
5878
+ return root2.select('[data-layer="links"]').selectAll("rect.link-hit-area").data(linkSelection.data()).join("rect").attr("class", "link-hit-area").attr("fill", "rgba(0,0,0,0)").style("pointer-events", "fill").style("cursor", "pointer").attr("opacity", 0).each(function(item) {
5879
+ const rectElement = this;
5880
+ updateHitAreaDimensions(rectElement, item, root2);
5881
+ });
5882
+ }
5883
+ function updateHitAreaDimensions(rectElement, item, root2) {
5884
+ const source = item.link.source;
5885
+ const target = item.link.target;
5886
+ if (!source.x || !source.y || !target.x || !target.y) return;
5887
+ const dx = target.x - source.x;
5888
+ const dy = target.y - source.y;
5889
+ const linkLength = Math.sqrt(dx * dx + dy * dy);
5890
+ const angle = Math.atan2(dy, dx);
5891
+ const midX = (source.x + target.x) / 2;
5892
+ const midY = (source.y + target.y) / 2;
5893
+ const thickness = Math.max((item.style.strokeWidth || 2) * 4, item.style.arrow.size * 2, 20);
5894
+ let length = linkLength + item.style.arrow.size * 2;
5895
+ let width = thickness;
5896
+ if (item.link.label) {
5897
+ const labelElement = root2.select('[data-layer="link-labels"]').selectAll(".link-label").filter((labelItem) => labelItem.link === item.link).node();
5898
+ if (labelElement) {
5899
+ try {
5900
+ const textElement = labelElement.querySelector("text");
5901
+ const rectElement2 = labelElement.querySelector("rect");
5902
+ if (textElement && rectElement2) {
5903
+ const bbox = textElement.getBBox();
5904
+ const labelWidth = bbox.width + item.style.label.paddingX * 2;
5905
+ const labelHeight = bbox.height + item.style.label.paddingY * 2;
5906
+ width = Math.max(width, labelHeight + 10);
5907
+ length = Math.max(length, labelWidth + 20);
5908
+ }
5909
+ } catch {
5910
+ const text = item.link.label ?? "";
5911
+ const fontSize = item.style.label.fontSize;
5912
+ const estimatedWidth = text.length * fontSize * 0.6 + item.style.label.paddingX * 2 + 20;
5913
+ const estimatedHeight = fontSize + item.style.label.paddingY * 2 + 10;
5914
+ width = Math.max(width, estimatedHeight);
5915
+ length = Math.max(length, estimatedWidth);
5916
+ }
5917
+ }
5918
+ }
5919
+ const rectX = midX - length / 2;
5920
+ const rectY = midY - width / 2;
5921
+ rectElement.setAttribute("width", String(length));
5922
+ rectElement.setAttribute("height", String(width));
5923
+ rectElement.setAttribute("x", String(rectX));
5924
+ rectElement.setAttribute("y", String(rectY));
5925
+ const degrees2 = angle * 180 / Math.PI;
5926
+ rectElement.setAttribute("transform", `rotate(${degrees2}, ${midX}, ${midY})`);
5880
5927
  }
5881
5928
 
5882
5929
  // src/utils/get-link-target-point.ts
@@ -6115,7 +6162,10 @@ var SelectionManager = class {
6115
6162
  if (style.stroke !== void 0) nodeElement.style.stroke = style.stroke;
6116
6163
  if (style.strokeWidth !== void 0) nodeElement.style.strokeWidth = String(style.strokeWidth);
6117
6164
  if (style.opacity !== void 0) nodeElement.style.opacity = String(style.opacity);
6118
- if (style.radius !== void 0) nodeElement.setAttribute("r", String(style.radius));
6165
+ if (style.radius !== void 0) {
6166
+ nodeElement.setAttribute("r", String(style.radius));
6167
+ this.updateConnectedLinkPositions(nodeData);
6168
+ }
6119
6169
  }
6120
6170
  this.root.selectAll(".link-label").filter((item) => {
6121
6171
  if (item.style.label.visibility !== "hover") return false;
@@ -6172,6 +6222,7 @@ var SelectionManager = class {
6172
6222
  element.style.opacity = "";
6173
6223
  const originalRadius = data.style?.radius ?? 8;
6174
6224
  element.setAttribute("r", String(originalRadius));
6225
+ this.updateConnectedLinkPositions(data);
6175
6226
  delete element.dataset.selected;
6176
6227
  this.root.selectAll(".link-label.label-selection-pinned").classed("label-selection-pinned", false).interrupt().transition().duration(200).style("opacity", 0).style("pointer-events", "none");
6177
6228
  this.state.selectedNode = null;
@@ -6184,7 +6235,7 @@ var SelectionManager = class {
6184
6235
  if (!this.state.selectedLink) return;
6185
6236
  const { element, data, originalMarker } = this.state.selectedLink;
6186
6237
  this.layers.links.appendChild(element);
6187
- this.root.selectAll(".link-label").filter((item) => item.link === data).each((d, i, nodes) => {
6238
+ this.root.selectAll(".link-label").filter((item) => item.link === data).each((_, i, nodes) => {
6188
6239
  const element2 = nodes[i];
6189
6240
  if (element2) {
6190
6241
  this.layers.linkLabels.appendChild(element2);
@@ -6254,13 +6305,13 @@ var SelectionManager = class {
6254
6305
  const target = d.link.target;
6255
6306
  return source.id === nodeData.id || target.id === nodeData.id;
6256
6307
  });
6257
- connectedLinks.each((d, i, nodes) => {
6308
+ connectedLinks.each((_, i, nodes) => {
6258
6309
  const element = nodes[i];
6259
6310
  if (element) {
6260
6311
  this.layers.selectionLayer.links.appendChild(element);
6261
6312
  }
6262
6313
  });
6263
- this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6314
+ this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6264
6315
  const element = nodes[i];
6265
6316
  if (element) {
6266
6317
  this.layers.selectionLayer.nodeLabels.appendChild(element);
@@ -6270,7 +6321,7 @@ var SelectionManager = class {
6270
6321
  const source = item.link.source;
6271
6322
  const target = item.link.target;
6272
6323
  return source.id === nodeData.id || target.id === nodeData.id;
6273
- }).each((d, i, nodes) => {
6324
+ }).each((_, i, nodes) => {
6274
6325
  const element = nodes[i];
6275
6326
  if (element) {
6276
6327
  this.layers.selectionLayer.linkLabels.appendChild(element);
@@ -6282,7 +6333,7 @@ var SelectionManager = class {
6282
6333
  */
6283
6334
  bringLinkToFront(linkElement, renderableLink) {
6284
6335
  this.layers.selectionLayer.links.appendChild(linkElement);
6285
- this.root.selectAll(".link-label").filter((item) => item.link === renderableLink.link).each((d, i, nodes) => {
6336
+ this.root.selectAll(".link-label").filter((item) => item.link === renderableLink.link).each((_, i, nodes) => {
6286
6337
  const element = nodes[i];
6287
6338
  if (element) {
6288
6339
  this.layers.selectionLayer.linkLabels.appendChild(element);
@@ -6293,7 +6344,7 @@ var SelectionManager = class {
6293
6344
  * Restore elements back to their original layers
6294
6345
  */
6295
6346
  restoreSelectedElements(nodeData) {
6296
- this.root.selectAll("circle").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6347
+ this.root.selectAll("circle").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6297
6348
  const element = nodes[i];
6298
6349
  if (element) {
6299
6350
  this.layers.nodes.appendChild(element);
@@ -6303,13 +6354,13 @@ var SelectionManager = class {
6303
6354
  const source = d.link.source;
6304
6355
  const target = d.link.target;
6305
6356
  return source.id === nodeData.id || target.id === nodeData.id;
6306
- }).each((d, i, nodes) => {
6357
+ }).each((_, i, nodes) => {
6307
6358
  const element = nodes[i];
6308
6359
  if (element) {
6309
6360
  this.layers.links.appendChild(element);
6310
6361
  }
6311
6362
  });
6312
- this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6363
+ this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6313
6364
  const element = nodes[i];
6314
6365
  if (element) {
6315
6366
  this.layers.nodeLabels.appendChild(element);
@@ -6319,22 +6370,13 @@ var SelectionManager = class {
6319
6370
  const source = item.link.source;
6320
6371
  const target = item.link.target;
6321
6372
  return source.id === nodeData.id || target.id === nodeData.id;
6322
- }).each((d, i, nodes) => {
6373
+ }).each((_, i, nodes) => {
6323
6374
  const element = nodes[i];
6324
6375
  if (element) {
6325
6376
  this.layers.linkLabels.appendChild(element);
6326
6377
  }
6327
6378
  });
6328
6379
  }
6329
- /**
6330
- * Utility method to bring any SVG element to front using appendChild
6331
- * Based on the reference implementation pattern
6332
- */
6333
- bringElementToFront(element) {
6334
- if (element.parentNode) {
6335
- element.parentNode.appendChild(element);
6336
- }
6337
- }
6338
6380
  /**
6339
6381
  * Clear hover state to prevent conflicts with selection
6340
6382
  * Similar to the clearAllHoverLayers function in create-node-hover.ts
@@ -6382,6 +6424,25 @@ var SelectionManager = class {
6382
6424
  }
6383
6425
  }
6384
6426
  }
6427
+ /**
6428
+ * Immediately update positions of links connected to the specified node
6429
+ * This ensures arrowheads reposition correctly when node radius changes
6430
+ */
6431
+ updateConnectedLinkPositions(nodeData) {
6432
+ this.root.selectAll("line:not(.link-hit-area)").filter((renderableLink) => {
6433
+ const source = renderableLink.link.source;
6434
+ const target = renderableLink.link.target;
6435
+ return source.id === nodeData.id || target.id === nodeData.id;
6436
+ }).each(function(item) {
6437
+ const linkElement = this;
6438
+ const sourcePoint = getShortenedSourcePoint(item.link, item.style);
6439
+ const targetPoint = getShortenedTargetPoint(item.link, item.style);
6440
+ linkElement.setAttribute("x1", String(sourcePoint.x));
6441
+ linkElement.setAttribute("y1", String(sourcePoint.y));
6442
+ linkElement.setAttribute("x2", String(targetPoint.x));
6443
+ linkElement.setAttribute("y2", String(targetPoint.y));
6444
+ });
6445
+ }
6385
6446
  /**
6386
6447
  * Clean up resources
6387
6448
  */
@@ -6548,6 +6609,13 @@ var InteractionManager = class {
6548
6609
  const nodeElement = event.currentTarget;
6549
6610
  this.manager.selectionManager?.selectNode(nodeElement, node);
6550
6611
  });
6612
+ selections.linkSelection.on("click.select", (event, renderableLinkData) => {
6613
+ event.stopPropagation();
6614
+ const linkElement = event.currentTarget;
6615
+ if (this.manager.selectionManager) {
6616
+ this.manager.selectionManager.selectLink(linkElement, renderableLinkData, event);
6617
+ }
6618
+ });
6551
6619
  selections.linkLabelSelection.on("click.select", (event, renderableLinkLabel) => {
6552
6620
  event.stopPropagation();
6553
6621
  const correspondingLink = selections.linkSelection.filter((d) => d.link === renderableLinkLabel.link).node();
@@ -6588,7 +6656,23 @@ var InteractionManager = class {
6588
6656
  }
6589
6657
  if (this.manager.simulation) {
6590
6658
  this.manager.simulation.on("tick.hitarea", () => {
6591
- linkHitAreaSelection.attr("x1", (item) => item.link.source.x ?? 0).attr("y1", (item) => item.link.source.y ?? 0).attr("x2", (item) => item.link.target.x ?? 0).attr("y2", (item) => item.link.target.y ?? 0);
6659
+ linkHitAreaSelection.each(function(item) {
6660
+ const source = item.link.source;
6661
+ const target = item.link.target;
6662
+ if (!source.x || !source.y || !target.x || !target.y) return;
6663
+ const rectElement = this;
6664
+ const dx = target.x - source.x;
6665
+ const dy = target.y - source.y;
6666
+ const angle = Math.atan2(dy, dx);
6667
+ const midX = (source.x + target.x) / 2;
6668
+ const midY = (source.y + target.y) / 2;
6669
+ const width = parseFloat(rectElement.getAttribute("width") || "20");
6670
+ const height = parseFloat(rectElement.getAttribute("height") || "20");
6671
+ rectElement.setAttribute("x", String(midX - width / 2));
6672
+ rectElement.setAttribute("y", String(midY - height / 2));
6673
+ const degrees2 = angle * 180 / Math.PI;
6674
+ rectElement.setAttribute("transform", `rotate(${degrees2}, ${midX}, ${midY})`);
6675
+ });
6592
6676
  });
6593
6677
  }
6594
6678
  if (this.manager.selectionManager) {
package/dist/index.css CHANGED
@@ -320,5 +320,19 @@
320
320
  cursor: pointer;
321
321
  transition: stroke-opacity 0.2s ease;
322
322
  }
323
+ .pg-hover-elevated {
324
+ paint-order: fill stroke markers;
325
+ transition: filter 0.15s ease-in-out;
326
+ }
327
+ .pg-hover-elevated.pg-layer-nodes circle,
328
+ .pg-hover-elevated[data-hover-elevated] {
329
+ paint-order: stroke fill markers;
330
+ }
331
+ svg .pg-hover-elevated {
332
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
333
+ }
334
+ [data-hover-elevated=true] {
335
+ opacity: 1 !important;
336
+ }
323
337
 
324
338
  /* src/styles/main.css */
package/dist/index.d.cts CHANGED
@@ -616,16 +616,16 @@ declare class SelectionManager {
616
616
  * Restore elements back to their original layers
617
617
  */
618
618
  private restoreSelectedElements;
619
- /**
620
- * Utility method to bring any SVG element to front using appendChild
621
- * Based on the reference implementation pattern
622
- */
623
- private bringElementToFront;
624
619
  /**
625
620
  * Clear hover state to prevent conflicts with selection
626
621
  * Similar to the clearAllHoverLayers function in create-node-hover.ts
627
622
  */
628
623
  private clearHoverState;
624
+ /**
625
+ * Immediately update positions of links connected to the specified node
626
+ * This ensures arrowheads reposition correctly when node radius changes
627
+ */
628
+ private updateConnectedLinkPositions;
629
629
  /**
630
630
  * Clean up resources
631
631
  */
package/dist/index.d.ts CHANGED
@@ -616,16 +616,16 @@ declare class SelectionManager {
616
616
  * Restore elements back to their original layers
617
617
  */
618
618
  private restoreSelectedElements;
619
- /**
620
- * Utility method to bring any SVG element to front using appendChild
621
- * Based on the reference implementation pattern
622
- */
623
- private bringElementToFront;
624
619
  /**
625
620
  * Clear hover state to prevent conflicts with selection
626
621
  * Similar to the clearAllHoverLayers function in create-node-hover.ts
627
622
  */
628
623
  private clearHoverState;
624
+ /**
625
+ * Immediately update positions of links connected to the specified node
626
+ * This ensures arrowheads reposition correctly when node radius changes
627
+ */
628
+ private updateConnectedLinkPositions;
629
629
  /**
630
630
  * Clean up resources
631
631
  */
package/dist/index.js CHANGED
@@ -4729,7 +4729,18 @@ function getShortenedSourcePoint(link, style) {
4729
4729
  const dx = targetX - sourceX;
4730
4730
  const dy = targetY - sourceY;
4731
4731
  const distance = Math.sqrt(dx * dx + dy * dy) || 1;
4732
- const sourceRadius = source.style?.radius ?? 12;
4732
+ let sourceRadius = source.style?.radius ?? 12;
4733
+ if (typeof document !== "undefined") {
4734
+ const circles = Array.from(document.querySelectorAll("circle"));
4735
+ for (const circle of circles) {
4736
+ const boundData = circle.__data__;
4737
+ if (boundData && boundData.id === source.id) {
4738
+ const currentRadius = parseFloat(circle.getAttribute("r") || "12");
4739
+ sourceRadius = currentRadius;
4740
+ break;
4741
+ }
4742
+ }
4743
+ }
4733
4744
  const sourceStrokeWidth = source.style?.strokeWidth ?? 1.5;
4734
4745
  const linkStrokeCompensation = style.strokeWidth / 2;
4735
4746
  const nodeStrokeOffset = sourceStrokeWidth / 2;
@@ -4750,7 +4761,18 @@ function getShortenedTargetPoint(link, style) {
4750
4761
  const dx = targetX - sourceX;
4751
4762
  const dy = targetY - sourceY;
4752
4763
  const distance = Math.sqrt(dx * dx + dy * dy) || 1;
4753
- const targetRadius = target.style?.radius ?? 12;
4764
+ let targetRadius = target.style?.radius ?? 12;
4765
+ if (typeof document !== "undefined") {
4766
+ const circles = Array.from(document.querySelectorAll("circle"));
4767
+ for (const circle of circles) {
4768
+ const boundData = circle.__data__;
4769
+ if (boundData && boundData.id === target.id) {
4770
+ const currentRadius = parseFloat(circle.getAttribute("r") || "12");
4771
+ targetRadius = currentRadius;
4772
+ break;
4773
+ }
4774
+ }
4775
+ }
4754
4776
  const targetStrokeWidth = target.style?.strokeWidth ?? 1.5;
4755
4777
  const arrowLength = style.arrow.enabled ? style.arrow.size * 2 : 0;
4756
4778
  const linkStrokeCompensation = style.strokeWidth / 2;
@@ -4836,10 +4858,7 @@ function renderLinkLabels(params, links) {
4836
4858
  const labelSelection = params.root.select('[data-layer="link-labels"]').selectAll(".link-label").data(renderableLinks, (item) => getLinkKey2(item.link)).join("g").attr("class", "link-label").style("opacity", (item) => {
4837
4859
  const visibility = item.style.label.visibility ?? "always";
4838
4860
  return visibility === "always" ? 1 : 0;
4839
- }).style("pointer-events", (item) => {
4840
- const visibility = item.style.label.visibility ?? "always";
4841
- return visibility === "always" ? "auto" : "none";
4842
- }).style("cursor", "pointer");
4861
+ }).style("pointer-events", "none").style("cursor", "pointer");
4843
4862
  labelSelection.selectAll("rect").data((item) => [item]).join("rect").attr("rx", (item) => item.style.label.borderRadius).attr("ry", (item) => item.style.label.borderRadius).attr("fill", (item) => item.style.label.backgroundFill).attr("stroke", (item) => item.style.label.borderColor).attr("stroke-width", (item) => item.style.label.borderWidth);
4844
4863
  const textSelection = labelSelection.selectAll("text").data((item) => [item]).join("text").attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("font-size", (item) => item.style.label.fontSize).attr("fill", (item) => item.style.label.textColor).text((item) => item.link.label ?? "");
4845
4864
  textSelection.each(function(item) {
@@ -5378,48 +5397,38 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5378
5397
  const svgElement = firstNode.ownerSVGElement;
5379
5398
  if (!svgElement) return;
5380
5399
  const root2 = select_default2(svgElement);
5400
+ const elevatedElements = /* @__PURE__ */ new Set();
5381
5401
  function clearAllHoverLayers() {
5382
- const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
5383
- const nodesLayer = root2.select('[data-layer="nodes"]').node();
5384
- if (hoverNodesLayer && nodesLayer) {
5385
- while (hoverNodesLayer.firstChild) {
5386
- nodesLayer.appendChild(hoverNodesLayer.firstChild);
5387
- }
5388
- }
5389
- const hoverNodeLabelsLayer = root2.select('[data-layer="hover-node-labels"]').node();
5390
- const nodeLabelsLayer = root2.select('[data-layer="node-labels"]').node();
5391
- if (hoverNodeLabelsLayer && nodeLabelsLayer) {
5392
- while (hoverNodeLabelsLayer.firstChild) {
5393
- nodeLabelsLayer.appendChild(hoverNodeLabelsLayer.firstChild);
5394
- }
5395
- }
5396
- const hoverLinksLayer = root2.select('[data-layer="hover-links"]').node();
5397
- const linksLayer = root2.select('[data-layer="links"]').node();
5398
- if (hoverLinksLayer && linksLayer) {
5399
- while (hoverLinksLayer.firstChild) {
5400
- const linkElement = hoverLinksLayer.firstChild;
5401
- linksLayer.appendChild(linkElement);
5402
- const event = new MouseEvent("mouseleave", {
5403
- bubbles: true,
5404
- cancelable: false,
5405
- view: window
5406
- });
5407
- linkElement.dispatchEvent(event);
5408
- }
5409
- }
5410
- const hoverLinkLabelsLayer = root2.select('[data-layer="hover-link-labels"]').node();
5411
- const linkLabelsLayer = root2.select('[data-layer="link-labels"]').node();
5412
- if (hoverLinkLabelsLayer && linkLabelsLayer) {
5413
- while (hoverLinkLabelsLayer.firstChild) {
5414
- const labelElement = hoverLinkLabelsLayer.firstChild;
5415
- const labelData = labelElement.__data__;
5416
- if (labelData && labelData.style.label.visibility === "hover" && !labelElement.classList.contains("label-selection-pinned")) {
5417
- labelElement.style.opacity = "0";
5418
- labelElement.style.pointerEvents = "none";
5402
+ elevatedElements.forEach((element) => {
5403
+ element.classList.remove("pg-hover-elevated");
5404
+ element.style.removeProperty("filter");
5405
+ if (element.tagName === "circle") {
5406
+ element.removeAttribute("data-hover-elevated");
5407
+ }
5408
+ if (element.classList.contains("link-label")) {
5409
+ const labelData = element.__data__;
5410
+ if (labelData && labelData.style.label.visibility === "hover" && !element.classList.contains("label-selection-pinned")) {
5411
+ element.style.opacity = "0";
5412
+ element.style.pointerEvents = "none";
5419
5413
  }
5420
- linkLabelsLayer.appendChild(labelElement);
5421
5414
  }
5422
- }
5415
+ });
5416
+ elevatedElements.clear();
5417
+ root2.selectAll("line[data-hover-elevated]").each(function() {
5418
+ const linkElement = this;
5419
+ linkElement.removeAttribute("data-hover-elevated");
5420
+ const event = new MouseEvent("mouseleave", {
5421
+ bubbles: true,
5422
+ cancelable: false,
5423
+ view: window
5424
+ });
5425
+ linkElement.dispatchEvent(event);
5426
+ });
5427
+ }
5428
+ function elevateElement(element) {
5429
+ element.classList.add("pg-hover-elevated");
5430
+ element.style.filter = "drop-shadow(0 2px 4px rgba(0,0,0,0.15))";
5431
+ elevatedElements.add(element);
5423
5432
  }
5424
5433
  nodeSelection.on("mouseenter.links", function(_event, hoveredNode) {
5425
5434
  const hoveredNodeElement = this;
@@ -5430,16 +5439,11 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5430
5439
  return;
5431
5440
  }
5432
5441
  clearAllHoverLayers();
5433
- const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
5434
- if (hoverNodesLayer) {
5435
- hoverNodesLayer.appendChild(hoveredNodeElement);
5436
- }
5442
+ elevateElement(hoveredNodeElement);
5443
+ hoveredNodeElement.setAttribute("data-hover-elevated", "true");
5437
5444
  root2.selectAll("text").filter((d) => d.id === hoveredNode.id).each(function() {
5438
5445
  const labelElement = this;
5439
- const hoverNodeLabelsLayer = root2.select('[data-layer="hover-node-labels"]').node();
5440
- if (hoverNodeLabelsLayer) {
5441
- hoverNodeLabelsLayer.appendChild(labelElement);
5442
- }
5446
+ elevateElement(labelElement);
5443
5447
  });
5444
5448
  const connectedLinks = root2.selectAll("line:not(.link-hit-area)").filter((renderableLink) => {
5445
5449
  const source = renderableLink.link.source;
@@ -5448,10 +5452,8 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5448
5452
  });
5449
5453
  connectedLinks.each(function(_renderableLink) {
5450
5454
  const linkElement = this;
5451
- const hoverLinksLayer = root2.select('[data-layer="hover-links"]').node();
5452
- if (hoverLinksLayer) {
5453
- hoverLinksLayer.appendChild(linkElement);
5454
- }
5455
+ elevateElement(linkElement);
5456
+ linkElement.setAttribute("data-hover-elevated", "true");
5455
5457
  const event = new MouseEvent("mouseenter", {
5456
5458
  bubbles: true,
5457
5459
  cancelable: false,
@@ -5465,13 +5467,10 @@ function createNodeHover(nodeSelection, hoverStyle, options) {
5465
5467
  return source.id === hoveredNode.id || target.id === hoveredNode.id;
5466
5468
  }).each(function(item) {
5467
5469
  const labelElement = this;
5468
- const hoverLinkLabelsLayer = root2.select('[data-layer="hover-link-labels"]').node();
5469
- if (hoverLinkLabelsLayer) {
5470
- hoverLinkLabelsLayer.appendChild(labelElement);
5471
- if (item.style.label.visibility === "hover") {
5472
- labelElement.style.opacity = "1";
5473
- labelElement.style.pointerEvents = "auto";
5474
- }
5470
+ elevateElement(labelElement);
5471
+ if (item.style.label.visibility === "hover") {
5472
+ labelElement.style.opacity = "1";
5473
+ labelElement.style.pointerEvents = "auto";
5475
5474
  }
5476
5475
  });
5477
5476
  }).on("mouseleave.links", function(_event, _hoveredNode) {
@@ -5547,7 +5546,7 @@ function createLinkHover(linkSelection, hoverStyle) {
5547
5546
  }
5548
5547
  }
5549
5548
  const labelSelection2 = root2.select('[data-layer="link-labels"]').selectAll(".link-label");
5550
- labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1).style("pointer-events", "auto");
5549
+ labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1);
5551
5550
  }).on("mouseleave.hover", function(_event, renderableLink) {
5552
5551
  const hoveredElement = this;
5553
5552
  let targetLinkElement;
@@ -5844,7 +5843,55 @@ function getDefaultContent(node) {
5844
5843
 
5845
5844
  // src/utils/node-link-selection.utils.ts
5846
5845
  function createLinkHitArea(root2, linkSelection) {
5847
- return root2.select('[data-layer="links"]').selectAll("line.link-hit-area").data(linkSelection.data()).join("line").attr("class", "link-hit-area").attr("stroke", "rgba(0,0,0,0)").attr("stroke-width", (item) => item.style.arrow.size * 4).style("pointer-events", "stroke").style("cursor", "pointer").attr("opacity", 0);
5846
+ return root2.select('[data-layer="links"]').selectAll("rect.link-hit-area").data(linkSelection.data()).join("rect").attr("class", "link-hit-area").attr("fill", "rgba(0,0,0,0)").style("pointer-events", "fill").style("cursor", "pointer").attr("opacity", 0).each(function(item) {
5847
+ const rectElement = this;
5848
+ updateHitAreaDimensions(rectElement, item, root2);
5849
+ });
5850
+ }
5851
+ function updateHitAreaDimensions(rectElement, item, root2) {
5852
+ const source = item.link.source;
5853
+ const target = item.link.target;
5854
+ if (!source.x || !source.y || !target.x || !target.y) return;
5855
+ const dx = target.x - source.x;
5856
+ const dy = target.y - source.y;
5857
+ const linkLength = Math.sqrt(dx * dx + dy * dy);
5858
+ const angle = Math.atan2(dy, dx);
5859
+ const midX = (source.x + target.x) / 2;
5860
+ const midY = (source.y + target.y) / 2;
5861
+ const thickness = Math.max((item.style.strokeWidth || 2) * 4, item.style.arrow.size * 2, 20);
5862
+ let length = linkLength + item.style.arrow.size * 2;
5863
+ let width = thickness;
5864
+ if (item.link.label) {
5865
+ const labelElement = root2.select('[data-layer="link-labels"]').selectAll(".link-label").filter((labelItem) => labelItem.link === item.link).node();
5866
+ if (labelElement) {
5867
+ try {
5868
+ const textElement = labelElement.querySelector("text");
5869
+ const rectElement2 = labelElement.querySelector("rect");
5870
+ if (textElement && rectElement2) {
5871
+ const bbox = textElement.getBBox();
5872
+ const labelWidth = bbox.width + item.style.label.paddingX * 2;
5873
+ const labelHeight = bbox.height + item.style.label.paddingY * 2;
5874
+ width = Math.max(width, labelHeight + 10);
5875
+ length = Math.max(length, labelWidth + 20);
5876
+ }
5877
+ } catch {
5878
+ const text = item.link.label ?? "";
5879
+ const fontSize = item.style.label.fontSize;
5880
+ const estimatedWidth = text.length * fontSize * 0.6 + item.style.label.paddingX * 2 + 20;
5881
+ const estimatedHeight = fontSize + item.style.label.paddingY * 2 + 10;
5882
+ width = Math.max(width, estimatedHeight);
5883
+ length = Math.max(length, estimatedWidth);
5884
+ }
5885
+ }
5886
+ }
5887
+ const rectX = midX - length / 2;
5888
+ const rectY = midY - width / 2;
5889
+ rectElement.setAttribute("width", String(length));
5890
+ rectElement.setAttribute("height", String(width));
5891
+ rectElement.setAttribute("x", String(rectX));
5892
+ rectElement.setAttribute("y", String(rectY));
5893
+ const degrees2 = angle * 180 / Math.PI;
5894
+ rectElement.setAttribute("transform", `rotate(${degrees2}, ${midX}, ${midY})`);
5848
5895
  }
5849
5896
 
5850
5897
  // src/utils/get-link-target-point.ts
@@ -6083,7 +6130,10 @@ var SelectionManager = class {
6083
6130
  if (style.stroke !== void 0) nodeElement.style.stroke = style.stroke;
6084
6131
  if (style.strokeWidth !== void 0) nodeElement.style.strokeWidth = String(style.strokeWidth);
6085
6132
  if (style.opacity !== void 0) nodeElement.style.opacity = String(style.opacity);
6086
- if (style.radius !== void 0) nodeElement.setAttribute("r", String(style.radius));
6133
+ if (style.radius !== void 0) {
6134
+ nodeElement.setAttribute("r", String(style.radius));
6135
+ this.updateConnectedLinkPositions(nodeData);
6136
+ }
6087
6137
  }
6088
6138
  this.root.selectAll(".link-label").filter((item) => {
6089
6139
  if (item.style.label.visibility !== "hover") return false;
@@ -6140,6 +6190,7 @@ var SelectionManager = class {
6140
6190
  element.style.opacity = "";
6141
6191
  const originalRadius = data.style?.radius ?? 8;
6142
6192
  element.setAttribute("r", String(originalRadius));
6193
+ this.updateConnectedLinkPositions(data);
6143
6194
  delete element.dataset.selected;
6144
6195
  this.root.selectAll(".link-label.label-selection-pinned").classed("label-selection-pinned", false).interrupt().transition().duration(200).style("opacity", 0).style("pointer-events", "none");
6145
6196
  this.state.selectedNode = null;
@@ -6152,7 +6203,7 @@ var SelectionManager = class {
6152
6203
  if (!this.state.selectedLink) return;
6153
6204
  const { element, data, originalMarker } = this.state.selectedLink;
6154
6205
  this.layers.links.appendChild(element);
6155
- this.root.selectAll(".link-label").filter((item) => item.link === data).each((d, i, nodes) => {
6206
+ this.root.selectAll(".link-label").filter((item) => item.link === data).each((_, i, nodes) => {
6156
6207
  const element2 = nodes[i];
6157
6208
  if (element2) {
6158
6209
  this.layers.linkLabels.appendChild(element2);
@@ -6222,13 +6273,13 @@ var SelectionManager = class {
6222
6273
  const target = d.link.target;
6223
6274
  return source.id === nodeData.id || target.id === nodeData.id;
6224
6275
  });
6225
- connectedLinks.each((d, i, nodes) => {
6276
+ connectedLinks.each((_, i, nodes) => {
6226
6277
  const element = nodes[i];
6227
6278
  if (element) {
6228
6279
  this.layers.selectionLayer.links.appendChild(element);
6229
6280
  }
6230
6281
  });
6231
- this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6282
+ this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6232
6283
  const element = nodes[i];
6233
6284
  if (element) {
6234
6285
  this.layers.selectionLayer.nodeLabels.appendChild(element);
@@ -6238,7 +6289,7 @@ var SelectionManager = class {
6238
6289
  const source = item.link.source;
6239
6290
  const target = item.link.target;
6240
6291
  return source.id === nodeData.id || target.id === nodeData.id;
6241
- }).each((d, i, nodes) => {
6292
+ }).each((_, i, nodes) => {
6242
6293
  const element = nodes[i];
6243
6294
  if (element) {
6244
6295
  this.layers.selectionLayer.linkLabels.appendChild(element);
@@ -6250,7 +6301,7 @@ var SelectionManager = class {
6250
6301
  */
6251
6302
  bringLinkToFront(linkElement, renderableLink) {
6252
6303
  this.layers.selectionLayer.links.appendChild(linkElement);
6253
- this.root.selectAll(".link-label").filter((item) => item.link === renderableLink.link).each((d, i, nodes) => {
6304
+ this.root.selectAll(".link-label").filter((item) => item.link === renderableLink.link).each((_, i, nodes) => {
6254
6305
  const element = nodes[i];
6255
6306
  if (element) {
6256
6307
  this.layers.selectionLayer.linkLabels.appendChild(element);
@@ -6261,7 +6312,7 @@ var SelectionManager = class {
6261
6312
  * Restore elements back to their original layers
6262
6313
  */
6263
6314
  restoreSelectedElements(nodeData) {
6264
- this.root.selectAll("circle").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6315
+ this.root.selectAll("circle").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6265
6316
  const element = nodes[i];
6266
6317
  if (element) {
6267
6318
  this.layers.nodes.appendChild(element);
@@ -6271,13 +6322,13 @@ var SelectionManager = class {
6271
6322
  const source = d.link.source;
6272
6323
  const target = d.link.target;
6273
6324
  return source.id === nodeData.id || target.id === nodeData.id;
6274
- }).each((d, i, nodes) => {
6325
+ }).each((_, i, nodes) => {
6275
6326
  const element = nodes[i];
6276
6327
  if (element) {
6277
6328
  this.layers.links.appendChild(element);
6278
6329
  }
6279
6330
  });
6280
- this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((d, i, nodes) => {
6331
+ this.root.selectAll("text").filter((d) => d.id === nodeData.id).each((_, i, nodes) => {
6281
6332
  const element = nodes[i];
6282
6333
  if (element) {
6283
6334
  this.layers.nodeLabels.appendChild(element);
@@ -6287,22 +6338,13 @@ var SelectionManager = class {
6287
6338
  const source = item.link.source;
6288
6339
  const target = item.link.target;
6289
6340
  return source.id === nodeData.id || target.id === nodeData.id;
6290
- }).each((d, i, nodes) => {
6341
+ }).each((_, i, nodes) => {
6291
6342
  const element = nodes[i];
6292
6343
  if (element) {
6293
6344
  this.layers.linkLabels.appendChild(element);
6294
6345
  }
6295
6346
  });
6296
6347
  }
6297
- /**
6298
- * Utility method to bring any SVG element to front using appendChild
6299
- * Based on the reference implementation pattern
6300
- */
6301
- bringElementToFront(element) {
6302
- if (element.parentNode) {
6303
- element.parentNode.appendChild(element);
6304
- }
6305
- }
6306
6348
  /**
6307
6349
  * Clear hover state to prevent conflicts with selection
6308
6350
  * Similar to the clearAllHoverLayers function in create-node-hover.ts
@@ -6350,6 +6392,25 @@ var SelectionManager = class {
6350
6392
  }
6351
6393
  }
6352
6394
  }
6395
+ /**
6396
+ * Immediately update positions of links connected to the specified node
6397
+ * This ensures arrowheads reposition correctly when node radius changes
6398
+ */
6399
+ updateConnectedLinkPositions(nodeData) {
6400
+ this.root.selectAll("line:not(.link-hit-area)").filter((renderableLink) => {
6401
+ const source = renderableLink.link.source;
6402
+ const target = renderableLink.link.target;
6403
+ return source.id === nodeData.id || target.id === nodeData.id;
6404
+ }).each(function(item) {
6405
+ const linkElement = this;
6406
+ const sourcePoint = getShortenedSourcePoint(item.link, item.style);
6407
+ const targetPoint = getShortenedTargetPoint(item.link, item.style);
6408
+ linkElement.setAttribute("x1", String(sourcePoint.x));
6409
+ linkElement.setAttribute("y1", String(sourcePoint.y));
6410
+ linkElement.setAttribute("x2", String(targetPoint.x));
6411
+ linkElement.setAttribute("y2", String(targetPoint.y));
6412
+ });
6413
+ }
6353
6414
  /**
6354
6415
  * Clean up resources
6355
6416
  */
@@ -6516,6 +6577,13 @@ var InteractionManager = class {
6516
6577
  const nodeElement = event.currentTarget;
6517
6578
  this.manager.selectionManager?.selectNode(nodeElement, node);
6518
6579
  });
6580
+ selections.linkSelection.on("click.select", (event, renderableLinkData) => {
6581
+ event.stopPropagation();
6582
+ const linkElement = event.currentTarget;
6583
+ if (this.manager.selectionManager) {
6584
+ this.manager.selectionManager.selectLink(linkElement, renderableLinkData, event);
6585
+ }
6586
+ });
6519
6587
  selections.linkLabelSelection.on("click.select", (event, renderableLinkLabel) => {
6520
6588
  event.stopPropagation();
6521
6589
  const correspondingLink = selections.linkSelection.filter((d) => d.link === renderableLinkLabel.link).node();
@@ -6556,7 +6624,23 @@ var InteractionManager = class {
6556
6624
  }
6557
6625
  if (this.manager.simulation) {
6558
6626
  this.manager.simulation.on("tick.hitarea", () => {
6559
- linkHitAreaSelection.attr("x1", (item) => item.link.source.x ?? 0).attr("y1", (item) => item.link.source.y ?? 0).attr("x2", (item) => item.link.target.x ?? 0).attr("y2", (item) => item.link.target.y ?? 0);
6627
+ linkHitAreaSelection.each(function(item) {
6628
+ const source = item.link.source;
6629
+ const target = item.link.target;
6630
+ if (!source.x || !source.y || !target.x || !target.y) return;
6631
+ const rectElement = this;
6632
+ const dx = target.x - source.x;
6633
+ const dy = target.y - source.y;
6634
+ const angle = Math.atan2(dy, dx);
6635
+ const midX = (source.x + target.x) / 2;
6636
+ const midY = (source.y + target.y) / 2;
6637
+ const width = parseFloat(rectElement.getAttribute("width") || "20");
6638
+ const height = parseFloat(rectElement.getAttribute("height") || "20");
6639
+ rectElement.setAttribute("x", String(midX - width / 2));
6640
+ rectElement.setAttribute("y", String(midY - height / 2));
6641
+ const degrees2 = angle * 180 / Math.PI;
6642
+ rectElement.setAttribute("transform", `rotate(${degrees2}, ${midX}, ${midY})`);
6643
+ });
6560
6644
  });
6561
6645
  }
6562
6646
  if (this.manager.selectionManager) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polly-graph",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Reusable D3-based graph visualization SDK with configurable nodes, links, labels, interactions, and layout behaviors.",
5
5
  "license": "MIT",
6
6
  "author": "Badal",