[前端]使用曲線將多點(diǎn)連成一條平滑的曲線

之前在寫一個(gè)項(xiàng)目需要把多點(diǎn)連成平滑的曲線,而且這些點(diǎn)是無(wú)法預(yù)知的。開(kāi)始想到用貝塞爾曲線,但是具體貝塞爾曲線的控制點(diǎn)要怎么設(shè)定,怎樣讓多點(diǎn)都落在曲線上而且保持曲線的平滑,就一直沒(méi)想到。
后來(lái)參考了一篇《Android 使用貝塞爾曲線將多點(diǎn)連成一條平滑的曲線》的博文,地址:http://m.blog.csdn.net/article/details?id=52667896
寫得挺好的,不過(guò)沒(méi)太仔細(xì)研究
原代碼是java的,然后就直接用原代碼改成了js版本的(雖然最后用了其他方式來(lái)實(shí)現(xiàn)……不過(guò)這個(gè)如果做什么在線生成圖表什么的可以用上)

效果:


Paste_Image.png

后面的點(diǎn)契合的挺好的

代碼:

var mPointList = [{x:10,y:10},{x:120,y:40},{x:260,y:180},{x:380,y:40},{x:420,y:120},
    {x:510,y:110},{x:620,y:140},{x:760,y:280},{x:880,y:240},{x:920,y:120}];
var lineSmoothness = 0.16;
measurePath(mPointList,lineSmoothness);
function measurePath(mPointList,lineSmoothness) {

    var prePreviousPointX ;
    var prePreviousPointY ;
    var previousPointX ;
    var previousPointY ;
    var currentPointX ;
    var currentPointY ;
    var nextPointX;
    var nextPointY;

    var lineSize = mPointList.length;
    var c=document.getElementById("myCanvas");

    var ctx=c.getContext("2d");
    ctx.strokeStyle="#FF0000";
    ctx.beginPath();

    for (var valueIndex = 0; valueIndex < lineSize; ++valueIndex) {
        if (currentPointX) {
            var point = mPointList[valueIndex];
            currentPointX = point.x;
            currentPointY = point.y;
        }
        if (previousPointX) {
            //是否是第一個(gè)點(diǎn)
            if (valueIndex > 0) {
                var point = mPointList[valueIndex-1];
                previousPointX = point.x;
                previousPointY = point.y;
            } else {
                //是的話就用當(dāng)前點(diǎn)表示上一個(gè)點(diǎn)
                previousPointX = currentPointX;
                previousPointY = currentPointY;
            }
        }

        if (prePreviousPointX) {
            //是否是前兩個(gè)點(diǎn)
            if (valueIndex > 1) {
                var point = mPointList[valueIndex-2];
                prePreviousPointX = point.x;
                prePreviousPointY = point.y;
            } else {
                //是的話就用當(dāng)前點(diǎn)表示上上個(gè)點(diǎn)
                prePreviousPointX = previousPointX;
                prePreviousPointY = previousPointY;
            }
        }

        // 判斷是不是最后一個(gè)點(diǎn)了
        if (valueIndex < lineSize - 1) {
            var point = mPointList[valueIndex+1];
            nextPointX = point.x;
            nextPointY = point.y;
        } else {
            //是的話就用當(dāng)前點(diǎn)表示下一個(gè)點(diǎn)
            nextPointX = currentPointX;
            nextPointY = currentPointY;
        }

        if (valueIndex == 0) {
            // 將Path移動(dòng)到開(kāi)始點(diǎn)
            ctx.moveTo(mPointList[0].x,mPointList[0].y);
        } else {
            // 求出控制點(diǎn)坐標(biāo)
            var firstDiffX = (currentPointX - prePreviousPointX);
            var firstDiffY = (currentPointY - prePreviousPointY);
            var secondDiffX = (nextPointX - previousPointX);
            var secondDiffY = (nextPointY - previousPointY);
            var firstControlPointX = previousPointX + (lineSmoothness * firstDiffX);
            var firstControlPointY = previousPointY + (lineSmoothness * firstDiffY);
            var secondControlPointX = currentPointX - (lineSmoothness * secondDiffX);
            var secondControlPointY = currentPointY - (lineSmoothness * secondDiffY);
            //畫(huà)出曲線
            ctx.bezierCurveTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
                    currentPointX, currentPointY);

        }

        // 更新值,
        prePreviousPointX = previousPointX;
        prePreviousPointY = previousPointY;
        previousPointX = currentPointX;
        previousPointY = currentPointY;
        currentPointX = nextPointX;
        currentPointY = nextPointY;
    }
    ctx.stroke();
}

//畫(huà)點(diǎn)
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#000";
for (var i=0;i<mPointList.length;i++){
    ctx.beginPath();
    ctx.arc(mPointList[i].x,mPointList[i].y,5,0,Math.PI*2,true);
    ctx.closePath();
    ctx.fill();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,872評(píng)論 25 709
  • 背景: 給一系列頂點(diǎn),如果只是用直線將其中的各個(gè)點(diǎn)依次連接起來(lái),最終形成一個(gè)折線圖,這種很容易實(shí)現(xiàn)。但是現(xiàn)實(shí)...
    狂風(fēng)無(wú)跡閱讀 40,515評(píng)論 12 70
  • 談?wù)勜惾麪柷€ 最近在做項(xiàng)目的時(shí)候,需要用到一個(gè)動(dòng)畫(huà),非常簡(jiǎn)單的動(dòng)畫(huà),簡(jiǎn)單到就是直接對(duì)一個(gè)View做平移… 然而雖...
    雨潤(rùn)聽(tīng)潮閱讀 6,275評(píng)論 1 16
  • 最近在做項(xiàng)目的時(shí)候,需要用到一個(gè)動(dòng)畫(huà),非常簡(jiǎn)單的動(dòng)畫(huà),簡(jiǎn)單到就是直接對(duì)一個(gè)View做平移... 然而雖然動(dòng)畫(huà)簡(jiǎn)單,...
    IAMDAEMON閱讀 4,406評(píng)論 12 69
  • 九斤20170606早自習(xí)打卡:越是圍繞一個(gè)明確的思想,來(lái)巧妙構(gòu)建你的故事,觀眾在你的影片中所能發(fā)現(xiàn)的意義就更多。...
    給小老板讀商業(yè)書(shū)閱讀 200評(píng)論 0 0

友情鏈接更多精彩內(nèi)容