Reputation: 6957
I need to use several canvas-es
with different values (see data-percent
) with same reusable code block but "animation" makes it a little bit tricky. Im not sure how to make it reusable. Copy-pasting the same code over and over again is obviously a wrong move, I usually avoid it at any cost.
First thing is obviously to remove id
and use class
instead, then I could select all the canvas
-es:
<canvas class="circle-thingy" width="120" height="120" data-percent="75"></canvas>
<canvas class="circle-thingy" width="120" height="120" data-percent="23"></canvas>
<canvas class="circle-thingy" width="120" height="120" data-percent="89"></canvas>
var allCircles = document.getElementsByClassName('circle-thingy');
But now comes the trickier part.. How about canvas
JavaScript code? There's probably a very easy solution but I can't see it! Terrible time to quit smoking I guess (as always), brain is like shut down.
What I tried: for loop
with allCircles
list. Problem is that I cannot use setInterval
and clearTimeout
with this approach. Dynamic variable names? How do I reference them later?
Here's my code with a single circle, try it.
// Get canvas context
var ctx = document.getElementById('my-circle').getContext('2d');
// Current percent
var currentPercent = 0;
// Canvas north (close enough)
var start = 4.72;
// Dimensions
var cWidth = ctx.canvas.width;
var cHeight = ctx.canvas.height;
// Desired percent -> comes from canvas data-* attribute
var finalPercent = ctx.canvas.getAttribute('data-percent');
var diff;
function circle() {
diff = ((currentPercent / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.lineWidth = 3;
// Bottom circle (grey)
ctx.strokeStyle = '#eee';
ctx.beginPath();
ctx.arc(60, 60, 55, 0, 2 * Math.PI);
ctx.stroke();
// Percent text
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.font="900 10px arial";
ctx.fillText(currentPercent + '%', cWidth * 0.5, cHeight * 0.5 + 2, cWidth);
// Upper circle (blue)
ctx.strokeStyle = '#0095ff';
ctx.beginPath();
ctx.arc(60, 60, 55, start, diff / 10 + start);
ctx.stroke();
// If has desired percent -> stop
if( currentPercent >= finalPercent) {
clearTimeout(myCircle);
}
currentPercent++;
}
var myCircle = setInterval(circle, 20);
<canvas id="my-circle" width="120" height="120" data-percent="75"></canvas>
Feel free to use this code snippet in your own projects.
Upvotes: 0
Views: 64
Reputation: 3484
You can use bind to solve this.
Create a helper function that will start animation for given canvas
:
function animateCircle(canvas) {
var scope = {
ctx: canvas.getContext('2d')
// other properties, like currentPercent, finalPercent, etc
};
scope.interval = setInterval(circle.bind(scope), 20);
}
Change your circle
function to refer variables from this
instead of global ones:
function circle() {
// your old code with corresponding changes
// e.g.
var ctx = this.ctx; // references corresponding scope.ctx
// or
this.currentPercent++; // references corresponding scope.currentPercent
}
Working JSFiddle, if something is not clear.
Upvotes: 1