Detecting mouse proximity in processing.js - javascript

I am coding with processing.js. I want the size variable to get greater as the cursor (mouse) approches the ellipse and to get smaller as the cursor moves away from the ellipse. The size should (if possible) be limited between minimum 50 and maximum 200. Is there any way to accomplish that ?
I've looked online, but there doesn't seem to be lots of documentation (at least for what I was searching for) about this.
Here is my code :
void setup()
{
// Setting up the page
size(screen.width, screen.height);
smooth();
background(0, 0, 0);
// Declaring the variable size ONCE
size = 50;
}
void draw()
{
background(0, 0, 0);
// I want the size variable to be greater as the cursor approches the ellipse and to be smaller as the cursor moves away from the ellipse. The size is limited if possible between 50 and 200
// Here is the variable that needs to be changed
size = 50;
// Drawing the concerned ellipse
ellipse(width/2, height/2, size, size);
}
Thanks.

First, you need to get the distance from the mouse to the ellipse:
float distance = dist(mouseX,mouseY, width/2,height/2);
Then, you need to convert that distance into a more usable range. We'll call the result dia, since size() is also the name of a command in Processing. We also want dia to get larger as the distance gets smaller.
For both those things, we'll use map() which takes an input value, it's range, and an output range:
float dia = map(distance, 0,width/2, 200,50);
When distance is 0, dia = 200 and when distance is the width of the screen divided by 2, dia = 50.

Related

How to lower one number when the other rises?

I take a value from the mouse (mouseX) position in Processing, as this value gets higher, I want the amount of boxes that are rendered to lower in steps of 5 (rotStep).
I did a lot of reading and found out the method I should use is called 'Negative correlation' or at least I think it is. I have never had high-grade math so I'm pretty much in the dark here. Maybe there is a function that already exists to do this. After a lot of googling I came in here to ask.
Tried dividing the mouseX input by itself and some other random sums but it seems this might be more complicated than I anticipated.
I am trying to get into generative art generation and could use a hint to get further with my attempt of rendering more boxes (quads) as the mouseX value lowers.
void setup() {
pixelDensity(displayDensity());
size(500, 500);
background(0);
noFill();
stroke(255);
}
void draw() {
translate(width/2, height/2);
ellipse(0, 0, 50, 50);
background(0);
mouseX= constrain(mouseX, 1, width);
mouseY= constrain(mouseY, 1, height);
float rotationMax = 90;
float rotStep = (mouseX/15)+5;
//I need to add a negative correlation so the number
//of squares lowers as the mouseX position gets higher
//and all this in steps of 5
float quadSize = mouseX;
float qs = quadSize;
for (float i=0; i<rotationMax; i+=rotStep) {
float deg = rotStep;
float rad = radians(deg);
stroke(255);
strokeWeight(1);
rotate(rad);
quad(-qs, -qs, qs, -qs, qs, qs, -qs, qs);
}
}
The rotStep variable should decrease when the mouseX variable increases and vice versa. The variable rotStep should also increase or decrease in steps of 5.
The best advice I can give you is to get out a piece of paper and a pencil, and draw a table of mouse positions and the number of boxes you want. It might look like this:
mouseX boxes
---------------
0 | 50
100 | 40
200 | 30
300 | 20
400 | 10
500 | 0
This is just an example, so your numbers would probably be different. But the idea is to have a general mapping of mouseX to the number of boxes you want to draw.
Once you have that, then you can try to find an equation that gets you from mouseX to your box count. That might be a single equation, or it might involve if statements to bucket values together.
You can get a "negative correlation" by subtracting from the maximum possible value, or by using mouseX as a divisor.
float reverseMouseX = width - mouseX;
float inverseMouseX = 1 / mouseX;
For both of these approaches, as mouseX increases, the value of the variable will decrease. Then you can use these values in your equation or in your if statement logic.
To get to the example table I showed above, I might do something like this:
int boxes = (width - mouseX) / 10;
This is a general approach, but you can apply it to your goal to come up with a specific solution.
Good luck!

Subtract opacity instead of multiplying

I'm trying to make it appear as though movement on my <canvas> creates motion trails. In order to do this, instead of clearing the canvas between frames I reduce the opacity of the existing content by replacing a clearRect call with something like this:
// Redraw the canvas's contents at lower opacity. The 'copy' blend
// mode keeps only the new content, discarding what was previously
// there. That way we don't have to use a second canvas when copying
// data
ctx.globalCompositeOperation = 'copy';
ctx.globalAlpha = 0.98;
ctx.drawImage(canvas, 0, 0);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
However, since setting globalAlpha multiplies alpha values, the alpha values of the trail can approach zero but will never actually reach it. This means that graphics never quite fade, leaving traces like these on the canvas that do not fade even after thousands of frames have passed over several minutes:
To combat this, I've been subtracting alpha values pixel-by-pixel instead of using globalAlpha. Subtraction guarantees that the pixel opacity will reach zero.
// Reduce opacity of each pixel in canvas
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Iterates, hitting only the alpha values of each pixel.
for (let i = 3; i < data.length; i += 4) {
// Use 0 if the result of subtraction would be less than zero.
data[i] = Math.max(data[i] - (0.02 * 255), 0);
}
ctx.putImageData(imageData, 0, 0);
This fixes the problem, but it's extremely slow since I'm manually changing each pixel value and then using the expensive putImageData() method.
Is there a more performant way to subtract, rather than multiplying, the opacity of pixels being drawn on the canvas?
Unfortunately there is nothing we can do about it except from manually iterating over the pixels to clear low-value alpha pixels like you do already.
The problem is related to integer math and rounding (more details at this link, from the answer).
There are blending modes such as "luminosity" (and to a certain degree "multiply") which can be used to subtract luma, the problem is it works on the entire surface contrary to composite modes which only works on alpha - there is no equivalent in composite operations. So this won't help here.
There is also a new luma mask via CSS but the problem is that the image source (which in theory could've been manipulated using for example contrast) has to be updated every frame and basically, the performance would be very bad.
Workaround
One workaround is to use "particles". That is, instead of using a feedback-loop instead log and store the path points, then redraw all logged points every frame. Using a max value and reusing that to set alpha can work fine in many cases.
This simple example is just a proof-of-concept and can be implemented in various ways in regards to perhaps pre-populated arrays, order of drawing, alpha value calculations and so forth. But I think you'll get the idea.
var ctx = c.getContext("2d");
var cx = c.width>>1, cy = c.height>>1, r = c.width>>2, o=c.width>>3;
var particles = [], max = 50;
ctx.fillStyle = "#fff";
(function anim(t) {
var d = t * 0.002, x = cx + r * Math.cos(d), y = cy + r * Math.sin(d);
// store point and trim array when reached max
particles.push({x: x, y: y});
if (particles.length > max) particles.shift();
// clear frame as usual
ctx.clearRect(0,0,c.width,c.height);
// redraw all particles at a log. alpha, except last which is drawn full
for(var i = 0, p, a; p = particles[i++];) {
a = i / max * 0.6;
ctx.globalAlpha = i === max ? 1 : a*a*a;
ctx.fillRect(p.x-o, p.y-o, r, r); // or image etc.
}
requestAnimationFrame(anim);
})();
body {background:#037}
<canvas id=c width=400 height=400></canvas>

canvas pendulum animation - canvas translating

I'm trying to make simple pendulum in HTML5 Canvas but I'm stuck. I want to swing it for 25 degrees to the left and to the right, so I calculated I should translate every frame about -3.5 px in y axis (and 3.5 px when swings to the right). I'm using below code
var rotation = Math.PI/180, //rotate about 1deg
translation = -3.5,
counter = 0; //count rotations
function draw() {
var element = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,element.width,element.height);
ctx.translate(0, translation);
ctx.rotate(rotation);
//function draws all objects
objects(element,ctx);
if (counter == 25) {
rotation *= -1;
translation *= -1;
counter = -25;
}
counter += 1;
window.requestAnimationFrame(draw);
}
Everything looks good but when pendulum is changing direction then everything is translating in also x axis and after few seconds disappears from screen.. What is wrong in this code? Or maybe I was miss something in my calculations? My code here https://jsfiddle.net/qskxjzv9/2/
Thanks in advance for your answers.
The problem is that when there is rotation involved, then translation, the x and y's will be translated in a different direction than what may seem logic.
To get around this we don't actually have to involve translation more than using it for placing pivot (point of rotation) and then use absolute rotation based on a different way of calculating the pendulum movement.
For example, this will take care of both the translation problem as well as smoothing the pendulum movement:
Change the draw method to draw the pendulum with origin (0,0) - it's just a matter of changing the initial coordinates so they evolve around (0,0)
Translate to pivot point of screen - this is where the rotation will take place.
Rotate using sin() as a factor - this will create a smooth animation and look more like a pendulum and it will restrict the movement to angle as range is [-1,1]
Use counter to move sin() instead - this acts as a frequency-ish factor (you can later convert this into an actual frequency to say, have the pendulum move n number of times per minute etc.). To keep it simple I have just used the existing counter variable and reduced its step value.
The main code then:
var maxRot = 25 / 180 * Math.PI, // max 25° in both directions
counter = 0,
// these are better off outside loop
element = document.getElementById('canvas');
ctx = element.getContext('2d');
function draw() {
// reset transform using absolute transformation. Include x translation:
ctx.setTransform(1,0,0,1,element.width*0.5,0);
// clear screen, compensate for initial translate
ctx.clearRect(-element.width*0.5,0,element.width,element.height);
// rotate using sin() with max angle
ctx.rotate(Math.sin(counter) * maxRot);
// draw at new orientation which now is pivot point
objects(element, ctx);
// move sin() using "frequency"-ish value
counter += 0.05;
window.requestAnimationFrame(draw);
}
Fiddle
Additional
Thanks to #Blindman67 for providing additional improvements:
To control frequency in terms of oscillations you could do some minor changes - first define frequency:
var FREQUENCY = 3;
Define a function that will do the conversion:
function sint(time) {
return Math.sin(FREQUENCY * time * Math.PI * 0.002); // 0.002 allow time in ms
}
If you now change the draw() method to take a time parameter instead of the counter:
function draw(time) {
...
}
Then you can call rotation like this:
ctx.rotate(sint(time) * maxRot);
you need to translate the origin to the point you want to rotate around:
ctx.translate(element.width / 2, 0);
Then, the rotation as you suggest:
ctx.rotate(rotation);
And finally, translate back:
ctx.translate(- element.width / 2, 0);
See this commented fork of your fiddle.

ProcessingJS - Rotating the camera in a circe around a fixed point?

Recently, I have been trying to build a kind of sailing simulator in Processing, and have encountered a problem. I'm not going to go into details on the project itself because I don't think it's really relevant.
Here's my problem: I need to find a way for the camera to look around while still focusing on the object in the middle (the boat). By this I mean that I'd like to find a circular path for the camera, while it orbits the boat. This is used in many simulators and video games, so I thought it could work in my project.
I have already thought about rotating every object instead of the camera, but I would prefer not to do that because dealing with the boat, sail, and wind is already going to cause lots of rotation and it would just complicate things to rotate it all again every time the player drags the mouse to pivot the point that they are looking from. So, I think finding this path for the camera is my only option right now and I have no idea how to even start to do the math out (going into 9th grade).
If anyone reading this has encountered this problem before, (using the mouse to rotate the camera around an object) please try to give me some tips. Thanks!
Code:
float x,y,z,ry;
int trimmingLimit;
void setup()
{
size(800, 600, P3D);
x = width/2;
y = height/2;
z = 0;
ry = 10;
trimmingLimit = int(random(75,84)); //randomizing sheet length length
}
void draw()
{
background(#FF844B);
stroke(255);
translate(x,y,z);
pushMatrix();
rotateY(radians(ry)); //mainsheet trimming and easing
triangle(-120, 50, 0, -140, 0, 50); //sail
ry=mouseY/(height/trimmingLimit); //since 80 to 85^o is the maximum amount
//the sail can be drawn, the height of the window is adjustable
//and divided by 90.
popMatrix();
noStroke();
pushMatrix();
translate(0,500,0);
fill(98,122,255,50);
cylinder(1000,500,15);
rectMode(CENTER);
popMatrix();
fill(#AD8B7C);
stroke(255);
pushMatrix();
translate(0,75);
rotateX(radians(0));
translate(0,75);
triangle(-180,100,0,-50,180,100);
popMatrix();
fill(100);
}
float d(float n) //converting to the correct type of degrees (with 0 being wind)
{
return n-90;
}

Scale a dot's X Y on HTML5 canvas by percentage

I'm working on my first canvas project, and it requires a partial map of the US, with a zoom and center on a state when clicked.
I was able to find X Y arrays of points to draw the country, with each state being its own array. I needed the states to be drawn out larger then these dimensions, so I introduced a scale varaible to multiply each point by.
My next challenge was that the client only wanted 13 states drawn out, but not placed to scale against each other. (Example, put Ohio and Illinois next to each other on the canvas and ignore Indiana). My solution to that was to introduce a fixed X, Y "constant" for each state, that after the scaling happens, add the X Y value for that state and make that the spot to draw on.
for ( var j = 0; j < state.myPolygons.length; ++j) {
context.beginPath();
context.lineWidth = lineWidth;
context.strokeStyle = stateStroke;
context.fillStyle = stateFill;
for ( var k = 0; k < state.myPolygons[j].myXVals.length; ++k ) {
var x = parseFloat(state.myPolygons[j].myXVals[k]*state.scale)+state.posX;
var y = parseFloat(state.myPolygons[j].myYVals[k]*state.scale)+state.posY;
y = canvas.height - y;
if ( k == 0 )
context.moveTo(x,y);
else
context.lineTo(x,y);
}
context.closePath();
context.fill();
context.stroke();
}
The effect of clicking on a state, and growing it and centering on the canvas was accomplished by defining a target scale and number of steps. I get the difference between the target scale and current scale, and divide that by number of steps to figure out how much to add to the scale of the state at each "frame".
Example: Ohio's initial scale is 1.97 of the found coords. My target for Ohio scale is 3.75%. I get the difference (1.78), and divide that by 45 (the defined set of steps) to draw. This gives me 0.039 as an incrementer to my scale at each frame. I then loop through while my states current scale is less than the target scale. Again however, since I need to manipulate the X Y of the rendering, I have then a zoomx and zoomy constant for each state that gets added to the calculated X Y so it can "slide" to the center of the canvas.
All of this works perfectly and I have California zoom/sliding from left to right, Ohio sliding right to left, etc. --- Here is my problem.
I have a series of dots to indicate client loctions in the state. These are simple X Ys that I draw a circle on. The initial rendering of the map includes a loop to run through each states set of locations. I'm applying the same scale factor, and posX,posY variables to adjust final placement of the dot in relation to final rendering of the state
for (var loc in state.Locations) {
var locx = parseFloat(state.Locations[loc].x*state.scale)+state.posX
var locy =parseFloat(state.Locations[loc].y*state.scale)+state.posY;
var txt=state.Locations[loc].text;
var lnk=state.Locations[loc].link;
context.beginPath();
context.arc(locx,locy,locationSize,0,Math.PI*2,true);
context.fillStyle = locationFill;
context.closePath();
context.fill();
context.stroke();
}
When the state is zooming however, the scaling logic for the dots fails. The state scale for a given frame applies
x = parseFloat(activeState.myPolygons[j].myXVals[k]*activeState.scale)+activeState.posX;
y = parseFloat(activeState.myPolygons[j].myYVals[k]*activeState.scale)+activeState.posY;
When I apply this to a given location in the state with
locx = parseFloat(activeState.Locations[loc].x*activeState.scale)+activeState.posX;
locy = parseFloat(activeState.Locations[loc].y*activeState.scale)+activeState.posY;
I end up with X following pretty closely, but in Ohio's example, the Y is somewhere near Florida. Other states like California are even worse with their dots starting more "stacked" on top of each other and end up more "spread out" beside each other.
I'm trying to figure out the trig functions needed to grow and shrink the position of the X Y on a location in relation to the current scale of the state, and keep it on the same path the state is traveling on through the animation (both zooming in and zooming out).
My final attempt before coming here was to get the inital X Y of the location, and compare its distance to the LAST X Y of the state array. I was trying to then find the angle of the line connecting those 2 points, and then use all this to scale. I still feel that I may be onto something with this approach, I just can't make it happen.
Thank you everyone for taking the time to read this, I appriciate any help you can offer
You could just look at the paper I put on your desk, the one with the equation on it. However, SVGs would be more optimal for the project, as you could easily group things together using the g tag and then could just scale the entire group.
However, since you're forced to use canvas at this point: You would have to scale up and down director, using trig given the angle of the start point to location dot and the DIFFERENCE of left or right travelled from the original distance. I will explain in more detail, with actual equations, when you allow me to give me that paper back. However, the only line you really need to modify at this point is:
locy = parseFloat(activeState.Locations[loc].y*activeState.scale)+activeState.posY;

Categories

Resources