I would like to be able to simulate the movement of the body on a "carousel" with respect to physics. (centripetal, centrifugal force, angular speed). Below is some sample code.
<!DOCTYPE html>
<html>
<head>
<script>
var rotate = Math.PI / 180;
var ballRotation = 1;
function drawthis() {
var friction = 0.5;
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, cvs.width, cvs.height);
context.translate(350, 350);
context.rotate(rotate);
context.beginPath();
context.arc(1, 1, 12, 0, 2 * Math.PI, false);
context.fill();
context.beginPath();
context.arc(0, 0, 150, 0, Math.PI * 2, false);
context.lineWidth = 6;
context.stroke();
motion = ballRotation - friction;
rotate += motion;
requestAnimationFrame(drawthis);
}
function init() {
cvs = document.getElementById("canvas");
context = cvs.getContext("2d");
context.clearRect(0, 0, context.width, context.height);
context.fillStyle = "#ff0000";
requestAnimationFrame(drawthis);
}
</script>
</head>
<body onload="init()">
<canvas id="canvas" width="800" height="800"></canvas>
</body>
</html>
I mean something like this
Ball on a turn table
Below you will find a simple simulation of a point sliding on a turning wheel. The point represents the contact point of a ball.
The simulation ignores the fact that the ball can roll, or has mass.
The ball slides via a simple friction model, where friction is a scalar value applied to the difference between the balls speed vector, and the speed of the wheel at the point under the ball.
There is only 1 force involved. It is the force tangential to the vector from the ball to the wheel center, subtracted by the ball movement vector and then multiplied by the friction coefficient.
For details on how this is calculated see comments in the function ball.update()
Notes
That if the ball starts at the dead center of the wheel nothing will happen.
I could not workout if it was the path of the ball you wanted or just the simulation of the ball, so I added both.
The ball resets after it leaves the wheel.
The wheel is marked with text and center cross so its rotation can be seen.
const ROTATE = Math.PI / 50;
const WHEEL_SIZE = 0.6;
Math.rand = (min, max) => Math.random() * (max - min) + min;
Math.randPow = (min, max, p) => Math.random() ** p * (max - min) + min;
var friction = 0.35;
const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
ctx.font = "30px arial";
ctx.textAlign = "center";
scrollBy(0, canvas.height / 2 - canvas.height / 2 * WHEEL_SIZE);
function mainLoop() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
wheel.update();
ball.update(wheel, arrow);
wheel.draw();
path.draw();
ball.draw();
arrow.draw(ball);
requestAnimationFrame(mainLoop);
}
const path = Object.assign([],{
draw() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.strokeStyle = "#F00";
ctx.lineWidth = 1;
ctx.beginPath();
for (const p of this) { ctx.lineTo(p.x, p.y) }
ctx.stroke();
},
reset() { this.length = 0 },
add(point) {
this.push({x: point.x, y: point.y});
if (this.length > 1000) { // prevent long lines from slowing render
this.shift()
}
}
});
const arrow = {
dx: 0,dy: 0,
draw(ball) {
if (this.dx || this.dy) {
const dir = Math.atan2(this.dy, this.dx);
// len is converted from frame 1/60th second to seconds
const len = Math.hypot(this.dy, this.dx) * 60;
const aXx = Math.cos(dir);
const aXy = Math.sin(dir);
ctx.setTransform(aXx, aXy, -aXy, aXx, ball.x, ball.y);
ctx.beginPath();
ctx.lineTo(0,0);
ctx.lineTo(len, 0);
ctx.moveTo(len - 4, -2);
ctx.lineTo(len, 0);
ctx.lineTo(len - 4, 2);
ctx.strokeStyle = "#FFF";
ctx.lineWidth = 2;
ctx.stroke();
}
}
};
const ball = {
x: canvas.width / 2 + 4,
y: canvas.height / 2,
dx: 0, // delta pos Movement vector
dy: 0,
update(wheel, arrow) {
// get distance from center
const dist = Math.hypot(wheel.x - this.x, wheel.y - this.y);
// zero force arrow
arrow.dx = 0;
arrow.dy = 0;
// check if on wheel
if (dist < wheel.radius) {
// get tangent vector direction
const tangent = Math.atan2(this.y - wheel.y, this.x - wheel.x) + Math.PI * 0.5 * Math.sign(wheel.dr);
// get tangent as vector
// which is distance times wheel rotation in radians.
const tx = Math.cos(tangent) * dist * wheel.dr;
const ty = Math.sin(tangent) * dist * wheel.dr;
// get difference between ball vector and tangent vector scaling by friction
const fx = arrow.dx = (tx - this.dx) * friction;
const fy = arrow.dy = (ty - this.dy) * friction;
// Add the force vector
this.dx += fx;
this.dy += fy;
} else if (dist > wheel.radius * 1.7) { // reset ball
// to ensure ball is off center use random polar coord
const dir = Math.rand(0, Math.PI * 2);
const dist = Math.randPow(1, 20, 2); // add bias to be close to center
this.x = canvas.width / 2 + Math.cos(dir) * dist;
this.y = canvas.height / 2 + Math.sin(dir) * dist;
this.dx = 0;
this.dy = 0;
path.reset();
}
// move the ball
this.x += this.dx;
this.y += this.dy;
path.add(ball);
},
draw() {
ctx.fillStyle = "#0004";
ctx.setTransform(1, 0, 0, 1, this.x + 5, this.y + 5);
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = "#f00";
ctx.setTransform(1, 0, 0, 1, this.x, this.y);
ctx.beginPath();
ctx.arc(0, 0, 12, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = "#FFF8";
ctx.setTransform(1, 0, 0, 1, this.x - 5, this.y - 5);
ctx.beginPath();
ctx.ellipse(0, 0, 2, 3, -Math.PI * 0.75, 0, 2 * Math.PI);
ctx.fill();
},
}
const wheel = {
x: canvas.width / 2, y: canvas.height / 2, r: 0,
dr: ROTATE, // delta rotate
radius: Math.min(canvas.height, canvas.width) / 2 * WHEEL_SIZE,
text: "wheel",
update() { this.r += this.dr },
draw() {
const aXx = Math.cos(this.r);
const aXy = Math.sin(this.r);
ctx.setTransform(aXx, aXy, -aXy, aXx, this.x, this.y);
ctx.fillStyle = "#CCC";
ctx.strokeStyle = "#000";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.arc(0, 0, this.radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.strokeStyle = ctx.fillStyle = "#aaa";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.lineTo(-20,0);
ctx.lineTo(20,0);
ctx.moveTo(0,-20);
ctx.lineTo(0,20);
ctx.stroke();
ctx.fillText(this.text, 0, this.radius - 16);
},
}
<canvas id="canvas" width="300" height="300"></canvas>
Centripetal force
Centripetal is the force towards the center of the turning wheel. However because the ball is sliding the force calculated is not a centripetal force.
You can calculate the centripetal force by scaling the vector from the ball to the center by the dot product of the "vector to center" dot "force vector"
The force vector on the ball is shown as a white arrow. The arrows size is the force as acceleration in pixels per second.
The vector is towards the center but will never point directly at the center of the wheel.
Approximation
This simulation is an approximation. You will need an understanding of calculus and differential equations to get closer to reality.
Using a more complex simulation would only be noticeable if the friction was very close or at 1 and it is easier then to just fix the ball to the wheel, scaling the position from center by an inverse power of the friction coefficient.
Related
I made a simple canvas program that draws a spiral starting from the canvas's center, using a line that constantly has new points drawn. It works until another shape or line is added, and I can't think of any way to fix it. Is there any way to separate these two strokes without using a beginPath() before the lineTo()?
const canvas = document.querySelector("canvas");
canvas.width = innerWidth;
canvas.height = innerHeight;
const c = canvas.getContext("2d");
let x, y;
let i = 0;
const animate = function() {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height);
c.lineTo(x, y);
c.stroke();
// c.beginPath();
// c.beginPath();
// c.arc(canvas.width / 2, canvas.height / 2, 20, 0, Math.PI * 2, false);
// c.strokeStyle = "red";
// c.stroke();
// c.closePath();
x = canvas.width / 2 + Math.cos(i * Math.PI / 180) * i;
y = canvas.height / 2 + Math.sin(i * Math.PI / 180) * i;
i += 5;
}
animate();
The drawing of your spiral is possible because the lineTo() method draws a straight line from the current path's last position to the position given as a parameter. As you realized, this breaks as soon as you add a new path somewhere in-between.
One possible solution is keeping track of the positions that make up the spiral instead of trying to draw it right away. To do this we can fill a simply array with object's holding the x and y values for the spiral's segments.
For example:
const canvas = document.querySelector("canvas");
canvas.width = innerWidth;
canvas.height = innerHeight;
const c = canvas.getContext("2d");
let x, y;
let i = 0;
let points = [];
const animate = function() {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height);
c.beginPath();
c.arc(canvas.width / 2, canvas.height / 2, 20, 0, Math.PI * 2, false);
c.strokeStyle = "red";
c.stroke();
c.closePath();
points.push({
x: canvas.width / 2 + Math.cos(i * Math.PI / 180) * i,
y: canvas.height / 2 + Math.sin(i * Math.PI / 180) * i
});
c.beginPath();
c.strokeStyle = "black";
c.moveTo(points[0].x, points[0].y);
if (points.length > 1) {
for (let a = 0; a < points.length; a++) {
c.lineTo(points[a].x, points[a].y);
}
}
c.stroke();
c.closePath();
i += 5;
}
animate();
<canvas></canvas>
i need help to create a function to create x quant of lines with circles in each end of the line using parameters to define the angle of rotation, width,height and color of the line and fill the space between the lines, the propours of this is making a kind of rotation max and min angle of the human arm and shoulder.
this is a image of ilustrative example what i need to do, the image of the person model is fine in png i need just to create dynamic lines.
this is the code i have so far:
function drawLine(deg,width,height,canvasId,color){
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
ctx.rotate(deg);
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
drawLine(0,200,3,'canvas','red')
drawLine(120,200,3,'canvas1','blue')
canvas{
position: absolute;
}
<canvas id="canvas"></canvas>
<canvas id="canvas1"></canvas>
thanks very much
Based on the picture I will assume 180deg is the reference point of 0. Anything out from there is where we start counting degrees. If that is the case you will want to run a function that calculates the angle between a solid line at 180deg and two other lines from that point.
In total you will need four points. You starting point for all references (pointB in this example), another point (pointD) will be used to set the angle reference to 0 degrees. We will measure the next two angles from this line.
PointA and PointC can be adjusted as needed and we then calculate the angle from pointD/pointB vector. We can use Math.atan2 to calculate the angles of BA and BC move away from BD.
let angle1 = Math.atan2(distBC_x * distBD_y - distBC_y * distBD_x, distBC_x * distBD_x + distBC_y * distBD_y);
In this snippet I changed the color of the lines to make it easier to see what is what. You also won't need to draw the pink line. This is static so you will need to create limits and a dynamic method to change the angles.
Change the x value of pointA and pointC to change the Min and Max. Keep in mind I have to restrictions set for you to be able to switch them.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
//change pointA and pointC x value.
//pointA sould be your Min
//PointC should be your Max
let pointA = {x: 200, y: 250};
let pointB = {x: 250, y: 100}; //common point
let pointC = {x: 120, y: 250};
//only used to set reference to 0 at 180 degrees
let pointD = {x: pointB.x, y: pointB.y + 150};
//creating our vectors length
let distBA_x = pointB.x - pointA.x;
let distBA_y = pointB.y - pointA.y;
let distBC_x = pointB.x - pointC.x;
let distBC_y = pointB.y - pointC.y;
let distBD_x = pointB.x - pointD.x;
let distBD_y = pointB.y - pointD.y;
//calculate angle between pink and purple
let angle1 = Math.atan2(distBC_x * distBD_y - distBC_y * distBD_x, distBC_x * distBD_x + distBC_y * distBD_y);
if(angle1 < 0) {angle1 = angle1 * -1;}
let degree_angle1 = angle1 * (180 / Math.PI);
//calculate angle between purple and red
let angle2 = Math.atan2(distBA_x * distBD_y - distBA_y * distBD_x, distBA_x * distBD_x + distBA_y * distBD_y);
if(angle2 < 0) {angle2 = angle2 * -1;}
let degree_angle2 = angle2 * (180 / Math.PI);
function draw() {
ctx.textStyle = 'black';
ctx.font = '20px Arial';
ctx.fillText('Max = '+ degree_angle1, 100, 20);
ctx.fillText('Min = '+ degree_angle2, 100, 50);
//Lines
ctx.strokeStyle = 'purple';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(pointA.x, pointA.y);
ctx.lineTo(pointB.x, pointB.y);
ctx.stroke();
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(pointB.x, pointB.y);
ctx.lineTo(pointC.x, pointC.y);
ctx.stroke();
ctx.strokeStyle = 'pink';
ctx.beginPath();
ctx.moveTo(pointB.x, pointB.y);
ctx.lineTo(pointD.x, pointD.y);
ctx.stroke();
//Points
ctx.fillStyle = 'purple';
ctx.beginPath();
ctx.arc(pointB.x, pointB.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(pointA.x, pointA.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(pointC.x, pointC.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
//Fill
ctx.fillStyle = 'rgba(113, 0, 158, 0.3)'
ctx.beginPath();
ctx.moveTo(pointA.x, pointA.y);
ctx.lineTo(pointB.x, pointB.y);
ctx.lineTo(pointC.x, pointC.y);
ctx.fill();
ctx.closePath();
}
draw()
<canvas id='canvas'></canvas>
I want to rotate a triangle in the center of itself.
I have this script:
var ctx = canvas.getContext('2d');
var angle = 30;
setInterval(rotate, 50);
function rotate() {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(150, 150); // x, y
ctx.rotate(angle * Math.PI / 180)
ctx.fillStyle = "yellow";
var path=new Path2D();
path.moveTo(-50+50,-25);
path.lineTo(-50,-50-25);
path.lineTo(-50-50,-25);
ctx.fill(path);
ctx.restore();
angle++;
}
<canvas id="canvas" width="1800" height="700"></canvas>
It rotates it, but not in the center. I want it to look like this:
var ctx = canvas.getContext('2d');
setInterval(rotate, 50);
var angle = 30;
function rotate() {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(50, 50);
ctx.rotate(angle * Math.PI / 180)
ctx.fillStyle = "green";
ctx.fillRect(-25, -25, 50, 50);
ctx.restore();
angle++;
}
<canvas id="canvas" width="1800" height="700"></canvas>
I think, I just have to get the width and hight of the triangle and devive it by 2, but I don't know, how to do that.
Thx for every answer!
What you want is the centroid of your shape.
var ctx = canvas.getContext('2d');
var angle = 30;
var points = [
{x:0, y:-25},
{x:-50, y:-75},
{x:-100, y:-25}
];
// first sum it all
var sums = points.reduce( (sum, point) => {
sum.x += point.x;
sum.y += point.y;
return sum;
}, {x:0, y:0});
// we want the mean
var centroid = {
x: sums.x / points.length,
y: sums.y / points.length
};
rotate();
function rotate() {
ctx.setTransform(1,0,0,1,0,0);
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// general position in canvas
ctx.translate(100, 100);
// move to centroid of our triangle
ctx.translate(centroid.x, centroid.y); // x, y
// rotate
ctx.rotate(angle * Math.PI / 180)
// go back to our initial position
ctx.translate(-centroid.x, -centroid.y); // x, y
ctx.fillStyle = "yellow";
var path=new Path2D();
path.moveTo(points[0].x, points[0].y);
path.lineTo(points[1].x, points[1].y);
path.lineTo(points[2].x, points[2].y);
ctx.fill(path);
// demo only
ctx.beginPath();
ctx.arc(centroid.x, centroid.y, 50, 0, Math.PI*2)
ctx.stroke();
angle++;
requestAnimationFrame( rotate );
}
<canvas id="canvas" width="1800" height="700"></canvas>
Create the Path once
You are using a Path2D object which is reusable.
If you create the triangle already centered on its origin (or any path for that matter) it is then trivial to rotate it.
Reusing the path object is also a lot quicker if you have a lot to render.
The function to creates a path from a set of points. It automatically centers the path to its own origin (defined by the mean of its points)
const point = (x, y) => ({x, y});
function createPath(...points) {
var cx = 0; cy = 0;
for (const p of points) {
cx += p.x;
cy += p.y;
}
cx /= points.length;
cy /= points.length;
const path = new Path2d;
for (const p of points) { path.lineTo(p.x - cx, p.y - cy); }
path.closePath();
return path;
}
To create the triangle
const triangle = createPath(point(0,-25), point(-50,-75), point(-100,-25));
Then you can render it rotated about its own origin with
function drawPath(path, x, y, angle) {
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(angle);
ctx.stroke(path);
}
Example
Shows how to create various shapes centered on their means. Each shape is a path created once and then rendered as needed.
const point = (x, y) => ({x, y});
const triangle = createPath(point(0,-25), point(-50,-75), point(-100,-25));
const rectangle = createPath(point(0,-25), point(-50,-25), point(-50,-125), point(0,-125));
const thing = createPath(point(0,-12), point(-25,-12), point(-25,-62), point(0,-62), point(22,-35));
function drawPath(path, x, y, angle) {
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(angle);
ctx.stroke(path);
}
function drawPath_V2(path, x, y, scale, angle, strokeStyle, fillStyle) {
ctx.setTransform(scale, 0, 0, scale, x, y);
ctx.rotate(angle);
fillStyle && (ctx.fillStyle = fillStyle, ctx.fill(path));
strokeStyle && (ctx.strokeStyle = strokeStyle, ctx.stroke(path));
}
function renderLoop(time) {
ctx.clearRect(0, 0, can.width, can.height);
const scale = Math.sin(time / 500) * 0.2 + 1.0;
const scale2 = Math.cos(time / 1000) * 0.4 + 1.0;
drawPath(triangle, 75, 74, time / 1000 * Math.PI); //360 every 2 second
// scale path
drawPath_V2(rectangle, 125, 125, scale, time / 2000 * Math.PI, "black"); //360 every 4 second
// fill scale path
drawPath_V2(thing, 125, 100, scale2, time / 3000 * Math.PI, "", "black");
ctx.setTransform(1, 0, 0, 1, 0, 0);
requestAnimationFrame(renderLoop);
}
requestAnimationFrame(renderLoop);
const can = Object.assign(document.createElement("canvas"), {width: 200, height: 200});
document.body.appendChild(can);
const ctx = can.getContext("2d");
function createPath(...points) {
var cx = 0; cy = 0;
for (const p of points) {
cx += p.x;
cy += p.y;
}
cx /= points.length;
cy /= points.length;
const path = new Path2D;
for (const p of points) {
path.lineTo(p.x - cx , p.y - cy);
}
path.closePath();
return path;
}
I am making a solar system with pre-made planets and want to know how to get more than one to rotate around the sun. I ran into the issue of not being able to rotate 2 at once. Any solutions?Here is current code:
Orbiting page:
var canvasP = document.getElementById("planetsOrbit");
var ctx2 = canvasP.getContext("2d");
var angle = 6 * Math.PI / 180;
var cx = window.innerWidth / 2;
var cy = window.innerHeight / 2.12;
var radiusNew = (window.innerHeight + window.innerWidth) * 0.15;
function resizeCanvasPOrbit() {
ctx2.clearRect(0, 0, canvasP.width, canvasP.height);
if (canvasP.width < window.innerWidth) {
canvasP.width = window.innerWidth * 0.99;
}'
if (canvasP.height < window.innerHeight)
{
canvasP.height = window.innerHeight * 0.98;
}
w = canvasP.width
h = canvasP.height
}
function draw(x, y) {
ctx2.clearRect(0, 0, w, h);
ctx2.save();
ctx2.beginPath();
ctx2.beginPath();
roa(x, y, window.innerHeight * window.innerWidth * 0.00008);
ctx2.stroke();
ctx2.restore();
};
function keepDrawing() {
ctx2.clearRect(0, 0, w, h);
draw(newX, newY);
setTimeout(keepDrawing, 250);
}
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 5000 / 60);
};
})();
var fps = 60;
function animate() {
setTimeout(function () {
requestAnimationFrame(animate);
// increase the angle of rotation A.K.A SPEED!
angle += 1 * Math.PI / 3600;
//calculate the new ball.x / ball.y
var newX = cx - radiusNew * Math.cos(angle);
var newY = cy + radiusNew * Math.sin(angle);
//draw
ctx2.clearRect(0, 0, w, h);
draw(newX, newY);
//draw the centerpoint
ctx2.beginPath();
ctx2.arc(cx, cy, radiusNew, 0, Math.PI * 2, false);
ctx2.closePath();
}, 1000 / fps);
}
animate();
and the Premade Planets:
//sun
solus = function(xAxis, yAxis, radius) {
ctx.shadowBlur=400
ctx.shadowColor="red"
ctx.fillStyle ="#ff9900";
ctx.beginPath();
ctx.arc(xAxis, yAxis, radius, 0, Math.PI * 2, false)
ctx.fill();
ctx.shadowBlur = 0;
}
//Fighting Pits
pits = function(xAxis, yAxis, radius) {
ctx.beginPath();
ctx.fillStyle ="#990000"
ctx.arc(xAxis, yAxis, radius, 0, Math.PI , false)
ctx.moveTo(xSpot1,ySpot1)
ctx.lineTo(xSpot1,ySpot2)
ctx.lineTo(xSpot2,ySpot2)
ctx.lineTo(xSpot2,ySpot3)
ctx.lineTo(xSpot3,ySpot4)
ctx.lineTo(xSpot4,ySpot3)
ctx.lineTo(xSpot4,ySpot2)
ctx.lineTo(xSpot5,ySpot2)
ctx.lineTo(xSpot5,ySpot1)
ctx.lineTo(xSpot1,ySpot1)
ctx.fill();
}
//Water Planet
roa = function(xAxis, yAxis, radius) {
ctx2.shadowBlur = 0;
ctx2.beginPath();
ctx2.fillStyle ="#00ffff"
ctx2.arc(xAxis, yAxis, radius, 0, Math.PI * 2, false)
ctx2.fill();
}
//Forest planet atmoshpere
eldridA = function(xAxis, yAxis, radius) {
ctx.beginPath();
ctx.fillStyle ="rgba(230, 230, 230, 0.3)";
ctx.arc(xAxis, yAxis, radius, 0, Math.PI * 2, false)
ctx.fill();
}
//forest core
eldrid = function(xAxis, yAxis, radius) {
ctx.shadowColor = "rgba(230, 230, 230, 0.2)";
ctx.shadowBlur = 200;
ctx.beginPath();
ctx.fillStyle ="#ff9900"
ctx.arc(xAxis, yAxis, radius / 2, 0, Math.PI * 2, false)
ctx.fill();
xAxis2 = xAxis - window.innerWidth * 0.009
yAxis2 = yAxis + window.innerHeight * 0.007
ctx.arc(xAxis2, yAxis2, radius / 4, 0, Math.PI * 2, false)
ctx.fill();
ctx.beginPath();
xAxis3 = xAxis + window.innerWidth * 0.011
ctx.arc(xAxis3 , yAxis2, radius / 3, 0, Math.PI * 2, false)
ctx.fill();
ctx.beginPath();
yAxis3 = yAxis - window.innerHeight * 0.03
ctx.arc(xAxis, yAxis3, radius / 3, 0, Math.PI * 2, false)
ctx.fill();
ctx.shadowBlur = 0;
ctx.shadowColor = null;
}
So how can I get more than one planet to orbit the Sun? any Help is appreciated.
I did a simple demo of a solar system with multiple planets using canvas: http://codepen.io/giladaya/pen/PWWKLP
I believe that you can easily adapt it to your needs and I'll explain the main parts of the code:
Each planet has it's own properties like radius, distance from center, radial velocity and a reference to a draw function.
var planets = [
{
name: 'sun', // for reference
rad: 30, // Planet radius
distance: 0, // Planet distance from center
rv: 0, // radial velocity (deg/sec)
drawFunc: drawSun // draw function
},
{
name: 'foo',
rad: 10,
distance: 70,
rv: 1,
drawFunc: drawBlue
},
{
name: 'bar',
rad: 15,
distance: 100,
rv: 2,
drawFunc: drawRed
}
];
The main loop iterates over all the planets, updates their current angle according to the radial velocity and draws each one in it's new, updated location.
function draw() {
ctx.fillRect(-cW/2, -cH/2, cW, cH);
var now = Date.now(),
dts = (now - lastFrameTime) / 1000;
planets.forEach(function(planet, idx){
var theta = 0;
planetsAngle[idx] += planet.rv/Math.PI * dts;
theta = planetsAngle[idx];
var x = planet.distance * Math.cos(theta);
var y = planet.distance * Math.sin(theta);
planet.drawFunc(ctx, x, y, planet.rad);
});
lastFrameTime = now;
requestAnimationFrame(draw);
}
Note that if using requestAnimationFrame, you don't need to set timers.
The draw function for each planet can be as complicated as you want in order to have more elements on the planet. For example:
function drawRed(ctx, x, y, rad) {
ctx.save();
ctx.fillStyle = 'red';
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(0, 0, rad, 0, 2*Math.PI , false);
ctx.fill();
ctx.fillStyle = '#A00';
ctx.fillRect(-4, -4, 8, 8);
ctx.restore();
}
I have a basic JSFiddle whereby I want to have random points plotted inside a circle.
But I do not know how to limit the points to be inside the circle.
This is what I currently have:
var ctx = canvas.getContext('2d'),
count = 1000, // number of random points
cx = 150,
cy = 150,
radius = 148;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(canvas.width/2, canvas.height/2, radius, 0, 2*Math.PI);
ctx.closePath();
ctx.fillStyle = '#00000';
ctx.fill();
// create random points
ctx.fillStyle = '#ffffff';
while(count) {
// randomise x:y
ctx.fillRect(x + canvas.width/2, y + canvas.height/2, 2, 2);
count--;
}
How would i go about generating random (x,y) coordinates to plot random points inside the circle?
My current fiddle: http://jsfiddle.net/e8jqdxp3/
To plot points randomly in a circle, you can pick a random value from the radius squared, then square root it, pick a random angle, and convert the polar coordinate to rectangular. The square / square root step ensures that we get a uniform distribution (otherwise most points would be near the center of the circle).
So the formula to plot a random point in the circle is the following, where r' is a random value between 0 and r2, and θ is a random value between 0 and 2π:
Screenshot of result:
Live Demo:
var canvas = document.getElementById("thecanvas");
var ctx = canvas.getContext('2d'),
count = 1000, // number of random points
cx = 150,
cy = 150,
radius = 148;
ctx.fillStyle = '#CCCCCC';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
// create random points
ctx.fillStyle = '#ffffff';
while (count) {
var pt_angle = Math.random() * 2 * Math.PI;
var pt_radius_sq = Math.random() * radius * radius;
var pt_x = Math.sqrt(pt_radius_sq) * Math.cos(pt_angle);
var pt_y = Math.sqrt(pt_radius_sq) * Math.sin(pt_angle);
ctx.fillRect(pt_x + canvas.width / 2, pt_y + canvas.width / 2, 2, 2);
count--;
}
<canvas id="thecanvas" width="400" height="400"></canvas>
JSFiddle Version: https://jsfiddle.net/qc735bqw/
Randomly pick dSquared (0..radius^2) and theta (0..2pi), then
x = sqrt(dSquared) cos(theta)
y = sqrt(dSquared) sin(theta)
JSFiddle
var ctx = canvas.getContext('2d'),
count = 1000, // number of random points
cx = canvas.width/2,
cy = canvas.height/2,
radius = 148;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(0+canvas.width/2, 0+canvas.height/2, radius, 0, 2*Math.PI);
ctx.closePath();
ctx.fillStyle = '#00000';
ctx.fill();
ctx.fillStyle = '#ffffff';
while(count) {
var x = Math.random() * canvas.width;
var y = Math.random() * canvas.height;
var xDiff = cx - x;
var yDiff = cy - y;
if(Math.sqrt(xDiff*xDiff+yDiff*yDiff)<radius)
{
ctx.fillRect(x, y, 2, 2);
count--;
}
}
This worked for me:
const getRandomCoordinateInCircle = radius => {
var angle = Math.random() * Math.PI * 2;
const x = Math.cos(angle) * radius * Math.random();
const y = Math.sin(angle) * radius * Math.random();
return { x, y };
};
console.log(getRandomCoordinateInCircle(1000);
// { x: 118.35662725763385, y: -52.60516556856313 }
Returns a random point with { x: 0, y: 0} as the centre of the circle.