How to randomize the speed of rotating circle? - javascript

I have two circles rotating round the circle and I would like the circle to change the speed at random after passing one revolution.Both circle should be at different speed or they might be the same speed (then collision will occurs). For example, during first run, both circles are moving at 10m/s and after it reaches end of the revolution,they will collide.Let's say after the revolution, it changes circle 1 to 15m/s and circle 2 to 30m/s , then they won't collide.I would like to know how to achieve this. This is just an idea of what i am trying to achieve. It would be even better if the speed is randomized after every revolution.
Any help would be appreciated.
Code:
(function() {
var ctx = document.getElementById("canvas").getContext("2d"),
x1 = 160,
y1 = 120,
x2 = 330,
y2 = 280,
radius = 20;
angle = 0,
velX = 0,
velY = 0,
thrust = 3,
rotation = 0;
function draw() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x1 += velX;
y1 += velY;
angle += 1;
ctx.fillStyle = "#000";
ctx.clearRect(0, 0, 550, 400);
ctx.beginPath();
ctx.arc(x1, y1, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
draw2();
setTimeout(function() {
draw()
}, 30);
}
function draw2() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x2 += -velX;
y2 += -velY;
angle += 1;
ctx.fillStyle = "#80ced6";
ctx.beginPath();
ctx.arc(x2, y2, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
collisiondetection();
}
var distance = 0;
var totalcounter = 0;
var collide = false;
function collisiondetection() {
distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (distance < radius * 2) {
if (collide == false) {
totalcounter = totalcounter + 1;
document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
collide = true;
}
} else {
collide = false;
}
}
draw();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

What you can do is to declare a local speed variable to the draw() function, then pass it to the setTimeout() callback, like this:
var speed = Math.floor(Math.random() * 11);
draw2();
setTimeout(function() {
draw()
}, speed);
The code Math.floor(Math.random() * 11) will give you a random number between 0 and 10 so setTimeout will be called with a different speed each time.
Demo:
window.onload = function() {
(function() {
var ctx = document.getElementById("canvas").getContext("2d"),
x1 = 160,
y1 = 120,
x2 = 330,
y2 = 280,
radius = 20;
angle = 0,
velX = 0,
velY = 0,
thrust = 3,
rotation = 0;
function draw() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x1 += velX;
y1 += velY;
angle += 1;
ctx.fillStyle = "#000";
ctx.clearRect(0, 0, 550, 400);
ctx.beginPath();
ctx.arc(x1, y1, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
var speed = Math.floor(Math.random() * 11);
draw2();
setTimeout(function() {
draw()
}, speed);
}
function draw2() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x2 += -velX;
y2 += -velY;
angle += 1;
ctx.fillStyle = "#80ced6";
ctx.beginPath();
ctx.arc(x2, y2, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
collisiondetection();
}
var distance = 0;
var totalcounter = 0;
var collide = false;
function collisiondetection() {
distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (distance < radius * 2) {
if (collide == false) {
totalcounter = totalcounter + 1;
document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
collide = true;
}
} else {
collide = false;
}
}
draw();
})();
}
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

You can change the timeGap when angle becomes 360, i.e., when a revolution completes. Thus, it will appear as the speed is getting changed.
Inside your draw() function:
if(angle % 360 == 0) {
timeGap = Math.random() * 20 + 5;
}
(function() {
var ctx = document.getElementById("canvas").getContext("2d"),
x1 = 160,
y1 = 120,
x2 = 330,
y2 = 280,
radius = 20,
angle1 = 0,
angle2 = 0,
velX = 0,
velY = 0,
thrust = 3,
rotation = 0,
timeGap1 = 10,
timeGap2 = 10,
diff = 20,
minTimeGap = 20;
function draw() {
velX = Math.cos(angle1 * Math.PI / 180) * thrust;
velY = Math.sin(angle1 * Math.PI / 180) * thrust;
x1 += velX;
y1 += velY;
angle1 += 2;
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.arc(x1, y1, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
if(angle1 % 360 == 0) {
timeGap1 = Math.random() * diff + minTimeGap;
}
setTimeout(function() {
draw();
}, timeGap1);
}
function draw2() {
velX = Math.cos(angle2 * Math.PI / 180) * thrust;
velY = Math.sin(angle2 * Math.PI / 180) * thrust;
x2 += -velX;
y2 += -velY;
angle2 += 2;
ctx.fillStyle = "#007700";
ctx.beginPath();
ctx.arc(x2, y2, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
if(angle2 % 360 == 0) {
timeGap2 = Math.random() * diff + minTimeGap;
}
setTimeout(function() {
draw2();
}, timeGap2);
}
function clearCanvas() {
ctx.fillStyle = 'rgba(220,220,220,0.5)';
ctx.fillRect(0, 0, 550, 400);
collisiondetection();
setTimeout(function() {
clearCanvas();
}, timeGap2 + timeGap1);
}
var distance = 0;
var totalcounter = 0;
var collide = false;
function collisiondetection() {
distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (distance < radius * 2) {
if (collide == false) {
totalcounter = totalcounter + 1;
document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter + "<br/>Speed1: " + timeGap1 + "<br/>Speed2: " + timeGap2;
collide = true;
}
} else {
collide = false;
}
}
draw();
draw2();
clearCanvas();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

(function() {
var ctx = document.getElementById("canvas").getContext("2d"),
x1 = 160,
y1 = 120,
x2 = 330,
y2 = 280,
radius = 20;
angle = 0,
velX = 0,
velY = 0,
thrust = 3,
rotation = 0,
maxSpeed = 100,
speed = Math.floor(Math.random() * 100) + 1;
function draw() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x1 += velX;
y1 += velY;
angle += 1;
ctx.fillStyle = "#000";
ctx.clearRect(0, 0, 550, 400);
ctx.beginPath();
ctx.arc(x1, y1, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
draw2();
SpeedCount();
}
function draw2() {
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x2 += -velX;
y2 += -velY;
angle += 1;
ctx.fillStyle = "#80ced6";
ctx.beginPath();
ctx.arc(x2, y2, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
collisiondetection();
}
function SpeedCount(){
(function(speed) {
setTimeout(function() {
draw()
}, speed);
})(speed);
}
var distance = 0;
var totalcounter = 0;
var collide = false;
function collisiondetection() {
distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (distance < radius * 2) {
if (collide == false) {
totalcounter = totalcounter + 1;
document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
collide = true;
}
} else {
collide = false;
}
if((angle + 90) % 360 == 0){
speed = Math.floor(Math.random() * maxSpeed) + 1;
}
}
draw();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>
try this one.

Let's rework it a bit:
First, when programming a graphical animation, you should separate your objects logic and your drawing operations.
The drawing operations should occur at regular intervals, based on the screen refresh rate (to avoid drawing sometimes twice a frame and sometimes not drawing at all).
A convenient method available in the Web API for this exact case is requestAnimationFrame(callback). It will queue our callback to fire just before the next screen refresh rate.
So we can use it as the core of our animation loop, that will always fire at the same rate as our screen can show (usually 60FPS).
When you have animated objects on your scene, the simplest data-structure in js, are Objects. Instead of holding a lot of variables everywhere, you pack them in their own object.
When you have multiple such objects, you hold them all together (e.g in an Array).
Now, in our animation loop, we will first update our objects position, then draw them.
It is in the update part that we will control the velocity of our objects, and only after we did update all the object, we will check if they collide.
(function() {
var ctx = document.getElementById("canvas").getContext("2d"),
max_speed = Math.PI / 12,
objects = [{
center_x: 160,
center_y: 120,
speed: Math.random() % max_speed,
angle: 0,
color: '#000'
},
{
center_x: 330,
center_y: 280,
speed: -(Math.random() % max_speed),
angle: 0,
color: "#80ced6"
}
],
radius = 20,
outerRad = 120,
totalcounter = 0,
collide = true;
anim(); // begin our main anim loop
function anim() {
update(); // our objects update logic
draw(); // now we draw
collisiondetection(); // DOM update
requestAnimationFrame(anim); // start again #next-frame
}
function update() {
// here we only change the object's properties
// nothing graphical should come here
objects.forEach(function(object) {
var angle = object.angle;
object.x = Math.cos(angle) * outerRad + object.center_x;
object.y = Math.sin(angle) * outerRad + object.center_y;
object.angle += object.speed;
});
}
function draw() {
// here is only the graphical part
// no logic should come here
ctx.clearRect(0, 0, 550, 400);
objects.forEach(function(object) {
ctx.fillStyle = object.color;
ctx.beginPath();
ctx.arc(object.x, object.y, radius, 0, Math.PI * 2);
ctx.fill();
});
}
function collisiondetection() {
var o1 = objects[0],
o2 = objects[1];
var distance = Math.sqrt((o1.x - o2.x) * (o1.x - o2.x) + (o1.y - o2.y) * (o1.y - o2.y));
if (distance < radius * 2) {
if (collide == false) {
totalcounter = totalcounter + 1;
document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
collide = true;
}
} else {
collide = false;
}
}
// and now if you want to update randomly these object's speed, you can do from anywhere
document.onclick = function() {
objects[0].speed = Math.random() % max_speed;
objects[1].speed = -(Math.random() % max_speed);
};
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<p id="cTotal">Total collisions: </p>

Related

Raycasting with maximum distance

I'm writing a simple raycast in htm5l and the main issue with the raycast is that the line goes off in a direction of probably infinite length.. I would like to limit that length to a specific radius but I'm not having any luck. If someone could guide me that'd be great.
window.addEventListener('DOMContentLoaded', (event) => {
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let coord = {
x: 0,
y: 0
}
function line(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Boundery {
constructor(x1, y1, x2, y2) {
this.a = new Vector(x1, y1);
this.b = new Vector(x2, y2);
}
show() {
ctx.strokeStyle = '#000000'
line(this.a.x, this.a.y, this.b.x, this.b.y);
}
}
class Ray {
constructor(x, y) {
this.pos = new Vector(x, y);
this.dir = new Vector(Math.cos(1), Math.sin(0));
}
show() {
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.ellipse(this.pos.x, this.pos.y, 5, 5, 0, 0, Math.PI * 2);
ctx.stroke();
}
cast(wall) {
let x1 = wall.a.x;
let y1 = wall.a.y;
let x2 = wall.b.x;
let y2 = wall.b.y;
let x3 = this.pos.x;
let y3 = this.pos.y;
let x4 = this.pos.x + this.dir.x;
let y4 = this.pos.y + this.dir.y;
let den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (den == 0) {
return;
}
let t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
let u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;
if (t > 0 && t < 1 && u > 0) {
let point = new Vector(x1 + t * (x2 - x1), y1 + t * (y2 - y1));
return point;
} else {
return;
}
}
}
let wall = new Boundery(300, 100, 300, 300);
let ray = new Ray(100, 200);
function tick(timestamp) {
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
wall.show();
ray.show();
let r = ray.cast(wall);
if (r) {
ctx.fillStyle = 'red';
ctx.ellipse(r.x, r.y, 10, 10, 0, 0, 2 * Math.PI);
ctx.fill();
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
});
<canvas id="canvas" width="2000" height="1000"></canvas>
So the ray currently fires to the right (1,0) of the small red circle but it's distance just goes on forever so I'm trying to limit that distance. In the example the position the ray hits the wall is the red circle that's drawn on the wall
Ray length and direction
Modify the ray to have the start position, a direction, and a length. as follows
class Ray {
constructor(pos, direction, length) {
this.pos = pos;
this.dir = direction;
this.length = length;
}
You can get the end point with
get end() {
return new Vector(
this.pos.x + Math.cos(this.dir) * this.length,
this.pos.y + Math.sin(this.dir) * this.length
);
}
When you cast the ray you convert the ray to a line segment and then check against any wall segments for the intercept. Only points withing the length of the ray will be found.
Example.
The example uses a ray to check against many walls. It finds the closest intercept to the to the start of the ray and within the rays length.
Note (FOR example only) the walls are random so if a wall gets to close to the ray, click the canvas to randomize the walls.
I have re-organised it somewhat with Vector as a point, Line (2 vectors) as a line segment with an intercept function (also represents a wall), And Ray as a vector, direction and length. The Ray.cast finds the intercept of an array of line, returning undefined if no intercept found.
const ctx = canvas.getContext("2d");
Math.TAU = Math.PI * 2;
Math.rand = (min, max) => Math.random() * (max - min) + min;
var myRay;
const WALL_COUNT = 30;
const WALL_STYLE = {radius: 0, lineWidth: 1, strokeStyle: "#000"};
const RAY_STYLE_A = {radius: 2, lineWidth: 1, strokeStyle: "#0FF", fillStyle: "#F00"};
const RAY_STYLE_B = {radius: 5, lineWidth: 3, strokeStyle: "#00F", fillStyle: "#F00"};
const RAY_INTERCEPT_STYLE = {radius: 5, lineWidth: 1, strokeStyle: "#000", fillStyle: "#FF0"};
const ROTATE_RAY = 10; // seconds per rotation
const walls = [];
setTimeout(init, 0);
canvas.addEventListener("click",init);
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
draw(ctx, {radius = 5, lineWidth = 2, strokeStyle = "#000", fillStyle = "#F00"} = {}) {
ctx.strokeStyle = strokeStyle;
ctx.fillStyle = fillStyle;
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.arc(this.x, this.y, radius, 0, Math.TAU);
ctx.fill();
ctx.stroke();
}
}
class Line {
constructor(start, end) {
this.start = start;
this.end = end;
}
draw(ctx, {radius = 5, lineWidth = 2, strokeStyle = "#000", fillStyle = "#F00"} = {}) {
if (radius > 0) {
this.start.draw(ctx, {radius, lineWidth, strokeStyle, fillStyle});
this.end.draw(ctx, {radius, lineWidth, strokeStyle, fillStyle});
}
ctx.strokeStyle = strokeStyle;
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.moveTo(this.start.x, this.start.y);
ctx.lineTo(this.end.x, this.end.y);
ctx.stroke();
}
intercept(line) {
var x1, y1, x2, y2, x3, y3, c, u;
x1 = line.end.x - line.start.x;
y1 = line.end.y - line.start.y;
x2 = this.end.x - this.start.x;
y2 = this.end.y - this.start.y;
c = x1 * y2 - y1 * x2;
if (c) {
x3 = line.start.x - this.start.x;
y3 = line.start.y - this.start.y;
u = (x1 * y3 - y1 * x3) / c;
if (u >= 0 && u <= 1) {
u = (x2 * y3 - y2 *x3) / c;
if (u >= 0 && u <= 1) { return [u, line.start.x + x1 * u, line.start.y + y1 * u] }
}
}
}
}
class Ray {
constructor(pos, direction, length) {
this.pos = pos;
this.dir = direction;
this.length = length;
}
draw(ctx, {radius = 5, lineWidth = 2, strokeStyle = "#000", fillStyle = "#F00"} = {}) {
this.pos.draw(ctx, {radius, lineWidth, strokeStyle, fillStyle});
ctx.strokeStyle = strokeStyle;
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.moveTo(this.pos.x, this.pos.y);
ctx.lineTo(
this.pos.x + Math.cos(this.dir) * this.length,
this.pos.y + Math.sin(this.dir) * this.length
);
ctx.stroke();
}
get end() {
return new Vector(
this.pos.x + Math.cos(this.dir) * this.length,
this.pos.y + Math.sin(this.dir) * this.length
);
}
get line() {
return new Line(this.pos, this.end);
}
cast(lines) {
const tLine = this.line;
var minDist = 1, point;
for (const line of lines) {
const result = line.intercept(tLine);
if (result) {
const [u, x, y] = result;
if (u <= minDist) {
minDist = u;
if (!point) { point = new Vector(x, y) }
else {
point.x = x;
point.y = y;
}
point.u = u;
}
}
}
return point;
}
}
function init() {
walls.length = 0;
for (let i = 0; i < WALL_COUNT / 2; i++) {
walls.push(new Ray(
new Vector(Math.rand(0, canvas.width * 0.4), Math.rand(0, canvas.height)),
(Math.rand(0, 8) | 0) / 4 * Math.PI, 100
).line);
walls.push(new Ray(
new Vector(Math.rand(canvas.width * 0.6, canvas.width), Math.rand(0, canvas.height)),
(Math.rand(0, 8) | 0) / 4 * Math.PI, 100
).line);
}
if(!myRay) {
myRay = new Ray(new Vector(canvas.width / 2, canvas.height / 2), 0, Math.max(canvas.width, canvas.height) * 0.485);
requestAnimationFrame(mainLoop);
}
}
function mainLoop(time) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
myRay.dir = (time / (ROTATE_RAY * 1000)) * Math.TAU;
const point = myRay.cast(walls)
myRay.draw(ctx, RAY_STYLE_A);
for(const w of walls) { w.draw(ctx, WALL_STYLE) }
if (point) {
const len = myRay.length;
myRay.length = point.u * len;
myRay.draw(ctx, RAY_STYLE_B);
myRay.length = len;
point.draw(ctx, RAY_INTERCEPT_STYLE);
}
requestAnimationFrame(mainLoop);
}
#canvas {
border: 2px solid black;
}
<canvas id="canvas" width="500" height="500"> </canvas>

button animation error: Cannot read property 'requestAnimationFrame' of undefined (line 11)

I'm working on a custom button animation for my Wix website it is written in JavaScript and I get this error when I plug the code into an onclick event:
"cannot read property 'requestAnimationFrame' of undefined"
I've tried removing the return and I think the problem has to do with some sort of iframe issue because the original code was built to run in an html <iframe> element but that dident end up working out.
If someone could rewrite this code so that it dosent give this error that would be super helpful.
export function button7_click(event) {
$w.window.requestAnimFrame = (function() {
return $w.window.requestAnimationFrame ||
$w.window.webkitRequestAnimationFrame ||
$w.window.mozRequestAnimationFrame ||
$w.window.oRequestAnimationFrame ||
$w.window.msRequestAnimationFrame ||
function(callback) {
$w.window.setTimeout(callback, 1000 / 60);
};
})();
Math.randMinMax = function(min, max, round) {
var val = min + (Math.random() * (max - min));
if (round) val = Math.round(val);
return val;
};
Math.TO_RAD = Math.PI / 180;
Math.getAngle = function(x1, y1, x2, y2) {
var dx = x1 - x2,
dy = y1 - y2;
return Math.atan2(dy, dx);
};
Math.getDistance = function(x1, y1, x2, y2) {
var xs = x2 - x1,
ys = y2 - y1;
xs *= xs;
ys *= ys;
return Math.sqrt(xs + ys);
};
var FX = {};
(function() {
var canvas = $w.document.getElementById('myCanvas'),
ctx = canvas.getContext('2d'),
lastUpdate = new Date(),
mouseUpdate = new Date(),
lastMouse = [],
width, height;
FX.particles = [];
setFullscreen();
$w.document.getElementById('button').addEventListener('mousedown', buttonEffect);
function buttonEffect() {
var button = $w.document.getElementById('button'),
height = button.offsetHeight,
left = button.offsetLeft,
top = button.offsetTop,
width = button.offsetWidth,
x, y, degree;
for (var i = 0; i < 40; i = i + 1) {
if (Math.random() < 0.5) {
y = Math.randMinMax(top, top + height);
if (Math.random() < 0.5) {
x = left;
degree = Math.randMinMax(-45, 45);
} else {
x = left + width;
degree = Math.randMinMax(135, 225);
}
} else {
x = Math.randMinMax(left, left + width);
if (Math.random() < 0.5) {
y = top;
degree = Math.randMinMax(45, 135);
} else {
y = top + height;
degree = Math.randMinMax(-135, -45);
}
}
createParticle({
x: x,
y: y,
degree: degree,
speed: Math.randMinMax(100, 150),
vs: Math.randMinMax(-4, -1)
});
}
}
$w.window.setTimeout(buttonEffect, 100);
loop();
$w.window.addEventListener('resize', setFullscreen);
function createParticle(args) {
var options = {
x: width / 2,
y: height / 2,
color: 'hsla(' + Math.randMinMax(160, 290) + ', 100%, 50%, ' + (Math.random().toFixed(2)) + ')',
degree: Math.randMinMax(0, 360),
speed: Math.randMinMax(300, 350),
vd: Math.randMinMax(-90, 90),
vs: Math.randMinMax(-8, -5)
};
for ($w.key in args) {
options[$w.key] = args[$w.key];
}
FX.particles.push(options);
}
function loop() {
var thisUpdate = new Date(),
delta = (lastUpdate - thisUpdate) / 1000,
amount = FX.particles.length,
size = 2,
i = 0,
p;
ctx.fillStyle = 'rgba(15,15,15,0.25)';
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeStyle = 'lighter';
for (; i < amount; i = i + 1) {
p = FX.particles[i];
p.degree += (p.vd * delta);
p.speed += (p.vs); // * delta);
if (p.speed < 0) continue;
p.x += Math.cos(p.degree * Math.TO_RAD) * (p.speed * delta);
p.y += Math.sin(p.degree * Math.TO_RAD) * (p.speed * delta);
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(p.degree * Math.TO_RAD);
ctx.fillStyle = p.color;
ctx.fillRect(-size, -size, size * 2, size * 2);
ctx.restore();
}
lastUpdate = thisUpdate;
$w.requestAnimFrame(loop);
}
function setFullscreen() {
width = canvas.width = $w.window.innerWidth;
height = canvas.height = $w.window.innerHeight;
};
})();
}
The button once clicked should run the JavaScript code and play the animation. Thanks for your help.

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>

Js - calculate distance from point mapped to colour forms square?

I am working on a project where I visualise the effect of a magnetic dipole, on a range of vectors, I'm just testing with one pole at the moment and something doesn't work but I don't know why.
the force that a vector receives is mapped onto a color to check if I did it right, these are my results:
so this is the canvas I'm working with
and when I lower the size of each vector and increase the density you can see this forms diamonds rather than a circular pattern.
Does anybody know why this is or what could be causing it?
code below here:
function calcForce(magnet, vector){
return 1/distance(magnet.x,magnet.y,vector.centerx,vector.centery) * magnet.force;
}
function distance(cx, cy, ex, ey){
var dy = Math.abs(ey - cy);
var dx = Math.abs(ex - cx);
return Math.sqrt((dx^2) + (dy^2));
}
function mapRainbow(value) {
return 'hsl(' + value + ',100%,50%)';
}
function map_range(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
function mapForce(force){
return map_range(force,10,1000,20,40);
}
function drawStroke(stroke){
ctx.beginPath();
ctx.moveTo(stroke.x1,stroke.y1);
ctx.lineTo(stroke.x2,stroke.y2);
stroke.color = mapRainbow(stroke.force);
ctx.strokeStyle = stroke.color;
ctx.stroke();
ctx.closePath();
}
*this is not all the code by far but I think this is enough, need to see more? just ask.
Use distance to generate gradient:
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 -= x1) * x2 + (y2 -= y1) * y2);
}
function angleBetweenPoints(x1, y1, x2, y2) {
return (Math.atan2(x2 - x1, y2 - y1) + 2 * Math.PI);
}
var center = { x: 250, y: 250 };
var vectorLength = 15;
function max(v, m) {
if (v > m) {
return m;
}
return v;
}
function draw() {
if (Math.random() > 0.5) {
center.x += (Math.random() - 0.5) * 10;
}
else {
center.y += (Math.random() - 0.5) * 10;
}
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var xIndex = 0; xIndex < canvas.width; xIndex += vectorLength) {
for (var yIndex = 0; yIndex < canvas.height; yIndex += vectorLength) {
var x = xIndex - (Math.random() * vectorLength * 0.0);
var y = yIndex - (Math.random() * vectorLength * 0.0);
var angle = angleBetweenPoints(center.x, center.y, x, y);
var dist = distance(x, y, center.x, center.y);
ctx.fillStyle = "rgb(" + Math.floor(max(dist, 255)) + "," + Math.floor((255 - max(dist, 255))) + ",0)";
ctx.translate((x + vectorLength * 0.5), (y + vectorLength * 0.5));
ctx.rotate(-angle);
ctx.fillRect(0 - vectorLength * 0.5, 0 - vectorLength * 0.5, vectorLength * 0.25, vectorLength * 0.75);
ctx.rotate(angle);
ctx.translate(0 - (x + vectorLength * 0.5), 0 - (y + vectorLength * 0.5));
}
}
ctx.fillRect(center.x + vectorLength / 2, center.y + vectorLength / 2, vectorLength, vectorLength);
requestAnimationFrame(function () {
setTimeout(draw, 1000 / 60);
});
}
draw();

Fill color dynamically in Canvas Cylinder I am getting error as max width undefined

kindly bear with my english
I am working on creating (I am new to Canvas) Cylinder. Dynamically fill color when the user enter the percentage value in the text box for example 10% the cylinder fill for 10% like wise till 100%.
I have created cylinder, I have created the little validation for the text box when i tried to other value instead of %
here is my code for validation and Filling color
<script type="text/javascript">
$(document).ready(function() {
$("#my_input").focusout(function(event) {
if($("#my_input").val().indexOf("%") != -1){
if($.isNumeric($("#my_input").val().replace('%',''))) {
// Allow only backspace and delete
if ( event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 37) {
//$("#myCanvas").animate({ opacity: 0.25 });
}
else {
// Ensure that it is a number and stop the keypress
if (event.keyCode < 48 || event.keyCode > 57) {
event.preventDefault();
}
}
perc = parseInt($("#my_input").val().replace('%','')) / 100;
draw();
}
}
else{
alert('Value in %');
}
});
});
function draw()
{
context.clearRect(0, 0, canvas.width, canvas.height);
var x = 180;
var y = 40;
context.beginPath();
context.rect(x, y, maxWidth, maxHeight);
context.lineWidth = 7;
var per = perc;
if(per > 1)perc = 1;
// fill
context.beginPath();
context.fillStyle = 'yellow';
context.rect(x, y, maxWidth * perc, maxHeight);
context.fill();
}
Here is my HTML Code for canvas
<canvas id="canvas" width="300px" height="300px"></canvas>
Here is the code for Creating Cylinder
<script type='text/javascript'>//<![CDATA[
//the below is code is for to work RequestAnimationFrame (SVG) in all the browsers -- Mahadevan
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
//the below code is to generate Cylinder object -- Mahadevan
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var degreeAngle = 0;
requestAnimationFrame(animate);
function drawRotatedCylinder(x, y, w, h, degreeAngle) {
context.save();
context.translate(x + w / 10, y + h / 10);
context.rotate(degreeAngle * Math.PI / 180);
drawCylinder(-w / 10, -h / 10, w, h);
context.restore();
}
function drawCylinder(x, y, w, h) {
context.beginPath(); //to draw the top circle
for (var i = 0 * Math.PI; i < 2 * Math.PI; i += 0.01) {
xPos = (x + w / 2) - (w / 2 * Math.sin(i)) * Math.sin(0 * Math.PI) + (w / 2 * Math.cos(i)) * Math.cos(0 * Math.PI);
yPos = (y + h / 8) + (h / 8 * Math.cos(i)) * Math.sin(0 * Math.PI) + (h / 8 * Math.sin(i)) * Math.cos(0 * Math.PI);
if (i == 0) {
context.moveTo(xPos, yPos);
} else {
context.lineTo(xPos, yPos);
}
}
context.moveTo(x, y + h / 8);
context.lineTo(x, y + h - h / 8);
for (var i = 0 * Math.PI; i < Math.PI; i += 0.01) {
xPos = (x + w / 2) - (w / 2 * Math.sin(i)) * Math.sin(0 * Math.PI) + (w / 2 * Math.cos(i)) * Math.cos(0 * Math.PI);
yPos = (y + h - h / 8) + (h / 8 * Math.cos(i)) * Math.sin(0 * Math.PI) + (h / 8 * Math.sin(i)) * Math.cos(0 * Math.PI);
if (i == 0) {
context.moveTo(xPos, yPos);
} else {
context.lineTo(xPos, yPos);
}
}
context.moveTo(x + w, y + h / 8);
context.lineTo(x + w, y + h - h / 8);
context.strokeStyle = '#ff0000';
context.stroke();
context.fillStyle = 'yellow';
context.fill();
}
function animate() {
//requestAnimationFrame(animate);
context.clearRect(0, 0, canvas.width, canvas.height);
drawRotatedCylinder(100, 100, 180, 180, degreeAngle++);
}
//]]>
</script>
And here is my Final HTml Code
Numberic Value <input type ="text" id="my_input" class="numeric" name="my_input" placeholder="Enter value"/>
When i tried to enter the value in the textbox that cylinder canvas getting hidden and i am getting an error as Uncaught ReferenceError: maxWidth is not defined
When i checked for circle canvas in google it says i need to put (context.rect) instead of rect i need to put arc i tried putting that still it was not working.
Kindly help me for the above solution
Thanks & REgards
Mahadevan
You should adjust the height of the cylinder, not the width... And should redraw the cylinder if you are clearing (clearRect) the canvas.
You can try with the following function:
function draw()
{
maxWidth = 180;
maxHeight = 140;
context.clearRect(0, 0, canvas.width, canvas.height);
var x = 190;
var y = 260;
var per = perc;
if(per > 1)perc = 1;
// fill
context.beginPath();
context.fillStyle = 'yellow';
context.rect(x-maxWidth/2, y-maxHeight * perc, maxWidth, maxHeight * perc);
context.fill();
drawCylinder(100, 100, 180, 180);
}
Check working Fiddle demo ...

Categories

Resources