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