in src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts [679:790]
private addNewNodes(): d3.Selection<Element, any, any, any> {
var self = this;
const newNodes = this.nodeSelection
.enter()
.append("g")
.attr("class", (d: D3Node) => {
return d._isRoot ? "node root" : "node";
})
.call(
drag()
.on("start", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
return this.dragstarted(d, e);
}) as any)
.on("drag", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
return this.dragged(d, e);
}) as any)
.on("end", ((e: D3DragEvent<SVGGElement, D3Node, unknown>, d: D3Node) => {
return this.dragended(d, e);
}) as any),
)
.on("mouseover", (_: MouseEvent, d: D3Node) => {
if (this.isHighlightDisabled || this.selectedNode || this.isDragging) {
return;
}
this.highlightNode(this, d);
this.simulation.stop();
})
.on("mouseout", (_: MouseEvent, d: D3Node) => {
if (this.isHighlightDisabled || this.selectedNode || this.isDragging) {
return;
}
this.unhighlightNode();
this.simulation.restart();
})
.each((d: D3Node) => {
// Initial position for nodes. This prevents blinking as following the tween transition doesn't always start right away
d.x = self.viewCenter.x;
d.y = self.viewCenter.y;
});
newNodes
.append("circle")
.attr("fill", this.getNodeColor.bind(this))
.attr("class", "main")
.attr("r", this.igraphConfig.nodeSize);
var iconGroup = newNodes
.append("g")
.attr("class", "iconContainer")
.attr("role", "group")
.attr("tabindex", 0)
.attr("aria-label", (d: D3Node) => {
return this.retrieveNodeCaption(d);
})
.on("dblclick", function (this: Element, _: MouseEvent, d: D3Node) {
// https://stackoverflow.com/a/41945742 ('this' implicitly has type 'any' because it does not have a type annotation)
// this is the <g> element
self.onNodeClicked(this.parentNode as BaseType, d);
})
.on("click", function (this: Element, _: MouseEvent, d: D3Node) {
// this is the <g> element
self.onNodeClicked(this.parentNode as BaseType, d);
})
.on("keypress", function (this: Element, event: KeyboardEvent, d: D3Node) {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
event.stopPropagation();
// this is the <g> element
self.onNodeClicked(this.parentNode as BaseType, d);
}
});
var nodeSize = this.igraphConfig.nodeSize;
var bgsize = nodeSize + 1;
iconGroup
.append("rect")
.attr("x", -bgsize)
.attr("y", -bgsize)
.attr("width", bgsize * 2)
.attr("height", bgsize * 2)
.attr("fill-opacity", (d: D3Node) => {
return this.igraphConfig.nodeIconKey ? 1 : 0;
})
.attr("class", "icon-background");
// Possible icon: if xlink:href is undefined, the image won't show
iconGroup
.append("svg:image")
.attr("xlink:href", (d: D3Node) => {
return D3ForceGraph.computeImageData(d, this.igraphConfig);
})
.attr("x", -nodeSize)
.attr("y", -nodeSize)
.attr("height", nodeSize * 2)
.attr("width", nodeSize * 2)
.attr("class", "icon");
newNodes
.append("text")
.attr("class", "caption")
.attr("dx", D3ForceGraph.TEXT_DX)
.attr("dy", ".35em")
.text((d: D3Node) => {
return this.retrieveNodeCaption(d);
});
this.nodeSelection = newNodes.merge(this.nodeSelection);
return newNodes;
}