4

現在、JavaScript/JQuery と HTML5 キャンバスを使用して、小さなピタゴラス ツリー アプリケーションを作成しようとしています。

アルゴリズムは正常に動作しますが、残念ながら描画のプロセスを見ることができません。終了後、UI がフリーズし、描画全体が表示されます。

現在の動作: http://www.kappelcation.com/index.php?contentid=4 これは私が望む動作です: http://www.jjam.de/Java/Applets/Fraktale/Pythagoras_Baum.html (描画の進行状況を確認するには、Java アプレットを許可して数回クリックする必要があります)。

$(document).ready(function(){ //just some listeners and initialization
initCanvas();

$(autOrManSelect).change(function(){
    if(($(this).val()==1)) //changed from manual to automatic
    {
        $(pythagorasCanvas).click();
    }
});
$(startButton).click(function(event){
    $(this).unbind(event);
    $(this).html('Add Leaves');
    $(restartButton).css("visibility", "visible");
    startTree();
    $(this).click(function(){
        var next = parseInt($(depthInput).val())+1;
        $(depthInput).val(next);
        $(pythagorasCanvas).click();
    });
});
$(restartButton).click(function(){
    startTree();
});
});

function initCanvas() //adjust size, clear the canvas and draw a boarder
{
var canvas = document.getElementById("pythagorasCanvas");
canvas.height=600;
canvas.width=$(mainDiv).width()-40;
$(pythagorasCanvas).unbind("click");
if (canvas.getContext) 
{
    var context = canvas.getContext("2d");
    //clear canvas
    drawRectangle(context, new Point(0,canvas.height), new Point(canvas.width,canvas.height), new Point(canvas.width,0), new Point(0,0), "#FFFFFF");
    //draw border for canvas
    drawRectangle(context,new Point(0,canvas.height),new Point(canvas.width,canvas.height), new Point(canvas.width, 0),new Point(0,0), '#000000', true);
}
}

function startTree() //start drawing process
{   
initCanvas();
var canvas = document.getElementById("pythagorasCanvas");
if (canvas.getContext) 
{
    var context = canvas.getContext("2d");
    var rectLength = parseInt($(firstSquareInput).val());
    var startWidth = canvas.width/2-rectLength/2;
    var startHeight = canvas.height-canvas.height/4;
    var startA = new Point(startWidth, startHeight);
    var startB = new Point(startWidth+rectLength, startHeight);     
    drawBranch(context, startA, startB, 0); 
}
}

function Point(x, y) {
this.x = x;
this.y = y;
}

function drawBranch(context, a, b, depth) //gets called recursively 
{
var maxDepth = $(depthInput).val();
if(depth<maxDepth)
{
    depth++;
    //calculate positions of current rectangle
    var dx = b.x - a.x;
    var dy = a.y - b.y;
    var c = new Point(b.x-dy, b.y-dx);
    var d = new Point(a.x-dy, a.y-dx);
    //draw current rectangle
    drawRectangle(context, a, b, c, d);

    //calculate new position
    var offSetX;
    if($(triangleOffsetInput).val().toLowerCase()=="random")
    {
        offSetX = Math.random();
    }
    else
    {
        offSetX = parseFloat($(triangleOffsetInput).val())/100; //first offset in x-direction (in relation to a square length of 1)
    }
    var offSetY = -Math.sqrt(Math.pow(0.5,2)-Math.pow((0.5-offSetX),2)); //Pythagoras to get the offset in y (negative sign necessary because the y-values get smaller upwards)
    var e = new Point( d.x + offSetX*(c.x-d.x) + offSetY*(a.y-b.y), d.y + offSetX*(c.y-d.y) + offSetY*(b.x-a.x));

    if($(fillTriangleBox).prop("checked"))
    {
        drawTriangle(context, c, d, e);
    }   

    var autOrMan = $(autOrManSelect).val();
    if(autOrMan==1)
    {
        //draw new positions
        drawBranch(context, d, e, depth);
        drawBranch(context, e ,c, depth);       
    }
    else
    {
        $(pythagorasCanvas).click(function(event) 
        {
            $(this).unbind(event);
            drawBranch(context, d, e, depth);
            drawBranch(context, e ,c, depth);       
        });
    }
}
else
{
    $(pythagorasCanvas).click(function(event) 
    {
        $(this).unbind(event);
        drawBranch(context, a, b, depth);
    });
}   
}

function drawTriangle(context, c, d, e, color)
{
if(typeof(color)==='undefined')
{
    color='#'+$(triangleColorInput).val();
} 
context.strokeStyle = color;
context.beginPath();
context.moveTo(c.x, c.y);
context.lineTo(d.x, d.y);
context.lineTo(e.x, e.y);
context.closePath();
context.fillStyle = color;
context.fill();
context.stroke();
}

function drawRectangle(context, a, b, c, d, color, ignoreFill)
{
if(typeof(color)==='undefined')
{
    color='#'+$(rectColorInput).val();
} 
if(typeof(ignoreFill)==='undefined')
{
    ignoreFill=false;
}
context.strokeStyle = color;
context.beginPath();
context.moveTo(a.x, a.y);
context.lineTo(b.x, b.y)
context.lineTo(c.x, c.y);
context.lineTo(d.x, d.y);
context.closePath();
if($(fillRectBox).prop("checked") && !ignoreFill)
{
    context.fillStyle = color;
    context.fill();
}
context.stroke();
}

setTimeout() 関数を使用して描画プロセスを非同期にして目的の動作を実現しようとしましたが、実装にひどく失敗したか、setTimeout() はこの状況では役に立ちません。

ヒントをいただければ幸いです。前もって感謝します!

4

2 に答える 2

1

JavaScript はシングル スレッドであるため、フリーズしています。再帰的に呼び出す代わりに、関数drawBranchを介して再帰的にスケジュールsetTimeoutし、関数をフォールオフします。これにより、ブラウザーがキャンバスを再描画する時間が与えられます。

于 2013-05-21T20:52:20.577 に答える
1

setTimeout を使用した drawBranch 関数への次の (テストされていない) 変更は機能するはずです

if(autOrMan==1)
{
    //draw new positions
    setTimeout(function() {
        drawBranch(context, d, e, depth);
        drawBranch(context, e ,c, depth);       
    }, 0);
}
else
{
    $(pythagorasCanvas).click(function(event) 
    {
        $(this).unbind(event);
        drawBranch(context, d, e, depth);
        drawBranch(context, e ,c, depth);     
    });
}
于 2013-05-21T20:50:59.900 に答える