I have this code that is displaying one circle with a % value, and i'm trying to add another circle next to it who displays another % value.
To do so, i have tried to add another JS code who calls the second ID my_canvas2 but the results are one circle with an incremental % value with no ending.
var ctx = document.getElementById('my_canvas1').getContext('2d');
var al = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function progressSim() {
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 7;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + '%', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(80, 80, 70, start, diff / 10 + start, false);
ctx.stroke();
if (al >= 65) {
clearTimeout(sim);
// Add scripting here that will run when progress completes
}
al++;
}
var sim = setInterval(progressSim, 25);
<canvas id="my_canvas1" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
<canvas id="my_canvas2" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
I've seen some similars subjects where the issue was the closing path of the first circle, i've tried so, still the same problem. Thanks for helping.
Try this.
function progressSim(ctx, al, start) {
let cw = ctx.canvas.width;
let ch = ctx.canvas.height;
let diff;
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 7;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + '%', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(80, 80, 70, start, diff / 10 + start, false);
ctx.stroke();
}
function startProgress(canvas_id, progress_int_1, stop_at) {
let ctx = document.getElementById(canvas_id).getContext('2d');
// let start = 4.72;
let al = progress_int_1;
let start = 4.72;
var sim = setInterval(function(){
progressSim(ctx, al, start);
al++;
if (al >= stop_at) {
clearTimeout(sim);
}
}, 25);
}
var progress_int_1 = 0;
var progress_int_2 = 0;
var sim1;
var sim2;
sim1 = startProgress('my_canvas1', progress_int_1, 50);
sim2 = startProgress('my_canvas2', progress_int_2, 80);
<canvas id="my_canvas1" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
<canvas id="my_canvas2" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
You need to isolate your variables if you want to duplicate the functionality. This allows you to have code that is free from conflict.
This function takes in 2 parameters, the ID of your Canvas, and what percentage you want to show it to. diff and start are local variables that do not need to persist in between calls.
function progressSim(id, percent) {
var ctx = document.getElementById(id).getContext('2d'),
cw = ctx.canvas.width,
ch = ctx.canvas.height,
al = 0,
sim = setInterval(progress, 25);
function progress() {
var start = 4.72,
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 7;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + '%', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(80, 80, 70, start, diff / 10 + start, false);
ctx.stroke();
if (al >= percent) {
clearTimeout(sim);
// Add scripting here that will run when progress completes
}
al++;
};
}
progressSim('my_canvas1', 65);
progressSim('my_canvas2', 80);
<canvas id="my_canvas1" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
<canvas id="my_canvas2" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
Very simple solution, I've just copied you code and done a find and replace on it so it can be used for my_canvas2
var ctx = document.getElementById('my_canvas1').getContext('2d');
var al = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function progressSim() {
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 7;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + '%', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(80, 80, 70, start, diff / 10 + start, false);
ctx.stroke();
if (al >= 65) {
clearTimeout(sim);
// Add scripting here that will run when progress completes
}
al++;
}
var sim = setInterval(progressSim, 25);
var ctx2 = document.getElementById('my_canvas2').getContext('2d');
var al2 = 0;
var start2 = 4.72;
var cw2 = ctx2.canvas.width;
var ch2 = ctx2.canvas.height;
var diff2;
function progresssim2() {
diff2 = ((al2 / 100) * Math.PI * 2 * 10).toFixed(2);
ctx2.clearRect(0, 0, cw2, ch2);
ctx2.lineWidth = 7;
ctx2.fillStyle = '#09F';
ctx2.strokeStyle = "#09F";
ctx2.textal2ign = 'center';
ctx2.fillText(al2 + '%', cw2 * .5, ch2 * .5 + 2, cw2);
ctx2.beginPath();
ctx2.arc(80, 80, 70, start2, diff2 / 10 + start2, false);
ctx2.stroke();
if (al2 >= 45) {
clearTimeout(sim2);
// Add scripting here that will run when progress completes
}
al2++;
}
var sim2 = setInterval(progresssim2, 25);
<canvas id="my_canvas1" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
<canvas id="my_canvas2" width="170" height="170" style="border:1px dashed #CCC;"></canvas>
Other on here may have a more eloquent solution
Related
So I have wanted to make an ocean in the night with a canvas. I got the Wave part down but I want them to be filled. So that they are not just a lign anymore but a solid block locking like waves. I really like how they look right now but if you have any tweeks that could make them look even better feel free to share them!
Thanks for the Help in Advance!
var c = document.getElementById("screen2");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var w = window.innerWidth;
var h = 100;
var amplitude = h;
var frequency = .01;
var phi = 0;
var frames = 0;
var stopped = true;
//ctx.strokeStyle = "Cornsilk";
ctx.lineWidth = 4;
//first wave
function Draw() {
frames++
phi = frames / 88;
ctx.clearRect(0, 0, cw, ch);
ctx.beginPath();
ctx.moveTo(0, ch);
for (var x = 0; x < w; x++) {
y = Math.sin(x * frequency + phi) * amplitude/2 + amplitude /2;
//y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
ctx.lineTo(x, y + ch -110); // setting it to the bottom of the page 100= lift
}
ctx.lineTo(w, ch);
ctx.lineTo(0, ch);
ctx.stroke();
requestId = window.requestAnimationFrame(Draw);
}
requestId = window.requestAnimationFrame(Draw);
//second wave
function Draw2() {
frames++
phi = frames / 72 ;
ctx.beginPath();
ctx.moveTo(0, ch);
for (var x = 0; x < w; x++) {
y = Math.sin(x * frequency + phi) * amplitude/4 + amplitude/4;
//y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
ctx.lineTo(x, y + ch -110); // setting it to the bottom of the page 100= lift
}
ctx.lineTo(w, ch);
ctx.lineTo(0, ch);
ctx.stroke();
requestId = window.requestAnimationFrame(Draw2);
}
requestId = window.requestAnimationFrame(Draw2);
canvas {
display:block;
margin:0 auto;
width:100%;
height:100vh;
}
<canvas id="screen2"></canvas>
First and foremost what I really would change is using requestAnimationFrame two times as it's completely redundant. You can group your drawing operations in a single function and just execute this.
As #mousetail hinted a simple 'fix' would be using .fill() instead of .stroke(). The problem is that you would have two completely solid shapes of the same colour making it look like there's just a single wave. So the next step would be adding two different colours. As that might still look a little boring I'd use two linear gradients - a lighter for the foreground and a darker for the background wave.
To make it look even more interesting I'd move the waves up & down over time.
var c = document.getElementById("screen2");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var w = window.innerWidth;
var h = 100;
var amplitude = h;
var frequency = .01;
var phi = 0;
var frames = 0;
var stopped = true;
var gradientA = ctx.createLinearGradient(0, ch / 2, 0, ch);
gradientA.addColorStop(0, "#29c3d3");
gradientA.addColorStop(1, "#15656e");
var gradientB = ctx.createLinearGradient(0, ch / 2, 0, ch);
gradientB.addColorStop(0, "#55dee5");
gradientB.addColorStop(1, "#399499");
ctx.lineWidth = 4;
var step = 0;
function drawWaves() {
frames++;
phi = frames / 88;
ctx.clearRect(0, 0, cw, ch);
ctx.beginPath();
ctx.moveTo(0, ch);
for (var x = 0; x < w; x++) {
y = Math.sin(x * frequency + phi) * amplitude / 2 + amplitude / 2;
//y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
ctx.lineTo(x, y + ch - 110 + Math.sin(step / 2) * 10); // setting it to the bottom of the page 100= lift
}
ctx.lineTo(w, ch);
ctx.lineTo(0, ch);
ctx.fillStyle = gradientA;
ctx.fill();
frames++;
phi = frames / 72;
ctx.beginPath();
ctx.moveTo(0, ch);
for (var x = 0; x < w; x++) {
y = Math.sin(x * frequency + phi) * amplitude / 4 + amplitude / 4;
//y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
ctx.lineTo(x, y + ch - 110 + Math.sin(step) * 20); // setting it to the bottom of the page 100= lift
}
ctx.lineTo(w, ch);
ctx.lineTo(0, ch);
ctx.fillStyle = gradientB;
ctx.fill();
step += 0.02;
requestId = window.requestAnimationFrame(drawWaves);
}
requestId = window.requestAnimationFrame(drawWaves);
canvas {
display: block;
margin: 0 auto;
width: 100%;
height: 100vh;
}
<canvas id="screen2"></canvas>
I've got this piece of code that draws a ball and i want to continuously pass in different cooridinates in order to make it move around but when the refresh rate gets way too high, canvas stops updating. How do i force canvas to update and redraw everything with the arguments passed in?
var c = document.getElementById("circle");
var ctx = c.getContext("2d");
var x = Math.floor(Math.random() * 50);
var y = Math.floor(Math.random() * 50);
function determinePosition(x, y) {
var trueX = x + 120;
var trueY = y + 80;
ctx.beginPath();
ctx.arc(trueX, trueY, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.strokeStyle = "black";
ctx.stroke();
}
while(true){
determinePosition(x, y);
}
<div class="gcircle">
<canvas id="circle" width="240px" height="160"></canvas>
</div>
var c = document.getElementById("circle");
var ctx = c.getContext("2d");
function determinePosition(x, y) {
//clear the canvas
ctx.clearRect(0, 0, c.width, c.height);
var trueX = x + 120;
var trueY = y + 80;
ctx.beginPath();
ctx.arc(trueX, trueY, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.strokeStyle = "black";
ctx.stroke();
}
//set random location for each 0.5 sec
setInterval(function() {
var x = Math.floor(Math.random() * 50);
var y = Math.floor(Math.random() * 50);
determinePosition(x, y);
}, 500)
<div class="gcircle">
<canvas id="circle" width="240px" height="160"></canvas>
</div>
`
Drawing should always happen in a requestAnimationFrame loop. requestAnimationFrame runs at your monitor's refresh rate, so it's the fastest any animation can run. You can set it up like this:
var c = document.getElementById("circle");
var ctx = c.getContext("2d");
var x = Math.floor(Math.random() * 50);
var y = Math.floor(Math.random() * 50);
var trueX = 0;
var trueY = 0;
function determinePosition(x, y) {
trueX = x + 120;
trueY = y + 80;
}
requestAnimationFrame(function draw() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.beginPath();
ctx.arc(trueX, trueY, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.strokeStyle = "black";
ctx.stroke();
requestAnimationFrame(draw);
})
determinePosition(x, y);
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>
I want four different circular progress bar in my webpage which will be placed on one particular div.Upon scrolling at that div I want all of them to be active at the same time and finishes on the specified percentage.
Only one is working fine.How can I do this? Here, is the attached code.
var ctx = document.getElementById('my_canvas').getContext('2d');
var al = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function progressSim() {
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 5;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + 'K TOURIST', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(35, 35, 30, start, diff / 10 + start, false);
/*ctx.arc(200,75,50,0*Math.PI,1.5*Math.PI);*/
ctx.stroke();
if (al >= 50) {
clearTimeout(sim);
// Add scripting here that will run when progress completes
}
al++;
}
var sim = setInterval(progressSim, 50);
<div id="first_progress">
<canvas id="my_canvas" width="70" height="70" style="border:1px dashed #CCC;"></canvas>
</div>
<div id="second_progress">
<canvas id="my_canvas2" width="70" height="70" style="border:1px dashed #CCC;"></canvas>
</div>
it seem you only update one canvas. you need to update both canvas using two different contexts. or you could draw the progress bars into the same but bigger canvas.
this example will not help using four. you need to store different angles and progress you know for each bar but it show how to update the two in the example.
hope it works out. ps - use arrays to store the ctx's and values. much easier that way.
var ctx = document.getElementById('my_canvas').getContext('2d');
var ctx2 = document.getElementById('my_canvas2').getContext('2d');
var al = 0;
var start = 4.72;
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
var diff;
function progressSim(ctx, simInx) {
diff = ((al / 100) * Math.PI * 2 * 10).toFixed(2);
ctx.clearRect(0, 0, cw, ch);
ctx.lineWidth = 5;
ctx.fillStyle = '#09F';
ctx.strokeStyle = "#09F";
ctx.textAlign = 'center';
ctx.fillText(al + 'K TOURIST', cw * .5, ch * .5 + 2, cw);
ctx.beginPath();
ctx.arc(35, 35, 30, start, diff / 10 + start, false);
/*ctx.arc(200,75,50,0*Math.PI,1.5*Math.PI);*/
ctx.stroke();
if (al >= 50) {
clearTimeout(simInx == 1 ? sim1 : sim2);
// Add scripting here that will run when progress completes
}
al++;
}
var sim1 = setInterval(progressSim, 50, ctx, 1);
var sim2 = setInterval(progressSim, 50, ctx2, 2);
<div id="first_progress">
<canvas id="my_canvas" width="70" height="70" style="border:1px dashed #CCC;"></canvas>
</div>
<div id="second_progress">
<canvas id="my_canvas2" width="70" height="70" style="border:1px dashed #CCC;"></canvas>
</div>
On an HTML5 canvas I can't find a method to make colored circles. I've been consulting this as a reference.
Here is my current attempt
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillRect(20, 20, 100, 100);
ctx.lineJoin = "round";
ctx.lineWidth = "cornerRadius";
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
(Also on jsFiddle: http://jsfiddle.net/kvnm21r1/1/)
I've tried using the canvas arc method, which creates a circle, but doesn't color it.
I can't use the border-radius property, because ctx is not an element.
Is there any way, I can transform my squares into circles?
Thanks in advance.
You can use quadratic curves to "round-out" the straight lines of your square until they form a circle.
// change sideCount to the # of poly sides desired
//
var sideCount = 4;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 2;
ctx.fillStyle = randomColor();
var PI2 = Math.PI * 2;
var cx = 150;
var cy = 150;
var radius = 100;
var xx = function (a) {
return (cx + radius * Math.cos(a));
}
var yy = function (a) {
return (cy + radius * Math.sin(a));
}
var lerp = function (a, b, x) {
return (a + x * (b - a));
}
var sides = [];
for (var i = 0; i < sideCount; i++) {
sides.push(makeSide(i, sideCount));
}
var percent = 0;
var percentDirection = 0.50;
$("#toShape").click(function () {
percentDirection = -0.50;
})
$("#toCircle").click(function () {
percentDirection = 0.50;
})
animate();
// functions
function animate() {
requestAnimationFrame(animate);
drawSides(percent);
percent += percentDirection;
if (percent > 100) {
percent = 100;
}
if (percent < 0) {
percent = 0;
}
}
function drawSides(pct, color) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (pct == 100) {
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, PI2);
ctx.closePath();
ctx.fill();
} else {
ctx.beginPath();
ctx.moveTo(sides[0].x0, sides[0].y0);
for (var i = 0; i < sideCount; i++) {
var side = sides[i];
var cpx = lerp(side.midX, side.cpX, pct / 100);
var cpy = lerp(side.midY, side.cpY, pct / 100);
ctx.quadraticCurveTo(cpx, cpy, side.x2, side.y2);
}
ctx.fill();
}
}
function makeSide(n, sideCount) {
var sweep = PI2 / sideCount;
var sAngle = sweep * (n - 1);
var eAngle = sweep * n;
var x0 = xx(sAngle);
var y0 = yy(sAngle);
var x1 = xx((eAngle + sAngle) / 2);
var y1 = yy((eAngle + sAngle) / 2);
var x2 = xx(eAngle);
var y2 = yy(eAngle);
var dx = x2 - x1;
var dy = y2 - y1;
var a = Math.atan2(dy, dx);
var midX = lerp(x0, x2, 0.50);
var midY = lerp(y0, y2, 0.50);
var cpX = 2 * x1 - x0 / 2 - x2 / 2;
var cpY = 2 * y1 - y0 / 2 - y2 / 2;
return ({
x0: x0,
y0: y0,
x2: x2,
y2: y2,
midX: midX,
midY: midY,
cpX: cpX,
cpY: cpY,
color: randomColor()
});
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="toShape">Animate to Shape</button>
<button id="toCircle">Animate to Circle</button><br>
<canvas id="canvas" width=300 height=300></canvas>
JSfiddle with a circle
To draw a circle you'll need to draw an arc and have a starting angle and an ending angle. So you'll have to use Pi and define a radius.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
Avoid w3schools.com whenever possible. Refer to sites like MDN instead.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.beginPath();
var radius = 50; // Arc radius
var startAngle = 0; // Starting point on circle
var endAngle = Math.PI*2; // End point on circle
ctx.arc(150, 75, radius, startAngle, endAngle, true);
ctx.fill();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">