svg.js rotation center of clipped element - javascript

Svg.js animation of rotations works great because it uses the center point of the element by default, even when the element is moving from one spot to another, but now I'm having trouble when I add a clipping path to an image, because the center point is still the center of the original image, even if it is outside of the clipping path. I would like to use the center point of the clipping path instead. The closest thing I could find was a question about d3.js.
var rect = draw.rect(60,60)
var picture = draw.image(img.jpg).clipWith(rect)
picture.animate(1000).rotate(360)
How can I get it working in svg.js?

You can pass a centre of rotation to the rotate() method. All you have to do is work out where the centre of the clip rect is and pass that in. It works out to be 90,80.
this.animate(1000).rotate(
360 + currentRotation, 90,80
)
Demo here
For some reason it doesn't work the first time, but after that it works fine. That seems like a bug in svg.js.

Related

How can I replace my cursor with a circle instead of drawing it to canvas in p5.js?

The problem: I'm trying to create a simple drawing app using p5.js. Instead of the standard cursor image, I'd like to show a circle at my cursor location that represents the size of the drawing brush.
Potential solution 1: Replace the cursor using the cursor() function native to p5.
Why it doesn't work: The p5 cursor function only takes the following parameters:
ARROW, CROSS, HAND, MOVE, TEXT, or WAIT, or path for image
As such, there's no native way to replace the cursor using the ellipse class.
Potential solution 2: Use the noCursor() function and then draw the circle at the cursor location, while also drawing the background, as such:
var brushSize = 50;
function setup() {
createCanvas(1080,720);
noCursor();
}
function draw() {
background(100);
ellipse(mouseX,mouseY,brushSize);
}
Why it doesn't work: While this solution gets the desired effect i.e. replacing the cursor with a circle the size of the brush, the constantly updating background prevents me from actually drawing to the canvas with the brush when I want to.
Is there some way I can replace the cursor without actually drawing the ellipse to the canvas? Is there any way to save and then instantly reload a canvas in p5? I couldn't find such a method searching through the API docs. Any hints are appreciated.
According to the reference, you can pass a URL into the cursor() function to set an image.
If you want to use an image that you draw, you're going to have to draw them ahead of time and save them to files, and then use those files. Something like this:
cursor('images/ellipse-15.png');
Where ellipse-15.png is an image that you generated ahead of time, to match when brushSize is 15, for example.
Btw P5.js is just setting the cursor CSS property. You can read more about it here.
If you want to go with the noCursor() approach and draw the ellipse yourself, you could draw your drawing to a buffer (the createGraphics() function is your friend) and then draw the ellipse on top of that every frame. I'd still probably use a cross cursor just because there's going to be some annoying lag if you draw it yourself.
Create a circular DIV inside the canvas container and show it on top of the actual canvas.

How to calculate the center of a rotated element, after resizing it

I've already asked this same question months ago, but no one was able to answer me, even after making a fully functional example on Plunker, then, I am going to ask it again, and yes, I still have the same problem.
My problem: find the centre of an element who have some rotation in it, after resizing it, to use it as the new pivot of rotation.
In my practical example, it is possible to see the problem in action; I have created two circles to show the problem better. After rotating and resizing the element, it's possible to see how the red and blue circles are apart from each other.
Blue Circle: the "correct" position of the centre, achieved by setting the cx/cy coordinates as the calculated element centre, plus, applying the transform rotate in it. The transform translates the circle to the correct position.
Red Circle: same as the blue circle, minus the transform rotate, these values are the ones used as the rotation pivot for the transform rotate().
My assumptions until here: By applying the transform rotate() in the blue circle, I'm considering the rotation angle in the calculated centre, so all I have to do is replicate the matrix calculations made by the rotate() function. I'm already doing this with the four handles that the user can click to make a rotation, what could go wrong?
My goal: Resize an element with rotation keeping the pivot of rotation in the centre.
I think this answer gave me some info, the math here helped me with the rotation handles starting position, but still, I can't find the right way to calculate the new centre after the resize.
The example was made using D3js + AngularJS v1. I work actively with both, but I am new to the geometry math world.
Again, this is the project on Plunker.
To get the centre of the transformed and rotated element, the most accurate way would probably be to get the browser to calculate it for you.
First create an SVGPoint object to hold our original centre point.
var centre = svg.createSVGPoint();
Initialize this point with the centre of the original object. You can get that by calling getBBox() on the element, and performing a smiple calculation.
var bbox = obj.getBBox();
centre.x = bbox.x + bbox.width / 2;
centre.y = bbox.y + bbox.height / 2;
Next, get the transform matrix from the transform attribute of the transformed object
var matrix = transformedObj.transform.baseVal.consolidate().matrix
Now we can transform our SVGPoint object with this matrix.
var transformedCentre = centre.matrixTransform(matrix);
After this, the x and y properties of transformedCentre should be your transformed centre point.
This should work, but I haven't tested it.

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

How to get image coordinates after centering the object using image.centerObject() in fabric js

I am drawing a rectangle on top of a image and then saving the coordinates of both to a Mysql Database table.
Then I have to retrieve the same image and overlaying Rectangle from a Andriod APP
which will not know anything on FabricJS .
It will only know the coordinates of image and rectangle.
Luckily for image it is not a problem as it can be maintained using some Aspect ratio algorithm.
But how to get the coordinates of Rectangle , so that it can be rendered correctly.
Now what I see is Fabricjs saves the coordinates according to window left ,top, width, height. But andriod app expects the coordinates according to image , which fabricjs doesn't provide.
Any suggestions how to achieve this?
Please let me know if somebody didn't understand .
Its a basic and easy statement , hence not adding any fiddle or code.
before saving to database do this:
image.setCoords();
rect.setCoords();
in
image.oCoords.tl, image.oCoords.tr, image.oCoords.bl, image.oCoords.br
and
rect.oCoords.tl, rect.oCoords.tr, rect.oCoords.bl, rect.oCoords.br
you will find 4 objects with both x and y coordinates that represent your absolute position of the object.
tl stands for Top Left, br stands for Bottom Right and so on.
You should have no problem then to make some subtraction and find relative coordinates of the two objects.
Example:
if image has tl (45,80) and rect has tl (80,110) it means that rect coordinate relative to image is (80-45, 110-80) = (35, 30)

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

Categories