Rotate a triangle in the cente of itself - javascript

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;
}

Related

Simulation of the rotation angular speed

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.

How to get coordinates of every circle from this Canvas

I need to create a pattern where 5 circles connected by lines to a middle main circle.
So I have created dynamically by rotating in some certain angle. Now I need each and every circle's x and y axis coordinates for capturing the click events on every circle.
Please help me how to find out of coordinates of every circle?
var canvas, ctx;
function createCanvasPainting() {
canvas = document.getElementById('myCanvas');
if (!canvas || !canvas.getContext) {
return false;
}
canvas.width = 600;
canvas.height = 600;
ctx = canvas.getContext('2d');
ctx.strokeStyle = '#B8D9FE';
ctx.fillStyle = '#B8D9FE';
ctx.translate(300, 250);
ctx.arc(0, 0, 50, 0, Math.PI * 2); //center circle
ctx.stroke();
ctx.fill();
drawChildCircles(5);
fillTextMultiLine('Test Data', 0, 0);
drawTextInsideCircles(5);
}
function drawTextInsideCircles(n) {
let ang_unit = Math.PI * 2 / n;
ctx.save();
for (var i = 0; i < n; i++) {
ctx.rotate(ang_unit);
//ctx.moveTo(0,0);
fillTextMultiLine('Test Data', 200, 0);
ctx.strokeStyle = '#B8D9FE';
ctx.fillStyle = '#B8D9FE';
}
ctx.restore();
}
function drawChildCircles(n) {
let ang_unit = Math.PI * 2 / n;
ctx.save();
for (var i = 0; i < n; ++i) {
ctx.rotate(ang_unit);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.arc(200, 0, 40, 0, Math.PI * 2);
let newW = ctx.fill();
ctx.stroke();
}
ctx.restore();
}
function fillTextMultiLine(text, x, y) {
ctx.font = 'bold 13pt Calibri';
ctx.textAlign = 'center';
ctx.fillStyle = "#FFFFFF";
// Defining the `textBaseline`…
ctx.textBaseline = "middle";
var lineHeight = ctx.measureText("M").width * 1.2;
var lines = text.split("\n");
for (var i = 0; i < lines.length; ++i) {
// console.log(lines);
if (lines.length > 1) {
if (i == 0) {
y -= lineHeight;
} else {
y += lineHeight;
}
}
ctx.fillText(lines[i], x, y);
}
}
createCanvasPainting();
<canvas id="myCanvas"></canvas>
The problem here is that you are rotating the canvas matrix and your circles are not aware of their absolute positions.
Why don't you use some simple trigonometry to determine the center of your circle and the ending of the connecting lines ?
function lineToAngle(ctx, x1, y1, length, angle) {
angle *= Math.PI / 180;
var x2 = x1 + length * Math.cos(angle),
y2 = y1 + length * Math.sin(angle);
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
return {x: x2, y: y2};
}
Ref: Finding coordinates after canvas Rotation
After that, given the xy center of your circles, calculating if a coord is inside a circle, you can apply the following formula:
Math.sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)) < r
Ref: Detect if user clicks inside a circle

Rotate circle around triangle canvas

I want to spin a circle around a triangle using canvas. Have this code from earlier, but here is the circle in the middle, and a rectangle spinning, i want the circle to spin and have a triangle in the middle. Can someone help?
Here is the JS code i have:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cx = 100;
var cy = 100;
var rectWidth = 15;
var rectHeight = 10;
var rotation = 0;
requestAnimationFrame(animate);
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(cx, cy, 10, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rotation);
ctx.strokeRect(-rectWidth / 2 + 20, -rectHeight / 2, rectWidth, rectHeight);
ctx.restore();
rotation += Math.PI / 180;
}
<canvas id="canvas"></canvas>
I have edited your code to draw the requested shapes and added comments to describe, what i am doing in the snippet below.
var canvas = document.body.appendChild(document.createElement("canvas"));
var ctx = canvas.getContext("2d");
var cx = 100;
var cy = 100;
var rotation = 0;
requestAnimationFrame(animate);
function animate() {
//Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Draw center figure
/*
ctx.beginPath();
ctx.arc(cx, cy, 10, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
*/
ctx.beginPath();
ctx.moveTo(cx - 10, cy - 10);
ctx.lineTo(cx, cy + 10);
ctx.lineTo(cx + 10, cy - 10);
ctx.closePath();
ctx.fill();
//Rotate canvas
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rotation);
//Draw rotating object
/*ctx.strokeRect(-rectWidth / 2 + 20, -rectHeight / 2, rectWidth, rectHeight);*/
ctx.beginPath();
ctx.arc(20, 0, 5, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
//Rotate canvas back
ctx.restore();
//Save rotation
rotation += Math.PI / 180;
//Request next frame
requestAnimationFrame(animate);
}
It sounds like you lack experience with HTML Canvas manipulation, so i would like to recommend some MDN's official canvas tutorial.
If you have further questions feel free to open new questions with more code-specific problems in the future.
Here is an alternative to moving objects without using the ctx.translate or the ctx.rotate
We can use Math.sin and Math.cos to move around in a circular or elliptical motion.
Once you understand this approach you open the door for many possibilities, for example you can make the spins relative to other objects.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var rotation = 0;
setInterval(animate, 10);
function animate(rx, ry, speed) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw(120, 80, 1)
draw(240, 80, 10/3)
}
function draw(rx, ry, speed) {
var x = Math.cos(rotation) * 50 + rx
var y = Math.sin(rotation) * 50 + ry
ctx.beginPath()
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.stroke();
for (var i = 1; i < 8; i++) {
x += Math.sin(rotation * i/speed) * 20
y += Math.cos(rotation * i/speed) * 20/i
ctx.beginPath()
ctx.arc(x, y, 8/i, 0, Math.PI * 2);
ctx.stroke();
}
rotation += Math.PI / 180;
}
<canvas id="canvas" height=170 width=400></canvas>
Try the following:
<code>
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cx=100;
var cy=100;
var rectWidth=15;
var rectHeight=10;
var rotation=0;
requestAnimationFrame(animate);
function animate(){
requestAnimationFrame(animate);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
var radius = 8;
ctx.moveTo(cx - radius, cy + radius);
ctx.lineTo(cx, cy - radius);
ctx.lineTo(cx + radius , cy + radius);
ctx.lineTo(cx - radius, cy + radius);
ctx.fill();
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(rotation);
ctx.strokeRect(-rectWidth/2+20,-rectHeight/2,rectWidth,rectHeight);
ctx.restore();
rotation+=Math.PI/180;
}
</code>

Use image to fill in arc in canvas using javascript

So I am totally new to canvas and trying a project in which I need to make small balls move around with their background as images. Following code is what I am trying right now.
ctx.beginPath();
ctx.arc(
this.pos[0], this.pos[1], this.radius, 0, 2 * Math.PI, true
);
let tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
let ballbackground = new Image();
if (this.color === "green") {
ballbackground.src = "https://s26.postimg.cc/fl2vwj1mh/greenball.png";
}
else if (this.color === "yellow") {
ballbackground.src = "https://s26.postimg.cc/if61a18yh/yellowball.png";
}
else if (this.color === "blue") {
ballbackground.src = "https://s26.postimg.cc/xb4khn7ih/blueball.jpg";
}
tempCanvas.width = 50;
tempCanvas.height = 50;
tCtx.drawImage(ballbackground,0,0,ballbackground.width, ballbackground.height,0,0,50,50);
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
And for moving those balls I do as follows:
const velocityScale = timeDelta / NORMAL_FRAME_TIME_DELTA,
offsetX = this.vel[0] * velocityScale * this.speed,
offsetY = this.vel[1] * velocityScale * this.speed;
this.pos = [this.pos[0] + offsetX, this.pos[1] + offsetY];
However, the problem is when objects move they seem like sliding over background image like so:
If I try "no-repeat" with createPattern, the balls won't display at all.
What I want is those balls with background images moving on the canvas?
move the balls by using the canvas transform?
const ctx = document.querySelector("canvas").getContext("2d");
const pattern = createPattern(ctx);
function drawCircleByPosition(ctx, x, y) {
ctx.beginPath();
ctx.arc(x, y, 50, 0, Math.PI * 2, true);
ctx.fill();
}
function drawCircleByTransform(ctx, x, y) {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(0, 0, 50, 0, Math.PI * 2, true);
ctx.fill();
ctx.restore();
}
function render(time) {
time *= 0.001;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = pattern;
drawCircleByPosition(ctx, 90, 75 + Math.sin(time) * 50);
drawCircleByTransform(ctx, 210, 75 + Math.sin(time) * 50);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function createPattern(ctx) {
const tCtx = document.createElement("canvas").getContext("2d");
tCtx.canvas.width = 50;
tCtx.canvas.height = 50;
tCtx.fillStyle = "yellow";
tCtx.fillRect(0, 0, 50, 50);
for (let x = 0; x < 50; x += 20) {
tCtx.fillStyle = "red";
tCtx.fillRect(x, 0, 10, 50);
tCtx.fillStyle = "blue";
tCtx.fillRect(0, x, 50, 10);
}
return ctx.createPattern(tCtx.canvas, "repeat");
}
canvas { border: 1px solid black; }
<canvas></canvas>
note that rather than call save and restore you can also just set the transform with setTransform which is probably faster since save and restore saves all state (fillStyle, strokeStyle, font, globalCompositeOperation, lineWidth, etc...).
You can either pass in your own matrix. Example
ctx.setTransform(1, 0, 0, 1, x, y); // for translation
and/or you can reset it to the default whenever and then use the standard transform manipulation functions
ctx.setTransform(1, 0, 0, 1, 0, 0); // the default
ctx.translate(x, y);
or whatever combination of things you want to do.

Simplest way to plot points randomly inside a circle

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.

Categories

Resources