Chart Label text rotation - html

I am using very similar code to create a pie chart using canvas as per this article:
http://wickedlysmart.com/how-to-make-a-pie-chart-with-html5s-canvas/
As you can see from this image, there are cases where the labels are upside down:
Here is the code that writes the labels to the graph:
var drawSegmentLabel = function(canvas, context, i) {
context.save();
var x = Math.floor(canvas.width / 2);
var y = Math.floor(canvas.height / 2);
var degrees = sumTo(data, i);
var angle = degreesToRadians(degrees);
context.translate(x, y);
context.rotate(angle);
context.textAlign = 'right';
var fontSize = Math.floor(canvas.height / 32);
context.font = fontSize + 'pt Helvetica';
var dx = Math.floor(canvas.width * 0.3) - 20;
var dy = Math.floor(canvas.height * 0.05);
context.fillText(labels[i], dx, dy);
context.restore();
};
I am trying to rectify this so the text is always readable and not upside down but cant work out how to do it!

Here's my solution! (A little kludgey but seems to work on the basic example, I haven't tested in on edge cases...)
var drawSegmentLabel = function(canvas, context, i) {
context.save();
var x = Math.floor(canvas.width / 2);
var y = Math.floor(canvas.height / 2);
var angle;
var angleD = sumTo(data, i);
var flip = (angleD < 90 || angleD > 270) ? false : true;
context.translate(x, y);
if (flip) {
angleD = angleD-180;
context.textAlign = "left";
angle = degreesToRadians(angleD);
context.rotate(angle);
context.translate(-(x + (canvas.width * 0.5))+15, -(canvas.height * 0.05)-10);
}
else {
context.textAlign = "right";
angle = degreesToRadians(angleD);
context.rotate(angle);
}
var fontSize = Math.floor(canvas.height / 25);
context.font = fontSize + "pt Helvetica";
var dx = Math.floor(canvas.width * 0.5) - 10;
var dy = Math.floor(canvas.height * 0.05);
context.fillText(labels[i], dx, dy);
context.restore();
};

To display the text in the correct way you have to check if the rotation angle is between 90 and 270 degree. If it is then you know the text will be display upside down.
To switch it correctly you then have to rotate you canvas of planed rotation - 180 degree and then to align it in left not right :
var drawSegmentLabel = function(canvas, context, i) {
context.save();
var x = Math.floor(canvas.width / 2);
var y = Math.floor(canvas.height / 2);
var degrees = sumTo(data, i);
var angle = 0;
if (degree > 90 && degree < 270)
angle = degreesToRadians(degrees - 180);
else
angle = degreesToRadians(degrees);
context.translate(x, y);
context.rotate(angle);
context.textAlign = 'right';
var fontSize = Math.floor(canvas.height / 32);
context.font = fontSize + 'pt Helvetica';
var dx = Math.floor(canvas.width * 0.3) - 20;
if (degree > 90 && degree < 270)
dx = 20;
var dy = Math.floor(canvas.height * 0.05);
context.fillText(labels[i], dx, dy);
context.restore();
};

Related

Draw Line Arrowhead Without Rotating in Canvas

Most code to drawing arrowheads in html canvas involves rotating the canvas context and drawing the lines.
My use case is to draw them using trigonometry without rotating the canvas. or is that vector algorithm you call it? Help is appreciated.
This is what I have (forgot where I got most of the code). Draws 2 arrowheads on start and end based on the last 2 parameters arrowStart and arrowEnd which are boolean.
drawLineArrowhead: function(context, arrowStart, arrowEnd) {
// Place start end points here.
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var distanceFromLine = 6;
var arrowLength = 9;
var dx = x2 - x1;
var dy = y2 - y1;
var angle = Math.atan2(dy, dx);
var length = Math.sqrt(dx * dx + dy * dy);
context.translate(x1, y1);
context.rotate(angle);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(length, 0);
if (arrowStart) {
context.moveTo(arrowLength, -distanceFromLine);
context.lineTo(0, 0);
context.lineTo(arrowLength, distanceFromLine);
}
if (arrowEnd) {
context.moveTo(length - arrowLength, -distanceFromLine);
context.lineTo(length, 0);
context.lineTo(length - arrowLength, distanceFromLine);
}
context.stroke();
context.setTransform(1, 0, 0, 1, 0, 0);
},
See the code below, just a bit of trigonometry.
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.lineCap = "round";
ctx.lineWidth = 5;
function drawLineArrowhead(p1, p2, startSize, endSize) {
ctx.beginPath()
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
if (startSize > 0) {
lineAngle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
delta = Math.PI/6
for (i=0; i<2; i++) {
ctx.moveTo(p1.x, p1.y);
x = p1.x + startSize * Math.cos(lineAngle + delta)
y = p1.y + startSize * Math.sin(lineAngle + delta)
ctx.lineTo(x, y);
delta *= -1
}
}
if (endSize > 0) {
lineAngle = Math.atan2(p1.y - p2.y, p1.x - p2.x);
delta = Math.PI/6
for (i=0; i<2; i++) {
ctx.moveTo(p2.x, p2.y);
x = p2.x + endSize * Math.cos(lineAngle + delta)
y = p2.y + endSize * Math.sin(lineAngle + delta)
ctx.lineTo(x, y);
delta *= -1
}
}
ctx.stroke();
}
drawLineArrowhead({x:10, y:10}, {x:100, y:20}, 0, 30)
drawLineArrowhead({x:20, y:25}, {x:140, y:120}, 20, 20)
drawLineArrowhead({x:140, y:20}, {x:80, y:50} , 20, 0)
drawLineArrowhead({x:150, y:20}, {x:150, y:90}, 20, 5)
drawLineArrowhead({x:180, y:90}, {x:180, y:20}, 20, 5)
drawLineArrowhead({x:200, y:10}, {x:200, y:140}, 10, 10)
drawLineArrowhead({x:220, y:140}, {x:220, y:10}, 10, 20)
<canvas id="canvas">
If you run it you should see a few samples.
The drawLineArrowhead has 4 parameters (p1, p2, startSize, endSize)
the first two are the starting-point and end-point of the line, the last two are arrow size, just to give some control to the final user over how big are those arrows at the end, if we want to remove them we set to 0.

Setting a correct angular velocity to a canvas object

I am building a space shooter game and would like the ship to fire rockets at the direction of the cursor. Therefore, I grab the radian value of the angle it should fire at, multiply it by the ship's speed and set it's x and y velocities respectively.
I have this as a Bullet class:
function Bullet(x, y) {
this.x = x;
this.y = y;
this.rotation = 0;
this.width = 6;
this.height = 3;
this.color = utils.getRandomColor();
this.speed = 80;
}
And here is the function which updates the movement of all instances of the bullet class:
function drawBullet(bullet) {
var dx = mouse.x - bullet.x,
dy = mouse.y - bullet.y,
angle = Math.atan2(dy, dx);
bullet.vx = Math.cos(angle) * bullet.speed;
bullet.vy = Math.sin(angle) * bullet.speed;
bullet.x += bullet.vx;
bullet.y += bullet.vy;
bullet.draw(ctx);
}
It starts okay, going in the right direction and velocity and stuff. But as soon as it reaches the mouse, it stops dead there and starts flickering. NOW, I realise that this is because of the way I am getting the angle, using the mouse position as a value - the problem is that I can't figure out a way to use just the angle for the velocity, not the distance to the mouse position. So it doesn't slow down.
All suggestions are welcome, thanks in advance!
If you don't need homing missile type behavior just pass the mouse coordinates when you create the bullet.
Example:
new Bullet(shooterX, shooterY, mouseX, mouseY)
I included an over engineered stack snippet but the relevant part is below.
var Bullet = function(x,y,tx,ty){
this.speed = 15;
this.x = x;
this.y = y;
var radians = Math.atan2(ty-y, tx-x);
// we now have our velX and velY we can just refer to
this.velX = Math.cos(radians) * this.speed;
this.velY = Math.sin(radians) * this.speed;
}
Bullet.prototype.update = function(){
// just update by our previous calculated velX and velY.
this.x += this.velX;
this.y += this.velY;
};
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 250,
height = 250,
output = document.getElementById("radians"),
output2 = document.getElementById("degrees"),
cX = 0,
cY = 0,
mX = 0,
mY = 0,
bullets = [];
canvas.width = width;
canvas.height = height;
canvas.addEventListener("mousemove", function (e) {
mX = e.pageX;
mY = e.pageY;
});
var Ball = function (x, y, radius, color) {
this.x = x || 0;
this.y = y || 0;
this.radius = radius || 10;
// makes our x and y the center of the circle.
this.x = (this.x-this.radius/2);
this.y = (this.y-this.radius/2);
// how far out do we want the point
this.pointLength = 50;
this.px = 0;
this.py = 0;
this.color = color || "rgb(255,0,0)";
}
Ball.prototype.shoot = function(tx, ty){
bullets.push(new Bullet(this.x, this.y, tx, ty));
}
Ball.prototype.update = function (x, y) {
// get the target x and y
this.targetX = x;
this.targetY = y;
var x = this.x - this.targetX,
y = this.y - this.targetY,
radians = Math.atan2(y,x);
this.px = this.x - this.pointLength * Math.cos(radians);
this.py = this.y - this.pointLength * Math.sin(radians);
// -y will make 0 the top, y will 0 us at the bottom.
output.textContent = radians;
output2.textContent = radians/Math.PI * 180
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.strokeStyle = "rgb(0,0,255)";
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.px, this.py);
ctx.closePath();
ctx.stroke();
};
var Bullet = function(x,y,tx,ty){
this.speed = 15;
this.x = x;
this.y = y;
var radians = Math.atan2(ty-y, tx-x);
this.velX = Math.cos(radians) * this.speed;
this.velY = Math.sin(radians) * this.speed;
}
Bullet.prototype.update = function(){
this.x += this.velX;
this.y += this.velY;
};
Bullet.prototype.render = function(){
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
};
var ball1 = new Ball(width/2, height/2, 10);
canvas.addEventListener("click", function (e) {
ball1.shoot(e.pageX, e.pageY);
});
function render() {
ctx.clearRect(0, 0, width, height);
ball1.update(mX, mY);
ball1.render();
bullets.forEach(function(b){
b.update();
b.render();
});
requestAnimationFrame(render);
}
render();
ol{list-style:none;}
<canvas id="canvas"></canvas>
<div>
<ol>
<li>
<span>Radians : </span><span id="radians"></span>
</li>
<li>
<span>Degrees : </span><span id="degrees"></span>
</li>
</ol>
</div>
Add a new property on bullet that stores the angle of motion, initialize it to -1. Then, on the very first drawBullet call, check if it has been initialized first. If not, set the angle...
function Bullet(x, y) {
this.x = x;
this.y = y;
this.rotation = 0;
this.width = 6;
this.height = 3;
this.color = utils.getRandomColor();
this.speed = 80;
this.angle = -1; // New, angle property initialized to -1
}
function drawBullet(bullet) {
if (bullet.angle === -1) { // Only pull the mouse cursor and get an angle
var dx = mouse.x - bullet.x, // If it hasn't already done so.
dy = mouse.y - bullet.y,
angle = Math.atan2(dy, dx);
bullet.angle = angle;
}
bullet.vx = Math.cos(bullet.angle) * bullet.speed; // Re-use the angle value.
bullet.vy = Math.sin(bullet.angle) * bullet.speed;
bullet.x += bullet.vx;
bullet.y += bullet.vy;
bullet.draw(ctx);
}

drawing a smooth line on html5 canvas for mobile app using jquery mobile

I am trying to draw on canvas, like drawing using pencil tool in the paint using jquery mobile.
I searched for many links and most of them were for the desktop, i tried to implement the same logic for the mobile app, i am able to obtain only the click events but not able to draw the line on the canvas.
This is what i was trying to implement on the mobile http://jsfiddle.net/loktar/dQppK/23/
This is my code
$(document).on(
'pageshow',
'#canvaspage',
function() {
var painting = false;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// ctx.fillStyle="#FF0000";
// ctx.fillRect(0,0,150,75);
// ctx.drawImage(icons-18-black.png)
ctx.canvas.width = window.innerWidth * 0.8;
ctx.canvas.height = window.innerHeight * 0.8;
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(imageObj, 0, 0, ctx.canvas.width * 0.8,
ctx.canvas.height * 0.7);
};
imageObj.src = 'Image.png';
// c.addEventListener('touchstart', function(e) {
$("#myCanvas").on("touchstart",function(e){
painting = true;
e.preventDefault();
ctx.fillStyle = "#FF0000";
lastX = e.pageX - this.offsetLeft;
lastY = e.pageY - this.offsetTop;
});
// c.addEventListener('touchend', function(e) {
$("#myCanvas").on("touchend",function(e){
painting = false;
});
// c.addEventListener('touchmove', function(e) {
$("#myCanvas").on("touchmove",function(e){
if (painting) {
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
// find all points between
var x1 = mouseX,
x2 = lastX,
y1 = mouseY,
y2 = lastY;
var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
if (steep){
var x = x1;
x1 = y1;
y1 = x;
var y = y2;
y2 = x2;
x2 = y;
}
if (x1 > x2) {
var x = x1;
x1 = x2;
x2 = x;
var y = y1;
y1 = y2;
y2 = y;
}
var dx = x2 - x1,
dy = Math.abs(y2 - y1),
error = 0,
de = dy / dx,
yStep = -1,
y = y1;
if (y1 < y2) {
yStep = 1;
}
lineThickness = 5 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10;
if(lineThickness < 1){
lineThickness = 1;
}
alert(painting +" " +x1 +" "+x2);
for (var x = x1; x < x2; x++) {
// alert(x +" "+ y +" "+ lineThickness);
if (steep) {
ctx.fillRect(y, x, lineThickness , lineThickness );
} else {
ctx.fillRect(x, y, lineThickness , lineThickness );
}
alert(steep);
error += de;
if (error >= 0.5) {
y += yStep;
error -= 1.0;
}
}
lastX = mouseX;
lastY = mouseY;
}
// ctx.fillRect(0, 0, 150, 75);
e.preventDefault();
}, false);
});
In the above code i am able to obtain all the touch events but the unable to draw the line.
How can i draw the lines on the canvas??..
Thanks:)
You can use sketch.js (http://intridea.github.io/sketch.js/) with a small modification to make it work on mobile. The modification is given in the comment by leonth here: https://github.com/intridea/sketch.js/issues/1; you basically add 3 lines to the plugin on the mousedown/touchstart event:
switch (e.type) {
case 'mousedown':
case 'touchstart':
if (this.painting) { //add
this.stopPainting(); //add
} //add
this.startPainting();
break;
...
Here is a DEMO FIDDLE, try it from mobile device.

How to draw a series of arc segments across line segments

I'm trying to draw a 'countdown' circle that will produce a visual clock, but don't like the resulting shape as it is not smooth. The code below draws and fills a series of triangles that approximate a circle when the variable 'numberOfSides' is sufficiently large, but this is both inefficient and produces an ugly 'circle.' What I would like to do is draw a series of arcs across the line segments but I don't know how to do it. Can anyone give me a prod in the right direction?
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600" frameRate="100" creationComplete="init()">
<mx:Script>
<![CDATA[
private var numberOfSides:int = 10;
private var angle:Number = 0;
private var lineLength:int = 100;
private var xStartingPos:int = 300;
private var yStartingPos:int = 300;
private var i:int = 90;//Start the drawing at 0 to 360;
private var speed:int = 100;
private var timer:Timer
private function init():void{
//uic.graphics.lineStyle(1);
uic.graphics.moveTo(xStartingPos,yStartingPos);
uic.graphics.beginFill(0xffff00);
timer = new Timer(speed, numberOfSides + 1);
timer.addEventListener(TimerEvent.TIMER,cont);
timer.start()
}
private function cont(event:TimerEvent):void{
angle = (Math.PI / numberOfSides * 2) * i;
var xAngle:Number = Math.sin(angle);
var yAngle:Number = Math.cos(angle);
var xResult:int = xAngle * lineLength;
var yResult:int = yAngle * lineLength;
uic.graphics.lineTo(xStartingPos + xResult, yStartingPos + (yResult*-1));
i++
}
]]>
</mx:Script>
<mx:Canvas id="uic"/>
</mx:Application>
This could be accomplished by drawing wedges using nl.funkymonkey.drawing.DrawingShapes:
Draw Wedge function:
public static function drawWedge(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number=0, yRadius:Number=0):void
{
if (yRadius == 0)
yRadius = radius;
target.moveTo(x, y);
var segAngle:Number, theta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
if (Math.abs(arc) > 360)
arc = 360;
segs = Math.ceil(Math.abs(arc) / 45);
segAngle = arc / segs;
theta = -(segAngle / 180) * Math.PI;
angle = -(startAngle / 180) * Math.PI;
if (segs > 0)
{
ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
ay = y + Math.sin(-startAngle / 180 * Math.PI) * yRadius;
target.lineTo(ax, ay);
for (var i:int = 0; i < segs; ++i)
{
angle += theta;
angleMid = angle - (theta / 2);
bx = x + Math.cos(angle) * radius;
by = y + Math.sin(angle) * yRadius;
cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
target.curveTo(cx, cy, bx, by);
}
target.lineTo(x, y);
}
}
Example implementation, animating countdown timer:
var value:Number = 0;
addEventListener(Event.ENTER_FRAME, frameHandler);
function frameHandler(event:Event):void
{
var g:Graphics = graphics;
g.clear();
value += 0.01;
g.lineStyle(1, 0x0000ff, 0.25);
g.beginFill(0x123456, 0.25);
drawWedge(g, 100, 100, 50, (360 * value) % 360);
g.endFill();
}
Any graphics line style or fill may be used; or, the fill could be used as a mask.
An other piece of code I found online:
http://flassari.is/2009/11/pie-mask-in-as3/
Changed this into:
var circleToMask:Sprite = new Sprite();
circleToMask.graphics.beginFill(0x004BA5DC); // color circle 0x00RRGGBB
circleToMask.graphics.drawCircle(0, 0, 50);
circleToMask.graphics.endFill();
addChildAt(circleToMask, 0);
var circleMask:Sprite = new Sprite();
circleToMask.x = (circleMask.x = 50);
circleToMask.y = (circleMask.y = 50);
circleToMask.mask = circleMask;
addChild(circleMask);
// inner circle
var circleTopMask:Sprite = new Sprite();
circleTopMask.graphics.beginFill(0x00FFFFFF); // color inner circle
circleTopMask.graphics.drawCircle(0, 0, 25);
circleTopMask.graphics.endFill();
addChild(circleTopMask);
circleTopMask.x = 50;
circleTopMask.y = 50;
// textfield in the center
var myFormat:TextFormat = new TextFormat();
myFormat.size = 18;
var myText:TextField = new TextField();
myText.defaultTextFormat = myFormat;
myText.text = "0%";
myText.autoSize = TextFieldAutoSize.CENTER;
myText.y = 50 - (myText.height/2);
addChild(myText);
var percentage:Number = 0;
var tper:Number = 0;
addEventListener(Event.ENTER_FRAME, function (_arg1:Event):void{
graphics.clear();
// Percentage should be between 0 and 1
tper = percentage < 0 ? 0 : (percentage > 1 ? 1 : percentage);
// Draw the masked circle
circleMask.graphics.clear();
circleMask.graphics.beginFill(0);
drawPieMask(circleMask.graphics, tper, 50, 0, 0, (-(Math.PI) / 2), 3);
circleMask.graphics.endFill();
// Increase percentage with margins so it appears to stop for a short while
percentage = (percentage + 0.01);
if (percentage > 1){
percentage = 0;
}
myText.text = ((percentage*100).toFixed(0))+"%";
})
function drawPieMask(graphics:Graphics, percentage:Number, radius:Number = 50, x:Number = 0, y:Number = 0, rotation:Number = 0, sides:int = 6):void {
// graphics should have its beginFill function already called by now
graphics.moveTo(x, y);
if (sides < 3) sides = 3; // 3 sides minimum
// Increase the length of the radius to cover the whole target
radius /= Math.cos(1/sides * Math.PI);
// Shortcut function
var lineToRadians:Function = function(rads:Number):void {
graphics.lineTo(Math.cos(rads) * radius + x, Math.sin(rads) * radius + y);
};
// Find how many sides we have to draw
var sidesToDraw:int = Math.floor(percentage * sides);
for (var i:int = 0; i <= sidesToDraw; i++)
lineToRadians((i / sides) * (Math.PI * 2) + rotation);
// Draw the last fractioned side
if (percentage * sides != sidesToDraw)
lineToRadians(percentage * (Math.PI * 2) + rotation);
}
The size of the resuling FLA should be 100 x 100 px.
Resulting in:

canvas.onmousedown function to add a shape won't work

I have some code, which can be seen below. At the bottom is a block of code to add a shape. For some reason it won't work unless the very first lines of code are different. Up until I added the 'addShape' code, it was all working fine, so I wandered if anyone on here could have a look and perhaps figure out a solution?
Cheers
Jon
EDIT Also available on jsFiddle http://jsfiddle.net/pukster/mfNq4/1/
$(document).ready(function() {
var canvas = $('#myCanvas');
var ctx = canvas.get(0).getContext("2d");
var context = new webkitAudioContext();
var canvasWidth = canvas.width();
var canvasHeight = canvas.height();
$(window).resize(resizeCanvas);
function resizeCanvas() {
canvas.attr("width", $(window).get(0).innerWidth - 2);
canvas.attr("height", $(window).get(0).innerHeight - 2);
canvasWidth = canvas.width();
canvasHeight = canvas.height();
};
resizeCanvas();
ctx.strokeStyle = "rgb(255, 0, 0)";
ctx.lineWidth = 2;
var playAnimation = true;
var Ring = function(x, y, radius, vx, vy) {
this.x = x;
this.y = y;
this.radius = radius;
this.vx = vx;
this.vy = vy;
};
var rings = [];
for (var i = 0; i < 10; i++) {
var x = Math.random()*ctx.canvas.width;
var y = Math.random()*ctx.canvas.height;
var vx = Math.random()*6-3;
var vy = Math.random()*6-3;
rings.push(new Ring(x, y, 40, vx, vy));
};
function animate() {
var ringsLength = rings.length;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for (var i = 0; i < ringsLength; i++) {
var tmpRing = rings[i];
for (var j = i+1; j < ringsLength; j++) {
var tmpRingB = rings[j];
var dx = tmpRingB.x - tmpRing.x;
var dy = tmpRingB.y - tmpRing.y;
var dist = Math.sqrt((dx * dx) + (dy * dy));
if(dist < tmpRing.radius + tmpRingB.radius) {
var sinewave = new SineWave(context);
var angle = Math.atan2(dy, dx);
var sine = Math.sin(angle);
var cosine = Math.cos(angle);
var x = 0;
var y = 0;
var xb = dx * cosine + dy * sine;
var yb = dy * cosine - dx * sine;
var vx = tmpRing.vx * cosine + tmpRing.vy * sine;
var vy = tmpRing.vy * cosine - tmpRing.vx * sine;
var vxb = tmpRingB.vx * cosine + tmpRingB.vy * sine;
var vyb = tmpRingB.vy * cosine - tmpRingB.vx * sine;
vx *= -1;
vxb *= -1;
xb = x + (tmpRing.radius + tmpRingB.radius);
tmpRing.x = tmpRing.x + (x * cosine - y * sine);
tmpRing.y = tmpRing.y + (y * cosine + x * sine);
tmpRingB.x = tmpRing.x + (xb * cosine - yb * sine);
tmpRingB.y = tmpRing.y + (yb * cosine + xb * sine);
tmpRing.vx = vx * cosine - vy * sine;
tmpRing.vy = vy * cosine + vx * sine;
tmpRingB.vx = vxb * cosine - vyb * sine;
tmpRingB.vy = vyb * cosine + vxb * sine;
tmpRing.loop = true;
};
};
tmpRing.x += tmpRing.vx;
tmpRing.y += tmpRing.vy;
if (tmpRing.x - tmpRing.radius < 0) {
var sinwave = new SinWave(context);
tmpRing.x = tmpRing.radius;
tmpRing.vx *= -1;
} else if (tmpRing.x + tmpRing.radius > ctx.canvas.width) {
var sinwave = new SinWave(context);
tmpRing.x = ctx.canvas.width - tmpRing.radius;
tmpRing.vx *= -1;
};
if (tmpRing.y - tmpRing.radius < 0) {
var sinwave = new SinWave(context);
tmpRing.y = tmpRing.radius;
tmpRing.vy *= -1;
} else if (tmpRing.y + tmpRing.radius > ctx.canvas.height) {
var sinwave = new SinWave(context);
tmpRing.y = ctx.canvas.height - tmpRing.radius;
tmpRing.vy *= -1;
};
ctx.beginPath();
ctx.arc(tmpRing.x, tmpRing.y, 40, 0, Math.PI*2, false);
ctx.closePath();
ctx.stroke();
//-------------------- The addRing Function Code --------------------//
var mx, my;
var offsetX, offsetY;
//canvas.onmousedown = sglClick;
function addRing(x, y, radius, vx, vy) {
var x = mx-5;
var y = my-5;
var vx = Math.random()*6-3;
var vy = Math.random()*6-3;
rings.push(new Ring(x, y, 40, vx, vy));
}
function sglClick(e) {
getMouse(e);
addRing();
}
function getMouse(e) {
var element = ctx, offsetX = 0, offsetY = 0;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
}
};
if(playAnimation) {
setTimeout(animate, 33);
};
};
animate();
});
I noticed a couple of problems.
First, you misspelled SineWave in a few places. Second, you are trying to bind an event to the canvas using canvas.onmousedown = sglClick;. You should try canvas.bind('mousedown', sglClick); instead and you shouldn't do the binding inside of your animate method. It will add a new event each iteration of the animation.