JavaScript drawing lissajous curve looks like complete mess - javascript

I am trying to draw lissajous curves using the canvas and javascript. I have put the formula's in but instead of drawing nice curves, the canvas looks like a complete mess. The code im currently using is:
<canvas id="myCanvas" width="720" height="720" style="border:1px solid #d3d3d3;">
<script src="canvas.js"> </script>
And for my javascript:
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctxt = canvas.getContext('2d');
var x;
var y;
var STARTi = 0;
var MAXi = 100;
var yOffset = canvas.height / 2;
var xOffset = canvas.width / 2;
var xAmp = 2;
var yAmp = 3;
var xFreq = 6;
var yFreq = 3;
var phaseDiff = Math.PI / 2;
//X-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(0, canvas.height / 2);
ctxt.lineTo(canvas.width, canvas.height / 2);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
//y-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(canvas.width / 2, 0);
ctxt.lineTo(canvas.width / 2, canvas.height);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
ctxt.setLineDash([0, 0]);
function xCoord(a) {
return 100 * (xAmp * Math.sin(xFreq * (0.4 * a) + phaseDiff));
}
function yCoord(a) {
return -100 * (yAmp * Math.sin(yFreq * (0.4 * a)));
}
x = xCoord(STARTi);
y = yCoord(x);
ctxt.beginPath();
ctxt.moveTo(x + xOffset, y + yOffset)
for (i = STARTi; i < MAXi; i++) {
ctxt.moveTo(x + xOffset, y + yOffset)
x = xCoord(i);
y = yCoord(x);
ctxt.lineTo(x + xOffset, y + yOffset)
ctxt.strokeStyle = "black"
ctxt.stroke();
}
Im trying to get these curved and i have tried things such as making the increase of the value so small that it will eventually look smooth: didn't work, just crashed my browser eventually.
I also tried to draw these lines using the Arc property. This gave me some smooth lines, but not ones that looked like lisajous curves. I believe this mainly is because i did not know what values or variables in needed to put in for the other required parameters.
I hope it is a little bit clear what i have problems with.
Thanks in advance for all the help. ;)

All angle operations in JavaScript uses radians [0, 2 × π>, but the xCoord() and yCoord() functions uses degrees [0, 360>.
Simple use radians instead or convert inside the functions:
function xCoord(a) {
// "a" converted from degree to radian _________________
return 100 * (xAmp * Math.sin(xFreq * (0.4 * a * Math.PI / 180) + phaseDiff));
}
function yCoord(a) {
return -100 * (yAmp * Math.sin(yFreq * (0.4 * a * Math.PI / 180)));
}
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctxt = canvas.getContext('2d');
var x;
var y;
var STARTi = 0;
var MAXi = 100;
var yOffset = canvas.height / 2;
var xOffset = canvas.width / 2;
var xAmp = 2;
var yAmp = 3;
var xFreq = 6;
var yFreq = 3;
var phaseDiff = Math.PI / 2;
//X-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(0, canvas.height / 2);
ctxt.lineTo(canvas.width, canvas.height / 2);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
//y-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(canvas.width / 2, 0);
ctxt.lineTo(canvas.width / 2, canvas.height);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
ctxt.setLineDash([0, 0]);
function xCoord(a) {
return 100 * (xAmp * Math.sin(xFreq * (0.4 * a * Math.PI / 180) + phaseDiff));
}
function yCoord(a) {
return -100 * (yAmp * Math.sin(yFreq * (0.4 * a * Math.PI / 180)));
}
x = xCoord(STARTi);
y = yCoord(x);
ctxt.beginPath();
ctxt.moveTo(x + xOffset, y + yOffset)
for (i = STARTi; i < MAXi; i++) {
ctxt.moveTo(x + xOffset, y + yOffset)
x = xCoord(i);
y = yCoord(x);
ctxt.lineTo(x + xOffset, y + yOffset)
}
ctxt.strokeStyle = "black"; // can be set right before stroked.
ctxt.stroke(); // call this outside the loop, otherwise the lines will
// overdraw eachother per iteration making it look pixelated
<canvas id="myCanvas" width="720" height="720" style="border:1px solid #d3d3d3;">

I also found an error in the argument for the ordinate Y. I believe this would be correct:
x = xCoord(i);
y = yCoord(i); // NO y = yCoord(x);
Similarly, the above
x = xCoord(STARTi);
y = yCoord(STARTi);

Related

How to generate and animate a hexagonal sine wave in javascript after drawing a hexagon in HTML canvas?

After having tried sine and cosine wave animations, I am facing issues while animating a hexagonal wave with rotating radius. I am unable to get the diagonal wave lines to be straight in the wave. They come out slightly curled.
var hexStep = 0;
var hexID;
function drawAxes(context) {
var width = context.canvas.width;
var height = context.canvas.height;
context.beginPath();
context.strokeStyle = "rgb(128,128,128)";
context.lineWidth = 1;
// X-axis
context.moveTo(0, height / 2);
context.lineTo(width, height / 2);
// Sine Wave starting wall
context.moveTo(width / 4, 0);
context.lineTo(width / 4, height);
// Sine Wave Y-axis
context.moveTo((2.5 * width) / 4, 0);
context.lineTo((2.5 * width) / 4, height);
// Shape Y-axis
context.moveTo(width / 8, 0);
context.lineTo(width / 8, height);
context.stroke();
}
// Hexagon
function drawHexagon(context, x, y, r, side) {
var width = context.canvas.width;
var height = context.canvas.height;
var angle = (2 * Math.PI) / side;
context.beginPath();
context.strokeStyle = "midnightblue";
context.lineWidth = 2;
context.moveTo(x + r, y);
var hx = 0;
var hy = 0;
for (var i = 1; i <= side; i++) {
hx = x + r * Math.cos(angle * i);
hy = y + r * Math.sin(angle * i);
context.lineTo(hx, hy);
}
context.stroke();
}
function getHexagonalWave(context, x, y, r, side, step, freq) {
var width = context.canvas.width;
var height = context.canvas.height;
var angle = (2 * Math.PI) / side;
var inr = r * Math.sqrt(0.75);
context.beginPath();
context.strokeStyle = "midnightblue";
context.lineWidth = 2;
context.moveTo(x, y);
var sf = step / freq;
var hr = inr / Math.cos(((sf + angle / 2) % angle) - angle / 2);
var hx = x + hr * Math.sin(sf);
var hy = y - hr * Math.cos(sf);
context.lineTo(hx, hy);
var wx = width / 4;
context.moveTo(hx, hy);
context.lineTo(wx, hy);
context.moveTo(wx, hy);
var hvr = 0;
var wvx = 0;
var wvy = 0;
var id = 0;
for (var i = 0; i < width; i++) {
hvr = inr / Math.cos((((i + step) / freq + angle / 2) % angle) - angle / 2);
wvy = y - hvr * Math.cos((i + step) / freq);
wvx = wx + hvr * Math.sin((i + step) / freq);
context.lineTo(wx + i, wvy);
}
context.stroke();
}
function doGenerateHexagonalWave() {
var canvas = document.getElementById("canvas3");
var context = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var x = width / 8;
var y = height / 2;
var r = (1.5 * height) / 4;
var side = 6;
var freq = 60;
context.clearRect(0, 0, width, height); // Check
drawAxes(context);
drawHexagon(context, x, y, r, side);
getHexagonalWave(context, x, y, r, side, hexStep, freq);
hexStep++;
hexID = window.requestAnimationFrame(doGenerateHexagonalWave);
}
function doStopHexagonalWave() {
window.cancelAnimationFrame(hexID);
}
function doClearHexagonalWave() {
window.cancelAnimationFrame(hexID);
var canvas = document.getElementById("canvas3");
var context = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
context.clearRect(0, 0, width, height);
}
body {
background-color:darkgray;
margin-left: 10px;
}
h1 {
margin: 5px;
}
hr {
border: 1px solid;
}
canvas {
margin: 5px;
margin-bottom: -8px;
background-color:lightgrey;
/*
width: 500px;
height: 100px;
*/
}
p {
margin-left: 5px;
}
<h1>Hexagonal Wave</h1>
<hr>
<div>
</p>
<canvas id="canvas3" width="800" height="200">
</canvas>
<p>
<input type="button" value="Generate" onclick="doGenerateHexagonalWave()"/>
<input type="button" value="Stop" onclick="doStopHexagonalWave()" />
<input type="button" value="Clear" onclick="doClearHexagonalWave()" />
</p>
</div>
How do I get the angles to form straight edges between vertices in the wave by using the variable 'wvx' in the for loop ? Can't seem to figure it out!

html canvas check that object is in angle

I have a circle, and a object.
I want to draw a circle segment with specified spread, and next check that the object is in defined angle, if it is, angle color will be red, otherwise green. But my code does not work in some cases...
in this case it work:
in this too:
but here it isn't:
I know that my angle detection code part is not perfect, but I have no idea what I can do.
This is my code:
html:
<html>
<head></head>
<body>
<canvas id="c" width="800" height="480" style="background-color: #DDD"></canvas>
<script src="script.js"></script>
</body>
</html>
js:
window.addEventListener('mousemove', updateMousePos, false);
var canvas = document.getElementById("c");
var context = canvas.getContext("2d");
//mouse coordinates
var mx = 0, my = 0;
draw();
function draw()
{
context.clearRect(0, 0, canvas.width, canvas.height);
//object coordinates
var ox = 350, oy = 260;
context.beginPath();
context.arc(ox,oy,5,0,2*Math.PI);
context.fill();
//circle
var cx = 400, cy = 280;
var r = 100;
var segmentPoints = 20;
var circlePoints = 40;
var spread = Math.PI / 2;
var mouseAngle = Math.atan2(my - cy, mx - cx); //get angle between circle center and mouse position
context.beginPath();
context.strokeStyle = "blue";
context.moveTo(cx + r, cy);
for(var i=0; i<circlePoints; i++)
{
var a = 2 * Math.PI / (circlePoints - 1) * i;
var x = cx + Math.cos(a) * r;
var y = cy + Math.sin(a) * r;
context.lineTo(x, y);
}
context.lineTo(cx + r, cy);
context.stroke();
var objAngle = Math.atan2(oy - cy, ox - cx);
var lowerBorder = mouseAngle - spread / 2;
var biggerBorder = mouseAngle + spread / 2;
/////////////////////////////////////////////ANGLES DETECTION PART
if(objAngle >= lowerBorder && objAngle <= biggerBorder ||
objAngle <= biggerBorder && objAngle >= lowerBorder)
{
context.strokeStyle = "red";
}
else
context.strokeStyle = "green";
context.lineWidth = 3;
//angle center line
context.beginPath();
context.moveTo(cx, cy);
context.lineTo(cx + Math.cos(mouseAngle) * r * 2, cy + Math.sin(mouseAngle) * r * 2);
context.stroke();
//draw spread arc
context.beginPath();
context.moveTo(cx, cy);
for(var i=0; i<segmentPoints; i++)
{
var a = mouseAngle - spread / 2 + spread / (segmentPoints - 1) * i;
var x = cx + Math.cos(a) * r;
var y = cy + Math.sin(a) * r;
context.lineTo(x, y);
}
context.lineTo(cx, cy);
context.stroke();
//show degrees
context.font = "20px Arial";
context.fillText((lowerBorder * 180 / Math.PI).toFixed(2), Math.cos(lowerBorder) * r + cx, Math.sin(lowerBorder) * r + cy);
context.fillText((biggerBorder * 180 / Math.PI).toFixed(2), Math.cos(biggerBorder) * r + cx, Math.sin(biggerBorder) * r + cy);
context.fillText((mouseAngle * 180 / Math.PI).toFixed(2), Math.cos(mouseAngle) * r + cx, Math.sin(mouseAngle) * r + cy);
//update
setTimeout(function() { draw(); }, 10);
}
//getting mouse coordinates
function updateMousePos(evt)
{
var rect = document.getElementById("c").getBoundingClientRect();
mx = evt.clientX - rect.left;
my = evt.clientY - rect.top;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// Rotation here is being measured in Radians
// Given two 2D vectors A & B, the angle between them can be drawn from this formula
// A dot B = length(a) * length(b) * cos(angle)
// if the vectors are normalized (the length is 1) the formula becomes
// A dot B = cos(angle)
// angle = acos(a.x * b.x + a.y * b.y)
// So here you are concerned with the direction of the two vectors
// One will be the vector facing outward from the middle of your arc segment
// The other will be a directional vector from the point you want to do collision with to the center
// of the circle
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var bounds = {top: 0.0, left: 0.0};
var circle = {
x: (canvasWidth * 0.5)|0,
y: (canvasHeight * 0.5)|0,
radius: 50.0,
rotation: 0.0, // In Radians
arcSize: 1.0
};
var point = {
x: 0.0,
y: 0.0
};
window.onmousemove = function(e) {
point.x = e.clientX - bounds.left;
point.y = e.clientY - bounds.top;
}
// runs after the page has loaded
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
bounds = canvas.getBoundingClientRect();
ctx = canvas.getContext("2d");
loop();
}
function loop() {
// Update Circle Rotation
circle.rotation = circle.rotation + 0.025;
if (circle.rotation > 2*Math.PI) {
circle.rotation = 0.0;
}
// Vector A (Point Pos -> Circle Pos)
var aX = circle.x - point.x;
var aY = circle.y - point.y;
var aLength = Math.sqrt(aX * aX + aY * aY);
// Vector B (The direction the middle of the arc is facing away from the circle)
var bX = Math.sin(circle.rotation);
var bY =-Math.cos(circle.rotation); // -1 is facing upward, not +1
var bLength = 1.0;
// Normalize vector A
aX = aX / aLength;
aY = aY / aLength;
// Are we inside the arc segment?
var isInsideRadius = aLength < circle.radius;
var isInsideAngle = Math.abs(Math.acos(aX * bX + aY * bY)) < circle.arcSize * 0.5;
var isInsideArc = isInsideRadius && isInsideAngle;
// Clear the screen
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
// Draw the arc
ctx.strokeStyle = isInsideArc ? "green" : "black";
ctx.beginPath();
ctx.moveTo(circle.x,circle.y);
ctx.arc(
circle.x,
circle.y,
circle.radius,
circle.rotation - circle.arcSize * 0.5 + Math.PI * 0.5,
circle.rotation + circle.arcSize * 0.5 + Math.PI * 0.5,
false
);
ctx.lineTo(circle.x,circle.y);
ctx.stroke();
// Draw the point
ctx.strokeStyle = "black";
ctx.fillStyle = "darkred";
ctx.beginPath();
ctx.arc(
point.x,
point.y,
5.0,
0.0,
2*Math.PI,
false
);
ctx.fill();
ctx.stroke();
// This is better to use then setTimeout()
// It automatically syncs the loop to 60 fps for you
requestAnimationFrame(loop);
}
</script>
</body>
</html>

My applet is not drawing a lisajouss figure but a sine function

I am trying to draw a lisajouss figure but instead my program is just drawing a single sine function, why?
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctxt = canvas.getContext('2d');
var x;
var y;
var STARTi = -1000;
var MAXi = 1000;
var yOffset = canvas.height / 2;
var xOffset = canvas.width / 2;
var xAmp = 2;
var yAmp = 3;
var xFreq = 6;
var yFreq = 4;
var phaseDiff = (Math.PI / 2);
//X-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(0, canvas.height / 2);
ctxt.lineTo(canvas.width, canvas.height / 2);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
//y-Axis
ctxt.beginPath();
ctxt.setLineDash([5, 15]);
ctxt.moveTo(canvas.width / 2, 0);
ctxt.lineTo(canvas.width / 2, canvas.height);
ctxt.strokeStyle = "rgba(169,169,169)"
ctxt.stroke();
ctxt.setLineDash([0, 0]);
function xCoord(a) {
return 100 * (xAmp * Math.sin(xFreq * (0.3 * a * Math.PI / 180)));
}
function yCoord(a) {
return 100 * (yAmp * Math.sin(yFreq * (0.3 * a * Math.PI / 180)));
}
x = xCoord(STARTi);
y = yCoord(x);
ctxt.beginPath();
ctxt.moveTo(x + xOffset, y + yOffset)
for (i = STARTi; i < MAXi; i++) {
ctxt.moveTo(x + xOffset, y + yOffset)
x = xCoord(i);
y = yCoord(x);
ctxt.lineTo(x + xOffset, y + yOffset)
}
ctxt.strokeStyle = "black";
ctxt.stroke();
Do I need to change up the way the formulas for the curves are formatted or is there something else wrong, because from what I see, the programm just seems to ignore the xCoord formula and just puts in a normal number.
You're passing the computed x coordinate as the parameter for the y coordinate function, but you should be passing i:
x = xCoord(STARTi);
y = yCoord(STARTi);
ctxt.beginPath();
ctxt.moveTo(x + xOffset, y + yOffset)
for (i = STARTi; i < MAXi; i++) {
ctxt.moveTo(x + xOffset, y + yOffset)
x = xCoord(i);
y = yCoord(i);
ctxt.lineTo(x + xOffset, y + yOffset)
}

How to draw an infinite Hexagon Spiral

I'm trying to create a Structure as shown in the Screenshot below. Is there a way to build an Algorithm for this in JavaScript to get the X and Y Coordinates of each red Point in chronological order to generate an infinite Spiral depending on a specific amount?
Screenshot of how it should look and work
This Code generates me a regular Hexagon:
function hexagon(centerX, centerY) {
var ctx = canvas.getContext('2d');
var x = centerX + Math.cos(Math.PI * 2 / 6) * 50;
var y = centerY + Math.sin(Math.PI * 2 / 6) * 50;
ctx.beginPath();
ctx.moveTo(x, y);
for (var i = 1; i < 7; i++) {
x = centerX + Math.cos(Math.PI * 2 / 6 * i) * 50;
y = centerY + Math.sin(Math.PI * 2 / 6 * i) * 50;
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.stroke();
}
And this is the Cluster-function so far:
function cluster(centerX, centerY, count) {
var ctx = canvas.getContext('2d');
for (var i = 0; i < count; i++) {
if (i == 0) {
var x = centerX;
var y = centerY;
} else {
var x = centerX + Math.cos(-Math.PI / 2) * (100 * (Math.sqrt(3) / 2));
var y = centerY + Math.sin(-Math.PI / 2) * (100 * (Math.sqrt(3) / 2));
}
hexagon(x, y);
}
}
Thank you!
Your cluster function could be like this:
function cluster(centerX, centerY, count) {
var x = centerX,
y = centerY,
angle = Math.PI / 3,
dist = Math.sin(angle) * 100,
i = 1,
side = 0;
hexagon(x, y);
count--;
while (count > 0) {
for (var t = 0; t < Math.floor((side+4)/6)+(side%6==0) && count; t++) {
y = y - dist * Math.cos(side * angle);
x = x - dist * Math.sin(side * angle);
hexagon(x, y);
count--;
}
side++;
}
}
function hexagon(centerX, centerY) {
var ctx = canvas.getContext('2d');
var x = centerX + Math.cos(Math.PI * 2 / 6) * 50;
var y = centerY + Math.sin(Math.PI * 2 / 6) * 50;
ctx.beginPath();
ctx.moveTo(x, y);
for (var i = 1; i < 7; i++) {
x = centerX + Math.cos(Math.PI * 2 / 6 * i) * 50;
y = centerY + Math.sin(Math.PI * 2 / 6 * i) * 50;
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.stroke();
}
function cluster(centerX, centerY, count) {
var x = centerX,
y = centerY,
angle = Math.PI / 3,
dist = Math.sin(angle) * 100,
i = 1,
side = 0;
hexagon(x, y);
count--;
while (count > 0) {
for (var t = 0; t < Math.floor((side+4)/6)+(side%6==0) && count; t++) {
y = y - dist * Math.cos(side * angle);
x = x - dist * Math.sin(side * angle);
hexagon(x, y);
count--;
}
side++;
}
}
cluster(200,230,9);
<canvas id="canvas" width="400" height="400"></canvas>

How To Get Value Of Canvas From A Wheel

How To Get The Value Of A Canvas . I have wheel which is rotating on mouse over the wheel stops now i want to echo out the value on which it was stopped. It is printing the whole array . Not the one on which the wheel stop.
$("#canvas").mouseover(function(){
backup= ctx;
alert(myData);
ctx = null;
});
this is the fiddle: https://jsfiddle.net/z61n9ccx/3/
Here is the full code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var angle = PI2 - PI2 / 4;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
function animate(time) {
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
alert(myData);
ctx = null;
});
$("#canvas").mouseout(function() {
// backup= ctx;
ctx = backup;
animate();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="canvas" width="600" height="600" style="background-color:#ffff">
</canvas>
I added a counter, and then use that as a index: https://jsfiddle.net/Twisty/L6nws9yz/2/
HTML
<canvas id="canvas" width="310" height="310" style="background-color:#ffff">
</canvas>
<div id="counterBox">
<label>Counter:</label>
<span></span>
</div>
<div id="countBox">
<label>Index:</label>
<span></span>
</div>
JS
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var currentSelection = 12;
var counter = 360;
var angle = PI2 - PI2 / 4;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
var lastloop = new Date;
var thisloop = new Date;
var fps = 0;
function animate(time) {
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
thisloop = new Date;
fps = 1000 / (thisloop - lastloop);
lastloop = thisloop;
counter--;
if (counter < 1) {
counter = 360;
}
$("#counterBox span").html(counter);
var index = counter / 30;
$("#countBox span").html(Math.round(index));
//$("#fpsBox span").html(fps);
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
alert(myData[Math.round(counter / 30)-1]);
ctx = null;
});
$("#canvas").mouseout(function() {
// backup= ctx;
ctx = backup;
animate();
});
Counter is set to 360 and then each frame decreases it. Take that and divide by 30 (360 / 12), and you can count each wedge. I round up and now I have 0 - 11 count.
Update
I moved the Index into a global space. To make it more precise, I used the % operator like so:
counter--;
if (counter == 0) {
counter = 360;
}
$("#counterBox span").html(counter);
if (counter % 30 === 0) {
index--;
}
$("#countBox span").html(Math.round(index));
if (index === 0) {
index = 12;
}
When you mouse over, you get the selection:
$("#canvas").mouseover(function() {
backup = ctx;
alert(index);
ctx = null;
});
I wrapped everything in an IIFE so that there aren't any global variables.
Updated Example
It's important to note that the angle calculation is:
angle = degree * Math.PI / 180;
With that being said, you can calculate the current degree and normalize it using:
(angle * (180 / Math.PI)) % 360
I added a function called getValue which takes an angle parameter:
function getValue(angle) {
var degree = (angle * (180 / Math.PI)) % 360,
offsetIndex = (Math.floor(degree / sweepDegree) + offset) % myData.length,
normalizedIndex = Math.abs(offsetIndex - (myData.length - 1));
return myData[normalizedIndex];
}
It essentially calculates the current degree, normalizes it taking into account what the initial degree was when the animation was initialized (which is the offset). Then it divides the degree by the sweep degree, which is 30 in this case since there are 12 items (i.e., 360/12 === 30) and rounds down.
var sweepDegree = 360 / myData.length;
var offset = (360 - (angle * (180 / Math.PI)) % 360) / sweepDegree;
This should work for a varying number of array items. In other words, nothing is hardcoded for a set length of 12 items (like in your case), so it should work for any given number of items.
Then you can simply use the getValue function in the mouseover event listener:
Updated Example
$("#canvas").mouseover(function() {
// ...
alert(getValue(angle));
});
(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var angle = PI2 - PI2 / 4;
var sweepDegree = 360 / myData.length;
var offset = (360 - (angle * (180 / Math.PI)) % 360) / sweepDegree;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
function animate(time) {
if (ctx === null) {
return
}
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
ctx = null;
alert(getValue(angle));
});
$("#canvas").mouseout(function() {
ctx = backup;
animate();
});
function getValue(angle) {
var degree = (angle * (180 / Math.PI)) % 360,
offsetIndex = (Math.floor(degree / sweepDegree) + offset) % myData.length,
normalizedIndex = Math.abs(offsetIndex - (myData.length - 1));
return myData[normalizedIndex];
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="canvas" width="600" height="600" style="background-color:#ffff">
</canvas>

Categories

Resources