Object controll with mouse position relative to circle - javascript

Need some inspiration. I've got a picture (blue) and want it to move proportional to the mouse position inside an invisible area (orange). So, if the mouse moves in top-left direction, the image should follow the movement.
I don't want to simply copy the mouse position, rather create an Joystick like behaviour, so if the mouse moves, the image should move stepwise in the desired direction.
But how? I've no idea how to set the right x+y coordinates for the image or how to establish a formula to calculate them.

Incremental (vectored) positions. Consider:
Let's call the dead center of your invisible circle the vector reference point (0,0) or VRP.
You move your mouse away form the VRP. Let's use your image as a reference and say that your mouse is at (-3x -2y) relative to the VRP. You keep it there; It creates a -3 X vector and a -2 Y vector.
For as long as you keep your mouse there, those vectors will be applied to the square's current coordinate at each cycle, like this:
Assume Picture starter position is absolute 100,100.
Cycle 1: [x]:100 -3 = 97;[Y]:100 -2 = 97. New picture position = 97x98y.
Cycle 2: [x]:97 -3 = 94;[Y]:98 -2 = 96. New picture position = 94x96y.
And so forth. If you want to stop the movement, just bring the cursor back to the VRP.
You may sophisticate the mechanism creating acceleration intermediate vectors, or a dead zone around the vector reference point.

Related

Get started with animated typography/particles in javascript (mapping particles to a word)?

Alright, so I have a good deal of experience with HTML and CSS, and some experience with Javascript (I can write basic functions and have coded in similar languages).
I'm looking to start some visual projects and am specifically interested in getting into particle systems. I have an idea for something similar to Codecademy's name generator here (https://www.codecademy.com/courses/animate-your-name/0/1) where particles are mapped to a word and move if hovered over. It seems as though alphabet.js is what's really behind Codecademy's demo however I can't understand exactly how they mapped the particles to a word, etc.
I've done some basic tutorials just creating rudimentary particles in a canvas but I'm not sure a canvas is the best way to go - demos that utilize one of the many libraries available (such as http://soulwire.github.io/sketch.js/examples/particles.html) don't use a canvas.
So my question is - what is the best way for a beginner/intermediate in Javascript to start with particle systems? Specifically to accomplish the Codecademy name effect or similar? Should I try to use canvas or which library would be best to start with and how would you recommend starting?
The code for this project is achievable for your intermediate JS programmer status.
How the CodeAcademy project works ...
Start by building each letter out of circles and saving each circle's centerpoint in an array. The alphabet.js script holds that array of circle centerpoints.
On mousemove events, test which circles are within a specified radius of the mouse position. Then animate each of those discovered circles radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which circles are no longer within the specified radius of the current mouse position. Then animate each of those "outside" circles back towards their original positions.
You can also use native html5 canvas without any libraries...
Another approach allowing any text to be "dissolved" and reassembled
Start by drawing the text on the canvas. BTW, this approach will "dissolve" any drawing, not just text.
Use context.getImageData to fetch the opacity value of every pixel on the canvas. Determine which pixels on the canvas contain parts of the text. You can tell if a pixel is part of the text because it will be opaque rather than transparent.
Now do the same procedure that CodeAcademy did with their circles -- but use your pixels:
On mousemove events, test which pixels are within a specified radius of the mouse position. Then animate each of those discovered pixels radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which pixels are no longer within the specified radius of the current mouse position. Then animate each of those "outside" pixels back towards their original positions.
[Addition: mousemove event to test if circles are within mouse distance]
Note: You probably want to keep an animation frame running that moves circles closer or further from their original positions based on a flag (isInside) for each circle.
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calc the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// test each circle to see if it's inside or outside
// radius of 40px to current mouse position
// circles[] is an array of circle objects shaped like this
// {x:,y:,r:,originalX:,originalY:,isInside:}
var radius=40;
for(var i=0;i<circles.length;i++){
var c=circles[i];
var dx=c.x-mouseX;
var dy=c.y-mouseY;
if(dx*dx+dy*dy<radius*radius){
c.isInside=true;
// move c.x & c.y away from its originalX & originalY
}else{
c.isInside=false;
// if the circle is not already back at it's originalX, originalY
// then move c.x & c.y back towards its originalX, originalY
}
}
}

Drawing a point to point ellipse to allow painting in GUI

I'm implementing some basic annotation draw features, such as arrows. Now I'm a little bit stuck with ellipse.
The methods to draw an ellipse usually address using it's two diameters and eventually a rotation:
However I want to display the ellipse between the point user clicked and the one he's hovering, therefore I need a function that calculates diameters and rotation based on two points:
How would I do that? Can it be achieved with sufficient performance (as it renders during mouse-hovering)?
the steps you shoul follow:
get the angle of the line (from this post: get angle of a line from horizon)
rotate the canvas or at least the part you currently drawing (live demo here: http://www.html5canvastutorials.com/advanced/html5-canvas-transform-rotate-tutorial)
draw an ellipse in canvas (http://www.scienceprimer.com/draw-oval-html5-canvas)
the resulted ellipse will be transformed as described
It can be done in the same way that it is normally done, just using different math to calculate the shape. Without writing the entire code for you, you can start by having an event trigger when the user clicks the mouse button down. The function will copy the users x and y position based on the screen. Then there is a second function which will handle mouse movement. This function will keep track of the x and y coords of the mouse while it is in motion. The final function will be a mouse up event, when a user lifts their finger from the mouse button (assuming this is when the event should be finished). Using the initial and final position of the x and y coordinates, you can calculate the length of the line the user created. That line is the long diameter of the ellipse. Half this number for the large radius. Then use whatever ratio you are using to calculate the smaller radius from the larger one. Then create an ellipse based on these numbers.
For the math: Suppose your first point is x1,y1 and the end point is x2,y2
I'm also assuming that we have a line going from bottom-left to top-right
Distance between two points = sqrt((x2-x1)^2 + (y2-y1)^2) ---> (we will call this d1)
half of this is the length of the large radius ---> (we will call this r1)
Midpoint formula = ((x1+x2)/2 , (y1+y2)/2) ---> axis of rotation (we will call it (m1, m2))
distance from midpoint to end is just the radius
radius is now the hypotenuse of constructed plane, y2-m2 is height of right triangle.
Find the angles between midpoint and one end of larger radius - sin((y2-m2)/r1).
Angle of smaller radius is this angle + pi/4 radians.
calculate length of smaller radius based on ratio.

How to rotate div in circular motion while counter rotating inner circles?

This image is what I am trying to achieve. Circles on the edges are clickable. Its structure is made such that each rotation will be multiple of 45 deg.
I am using css transform rotate property for rotation.
How is it supposed to work?
When we click on any circle on the edge it should come to its active position and it should always rotate in clockwise direction.
Here is what I did
I achieved rotation by assigning numbers to the circles.
i.e., if clicked on 7 number then it will rotate by angle (9-7)*45=90 degrees.
(This time I did not change the numbers dynamically. i.e., as the circle is rotating the numbers given to the circles are the same.)
This works fine here. But, lets see this scenario: when we click on 2nd position circle it will rotate by 315 deg and then if you click again on the same (second) position then it will make the angle of 270 and it rotates the div in anti-clockwise direction. I think this is its behavior. But, I don't want this to happen. It should rotate again in clockwise direction and should take the active position.
Now to achieve above I did this:
Adding angle with prev angle.
var prev_degree = prev_degree + current_degree;
(current degree is being calculated using the same formula from above.)
This time I changed numbers dynamically i.e., on each click numbers are given to the desired positions. Starting 1 as from Active position till 8 as shown in Image
But this time, when I rotate circle 1, 2 times it rotates perfect then it starts working strange. If you are constantly clicking on the same number then it will add the same angle and will keep rotating perfect no matter what your angle is. If you click on random circles then it wont work which is totally wrong.
Why clockwise?
Because the circles on edges, they contain icon of which I have to maintain position when whole circle rotates.(I can achieve that rotating circles on the edges by assigning negative angles. But, now this is not a problem.)
There is no case when I am getting negative angle.
Let me know if you are not clear with my question.
Please let me know your suggestions to make this work :-)

Understanding rotation and calculating the top left point in KineticJS

I am working on a page where I can view images. I want to create a rotation tool. I've done that, but, it's not working consistently. When I set up the centre point to rotate by, the image jumps slightly, and it gets worse each time. I was experimenting, and, I have code to add a wedge to the top left corner of my top level group ( so, at 0,0 ). If I rotate the image by 45 degrees and drag it so that half of it is off the left edge of my canvas, then I call getAbsolutePosition on the wedge and on the group, I get these values:
layer.getAbsolutePosition()
Object {x: 104.66479545850302, y: 279.2748571151325}
wedge.getAbsolutePosition()
Object {x: 180.2684127179338, y: -73.48773356791764}
I think this means my y position is actually the bottom of the image, which is off screen.
What I want to do, is calculate the absolute position of the middle of my image, when the mouse moves over it, regardless of it's rotation. I have some code that works out points with rotation, which seems like it works at first, almost, but it just gets more and more broken the more I use the tool. I feel like there's something about how Kinetic is tracking these things and what it's reporting, that I am missing. Any hints would be most appreciated. Tutorials I can read are even better ( yes, I've read everything linked from the KineticJS site and searched the web ).
In a nutshell, the question is, if I have an image inside a group, and it's rotated, how do I work out the centre point of the image, taking the rotation in to account, and how do I set the offset so it will rotate from that point, and stay in the same place ?
Thanks
As you've discovered about KinetiJS:
rotation is easy
dragging is easy
dragging+rotation is difficult
After you drag your image you must reset its rotation point (offsetX/offsetY).
KineticJS makes dragging+rotation more difficult than it has to be.
Resetting the offset points of your image will cause KineticJS to automatically move your image (Noooo!!).
That's what's causing your jumping.
The solution to the "jumping" problem:
When you reset the image's rotation point (offsetX/OffsetY) you must also reset the image's X/Y position.
This code resets both XY and Offsets for an image after dragging:
A Demo: http://jsfiddle.net/m1erickson/m9Nw7/
// calc new position and offset
var pos=rect.getPosition();
var size=rect.getSize();
var offset=rect.getOffset();
var newX=pos.x-offset.x+size.width/2;
var newY=pos.y-offset.y+size.height/2;
// reset both position and offset
rect.setPosition([newX,newY]);
rect.setOffset(size.width/2,size.height/2);

Moving a vector "straight out" along a fixed angle

I've searched for the answer to this and have tried many proposed solutions, but none seem to work. I've been struggling with this forever so any insight is greatly appreciated.
I have 3 shapes (vectors I suppose) on a JS canvas, each with an orientation represented as degrees off of 0 and a width. I need to drag one of these shapes "straight out" from its orientation. This is difficult to explain in words so please view the graphic I created:
The middle (diagonal) shape is at 45 degrees. It's origin is the red dot, (x1,y1). The user drags the shape and their mouse lies at the green dot, (x2,y2). Since the shape's origin is in the lower left, I need to position the shape at the position of the lighter blue shape as if the user has dragged straight outward from the shape's origin.
I don't think it matters, but the library I'm using to do this is KineticJS. Here's the code and some information I have available which may help solve the problem. This code positions the shape on top of the mouse, which isn't what I want:
var rotationDeg = this.model.get("DisplayOri"), // rotation in degrees
rotationRadians = rotationDeg * Math.PI / 180, // rotation in rads
unchanged = this.content.getAbsolutePosition(), // {x,y} of the shape before any dragging
dragBoundFunc = function (changed) {
// called on a mouseMove event, so changed is always different and is the x,y of mouse on stage
var delta = {
x: changed.x - unchanged.x,
y: changed.y - unchanged.y
};
return changed; // go to the mouse position
};
[edit] I should mention that the obvious of "return delta" doesn't work.
It sounds like you want to constrain the movement of the object.
Determine the vector representing the constraint axis : that is, we only want motion to occur along this line. It appears from your drawing that this is in the direction of the short line from the red dot out to the left. That vector has a direction of -1/m where m is the slope of the line we are moving.
Constrain the movement. The movement is represented by the mouse move delta - but we only want the portion of that movement in the direction of the constraint axis. This is done with a dot product of the two vectors.
So in pseudo code
m = (line.y2 - line.y1)/(line.x2 - line.x1)
constraintSlope = -1/m
contraintVector = {1, constraintSlope} //unit vector in that direction
userMove = {x2-x1, y2-y1} //vector of mouse move direction
projection = userMove.x * constraintVector.x + userMove.y * constraintVector.y
translation = projection * constraintVector //scaled vector

Categories