Linear/Incremental rotation animation with transition - javascript

I'm trying to get a SVG shape to rotate using the transform attribute and the transition method in D3. Here is the jsfiddle containing an example: http://jsfiddle.net/TJd2a/
I'm using two buttons, Left and Right, to rotate the rectangle by incrementing by its angle by 45 or -45 degrees. When the shape reaches either 180 or -180 degrees, the transition rotates the shape the opposite way, rather than moving linearly to the next angle. Using console logging, I've found there is nothing wrong with the angles that my code is generating. It appears to be how D3 is dealing the transition, as the generated XML does not show the same angle as the current (eg. when at 225 degrees, D3 gives the rectangle a rotation of -135 instead).
From what I've read and understand from the documentation, I need to use a custom Tween, but I 'm not sure where to start with a custom tween as I cannot find any examples specific or similar examples to help me understand how it works.

Correct; you can use a custom tween to change the interpolator. D3 has a special interpolator for transforms, but it's not doing the right thing in your case. (I think that's probably a bug which should be fixed, so I filed issue 661.) Here's an example using interpolateString instead:
d3.select("rect").transition().attrTween("transform", function(d) {
return d3.interpolateString(
"rotate("+ d.a +")",
"rotate(" + (d.a += 45) + ")"
);
});

Related

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.

Concurrency transitions in D3 (circle following filling path)

I am trying to create simple animated gauge charts, with red points on the end of each circle. Whole example is in here https://jsfiddle.net/yhLch8fc/3/ (please do not solve text position, it's not a problem). I tried to search on stack overflow, but tutorials like Change starting point of alongPath animation are not helping me, because my path is translated by X,Y and rotated. I thing the key part of code is:
circle.transition().duration(_duration)
.attrTween('cx', arcCircleX(_myPath.node()))
.attrTween('cy', arcCircleY(_myPath.node()));
you can easy switch to similar version (code from stack overflow above):
circle.transition().duration(_duration)
.attrTween('transformation', circleTween(_myPath.node()));
I don't know why, but it seems the red circle goes to the left side. Maybe it's because the original path is translated and rotated.
(The original version was, when I try to follow filling path, but it does not work either.)
Instead of rotating the hover path, rotate the g element that contains both the path and the circle:
enter.append("g").attr("class", "hover")
.attr("transform", "translate(" + _width / 2 + "," + _width / 2 + "), rotate(-90)");
Then:
circle.transition().duration(_duration)
.attrTween('transform', circleTween(_myPath.node()));
Here's an example. Is that what you were after?

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

Is it possible to draw any arbitary degree Eliptical Arc with SVG?

I am trying to smoothen the transition from a diagonal line to a horizontal line by using arcs of circles that I calculate with a little calculus. The problem I am running into is that it seems as though I can't get the arcs to be positioned correctly.
For example: jsfiddle.net/5Wa9e/2
It might just be a problem with my calculations but from "inspection" it seems as though I have the right circles. I want the red points on the right to always be at the bottom of the circle at the point where the tangent is horizontal.
I am using: A#{radius},#{radius} 0 0 0 #{curveEndX},#{curveEndY}" to define the arc. Am I missing something?
--edit--
It was just my math. Turns out the arcs I see are just fallback mechanisms for when the SVG renderer can't find a circle matching my constraints.
--edit--
end result: jsfiddle.net/5Wa9e/2

Canvas Rotating object about dynamic points

I have a rounded rectangle at a specific x, y, w, h on a canvas. I first do a context.translate to get the object where I want it, then when it comes to rotating it, this is where I'm having issues working out the math needed.
I can do a simple context.rotate(Math.PI/180 * 25) to rotate it 25degs but it rotates from the x,y. I really want to shift the rotating point to like x + (w/2) and y + (w/2).
I'm not sure how to tell the rotate method to rotate it around a different point. I think I have to rotate it like normal but recalculate x,y perhaps based on the rotation maybe?
The canvas always rotates about the origin (0,0). The ctx.translate command can be thought of as shifting the origin, so you must translate by (x+w/2, y+h/2) before you rotate if you wish to rotate about the center of the rectangle.
(and of course, translate back after, or use save and restore)

Categories