function drawSegment()

in src/chart/line/poly.ts [38:212]


function drawSegment(
    ctx: PathProxy,
    points: ArrayLike<number>,
    start: number,
    segLen: number,
    allLen: number,
    dir: number,
    smooth: number,
    smoothMonotone: 'x' | 'y' | 'none',
    connectNulls: boolean
) {
    let prevX: number;
    let prevY: number;
    let cpx0: number;
    let cpy0: number;
    let cpx1: number;
    let cpy1: number;
    let idx = start;
    let k = 0;
    for (; k < segLen; k++) {

        let x = points[idx * 2];
        let y = points[idx * 2 + 1];

        if (idx >= allLen || idx < 0) {
            break;
        }
        if (isPointNull(x, y)) {
            if (connectNulls) {
                idx += dir;
                continue;
            }
            break;
        }

        if (idx === start) {
            ctx[dir > 0 ? 'moveTo' : 'lineTo'](x, y);
            cpx0 = x;
            cpy0 = y;
        }
        else {
            let dx = x - prevX;
            let dy = y - prevY;

            // Ignore tiny segment.
            if ((dx * dx + dy * dy) < 0.5) {
                idx += dir;
                continue;
            }

            if (smooth > 0) {
                let nextIdx = idx + dir;
                let nextX = points[nextIdx * 2];
                let nextY = points[nextIdx * 2 + 1];
                // Ignore duplicate point
                while (nextX === x && nextY === y && k < segLen) {
                    k++;
                    nextIdx += dir;
                    idx += dir;
                    nextX = points[nextIdx * 2];
                    nextY = points[nextIdx * 2 + 1];
                    x = points[idx * 2];
                    y = points[idx * 2 + 1];
                    dx = x - prevX;
                    dy = y - prevY;
                }

                let tmpK = k + 1;
                if (connectNulls) {
                    // Find next point not null
                    while (isPointNull(nextX, nextY) && tmpK < segLen) {
                        tmpK++;
                        nextIdx += dir;
                        nextX = points[nextIdx * 2];
                        nextY = points[nextIdx * 2 + 1];
                    }
                }

                let ratioNextSeg = 0.5;
                let vx: number = 0;
                let vy: number = 0;
                let nextCpx0;
                let nextCpy0;
                // Is last point
                if (tmpK >= segLen || isPointNull(nextX, nextY)) {
                    cpx1 = x;
                    cpy1 = y;
                }
                else {
                    vx = nextX - prevX;
                    vy = nextY - prevY;

                    const dx0 = x - prevX;
                    const dx1 = nextX - x;
                    const dy0 = y - prevY;
                    const dy1 = nextY - y;
                    let lenPrevSeg;
                    let lenNextSeg;
                    if (smoothMonotone === 'x') {
                        lenPrevSeg = Math.abs(dx0);
                        lenNextSeg = Math.abs(dx1);
                        const dir = vx > 0 ? 1 : -1;
                        cpx1 = x - dir * lenPrevSeg * smooth;
                        cpy1 = y;
                        nextCpx0 = x + dir * lenNextSeg * smooth;
                        nextCpy0 = y;
                    }
                    else if (smoothMonotone === 'y') {
                        lenPrevSeg = Math.abs(dy0);
                        lenNextSeg = Math.abs(dy1);
                        const dir = vy > 0 ? 1 : -1;
                        cpx1 = x;
                        cpy1 = y - dir * lenPrevSeg * smooth;
                        nextCpx0 = x;
                        nextCpy0 = y + dir * lenNextSeg * smooth;
                    }
                    else {
                        lenPrevSeg = Math.sqrt(dx0 * dx0 + dy0 * dy0);
                        lenNextSeg = Math.sqrt(dx1 * dx1 + dy1 * dy1);

                        // Use ratio of seg length
                        ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);

                        cpx1 = x - vx * smooth * (1 - ratioNextSeg);
                        cpy1 = y - vy * smooth * (1 - ratioNextSeg);

                        // cp0 of next segment
                        nextCpx0 = x + vx * smooth * ratioNextSeg;
                        nextCpy0 = y + vy * smooth * ratioNextSeg;

                        // Smooth constraint between point and next point.
                        // Avoid exceeding extreme after smoothing.
                        nextCpx0 = mathMin(nextCpx0, mathMax(nextX, x));
                        nextCpy0 = mathMin(nextCpy0, mathMax(nextY, y));
                        nextCpx0 = mathMax(nextCpx0, mathMin(nextX, x));
                        nextCpy0 = mathMax(nextCpy0, mathMin(nextY, y));
                        // Reclaculate cp1 based on the adjusted cp0 of next seg.
                        vx = nextCpx0 - x;
                        vy = nextCpy0 - y;

                        cpx1 = x - vx * lenPrevSeg / lenNextSeg;
                        cpy1 = y - vy * lenPrevSeg / lenNextSeg;

                        // Smooth constraint between point and prev point.
                        // Avoid exceeding extreme after smoothing.
                        cpx1 = mathMin(cpx1, mathMax(prevX, x));
                        cpy1 = mathMin(cpy1, mathMax(prevY, y));
                        cpx1 = mathMax(cpx1, mathMin(prevX, x));
                        cpy1 = mathMax(cpy1, mathMin(prevY, y));

                        // Adjust next cp0 again.
                        vx = x - cpx1;
                        vy = y - cpy1;
                        nextCpx0 = x + vx * lenNextSeg / lenPrevSeg;
                        nextCpy0 = y + vy * lenNextSeg / lenPrevSeg;
                    }
                }

                ctx.bezierCurveTo(cpx0, cpy0, cpx1, cpy1, x, y);

                cpx0 = nextCpx0;
                cpy0 = nextCpy0;
            }
            else {
                ctx.lineTo(x, y);
            }
        }

        prevX = x;
        prevY = y;
        idx += dir;
    }

    return k;
}