Rotate rectangle around center on mouse drag - javascript

I want to make a rectangle rotate around its center as in this code. The problem is that the rectangle rotates on mouse drag on any area.
I want the rectangle to rotate on its position when the mouse drags it only not any mouse drag rotates it.
I am using the p5.js library.
If there any code that rotates rectangle around its center on the mouse drag that please share it with me.
Link of code: https://editor.p5js.org/jwglazebrook/sketches/p2pnhPSZE
let angle = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
push();
translate(150, 150);
rotate(angle);
stroke(0);
strokeWeight(2);
rect(-100, -75, 200, 150);
stroke(255, 0, 0);
strokeWeight(5);
line(-100, -75, 100, -75);
stroke(0, 255, 0);
point(0, 0);
pop();
}
function mouseDragged() {
m_angle = atan2(mouseY - 150, mouseX - 150);
angle = /* MAGIC FORMULA HERE */ m_angle;
}
Code of 2 circle
let angle = 0.6;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(204, 226, 225); // Light blue color
fill(204, 226, 225); // Blue color
push();
translate(150, 150);
rotate(angle);
circle(-50,0,100);
circle(50,0,100);
pop();
line(100, 100, 200, 200);
}
function mouseDragged() {
m_angle = atan2(mouseY - 150, mouseX - 150);
angle = m_angle;
}

Related

How to draw line slowly from a point to another point in P5?

I am using p5.js to draw a simple line.
function setup() {
//createCanvas(windowWidth, windowHeight);
createCanvas(400, 200);
}
function draw() {
background(255, 255, 255);
fill(255, 0, 0);
stroke(255, 0, 0);
strokeWeight(1);
line(0, 0, 250, 100);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
But the line drawn suddenly at once.
How can I draw the line slowly / gradually? (i.e in 300 milliseconds).
That it looks like animating from point(0,0) to point(250,100).
I had a quick look at p5 and it looks like it calls the draw method at intervals. If you want movement to happen you just need to program it.
I've put together a quick example below. I think it's drawing a lot slower than you want but I'm not sure how often p5 calls draw.
var position = 0,
end = 300;
function setup() {
//createCanvas(windowWidth, windowHeight);
createCanvas(400, 200);
}
function draw() {
background(255, 255, 255);
fill(255, 0, 0);
stroke(255, 0, 0);
strokeWeight(1);
var xEnd = 250,
yEnd = 100;
// Got to the end yet?
if (position < end) {
// Work out positions.
xEnd = (xEnd / end) * position;
yEnd = (yEnd / end) * position;
}
line(0, 0, xEnd, yEnd);
// Increment position.
position++;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
FrameRate can be used to adjust the speed of a drawing. This sketch draws a diagonal line that begins slowly at point 0,0 and then speeds up until it reaches point 250, 100.
var x = 0;
function setup() {
createCanvas(400, 200);
frameRate(10);
}
function draw() {
background(255, 255, 255);
fill(255, 0, 0);
stroke(255, 0, 0);
strokeWeight(1);
// y = mx + b
line(0, 0, x, 100/250*x);
x++;
if (x > 50){
frameRate(30);
}
if (x > 250){
noLoop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script>

Use mouse to rotate a rectangle

I have the rectangle pointing at the mouse. What I want: when I lift the mouse and click and drag that the rectangle rotates further.
Or that I can click on any corner to rotate the rectangle. Just like you would with your finger and a sheet of paper.
let angle = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
push();
translate(150, 150);
rotate(angle);
stroke(0);
strokeWeight(2);
rect(-100, -75, 200, 150);
stroke(255, 0, 0);
strokeWeight(5);
line(-100, -75, 100, -75);
stroke(0, 255, 0);
point(0, 0);
pop();
}
function mouseDragged() {
m_angle = atan2(mouseY - 150, mouseX - 150);
angle = /* MAGIC FORMULA HERE */ m_angle;
}
https://editor.p5js.org/jwglazebrook/sketches/p2pnhPSZE
The Problem:
The issue with your code is that you need to store the offset from the initial mouse click to the new dragged point.
The Solution:
To fix the jerky behavior we just have to store the previous mouse angle and box angle and compare the difference with the dragged mouse angle.
The Code:
let angle = 0;
function setup() {
angleMode(DEGREES);
createCanvas(400, 400);
}
function draw() {
background(220);
push();
translate(150, 150);
rotate(angle);
stroke(0);
strokeWeight(2);
rect(-100, -75, 200, 150);
stroke(255, 0, 0);
strokeWeight(5);
line(-100, -75, 100, -75);
stroke(0, 255, 0);
point(0, 0);
pop();
}
let c_angle = 0;
let q_angle = 0;
function mousePressed() {
c_angle = atan2(mouseY - 150, mouseX - 150); //The initial mouse rotation
q_angle = angle; //Initial box rotation
}
function mouseDragged() {
m_angle = atan2(mouseY - 150, mouseX - 150);
let dangle = m_angle - c_angle; //How much the box needs to be rotated
if (dangle>=360) dangle-=360; //clamping
if (dangle<0) dangle+=360; //clamping
angle = q_angle + dangle; //Apply the rotation
if (angle>=360) angle -= 360; //clamping
}

How to rotate a canvas by following mouse if the canvas already has something drawn on it

I currently have a canvas that has an element drawn on it that I draw using a custom function and the onload function I would like to know how to be able to rotate this canvas around by following the mouse 360 degrees like turning a wheel. The code is as follows
<!DOCTYPE html>
<html>
<head>
<title>Help</title>
</head>
<body>
<canvas id="MyCanvas" width="500" height="500"></canvas>
<script>
var ctx = document.getElementById("MyCanvas").getContext("2d");
ctx.translate(250,250);
function draw(){
ctx.arc(0,0,100,0,Math.PI*2,false); // x, y, radius, start angle, end angle, false/true
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-100,0);
ctx.lineTo(100,0);
ctx.moveTo(100,0);
ctx.lineTo(60,-80);
ctx.moveTo(60,-80);
ctx.lineTo(-100,0);
ctx.stroke();
}
window.onload=draw;
</script>
</body>
</html>
Does anyone know how this would be possible I have tried multiple different functions. however, they do not seem to be able to do anything.
help will be very appreciated.
Edited but with slight issue
<!DOCTYPE html>
<html>
<head>
<title>Help</title>
</head>
<style>
canvas{
border: 2px solid black;
}
</style>
<body>
<canvas id="Canvas" height="300"></canvas>
<script>
const ctx = canvas.getContext("2d");
const mouse = { x: 0, y: 0 };
function mouseEvents(e) {
const bounds = canvas.getBoundingClientRect();
mouse.x = e.pageX - bounds.left - scrollX;
mouse.y = e.pageY - bounds.top - scrollY;
}
document.addEventListener("mousemove", mouseEvents);
function drawRotated(x, y, angle) {
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(angle);
ctx.beginPath();
ctx.arc(0, 0, 100, 0, Math.PI * 2);
ctx.moveTo(-100, 0);
ctx.lineTo(100, 0);
ctx.lineTo(60, -80);
ctx.closePath();
ctx.stroke();
}
function update(timer) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.clearRect(0, 0, 300, 300);
var angle = Math.atan2(mouse.y - 150, mouse.x - 150);
drawRotated(150, 150, angle);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
</script>
</body>
</html>
You need to create a mouse move listener, and an animation loop.
In the animation loop get the mouse position and use Math.atan2( to get the direction from the center canvas to the mouse.
Then set the transform with ctx.setTransform to scale and position the designs rotation center, and then use ctx.rotate to rotate the transform to point along the angle computed.
See snippet for more details
const ctx = canvas.getContext("2d");
// create mouse event listener
const mouse = { x: 0, y: 0 };
function mouseEvents(e) {
const bounds = canvas.getBoundingClientRect();
mouse.x = e.pageX - bounds.left - scrollX;
mouse.y = e.pageY - bounds.top - scrollY;
}
document.addEventListener("mousemove", mouseEvents);
// draw design at x,y and rotated by angle
function drawRotated(x, y, angle) {
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(angle);
ctx.beginPath();
ctx.arc(0, 0, 100, 0, Math.PI * 2);
ctx.moveTo(-100, 0);
ctx.lineTo(100, 0);
ctx.lineTo(60, -80);
ctx.closePath();
ctx.stroke();
}
// render loop called 60 times a second
function update(timer) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.clearRect(0, 0, 300, 300);
// get angle from center to mouse
var angle = Math.atan2(mouse.y - 150, mouse.x - 150);
// draw rotated design
drawRotated(150, 150, angle);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
canvas {
border: 2px solid black;
}
<canvas id="canvas" height=300></canvas>

Trying to get responsive window and shapes using p5.js

I'm making my way through JavaScript tutorials (using p5.js) and was interested in coding a responsive screen with four shapes that scale down and stick next to each other while doing so.
Is defining a separate variable for y enough, or would it be better to redefine all the shapes by a new set of x and y variables? Window height/width seems like it should be the correct code to use.
My code:
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
}
function draw() {
background(200);
noStroke();
var labelw = window.innerWidth/8;
var labelh = labelw/4;
var sectionw = window.innerWidth;
var sectionh = window.innerHeight;
// Red
if(window.innerWidth/2 < window.innerHeight){
fill(200, 50, 50);
rect(0, 0, sectionw/2, sectionw/4)
}
// Blue
if(window.innerWidth/2 < window.innerHeight){
fill(50, 50, 200);
rect(sectionw/2, 0, sectionw/2, sectionw/4)
}
// Green
if(window.innerWidth/2 < window.innerHeight){
fill(130, 230, 130);
rect(0, sectionh/2, sectionw/2, sectionw/4)
}
// Purple
if(window.innerWidth/2 < window.innerHeight){
fill(190, 100, 230);
rect(sectionw/2, sectionh/2, sectionw/2, sectionw/4)
}
// label1
fill(50)
rect(0, 0, labelw, labelh)
fill(255);
textSize(labelw/10);
text("Test Label\nTestIdeo, 19xx-20xx",0, 0, 200, 200);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
<html>
<head></head>
<body></body>
</html>
You need to do two things:
First, you need to detect when the screen is resized, and resize the canvas when that happens. The windowResized() and resizeCanvas() functions come in handy for that. See the reference for more info.
Second, you just need to use the width and height variables to draw your shapes. The width and height variables are automatically updated when you resize the canvas.
Putting it all together, it would look like this:
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
fill(255, 0, 0);
rect(0, 0, width/2, height/2);
fill(0, 255, 0);
rect(width/2, 0, width/2, height/2);
fill(0, 0, 255);
rect(0, height/2, width/2, height/2);
fill(255, 255, 0);
rect(width/2, height/2, width/2, height/2);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}

Filling a shape procedurally with more than one color

I'm making an app with node,js,etc. I'd like to fill custom shapes I can create either via data points or another format with different, layered colors. For example, I have a triangle. I want to fill the bottom 1/3 with red, the middle 1/3 with blue, and the top 1/3 with green. How would I go about this?
I'm looking at Paper.js and the basic canvas, but they seem to only have single color fills.
Thanks for any advice!
I am aware of that an answer has been accepted, but I wanted to present a very simple approach for future readers. Which, as a bonus, automatically calculates the height of each part and is fast, using a linear gradient -
Result will be
Code and demo
var ctx = document.querySelector("canvas").getContext("2d"),
grad = ctx.createLinearGradient(0, 0, 0, 150);
grad.addColorStop(0, "red"); // start of red
grad.addColorStop(1/3, "red"); // end of red at 1/3
grad.addColorStop(1/3, "gold"); // start of gold at 1/3
grad.addColorStop(2/3, "gold"); // end of gold at 2/3
grad.addColorStop(2/3, "blue"); // start of blue at 2/3
grad.addColorStop(1, "blue"); // end of blue at 3/3
// Fill a triangle:
ctx.moveTo(75, 0); ctx.lineTo(150, 150); ctx.lineTo(0, 150);
ctx.fillStyle = grad;
ctx.fill();
<canvas/>
Animated version using compositing technique
var ctx = document.querySelector("canvas").getContext("2d"),
grad = ctx.createLinearGradient(0, 0, 0, 150),
step = grad.addColorStop.bind(grad), // function reference to simplify
dlt = -3, y = 150;
step(0, "red"); // start of red
step(1/3, "red"); // end of red at 1/3
step(1/3, "gold"); // start of gold at 1/3
step(2/3, "gold"); // end of gold at 2/3
step(2/3, "blue"); // start of blue at 2/3
step(1, "blue"); // end of blue at 3/3
// store a triangle path - we'll reuse this for the demo loop
ctx.moveTo(75, 0); ctx.lineTo(150, 150); ctx.lineTo(0, 150);
(function loop() {
ctx.globalCompositeOperation = "copy"; // will clear canvas with next draw
// Fill the previously defined triangle path with any color:
ctx.fillStyle = "#000"; // fill some solid color for performance
ctx.fill();
// draw a rectangle to clip the top using the following comp mode:
ctx.globalCompositeOperation = "destination-in";
ctx.fillRect(0, y, 150, 150 - y);
// now that we have the shape we want, just replace it with the gradient:
// to do that we use a new comp. mode
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 150, 150);
y += dlt; if (y <= 0 || y >= 150) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas/>
Cached gradient image for animation (recommended)
var ctx = document.querySelector("canvas").getContext("2d"),
tcanvas = document.createElement("canvas"), // to cache triangle
tctx = tcanvas.getContext("2d"),
grad = tctx.createLinearGradient(0, 0, 0, 150),
step = grad.addColorStop.bind(grad), // function reference to simplify
dlt = -3, y = 150;
step(0, "red"); // start of red
step(1/3, "red"); // end of red at 1/3
step(1/3, "gold"); // start of gold at 1/3
step(2/3, "gold"); // end of gold at 2/3
step(2/3, "blue"); // start of blue at 2/3
step(1, "blue"); // end of blue at 3/3
// draw triangle to off-screen canvas once.
tctx.moveTo(75, 0); tctx.lineTo(150, 150); tctx.lineTo(0, 150);
tctx.fillStyle = grad; tctx.fill();
(function loop() {
ctx.clearRect(0, 0, 150, 150);
// draw clipped version of the cached triangle image
if (150-y) ctx.drawImage(tcanvas, 0, y, 150, 150 - y, 0, y, 150, 150 - y);
y += dlt; if (y <= 0 || y >= 150) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas/>
You can change direction using the gradient line, which dictates the angle of the gradient.
// vertical
ctx.createLinearGradient(0, 0, 0, 150); // x1, y1, x2, y2
// hortizontal
ctx.createLinearGradient(0, 0, 150, 0); // x1, y1, x2, y2
// 45° degrees
ctx.createLinearGradient(0, 0, 150, 150); // x1, y1, x2, y2
etc.
You can use native html canvas by making your shapes (eg triangle) into a clipping regions.
This means any fills you do subsequently will not draw outside your triangle.
All you have to do is:
Draw you triangle
Make it a clipping region
Draw a green rectangle over the top 1/3 of your triangle. Don't worry...the rectangle will be clipped to appear only where it is inside the triangle.
Draw a blue rectangle over the middle 1/3 of your triangle
Draw a red rectangle over the bottom 1/3 of your triangle
Here's example code and a demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var points=[];
points.push({x:100,y:50});
points.push({x:150,y:150});
points.push({x:50,y:150});
points.push({x:100,y:50});
drawPoints(points);
function drawPoints(pts){
var minY= 100000;
var maxY=-100000;
ctx.save();
ctx.beginPath();
for(var i=0;i<pts.length;i++){
var p=pts[i];
if(i==0){
ctx.moveTo(p.x,p.y);
}else{
ctx.lineTo(p.x,p.y);
}
if(p.y<minY){minY=p.y;}
if(p.y>maxY){maxY=p.y;}
}
ctx.stroke();
ctx.clip();
var height=maxY-minY;
ctx.fillStyle='green';
ctx.fillRect(0,minY,cw,minY,height/3);
ctx.fillStyle='blue';
ctx.fillRect(0,minY+height/3,cw,height/3);
ctx.fillStyle='red';
ctx.fillRect(0,minY+height*2/3,cw,height/3);
ctx.restore();
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

Categories

Resources