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 +170 -86
- package/dist/index.css +14 -0
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +170 -86
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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", (
|
|
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
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
}
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
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
|
-
|
|
5466
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5484
|
-
|
|
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
|
-
|
|
5501
|
-
if (
|
|
5502
|
-
|
|
5503
|
-
|
|
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)
|
|
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("
|
|
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)
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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", (
|
|
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
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
}
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
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
|
-
|
|
5434
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5452
|
-
|
|
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
|
-
|
|
5469
|
-
if (
|
|
5470
|
-
|
|
5471
|
-
|
|
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)
|
|
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("
|
|
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)
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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.
|
|
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