贝塞尔曲线算法演示

描述:当前是关于Echarts图表中的 折线图 示例。
 
            var symbolSize = 20;
var data = [[0,0], [255,255]];

var _factorial = (n) => {
    if (n > 20) {
        return +Infinity
    }
    if (n === 0) {
        return 1
    }
    return n * _factorial(n - 1)
}

function bezierPrams(n,t,i) {
    if (i>=0 && i<=n) {
        return _factorial(n)/(_factorial(i) * _factorial(n-i)) * Math.pow(1-t, n-i) * Math.pow(t, i)
    }
    return 0
}

function bezier(points, limit = 50) {
    let length = points.length
    if (length > 20 || length< 3) {
        console.warn('只允许添加3-20个点')
        return []
    }
    const ret = []
    for (let i = 0; i<=limit; i++) {
        const t = i / limit
        let sum = [0, 0]
        for(let j=0; j<length; j++) {
            sum[0] = sum[0] + bezierPrams(length-1,t,j) * points[j][0]
            sum[1] = sum[1] + bezierPrams(length-1,t,j) * points[j][1]
        }
        ret.push(sum)
    }
    return ret
}

option = {
    animation: false,
    title: {
        text: '贝塞尔曲线算法演示'
    },
    tooltip: {
        show: false,
        triggerOn: 'none',
        formatter: function (params) {
            return 'X: ' + params.data[0].toFixed(2) + '<br>Y: ' + params.data[1].toFixed(2);
        }
    },
    grid: {
    },
    xAxis: {
        min: 0,
        max: 255,
        type: 'value',
        axisLine: {onZero: false}
    },
    yAxis: {
        min: 0,
        max: 255,
        type: 'value',
        axisLine: {onZero: false}
    },
    dataZoom: [
        {
            type: 'slider',
            xAxisIndex: 0,
            filterMode: 'empty'
        },
        {
            type: 'slider',
            yAxisIndex: 0,
            filterMode: 'empty'
        },
        {
            type: 'inside',
            xAxisIndex: 0,
            filterMode: 'empty'
        },
        {
            type: 'inside',
            yAxisIndex: 0,
            filterMode: 'empty'
        }
    ],
    series: [
        {
            id: 'a',
            type: 'line',
            //smooth: true,
            symbolSize: symbolSize,
            data: data
        }
    ]
};


setTimeout(function () {
    // Add shadow circles (which is not visible) to enable drag.
    myChart.setOption({
        graphic: echarts.util.map(data, function (item, dataIndex) {
            return {
                type: 'circle',
                position: myChart.convertToPixel('grid', item),
                shape: {
                    cx: 0,
                    cy: 0,
                    r: symbolSize / 2
                },
                invisible: true,
                draggable: true,
                ondrag: echarts.util.curry(onPointDragging, dataIndex),
                onmousemove: echarts.util.curry(showTooltip, dataIndex),
                onmouseout: echarts.util.curry(hideTooltip, dataIndex),
                z: 100
            };
        })
    });
}, 0);

window.addEventListener('resize', updatePosition);

myChart.on('dataZoom', updatePosition);

function updatePosition() {
    myChart.setOption({
        graphic: echarts.util.map(data, function (item, dataIndex) {
            return {
                position: myChart.convertToPixel('grid', item)
            };
        })
    });
}

function showTooltip(dataIndex) {
    myChart.dispatchAction({
        type: 'showTip',
        seriesIndex: 0,
        dataIndex: dataIndex
    });
}

function hideTooltip(dataIndex) {
    myChart.dispatchAction({
        type: 'hideTip'
    });
}

function onPointDragging(dataIndex, dx, dy) {
    data[dataIndex] = myChart.convertFromPixel('grid', this.position);

    // Update data
   series =  [{
        id: 'a',
        type: 'line',
        //smooth: true,
        symbolSize: symbolSize,
        data: data
    },{
        id: 'b',
        type: 'line',
        smooth: true,
        data: data.length >2 ? bezier(data) : []
    }]
    myChart.setOption({ series });
}

function removePoint(dataIndex) {
    data = [...data.slice(0, dataIndex), ...data.slice(dataIndex+1)]
    update()
}

var zr = myChart.getZr();

function update() {
    series =  [{
        id: 'a',
        type: 'line',
        //smooth: true,
        symbolSize: symbolSize,
        data: data
    },{
        id: 'b',
        type: 'line',
        smooth: true,
        symbolSize: 0,
        data: data.length >2 ? bezier(data) : []
    }]
    myChart.setOption({ series });
    setTimeout(function () {
        // Add shadow circles (which is not visible) to enable drag.
        myChart.setOption({
            graphic: echarts.util.map(data, function (item, dataIndex) {
                return {
                    type: 'circle',
                    position: myChart.convertToPixel('grid', item),
                    shape: {
                        cx: 0,
                        cy: 0,
                        r: symbolSize / 2
                    },
                    invisible: true,
                    draggable: true,
                    ondrag: echarts.util.curry(onPointDragging, dataIndex),
                    onmousemove: echarts.util.curry(showTooltip, dataIndex),
                    onmouseout: echarts.util.curry(hideTooltip, dataIndex),
                    onclick: echarts.util.curry(removePoint, dataIndex),
                    z: 100
                };
            })
        });
    }, 0);
}

zr.on('click', function (params) {
    if (params.target && params.target.type === 'circle') {
        return
    }
    var pointInPixel = [params.offsetX, params.offsetY];
    var pointInGrid = myChart.convertFromPixel('grid', pointInPixel);

    if (myChart.containPixel('grid', pointInPixel)) {
        data.push(pointInGrid);
        data.sort((a, b) => a[0]-b[0])

        update()
    }
});