I made some web searching about canvas and how to create a circular progress bar and i got this. I made some changes to the pieces of code that I found online but i can't reload the circular path again. By reload I mean, when the circle is full ( a perfect circle) I would like to draw it again. In other words, I would like to repeat the procedure of drawing the circle again after a full spin is completed. I tried to clear the whole canvas when my variable trigger is greater than 100, but no success. Any ideas?
here's the code
function draw() {
var c=document.getElementById("prog");
var ctx=c.getContext("2d");
var time = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function justdoit(){
diff = ((time / 100) * Math.PI*2*10);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 10;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText( time+'s', cw*.5, ch*.5+2, cw);
ctx.beginPath();
ctx.arc(75, 75, 30, start, diff/10+start, false);
ctx.stroke();
if(trigger >= 100){
ctx.clearRect(0, 0, cw, ch);
}
time++;
}
var trigger = setInterval(justdoit, 1000);
}
<button onclick="draw()"> draw </button>
<canvas id="prog"></canvas>
The function draw is called on a button element with an attribute onclick="draw()";
I am not sure if this is what you are after, I have separated the timer out for the position of the circle so you can reset the position to 0 every 100 seconds without reseting the time.
The important things I have changed:
Added a new variable called pos.
var pos = 0;
Changed the diff calculation to use pos.
diff = ((pos / 100) * Math.PI*2*10);
Changed the if statement to set pos back to 0 every 100 seconds and clear the circle.
if(time % 100 == 0){
pos = 0;
ctx.clearRect(0, 0, cw, ch);
}
Increment pos with time.
pos++;
Also I have decreased the timer in the example so we don't have to wait a long time to see. - Change back to 1000 for 1 second interval setInterval(justdoit, 100);
function draw() {
var c=document.getElementById("prog");
var ctx=c.getContext("2d");
var time = 0;
var pos = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function justdoit(){
diff = ((pos / 100) * Math.PI*2*10);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 10;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText( time+'s', cw*.5, ch*.5+2, cw);
ctx.beginPath();
ctx.arc(75, 75, 30, start, diff/10+start, false);
ctx.stroke();
if(time % 100 == 0){
pos = 0;
ctx.clearRect(0, 0, cw, ch);
}
time++;
pos++;
}
var trigger = setInterval(justdoit, 100);
}
<button onclick="draw()"> draw </button>
<canvas id="prog"></canvas>
The last 'if' block is wrong. Use this instead:
if(time >= 100){
ctx.clearRect(0, 0, cw, ch);
time = 0;
}
This will just make the thing repeat itself over and over again. Hopefully this was what you wanted.
The complete code is here (I speeded the thing up by changing the step wait time from '1000' to '10 in the second line from the bottom):
function draw() {
var c=document.getElementById("prog");
var ctx=c.getContext("2d");
var time = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function justdoit(){
diff = ((time / 100) * Math.PI*2*10);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 10;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText( time+'s', cw*.5, ch*.5+2, cw);
ctx.beginPath();
ctx.arc(75, 75, 30, start, diff/10+start, false);
ctx.stroke();
if(time >= 100){
ctx.clearRect(0, 0, cw, ch);
time = 0;
}
time++;
}
var trigger = setInterval(justdoit, 10);
}
<button onclick="draw()"> draw </button>
<canvas id="prog"></canvas>
Related
I'm trying to make circular chart on html5 canvas el.
(function () {
var ctx = document.getElementById('canvas').getContext('2d');
var counter = 0;
var start = 4.72;
var cW = ctx.canvas.width;
var cH = ctx.canvas.height;
var diff;
var maxVal = 44;
function progressChart(){
diff = ((counter / 100) * Math.PI*2*10).toFixed(2);
ctx.clearRect(0, 0, cW, cH);
ctx.lineWidth = 15;
ctx.fillStyle = '#ff883c';
ctx.strokeStyle = '#ff883c';
ctx.textAlign = 'center';
ctx.font = '25px Arial';
ctx.fillText(counter+'%', cW*.5, cH*.55, cW);
ctx.beginPath();
ctx.arc(70, 70, 60, start, diff/10+start, false);
ctx.stroke();
if(counter >= maxVal){
clearTimeout(drawChart);
}
counter++;
}
var drawChart = setInterval(progressChart, 20);
})();
<canvas id="canvas" width="140" height="140"></canvas>
I want to add doughnut background before browser start drawing fill chart. Unfortunately, I need to use ctx.clearRect() because I've got strange visual effect. Is any way to combine this two rings?
Yes, there is a way and that is, drawing another arc for doughnut background, before drawing fill chart.
Also, you should use requestAnimationFrame() instead of setInterval(), for better efficiency.
var ctx = document.getElementById('canvas').getContext('2d');
var counter = 0;
var start = 4.72;
var cW = ctx.canvas.width;
var cH = ctx.canvas.height;
var diff;
var maxVal = 44;
var rAF;
function progressChart() {
diff = ((counter / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cW, cH);
ctx.lineWidth = 15;
ctx.fillStyle = '#ff883c';
ctx.textAlign = 'center';
ctx.font = '25px Arial';
ctx.fillText(counter + '%', cW * .5, cH * .55, cW);
// doughnut background
ctx.beginPath();
ctx.arc(70, 70, 60, 0, Math.PI * 2, false);
ctx.strokeStyle = '#ddd';
ctx.stroke();
// fill chart
ctx.beginPath();
ctx.arc(70, 70, 60, start, diff / 10 + start, false);
ctx.strokeStyle = '#ff883c';
ctx.stroke();
if (counter >= maxVal) {
cancelAnimationFrame(rAF);
return;
}
counter++;
rAF = requestAnimationFrame(progressChart);
}
progressChart();
<canvas id="canvas" width="140" height="140"></canvas>
Trying to animate some balls, that appear with an interval on canvas.
Balls do appear every n* seconds, but I can't make them move :c
What am I doing wrong?
https://jsbin.com/mexofuz/26/edit?js,output
function Ball(){
this.X = 50;
this.Y = 50;
this.radius = Math.floor(Math.random()*(30-10)+10);
this.color = getRandomColor();
this.dx = Math.floor(Math.random()*(20-10)+10);
this.dy = Math.floor(Math.random()*(20-10)+10);
}
Ball.prototype.draw = function(){
context.fillStyle = this.color;
context.beginPath();
context.arc(this.X, this.Y, this.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
}
Ball.prototype.animate = function(){
if(this.X<0 || this.X>(w-this.radius)) this.dx=-this.dx;
if(this.Y<0 || this.Y>(h-this.radius)) this.dy=-this.dy;
this.X+=this.dx;
this.Y+=this.dy;
}
var balls = [];
function render() {
context.fillStyle = "white";
context.fillRect(0, 0, w, h);
for(var i = 1;i<=20;i++){
balls[i] = new Ball();
setTimeout(Ball.prototype.draw.bind(this.balls[i]), 5000 * i);
// Ball.prototype.animate.bind(this.balls[i]);
if (balls[i].X < 0 || balls[i].X > w-balls[i].radius) {
balls[i].dx = -balls[i].dx;
}
if (balls[i].Y < 0 || balls[i].Y > h-balls[i].radius) {
balls[i].dy = -balls[i].dy;
}
balls[i].x += balls[i].dx
balls[i].y += balls[i].dy
}
console.log(balls);
}
render();
You need to do two things - firstly, update your 'ball' position. At the moment you just do this once, you need to place it inside of a setInterval or another method of updating several times a second. Secondly you need to redraw the canvas each time the balls move (once per update is fine rather than once per ball). An example:
setInterval(function () {
balls.forEach(a=>a.animate());
context.fillStyle = "white";
context.fillRect(0, 0, w, h);
balls.forEach(a=>a.draw());
}, 30);
Add this inside your render function after your for loop.
I'm working on a game to play in canvas, and was wanting to add some ambiance to a background layer using javascript. To start, here is the code...
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-150;
var dx = Math.random() * (-5 * 5) + 15;
var dy = -15;
function drawDot() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
};
function move() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawDot();
x += dx;
y += dy;
};
setInterval(move, 50);
If you run that, you can see that what I have is a black ball that moves up and off the page inside a random conal space. What I need help with is figuring out the best way to:
A. Populate it with more balls (maybe like 2-3) that are on their own random trajectory, and
B. Make it so those 2-3 balls are constantly animating inside the random cone area off the page from the same starting area (kind of like a constant spurting fountain effect).
A problem I can already see is that by using the console log, the 1 working ball I have now just keeps going off into infinity outside the canvas, so when I try to add a new one it won't run the function. I'm very new to javascript and especially canvas so apologies if this is obvious!
Thank you for any help with this!
There is a good tutorial by Seb Lee-Delisle on this exact problem here:
https://vimeo.com/36278748
Basically you have to encapsulate each Dot so it knows about its own position and acceleration.
EDIT 1
Here is an example using you own code:
document.body.innerHTML = '<canvas height="600" width="600" id="myCanvas"></canvas>';
clearInterval(interval);
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var dotArray = [];
function Dot() {
var dot = {
y : canvas.height / 2,
x : canvas.width / 2,
speedX : Math.random() * ( - 5 * 5) + 15,
speedY : Math.random() * ( - 5 * 5) + 15,
age : 0,
draw : function () {
this.x += this.speedX;
this.y += this.speedY;
ctx.beginPath();
ctx.arc(this.x, this.y, 10, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
};
return dot;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].draw();
dotArray[i].age++;
if (dotArray[i].age > 20) {
dotArray.splice(i, 1);
}
}
dotArray.push(new Dot());
}
draw();
var interval = setInterval(draw, 1000 / 60);
I am trying to change the size of my canvas element.
var canvas = document.getElementById('timer'),
ctx = canvas.getContext('2d'),
sec = this.length,
countdown = sec;
ctx.lineWidth = 10;
ctx.strokeStyle = "#F60017";
ctx.strokeStyle = "#000000";
var startAngle = 0,
time = 0,
intv = setInterval(function () {
ctx.clearRect(0, 0, 200, 200);
var endAngle = (Math.PI * time * 2 / sec);
ctx.arc(65, 35, 30, startAngle, endAngle, false);
startAngle = endAngle;
ctx.stroke();
countdown--;
if (++time > sec, countdown == 0) {
clearInterval(intv), $("#timer, #counter").show();
}
}, 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="timer"></canvas>
If I change ctx.clearRect(0, 0, 200, 200); it still remains 200x200
The clearRect() is used to remove the previous drawing before a new one is drawn. I added new variables: x, y and size. Along with ctx.lineWidth, this should be enough to change the appearance.
var canvas = document.getElementById('timer'),
ctx = canvas.getContext('2d'),
sec = 100,
countdown = sec;
var x = 60,
y = 60
size = 30; // change me
ctx.lineWidth = 25;
ctx.strokeStyle = "#F60017";
ctx.strokeStyle = "#000000";
var startAngle = 0,
time = 0,
intv = setInterval(function () {
console.log('interval');
ctx.clearRect(0, 0, 200, 200);
var endAngle = (Math.PI * time * 2 / sec);
ctx.arc(x, y, size, startAngle, endAngle, false);
startAngle = endAngle;
ctx.stroke();
countdown--;
if (++time > sec && countdown <0) {
clearInterval(intv), $("#timer, #counter").show();
}
}, 10);
<canvas id="timer"></canvas>
I am doing some work with HTML canvases. Unfortunately I have ran into a very weird problem. At some point during development of the code the web page started to hang the browser. There were no tight loops apart from the requestAnimFrame shim so I took it back to basics and have found a very odd thing.
The code below will animate a circle across the screen. This works perfectly fine. If I comment out the code to draw the circle (marked in the code) it then grinds the browser to a halt. What is happening?
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(lastTime, myCircle) {
//return;
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// update
var date = new Date();
var time = date.getTime();
var timeDiff = time - lastTime;
var linearSpeed = 100;
// pixels / second
var linearDistEachFrame = linearSpeed * timeDiff / 1000;
var currentX = myCircle.x;
if(currentX < canvas.width - myCircle.width - myCircle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myCircle.x = newX;
}
lastTime = time;
// clear
drawGrid();
//draw a circle
context.beginPath();
context.fillStyle = "#8ED6FF";
context.arc(myCircle.x, myCircle.y, myCircle.width, 0, Math.PI*2, true);
context.closePath();
context.fill();
context.lineWidth = myCircle.borderWidth;
context.strokeStyle = "black";
context.stroke();
// request new frame
requestAnimFrame(function() {
animate(lastTime, myCircle);
});
}
$(document).ready(function() {
var myCircle = {
x: 50,
y: 50,
width: 30,
height: 50,
borderWidth: 2
};
//drawGrid();
var date = new Date();
var time = date.getTime();
animate(time, myCircle);
});
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.strokeStyle = "#ddd";
context.stroke();
}
And my canvas is declared like so:
<canvas id="myCanvas" width="700" height="400"></canvas>
Turns out that the reason it worked when I draw the circle was because that code contained a closePath function. Adding that to the drawGrid function below fixes the issue.
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
context.beginPath();
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.closePath();
context.strokeStyle = "#ddd";
context.stroke();
}