private drawConnectingLines()

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()
    }