使用 canvas 为圆环图中的线条设置动画
Animate lines in a donut chart using a canvas
基本上,我尝试为圆环图中的线条设置动画(参见 example), so that each of them is counted up with document.ready. I tried to adopt the solution from and here
如您所见,countUp 解决方案已经运行良好,但它需要连接到图表,以便在页面加载时绘制。
我对 canvas 的了解并不惊人。如果有人能提供帮助,我会很高兴。这是代码:https://jsfiddle.net/9oyoh67x/10/
$(document).ready(function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
ctx.lineWidth = 19;
ctx.lineCap = 'round';
ctx.shadowBlur = 10;
donutChart();
function degtoRad(degree) {
var factor = Math.PI / 180; // = 1 deg = 0.01745 rad
return degree * factor; // for 360 = 6.28 = 360°
}
/*function move() {
var elem = document.getElementById("canvas");
var width = 0;
var id = setInterval(countUp, 1000); }
*/
$(function () {
var countUp = setInterval(function () { donutChart }, 40);
function count($this) {
var current = parseInt($this.html(), 10);
$this.html(++current);
if (current !== $this.data('count')) {
setTimeout(function () { count($this) }, 50);
}
}
$(".testspan1").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan2").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan3").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan4").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
});
function donutChart() {
var factor_calc = Math.PI / 180;
var record = $('.testspan1').text(); // equal to 100% or 360°
var average = $('.testspan2').text();
var income = $('.testspan2').text();
var target = $('.testspan3').text();
// Record
ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 200, degtoRad(270), degtoRad(270 + (record / record) * 360));
ctx.stroke();
// Average
ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 170, degtoRad(270), degtoRad(270 + (average / record) * 360));
ctx.stroke();
//Income
ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 140, degtoRad(270), degtoRad(270 + (income / record) * 360));
ctx.stroke();
// Target
ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 110, degtoRad(270), degtoRad(270 + (target / record) * 360));
ctx.stroke();
// Record
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(115, 100, 164, 1)';
ctx.fillText(record, 220, 200);
//Average
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(125, 131, 164, 1)';
ctx.fillText(average, 220, 230);
//Income
ctx.font = "30px Philosopher";
ctx.fillStyle = 'rgba(75, 181, 164, 1)';
ctx.fillText(income, 220, 260);
// Target
ctx.font = "35px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText(target, 220, 290);
// Euro
ctx.font = "60px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText('€', 280, 255);
}
var options = {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '',
prefix: '',
suffix: '€'
};
});
HTML:
<div class="canvasdiv">
<canvas id="canvas" width="500" height="500"></canvas>
<img id="myImage" />
<span class='testspan1'>1250</span>
<span class='testspan2'>250</span>
<span class='testspan3'>450</span>
<span class='testspan4'>130</span>
</div>
对于有类似问题的人,这里有一些进一步的相关链接(不使用 canvas):
我做到了。这是我的解决方案 (https://jsfiddle.net/9oyoh67x/12/):
// requestAnimationFrame Shim
(function start() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
ctx.lineWidth = 19;
ctx.lineCap = 'round';
ctx.shadowBlur = 10;
var record = 820; // equal to 100% or 360°
var record_count = (record / record * 100)
var average = (229 / record * 100);
var income = (490 / record * 100);
var target = (750 / record * 100);
var counterClockwise = true;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
var startTime1 = null;
var startTime2 = null;
var startTime3 = null;
var startTime4 = null;
var duration = null;
var duration1 = null;
var duration2 = null;
var duration3 = null;
var duration4 = null;
var options = {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '0',
prefix: '',
suffix: ''
};
function animate_rec(time) {
if (!startTime1) {
startTime1 = time;
}
var delta1 = Math.min(1, (time - startTime1) / duration1);
var curPerc = ((2 * Math.PI) / 100) * (record_count * delta1);
console.log(curPerc)
var innerNumRec = (record * delta1);
//console.log(innerNumRec);
ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 200, -quart, curPerc - quart);
ctx.stroke();
if (delta1 < 1) {
requestAnimationFrame(animate_rec);
ctx.clearRect(215, 180, 50, 30);
} else {
startTime1 = null;
ctx.clearRect(215, 180, 50, 30);
}
// Record
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(115, 100, 164, 1)';
ctx.fillText(Math.round(innerNumRec), 220, 200);
}
var startAnim_rec = function () {
duration1 = 3000;
requestAnimationFrame(animate_rec);
};
function animate_avg(time) {
if (!startTime2) {
startTime2 = time;
}
var delta2 = Math.min(1, (time - startTime2) / duration2);
var curPerc = ((2 * Math.PI) / 100) * (average * delta2);
var innerNumAvg = ((average * record / 100) * delta2);
console.log(innerNumAvg);
ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 170, -quart, curPerc - quart);
ctx.stroke();
if (delta2 < 1) {
requestAnimationFrame(animate_avg);
ctx.clearRect(215, 210, 70, 50);
} else {
startTime2 = null;
ctx.clearRect(215, 210, 70, 50);
}
// Average
ctx.font = "30px Philosopher";
ctx.fillStyle = 'rgba(125, 131, 164, 1)';
ctx.fillText(Math.round(innerNumAvg), 220, 230);
}
var startAnim_avg = function () {
duration2 = 3200;
requestAnimationFrame(animate_avg);
};
function animate_inc(time) {
if (!startTime3) {
startTime3 = time;
}
var delta3 = Math.min(1, (time - startTime3) / duration3);
var curPerc = ((2 * Math.PI) / 100) * (income * delta3);
var innerNumInc = ((income * record / 100) * delta3);
console.log(innerNumInc);
ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 140, -quart, curPerc - quart);
ctx.stroke();
if (delta3 < 1) {
requestAnimationFrame(animate_inc);
ctx.clearRect(215, 230, 70, 50);
} else {
startTime3 = null;
ctx.clearRect(215, 230, 70, 50);
}
// Income
ctx.font = "35px Philosopher";
ctx.fillStyle = 'rgba(75, 181, 164, 1)';
ctx.fillText(Math.round(innerNumInc), 220, 260);
}
var startAnim_inc = function () {
duration3 = 3400;
requestAnimationFrame(animate_inc);
};
function animate_tar(time) {
if (!startTime4) {
startTime4 = time;
}
var delta4 = Math.min(1, (time - startTime4) / duration4);
var curPerc = ((2 * Math.PI) / 100) * (target * delta4);
var innerNumTar = ((target * record / 100) * delta4);
console.log(innerNumTar);
ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 110, -quart, curPerc - quart);
ctx.stroke();
if (delta4 < 1) {
requestAnimationFrame(animate_tar);
ctx.clearRect(220, 260, 70, 50);
} else {
startTime4 = null;
ctx.clearRect(220, 260, 70, 50);
}
// Target
ctx.font = "40px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText(Math.round(innerNumTar), 220, 290);
}
var startAnim_tar = function () {
duration4 = 3600;
requestAnimationFrame(animate_tar);
};
startAnim_rec();
startAnim_avg();
startAnim_inc();
startAnim_tar();
// Euro
ctx.font = "60px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText('€', 280, 255);});
基本上,我尝试为圆环图中的线条设置动画(参见 example), so that each of them is counted up with document.ready. I tried to adopt the solution from
如您所见,countUp 解决方案已经运行良好,但它需要连接到图表,以便在页面加载时绘制。
我对 canvas 的了解并不惊人。如果有人能提供帮助,我会很高兴。这是代码:https://jsfiddle.net/9oyoh67x/10/
$(document).ready(function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
ctx.lineWidth = 19;
ctx.lineCap = 'round';
ctx.shadowBlur = 10;
donutChart();
function degtoRad(degree) {
var factor = Math.PI / 180; // = 1 deg = 0.01745 rad
return degree * factor; // for 360 = 6.28 = 360°
}
/*function move() {
var elem = document.getElementById("canvas");
var width = 0;
var id = setInterval(countUp, 1000); }
*/
$(function () {
var countUp = setInterval(function () { donutChart }, 40);
function count($this) {
var current = parseInt($this.html(), 10);
$this.html(++current);
if (current !== $this.data('count')) {
setTimeout(function () { count($this) }, 50);
}
}
$(".testspan1").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan2").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan3").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
$(".testspan4").each(function () {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
});
function donutChart() {
var factor_calc = Math.PI / 180;
var record = $('.testspan1').text(); // equal to 100% or 360°
var average = $('.testspan2').text();
var income = $('.testspan2').text();
var target = $('.testspan3').text();
// Record
ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 200, degtoRad(270), degtoRad(270 + (record / record) * 360));
ctx.stroke();
// Average
ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 170, degtoRad(270), degtoRad(270 + (average / record) * 360));
ctx.stroke();
//Income
ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 140, degtoRad(270), degtoRad(270 + (income / record) * 360));
ctx.stroke();
// Target
ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 110, degtoRad(270), degtoRad(270 + (target / record) * 360));
ctx.stroke();
// Record
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(115, 100, 164, 1)';
ctx.fillText(record, 220, 200);
//Average
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(125, 131, 164, 1)';
ctx.fillText(average, 220, 230);
//Income
ctx.font = "30px Philosopher";
ctx.fillStyle = 'rgba(75, 181, 164, 1)';
ctx.fillText(income, 220, 260);
// Target
ctx.font = "35px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText(target, 220, 290);
// Euro
ctx.font = "60px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText('€', 280, 255);
}
var options = {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '',
prefix: '',
suffix: '€'
};
});
HTML:
<div class="canvasdiv">
<canvas id="canvas" width="500" height="500"></canvas>
<img id="myImage" />
<span class='testspan1'>1250</span>
<span class='testspan2'>250</span>
<span class='testspan3'>450</span>
<span class='testspan4'>130</span>
</div>
对于有类似问题的人,这里有一些进一步的相关链接(不使用 canvas):
我做到了。这是我的解决方案 (https://jsfiddle.net/9oyoh67x/12/):
// requestAnimationFrame Shim
(function start() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
ctx.lineWidth = 19;
ctx.lineCap = 'round';
ctx.shadowBlur = 10;
var record = 820; // equal to 100% or 360°
var record_count = (record / record * 100)
var average = (229 / record * 100);
var income = (490 / record * 100);
var target = (750 / record * 100);
var counterClockwise = true;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
var startTime1 = null;
var startTime2 = null;
var startTime3 = null;
var startTime4 = null;
var duration = null;
var duration1 = null;
var duration2 = null;
var duration3 = null;
var duration4 = null;
var options = {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '0',
prefix: '',
suffix: ''
};
function animate_rec(time) {
if (!startTime1) {
startTime1 = time;
}
var delta1 = Math.min(1, (time - startTime1) / duration1);
var curPerc = ((2 * Math.PI) / 100) * (record_count * delta1);
console.log(curPerc)
var innerNumRec = (record * delta1);
//console.log(innerNumRec);
ctx.strokeStyle = 'rgba(115, 100, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 200, -quart, curPerc - quart);
ctx.stroke();
if (delta1 < 1) {
requestAnimationFrame(animate_rec);
ctx.clearRect(215, 180, 50, 30);
} else {
startTime1 = null;
ctx.clearRect(215, 180, 50, 30);
}
// Record
ctx.font = "25px Philosopher";
ctx.fillStyle = 'rgba(115, 100, 164, 1)';
ctx.fillText(Math.round(innerNumRec), 220, 200);
}
var startAnim_rec = function () {
duration1 = 3000;
requestAnimationFrame(animate_rec);
};
function animate_avg(time) {
if (!startTime2) {
startTime2 = time;
}
var delta2 = Math.min(1, (time - startTime2) / duration2);
var curPerc = ((2 * Math.PI) / 100) * (average * delta2);
var innerNumAvg = ((average * record / 100) * delta2);
console.log(innerNumAvg);
ctx.strokeStyle = 'rgba(125, 131, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 170, -quart, curPerc - quart);
ctx.stroke();
if (delta2 < 1) {
requestAnimationFrame(animate_avg);
ctx.clearRect(215, 210, 70, 50);
} else {
startTime2 = null;
ctx.clearRect(215, 210, 70, 50);
}
// Average
ctx.font = "30px Philosopher";
ctx.fillStyle = 'rgba(125, 131, 164, 1)';
ctx.fillText(Math.round(innerNumAvg), 220, 230);
}
var startAnim_avg = function () {
duration2 = 3200;
requestAnimationFrame(animate_avg);
};
function animate_inc(time) {
if (!startTime3) {
startTime3 = time;
}
var delta3 = Math.min(1, (time - startTime3) / duration3);
var curPerc = ((2 * Math.PI) / 100) * (income * delta3);
var innerNumInc = ((income * record / 100) * delta3);
console.log(innerNumInc);
ctx.strokeStyle = 'rgba(75, 181, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 140, -quart, curPerc - quart);
ctx.stroke();
if (delta3 < 1) {
requestAnimationFrame(animate_inc);
ctx.clearRect(215, 230, 70, 50);
} else {
startTime3 = null;
ctx.clearRect(215, 230, 70, 50);
}
// Income
ctx.font = "35px Philosopher";
ctx.fillStyle = 'rgba(75, 181, 164, 1)';
ctx.fillText(Math.round(innerNumInc), 220, 260);
}
var startAnim_inc = function () {
duration3 = 3400;
requestAnimationFrame(animate_inc);
};
function animate_tar(time) {
if (!startTime4) {
startTime4 = time;
}
var delta4 = Math.min(1, (time - startTime4) / duration4);
var curPerc = ((2 * Math.PI) / 100) * (target * delta4);
var innerNumTar = ((target * record / 100) * delta4);
console.log(innerNumTar);
ctx.strokeStyle = 'rgba(26, 221, 164, 1)';
ctx.beginPath();
ctx.arc(250, 250, 110, -quart, curPerc - quart);
ctx.stroke();
if (delta4 < 1) {
requestAnimationFrame(animate_tar);
ctx.clearRect(220, 260, 70, 50);
} else {
startTime4 = null;
ctx.clearRect(220, 260, 70, 50);
}
// Target
ctx.font = "40px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText(Math.round(innerNumTar), 220, 290);
}
var startAnim_tar = function () {
duration4 = 3600;
requestAnimationFrame(animate_tar);
};
startAnim_rec();
startAnim_avg();
startAnim_inc();
startAnim_tar();
// Euro
ctx.font = "60px Philosopher";
ctx.fillStyle = 'rgba(26, 221, 164, 1)';
ctx.fillText('€', 280, 255);});