如何使javascript画布绘制速度更快

How to make javascript canvas draw faster?

本文关键字:绘制 速度 何使 javascript 布绘制      更新时间:2023-09-26

我有以下代码来显示心电图。我用画布绘制图形背景(每个网格的尺寸为2.5毫米)。稍后,我将从数组中获取y坐标array_1(x坐标在程序中计算)。这种方法的问题是,绘制整个图形大约需要40秒,因为arrayarray_1中有1250个值。我可以做的是,我可以在循环中绘制部分,在这种情况下,一旦加载页面,就会绘制整个图形。但是,我需要在5秒内完成策划。没有更多。不少。我该如何修改代码才能做到这一点?请帮忙。

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <canvas id="canvas" width="1350" height="1300" style="background-color: white;"></canvas>
    <script type='text/javascript'>
    var canvas = document.getElementById("canvas");
    var ctxt = canvas.getContext("2d");
    var n1 = 1;
    var n1_x=49; //Graph x coordinate starting pixel.
    var n1_y=72;//Graph y coordinate starting pixel.
    var array_1 = []// array from which y coordinates are taken. Has 1250 elements
     var ctx = canvas.getContext("2d");
    var x=0;
    var y=0;
    var Line_position=-1;
    while(x<=1350)//graph width
    {
        ctxt.lineWidth = "0.5";
        Line_position=Line_position+1;
        if(Line_position%5==0)
        {
            ctxt.lineWidth = "1.5";
        }
        ctxt.strokeStyle = "black";
        ctxt.beginPath();
        ctxt.moveTo(x, 0);
        ctxt.lineTo(x, 1300);
        ctxt.stroke();
        x=x+9.43;
    }
    Line_position=-1;
    while(y<=1300)//graph height
    {
        ctxt.lineWidth = "0.5";
        Line_position=Line_position+1;
        if(Line_position%5==0)
        {
            ctxt.lineWidth = "1.5";
        }
        ctxt.strokeStyle = "black";
        ctxt.beginPath();
        ctxt.moveTo(0, y);
        ctxt.lineTo(1350,y);
        ctxt.stroke();
        y=y+9.43;
    }
   drawWave();
        function drawWave()
        {
          requestAnimationFrame(drawWave);
                ctx.lineWidth = "1";
                ctx.strokeStyle = 'blue';
               ctx.beginPath();
                ctx.moveTo(n1_x- 1, n1_y+array_1[n1-1]);//move to the pixel position
                ctx.lineTo(n1_x, n1_y+array_1[n1]);//Draw to the pixel position
                ctx.stroke();
                n1_x=n1_x+0.374;//Incrementing pixel so as to traverse x axis.
                n1++;
 }
    </script>
</body>
</html>

以下是数组:array_1=[69,69,69,69,69,69,69,69、69、69,69、六十九、69、六十九,69,六十九,69、69,69,9、69、69,79,69、69,69、69、60,9、20,20,20,20,40,20,20,020,20,30,20,200,20,220,20,20,20,20,0,20,20,20,220,020,020,30,20,20,20,20,30,20 9,69,69,69,69,69,69,69,69,69,69,69,79,69,72,72,72,72.72,73,73,74,74,74,74,73,73,73,73,73,73,73,74,74,73,73.73,73,73,73.73,74,74,73,73,73,73,73,72,73,74,74,73,73.73,73,73,73,77,73,73 73,73,73/73,73,72,71,72,72,72,72,72,72,73,73,73,72,72,73,73,74.73,72,72,72,72 2,73,73,73,73,7,7,2,72,73,73.73,72,72,72,71101,71,70,70,70,69,68,67,67,66,66,67,67,69,70,72,72,72,73,73,74,73,73,73,73.73,73,73.73,73,77,74,76,77,76,70,57,40,22,11,11,2,40,57,69,73,71,71,71,72,72,73,73/74,74,74,73,72,72/72,72,72,72.72,72,77,71,72,70,70,70,69,69,69,69,69,69:68,68,68,67,67,66,66,65,65,64,63,63,62,62,62,62,62.62,62,63,63,64,65,66,67,68,68,69,70,70 71,72,72,72,73,73,73,73,72,72,72.73,73,73.73,73,77,73,73,73,73,73,72,72,73,73,73.73,73,72,73,73,73,73.73,73,77,73,73,73,72,72,72,72.73,73.74,74,74,74,73,73/73,73,72,72/72,72,73,73,73,73,74,74,73,73.73,73,73,73,73,73 73,73.73,73,73,73-73,73,74,73,72,72,70,70,70,70,69,69,68,67,67,68,68,69,71,72,73,72,73,73,73,74,73,75,77,75 8,76,67,53,35,18,8,10,23,4,58,69,73,72,71,70,71,72,73,73,73,73.72,72,73,73,73,731,70,70,71,71,71,71,71,71,71,70,70,16,69,69,69,68,67,67,67,66,65,65,63,62,61,60,60,60,59,60,60,70,61,62,63,65,66,66,67,68,69,70,71/72,72,73,73,73,72,72,72,72,73,73,73.73,73,77,73,73,73,73,73,73,73,73/73,73,73,73,72,72,72,72,72,72,72,72,73,73,73,73.73,73,77,73,73,72,73,73.73,73,73,73,73,73.73,73.73,73,72,72,73,73,73/73,73,733,73,73,73,73.73,73,77,73,73,73,73,73,73.73,72,71,71,70,70,69,69,68,67,67,66,65,66,66,68,69,71,72,72,73,73,74,74,74,74,76,78,78,74,64,48,29,13,5,10,26,45,62,71,73,72,71,71,72,73.73,73,74,74.74,73,72,72,72,73,73.73,72,72,72.72,72,71,71,71,71,71,70,69,69,69,68,68,67,66,66,66,66,65,65,64,63,62,62,61,61,60,60,60,60,61,62,62,63,64,65,66,67,68,70,71,72,72,72,72.73,73,73,73,77,73,73,74,74,75,75,74,74,74,73,73.73,74,73,74.74,74,74,73,73,73,73,73/73,73,77,73,73,73.73,73,72,72,73,73,74,74,73,73,73.73,73,72,73,73-73,73,73,73,72,72,72,72,73,73,73,73,72,73,73 7,73,73,73,73.73,73,73.73,73.73,73.73,73,73,72.73,73.73,73,73 2,72,71,70,70,70,69,69,68,68,67,67,66,67,67,68,69,71,72,73,73,74,74,73,73.73,74,75,75,74,73,73,74,76,78,75,67,52,32,15,5,8,22,41,59,69,73,72,71,70,71,72,72,73,73,73,73,72.72,72,72,72,76,72,71,71,71,70/70,70,70,70,69,69,66,69,68,68,68,68,77,67,66,65,65,64,64,62,61,60,60,60,60,61,62,62,63,64,65,65,66,6,6,6,67,68,69,70,71,71,717,71,71,72.72,73,72,73.73,73,72,73,73,73,73,73,73,73,73.73,73,73.73,73,77,73,73,72,72,72,72,72,71,71,71,71,71,71,72,72.72,72,72,72,72.72,72,71,71,71,72,72,73,73,72,72,72,73,73,73,73.73,72,73,74,75,77,77,75,77,52,74,18,10,12,26,45,71,72,71,71,70,70,70,69,68,67,67,68,79,72,73.73,73,75,75,75,74,74,74,75,7,77,77,7,75,7,77,52,34,18,72,26,46,62,74,72,72,71.72,71,77,70,70,7,70,79,76,68,77,68,77,71,72,737,73,73,73 73,74,74,74,75,75,74,74,74.74,74,77,74,73,73,74,74,73,73.73,73,73,73-73,73,77,73,73,72,72,71,71,71,71,71,70,70,70,69,69,68,68,68,67,66,65,64,63,63,62,62,63,66,63,66,67,69,70,71,72,72,73,73,74,74,74,74/75,75,76,76,74,72,70,70,79,69];

我可能会这样做。正如在评论中提到的,我们需要在每帧中绘制许多数据点。我们画了多少取决于浏览器提供动画帧的速度。

我已经将该值硬编码为4,因为这在我的机器上似乎有效,但如果不需要做更多的工作,你可能会制作代码时间本身,并动态调整该值,以便动画尽可能接近目标时间。我试了一下,但结果很糟糕,我将把它作为研究或思考的练习留给读者。

通过跟踪我们已经为当前"刷新周期"绘制了多少帧,我们知道为每个帧绘制的第一个点在数组中索引多远。

我试着尽可能多地参数化代码,但为时已晚,我很累,我可能在某个地方忽略了一些东西。

<!doctype html>
<html>
<head>
<script>
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
    drawBkg(byId('canvas'), 9.43, 5, "0.5", "1.5", "black");
    drawCurFrame();
}
var dataSamples = [69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,72,72,72,72,72,72,72,73,73,74,74,74,74,74,74,74,73,73,73,73,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,74,74,74,73,73,73,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,71,72,72,72,73,73,73,72,72,72,73,73,73,74,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,73,73,73,72,72,72,71,101,71,70,70,70,69,68,68,67,67,66,66,67,67,69,70,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,74,76,77,76,70,57,40,22,11,11,22,40,57,69,73,73,71,71,71,72,72,73,73,74,74,74,73,72,72,72,72,72,72,72,72,72,72,72,72,71,71,70,70,71,71,71,71,70,70,69,69,69,69,69,69,69,68,68,68,67,67,66,66,65,65,64,63,63,62,62,62,62,62,62,62,62,63,63,64,65,66,67,68,68,69,70,71,72,72,72,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,73,73,73,73,72,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,73,73,74,74,74,74,74,74,73,73,72,73,73,73,74,73,73,72,72,72,73,73,73,72,72,73,73,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,70,70,70,70,70,69,69,68,67,67,67,67,68,69,71,72,72,73,73,73,73,74,74,74,74,74,73,73,73,73,75,77,78,76,67,53,35,18,8,10,23,41,58,69,73,72,71,70,71,72,73,73,73,73,73,73,73,73,72,72,73,73,73,73,72,71,71,70,70,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,68,67,67,67,67,67,66,65,65,65,64,63,62,61,61,61,60,60,60,59,60,60,60,61,62,63,65,66,66,67,68,69,70,71,72,72,72,72,73,73,73,72,72,72,72,72,72,72,73,73,73,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,71,72,72,73,73,73,72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,72,73,73,73,73,73,73,72,73,73,73,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,71,71,70,70,69,69,69,68,67,67,66,65,66,66,68,69,70,71,72,72,73,73,73,73,73,73,74,74,74,74,74,74,76,78,78,74,64,48,29,13,5,10,26,45,62,71,73,72,71,71,72,73,73,73,73,73,74,74,74,73,72,72,72,73,73,73,73,73,73,73,72,72,72,72,71,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,67,66,66,66,66,65,65,64,63,62,62,61,61,60,60,60,60,61,62,62,63,64,65,66,67,68,70,71,72,72,72,72,72,72,73,73,73,73,73,73,73,74,74,75,75,74,74,74,73,73,73,74,73,73,73,73,73,74,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,74,74,74,73,73,73,73,73,73,73,73,73,73,72,72,72,72,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,72,72,71,70,70,70,69,69,68,68,67,67,66,67,67,68,69,70,71,72,73,73,74,74,73,73,73,74,75,75,74,73,73,74,76,78,75,67,52,32,15,5,8,22,41,59,69,73,72,71,70,71,72,72,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,72,72,72,71,71,71,70,70,70,70,70,70,70,69,69,69,69,68,68,68,68,67,67,66,65,65,64,64,64,63,62,61,60,60,60,60,60,61,61,62,62,63,64,65,65,66,67,68,69,70,71,71,71,71,71,71,72,72,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,71,71,71,72,72,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,71,71,71,70,70,70,70,69,69,68,67,67,68,69,71,72,73,73,73,73,73,73,73,73,74,75,75,75,74,74,74,75,77,77,75,67,52,34,18,10,12,26,45,62,71,74,73,72,72,72,73,74,74,74,75,75,74,74,74,74,74,74,74,74,74,73,73,73,73,74,74,73,73,73,73,73,73,73,72,72,71,71,71,71,71,70,70,70,69,69,69,68,68,68,68,67,66,65,64,63,63,62,62,62,63,63,63,63,64,65,66,67,69,69,70,71,72,72,73,73,74,74,74,74,75,75,76,76,74,72,70,70,69,69 ];
function drawBkg(canvasElem, squareSize, numSquaresPerBlock, minorLineWidthStr, majorLineWidthStr, lineColStr)
{
    var nLinesDone = 0;
    var i, curX, curY;
    var ctx = canvasElem.getContext('2d');
    ctx.clearRect(0,0,canvasElem.width,canvasElem.height);
    // draw the vertical lines
    curX=0;
    ctx.strokeStyle = lineColStr;
    while (curX < canvasElem.width)
    {
        if (nLinesDone % numSquaresPerBlock == 0)
            ctx.lineWidth = majorLineWidthStr;
        else
            ctx.lineWidth = minorLineWidthStr;
        ctx.beginPath();
        ctx.moveTo(curX, 0);
        ctx.lineTo(curX, canvasElem.height);
        ctx.stroke();
        curX += squareSize;
        nLinesDone++;
    }
    // draw the horizontal lines
    curY=0;
    nLinesDone = 0;
    while (curY < canvasElem.height)
    {
        if (nLinesDone % numSquaresPerBlock == 0)
            ctx.lineWidth = majorLineWidthStr;
        else
            ctx.lineWidth = minorLineWidthStr;
        ctx.beginPath();
        ctx.moveTo(0, curY);
        ctx.lineTo(canvasElem.width, curY);
        ctx.stroke();
        curY += squareSize;
        nLinesDone++;
    }
}
// position that will be treated as 0,0 when drawing our points.
var originX=49;
var originY=72;
function drawSamples(nSamplesToDraw, firstSample, lineWidthStr, lineColourStr)
{
    var can = byId('canvas');
    var ctx = can.getContext('2d');
    ctx.strokeStyle = lineColourStr;
    ctx.lineWidth = lineWidthStr;
    console.log(firstSample);
    ctx.beginPath();
    ctx.moveTo( originX+firstSample-1, dataSamples[firstSample-1]+originY );
    for (var i=0; i<nSamplesToDraw; i++)
    {
        var curSample = dataSamples[i + firstSample];
        ctx.lineTo( originX+firstSample+i, curSample+originY );
    }
    ctx.stroke();
}
var curFrame=0;
var nPointsPerFrame = 4;
function drawCurFrame()
{
    if ((dataSamples.length - (nPointsPerFrame * curFrame)) < nPointsPerFrame)      // will we over-run the end of the array of datapoints?
    {
        curFrame = 0;                                                               // if so, reset
        drawBkg(byId('canvas'), 9.43, 5, "0.5", "1.5", "black");
    }
    drawSamples(nPointsPerFrame, nPointsPerFrame*curFrame, "1", "blue");
    curFrame++;
    requestAnimationFrame( drawCurFrame );
}
</script>
<style>
#canvas
{
    border: solid 1px black;
    background-color: #FFFFFF;
}
</style>
</head>
<body>
    <div id='txt'></div>
    <canvas id="canvas" width="1350" height="1300"></canvas>
</body>
</html>

更新

现在我看到你提供了更多的信息,我得到了你想要的。

问题是需要在时间t内绘制固定数量的线段。

由于您不知道每帧可能需要多长时间,因此不能依赖固定的帧速率。另一种选择是只使用当前时间并保存结束时间。

获取开始时间,然后绘制每一帧所有应该绘制的,直到当前时间。由于在下一次屏幕刷新之前不会显示正在绘制的线段,因此您获得的时间将落后约16毫秒,因此需要对此进行调整。

我所做的是跟踪平均帧时间,并用一半的时间来估计何时显示新的画布更新。

这有点迂腐,但也可以展示如何尽可能接近所需的时间。如果你不在乎它有几毫秒,那么就去掉平均帧时间的东西。在慢速机器上,您最多可以休息30毫秒。

var canvas; // canvas
var ctx; 
function getCanvas () {
    // to do 
    // get canvas and context
}
function drawGrid () {
    // to do
    // draw the grid
}
function drawTimedLine(){
    if(canvas === undefined){ // if the canvas not available get it
       getCanvas();
    }
    // clear the canvas is repeating animation
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawGrid();
    var array_1 = ; // your data

    // All stuff needed for timed animation.
    // The frame you render will not be displayed untill the next
    // vertical refresh which is unknown, Assume it is one frame.
    var startDelay = 1000;      // if Needed time in milliseconds to delay start
    var endTime;                // hold the time that the animation has to end
    var lastDataPoint;          // holds the last point drawn to
    var timeToDraw = 5 * 1000;  // how long the animation should last
    var repeatAfter = 1 *1000;  // if you want to repeat the animatoin
    var frameCount = 0;         // count the frames to get average frame time
    var startTime;              //the start time;
    var numberPoints = array_1.length; // number of points;
    var startX = 49;            // line starts at
    var yOffset = 72;           // line Y offset
    var endX = 512;             // line ends at. 
    var width = endX - startX;  // width  
    var xStep = width / numberPoints;   // X step per point
    var pointsPerMS = numberPoints / timeToDraw; // get how many points per ms should be drawn
    // function to draw
    function drawWave() {
        // variable needed
        var averageframeTime, timeLeft, i, currentTime;
        currentTime = new Date().valueOf();     // gets the time in millisecond;
        if (startTime === undefined) {          // Is this the first frame      
            startTime = currentTime;            // save the start time;
            endTime = currentTime + timeToDraw; // workout when the end time is;
            lastDataPoint = 0;                  // set the data position to the start;
            averageframeTime = 0;               // no frames counted so frame time is zero          
        } else {
            frameCount += 1;                    // count the frames
            // get the average frame time
            averageframeTime = (currentTime - startTime) / frameCount; 
        }
        // get the time this frame
        // will most likely be displayed
        // then calculate how long
        // till the end
        timeLeft = endTime - Math.min(endTime, currentTime + averageframeTime / 2); 
        // now get where we should
        // be when the frame is presented
        pointPos = Math.floor(pointsPerMS * (timeToDraw - timeLeft)); 

        // now draw the points from where we last left of
        // till the new pos;
        ctx.lineWidth = 4;
        ctx.strokeStyle = 'blue';
        ctx.beginPath();
        ctx.moveTo(  // move to first point
            lastDataPoint * xStep + startX,
            array_1[lastDataPoint] + yOffset 
        ); 
        // draw each line from the last drawn to the new position 
        for (i = lastDataPoint + 1; i <= pointPos && i < numberPoints; i++) { 
            // Add the line segment
            ctx.lineTo(
                i * xStep + startX, 
                array_1[i] + yOffset
            );
        }
        ctx.stroke();                   // execute the render commands
        lastDataPoint = pointPos;       // update the last point
        if (pointPos < numberPoints) {  // are we there yet???
            requestAnimationFrame(drawWave); // no so request another frame
        }else{
            // if you want to repeat the animation
            setTimeout(drawTimedLine , repeatAfter ); 
        } 
    }
    // start the line animation with delay if needed
    setTimeout(drawWave,startDelay);
}    
// use this if you want it to start as soon as page is ready.    
document.addEventListener("DOMContentLoaded",drawTimedLine);
// or use if you want it to start when page has images loaded and is ready
// document.addEventListener("load",drawTimedLine);

我还添加了重复动画的功能。如果不需要,只需删除该代码

我的原始答案

我不知道速度有什么问题,因为它在我的机器上运行得很好。

为了更好地开始使用

function startFunction(){
   // your code
}
document.addEventListener("DOMContentLoaded",startFunction);

这将一直等到页面加载并解析页面。图像和其他媒体可能尚未加载,但页面已准备好进行操作。

不知道你说的5秒是什么意思。假设你可能想让这件衣服在5秒内穿好。

以下内容将做到这一点。

document.addEventListener("DOMContentLoaded",function() {setTimeout(startFunction,5000);});

我想问,为什么用requestAnimationFrame 1250一次绘制一个条目的图形并不是那么多线。如果添加ctx.beginPath() ctx.moveTo(/*first point*/),然后使用ctx.moveTo(/*points*/)循环所有点,则ctx.stroke()将在最慢的设备上实时运行。

BTW ctx.lineWidthNumber而不是字符串。你还有两个上下文?使用画布的一个上下文。删除ctxt并只使用ctx,最后您不需要将type='text/javascript'添加到脚本标记中,因为Javascript是默认的。

1)绘制1000条线不会花那么长时间,即使是100000条线在任何像样的浏览器上也不会花超过10毫秒。看看时间浪费的地方
2) 代码的核心问题是它缺乏模块性。将代码拆分为几个清晰的函数,仅将参数分组为几个对象,正确命名和缩进内容。

下面是一个(不完整但有效的)例子,说明这可能是什么样子。

var cv, ctx;
var data = null;
var debug = true;
// ---------------------------------------
// define here all graphic related parameters
var gfxParams = {
  canvasWidth: 600,
  canvasHeight: 600,
  gridColor: '#A66',
  gridSpacing: 10,
  gridLineWidth: 0.5,
  gridStrongLinesEvery: 5,
  lineColor: '#AEB',
  lastLineColor: '#8A9' // , ...
};
// define here all animation related parameters
var animationParams = {
  duration: 5,
  startTime: -1
}
// ---------------------------------------
//              main
// ---------------------------------------
window.onload = function() {
  data = getData();
  setupCanvas(data);
  launchAnimation();
}
// ---------------------------------------
// 
function setupCanvas(data) {
  cv = document.getElementById('cv');
  cv.width = gfxParams.canvasWidth;
  cv.height = gfxParams.canvasHeight;
  ctx = cv.getContext('2d');
  // here you should translate and scale the context
  // so that it shows your data.
}
function drawGrid(ctx) {
  var i = 0,
    pos = 0,
    lw = gfxParams.gridLineWidth;
  ctx.fillStyle = gfxParams.gridColor;
  var vLineCount = gfxParams.canvasWidth / gfxParams.gridSpacing;
  for (i = 0; i < vLineCount; i++) {
    pos = i * gfxParams.gridSpacing;
    ctx.fillRect(pos, 0, lw, gfxParams.canvasHeight);
  }
  var hLineCount = gfxParams.canvasHeight / gfxParams.gridSpacing;
  for (i = 0; i < hLineCount; i++) {
    pos = i * gfxParams.gridSpacing;
    ctx.fillRect(0, pos, gfxParams.canvasWidth, lw);
  }
}
function animate() {
  requestAnimationFrame(animate);
  var now = Date.now();
  // erase screen
  ctx.clearRect(0, 0, gfxParams.canvasWidth, gfxParams.canvasHeight);
  // draw grid
  drawGrid(ctx);
  // draw lines 
  var lastIndex = getLastDrawnIndex(data, now - animationParams.startTime);
  drawLines(ctx, data, lastIndex);
  if (debug) {
    ctx.save();
    ctx.fillStyle = '#000';
    ctx.fillText(lastIndex + ' lines drawn. Time elapsed : ' + (now - animationParams.startTime), 10, 10);
    ctx.restore();
  }
}
// comment
function launchAnimation() {
  requestAnimationFrame(animate);
  animationParams.startTime = Date.now();
}
// comment
function getData() {
  var newData = [];
  for (var i = 0; i < 500; i++) {
    newData.push([Math.random() * 600, Math.random() * 600]);
  }
  return newData;
}
// comment
function getLastDrawnIndex(data, timeElapsed_ms) {
  var timeElapsed = timeElapsed_ms / 1000;
  if (timeElapsed >= animationParams.duration) return data.length - 1;
  return Math.floor(data.length * timeElapsed / animationParams.duration);
}
function drawLines(ctx, data, lastIndex) {
  ctx.strokeStyle = gfxParams.lineColor;
  // other ctx setup here.
  for (var i = 0; i < lastIndex - 1; i++) {
    drawLine(ctx, data[i], data[i + 1]);
  }
  ctx.strokeStyle = gfxParams.lastLineColor;
  drawLine(ctx, data[lastIndex - 1], data[lastIndex]);
}
function drawLine(ctx, p1, p2) {
  ctx.beginPath();
  ctx.moveTo(p1[0], p1[1]);
  ctx.lineTo(p2[0], p2[1]);
  ctx.stroke();
}
<canvas id='cv'></canvas>