简体   繁体   中英

Canvas Bar Graph Animation

I'm trying to get up to speed on the canvas tag and I'm getting stuck when it comes to basic animations. I've searched around and I can get most of the tutorials I've found working, but I've had some trouble translating that into what I'm trying to do.

I have a bar graph that I'm building for my portfolio, and I would like to have the ability to animate the bars on the graph. Basically when the page loads, the bars start from the bottom of the graph, and grow upwards to where they need to be. I have a version I built in jquery found here to give an idea of what I'm after: http://jokedesigns.com/portfoliov6/

Could someone point me in the right direction on how to achieve the animations I'm looking for? Even if its a simple function I should be able to rework it into what I need. Most of the tutorials I've found mainly deal with rotation, I did find one that was a linear animation, but I still wasn't able to quite rework that into what I need.

Here is the code I have so far for the graph:

<html>
  <head>
    <script type="application/javascript">
function loadImages(sources, callback) {
    var images = {};
    var loadedImages = 0;
    var numImages = 0;
    // get num of sources
    for(var src in sources) {
      numImages++;
    }
    for(var src in sources) {
      images[src] = new Image();
      images[src].onload = function() {
        if(++loadedImages >= numImages) {
          callback(images);
        }
      };
      images[src].src = sources[src];
    }
  }
function draw() {
  var canvas = document.getElementById("canvas");
   var canvasbg = document.getElementById("canvasbg");
  if (canvas.getContext) {
    var ctx = canvas.getContext("2d");
    var ctx2 = canvasbg.getContext("2d");
    var img = new Image();
    img.onload = function(){
        ctx2.drawImage(img,0,0);
    };
    img.src = 'skills_bg.jpg';
    ctx.fillStyle = "#0a4888";
    ctx.fillRect (0, 82, 34, 50);
    ctx.fillStyle = "#ed9323";
    ctx.fillRect (60, 82, 34, 50);
    ctx.fillStyle = "#87982d";
    ctx.fillRect (120, 82, 34, 50);
    ctx.fillStyle = "#902e63";
    ctx.fillRect (180, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (360, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (420, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (480, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (540, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (600, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (660, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (720, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (780, 82, 34, 50);
    ctx.fillStyle = "#262627";
    ctx.fillRect (840, 82, 34, 50);

    var sources = {
        ps: 'icn_ps.png',
        ai: 'icn_ai.png',
        dw: 'icn_dw.png',
        id: 'icn_id.png',
        ht: 'icn_html.png',
        cs: 'icn_css.png',
        js: 'icn_js.png',
        sql: 'icn_mysql.png',
        php: 'icn_php.png',
        perl: 'icn_perl.png',
        ruby: 'icn_ruby.png',
        cplus: 'icn_cplusplus.png',
        asp: 'icn_asp.png'
    };
    loadImages(sources, function(images) {
        ctx.drawImage(images.ps, 0, 132, 36, 37);
        ctx.drawImage(images.ai, 60, 132, 36, 37);
        ctx.drawImage(images.dw, 120, 132, 36, 37);
        ctx.drawImage(images.id, 180, 132, 36, 37);
        ctx.drawImage(images.ht, 360, 132, 36, 37);
        ctx.drawImage(images.cs, 420, 132, 36, 37);
        ctx.drawImage(images.js, 480, 132, 36, 37);
        ctx.drawImage(images.sql, 540, 132, 36, 37);
        ctx.drawImage(images.php, 600, 132, 36, 37);
        ctx.drawImage(images.perl, 660, 132, 36, 37);
        ctx.drawImage(images.ruby, 720, 132, 36, 37);
        ctx.drawImage(images.cplus, 780, 132, 36, 37);
        ctx.drawImage(images.asp, 840, 132, 36, 37);
    });

  }
}

</script>
</head>
<body onload="draw();">
<canvas id="canvasbg" width="960" height="200" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
<canvas id="canvas" width="960" height="200" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</body>
</html>

You can use requestAnimationFrame to create animation loops to allow your bars to grow

To create uniform growth for bars that are uneven height you can apply a percentage

// this will grow all bars at an even rate

bar1Height = bar1.maxHeight * percentComplete/100;

bar2Height = bar2.maxHeight * percentComplete/100;  

percentComplete++;

Here's example code and a Demo: http://jsfiddle.net/m1erickson/YR4D7/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script 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 ctx=canvas.getContext("2d");

        var skillBars=[];
        skillBars.push({max:200,color:"red"});
        skillBars.push({max:75,color:"green"});
        skillBars.push({max:275,color:"blue"});

        var chartBottomY=325;
        var chartBarWidth=30;
        var chartBarPadding=20;
        var percent=0;

        animate();

        function animate() {
            // if not 100% done, request another frame
            if(percent++<100){
                requestAnimationFrame(animate);
            }

            // Drawing code goes here
            ctx.clearRect(0,0,canvas.width,canvas.height);
            var x=chartBarPadding;
            for(var i=0;i<skillBars.length;i++){
                var height=skillBars[i].max*percent/100;
                ctx.fillStyle=skillBars[i].color;
                ctx.fillRect(x,chartBottomY,chartBarWidth,-height);
                x+=chartBarWidth+chartBarPadding;
            }
        }

    }); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=350 height=350></canvas>
</body>
</html>

I see a couple issues.

First, you draw everything at one time, whereas you should draw after each image is loaded, but yiu will want to use setTimeout or something similar to allow the canvas element to be drawn.

You should also have a method for the bar, and have it remember the current step value and it will just draw the next block.

I would put onload on the image tag, image.onload function with return , and when it loaded draw the next bar and load the next one.

But remember to use setTimeout to allow the drawing to take place.

Here are some links that may help

JavaScript animation with multiple setTimeout

https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AnimatingtheCanvas/AnimatingtheCanvas.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM