canvas 上的动画矩形

Animate rectangle on canvas

我正在尝试为水平条形图绘图设置动画。它将缓慢绘制,完成后绘制第二个。就像 chart.js。它不必那么先进。我只是想学习 canvas 绘图 + 动画。我正在使用 ctx.fillRect,但不确定是否可以设置动画。

更新:在我的第二个片段中,我在 fillRect 周围添加了一个超时。它使栏动画化,但现在 position.Y 似乎没有在正确的时间更新。条形图彼此叠加。

/**
*  Javascript Carousel
*  Author: Yasin Yaqoobi
*  Project Goal: Build a really simple slider using javascript timer and css transition. 
*  Date: 07/09/16
**/

var Charts = (function(){

var ctx; 
var canvas; 
var legendsHeight = 50; 
var yLabelsWidth = 100;
var scaleRatio; 

function init(canvas, chart){
 setupCanvas(canvas); 
 setScaleRatio(chart);
 if (chart.type.localeCompare('HorizontalBar') != -1){
  drawHorizontalChart(chart);
 }
}

function drawHorizontalChart(chart){
 var canvasHeight = $(canvas).outerHeight();
 var canvaswidth = $(canvas).outerWidth(); 
 var marginRatio = (canvasHeight - 2 * legendsHeight) / chart.data.labels.length * 0.2; 
 var barHeight = ((canvasHeight - 2 * legendsHeight) / chart.data.labels.length) - marginRatio; 
  
 ctx.beginPath();
 ctx.moveTo(yLabelsWidth, legendsHeight);   // (30, 15)
 ctx.lineTo(yLabelsWidth, canvasHeight - legendsHeight); // (30,385)
 ctx.lineTo(canvaswidth, canvasHeight - legendsHeight); // (1000,385)
 ctx.stroke();

 ctx.font = "16px serif";
 ctx.fillText(chart.data.datasets[0].label, (canvaswidth - yLabelsWidth)/2, legendsHeight / 2 );
 var position = {x:yLabelsWidth,y:legendsHeight};

 for (var i = chart.data.labels.length-1; i >= 0; i--){
  ctx.fillStyle = chart.data.datasets[0].backgroundColor[i]; 
  ctx.fillRect(position.x,position.y, scaleRatio * chart.data.datasets[0].data[i], barHeight);
  position.y += marginRatio + barHeight; 
  console.log('this is i ' + i);
 }
}

function setScaleRatio(chart){
 scaleRatio = chart.data.datasets[0].data.reduce(function(prev,curr){
  if (prev > curr){
   return prev; 
  }
  return curr; 
 });

 scaleRatio = $(canvas).outerWidth() / (scaleRatio + 10); 
}

function setupCanvas(canv){
 canvas = canv;
 if (canvas.getContext){
  ctx = canvas.getContext('2d');
 }
 console.log(ctx);
}

var publicApi = {
 init: init
}; 

return publicApi; 

})();


$(document).ready(function(){
 var canvas = document.getElementById("myChart");
 Charts.init(canvas, {
  type: 'HorizontalBar',
  data: {
   labels: ['USA', 'Russia', 'China'], 
   datasets: [
    {
     label: 'Progress Chart',
     backgroundColor: [
      'rgba(255, 99, 132, 0.2)',
                  'rgba(54, 162, 235, 0.2)',
                  'rgba(255, 206, 86, 0.2)'
                 ], 
                  borderColor: [
                  'rgba(255,99,132,1)',
                  'rgba(54, 162, 235, 1)',
                  'rgba(255, 206, 86, 1)'
                 ], 
                 borderWidth: 1,
                 data: [60, 30, 80]
             }
   ]
  }

 });
});
.container{
 width: 1200px;
 box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 -webkit-box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 -moz-box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 overflow: hidden;
 margin: 0 auto; 
 padding: 5%;
}

canvas{
 margin: 0 auto;
 display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>

<div class="container">
 <h1 class="page-title underline-text">Charts</h1> 
  <div class="charts-area">
  <h3>Progress Chart</h3>
  <canvas id="myChart" width="1000" height="400"></canvas>
 </div>
<script src="jquery-3.1.0.js"></script>
<script src="npo.js"></script>
<script src="index.js"></script>

</body>

/**
*  Javascript Carousel
*  Author: Yasin Yaqoobi
*  Project Goal: Build a really simple slider using javascript timer and css transition. 
*  Date: 07/09/16
**/

var Charts = (function(){

var ctx; 
var canvas; 
var legendsHeight = 50; 
var yLabelsWidth = 100;
var scaleRatio; 

function init(canvas, chart){
 setupCanvas(canvas); 
 setScaleRatio(chart);
 if (chart.type.localeCompare('HorizontalBar') != -1){
  drawHorizontalChart(chart);
 }
}

function drawHorizontalChart(chart){
 var canvasHeight = $(canvas).outerHeight();
 var canvaswidth = $(canvas).outerWidth(); 
 var marginRatio = (canvasHeight - 2 * legendsHeight) / chart.data.labels.length * 0.2; 
 var barHeight = ((canvasHeight - 2 * legendsHeight) / chart.data.labels.length) - marginRatio; 
  
 ctx.beginPath();
 ctx.moveTo(yLabelsWidth, legendsHeight);   // (30, 15)
 ctx.lineTo(yLabelsWidth, canvasHeight - legendsHeight); // (30,385)
 ctx.lineTo(canvaswidth, canvasHeight - legendsHeight); // (1000,385)
 ctx.stroke();

 ctx.font = "16px serif";
 ctx.fillText(chart.data.datasets[0].label, (canvaswidth - yLabelsWidth)/2, legendsHeight / 2 );
 var position = {x:yLabelsWidth,y:legendsHeight};

 for (var i = chart.data.labels.length-1; i >= 0; i--){
  ctx.fillStyle = chart.data.datasets[0].backgroundColor[i]; 
  for (var n = 20; n < scaleRatio * chart.data.datasets[0].data[i]; n+=1){
  (function (ratio){
   setTimeout(function(){
    console.log(ratio);
    ctx.fillRect(position.x,position.y, ratio, barHeight);
   }, 1000);
  })(n);
 }
  position.y += marginRatio + barHeight; 
  console.log('this is positionY ' + position.y);
 }
}

function setScaleRatio(chart){
 scaleRatio = chart.data.datasets[0].data.reduce(function(prev,curr){
  if (prev > curr){
   return prev; 
  }
  return curr; 
 });

 scaleRatio = $(canvas).outerWidth() / (scaleRatio + 10); 
}

function setupCanvas(canv){
 canvas = canv;
 if (canvas.getContext){
  ctx = canvas.getContext('2d');
 }
 console.log(ctx);
}

var publicApi = {
 init: init
}; 

return publicApi; 

})();


$(document).ready(function(){
 var canvas = document.getElementById("myChart");
 Charts.init(canvas, {
  type: 'HorizontalBar',
  data: {
   labels: ['USA', 'Russia', 'China'], 
   datasets: [
    {
     label: 'Progress Chart',
     backgroundColor: [
      'rgba(255, 99, 132, 0.2)',
                  'rgba(54, 162, 235, 0.2)',
                  'rgba(255, 206, 86, 0.2)'
                 ], 
                  borderColor: [
                  'rgba(255,99,132,1)',
                  'rgba(54, 162, 235, 1)',
                  'rgba(255, 206, 86, 1)'
                 ], 
                 borderWidth: 1,
                 data: [60, 30, 80]
             }
   ]
  }

 });
});
.container{
 width: 1200px;
 box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 -webkit-box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 -moz-box-shadow: 5px 5px 35px 0px rgba(0,0,0,0.4);
 overflow: hidden;
 margin: 0 auto; 
 padding: 5%;
}

canvas{
 margin: 0 auto;
 display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>

<div class="container">
 <h1 class="page-title underline-text">Charts</h1> 
  <div class="charts-area">
  <h3>Progress Chart</h3>
  <canvas id="myChart" width="1000" height="400"></canvas>
 </div>
<script src="jquery-3.1.0.js"></script>
<script src="npo.js"></script>
<script src="index.js"></script>

</body>

这是一个使用setTimeout依次绘制单杠的小示例。我为您提供了一个示例计时设置,它等待前一个柱形图完成并每 10 毫秒重新绘制一次。 运行 看看吧。

<!DOCTYPE html>
<html>

<body>

<canvas id="canvas" height="300" width="600"></canvas>

<script>

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');

var bars = [
    { name: 'bar1', value: 567 },
    { name: 'bar2', value: 394 }
];

var delay = 0,
    speed = 10;

for(var i = 0; i < bars.length; ++i){
    for(var l = 0; l < bars[i].value; ++l) setTimeout(ctx.fillRect.bind(ctx,0,50 + 100 * i, l, 75),(i > 0 ? delay+(bars[i-1].value*speed) : 0) + delay+l*speed);
}

</script>

</body>

</html>

编辑:更清晰,汇总多个柱的延迟

<!DOCTYPE html>
<html>

<body>

<canvas id="canvas" height="300" width="675"></canvas>

<script>

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');

var bars = [
    { name: 'bar1', value: 567 },
    { name: 'bar2', value: 394 },
    { name: 'bar3', value: 217 }
];

var delay = 0, // accrued delay
    speed = 3; // drawing speed (milliseconds per render)

for(var i = 0; i < bars.length; ++i){
    for(var l = 0; l < bars[i].value; ++l){
        setTimeout(
            ctx.fillRect.bind(ctx,0,50 + 100 * i, l, 75),
            (i == 0 ? 0 : delay) + l*speed
        );
    }
    delay += bars[i].value * speed;
}

</script>

</body>

</html>