Javascript animation of arc() length - javascript

I know that this question may have already been answered, but I am having a hard time figuring out how to do it with my code.
What I would like is for the arc of the circle to do a draw animation from 0deg to 360deg whenever the mouse is clicked.
I know that I should put this in a loop that increases the angle, but I keep running into issues with (I think) translate.
Here is my code so far:
https://jsfiddle.net/s7aufv0g/2/
This is where I draw the ball:
// Draw the ball
ctx.clearRect(0,0,width,height);
ctx.save();
ctx.translate(ball.position.x, ball.position.y);
ctx.beginPath();
ctx.arc(0, 0, ball.radius, 0, Math.PI*2, true);
ctx.stroke();
ctx.closePath();
ctx.restore();
Any help would be great, thank you very much.

Don't bother with context.translate because you can set the arc's centerX & centerY directly in the context.arc command.
You can control how much of the 360 degree arc angle is shown in the animation by setting the startAngle & endAngle in context.arc(centerX,centerY,radius,startAngle,endAngle).
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var cx=cw/2;
var cy=ch/2;
var radius=Math.min(cw,ch)*.75/2;
var startAngle=-Math.PI/2;
var accumAngle=0;
var increment=Math.PI*2/120;
ctx.lineWidth=13;
ctx.strokeStyle='skyblue';
requestAnimationFrame(animate);
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function handleMouseDown(e){
if(accumAngle>=Math.PI*2){
accumAngle=0;
requestAnimationFrame(animate);
}
}
function animate(time){
accumAngle+=increment;
ctx.clearRect(0,0,cw,ch);
ctx.beginPath();
ctx.arc(cx,cy,radius,startAngle,startAngle+accumAngle);
ctx.stroke();
if(accumAngle<=Math.PI*2){ requestAnimationFrame(animate); }
}
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>
<h4>Click in red canvas to begin arc animation<br>You must wait for any current circle to finish drawing.</h4>
<canvas id="canvas" width=300 height=300></canvas>

Here is someone else's fiddle animating the drawing of arc(). Perhaps it will get you pointed in the right direction. Add a click handler to start the draw() method and you should be good to go.
HTML
<html>
<head>
</head>
<body>
<canvas id="canvas1" width="500" height="500"></canvas>
</body>
</html>
JS
var currentEndAngle = 0
var currentStartAngle = 0;
var currentColor = 'black';
var lineRadius = 75;
var lineWidth = 15;
setInterval(draw, 50);
function draw() { /***************/
var can = document.getElementById('canvas1'); // GET LE CANVAS
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius;
var width;
var startAngle = currentStartAngle * Math.PI;
var endAngle = (currentEndAngle) * Math.PI;
currentStartAngle = currentEndAngle - 0.01;
currentEndAngle = currentEndAngle + 0.01;
if (Math.floor(currentStartAngle / 2) % 2) {
currentColor = "white";
radius = lineRadius - 1;
width = lineWidth + 3;
} else {
currentColor = "black";
radius = lineRadius;
width = lineWidth;
}
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = width;
context.lineCap = "round";
// line color
context.strokeStyle = currentColor;
context.stroke();
http://jsfiddle.net/umaar/fnMvf/

Related

Animate a Fill Circle like pie chart using Canvas

Basically I want to be able to Fill a Circle using canvas, but it animate like pie chart and mask to show new image in circle.
My canvas knowledge isn't amazing, Here is an image to display what i want.
an anyone shed some light on how to do it?
Here is a fiddle of what I've managed
var canvas = document.getElementById('Circle');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 80;
var full = radius*2;
var amount = 0;
var amountToIncrease = 0.1;
function draw() {
context.beginPath();
context.arc(centerX, centerY, radius, 0, amount * Math.PI, false);
context.fillStyle = '#13a8a4';
context.fill();
context.lineWidth = 10;
context.strokeStyle = '#000000';
context.stroke();
amount += amountToIncrease;
if (amount > full) amount = 0; // restart
}
draw();
// Every second we'll fill more;
setInterval(draw, 100);
This is one way:
Draw your gray background.
Fill your percent-arc with a starting angle at -Math.PI*2 (=="12 on a clock") and an ending angle of -Math.PI*2 + Math.PI*2*percent (==a full circle of 2PI times your desired percent).
Draw your logo.
To animate, just use a requestAnimationFrame loop that incrementally draws the percent-arc starting at 0 percent and ending at your target percent.
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var nextTime=0;
var duration=1000;
var endingPct=75;
var pct=0;
var increment=duration/pct;
requestAnimationFrame(animate);
function animate(time){
draw(pct);
pct++;
if(pct<=endingPct){requestAnimationFrame(animate);}
}
function draw(pct){
var endRadians=-Math.PI/2+Math.PI*2*pct/100;
ctx.fillStyle='lightgray';
ctx.fillRect(0,0,cw,ch);
ctx.beginPath();
ctx.arc(150,125,100,-Math.PI/2,endRadians);
ctx.lineTo(150,125);
ctx.fillStyle='white';
ctx.fill();
ctx.beginPath();
ctx.moveTo(150,100);
ctx.lineTo(175,150);
ctx.quadraticCurveTo(150,125,125,150);
ctx.closePath();
ctx.strokeStyle='#13a8a4';
ctx.lineJoin='bevel';
ctx.lineWidth=10;
ctx.stroke();
ctx.fillStyle='black';
ctx.textAlign='center';
ctx.textBaseline='middle'
ctx.font='18px arial';
ctx.fillText('ADUR',150,175);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
[Update: We needed an image clipped inside the animated wedge]
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var nextTime=0;
var duration=1000;
var endingPct=75;
var pct=0;
var increment=duration/pct;
var cx=cw/2;
var cy=ch/2;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/mm.jpg";
function start(){
requestAnimationFrame(animate);
}
function animate(time){
draw(pct);
pct++;
if(pct<=endingPct){requestAnimationFrame(animate);}
}
function draw(pct){
//
var endRadians=-Math.PI/2+Math.PI*2*pct/100;
//
ctx.fillStyle='lightgray';
ctx.fillRect(0,0,cw,ch);
//
ctx.beginPath();
ctx.arc(cx,cy,100,-Math.PI/2,endRadians);
ctx.lineTo(cx,cy);
ctx.save();
ctx.clip();
ctx.drawImage(img,cx-img.width/2,cx-img.height/2);
ctx.restore();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>

Javascript canvas animated arc

I've been learning some javascript/canvas animation, I'm having trouble getting this animation to work correctly.
My goal is that the animation will start drawing at the top, then as it gets back to the top it will stop progressing and the start position will progress around the arc making it look as though it is erasing itself and once at the top (1.5 * PI) will starting drawing again.
Here is a fiddle: https://jsfiddle.net/kg1fmsjj/
Here is my code:
function f(element, colour, thickness, elapsedTime) {
// Create Element
element.innerHTML = '';
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
element.appendChild(canvas);
// Circle Params
context.lineWidth = thickness;
context.strokeStyle = colour;
var width = canvas.width;
var height = canvas.height;
var mathPi = Math.PI;
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 40;
var startAngle = 1.5 * mathPi;
var endAngle = 1.5 * mathPi;
context.lineWidth = thickness;
context.strokeStyle = colour;
var erasing = false;
function animate() {
if(erasing) {
startAngle = startAngle + 0.01 * mathPi;
} else {
endAngle = endAngle + 0.01 * mathPi;
}
if (endAngle > (1.5 * mathPi)) {
erasing = true;
}
if (startAngle > (1.5 * mathPi)) {
erasing = false;
}
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, false);
context.stroke();
context.closePath();
}
setInterval(animate, 10);
}
f(document.getElementById('out'), '#800080', 4, 60);
context.arc lets you optionally draw your arc counterclockwise.
This ability lets you create your desired effect:
To "draw" the arc, draw an increasing arc clockwise.
To "erase" the arc, draw a decreasing arc counterclockwise.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
ctx.lineWidth=2;
ctx.strokeStyle='#800080';
var PI=Math.PI;
var cx=cw/2;
var cy=ch/2;
var radius=cw/2-30;
var angle=0;
var direction=1;
requestAnimationFrame(animate);
function animate(time){
ctx.clearRect(0,0,cw,ch);
angle+=PI/120;
if(angle<0 || angle>PI*2){
angle=0;
direction*=-1;
}
draw();
requestAnimationFrame(animate);
}
function draw(){
var counterclockwise=(direction>0)?false:true;
var s=-Math.PI/2;
var e=angle-Math.PI/2;
ctx.beginPath();
ctx.arc(cx,cy,radius,s,e,counterclockwise);
ctx.stroke();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
You need to clear the canvas on each repaint using the clearRect() method.
You need to change the conditions when erasing variable is toggled. If erasing and startAngle >= endAngle then toggle erasing variable. If not erasing and endAngle >= startAngle + 2 * PI then toggle erasing variable.
The animate() method then become...
function animate() {
if(erasing) {
startAngle = startAngle + 0.01 * mathPi;
if (startAngle >= endAngle) {
erasing = false;
}
} else {
endAngle = endAngle + 0.01 * mathPi;
if (endAngle >= startAngle + 2.0 * mathPi) {
erasing = true;
}
}
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, false);
context.stroke();
}

'loading circle' through Canvas

Alright guys, I'm sure this has been asked before, but I couldn't find anything that directly related to what I was doing. So I have these 4 self drawing circles (or gauges.) Each one has it's own value, and I've been looking through just nit picking through codes and books to build this. My question I need to figure out is how I would go about putting in a count up? Basically I want a counter to go from 1 - x (x being the degree of the circle it's in). I've included my js and HTML 5 for you guys to look at.
HTML
<canvas id="a" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById('a');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.5 * Math.PI;
var endAngle = 3.2 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 15;
// line color
context.strokeStyle = 'black';
context.stroke();
</script>
Canvas.JS
$(document).ready(function(){
function animate(elementId, endPercent) {
var canvas = document.getElementById(elementId);
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var curPerc = 0;
var counterClockwise = false;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
context.lineWidth = 15;
context.strokeStyle = '#85c3b8';
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 10;
function render(current) {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
context.stroke();
curPerc++;
if (curPerc < endPercent) {
requestAnimationFrame(function () {
render(curPerc / 100);
});
}
}
render();
}
$(window).scroll(function(){
if($(this).scrollTop()<1600){
animate('a', 85);
animate('b', 95);
animate('c', 80);
animate('d', 75);
}
});
});
Keep in mind that I am very new to canvas, I appreciate all the help guys!
Demo: http://jsfiddle.net/m1erickson/mYKp5/
You can save your gauges as objects in an array:
var guages=[];
guages.push({ x:50, y:100, radius:40, start:0, end:70, color:"blue" });
guages.push({ x:200, y:100, radius:40, start:0, end:90, color:"green" });
guages.push({ x:50, y:225, radius:40, start:0, end:35, color:"gold" });
guages.push({ x:200, y:225, radius:40, start:0, end:55, color:"purple" });
The render function takes a guage object draws its progress
function render(guage,percent) {
var pct=percent/100;
var extent=parseInt((guage.end-guage.start)*pct);
var current=(guage.end-guage.start)/100*PI2*pct-quart;
ctx.beginPath();
ctx.arc(guage.x,guage.y,guage.radius,-quart,current);
ctx.strokeStyle=guage.color;
ctx.stroke();
ctx.fillStyle=guage.color;
ctx.fillText(extent,guage.x-15,guage.y+5);
}
And the animation loop asks render to draw all gauges from 0-100 percent of their full values
function animate() {
// if the animation is not 100% then request another frame
if(percent<100){
requestAnimationFrame(animate);
}
// redraw all guages with the current percent
drawAll(percent);
// increase percent for the next frame
percent+=1;
}
function drawAll(percent){
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw all the guages
for(var i=0;i<guages.length;i++){
render(guages[i],percent);
}
}

Adding alert to canvas faces

I'm currently trying to make so that when you click on one of the happy face you get an alert box which says "thanks for the feed back", but I'm currently not sure to to incoperate that in tho my code! Thanks! Here is the fiddle http://jsfiddle.net/bsjs9/
<html lang="en">
<head>
<meta charset="utf-8" />
<title>SmileMore</title>
</head>
<body>
<h1>
Bring your Charts to life with HTML5 Canvas</h1>
</hgroup>
<p>
Rendering Dynamic charts in JS
</p>
<div class="smile">
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE"></canvas>
<canvas id="canvas" width="200" height="200" style="border:1px solid #EEE"></canvas>
</div>
<script>
var FacePainter = function(canvasName)
{
var canvas = document.getElementById(canvasName);
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 0;
var endAngle = 2 * Math.PI;
function drawFace() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
}
function drawSmile(startAngle, endAngle)
{
var x = canvas.width / 2;
var y = 150;
var radius = 40;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle * Math.PI, endAngle * Math.PI);
ctx.lineWidth = 7;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawEyes() {
var centerX = 40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
//left eye
var centerX = -40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
this.drawHappyFace = function() {
drawFace();
drawEyes();
drawSmile(1.1, 1.9);
}
this.drawSadFace = function() {
drawFace();
drawEyes();
drawSmile(1.9, 1.1);
;
}
}
new FacePainter('canvas').drawHappyFace();
new FacePainter('myDrawing').drawSadFace();
</script>
</body>
</html>
</body>
</html>
As an extra assignment I would like to know if anyone knows how to fix the "happy" smile, its kinda way off! Thanks all!
Since you draw the happy face on its own canvas, you can simple put an onclick handler on the canvas.
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE" onclick="alert('thanks');"></canvas>
Regarding the smiles, I added a new ofsy parameter to drawSmile, which offsets the arc origin vertically.
Here is the updated fiddle.
If you only want to show the alert, when the user clicks inside the face, you need to get the click coordinates and hittest it against the circle. You can see this in this fiddle.

building a color wheel in html5

I am just learning some details about html5 canvas, and in the progress, I am trying to build a simple color wheel by wedges (build a 1 degree wedge at a time and add it up to 360 degree). However, I am getting some weird marks on the gradient as shown in the following image:
.
Here is the fiddle that produced the colorwheel: http://jsfiddle.net/53JBM/
In particular, this is the JS code:
var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 100;
var counterClockwise = false;
for(var angle=0; angle<=360; angle+=1){
var startAngle = (angle-1)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.closePath();
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
context.fill();
}
If anyone can point out what I am doing wrong or if there is a better way to accomplish what I am attempting to do it would be much appreciated :)
Is this enough to you, please check
var startAngle = (angle-2)*Math.PI/180;
Try this it looks great.
Thanks by the way this is exactly what I was trying to make.
var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 100;
var counterClockwise = false;
for(var angle=0; angle<=360; angle+=1){
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.closePath();
var gradient = context.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0,'hsl('+angle+', 10%, 100%)');
gradient.addColorStop(1,'hsl('+angle+', 100%, 50%)');
context.fillStyle = gradient;
context.fill();
}
<body>
<canvas id="picker"></canvas>
</body>
Similar approach, just for the color
var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 50;
var thickness = 0.6;
for(var angle=0; angle<=360; angle+=1){
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.arc(x, y, (1-thickness/2)*radius, startAngle, endAngle, false);
context.lineWidth = thickness*radius;
context.strokeStyle = 'hsl('+angle+', 100%, 50%)';
context.stroke();
}
<body>
<canvas id="picker"></canvas>
</body>
Edit: full project here: https://github.com/dersimn/jquery-colorwheel

Categories

Resources