in src/sankeyDiagram.ts [1494:1682]
private renderNodes(sankeyDiagramDataView: SankeyDiagramDataView): Selection<SankeyDiagramNode> {
let nodeElements: Selection<SankeyDiagramNode> = this.main
.select(SankeyDiagram.NodesSelector.selectorName)
.selectAll(SankeyDiagram.NodeSelector.selectorName);
let nodesSelectionData = nodeElements
.data(
sankeyDiagramDataView.nodes
.filter((node: SankeyDiagramNode) => {
return node.height > SankeyDiagram.MinSize;
})
);
nodesSelectionData
.exit()
.remove();
let nodesEnterSelection: Selection<SankeyDiagramNode> = nodesSelectionData
.enter()
.append("g");
nodesEnterSelection
.append("rect")
.classed(SankeyDiagram.NodeRectSelector.className, true);
nodesEnterSelection
.append("text")
.classed(SankeyDiagram.NodeLabelSelector.className, true);
let nodesSelectionMerged = nodesEnterSelection.merge(nodeElements);
nodesSelectionMerged
.attr("transform", (node: SankeyDiagramNode) => {
return translate(node.x, node.y);
})
.classed(SankeyDiagram.NodeSelector.className, true);
nodesSelectionMerged
.select(SankeyDiagram.NodeRectSelector.selectorName)
.style("fill", (node: SankeyDiagramNode) => node.fillColor)
.style(
"stroke", (node: SankeyDiagramNode) => this.colorHelper.isHighContrast ? node.strokeColor :
d3.rgb(node.fillColor)
.darker(SankeyDiagram.StrokeColorFactor)
.toString()
)
.attr("x", SankeyDiagram.DefaultPosition)
.attr("y", SankeyDiagram.DefaultPosition)
.attr("height", (node: SankeyDiagramNode) => node.height < SankeyDiagram.MinHeightOfNode ? SankeyDiagram.MinHeightOfNode : node.height)
.attr("width", (node: SankeyDiagramNode) => node.width);
nodesSelectionMerged
.select(SankeyDiagram.NodeLabelSelector.selectorName)
.attr("x", (node: SankeyDiagramNode) => node.left - node.x)
.attr("y", (node: SankeyDiagramNode) => node.top - node.y)
.attr("dy", SankeyDiagram.DefaultDy)
.style("fill", (node: SankeyDiagramNode) => node.label.color)
.style("font-family", this.textProperties.fontFamily)
.style("font-size", this.textProperties.fontSize)
.style("display", (node: SankeyDiagramNode) => {
let isNotVisibleLabel: boolean,
labelPositionByAxisX: number = this.getCurrentPositionOfLabelByAxisX(node);
isNotVisibleLabel =
(labelPositionByAxisX >= this.viewport.width ||
labelPositionByAxisX <= SankeyDiagram.MinSize ||
(node.height + SankeyDiagram.NodeMargin) < node.label.height) && !sankeyDiagramDataView.settings.labels.forceDisplay;
if (isNotVisibleLabel || !sankeyDiagramDataView.settings.labels.show
|| node.label.maxWidth < SankeyDiagram.MinWidthOfLabel) {
return SankeyDiagram.DisplayNone;
}
return null;
})
.style("text-anchor", (node: SankeyDiagramNode) => {
if (this.isLabelLargerThanWidth(node)) {
return SankeyDiagram.TextAnchorEnd;
}
return null;
})
.text((node: SankeyDiagramNode) => {
if (node.label.width > node.label.maxWidth) {
return textMeasurementService.getTailoredTextOrDefault({
text: node.label.formattedName,
fontFamily: this.textProperties.fontFamily,
fontSize: this.textProperties.fontSize
}, node.label.maxWidth);
}
return node.label.formattedName;
});
function dragstarted(node: SankeyDiagramNode) {
(<any>getEvent()).sourceEvent.stopPropagation();
}
let minHeight: number = d3.min(sankeyDiagramDataView.links.map(l => l.height));
let sankeyVisual = this;
function dragged(node: SankeyDiagramNode) {
node.x = (getEvent()).x;
node.y = (getEvent()).y;
if (node.x < 0) {
node.x = 0;
}
if (node.y < 0) {
node.y = 0;
}
if (node.x + node.width > sankeyVisual.viewport.width) {
node.x = sankeyVisual.viewport.width - node.width;
}
if (node.y + node.height > sankeyVisual.viewport.height) {
node.y = sankeyVisual.viewport.height - node.height;
}
node.settings = {
x: node.x.toFixed(2),
y: node.y.toFixed(2),
name: node.label.name
};
// Update each link related with this node
node.links.forEach((link: SankeyDiagramLink) => {
// select link svg element by ID generated in link creation as Source-Destination
d3.select(`#${SankeyDiagram.createLink(link, true)}`).attr(
// get updated path params based on actual positions of node
"d", (link: SankeyDiagramLink) => {
if (link.direction === SankeyLinkDirrections.Forward) {
return sankeyVisual.getSvgPathForForwardLink(link);
}
if (link.direction === SankeyLinkDirrections.Backward) {
if (link.source.x + link.source.width > link.destination.x) {
return sankeyVisual.getSvgPathForForwardLink(link);
}
return sankeyVisual.getSvgPathForBackwardLink(link);
}
if (link.direction === SankeyLinkDirrections.SelfLink) {
return sankeyVisual.getSvgPathForSelfLink(link, minHeight);
}
}
);
d3.select(`#${SankeyDiagram.createLink(link)}`).attr(
// get updated path params based on actual positions of node
"d", (link: SankeyDiagramLink) => {
if (link.direction === SankeyLinkDirrections.Forward) {
return sankeyVisual.getSvgPathForForwardLink(link);
}
if (link.direction === SankeyLinkDirrections.Backward) {
if (link.source.x + link.source.width > link.destination.x) {
return sankeyVisual.getSvgPathForForwardLink(link);
}
return sankeyVisual.getSvgPathForBackwardLink(link);
}
if (link.direction === SankeyLinkDirrections.SelfLink) {
return sankeyVisual.getSvgPathForSelfLink(link, minHeight);
}
}
);
});
// Translate the object on the actual moved point
d3.select(this).attr(
"transform", translate(node.x, node.y)
);
}
function dragend(node: SankeyDiagramNode) {
sankeyVisual.saveNodePositions(sankeyVisual.dataView.nodes);
sankeyVisual.saveViewportSize();
}
let drag = d3.drag()
.subject((node: SankeyDiagramNode) => {
return { x: node.x, y: node.y };
})
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragend);
nodesSelectionMerged.call(drag);
return nodesSelectionMerged;
}