簡體   English   中英

在HTML畫布上繪制貝塞爾曲線

[英]Drawing bezier curve on html canvas

我需要繪制由N個控制點定義的貝塞爾曲線,這些控制點存儲在數組中。 我有一個500px x 500px的畫布。 這是JSFiddle鏈接:jsfiddle.net/HswXy整個JS代碼:

<script>
    window.onload=function(){
        var old_n=0,n=0;
        var nrSelect = document.getElementById("mySelect");
        var submit = document.getElementById("submit");

        nrSelect.addEventListener("change",function(){
            old_n=n;
            n = nrSelect.selectedIndex;

            var inputx,inputy,br;

            if(document.getElementById("pointsdiv"))
            {
                for(i=1;i<=n;i++){
                    inputx = document.createElement('input');
                    inputy = document.createElement('input');
                    br = document.createElement('br');

                    inputx.type = "text";
                    inputy.type = "text";
                    inputx.size = 3;
                    inputy.size = 3;
                    inputx.id = "x_" + i;
                    inputy.id = "y_" + i;
                    inputx.value = "x_" + i;
                    inputy.value = "y_" + i;

                    inputx.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
                    inputy.addEventListener("focus",function(){if(this.value==this.id) this.value="";});

                    document.getElementById("pointsdiv").appendChild(inputx);
                    document.getElementById("pointsdiv").appendChild(inputy);
                    document.getElementById("pointsdiv").appendChild(br);
                }

                document.getElementById("pointsdiv").id="pointsdiv_after";
            }
            else
            {
                if( old_n < n )
                {
                    for(i=old_n+1;i<=n;i++){
                        inputx = document.createElement('input');
                        inputy = document.createElement('input');
                        br = document.createElement('br');

                        inputx.type = "text";
                        inputy.type = "text";
                        inputx.size = 3;
                        inputy.size = 3;
                        inputx.id = "x_" + i;
                        inputy.id = "y_" + i;
                        inputx.value = "x_" + i;
                        inputy.value = "y_" + i;

                        inputx.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
                        inputy.addEventListener("focus",function(){if(this.value==this.id) this.value="";});

                        document.getElementById("pointsdiv_after").appendChild(inputx);
                        document.getElementById("pointsdiv_after").appendChild(inputy);
                        document.getElementById("pointsdiv_after").appendChild(br);
                    }
                }
                else
                {
                    var parent;

                    for(i=n+1;i<=old_n;i++){
                        parent = document.getElementById("pointsdiv_after");

                        parent.removeChild(parent.lastChild);
                        parent.removeChild(parent.lastChild);
                        parent.removeChild(parent.lastChild);
                    }
                }
            }
        });



        //BEZIER CURVE
        function factorial(n){
            var result=1;
            for(i=2;i<=n;i++){
                result = result*i;
            }
            return result;
        }
        function Point(x,y){
            this.x=x;
            this.y=y;
        }
        var points = new Array();
        function getPoint(t){
            var i;
            var x=points[0].x;
            var y=points[0].y;
            var factn = factorial(n);
            for(i=0;i<n;i++){
                var b = factn / (factorial(i)*factorial(n-i));
                var k = Math.pow(1-t,n-i)*Math.pow(t,i);
                // console.debug( i+": ",points[i] );
                x += b*k*points[i].x;
                y += b*k*points[i].y;
            }
            return new Point(x, y);
        }
        //--BEZIER CURVE
        submit.addEventListener("click",function(){
            if(n){
                for(i=1;i<=n;i++){
                    var px = document.getElementById("x_"+i);
                    var py = document.getElementById("y_"+i);
                    points.push(new Point(parseInt(px.value,10),parseInt(py.value,10)));
                    // console.debug( points[i-1] );
                }
                var canvas = document.getElementById('myCanvas');
                var context = canvas.getContext('2d');
                context.beginPath();
                console.debug( points[0].x, points[0].y );
                context.moveTo(points[0].x, points[0].y);
                var t=0.01;
                while (t<=1)
                {
                    //get coordinates at position
                    var p=getPoint(t);
                    // console.debug( p.x, p.y );
                    //draw line to coordinates
                    context.lineTo(p.x, p.y);
                    //increment position
                    t += 0.01;
                }
                context.stroke();
            }
        });
    }
</script>

問題在於它似乎無法正常工作。 我現在對其進行2點測試,並且總是從畫布的左上角開始(即使我的第一個點位於(250,250),並且線的長度也不應該是像素數)。更長。

我在畫布上或幾何方面的專家,但這里是我的想法:你不應該moveTo points[0]繪制的仿前行,因為你getPoint功能似乎有引導你。 在調試代碼時,我可以看到的是,您首先移至(20,20) ,然后繪制了一條直線到(大約) (40,40) ,然后開始逐漸繪制回(20,20) ,生成了封閉的形狀不是您想要的。

對您的代碼進行少量(快速而骯臟的)更改,使其開始繪制曲線:

// DO NOT MOVE TO HERE
//context.moveTo(points[0].x, points[0].y);
var t = 0.01;

// MOVE TO THE FIRST POINT RETURNED BY getPoint
var p0 = getPoint(t);
context.moveTo(p0.x, p0.y);
t+=0.01;

// now loop from 0.02 to 1...

我確信您可以將其重構為更好的東西,因為我說過我的更改既快速又骯臟。

http://jsfiddle.net/HswXy/3/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM