HTML5画布不断抚摸着线条

时间:2013-06-02 21:56:20

标签: javascript html5 canvas

我想在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; 
}

我希望屏幕看起来一点一点地绘制增量线,直到达到我想要的长度。但是,似乎没有显示整个增量过程,它只显示完成的绘图。

谁能告诉我为什么?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:1)

关于您的动画循环失败原因的后续问题

通过将setTimeout置于for循环中,每个新的setTimeout都取消之前的setTimeout。

所以你刚刚离开最后一个setTimeout运行完成。

在动画循环中,您通常在每个“框架”中执行3项操作:

  1. 更改一些数据以反映新帧与前一帧的不同之处。
  2. 画框。
  3. 测试动画是否完整。如果没有,请做另一帧(转到#1)。
  4. 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);
        }
    }