polly-graph 0.1.9 → 0.1.11
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/README.md +4 -0
- package/dist/index.cjs +310 -28
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +310 -28
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# polly-graph
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/polly-graph)
|
|
4
|
+
[](http://www.typescriptlang.org/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
3
7
|
A framework-independent TypeScript-based D3 graph visualization SDK that provides a comprehensive, reusable solution for creating interactive network graphs. Designed to work seamlessly across React, Angular, Vue, Svelte, or vanilla JavaScript applications.
|
|
4
8
|
|
|
5
9
|
## Features
|
package/dist/index.cjs
CHANGED
|
@@ -5107,6 +5107,258 @@ function createDragBehavior(simulation, onDragStart, canvasBounds) {
|
|
|
5107
5107
|
});
|
|
5108
5108
|
}
|
|
5109
5109
|
|
|
5110
|
+
// src/utils/node-style-manager.ts
|
|
5111
|
+
var NodeStyleManager = class {
|
|
5112
|
+
styleStates = /* @__PURE__ */ new Map();
|
|
5113
|
+
/**
|
|
5114
|
+
* Initialize a node's style state by capturing its original styles
|
|
5115
|
+
*/
|
|
5116
|
+
initializeNode(element, node) {
|
|
5117
|
+
if (this.styleStates.has(element)) {
|
|
5118
|
+
return;
|
|
5119
|
+
}
|
|
5120
|
+
const domBackup = {
|
|
5121
|
+
stroke: element.getAttribute("stroke"),
|
|
5122
|
+
strokeWidth: element.getAttribute("stroke-width"),
|
|
5123
|
+
opacity: element.getAttribute("opacity"),
|
|
5124
|
+
fill: element.getAttribute("fill")
|
|
5125
|
+
};
|
|
5126
|
+
const originalStyle = {
|
|
5127
|
+
stroke: node.style?.stroke || void 0,
|
|
5128
|
+
strokeWidth: node.style?.strokeWidth || void 0,
|
|
5129
|
+
opacity: node.style?.opacity || void 0,
|
|
5130
|
+
fill: node.style?.fill || void 0
|
|
5131
|
+
};
|
|
5132
|
+
this.styleStates.set(element, {
|
|
5133
|
+
original: originalStyle,
|
|
5134
|
+
current: { ...originalStyle },
|
|
5135
|
+
domBackup
|
|
5136
|
+
});
|
|
5137
|
+
}
|
|
5138
|
+
/**
|
|
5139
|
+
* Apply temporary styles (e.g., hover effects) that will be reset later
|
|
5140
|
+
*/
|
|
5141
|
+
applyTemporaryStyles(element, styles) {
|
|
5142
|
+
this.applyStylesToDOM(element, styles);
|
|
5143
|
+
}
|
|
5144
|
+
/**
|
|
5145
|
+
* Apply permanent styles that become the new base styles
|
|
5146
|
+
*/
|
|
5147
|
+
applyPermanentStyles(element, styles) {
|
|
5148
|
+
const state = this.styleStates.get(element);
|
|
5149
|
+
if (!state) {
|
|
5150
|
+
console.warn("[NodeStyleManager] Node not initialized, cannot apply permanent styles");
|
|
5151
|
+
return;
|
|
5152
|
+
}
|
|
5153
|
+
this.applyStylesToDOM(element, styles);
|
|
5154
|
+
Object.assign(state.current, styles);
|
|
5155
|
+
}
|
|
5156
|
+
/**
|
|
5157
|
+
* Reset node to its current base styles (removes temporary styles)
|
|
5158
|
+
*/
|
|
5159
|
+
resetToBase(element) {
|
|
5160
|
+
const state = this.styleStates.get(element);
|
|
5161
|
+
if (!state) {
|
|
5162
|
+
this.clearAllStyles(element);
|
|
5163
|
+
return;
|
|
5164
|
+
}
|
|
5165
|
+
this.clearAllStyles(element);
|
|
5166
|
+
this.applyStylesToDOM(element, state.current);
|
|
5167
|
+
}
|
|
5168
|
+
/**
|
|
5169
|
+
* Reset node to its original styles (as captured during initialization)
|
|
5170
|
+
*/
|
|
5171
|
+
resetToOriginal(element) {
|
|
5172
|
+
const state = this.styleStates.get(element);
|
|
5173
|
+
if (!state) {
|
|
5174
|
+
this.clearAllStyles(element);
|
|
5175
|
+
return;
|
|
5176
|
+
}
|
|
5177
|
+
this.clearAllStyles(element);
|
|
5178
|
+
this.restoreOriginalDOM(element, state.domBackup);
|
|
5179
|
+
state.current = { ...state.original };
|
|
5180
|
+
}
|
|
5181
|
+
/**
|
|
5182
|
+
* Check if node is in a specific state (selected, hovered, etc.)
|
|
5183
|
+
*/
|
|
5184
|
+
hasState(element, stateName) {
|
|
5185
|
+
return element.dataset[stateName] === "true";
|
|
5186
|
+
}
|
|
5187
|
+
/**
|
|
5188
|
+
* Set state marker on node
|
|
5189
|
+
*/
|
|
5190
|
+
setState(element, stateName, value) {
|
|
5191
|
+
if (value) {
|
|
5192
|
+
element.dataset[stateName] = "true";
|
|
5193
|
+
} else {
|
|
5194
|
+
delete element.dataset[stateName];
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
/**
|
|
5198
|
+
* Get the original styles for a node
|
|
5199
|
+
*/
|
|
5200
|
+
getOriginalStyles(element) {
|
|
5201
|
+
const state = this.styleStates.get(element);
|
|
5202
|
+
return state ? { ...state.original } : null;
|
|
5203
|
+
}
|
|
5204
|
+
/**
|
|
5205
|
+
* Get the current base styles for a node
|
|
5206
|
+
*/
|
|
5207
|
+
getCurrentStyles(element) {
|
|
5208
|
+
const state = this.styleStates.get(element);
|
|
5209
|
+
return state ? { ...state.current } : null;
|
|
5210
|
+
}
|
|
5211
|
+
/**
|
|
5212
|
+
* Remove a node from management (cleanup)
|
|
5213
|
+
*/
|
|
5214
|
+
removeNode(element) {
|
|
5215
|
+
this.styleStates.delete(element);
|
|
5216
|
+
}
|
|
5217
|
+
/**
|
|
5218
|
+
* Clear all managed nodes (for cleanup)
|
|
5219
|
+
*/
|
|
5220
|
+
clear() {
|
|
5221
|
+
this.styleStates.clear();
|
|
5222
|
+
}
|
|
5223
|
+
/**
|
|
5224
|
+
* Private: Apply styles to DOM element
|
|
5225
|
+
*/
|
|
5226
|
+
applyStylesToDOM(element, styles) {
|
|
5227
|
+
if (styles.stroke !== void 0) {
|
|
5228
|
+
if (styles.stroke === null || styles.stroke === "") {
|
|
5229
|
+
element.removeAttribute("stroke");
|
|
5230
|
+
element.style.stroke = "";
|
|
5231
|
+
} else {
|
|
5232
|
+
element.style.stroke = styles.stroke;
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
if (styles.strokeWidth !== void 0) {
|
|
5236
|
+
if (styles.strokeWidth === null || styles.strokeWidth === 0) {
|
|
5237
|
+
element.removeAttribute("stroke-width");
|
|
5238
|
+
element.style.strokeWidth = "";
|
|
5239
|
+
} else {
|
|
5240
|
+
element.style.strokeWidth = String(styles.strokeWidth);
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
if (styles.opacity !== void 0) {
|
|
5244
|
+
if (styles.opacity === null || styles.opacity === 1) {
|
|
5245
|
+
element.removeAttribute("opacity");
|
|
5246
|
+
element.style.opacity = "";
|
|
5247
|
+
} else {
|
|
5248
|
+
element.style.opacity = String(styles.opacity);
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5251
|
+
if (styles.fill !== void 0) {
|
|
5252
|
+
if (styles.fill === null || styles.fill === "") {
|
|
5253
|
+
element.removeAttribute("fill");
|
|
5254
|
+
element.style.fill = "";
|
|
5255
|
+
} else {
|
|
5256
|
+
element.style.fill = styles.fill;
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
if (styles.radius !== void 0) {
|
|
5260
|
+
if (styles.radius === null || styles.radius === 0) {
|
|
5261
|
+
element.removeAttribute("r");
|
|
5262
|
+
element.style.removeProperty("r");
|
|
5263
|
+
} else {
|
|
5264
|
+
element.setAttribute("r", String(styles.radius));
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
/**
|
|
5269
|
+
* Private: Clear all inline styles and remove hover-related attributes
|
|
5270
|
+
*/
|
|
5271
|
+
clearAllStyles(element) {
|
|
5272
|
+
element.style.stroke = "";
|
|
5273
|
+
element.style.strokeWidth = "";
|
|
5274
|
+
element.style.opacity = "";
|
|
5275
|
+
element.style.fill = "";
|
|
5276
|
+
element.style.removeProperty("r");
|
|
5277
|
+
this.removeIfHoverAttribute(element, "stroke");
|
|
5278
|
+
this.removeIfHoverAttribute(element, "stroke-width");
|
|
5279
|
+
this.removeIfHoverAttribute(element, "opacity");
|
|
5280
|
+
}
|
|
5281
|
+
/**
|
|
5282
|
+
* Private: Restore original DOM attributes
|
|
5283
|
+
*/
|
|
5284
|
+
restoreOriginalDOM(element, domBackup) {
|
|
5285
|
+
if (domBackup.stroke !== void 0) {
|
|
5286
|
+
if (domBackup.stroke === null) {
|
|
5287
|
+
element.removeAttribute("stroke");
|
|
5288
|
+
} else {
|
|
5289
|
+
element.setAttribute("stroke", domBackup.stroke);
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
if (domBackup.strokeWidth !== void 0) {
|
|
5293
|
+
if (domBackup.strokeWidth === null) {
|
|
5294
|
+
element.removeAttribute("stroke-width");
|
|
5295
|
+
} else {
|
|
5296
|
+
element.setAttribute("stroke-width", domBackup.strokeWidth);
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
5299
|
+
if (domBackup.opacity !== void 0) {
|
|
5300
|
+
if (domBackup.opacity === null) {
|
|
5301
|
+
element.removeAttribute("opacity");
|
|
5302
|
+
} else {
|
|
5303
|
+
element.setAttribute("opacity", domBackup.opacity);
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
if (domBackup.fill !== void 0) {
|
|
5307
|
+
if (domBackup.fill === null) {
|
|
5308
|
+
element.removeAttribute("fill");
|
|
5309
|
+
} else {
|
|
5310
|
+
element.setAttribute("fill", domBackup.fill);
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
/**
|
|
5315
|
+
* Private: Remove attribute only if it looks like it was set by hover/interaction
|
|
5316
|
+
*/
|
|
5317
|
+
removeIfHoverAttribute(element, attr) {
|
|
5318
|
+
const value = element.getAttribute(attr);
|
|
5319
|
+
if (!value) return;
|
|
5320
|
+
const hoverPatterns = {
|
|
5321
|
+
"stroke": ["#6366f1", "#8b5cf6", "#3b82f6", "#ffffff", "#fff", "white"],
|
|
5322
|
+
// Common hover stroke colors
|
|
5323
|
+
"stroke-width": ["2", "2.5", "3", "4"],
|
|
5324
|
+
// Common hover stroke widths
|
|
5325
|
+
"opacity": ["0.8", "0.9", "0.7"]
|
|
5326
|
+
// Common hover opacity values
|
|
5327
|
+
};
|
|
5328
|
+
const patterns = hoverPatterns[attr];
|
|
5329
|
+
if (patterns && patterns.includes(value)) {
|
|
5330
|
+
element.removeAttribute(attr);
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
};
|
|
5334
|
+
var nodeStyleManager = new NodeStyleManager();
|
|
5335
|
+
function applyHoverStyles(element, node, hoverStyle) {
|
|
5336
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5337
|
+
return;
|
|
5338
|
+
}
|
|
5339
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5340
|
+
nodeStyleManager.applyTemporaryStyles(element, hoverStyle);
|
|
5341
|
+
nodeStyleManager.setState(element, "hovered", true);
|
|
5342
|
+
}
|
|
5343
|
+
function removeHoverStyles(element, node) {
|
|
5344
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5345
|
+
return;
|
|
5346
|
+
}
|
|
5347
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5348
|
+
nodeStyleManager.resetToBase(element);
|
|
5349
|
+
nodeStyleManager.setState(element, "hovered", false);
|
|
5350
|
+
}
|
|
5351
|
+
function applySelectionStyles(element, node, selectionStyle) {
|
|
5352
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5353
|
+
nodeStyleManager.applyPermanentStyles(element, selectionStyle);
|
|
5354
|
+
nodeStyleManager.setState(element, "selected", true);
|
|
5355
|
+
}
|
|
5356
|
+
function removeSelectionStyles(element, node) {
|
|
5357
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5358
|
+
nodeStyleManager.resetToOriginal(element);
|
|
5359
|
+
nodeStyleManager.setState(element, "selected", false);
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5110
5362
|
// src/interactions/create-node-hover.ts
|
|
5111
5363
|
function createNodeHover(nodeSelection, hoverStyle) {
|
|
5112
5364
|
const firstNode = nodeSelection.node();
|
|
@@ -5114,14 +5366,10 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5114
5366
|
if (hoverStyle) {
|
|
5115
5367
|
nodeSelection.on("mouseenter.hover", function(_event, node) {
|
|
5116
5368
|
const circle = this;
|
|
5117
|
-
circle
|
|
5118
|
-
circle.setAttribute("stroke-width", String(hoverStyle.strokeWidth ?? node.style?.strokeWidth ?? 1.5));
|
|
5119
|
-
circle.setAttribute("opacity", String(hoverStyle.opacity ?? node.style?.opacity ?? 1));
|
|
5369
|
+
applyHoverStyles(circle, node, hoverStyle);
|
|
5120
5370
|
}).on("mouseleave.hover", function(_event, node) {
|
|
5121
5371
|
const circle = this;
|
|
5122
|
-
circle
|
|
5123
|
-
circle.setAttribute("stroke-width", String(node.style?.strokeWidth ?? 1.5));
|
|
5124
|
-
circle.setAttribute("opacity", String(node.style?.opacity ?? 1));
|
|
5372
|
+
removeHoverStyles(circle, node);
|
|
5125
5373
|
});
|
|
5126
5374
|
}
|
|
5127
5375
|
const svgElement = firstNode.ownerSVGElement;
|
|
@@ -5518,6 +5766,8 @@ function bindNodeTooltip(params) {
|
|
|
5518
5766
|
destroy: () => {
|
|
5519
5767
|
},
|
|
5520
5768
|
reposition: () => {
|
|
5769
|
+
},
|
|
5770
|
+
hide: () => {
|
|
5521
5771
|
}
|
|
5522
5772
|
};
|
|
5523
5773
|
}
|
|
@@ -5527,6 +5777,9 @@ function bindNodeTooltip(params) {
|
|
|
5527
5777
|
"mouseenter.tooltip",
|
|
5528
5778
|
function(event, node) {
|
|
5529
5779
|
const target = this;
|
|
5780
|
+
if (target.dataset.selected === "true") {
|
|
5781
|
+
return;
|
|
5782
|
+
}
|
|
5530
5783
|
activeTarget = target;
|
|
5531
5784
|
const customContent = params.tooltipConfig?.renderContent?.(node);
|
|
5532
5785
|
const content = customContent ?? getDefaultContent(node);
|
|
@@ -5536,6 +5789,11 @@ function bindNodeTooltip(params) {
|
|
|
5536
5789
|
"mousemove.tooltip",
|
|
5537
5790
|
function() {
|
|
5538
5791
|
const target = this;
|
|
5792
|
+
if (target.dataset.selected === "true") {
|
|
5793
|
+
activeTarget = null;
|
|
5794
|
+
tooltip.hide();
|
|
5795
|
+
return;
|
|
5796
|
+
}
|
|
5539
5797
|
activeTarget = target;
|
|
5540
5798
|
tooltip.move(target);
|
|
5541
5799
|
}
|
|
@@ -5552,12 +5810,16 @@ function bindNodeTooltip(params) {
|
|
|
5552
5810
|
}
|
|
5553
5811
|
tooltip.move(activeTarget);
|
|
5554
5812
|
}
|
|
5813
|
+
function hide() {
|
|
5814
|
+
activeTarget = null;
|
|
5815
|
+
tooltip.hide();
|
|
5816
|
+
}
|
|
5555
5817
|
function destroy() {
|
|
5556
5818
|
activeTarget = null;
|
|
5557
5819
|
params.selection.on(".tooltip", null);
|
|
5558
5820
|
tooltip.destroy();
|
|
5559
5821
|
}
|
|
5560
|
-
return { destroy, reposition };
|
|
5822
|
+
return { destroy, reposition, hide };
|
|
5561
5823
|
}
|
|
5562
5824
|
function getDefaultContent(node) {
|
|
5563
5825
|
return `
|
|
@@ -5787,27 +6049,27 @@ var SelectionManager = class {
|
|
|
5787
6049
|
layers;
|
|
5788
6050
|
linkMarkerSnapshots;
|
|
5789
6051
|
root;
|
|
5790
|
-
|
|
6052
|
+
tooltipBinding;
|
|
6053
|
+
constructor(eventEmitter, config, layers, linkMarkerSnapshots, root2, tooltipBinding) {
|
|
5791
6054
|
this.eventEmitter = eventEmitter;
|
|
5792
6055
|
this.config = config;
|
|
5793
6056
|
this.layers = layers;
|
|
5794
6057
|
this.linkMarkerSnapshots = linkMarkerSnapshots;
|
|
5795
6058
|
this.root = root2;
|
|
6059
|
+
this.tooltipBinding = tooltipBinding;
|
|
5796
6060
|
}
|
|
5797
6061
|
/**
|
|
5798
6062
|
* Select a node, automatically deselecting any current selection
|
|
5799
6063
|
*/
|
|
5800
6064
|
selectNode(nodeElement, nodeData) {
|
|
6065
|
+
if (this.tooltipBinding) {
|
|
6066
|
+
this.tooltipBinding.hide();
|
|
6067
|
+
}
|
|
5801
6068
|
this.clearHoverState();
|
|
5802
6069
|
this.clearSelection();
|
|
5803
6070
|
this.bringNodeToFront(nodeElement, nodeData);
|
|
5804
6071
|
if (this.config.nodeStyle) {
|
|
5805
|
-
|
|
5806
|
-
if (style.fill !== void 0) nodeElement.style.fill = style.fill;
|
|
5807
|
-
if (style.stroke !== void 0) nodeElement.style.stroke = style.stroke;
|
|
5808
|
-
if (style.strokeWidth !== void 0) nodeElement.style.strokeWidth = String(style.strokeWidth);
|
|
5809
|
-
if (style.opacity !== void 0) nodeElement.style.opacity = String(style.opacity);
|
|
5810
|
-
if (style.radius !== void 0) nodeElement.style.setProperty("r", String(style.radius));
|
|
6072
|
+
applySelectionStyles(nodeElement, nodeData, this.config.nodeStyle);
|
|
5811
6073
|
}
|
|
5812
6074
|
this.root.selectAll(".link-label").filter((item) => {
|
|
5813
6075
|
if (item.style.label.visibility !== "hover") return false;
|
|
@@ -5858,12 +6120,7 @@ var SelectionManager = class {
|
|
|
5858
6120
|
if (!this.state.selectedNode) return;
|
|
5859
6121
|
const { element, data } = this.state.selectedNode;
|
|
5860
6122
|
this.restoreSelectedElements(data);
|
|
5861
|
-
element
|
|
5862
|
-
element.style.stroke = "";
|
|
5863
|
-
element.style.strokeWidth = "";
|
|
5864
|
-
element.style.opacity = "";
|
|
5865
|
-
element.style.removeProperty("r");
|
|
5866
|
-
delete element.dataset.selected;
|
|
6123
|
+
removeSelectionStyles(element, data);
|
|
5867
6124
|
this.root.selectAll(".link-label.label-selection-pinned").classed("label-selection-pinned", false).interrupt().transition().duration(200).style("opacity", 0).style("pointer-events", "none");
|
|
5868
6125
|
this.state.selectedNode = null;
|
|
5869
6126
|
this.eventEmitter.emit("nodeDeselect", { node: data, element });
|
|
@@ -6088,18 +6345,42 @@ var DEFAULT_NODE_HOVER_STYLE = {
|
|
|
6088
6345
|
};
|
|
6089
6346
|
function resolveNodeStyle(params) {
|
|
6090
6347
|
if (params.isSelected) {
|
|
6091
|
-
return
|
|
6348
|
+
return mergeNodeStyleSmart(DEFAULT_NODE_HOVER_STYLE, params.interaction?.selection?.nodeStyle);
|
|
6092
6349
|
}
|
|
6093
6350
|
if (params.isHovered) {
|
|
6094
|
-
return
|
|
6351
|
+
return mergeNodeStyleSmart(DEFAULT_NODE_HOVER_STYLE, params.interaction?.hover?.nodeStyle);
|
|
6095
6352
|
}
|
|
6096
6353
|
return void 0;
|
|
6097
6354
|
}
|
|
6098
|
-
function
|
|
6099
|
-
return
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6355
|
+
function mergeNodeStyleSmart(base, override) {
|
|
6356
|
+
if (!override) return base;
|
|
6357
|
+
const result = { ...override };
|
|
6358
|
+
if (override.strokeWidth !== void 0 && override.stroke === void 0 && base.stroke !== void 0) {
|
|
6359
|
+
result.stroke = base.stroke;
|
|
6360
|
+
}
|
|
6361
|
+
const baseKeys = Object.keys(base);
|
|
6362
|
+
baseKeys.forEach((key) => {
|
|
6363
|
+
if (key !== "stroke" && override[key] === void 0 && base[key] !== void 0) {
|
|
6364
|
+
switch (key) {
|
|
6365
|
+
case "fill":
|
|
6366
|
+
result.fill = base.fill;
|
|
6367
|
+
break;
|
|
6368
|
+
case "strokeWidth":
|
|
6369
|
+
result.strokeWidth = base.strokeWidth;
|
|
6370
|
+
break;
|
|
6371
|
+
case "opacity":
|
|
6372
|
+
result.opacity = base.opacity;
|
|
6373
|
+
break;
|
|
6374
|
+
case "radius":
|
|
6375
|
+
result.radius = base.radius;
|
|
6376
|
+
break;
|
|
6377
|
+
case "textColor":
|
|
6378
|
+
result.textColor = base.textColor;
|
|
6379
|
+
break;
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
});
|
|
6383
|
+
return result;
|
|
6103
6384
|
}
|
|
6104
6385
|
|
|
6105
6386
|
// src/core/interaction-manager.ts
|
|
@@ -6199,7 +6480,8 @@ var InteractionManager = class {
|
|
|
6199
6480
|
this.manager.config.interaction.selection,
|
|
6200
6481
|
this.manager.layers,
|
|
6201
6482
|
this.manager.linkMarkerSnapshots,
|
|
6202
|
-
this.manager.rootSelection
|
|
6483
|
+
this.manager.rootSelection,
|
|
6484
|
+
this.manager.tooltipBinding || void 0
|
|
6203
6485
|
);
|
|
6204
6486
|
this.setupSelectionHandlers(selections);
|
|
6205
6487
|
this.setupBackgroundClickHandler();
|
package/dist/index.d.cts
CHANGED
|
@@ -537,6 +537,12 @@ interface RenderableGraphLink {
|
|
|
537
537
|
readonly markerEnd: string;
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
+
interface NodeTooltipBinding {
|
|
541
|
+
destroy(): void;
|
|
542
|
+
reposition(): void;
|
|
543
|
+
hide(): void;
|
|
544
|
+
}
|
|
545
|
+
|
|
540
546
|
/**
|
|
541
547
|
* Centralized selection management for graph nodes and links.
|
|
542
548
|
* Simplifies selection logic and ensures consistent behavior.
|
|
@@ -560,7 +566,8 @@ declare class SelectionManager {
|
|
|
560
566
|
private readonly layers;
|
|
561
567
|
private readonly linkMarkerSnapshots;
|
|
562
568
|
private readonly root;
|
|
563
|
-
|
|
569
|
+
private readonly tooltipBinding?;
|
|
570
|
+
constructor(eventEmitter: TypedGraphEventEmitter, config: SelectionInteractionConfig, layers: GraphLayers, linkMarkerSnapshots: Map<SVGLineElement, string | null>, root: Selection<SVGGElement, unknown, null, undefined>, tooltipBinding?: NodeTooltipBinding);
|
|
564
571
|
/**
|
|
565
572
|
* Select a node, automatically deselecting any current selection
|
|
566
573
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -537,6 +537,12 @@ interface RenderableGraphLink {
|
|
|
537
537
|
readonly markerEnd: string;
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
+
interface NodeTooltipBinding {
|
|
541
|
+
destroy(): void;
|
|
542
|
+
reposition(): void;
|
|
543
|
+
hide(): void;
|
|
544
|
+
}
|
|
545
|
+
|
|
540
546
|
/**
|
|
541
547
|
* Centralized selection management for graph nodes and links.
|
|
542
548
|
* Simplifies selection logic and ensures consistent behavior.
|
|
@@ -560,7 +566,8 @@ declare class SelectionManager {
|
|
|
560
566
|
private readonly layers;
|
|
561
567
|
private readonly linkMarkerSnapshots;
|
|
562
568
|
private readonly root;
|
|
563
|
-
|
|
569
|
+
private readonly tooltipBinding?;
|
|
570
|
+
constructor(eventEmitter: TypedGraphEventEmitter, config: SelectionInteractionConfig, layers: GraphLayers, linkMarkerSnapshots: Map<SVGLineElement, string | null>, root: Selection<SVGGElement, unknown, null, undefined>, tooltipBinding?: NodeTooltipBinding);
|
|
564
571
|
/**
|
|
565
572
|
* Select a node, automatically deselecting any current selection
|
|
566
573
|
*/
|
package/dist/index.js
CHANGED
|
@@ -5075,6 +5075,258 @@ function createDragBehavior(simulation, onDragStart, canvasBounds) {
|
|
|
5075
5075
|
});
|
|
5076
5076
|
}
|
|
5077
5077
|
|
|
5078
|
+
// src/utils/node-style-manager.ts
|
|
5079
|
+
var NodeStyleManager = class {
|
|
5080
|
+
styleStates = /* @__PURE__ */ new Map();
|
|
5081
|
+
/**
|
|
5082
|
+
* Initialize a node's style state by capturing its original styles
|
|
5083
|
+
*/
|
|
5084
|
+
initializeNode(element, node) {
|
|
5085
|
+
if (this.styleStates.has(element)) {
|
|
5086
|
+
return;
|
|
5087
|
+
}
|
|
5088
|
+
const domBackup = {
|
|
5089
|
+
stroke: element.getAttribute("stroke"),
|
|
5090
|
+
strokeWidth: element.getAttribute("stroke-width"),
|
|
5091
|
+
opacity: element.getAttribute("opacity"),
|
|
5092
|
+
fill: element.getAttribute("fill")
|
|
5093
|
+
};
|
|
5094
|
+
const originalStyle = {
|
|
5095
|
+
stroke: node.style?.stroke || void 0,
|
|
5096
|
+
strokeWidth: node.style?.strokeWidth || void 0,
|
|
5097
|
+
opacity: node.style?.opacity || void 0,
|
|
5098
|
+
fill: node.style?.fill || void 0
|
|
5099
|
+
};
|
|
5100
|
+
this.styleStates.set(element, {
|
|
5101
|
+
original: originalStyle,
|
|
5102
|
+
current: { ...originalStyle },
|
|
5103
|
+
domBackup
|
|
5104
|
+
});
|
|
5105
|
+
}
|
|
5106
|
+
/**
|
|
5107
|
+
* Apply temporary styles (e.g., hover effects) that will be reset later
|
|
5108
|
+
*/
|
|
5109
|
+
applyTemporaryStyles(element, styles) {
|
|
5110
|
+
this.applyStylesToDOM(element, styles);
|
|
5111
|
+
}
|
|
5112
|
+
/**
|
|
5113
|
+
* Apply permanent styles that become the new base styles
|
|
5114
|
+
*/
|
|
5115
|
+
applyPermanentStyles(element, styles) {
|
|
5116
|
+
const state = this.styleStates.get(element);
|
|
5117
|
+
if (!state) {
|
|
5118
|
+
console.warn("[NodeStyleManager] Node not initialized, cannot apply permanent styles");
|
|
5119
|
+
return;
|
|
5120
|
+
}
|
|
5121
|
+
this.applyStylesToDOM(element, styles);
|
|
5122
|
+
Object.assign(state.current, styles);
|
|
5123
|
+
}
|
|
5124
|
+
/**
|
|
5125
|
+
* Reset node to its current base styles (removes temporary styles)
|
|
5126
|
+
*/
|
|
5127
|
+
resetToBase(element) {
|
|
5128
|
+
const state = this.styleStates.get(element);
|
|
5129
|
+
if (!state) {
|
|
5130
|
+
this.clearAllStyles(element);
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
5133
|
+
this.clearAllStyles(element);
|
|
5134
|
+
this.applyStylesToDOM(element, state.current);
|
|
5135
|
+
}
|
|
5136
|
+
/**
|
|
5137
|
+
* Reset node to its original styles (as captured during initialization)
|
|
5138
|
+
*/
|
|
5139
|
+
resetToOriginal(element) {
|
|
5140
|
+
const state = this.styleStates.get(element);
|
|
5141
|
+
if (!state) {
|
|
5142
|
+
this.clearAllStyles(element);
|
|
5143
|
+
return;
|
|
5144
|
+
}
|
|
5145
|
+
this.clearAllStyles(element);
|
|
5146
|
+
this.restoreOriginalDOM(element, state.domBackup);
|
|
5147
|
+
state.current = { ...state.original };
|
|
5148
|
+
}
|
|
5149
|
+
/**
|
|
5150
|
+
* Check if node is in a specific state (selected, hovered, etc.)
|
|
5151
|
+
*/
|
|
5152
|
+
hasState(element, stateName) {
|
|
5153
|
+
return element.dataset[stateName] === "true";
|
|
5154
|
+
}
|
|
5155
|
+
/**
|
|
5156
|
+
* Set state marker on node
|
|
5157
|
+
*/
|
|
5158
|
+
setState(element, stateName, value) {
|
|
5159
|
+
if (value) {
|
|
5160
|
+
element.dataset[stateName] = "true";
|
|
5161
|
+
} else {
|
|
5162
|
+
delete element.dataset[stateName];
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
/**
|
|
5166
|
+
* Get the original styles for a node
|
|
5167
|
+
*/
|
|
5168
|
+
getOriginalStyles(element) {
|
|
5169
|
+
const state = this.styleStates.get(element);
|
|
5170
|
+
return state ? { ...state.original } : null;
|
|
5171
|
+
}
|
|
5172
|
+
/**
|
|
5173
|
+
* Get the current base styles for a node
|
|
5174
|
+
*/
|
|
5175
|
+
getCurrentStyles(element) {
|
|
5176
|
+
const state = this.styleStates.get(element);
|
|
5177
|
+
return state ? { ...state.current } : null;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Remove a node from management (cleanup)
|
|
5181
|
+
*/
|
|
5182
|
+
removeNode(element) {
|
|
5183
|
+
this.styleStates.delete(element);
|
|
5184
|
+
}
|
|
5185
|
+
/**
|
|
5186
|
+
* Clear all managed nodes (for cleanup)
|
|
5187
|
+
*/
|
|
5188
|
+
clear() {
|
|
5189
|
+
this.styleStates.clear();
|
|
5190
|
+
}
|
|
5191
|
+
/**
|
|
5192
|
+
* Private: Apply styles to DOM element
|
|
5193
|
+
*/
|
|
5194
|
+
applyStylesToDOM(element, styles) {
|
|
5195
|
+
if (styles.stroke !== void 0) {
|
|
5196
|
+
if (styles.stroke === null || styles.stroke === "") {
|
|
5197
|
+
element.removeAttribute("stroke");
|
|
5198
|
+
element.style.stroke = "";
|
|
5199
|
+
} else {
|
|
5200
|
+
element.style.stroke = styles.stroke;
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
if (styles.strokeWidth !== void 0) {
|
|
5204
|
+
if (styles.strokeWidth === null || styles.strokeWidth === 0) {
|
|
5205
|
+
element.removeAttribute("stroke-width");
|
|
5206
|
+
element.style.strokeWidth = "";
|
|
5207
|
+
} else {
|
|
5208
|
+
element.style.strokeWidth = String(styles.strokeWidth);
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
if (styles.opacity !== void 0) {
|
|
5212
|
+
if (styles.opacity === null || styles.opacity === 1) {
|
|
5213
|
+
element.removeAttribute("opacity");
|
|
5214
|
+
element.style.opacity = "";
|
|
5215
|
+
} else {
|
|
5216
|
+
element.style.opacity = String(styles.opacity);
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
if (styles.fill !== void 0) {
|
|
5220
|
+
if (styles.fill === null || styles.fill === "") {
|
|
5221
|
+
element.removeAttribute("fill");
|
|
5222
|
+
element.style.fill = "";
|
|
5223
|
+
} else {
|
|
5224
|
+
element.style.fill = styles.fill;
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
if (styles.radius !== void 0) {
|
|
5228
|
+
if (styles.radius === null || styles.radius === 0) {
|
|
5229
|
+
element.removeAttribute("r");
|
|
5230
|
+
element.style.removeProperty("r");
|
|
5231
|
+
} else {
|
|
5232
|
+
element.setAttribute("r", String(styles.radius));
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
/**
|
|
5237
|
+
* Private: Clear all inline styles and remove hover-related attributes
|
|
5238
|
+
*/
|
|
5239
|
+
clearAllStyles(element) {
|
|
5240
|
+
element.style.stroke = "";
|
|
5241
|
+
element.style.strokeWidth = "";
|
|
5242
|
+
element.style.opacity = "";
|
|
5243
|
+
element.style.fill = "";
|
|
5244
|
+
element.style.removeProperty("r");
|
|
5245
|
+
this.removeIfHoverAttribute(element, "stroke");
|
|
5246
|
+
this.removeIfHoverAttribute(element, "stroke-width");
|
|
5247
|
+
this.removeIfHoverAttribute(element, "opacity");
|
|
5248
|
+
}
|
|
5249
|
+
/**
|
|
5250
|
+
* Private: Restore original DOM attributes
|
|
5251
|
+
*/
|
|
5252
|
+
restoreOriginalDOM(element, domBackup) {
|
|
5253
|
+
if (domBackup.stroke !== void 0) {
|
|
5254
|
+
if (domBackup.stroke === null) {
|
|
5255
|
+
element.removeAttribute("stroke");
|
|
5256
|
+
} else {
|
|
5257
|
+
element.setAttribute("stroke", domBackup.stroke);
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
if (domBackup.strokeWidth !== void 0) {
|
|
5261
|
+
if (domBackup.strokeWidth === null) {
|
|
5262
|
+
element.removeAttribute("stroke-width");
|
|
5263
|
+
} else {
|
|
5264
|
+
element.setAttribute("stroke-width", domBackup.strokeWidth);
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
if (domBackup.opacity !== void 0) {
|
|
5268
|
+
if (domBackup.opacity === null) {
|
|
5269
|
+
element.removeAttribute("opacity");
|
|
5270
|
+
} else {
|
|
5271
|
+
element.setAttribute("opacity", domBackup.opacity);
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
if (domBackup.fill !== void 0) {
|
|
5275
|
+
if (domBackup.fill === null) {
|
|
5276
|
+
element.removeAttribute("fill");
|
|
5277
|
+
} else {
|
|
5278
|
+
element.setAttribute("fill", domBackup.fill);
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
}
|
|
5282
|
+
/**
|
|
5283
|
+
* Private: Remove attribute only if it looks like it was set by hover/interaction
|
|
5284
|
+
*/
|
|
5285
|
+
removeIfHoverAttribute(element, attr) {
|
|
5286
|
+
const value = element.getAttribute(attr);
|
|
5287
|
+
if (!value) return;
|
|
5288
|
+
const hoverPatterns = {
|
|
5289
|
+
"stroke": ["#6366f1", "#8b5cf6", "#3b82f6", "#ffffff", "#fff", "white"],
|
|
5290
|
+
// Common hover stroke colors
|
|
5291
|
+
"stroke-width": ["2", "2.5", "3", "4"],
|
|
5292
|
+
// Common hover stroke widths
|
|
5293
|
+
"opacity": ["0.8", "0.9", "0.7"]
|
|
5294
|
+
// Common hover opacity values
|
|
5295
|
+
};
|
|
5296
|
+
const patterns = hoverPatterns[attr];
|
|
5297
|
+
if (patterns && patterns.includes(value)) {
|
|
5298
|
+
element.removeAttribute(attr);
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5301
|
+
};
|
|
5302
|
+
var nodeStyleManager = new NodeStyleManager();
|
|
5303
|
+
function applyHoverStyles(element, node, hoverStyle) {
|
|
5304
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5305
|
+
return;
|
|
5306
|
+
}
|
|
5307
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5308
|
+
nodeStyleManager.applyTemporaryStyles(element, hoverStyle);
|
|
5309
|
+
nodeStyleManager.setState(element, "hovered", true);
|
|
5310
|
+
}
|
|
5311
|
+
function removeHoverStyles(element, node) {
|
|
5312
|
+
if (nodeStyleManager.hasState(element, "selected")) {
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5316
|
+
nodeStyleManager.resetToBase(element);
|
|
5317
|
+
nodeStyleManager.setState(element, "hovered", false);
|
|
5318
|
+
}
|
|
5319
|
+
function applySelectionStyles(element, node, selectionStyle) {
|
|
5320
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5321
|
+
nodeStyleManager.applyPermanentStyles(element, selectionStyle);
|
|
5322
|
+
nodeStyleManager.setState(element, "selected", true);
|
|
5323
|
+
}
|
|
5324
|
+
function removeSelectionStyles(element, node) {
|
|
5325
|
+
nodeStyleManager.initializeNode(element, node);
|
|
5326
|
+
nodeStyleManager.resetToOriginal(element);
|
|
5327
|
+
nodeStyleManager.setState(element, "selected", false);
|
|
5328
|
+
}
|
|
5329
|
+
|
|
5078
5330
|
// src/interactions/create-node-hover.ts
|
|
5079
5331
|
function createNodeHover(nodeSelection, hoverStyle) {
|
|
5080
5332
|
const firstNode = nodeSelection.node();
|
|
@@ -5082,14 +5334,10 @@ function createNodeHover(nodeSelection, hoverStyle) {
|
|
|
5082
5334
|
if (hoverStyle) {
|
|
5083
5335
|
nodeSelection.on("mouseenter.hover", function(_event, node) {
|
|
5084
5336
|
const circle = this;
|
|
5085
|
-
circle
|
|
5086
|
-
circle.setAttribute("stroke-width", String(hoverStyle.strokeWidth ?? node.style?.strokeWidth ?? 1.5));
|
|
5087
|
-
circle.setAttribute("opacity", String(hoverStyle.opacity ?? node.style?.opacity ?? 1));
|
|
5337
|
+
applyHoverStyles(circle, node, hoverStyle);
|
|
5088
5338
|
}).on("mouseleave.hover", function(_event, node) {
|
|
5089
5339
|
const circle = this;
|
|
5090
|
-
circle
|
|
5091
|
-
circle.setAttribute("stroke-width", String(node.style?.strokeWidth ?? 1.5));
|
|
5092
|
-
circle.setAttribute("opacity", String(node.style?.opacity ?? 1));
|
|
5340
|
+
removeHoverStyles(circle, node);
|
|
5093
5341
|
});
|
|
5094
5342
|
}
|
|
5095
5343
|
const svgElement = firstNode.ownerSVGElement;
|
|
@@ -5486,6 +5734,8 @@ function bindNodeTooltip(params) {
|
|
|
5486
5734
|
destroy: () => {
|
|
5487
5735
|
},
|
|
5488
5736
|
reposition: () => {
|
|
5737
|
+
},
|
|
5738
|
+
hide: () => {
|
|
5489
5739
|
}
|
|
5490
5740
|
};
|
|
5491
5741
|
}
|
|
@@ -5495,6 +5745,9 @@ function bindNodeTooltip(params) {
|
|
|
5495
5745
|
"mouseenter.tooltip",
|
|
5496
5746
|
function(event, node) {
|
|
5497
5747
|
const target = this;
|
|
5748
|
+
if (target.dataset.selected === "true") {
|
|
5749
|
+
return;
|
|
5750
|
+
}
|
|
5498
5751
|
activeTarget = target;
|
|
5499
5752
|
const customContent = params.tooltipConfig?.renderContent?.(node);
|
|
5500
5753
|
const content = customContent ?? getDefaultContent(node);
|
|
@@ -5504,6 +5757,11 @@ function bindNodeTooltip(params) {
|
|
|
5504
5757
|
"mousemove.tooltip",
|
|
5505
5758
|
function() {
|
|
5506
5759
|
const target = this;
|
|
5760
|
+
if (target.dataset.selected === "true") {
|
|
5761
|
+
activeTarget = null;
|
|
5762
|
+
tooltip.hide();
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5507
5765
|
activeTarget = target;
|
|
5508
5766
|
tooltip.move(target);
|
|
5509
5767
|
}
|
|
@@ -5520,12 +5778,16 @@ function bindNodeTooltip(params) {
|
|
|
5520
5778
|
}
|
|
5521
5779
|
tooltip.move(activeTarget);
|
|
5522
5780
|
}
|
|
5781
|
+
function hide() {
|
|
5782
|
+
activeTarget = null;
|
|
5783
|
+
tooltip.hide();
|
|
5784
|
+
}
|
|
5523
5785
|
function destroy() {
|
|
5524
5786
|
activeTarget = null;
|
|
5525
5787
|
params.selection.on(".tooltip", null);
|
|
5526
5788
|
tooltip.destroy();
|
|
5527
5789
|
}
|
|
5528
|
-
return { destroy, reposition };
|
|
5790
|
+
return { destroy, reposition, hide };
|
|
5529
5791
|
}
|
|
5530
5792
|
function getDefaultContent(node) {
|
|
5531
5793
|
return `
|
|
@@ -5755,27 +6017,27 @@ var SelectionManager = class {
|
|
|
5755
6017
|
layers;
|
|
5756
6018
|
linkMarkerSnapshots;
|
|
5757
6019
|
root;
|
|
5758
|
-
|
|
6020
|
+
tooltipBinding;
|
|
6021
|
+
constructor(eventEmitter, config, layers, linkMarkerSnapshots, root2, tooltipBinding) {
|
|
5759
6022
|
this.eventEmitter = eventEmitter;
|
|
5760
6023
|
this.config = config;
|
|
5761
6024
|
this.layers = layers;
|
|
5762
6025
|
this.linkMarkerSnapshots = linkMarkerSnapshots;
|
|
5763
6026
|
this.root = root2;
|
|
6027
|
+
this.tooltipBinding = tooltipBinding;
|
|
5764
6028
|
}
|
|
5765
6029
|
/**
|
|
5766
6030
|
* Select a node, automatically deselecting any current selection
|
|
5767
6031
|
*/
|
|
5768
6032
|
selectNode(nodeElement, nodeData) {
|
|
6033
|
+
if (this.tooltipBinding) {
|
|
6034
|
+
this.tooltipBinding.hide();
|
|
6035
|
+
}
|
|
5769
6036
|
this.clearHoverState();
|
|
5770
6037
|
this.clearSelection();
|
|
5771
6038
|
this.bringNodeToFront(nodeElement, nodeData);
|
|
5772
6039
|
if (this.config.nodeStyle) {
|
|
5773
|
-
|
|
5774
|
-
if (style.fill !== void 0) nodeElement.style.fill = style.fill;
|
|
5775
|
-
if (style.stroke !== void 0) nodeElement.style.stroke = style.stroke;
|
|
5776
|
-
if (style.strokeWidth !== void 0) nodeElement.style.strokeWidth = String(style.strokeWidth);
|
|
5777
|
-
if (style.opacity !== void 0) nodeElement.style.opacity = String(style.opacity);
|
|
5778
|
-
if (style.radius !== void 0) nodeElement.style.setProperty("r", String(style.radius));
|
|
6040
|
+
applySelectionStyles(nodeElement, nodeData, this.config.nodeStyle);
|
|
5779
6041
|
}
|
|
5780
6042
|
this.root.selectAll(".link-label").filter((item) => {
|
|
5781
6043
|
if (item.style.label.visibility !== "hover") return false;
|
|
@@ -5826,12 +6088,7 @@ var SelectionManager = class {
|
|
|
5826
6088
|
if (!this.state.selectedNode) return;
|
|
5827
6089
|
const { element, data } = this.state.selectedNode;
|
|
5828
6090
|
this.restoreSelectedElements(data);
|
|
5829
|
-
element
|
|
5830
|
-
element.style.stroke = "";
|
|
5831
|
-
element.style.strokeWidth = "";
|
|
5832
|
-
element.style.opacity = "";
|
|
5833
|
-
element.style.removeProperty("r");
|
|
5834
|
-
delete element.dataset.selected;
|
|
6091
|
+
removeSelectionStyles(element, data);
|
|
5835
6092
|
this.root.selectAll(".link-label.label-selection-pinned").classed("label-selection-pinned", false).interrupt().transition().duration(200).style("opacity", 0).style("pointer-events", "none");
|
|
5836
6093
|
this.state.selectedNode = null;
|
|
5837
6094
|
this.eventEmitter.emit("nodeDeselect", { node: data, element });
|
|
@@ -6056,18 +6313,42 @@ var DEFAULT_NODE_HOVER_STYLE = {
|
|
|
6056
6313
|
};
|
|
6057
6314
|
function resolveNodeStyle(params) {
|
|
6058
6315
|
if (params.isSelected) {
|
|
6059
|
-
return
|
|
6316
|
+
return mergeNodeStyleSmart(DEFAULT_NODE_HOVER_STYLE, params.interaction?.selection?.nodeStyle);
|
|
6060
6317
|
}
|
|
6061
6318
|
if (params.isHovered) {
|
|
6062
|
-
return
|
|
6319
|
+
return mergeNodeStyleSmart(DEFAULT_NODE_HOVER_STYLE, params.interaction?.hover?.nodeStyle);
|
|
6063
6320
|
}
|
|
6064
6321
|
return void 0;
|
|
6065
6322
|
}
|
|
6066
|
-
function
|
|
6067
|
-
return
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6323
|
+
function mergeNodeStyleSmart(base, override) {
|
|
6324
|
+
if (!override) return base;
|
|
6325
|
+
const result = { ...override };
|
|
6326
|
+
if (override.strokeWidth !== void 0 && override.stroke === void 0 && base.stroke !== void 0) {
|
|
6327
|
+
result.stroke = base.stroke;
|
|
6328
|
+
}
|
|
6329
|
+
const baseKeys = Object.keys(base);
|
|
6330
|
+
baseKeys.forEach((key) => {
|
|
6331
|
+
if (key !== "stroke" && override[key] === void 0 && base[key] !== void 0) {
|
|
6332
|
+
switch (key) {
|
|
6333
|
+
case "fill":
|
|
6334
|
+
result.fill = base.fill;
|
|
6335
|
+
break;
|
|
6336
|
+
case "strokeWidth":
|
|
6337
|
+
result.strokeWidth = base.strokeWidth;
|
|
6338
|
+
break;
|
|
6339
|
+
case "opacity":
|
|
6340
|
+
result.opacity = base.opacity;
|
|
6341
|
+
break;
|
|
6342
|
+
case "radius":
|
|
6343
|
+
result.radius = base.radius;
|
|
6344
|
+
break;
|
|
6345
|
+
case "textColor":
|
|
6346
|
+
result.textColor = base.textColor;
|
|
6347
|
+
break;
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
6350
|
+
});
|
|
6351
|
+
return result;
|
|
6071
6352
|
}
|
|
6072
6353
|
|
|
6073
6354
|
// src/core/interaction-manager.ts
|
|
@@ -6167,7 +6448,8 @@ var InteractionManager = class {
|
|
|
6167
6448
|
this.manager.config.interaction.selection,
|
|
6168
6449
|
this.manager.layers,
|
|
6169
6450
|
this.manager.linkMarkerSnapshots,
|
|
6170
|
-
this.manager.rootSelection
|
|
6451
|
+
this.manager.rootSelection,
|
|
6452
|
+
this.manager.tooltipBinding || void 0
|
|
6171
6453
|
);
|
|
6172
6454
|
this.setupSelectionHandlers(selections);
|
|
6173
6455
|
this.setupBackgroundClickHandler();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polly-graph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|
|
@@ -52,7 +52,11 @@
|
|
|
52
52
|
"lint": "eslint \"src/**/*.ts\"",
|
|
53
53
|
"typecheck": "tsc --noEmit",
|
|
54
54
|
"test": "vitest run --passWithNoTests",
|
|
55
|
-
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build"
|
|
55
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
56
|
+
"version:patch": "npm version patch",
|
|
57
|
+
"version:minor": "npm version minor",
|
|
58
|
+
"version:major": "npm version major",
|
|
59
|
+
"version:prerelease": "npm version prerelease"
|
|
56
60
|
},
|
|
57
61
|
"dependencies": {
|
|
58
62
|
"d3": "7.9.0"
|