2

HTML5 と Javascript で継続的に成長する線を描画したいと考えています。これが私がやりたいことです:

画面の中心にあるポイントには、3 つの線 (互いに 120 度) が特定の長さ (たとえば 50 ピックス) まで成長し、この 3 つの頂点のそれぞれが新しい中心になり、別の 3 つの線があります。

(評判が悪いため画像を投稿できませんでした。うまくいけば、ここにある画像について私が何を意味するかを理解していただければ幸いです...)

画面の中心から始めて、中心として必要なすべてのポイントの配列を持つ関数を既に作成しました。この配列にループを書いて線を引くことを考えています。線が画面に表示されるように、ストロークを直接使用したくありません。事前に定義された長さに達するまで、線が少しずつ描かれるようなものを持ちたいです(ここでは悪い英語です、私の英語を許してください)。ただし、私のコードはここではうまく機能しません。すべての中心点のみが表示され、最後の中心点のみが 3 本の線を伸ばす動きをします...

これを行う正しい方法を知る必要があります...事前に感謝します!

(コード内の変数 time または startTime を無視してください...)

<script>
window.requestAnimFrame = (function(callback) {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };
})();

var canvas = document.getElementById('myCanvas');
canvas.width= window.innerWidth;
canvas.height= window.innerHeight;
var context = canvas.getContext('2d');
var totalLength = 50;

var centreSet = new Array();
var counter = 0;

var centre = {
    x: canvas.width / 2,
    y: canvas.height / 2,
};

var myLine = {
    length : 0,
    color : 'grey',
    lineWidth : 0.5,
};

function drawLine(centre, context, mylength) {
    context.beginPath();
    context.moveTo(centre.x, centre.y);
    context.lineTo(centre.x, centre.y - mylength);
    context.moveTo(centre.x, centre.y);
    context.lineTo(centre.x - 0.866 * mylength, centre.y + mylength/2);
    context.moveTo(centre.x, centre.y);
    context.lineTo(centre.x + 0.866 * mylength, centre.y + mylength/2);
    context.lineWidth = myLine.lineWidth;
    context.strokeStyle = myLine.color;
    context.closePath();
    context.stroke();
}

function startAnimate(centre, canvas, context, startTime, mylength) {
        // update
    var time = (new Date()).getTime() - startTime;
    var linearSpeed = 5;
    // pixels / second
    var newX = linearSpeed / 10;

    if(mylength < totalLength) {
        mylength = mylength + newX;
        // clear
        //context.clearRect(0, 0, canvas.width, canvas.height);
        drawLine(centre, context, mylength);

        // request new frame
        requestAnimFrame(function() {
            startAnimate(centre, canvas, context, startTime, mylength);
        });
    }

}

function animate(centre, canvas, context, startTime){
            //create array to have all the center points
    centreSet = getCentres(); 
    for (var i = 0; i < centreSet.length; i++){
                    //pass the x and y values in a object for each center we have in the array
        centre.x = str2x(centreSet[i]);
        centre.y = str2y(centreSet[i]);
        startAnimate(centre, canvas, context, startTime, 0);
    }
}

    setTimeout(function() {
    var startTime = (new Date()).getTime();
    animate(centre, canvas, context, startTime);
}, 1000);

コードを編集したところ、次の部分を追加しました。

var length = 0;
for(var i = 0; i < 380; i++){
window.setTimeout(function() {drawFrame(length);},16.67);
length = length + 0.25; 
}

必要な長さに達するまで、画面が増分線を少しずつ描画しているように見えると思います。ただし、インクリメンタルプロセス全体が表示されておらず、完成した図面のみが表示されているようです。

誰でも理由を教えてもらえますか?

4

2 に答える 2

1

アニメーション ループが失敗する理由に関するフォローアップの質問について

setTimeout を for ループに入れることで、新しい setTimeout ごとに前の setTimeout がキャンセルされます。

そのため、最後の setTimeout が完了するまで実行されたままになります。

アニメーション ループでは、通常、各「フレーム」で次の 3 つのことを行います。

  1. 新しいフレームが前のフレームとどのように異なるかを反映するために、いくつかのデータを変更します。
  2. フレームを描画します。
  3. アニメーションが完成したかどうかをテストします。そうでない場合は、別のフレームを実行します (#1 に進みます)。

このsetTimeout関数は、#3 の最後の部分を実行するために使用されます (別のフレームを実行します)。

したがって、setTimeout は実際にアニメーション ループとして機能します。--- for ループは必要ありません。

これは、このパターンに従うようにコードを再構築する方法です。

var length=0;
var maxLength=50;

function draw(){

    // make the line .25 longer
    length=length+.25;

    // draw
    drawFrame(length);

    // test if the line is fully extended
    // if not, call setTimeout again
    // setTimeout(draw,100) will call this same draw() function in 100ms
    if(length<maxLength){
        setTimeout(draw,100);
    }
}
于 2013-06-04T19:09:44.617 に答える
1

[編集: 線が終端距離に到達した後の子オブジェクトのスポーンを含める]

あなたのコードでは、線が最大延長に達したときに新しい中心点を生成していませんでした。

線が終端の長さに達したときに中心オブジェクトの新しいセットを生成するために、中心オブジェクトのそれぞれが少なくともこれだけの情報を持っていることをお勧めします。

var newCentrePoint={
    x:x,
    y:y,
    maxLength:newMaxLength,
    growLength:growLength,
    currentLength:0,
    isActive:true
}

x、y は中心点の座標です。

maxLength は、3 回線が終了する前の最大延長です。

growLength は、新しいフレームごとに各ラインが伸びる量です。

currentLength は、線の現在の長さです。

isActive は、このポイントがラインを伸ばしているか (true)、終了しているか (false) を示すフラグです。

次に、各行が終端の長さに達すると、次のように新しい行のセットを生成できます。

// spawns 3 new centre points – default values are for testing
function spawn(point,newMaxLength,newColor,growLength,newLineWidth){
    var max=newMaxLength||point.maxLength/2;
    var color=newColor|| (colors[++colorIndex%(colors.length)]);
    var grow=growLength||point.growLength/2;
    var lw=newLineWidth||point.lineWidth-1;

    // new center points are spawned at the termination points of the 3 current lines
    newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw);
    newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
    newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
}

// creates a new point object and puts in the centreSet array for processing
function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){
    var newPt={
        x:x,
        y:y,
        maxLength:newMaxLength,
        color:newColor,
        lineWidth:newLineWidth,
        growLength:growLength,
        currentLength:0,
        isActive:true
    }
    centreSet.push(newPt);
}

ここにコードとフィドルがあります: http://jsfiddle.net/m1erickson/Vc8Gf/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var context = canvas.getContext('2d');

    // colors
    var colors=["red","blue","gold","purple","green"];
    var colorIndex=0;

    //
    var centreSet=[]
    var generations=1;

    // seed point
    newPoint(canvas.width/2,canvas.height/2,100,"red",15);

    // start 
    draw();

    //
    function draw(){
        //
        context.clearRect(0,0,canvas.width,canvas.height);
        //
        for(var i=0;i<centreSet.length;i++){
            //
            var centre=centreSet[i];


            //
            if(centre.isActive){
                // 
                centre.currentLength+=centre.growLength;
                //
                if(centre.currentLength>=centre.maxLength){
                    centre.isActive=false;
                    centre.currentLength=centre.maxLength;
                    spawn(centre);
                }
            }
            //
            drawLines(centre);
        }
        //
        if(generations<120){
            setTimeout(draw,500);
        }else{
            context.font="18pt Verdana";
            context.fillText("Finished 120 generations",40,350);
        }
    }


    function spawn(point,newMaxLength,newColor,growLength,newLineWidth){
        var max=newMaxLength||point.maxLength/2;
        var color=newColor|| (colors[++colorIndex%(colors.length)]);
        var grow=growLength||point.growLength/2;
        var lw=newLineWidth||point.lineWidth-1;
        newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw);
        newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
        newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
        generations++;
    }

    function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){
        var newPt={
            x:x,
            y:y,
            maxLength:newMaxLength,
            color:newColor,
            lineWidth:newLineWidth,
            growLength:growLength,
            currentLength:0,
            isActive:true
        }
        centreSet.push(newPt);
    }


    function drawLines(centre) {

        var length=centre.currentLength;
        //
        context.beginPath();
        context.moveTo(centre.x, centre.y);
        context.lineTo(centre.x, centre.y - length);
        //
        context.moveTo(centre.x, centre.y);
        context.lineTo(centre.x - 0.866 * length, centre.y + length/2);
        //
        context.moveTo(centre.x, centre.y);
        context.lineTo(centre.x + 0.866 * length, centre.y + length/2);
        //
        context.strokeStyle=centre.color;
        context.lineWidth = centre.lineWidth;
        context.stroke();
    }

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=400 height=400></canvas>
</body>
</html>
于 2013-06-03T01:29:02.047 に答える