in src/UXClient/Components/ScatterPlot/ScatterPlot.ts [385:466]
private drawConnectingLines(){
// Don't render connecting lines on temporal mode
if(this.chartOptions.isTemporal){
this.lineWrapper.selectAll("*").remove();
return;
}
let dataSet = this.cleanData(this.chartComponentData.temporalDataArray);
let connectedSeriesMap = {};
// Find measure by which to connect series of points
const getPointConnectionMeasure = (point => {
let pConMes = this.aggregateExpressionOptions[point.aggregateKeyI]?.pointConnectionMeasure;
return pConMes && pConMes in point.measures ? pConMes : null;
})
// Map data into groups of connected points, if connectedPoints enabled for agg
dataSet.forEach(point => {
if(point.aggregateKeyI !== null && point.aggregateKeyI < this.aggregateExpressionOptions.length &&
this.aggregateExpressionOptions[point.aggregateKeyI].connectPoints){
let series = point.aggregateKey + "_" + point.splitBy;
if(series in connectedSeriesMap){
connectedSeriesMap[series].data.push(point);
} else{
connectedSeriesMap[series] = {
data: [point],
pointConnectionMeasure: getPointConnectionMeasure(point)
}
}
}
})
// Sort connected series by pointConnectionMeasure
for(let key of Object.keys(connectedSeriesMap)){
let sortMeasure = connectedSeriesMap[key].pointConnectionMeasure;
// If sort measure specified, sort by that measure
if(sortMeasure){
connectedSeriesMap[key].data.sort((a,b) => {
if(a.measures[sortMeasure] < b.measures[sortMeasure]) return -1;
if(a.measures[sortMeasure] > b.measures[sortMeasure]) return 1;
return 0;
})
}
}
let line = d3.line()
.x((d:any) => this.xScale(d.measures[this.xMeasure]))
.y((d:any) => this.yScale(d.measures[this.yMeasure]))
.curve(this.chartOptions.interpolationFunction); // apply smoothing to the line
// Group lines by aggregate
let connectedGroups = this.lineWrapper.selectAll(`.tsi-lineSeries`).data(Object.keys(connectedSeriesMap));
let self = this;
connectedGroups.enter()
.append("g")
.attr("class", 'tsi-lineSeries')
.merge(connectedGroups)
.each(function(seriesName){
let series = d3.select(this).selectAll<SVGPathElement, any>(`.tsi-line`).data([connectedSeriesMap[seriesName].data], d => d[0].aggregateKeyI+d[0].splitBy);
series.exit().remove();
series
.enter()
.append("path")
.attr("class", `tsi-line`)
.merge(series as d3.Selection<SVGPathElement, any, any, unknown>)
.attr("fill", "none")
.transition()
.duration(self.chartOptions.noAnimate ? 0 : self.TRANSDURATION)
.ease(d3.easeExp)
.attr("stroke", (d) => Utils.colorSplitBy(self.chartComponentData.displayState, d[0].splitByI, d[0].aggregateKey, self.chartOptions.keepSplitByColor))
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", line)
})
connectedGroups.exit().remove()
}