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>
我正在尝试为水平条形图绘图设置动画。它将缓慢绘制,完成后绘制第二个。就像 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>