private renderChart()

in src/visual.ts [907:1053]


    private renderChart(
        series: StreamGraphSeries[],
        stackedSeries: d3.Series<any, any>[],
        duration: number,
        hasHighlights: boolean = false
    ): Selection<d3.BaseType, StreamGraphSeries, any, any> {

        const { width, height } = this.viewport;

        this.margin.left = this.data.settings.valueAxis.show
            ? StreamGraph.YAxisOnSize + this.data.yAxisValueMaxTextSize
            : StreamGraph.YAxisOffSize;

        if (this.data.settings.valueAxis.showAxisTitle) {
            this.margin.left += StreamGraph.YAxisLabelSize;
        }

        this.margin.bottom = this.data.settings.categoryAxis.show
            ? StreamGraph.XAxisOnSize + this.data.xAxisFontSize
            : StreamGraph.XAxisOffSize;

        if (this.data.settings.categoryAxis.showAxisTitle) {
            this.margin.bottom += StreamGraph.XAxisLabelSize;
        }

        const
            margin: IMargin = this.margin,
            xScale: LinearScale<number, number> = d3.scaleLinear()
                .domain([0, series[0].dataPoints.length - 1])
                .range([margin.left, width - (margin.right + this.data.xAxisValueMaxTextHalfSize)]);

        const yMin: number = d3.min(stackedSeries, serie => d3.min(serie, d => d[0]));
        const yMax: number = d3.max(stackedSeries, serie => d3.max(serie, d => d[1])) + this.YMaxAdjustment;

        const yScale: LinearScale<number, number> = d3.scaleLinear()
            .domain([Math.min(yMin, 0), yMax])
            .range([height - (margin.bottom + StreamGraph.TickHeight), (this.margin.top - this.data.yAxisFontHalfSize)]);

        const area: d3.Area<any> = d3.area<StreamDataPoint>()
            .curve(d3.curveCatmullRom.alpha(0.5))
            .x((d, i) => xScale(i))
            .y0(d => yScale(d[0]))
            .y1(d => yScale(d[1]))
            .defined(d => StreamGraph.isNumber(d[0]) && StreamGraph.isNumber(d[1]));

        const isHighContrast: boolean = this.colorPalette.isHighContrast;

        let selection: Selection<d3.BaseType, any, any, any> = this.dataPointsContainer
            .selectAll(StreamGraph.LayerSelector.selectorName)
            .data(stackedSeries);

        const selectionMerged = selection
            .enter()
            .append("path")
            .merge(selection);

        selectionMerged
            .classed(StreamGraph.LayerSelector.className, true)
            .style("opacity", DefaultOpacity)
            .style("fill", (d, index) => isHighContrast ? null : series[index].color)
            .style("stroke", (d, index) => isHighContrast ? series[index].color : null);

        selectionMerged
            .transition()
            .duration(duration)
            .attr("d", area);

        selectionMerged
            .selectAll("path")
            .append("g")
            .classed(StreamGraph.DataPointsContainer, true);

        selection
            .exit()
            .remove();

        if (this.data.settings.labels.show) {
            const labelsXScale: LinearScale<number, number> = d3.scaleLinear()
                .domain([0, series[0].dataPoints.length - 1])
                .range([0, width - margin.left - this.margin.right - this.data.xAxisValueMaxTextHalfSize]);

            const layout: ILabelLayout = StreamGraph.getStreamGraphLabelLayout(
                labelsXScale,
                yScale,
                this.data.settings.labels);

            // Merge all points into a single array
            let dataPointsArray: StreamDataPoint[] = [];

            stackedSeries.forEach((seriesItem: d3.Series<any, any>) => {
                let filteredDataPoints: any[];


                filteredDataPoints = seriesItem.filter((dataPoint: any) => {
                    return dataPoint && dataPoint[0] !== null && dataPoint[0] !== undefined;
                }).map((dataPoint: any) => {
                    return {
                        x: dataPoint.data.x,
                        y0: dataPoint[0],
                        y: dataPoint[1],
                        text: seriesItem.key,
                        value: dataPoint.data[seriesItem.key],
                        highlight: dataPoint.data.highlight
                    };
                });

                if (filteredDataPoints.length > 0) {
                    dataPointsArray = dataPointsArray.concat(filteredDataPoints);
                }
            });

            const viewport: IViewport = {
                height: height - (this.margin.top + this.data.yAxisFontHalfSize),
                width: width - (this.margin.right + this.data.xAxisValueMaxTextHalfSize) - margin.left,
            };

            if (hasHighlights) {
                const highlightedPointArray: StreamDataPoint[] = dataPointsArray.filter((d: StreamDataPoint) => d.highlight && d.value !== StreamGraph.DefaultValue);
                const additionalPointsArray: StreamDataPoint[] = dataPointsArray.filter((d: StreamDataPoint) => highlightedPointArray[0] && d.text === highlightedPointArray[0].text && d.x < highlightedPointArray[0].x);
                dataPointsArray = additionalPointsArray.concat(highlightedPointArray);
            }

            dataLabelUtils.cleanDataLabels(this.svg);

            const labels: Selection<d3.BaseType, StreamDataPoint, any, any> =
                dataLabelUtils.drawDefaultLabelsForDataPointChart(
                    dataPointsArray,
                    this.svg,
                    layout,
                    viewport);

            if (labels) {
                const offset: number = StreamGraph.DefaultDataLabelsOffset + margin.left;

                labels.attr("transform", (dataPoint: StreamDataPoint) => {
                    return translate(
                        offset + (dataPoint.size.width / StreamGraph.MiddleOfTheLabel),
                        dataPoint.size.height / StreamGraph.MiddleOfTheLabel);
                });
            }
        }
        else {
            dataLabelUtils.cleanDataLabels(this.svg);
        }

        return selectionMerged;
    }