Identify points in each quadrant of a canvas - javascript

How do you divide a canvas into four quadrants (top-left, bottom-left, top-right, bottom-right) and then identify points drawn at random in each quadrant?
Here is my not so futile attempt:
var myCanvas = document.getElementById("showCanvas");
var myContext = myCanvas.getContext("2d");
var xAxis = [];
var yAxis = [];
for (var i = 0; i < 4; i++) {
var x = Math.floor(Math.random() * 600);
var y = Math.floor(Math.random() * 350);
var r = 5;
xAxis.push(x);
yAxis.push(y);
myContext.arc(x, y, r, 0, 2 * Math.PI, true);
myContext.closePath();
myContext.fill();
}
var startingPoint = xAxis[0] + ", " + yAxis[0];
var endingPoint = xAxis[3] + ", " + yAxis[3];
var horizontalSlash = myCanvas.width / 2;
var verticalSlash = myCanvas.height / 2;
var remainder = horizontalSlash % verticalSlash;
<canvas id="showCanvas"></canvas>
And the result should show up in these tags:
<h3>The starting point of the line is: <label id="sumPoints">e.g. top, right</label></h3>
<h3>The end point of the line is: <label id="sumPoints">e.g. bottom, left</label></h3>

The suggestion to check the point's coordinates is correct...
Here is an example using a bit of math.
const canvas = document.getElementById("showCanvas");
const ctx = canvas.getContext("2d");
const names = [
["top left", "bottom left"],
["top right", "bottom right"]
]
var points = []
for (var i = 0; i < 4; i++) {
var x = Math.random() * canvas.width
var y = Math.random() * canvas.height
var quadrant = names[Math.floor(x / (canvas.width / 2))][Math.floor(y / (canvas.height / 2))]
points.push({ x, y, quadrant })
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.fillText(quadrant, x-8, y-8)
ctx.closePath();
ctx.fill();
}
console.log(points[0])
canvas {
border:2px dotted gray;
}
<canvas id="showCanvas" width=200 height=200></canvas>

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!

Is there a way to rotate individual pixel from a ImageData data array?

With the following function I create seperate pixels and put them on the canvas:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
function imageData() {
var id = ctx.getImageData(0, 0, 50, 50);
var pixels = id.data;
for (var i = 0; i < 1000; ++i) {
var x = Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
var off = (y * id.width + x) * 4;
pixels[off] = r;
pixels[off + 1] = g;
pixels[off + 2] = b;
pixels[off + 3] = 255;
}
ctx.putImageData(id, 0, 0);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body onload="imageData()" >
<canvas id="canvas" width="50" height="50">
</body>
</html>
Is there a way to rotate the individual pixels? I tried rotating the context in general, but this doesn't seem to work.
Here you have (dumb) example drawing circle. You need some math knowledge to understand what is going on. This example have to show you how to convert x,y to pixel array.
Basically you must keep in mind that we will do rotation in Cartesian coordinate system and then raster points, lines, circles to pixel array.
If you want "rotate pixel" pixels[0...3] you need to "convert" it to Point:
var width = 100
var height = 100
var index = 2 // third pixel
var x = index % width
var y = index / width
var r = pixels[(index + 0) * 4]
var g = pixels[(index + 1) * 4]
var b = pixels[(index + 2) * 4]
var point = {
x, y, r, g, b
}
Now with point you can apply some formulas, and then rasterize it again (you will also need to clear previous position manually). Please find some tutorials how to rotate point eg. this
You can also read how some libraries, engines works, or read some articles about rasterization etc.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
console.log(width, height)
function imageData() {
var id = ctx.getImageData(0, 0, 250, 250);
var pixels = id.data;
/*for (var x = 0; x < width; ++x) {
for (var y = 0; y < height; ++y) {
var off = (x + y * width) * 4;
pixels[off + 0] = 0;
pixels[off + 1] = 0;
pixels[off + 2] = 0;
pixels[off + 3] = 255;
}
}*/
var r = 50;
var offX = 100;
var offY = 100;
var iterations = 1000;
for (var i = 0; i < iterations; i++) {
var angle = 2 * Math.PI * (i / iterations);
var x = offX + Math.floor(Math.sin(angle) * r);
var y = offY + Math.floor(Math.cos(angle) * r);
var off = (x + y * width) * 4;
pixels[off + 0] = 255;
pixels[off + 1] = 0;
pixels[off + 2] = 0;
pixels[off + 3] = 255;
}
ctx.putImageData(id, 0, 0);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body onload="imageData()" >
<canvas id="canvas" width="250" height="250">
</body>
</html>
putImageData() will really "put" the pixels in place on the canvas buffer, ignoring all of the context's attributes when doing so: global-alpha, composite mode, transformation matrix, etc.
To do what you want, you'll need to create a bitmap version of your ImageData object first.
And to do so, the best is to use the createImageBitmap() method which returns a Promise that will resolve to an ImageBitmap object that you will be able to draw on your context using drawImage(), which is affected by the context's state.
(async () => {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
const bmp = await createImageBitmap(imageData());
let angle = 0;
anim();
function anim() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(bmp.width/2, bmp.height/2);
ctx.rotate(angle+=Math.PI/180);
ctx.drawImage(bmp, -bmp.width/2, -bmp.height/2);
requestAnimationFrame(anim);
}
function imageData() {
var id = ctx.getImageData(0, 0, 50, 50);
var pixels = id.data;
for (var i = 0; i < 1000; ++i) {
var x = Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
var off = (y * id.width + x) * 4;
pixels[off] = r;
pixels[off + 1] = g;
pixels[off + 2] = b;
pixels[off + 3] = 255;
}
return id;
}
})().catch(console.error);
<canvas id="canvas" width="50" height="50"></canvas>

How to curve a texture by offsetting X Pixels

Refer to this fiddle:
// get canvas references (canvas=collar, canvas1=texture)
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvas1 = document.getElementById("canvas1");
var ctx1 = canvas1.getContext("2d");
// preload the texture and collar images before starting
var textureImg, collarImg;
var imageURLs = [];
var imagesOK = 0;
var imgs = [];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/checkered.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/collar.png");
loadAllImages();
function loadAllImages(callback) {
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
img.crossOrigin = "anonymous";
imgs.push(img);
img.onload = function () {
imagesOK++;
if (imagesOK == imageURLs.length) {
textureImg = imgs[0];
collarImg = imgs[1];
start();
}
};
img.src = imageURLs[i];
}
}
function start() {
// set both canvas dimensions
canvas.width = collarImg.width;
canvas.height = collarImg.height + 5;
canvas1.width = textureImg.width;
canvas1.height = textureImg.height;
// draw the textureImg on canvas1
ctx1.drawImage(textureImg, 0, 0, canvas1.width, canvas1.height);
// curve the texture into a collar shaped curved
curveTexture(collarImg.width, collarImg.height);
// draw the collarImg on canvas
ctx.drawImage(collarImg, 0, 0);
// set compositing to source-atop
// any new drawing will ONLY fill existing non-transparent pixels
ctx.globalCompositeOperation = "source-atop";
// draw the curved texture from canvas1 onto the collar of canvas
// (the existing pixels are the collar, so only the collar is filled)
ctx.drawImage(canvas1, 0, 0);
}
function curveTexture(w, h) {
// define a quadratic curve that fits the collar bottom
// These values change if the collar image changes (+5,-32)
var x0 = 0;
var y0 = h + 5;
var cx = w / 2;
var cy = h - 32;
var x1 = w;
var y1 = h + 5;
// get a,b,c for quadratic equation
// equation is used to offset columns of texture pixels
// in the same shape as the collar
var Q = getQuadraticEquation(x0, y0, cx, cy, x1, y1);
// get the texture canvas pixel data
// 2 copies to avoid self-referencing
var imageData0 = ctx1.getImageData(0, 0, w, h);
var data0 = imageData0.data;
var imageData1 = ctx1.getImageData(0, 0, w, h);
var data1 = imageData1.data;
// loop thru each vertical column of pixels
// Offset the pixel column into the shape of the quad-curve
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
// the pixel to write
var n = ((w * y) + x) * 4;
// the vertical offset amount
var yy = parseInt(y + h - (Q.a * x * x + Q.b * x + Q.c));
// the offset pixel to read
var nn = ((w * yy) + x) * 4;
// offset this pixel by the quadCurve Y value (yy)
data0[n + 0] = data1[nn + 0];
data0[n + 1] = data1[nn + 1];
data0[n + 2] = data1[nn + 2];
data0[n + 3] = data1[nn + 3];
}
}
ctx1.putImageData(imageData0, 0, 0);
}
// Quadratic Curve: given x coordinate, find y coordinate
function getQuadraticY(x, Q) {
return (Q.a * x * x + Q.b * x + Q.c);
}
// Quadratic Curve:
// Given: start,control,end points
// Find: a,b,c in quadratic equation ( y=a*x*x+b*x+c )
function getQuadraticEquation(x0, y0, cx, cy, x2, y2) {
// need 1 more point on q-curve, so calc its midpoint XY
// Note: since T=0.5 therefore TT=(1-T)=0.5 also [so could simplify]
var T = 0.50;
var TT = 1 - T;
var x1 = TT * TT * x0 + 2 * TT * T * cx + T * T * x2;
var y1 = TT * TT * y0 + 2 * TT * T * cy + T * T * y2;
var A = ((y1 - y0) * (x0 - x2) + (y2 - y0) * (x1 - x0)) / ((x0 - x2) * (x1 * x1 - x0 * x0) + (x1 - x0) * (x2 * x2 - x0 * x0));
var B = ((y1 - y0) - A * (x1 * x1 - x0 * x0)) / (x1 - x0);
var C = y0 - A * x0 * x0 - B * x0;
return ({
a: A,
b: B,
c: C
});
}
body {
background-color: ivory;
padding:20px;
}
canvas {
border:1px solid red;
}
<h3>"Curve" a texture</h3>
<p>by offsetting Y pixels based on Q-curve</p>
<canvas id="canvas" width=300 height=300></canvas>
<p>The temporary texture canvas (canvas1)</p>
<canvas id="canvas1" width=300 height=300></canvas>
http://jsfiddle.net/m1erickson/hdXyk/
I want to convert that horizontal generated lines to vertical. I tries to change the values but unable to achieved it.
I think that "Curve" a texture by offsetting X pixels based on Q-curve might work for getting vertical lines. Please help me for this.
For more you can refer this link : How to fill pattern in canvas and curving along the shape?

pack in small circles into a bigger circle

I'm trying to figure out a way to pack in smaller circles into a bigger one , but for some reason smaller circles are not correctly aligned.
I believe it's the position calculation that is probably missing something.
Please see the code for more details:
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var canvas_width = c_el.clientWidth;
var canvas_height = c_el.clientHeight;
var circle1 = {
r: 50, /// radius
pos: {
x: (canvas_width / 2),
y: (canvas_height / 2)
}
}
var circle2 = {
r: 5,
pos:{}
}
var c2h = circle2.r * 2; /// circle height ////
var c2w = c2h; //// circle width /////
var c1h = circle1.r * 2; /// circle height ////
var c1w = c1h; //// circle width /////
var max_circles2_H = c1h / c2h;
var r = circle1.r;
var d = circle1.r - 2; //// segement distance from center ////
drawCircle( circle1 );
for(var col = 1; col < max_circles2_H; col++){
var d = circle1.r - ( col * c2h); /// distance from center to segment ///
var c = 2 * (Math.sqrt((r*r) - (d * d))); //// circle's chord length
var max_circles2_W = c / c2w;
for(var row = 1; row < max_circles2_W; row++){
circle2.pos.x = (row * c2w) + (circle1.pos.x - circle1.r);
circle2.pos.y = (col * c2h) + (circle1.pos.y - circle1.r);
drawCircle(circle2);
}
}
function drawCircle( circle ){
ctx.beginPath();
ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
ctx.stroke();
}
<canvas id="myCanvas" width="300" height="150">
Any help is greatly appreciated.
This is close but it's needs a little adjusting. You can see where x_offset is calculated and try some different math to tighten it up.
update
Added Math.ceil to max_circles2_W and it seems to fit.
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var canvas_width = c_el.clientWidth;
var canvas_height = c_el.clientHeight;
var circle1 = {
r: 50, /// radius
pos: {
x: (canvas_width / 2),
y: (canvas_height / 2)
}
}
var circle2 = {
r: 5,
pos:{}
}
var c2h = circle2.r * 2; /// circle height ////
var c2w = c2h; //// circle width /////
var c1h = circle1.r * 2; /// circle height ////
var c1w = c1h; //// circle width /////
var max_circles2_H = c1h / c2h;
var r = circle1.r;
var d = circle1.r - 2; //// segement distance from center ////
drawCircle( circle1 );
for(var col = 1; col < max_circles2_H; col++){
var d = circle1.r - ( col * c2h); /// distance from center to segment ///
var c = 2 * (Math.sqrt((r*r) - (d * d))); //// circle's chord length
var max_circles2_W = Math.ceil(c / c2w);
// CALCULATE OFFSET HERE
var x_offset = Math.floor((c1w - (max_circles2_W * c2w)) / 2);
for(var row = 1; row < max_circles2_W; row++){
circle2.pos.x = (row * c2w) + (circle1.pos.x - circle1.r) + x_offset;
circle2.pos.y = (col * c2h) + (circle1.pos.y - circle1.r);
ctx.fillText(row, circle2.pos.x-3, circle2.pos.y+4);
drawCircle(circle2);
}
}
function drawCircle( circle ){
ctx.beginPath();
ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
ctx.stroke();
}
<canvas id="myCanvas" width="300" height="150">

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