polly-graph 0.1.13 → 0.1.15
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 +342 -28
- package/dist/index.js +342 -28
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4868,10 +4868,7 @@ function renderLinkLabels(params, links) {
|
|
|
4868
4868
|
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
4869
|
const visibility = item.style.label.visibility ?? "always";
|
|
4870
4870
|
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");
|
|
4871
|
+
}).style("pointer-events", "none").style("cursor", "pointer");
|
|
4875
4872
|
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
4873
|
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
4874
|
textSelection.each(function(item) {
|
|
@@ -5117,34 +5114,294 @@ function createDragBehavior(simulation, onDragStart, canvasBounds) {
|
|
|
5117
5114
|
});
|
|
5118
5115
|
}
|
|
5119
5116
|
|
|
5117
|
+
// src/utils/node-style-manager.ts
|
|
5118
|
+
var NodeStyleManager = class {
|
|
5119
|
+
styleStates = /* @__PURE__ */ new Map();
|
|
5120
|
+
/**
|
|
5121
|
+
* Initialize a node's style state by capturing its original styles
|
|
5122
|
+
*/
|
|
5123
|
+
initializeNode(element, node) {
|
|
5124
|
+
if (this.styleStates.has(element)) {
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5127
|
+
const domBackup = {
|
|
5128
|
+
stroke: element.getAttribute("stroke"),
|
|
5129
|
+
strokeWidth: element.getAttribute("stroke-width"),
|
|
5130
|
+
opacity: element.getAttribute("opacity"),
|
|
5131
|
+
fill: element.getAttribute("fill")
|
|
5132
|
+
};
|
|
5133
|
+
const originalStyle = {
|
|
5134
|
+
stroke: node.style?.stroke || void 0,
|
|
5135
|
+
strokeWidth: node.style?.strokeWidth || void 0,
|
|
5136
|
+
opacity: node.style?.opacity || void 0,
|
|
5137
|
+
fill: node.style?.fill || void 0
|
|
5138
|
+
};
|
|
5139
|
+
this.styleStates.set(element, {
|
|
5140
|
+
original: originalStyle,
|
|
5141
|
+
current: { ...originalStyle },
|
|
5142
|
+
domBackup
|
|
5143
|
+
});
|
|
5144
|
+
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Apply temporary styles (e.g., hover effects) that will be reset later
|
|
5147
|
+
*/
|
|
5148
|
+
applyTemporaryStyles(element, styles) {
|
|
5149
|
+
this.applyStylesToDOM(element, styles);
|
|
5150
|
+
}
|
|
5151
|
+
/**
|
|
5152
|
+
* Apply permanent styles that become the new base styles
|
|
5153
|
+
*/
|
|
5154
|
+
applyPermanentStyles(element, styles) {
|
|
5155
|
+
const state = this.styleStates.get(element);
|
|
5156
|
+
if (!state) {
|
|
5157
|
+
console.warn("[NodeStyleManager] Node not initialized, cannot apply permanent styles");
|
|
5158
|
+
return;
|
|
5159
|
+
}
|
|
5160
|
+
this.applyStylesToDOM(element, styles);
|
|
5161
|
+
Object.assign(state.current, styles);
|
|
5162
|
+
}
|
|
5163
|
+
/**
|
|
5164
|
+
* Reset node to its current base styles (removes temporary styles)
|
|
5165
|
+
*/
|
|
5166
|
+
resetToBase(element) {
|
|
5167
|
+
const state = this.styleStates.get(element);
|
|
5168
|
+
if (!state) {
|
|
5169
|
+
this.clearAllStyles(element);
|
|
5170
|
+
return;
|
|
5171
|
+
}
|
|
5172
|
+
this.clearAllStyles(element);
|
|
5173
|
+
this.applyStylesToDOM(element, state.current);
|
|
5174
|
+
}
|
|
5175
|
+
/**
|
|
5176
|
+
* Reset node to its original styles (as captured during initialization)
|
|
5177
|
+
*/
|
|
5178
|
+
resetToOriginal(element) {
|
|
5179
|
+
const state = this.styleStates.get(element);
|
|
5180
|
+
if (!state) {
|
|
5181
|
+
this.clearAllStyles(element);
|
|
5182
|
+
return;
|
|
5183
|
+
}
|
|
5184
|
+
this.clearAllStyles(element);
|
|
5185
|
+
this.restoreOriginalDOM(element, state.domBackup);
|
|
5186
|
+
state.current = { ...state.original };
|
|
5187
|
+
}
|
|
5188
|
+
/**
|
|
5189
|
+
* Check if node is in a specific state (selected, hovered, etc.)
|
|
5190
|
+
*/
|
|
5191
|
+
hasState(element, stateName) {
|
|
5192
|
+
return element.dataset[stateName] === "true";
|
|
5193
|
+
}
|
|
5194
|
+
/**
|
|
5195
|
+
* Set state marker on node
|
|
5196
|
+
*/
|
|
5197
|
+
setState(element, stateName, value) {
|
|
5198
|
+
if (value) {
|
|
5199
|
+
element.dataset[stateName] = "true";
|
|
5200
|
+
} else {
|
|
5201
|
+
delete element.dataset[stateName];
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
/**
|
|
5205
|
+
* Get the original styles for a node
|
|
5206
|
+
*/
|
|
5207
|
+
getOriginalStyles(element) {
|
|
5208
|
+
const state = this.styleStates.get(element);
|
|
5209
|
+
return state ? { ...state.original } : null;
|
|
5210
|
+
}
|
|
5211
|
+
/**
|
|
5212
|
+
* Get the current base styles for a node
|
|
5213
|
+
*/
|
|
5214
|
+
getCurrentStyles(element) {
|
|
5215
|
+
const state = this.styleStates.get(element);
|
|
5216
|
+
return state ? { ...state.current } : null;
|
|
5217
|
+
}
|
|
5218
|
+
/**
|
|
5219
|
+
* Remove a node from management (cleanup)
|
|
5220
|
+
*/
|
|
5221
|
+
removeNode(element) {
|
|
5222
|
+
this.styleStates.delete(element);
|
|
5223
|
+
}
|
|
5224
|
+
/**
|
|
5225
|
+
* Clear all managed nodes (for cleanup)
|
|
5226
|
+
*/
|
|
5227
|
+
clear() {
|
|
5228
|
+
this.styleStates.clear();
|
|
5229
|
+
}
|
|
5230
|
+
/**
|
|
5231
|
+
* Private: Apply styles to DOM element
|
|
5232
|
+
*/
|
|
5233
|
+
applyStylesToDOM(element, styles) {
|
|
5234
|
+
if (styles.stroke !== void 0) {
|
|
5235
|
+
if (styles.stroke === null || styles.stroke === "") {
|
|
5236
|
+
element.removeAttribute("stroke");
|
|
5237
|
+
element.style.stroke = "";
|
|
5238
|
+
} else {
|
|
5239
|
+
element.style.stroke = styles.stroke;
|
|
5240
|
+
}
|
|
5241
|
+
}
|
|
5242
|
+
if (styles.strokeWidth !== void 0) {
|
|
5243
|
+
if (styles.strokeWidth === null || styles.strokeWidth === 0) {
|
|
5244
|
+
element.removeAttribute("stroke-width");
|
|
5245
|
+
element.style.strokeWidth = "";
|
|
5246
|
+
} else {
|
|
5247
|
+
element.style.strokeWidth = String(styles.strokeWidth);
|
|
5248
|
+
}
|
|
5249
|
+
}
|
|
5250
|
+
if (styles.opacity !== void 0) {
|
|
5251
|
+
if (styles.opacity === null || styles.opacity === 1) {
|
|
5252
|
+
element.removeAttribute("opacity");
|
|
5253
|
+
element.style.opacity = "";
|
|
5254
|
+
} else {
|
|
5255
|
+
element.style.opacity = String(styles.opacity);
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
if (styles.fill !== void 0) {
|
|
5259
|
+
if (styles.fill === null || styles.fill === "") {
|
|
5260
|
+
element.removeAttribute("fill");
|
|
5261
|
+
element.style.fill = "";
|
|
5262
|
+
} else {
|
|
5263
|
+
element.style.fill = styles.fill;
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
if (styles.radius !== void 0) {
|
|
5267
|
+
if (styles.radius === null || styles.radius === 0) {
|
|
5268
|
+
element.removeAttribute("r");
|
|
5269
|
+
element.style.removeProperty("r");
|
|
5270
|
+
} else {
|
|
5271
|
+
element.setAttribute("r", String(styles.radius));
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
/**
|
|
5276
|
+
* Private: Clear all inline styles and remove hover-related attributes
|
|
5277
|
+
*/
|
|
5278
|
+
clearAllStyles(element) {
|
|
5279
|
+
element.style.stroke = "";
|
|
5280
|
+
element.style.strokeWidth = "";
|
|
5281
|
+
element.style.opacity = "";
|
|
5282
|
+
element.style.fill = "";
|
|
5283
|
+
element.style.removeProperty("r");
|
|
5284
|
+
this.removeIfHoverAttribute(element, "stroke");
|
|
5285
|
+
this.removeIfHoverAttribute(element, "stroke-width");
|
|
5286
|
+
this.removeIfHoverAttribute(element, "opacity");
|
|
5287
|
+
}
|
|
5288
|
+
/**
|
|
5289
|
+
* Private: Restore original DOM attributes
|
|
5290
|
+
*/
|
|
5291
|
+
restoreOriginalDOM(element, domBackup) {
|
|
5292
|
+
if (domBackup.stroke !== void 0) {
|
|
5293
|
+
if (domBackup.stroke === null) {
|
|
5294
|
+
element.removeAttribute("stroke");
|
|
5295
|
+
} else {
|
|
5296
|
+
element.setAttribute("stroke", domBackup.stroke);
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
5299
|
+
if (domBackup.strokeWidth !== void 0) {
|
|
5300
|
+
if (domBackup.strokeWidth === null) {
|
|
5301
|
+
element.removeAttribute("stroke-width");
|
|
5302
|
+
} else {
|
|
5303
|
+
element.setAttribute("stroke-width", domBackup.strokeWidth);
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
if (domBackup.opacity !== void 0) {
|
|
5307
|
+
if (domBackup.opacity === null) {
|
|
5308
|
+
element.removeAttribute("opacity");
|
|
5309
|
+
} else {
|
|
5310
|
+
element.setAttribute("opacity", domBackup.opacity);
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
if (domBackup.fill !== void 0) {
|
|
5314
|
+
if (domBackup.fill === null) {
|
|
5315
|
+
element.removeAttribute("fill");
|
|
5316
|
+
} else {
|
|
5317
|
+
element.setAttribute("fill", domBackup.fill);
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
/**
|
|
5322
|
+
* Private: Remove attribute only if it looks like it was set by hover/interaction
|
|
5323
|
+
*/
|
|
5324
|
+
removeIfHoverAttribute(element, attr) {
|
|
5325
|
+
const value = element.getAttribute(attr);
|
|
5326
|
+
if (!value) return;
|
|
5327
|
+
const hoverPatterns = {
|
|
5328
|
+
"stroke": ["#6366f1", "#8b5cf6", "#3b82f6", "#ffffff", "#fff", "white"],
|
|
5329
|
+
// Common hover stroke colors
|
|
5330
|
+
"stroke-width": ["2", "2.5", "3", "4"],
|
|
5331
|
+
// Common hover stroke widths
|
|
5332
|
+
"opacity": ["0.8", "0.9", "0.7"]
|
|
5333
|
+
// Common hover opacity values
|
|
5334
|
+
};
|
|
5335
|
+
const patterns = hoverPatterns[attr];
|
|
5336
|
+
if (patterns && patterns.includes(value)) {
|
|
5337
|
+
element.removeAttribute(attr);
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
};
|
|
5341
|
+
var nodeStyleManager = new NodeStyleManager();
|
|
5342
|
+
function applyHoverStyles(element, node, hoverStyle) {
|
|
5343
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5344
|
+
return;
|
|
5345
|
+
}
|
|
5346
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5347
|
+
nodeStyleManager.applyTemporaryStyles(element, hoverStyle);
|
|
5348
|
+
nodeStyleManager.setState(element, "hovered", true);
|
|
5349
|
+
}
|
|
5350
|
+
function removeHoverStyles(element, node) {
|
|
5351
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5352
|
+
return;
|
|
5353
|
+
}
|
|
5354
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5355
|
+
nodeStyleManager.resetToBase(element);
|
|
5356
|
+
nodeStyleManager.setState(element, "hovered", false);
|
|
5357
|
+
}
|
|
5358
|
+
|
|
5120
5359
|
// src/interactions/create-node-hover.ts
|
|
5121
|
-
|
|
5360
|
+
var currentHoveredNode = null;
|
|
5361
|
+
var hoverTimerManager = new TimerManager();
|
|
5362
|
+
function createNodeHover(nodeSelection, hoverStyle, options) {
|
|
5122
5363
|
const firstNode = nodeSelection.node();
|
|
5123
5364
|
if (!firstNode) return;
|
|
5365
|
+
const {
|
|
5366
|
+
enableDebouncing = false,
|
|
5367
|
+
enterDelay = 16,
|
|
5368
|
+
// ~1 frame at 60fps
|
|
5369
|
+
leaveDelay = 50
|
|
5370
|
+
// Longer delay for smoother transitions
|
|
5371
|
+
} = options || {};
|
|
5124
5372
|
if (hoverStyle) {
|
|
5125
|
-
nodeSelection.on("mouseenter.hover", function(_event,
|
|
5373
|
+
nodeSelection.on("mouseenter.hover", function(_event, node) {
|
|
5126
5374
|
const circle = this;
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5375
|
+
const applyHover = () => {
|
|
5376
|
+
if (currentHoveredNode && currentHoveredNode.element !== circle) {
|
|
5377
|
+
removeHoverStyles(currentHoveredNode.element, currentHoveredNode.node);
|
|
5378
|
+
clearAllHoverLayers();
|
|
5379
|
+
}
|
|
5380
|
+
currentHoveredNode = { element: circle, node };
|
|
5381
|
+
applyHoverStyles(circle, node, hoverStyle);
|
|
5382
|
+
};
|
|
5383
|
+
if (enableDebouncing) {
|
|
5384
|
+
hoverTimerManager.clearTimer("hover-enter");
|
|
5385
|
+
hoverTimerManager.clearTimer("hover-leave");
|
|
5386
|
+
hoverTimerManager.debounce("hover-enter", applyHover, enterDelay);
|
|
5387
|
+
} else {
|
|
5388
|
+
applyHover();
|
|
5138
5389
|
}
|
|
5139
|
-
}).on("mouseleave.hover", function(_event,
|
|
5390
|
+
}).on("mouseleave.hover", function(_event, node) {
|
|
5140
5391
|
const circle = this;
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5392
|
+
const removeHover = () => {
|
|
5393
|
+
if (currentHoveredNode?.element === circle) {
|
|
5394
|
+
currentHoveredNode = null;
|
|
5395
|
+
removeHoverStyles(circle, node);
|
|
5396
|
+
clearAllHoverLayers();
|
|
5397
|
+
}
|
|
5398
|
+
};
|
|
5399
|
+
if (enableDebouncing) {
|
|
5400
|
+
hoverTimerManager.clearTimer("hover-enter");
|
|
5401
|
+
hoverTimerManager.debounce("hover-leave", removeHover, leaveDelay);
|
|
5402
|
+
} else {
|
|
5403
|
+
removeHover();
|
|
5144
5404
|
}
|
|
5145
|
-
circle.style.stroke = "";
|
|
5146
|
-
circle.style.strokeWidth = "";
|
|
5147
|
-
circle.style.opacity = "";
|
|
5148
5405
|
});
|
|
5149
5406
|
}
|
|
5150
5407
|
const svgElement = firstNode.ownerSVGElement;
|
|
@@ -5198,6 +5455,9 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5198
5455
|
if (hoveredNodeElement.dataset.selected === "true") {
|
|
5199
5456
|
return;
|
|
5200
5457
|
}
|
|
5458
|
+
if (!currentHoveredNode || currentHoveredNode.element !== hoveredNodeElement) {
|
|
5459
|
+
return;
|
|
5460
|
+
}
|
|
5201
5461
|
clearAllHoverLayers();
|
|
5202
5462
|
const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
|
|
5203
5463
|
if (hoverNodesLayer) {
|
|
@@ -5244,7 +5504,10 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5244
5504
|
}
|
|
5245
5505
|
});
|
|
5246
5506
|
}).on("mouseleave.links", function(_event, _hoveredNode) {
|
|
5247
|
-
|
|
5507
|
+
const hoveredNodeElement = this;
|
|
5508
|
+
if (currentHoveredNode?.element === hoveredNodeElement) {
|
|
5509
|
+
clearAllHoverLayers();
|
|
5510
|
+
}
|
|
5248
5511
|
});
|
|
5249
5512
|
}
|
|
5250
5513
|
|
|
@@ -5313,7 +5576,7 @@ function createLinkHover(linkSelection, hoverStyle) {
|
|
|
5313
5576
|
}
|
|
5314
5577
|
}
|
|
5315
5578
|
const labelSelection2 = root2.select('[data-layer="link-labels"]').selectAll(".link-label");
|
|
5316
|
-
labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1)
|
|
5579
|
+
labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1);
|
|
5317
5580
|
}).on("mouseleave.hover", function(_event, renderableLink) {
|
|
5318
5581
|
const hoveredElement = this;
|
|
5319
5582
|
let targetLinkElement;
|
|
@@ -5610,7 +5873,47 @@ function getDefaultContent(node) {
|
|
|
5610
5873
|
|
|
5611
5874
|
// src/utils/node-link-selection.utils.ts
|
|
5612
5875
|
function createLinkHitArea(root2, linkSelection) {
|
|
5613
|
-
return root2.select('[data-layer="links"]').selectAll("
|
|
5876
|
+
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) {
|
|
5877
|
+
const rectElement = this;
|
|
5878
|
+
updateHitAreaDimensions(rectElement, item, root2);
|
|
5879
|
+
});
|
|
5880
|
+
}
|
|
5881
|
+
function updateHitAreaDimensions(rectElement, item, root2) {
|
|
5882
|
+
const source = item.link.source;
|
|
5883
|
+
const target = item.link.target;
|
|
5884
|
+
if (!source.x || !source.y || !target.x || !target.y) return;
|
|
5885
|
+
const midX = (source.x + target.x) / 2;
|
|
5886
|
+
const midY = (source.y + target.y) / 2;
|
|
5887
|
+
const linkPadding = Math.max(item.style.strokeWidth || 2, item.style.arrow.size) * 2;
|
|
5888
|
+
let width = linkPadding;
|
|
5889
|
+
let height = linkPadding;
|
|
5890
|
+
if (item.link.label) {
|
|
5891
|
+
const labelElement = root2.select('[data-layer="link-labels"]').selectAll(".link-label").filter((labelItem) => labelItem.link === item.link).node();
|
|
5892
|
+
if (labelElement) {
|
|
5893
|
+
try {
|
|
5894
|
+
const textElement = labelElement.querySelector("text");
|
|
5895
|
+
const rectElement2 = labelElement.querySelector("rect");
|
|
5896
|
+
if (textElement && rectElement2) {
|
|
5897
|
+
const bbox = textElement.getBBox();
|
|
5898
|
+
const labelWidth = bbox.width + item.style.label.paddingX * 2;
|
|
5899
|
+
const labelHeight = bbox.height + item.style.label.paddingY * 2;
|
|
5900
|
+
width = Math.max(width, labelWidth + 10);
|
|
5901
|
+
height = Math.max(height, labelHeight + 10);
|
|
5902
|
+
}
|
|
5903
|
+
} catch {
|
|
5904
|
+
const text = item.link.label ?? "";
|
|
5905
|
+
const fontSize = item.style.label.fontSize;
|
|
5906
|
+
const estimatedWidth = text.length * fontSize * 0.6 + item.style.label.paddingX * 2 + 10;
|
|
5907
|
+
const estimatedHeight = fontSize + item.style.label.paddingY * 2 + 10;
|
|
5908
|
+
width = Math.max(width, estimatedWidth);
|
|
5909
|
+
height = Math.max(height, estimatedHeight);
|
|
5910
|
+
}
|
|
5911
|
+
}
|
|
5912
|
+
}
|
|
5913
|
+
rectElement.setAttribute("x", String(midX - width / 2));
|
|
5914
|
+
rectElement.setAttribute("y", String(midY - height / 2));
|
|
5915
|
+
rectElement.setAttribute("width", String(width));
|
|
5916
|
+
rectElement.setAttribute("height", String(height));
|
|
5614
5917
|
}
|
|
5615
5918
|
|
|
5616
5919
|
// src/utils/get-link-target-point.ts
|
|
@@ -6322,7 +6625,18 @@ var InteractionManager = class {
|
|
|
6322
6625
|
}
|
|
6323
6626
|
if (this.manager.simulation) {
|
|
6324
6627
|
this.manager.simulation.on("tick.hitarea", () => {
|
|
6325
|
-
linkHitAreaSelection.
|
|
6628
|
+
linkHitAreaSelection.each(function(item) {
|
|
6629
|
+
const source = item.link.source;
|
|
6630
|
+
const target = item.link.target;
|
|
6631
|
+
if (!source.x || !source.y || !target.x || !target.y) return;
|
|
6632
|
+
const rectElement = this;
|
|
6633
|
+
const midX = (source.x + target.x) / 2;
|
|
6634
|
+
const midY = (source.y + target.y) / 2;
|
|
6635
|
+
const width = parseFloat(rectElement.getAttribute("width") || "20");
|
|
6636
|
+
const height = parseFloat(rectElement.getAttribute("height") || "20");
|
|
6637
|
+
rectElement.setAttribute("x", String(midX - width / 2));
|
|
6638
|
+
rectElement.setAttribute("y", String(midY - height / 2));
|
|
6639
|
+
});
|
|
6326
6640
|
});
|
|
6327
6641
|
}
|
|
6328
6642
|
if (this.manager.selectionManager) {
|
package/dist/index.js
CHANGED
|
@@ -4836,10 +4836,7 @@ function renderLinkLabels(params, links) {
|
|
|
4836
4836
|
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
4837
|
const visibility = item.style.label.visibility ?? "always";
|
|
4838
4838
|
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");
|
|
4839
|
+
}).style("pointer-events", "none").style("cursor", "pointer");
|
|
4843
4840
|
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
4841
|
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
4842
|
textSelection.each(function(item) {
|
|
@@ -5085,34 +5082,294 @@ function createDragBehavior(simulation, onDragStart, canvasBounds) {
|
|
|
5085
5082
|
});
|
|
5086
5083
|
}
|
|
5087
5084
|
|
|
5085
|
+
// src/utils/node-style-manager.ts
|
|
5086
|
+
var NodeStyleManager = class {
|
|
5087
|
+
styleStates = /* @__PURE__ */ new Map();
|
|
5088
|
+
/**
|
|
5089
|
+
* Initialize a node's style state by capturing its original styles
|
|
5090
|
+
*/
|
|
5091
|
+
initializeNode(element, node) {
|
|
5092
|
+
if (this.styleStates.has(element)) {
|
|
5093
|
+
return;
|
|
5094
|
+
}
|
|
5095
|
+
const domBackup = {
|
|
5096
|
+
stroke: element.getAttribute("stroke"),
|
|
5097
|
+
strokeWidth: element.getAttribute("stroke-width"),
|
|
5098
|
+
opacity: element.getAttribute("opacity"),
|
|
5099
|
+
fill: element.getAttribute("fill")
|
|
5100
|
+
};
|
|
5101
|
+
const originalStyle = {
|
|
5102
|
+
stroke: node.style?.stroke || void 0,
|
|
5103
|
+
strokeWidth: node.style?.strokeWidth || void 0,
|
|
5104
|
+
opacity: node.style?.opacity || void 0,
|
|
5105
|
+
fill: node.style?.fill || void 0
|
|
5106
|
+
};
|
|
5107
|
+
this.styleStates.set(element, {
|
|
5108
|
+
original: originalStyle,
|
|
5109
|
+
current: { ...originalStyle },
|
|
5110
|
+
domBackup
|
|
5111
|
+
});
|
|
5112
|
+
}
|
|
5113
|
+
/**
|
|
5114
|
+
* Apply temporary styles (e.g., hover effects) that will be reset later
|
|
5115
|
+
*/
|
|
5116
|
+
applyTemporaryStyles(element, styles) {
|
|
5117
|
+
this.applyStylesToDOM(element, styles);
|
|
5118
|
+
}
|
|
5119
|
+
/**
|
|
5120
|
+
* Apply permanent styles that become the new base styles
|
|
5121
|
+
*/
|
|
5122
|
+
applyPermanentStyles(element, styles) {
|
|
5123
|
+
const state = this.styleStates.get(element);
|
|
5124
|
+
if (!state) {
|
|
5125
|
+
console.warn("[NodeStyleManager] Node not initialized, cannot apply permanent styles");
|
|
5126
|
+
return;
|
|
5127
|
+
}
|
|
5128
|
+
this.applyStylesToDOM(element, styles);
|
|
5129
|
+
Object.assign(state.current, styles);
|
|
5130
|
+
}
|
|
5131
|
+
/**
|
|
5132
|
+
* Reset node to its current base styles (removes temporary styles)
|
|
5133
|
+
*/
|
|
5134
|
+
resetToBase(element) {
|
|
5135
|
+
const state = this.styleStates.get(element);
|
|
5136
|
+
if (!state) {
|
|
5137
|
+
this.clearAllStyles(element);
|
|
5138
|
+
return;
|
|
5139
|
+
}
|
|
5140
|
+
this.clearAllStyles(element);
|
|
5141
|
+
this.applyStylesToDOM(element, state.current);
|
|
5142
|
+
}
|
|
5143
|
+
/**
|
|
5144
|
+
* Reset node to its original styles (as captured during initialization)
|
|
5145
|
+
*/
|
|
5146
|
+
resetToOriginal(element) {
|
|
5147
|
+
const state = this.styleStates.get(element);
|
|
5148
|
+
if (!state) {
|
|
5149
|
+
this.clearAllStyles(element);
|
|
5150
|
+
return;
|
|
5151
|
+
}
|
|
5152
|
+
this.clearAllStyles(element);
|
|
5153
|
+
this.restoreOriginalDOM(element, state.domBackup);
|
|
5154
|
+
state.current = { ...state.original };
|
|
5155
|
+
}
|
|
5156
|
+
/**
|
|
5157
|
+
* Check if node is in a specific state (selected, hovered, etc.)
|
|
5158
|
+
*/
|
|
5159
|
+
hasState(element, stateName) {
|
|
5160
|
+
return element.dataset[stateName] === "true";
|
|
5161
|
+
}
|
|
5162
|
+
/**
|
|
5163
|
+
* Set state marker on node
|
|
5164
|
+
*/
|
|
5165
|
+
setState(element, stateName, value) {
|
|
5166
|
+
if (value) {
|
|
5167
|
+
element.dataset[stateName] = "true";
|
|
5168
|
+
} else {
|
|
5169
|
+
delete element.dataset[stateName];
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
/**
|
|
5173
|
+
* Get the original styles for a node
|
|
5174
|
+
*/
|
|
5175
|
+
getOriginalStyles(element) {
|
|
5176
|
+
const state = this.styleStates.get(element);
|
|
5177
|
+
return state ? { ...state.original } : null;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Get the current base styles for a node
|
|
5181
|
+
*/
|
|
5182
|
+
getCurrentStyles(element) {
|
|
5183
|
+
const state = this.styleStates.get(element);
|
|
5184
|
+
return state ? { ...state.current } : null;
|
|
5185
|
+
}
|
|
5186
|
+
/**
|
|
5187
|
+
* Remove a node from management (cleanup)
|
|
5188
|
+
*/
|
|
5189
|
+
removeNode(element) {
|
|
5190
|
+
this.styleStates.delete(element);
|
|
5191
|
+
}
|
|
5192
|
+
/**
|
|
5193
|
+
* Clear all managed nodes (for cleanup)
|
|
5194
|
+
*/
|
|
5195
|
+
clear() {
|
|
5196
|
+
this.styleStates.clear();
|
|
5197
|
+
}
|
|
5198
|
+
/**
|
|
5199
|
+
* Private: Apply styles to DOM element
|
|
5200
|
+
*/
|
|
5201
|
+
applyStylesToDOM(element, styles) {
|
|
5202
|
+
if (styles.stroke !== void 0) {
|
|
5203
|
+
if (styles.stroke === null || styles.stroke === "") {
|
|
5204
|
+
element.removeAttribute("stroke");
|
|
5205
|
+
element.style.stroke = "";
|
|
5206
|
+
} else {
|
|
5207
|
+
element.style.stroke = styles.stroke;
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
if (styles.strokeWidth !== void 0) {
|
|
5211
|
+
if (styles.strokeWidth === null || styles.strokeWidth === 0) {
|
|
5212
|
+
element.removeAttribute("stroke-width");
|
|
5213
|
+
element.style.strokeWidth = "";
|
|
5214
|
+
} else {
|
|
5215
|
+
element.style.strokeWidth = String(styles.strokeWidth);
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
if (styles.opacity !== void 0) {
|
|
5219
|
+
if (styles.opacity === null || styles.opacity === 1) {
|
|
5220
|
+
element.removeAttribute("opacity");
|
|
5221
|
+
element.style.opacity = "";
|
|
5222
|
+
} else {
|
|
5223
|
+
element.style.opacity = String(styles.opacity);
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
if (styles.fill !== void 0) {
|
|
5227
|
+
if (styles.fill === null || styles.fill === "") {
|
|
5228
|
+
element.removeAttribute("fill");
|
|
5229
|
+
element.style.fill = "";
|
|
5230
|
+
} else {
|
|
5231
|
+
element.style.fill = styles.fill;
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
if (styles.radius !== void 0) {
|
|
5235
|
+
if (styles.radius === null || styles.radius === 0) {
|
|
5236
|
+
element.removeAttribute("r");
|
|
5237
|
+
element.style.removeProperty("r");
|
|
5238
|
+
} else {
|
|
5239
|
+
element.setAttribute("r", String(styles.radius));
|
|
5240
|
+
}
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
/**
|
|
5244
|
+
* Private: Clear all inline styles and remove hover-related attributes
|
|
5245
|
+
*/
|
|
5246
|
+
clearAllStyles(element) {
|
|
5247
|
+
element.style.stroke = "";
|
|
5248
|
+
element.style.strokeWidth = "";
|
|
5249
|
+
element.style.opacity = "";
|
|
5250
|
+
element.style.fill = "";
|
|
5251
|
+
element.style.removeProperty("r");
|
|
5252
|
+
this.removeIfHoverAttribute(element, "stroke");
|
|
5253
|
+
this.removeIfHoverAttribute(element, "stroke-width");
|
|
5254
|
+
this.removeIfHoverAttribute(element, "opacity");
|
|
5255
|
+
}
|
|
5256
|
+
/**
|
|
5257
|
+
* Private: Restore original DOM attributes
|
|
5258
|
+
*/
|
|
5259
|
+
restoreOriginalDOM(element, domBackup) {
|
|
5260
|
+
if (domBackup.stroke !== void 0) {
|
|
5261
|
+
if (domBackup.stroke === null) {
|
|
5262
|
+
element.removeAttribute("stroke");
|
|
5263
|
+
} else {
|
|
5264
|
+
element.setAttribute("stroke", domBackup.stroke);
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
if (domBackup.strokeWidth !== void 0) {
|
|
5268
|
+
if (domBackup.strokeWidth === null) {
|
|
5269
|
+
element.removeAttribute("stroke-width");
|
|
5270
|
+
} else {
|
|
5271
|
+
element.setAttribute("stroke-width", domBackup.strokeWidth);
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
if (domBackup.opacity !== void 0) {
|
|
5275
|
+
if (domBackup.opacity === null) {
|
|
5276
|
+
element.removeAttribute("opacity");
|
|
5277
|
+
} else {
|
|
5278
|
+
element.setAttribute("opacity", domBackup.opacity);
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
if (domBackup.fill !== void 0) {
|
|
5282
|
+
if (domBackup.fill === null) {
|
|
5283
|
+
element.removeAttribute("fill");
|
|
5284
|
+
} else {
|
|
5285
|
+
element.setAttribute("fill", domBackup.fill);
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
/**
|
|
5290
|
+
* Private: Remove attribute only if it looks like it was set by hover/interaction
|
|
5291
|
+
*/
|
|
5292
|
+
removeIfHoverAttribute(element, attr) {
|
|
5293
|
+
const value = element.getAttribute(attr);
|
|
5294
|
+
if (!value) return;
|
|
5295
|
+
const hoverPatterns = {
|
|
5296
|
+
"stroke": ["#6366f1", "#8b5cf6", "#3b82f6", "#ffffff", "#fff", "white"],
|
|
5297
|
+
// Common hover stroke colors
|
|
5298
|
+
"stroke-width": ["2", "2.5", "3", "4"],
|
|
5299
|
+
// Common hover stroke widths
|
|
5300
|
+
"opacity": ["0.8", "0.9", "0.7"]
|
|
5301
|
+
// Common hover opacity values
|
|
5302
|
+
};
|
|
5303
|
+
const patterns = hoverPatterns[attr];
|
|
5304
|
+
if (patterns && patterns.includes(value)) {
|
|
5305
|
+
element.removeAttribute(attr);
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
};
|
|
5309
|
+
var nodeStyleManager = new NodeStyleManager();
|
|
5310
|
+
function applyHoverStyles(element, node, hoverStyle) {
|
|
5311
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5312
|
+
return;
|
|
5313
|
+
}
|
|
5314
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5315
|
+
nodeStyleManager.applyTemporaryStyles(element, hoverStyle);
|
|
5316
|
+
nodeStyleManager.setState(element, "hovered", true);
|
|
5317
|
+
}
|
|
5318
|
+
function removeHoverStyles(element, node) {
|
|
5319
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5320
|
+
return;
|
|
5321
|
+
}
|
|
5322
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5323
|
+
nodeStyleManager.resetToBase(element);
|
|
5324
|
+
nodeStyleManager.setState(element, "hovered", false);
|
|
5325
|
+
}
|
|
5326
|
+
|
|
5088
5327
|
// src/interactions/create-node-hover.ts
|
|
5089
|
-
|
|
5328
|
+
var currentHoveredNode = null;
|
|
5329
|
+
var hoverTimerManager = new TimerManager();
|
|
5330
|
+
function createNodeHover(nodeSelection, hoverStyle, options) {
|
|
5090
5331
|
const firstNode = nodeSelection.node();
|
|
5091
5332
|
if (!firstNode) return;
|
|
5333
|
+
const {
|
|
5334
|
+
enableDebouncing = false,
|
|
5335
|
+
enterDelay = 16,
|
|
5336
|
+
// ~1 frame at 60fps
|
|
5337
|
+
leaveDelay = 50
|
|
5338
|
+
// Longer delay for smoother transitions
|
|
5339
|
+
} = options || {};
|
|
5092
5340
|
if (hoverStyle) {
|
|
5093
|
-
nodeSelection.on("mouseenter.hover", function(_event,
|
|
5341
|
+
nodeSelection.on("mouseenter.hover", function(_event, node) {
|
|
5094
5342
|
const circle = this;
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5343
|
+
const applyHover = () => {
|
|
5344
|
+
if (currentHoveredNode && currentHoveredNode.element !== circle) {
|
|
5345
|
+
removeHoverStyles(currentHoveredNode.element, currentHoveredNode.node);
|
|
5346
|
+
clearAllHoverLayers();
|
|
5347
|
+
}
|
|
5348
|
+
currentHoveredNode = { element: circle, node };
|
|
5349
|
+
applyHoverStyles(circle, node, hoverStyle);
|
|
5350
|
+
};
|
|
5351
|
+
if (enableDebouncing) {
|
|
5352
|
+
hoverTimerManager.clearTimer("hover-enter");
|
|
5353
|
+
hoverTimerManager.clearTimer("hover-leave");
|
|
5354
|
+
hoverTimerManager.debounce("hover-enter", applyHover, enterDelay);
|
|
5355
|
+
} else {
|
|
5356
|
+
applyHover();
|
|
5106
5357
|
}
|
|
5107
|
-
}).on("mouseleave.hover", function(_event,
|
|
5358
|
+
}).on("mouseleave.hover", function(_event, node) {
|
|
5108
5359
|
const circle = this;
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5360
|
+
const removeHover = () => {
|
|
5361
|
+
if (currentHoveredNode?.element === circle) {
|
|
5362
|
+
currentHoveredNode = null;
|
|
5363
|
+
removeHoverStyles(circle, node);
|
|
5364
|
+
clearAllHoverLayers();
|
|
5365
|
+
}
|
|
5366
|
+
};
|
|
5367
|
+
if (enableDebouncing) {
|
|
5368
|
+
hoverTimerManager.clearTimer("hover-enter");
|
|
5369
|
+
hoverTimerManager.debounce("hover-leave", removeHover, leaveDelay);
|
|
5370
|
+
} else {
|
|
5371
|
+
removeHover();
|
|
5112
5372
|
}
|
|
5113
|
-
circle.style.stroke = "";
|
|
5114
|
-
circle.style.strokeWidth = "";
|
|
5115
|
-
circle.style.opacity = "";
|
|
5116
5373
|
});
|
|
5117
5374
|
}
|
|
5118
5375
|
const svgElement = firstNode.ownerSVGElement;
|
|
@@ -5166,6 +5423,9 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5166
5423
|
if (hoveredNodeElement.dataset.selected === "true") {
|
|
5167
5424
|
return;
|
|
5168
5425
|
}
|
|
5426
|
+
if (!currentHoveredNode || currentHoveredNode.element !== hoveredNodeElement) {
|
|
5427
|
+
return;
|
|
5428
|
+
}
|
|
5169
5429
|
clearAllHoverLayers();
|
|
5170
5430
|
const hoverNodesLayer = root2.select('[data-layer="hover-nodes"]').node();
|
|
5171
5431
|
if (hoverNodesLayer) {
|
|
@@ -5212,7 +5472,10 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5212
5472
|
}
|
|
5213
5473
|
});
|
|
5214
5474
|
}).on("mouseleave.links", function(_event, _hoveredNode) {
|
|
5215
|
-
|
|
5475
|
+
const hoveredNodeElement = this;
|
|
5476
|
+
if (currentHoveredNode?.element === hoveredNodeElement) {
|
|
5477
|
+
clearAllHoverLayers();
|
|
5478
|
+
}
|
|
5216
5479
|
});
|
|
5217
5480
|
}
|
|
5218
5481
|
|
|
@@ -5281,7 +5544,7 @@ function createLinkHover(linkSelection, hoverStyle) {
|
|
|
5281
5544
|
}
|
|
5282
5545
|
}
|
|
5283
5546
|
const labelSelection2 = root2.select('[data-layer="link-labels"]').selectAll(".link-label");
|
|
5284
|
-
labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1)
|
|
5547
|
+
labelSelection2.filter((item) => item.link === renderableLink.link && item.style.label.visibility === "hover").style("opacity", 1);
|
|
5285
5548
|
}).on("mouseleave.hover", function(_event, renderableLink) {
|
|
5286
5549
|
const hoveredElement = this;
|
|
5287
5550
|
let targetLinkElement;
|
|
@@ -5578,7 +5841,47 @@ function getDefaultContent(node) {
|
|
|
5578
5841
|
|
|
5579
5842
|
// src/utils/node-link-selection.utils.ts
|
|
5580
5843
|
function createLinkHitArea(root2, linkSelection) {
|
|
5581
|
-
return root2.select('[data-layer="links"]').selectAll("
|
|
5844
|
+
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) {
|
|
5845
|
+
const rectElement = this;
|
|
5846
|
+
updateHitAreaDimensions(rectElement, item, root2);
|
|
5847
|
+
});
|
|
5848
|
+
}
|
|
5849
|
+
function updateHitAreaDimensions(rectElement, item, root2) {
|
|
5850
|
+
const source = item.link.source;
|
|
5851
|
+
const target = item.link.target;
|
|
5852
|
+
if (!source.x || !source.y || !target.x || !target.y) return;
|
|
5853
|
+
const midX = (source.x + target.x) / 2;
|
|
5854
|
+
const midY = (source.y + target.y) / 2;
|
|
5855
|
+
const linkPadding = Math.max(item.style.strokeWidth || 2, item.style.arrow.size) * 2;
|
|
5856
|
+
let width = linkPadding;
|
|
5857
|
+
let height = linkPadding;
|
|
5858
|
+
if (item.link.label) {
|
|
5859
|
+
const labelElement = root2.select('[data-layer="link-labels"]').selectAll(".link-label").filter((labelItem) => labelItem.link === item.link).node();
|
|
5860
|
+
if (labelElement) {
|
|
5861
|
+
try {
|
|
5862
|
+
const textElement = labelElement.querySelector("text");
|
|
5863
|
+
const rectElement2 = labelElement.querySelector("rect");
|
|
5864
|
+
if (textElement && rectElement2) {
|
|
5865
|
+
const bbox = textElement.getBBox();
|
|
5866
|
+
const labelWidth = bbox.width + item.style.label.paddingX * 2;
|
|
5867
|
+
const labelHeight = bbox.height + item.style.label.paddingY * 2;
|
|
5868
|
+
width = Math.max(width, labelWidth + 10);
|
|
5869
|
+
height = Math.max(height, labelHeight + 10);
|
|
5870
|
+
}
|
|
5871
|
+
} catch {
|
|
5872
|
+
const text = item.link.label ?? "";
|
|
5873
|
+
const fontSize = item.style.label.fontSize;
|
|
5874
|
+
const estimatedWidth = text.length * fontSize * 0.6 + item.style.label.paddingX * 2 + 10;
|
|
5875
|
+
const estimatedHeight = fontSize + item.style.label.paddingY * 2 + 10;
|
|
5876
|
+
width = Math.max(width, estimatedWidth);
|
|
5877
|
+
height = Math.max(height, estimatedHeight);
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
rectElement.setAttribute("x", String(midX - width / 2));
|
|
5882
|
+
rectElement.setAttribute("y", String(midY - height / 2));
|
|
5883
|
+
rectElement.setAttribute("width", String(width));
|
|
5884
|
+
rectElement.setAttribute("height", String(height));
|
|
5582
5885
|
}
|
|
5583
5886
|
|
|
5584
5887
|
// src/utils/get-link-target-point.ts
|
|
@@ -6290,7 +6593,18 @@ var InteractionManager = class {
|
|
|
6290
6593
|
}
|
|
6291
6594
|
if (this.manager.simulation) {
|
|
6292
6595
|
this.manager.simulation.on("tick.hitarea", () => {
|
|
6293
|
-
linkHitAreaSelection.
|
|
6596
|
+
linkHitAreaSelection.each(function(item) {
|
|
6597
|
+
const source = item.link.source;
|
|
6598
|
+
const target = item.link.target;
|
|
6599
|
+
if (!source.x || !source.y || !target.x || !target.y) return;
|
|
6600
|
+
const rectElement = this;
|
|
6601
|
+
const midX = (source.x + target.x) / 2;
|
|
6602
|
+
const midY = (source.y + target.y) / 2;
|
|
6603
|
+
const width = parseFloat(rectElement.getAttribute("width") || "20");
|
|
6604
|
+
const height = parseFloat(rectElement.getAttribute("height") || "20");
|
|
6605
|
+
rectElement.setAttribute("x", String(midX - width / 2));
|
|
6606
|
+
rectElement.setAttribute("y", String(midY - height / 2));
|
|
6607
|
+
});
|
|
6294
6608
|
});
|
|
6295
6609
|
}
|
|
6296
6610
|
if (this.manager.selectionManager) {
|
package/package.json
CHANGED