private renderNodes()

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;
    }