<!DOCTYPE html><html><head>    <meta charset=utf-8 />    <title>Demo smooth connection</title></head><body>    <canvas id="canvas"></canvas>    <style>        html {            position: relative;            height: 100%;            width: 100%;        }        body {            position: absolute;            left: 0;            right: 0;            top: 0;            bottom: 0;            margin: 0;        }        canvas {            outline: 1px solid red;        }    </style>    <script>        const getDistance = (p1, p2) => {            return Math.sqrt(                Math.pow(p1.x + p2.x, 2)                +                Math.pow(p1.y + p1.y, 2)            )        }        const getControlpoint = (points) => {//三个点出两个控制点            const p01 = getDistance(points[0], points[1])            const p12 = getDistance(points[1], points[2])            const p02 = p01 + p12            let vector = [points[2].x - points[0].x, points[2].y - points[0].y]            return [                {                    x: points[1].x - vector[0] * 0.5 * p01 / p02,                    y: points[1].y - vector[1] * 0.5 * p01 / p02                },                {                    x: points[1].x + vector[0] * 0.5 * p01 / p02,                    y: points[1].y + vector[1] * 0.5 * p01 / p02                }            ]        }        let canvas = document.querySelector('canvas')        let ctx = canvas.getContext('2d')        window.onload = window.onresize = () => {            canvas.width = document.body.clientWidth            canvas.height = document.body.clientHeight            drawBezierCurve()            drawPoint()        }        let points = [            { x: 131, y: 193 },            { x: 187, y: 128 },            { x: 231, y: 240 },            { x: 280, y: 124 },            { x: 340, y: 236 },            { x: 368, y: 131 },            { x: 416, y: 239 },        ]        const drawPoint = () => {            points.forEach(point => {                ctx.beginPath()                ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI)                ctx.fill()            })        }        const drawBezierCurve = () => {            let len = points.length            if (len < 2) {                return            }            ctx.beginPath()            ctx.moveTo(points[0].x, points[0].y)            if (len === 2) {                ctx.lineTo(points[1].x, points[1].y)            } else {                let controlPoint = []                for (let i = 1; i < len - 1; i++) {                    controlPoint = controlPoint.concat(getControlpoint([points[i - 1], points[i], points[i + 1]]))                }                let i = 2                ctx.quadraticCurveTo(controlPoint[0].x, controlPoint[0].y, points[1].x, points[1].y)                for (; i < len - 1; i++) {                    ctx.bezierCurveTo(                        controlPoint[(i - 2) * 2 + 1].x,                        controlPoint[(i - 2) * 2 + 1].y,                        controlPoint[(i - 1) * 2].x,                        controlPoint[(i - 1) * 2].y,                        points[i].x,                        points[i].y                    )                }                console.log(controlPoint, i)                ctx.quadraticCurveTo(                    controlPoint[(i - 2) * 2 + 1].x,                    controlPoint[(i - 2) * 2 + 1].y,                    points[i].x,                    points[i].y                )            }            ctx.strokeStyle = 'blue'            ctx.stroke()        }    </script></body></html>

留神点:1.第二个点和最初一个点要应用quadraticCurveTo, 2.线1受2点和3点管制

参考资料:https://stackoverflow.com/questions/7054272/how-to-draw-smooth-curve-through-n-points-using-javascript-html5-canvas/10060462#10060462
原理:http://scaledinnovation.com/analytics/splines/aboutSplines.html