I made a codepen with snap svg: Codepen
I try to rotate a svg-gear in an endless-loop around his own centerpoint.
This works on Internet Explorer, but fails on Mozilla-Firefox and Google-Chrome.
The center point in Chrome and Firefox seems wrong and so the gear move out of his position.
For the rotation i used following code:
function infRotate(el, time, cw) {
var box = el.getBBox();
el.transform('r0,' + box.cx + ',' + box.cy);
if (cw)
el.animate({transform: 'r360,' + box.cx + ', ' + box.cy}, time, mina.linear, infRotate.bind(null, el, time, cw));
else
el.animate({transform: 'r-360,' + box.cx + ', ' + box.cy}, time, mina.linear, infRotate.bind(null, el, time, cw));
}
What i have to do for Firefox and Chrome to find right center point?
Thanks for your help.
Found solution based on #lan's comment.
The gear was in a group, which contains a X/Y - transformation.
So I try to remove each group and layer in the svg file. To see clearly the nesting of objects, I work with the XML-Editor in Inkscape.
Each object must be moved to his original position by using relativ-transformation. Using relativ movements prevent inkscape to print out translations attributes to groups.
Steps to move object relativ in Inkscape:
Go to Edit -> Select All in All Layers
Go to Object -> Transform
In Transform panel:
Uncheck Relative move and check Apply to each object separately
Move object to target position
After clean up the svg file, firefox and chrome calculate the right values too and the gear is now rotation well (see updated code on codpen)
Maybe it exist a better solution to tell Inkscape not working with transformation-attributes, but i didn't found it yet.
So if you work with animated SVG, be sure that the file is has no unnecessary groups and layers and keep attentions on transformation.
Joel except of taking center by using box.cx and box.cy. take center by dividing width and height of container by 2 and then set with it.
Related
I'm trying to integrate a constrained zoom (http://bl.ocks.org/mbostock/4987520) into the example featuring Bounding Box (https://bl.ocks.org/mbostock/9656675).
The point is to get the same behavior as the Bounding Box example while constraining the window zoom (and also being able to move around/zoom in/zoom out with the mouse which is already done in the given example).
I've been trying out and also found examples (not aiming to do the exact same thing though) but nothing worked as expected.
My code can be boiled down to the one in the Bounding Box, with the following "move" function :
var t = d3.event.translate,
s = d3.event.scale;
t[0] = Math.min(0,Math.max(t[0],width - width*s));
t[1] = Math.min(0,Math.max(t[1],height - height*s));
zoom.translate(t);
g.style("stroke-width", 1/s).attr("transform","translate(" + t + ")scale(" + s + ")");
Now the behavior I get almost meets the requirements except that when clicking on a specific state to zoom in on it, the view abruptly recenters on the previous clicked state before smoothly moving into the new chosen one.
Strangely enough, removing the "zoom.translate(t)" in the previous code fixes the bug but gives an "over-constrained" feeling to the manual zoom, i.e some areas are not reachable by zooming in and the "camera" translates in a peculiar way making it also impossible to zoom out - the zoom view is somehow attracted by the current selected state.
If someone knows how to work it out to get the expected behavior, I'll be thrilled.
Thanks in advance,
Killian.
I'm fiddling around with D3.js in this plunker.
It mostly does what I want, but I noticed a small inconsistency.
The idea is that the 2nd slider rotates the SVG elements in the container. As the elements within are actually text elements, I would like to have them displayed unrotated, and as such, I applied a transform: rotate to them with the symmetric value from the slider.
Although, I noticed that by doing that, the text elements don't rotate around their center, but rather around their top-left corner (I think). This is mostly visible when you observe a point near the edge and see how in transposes the edge on rotation.
I tried already setting both text-anchor and alignment-baseline to middle on these elements, hoping it would offset the text path, but apparently it doesn't change the point around which they pivot when rotated.
Additionally, should I try to set the rotate with pivot point coordinates, it boggles the effect entirely, by applying some translate to the elements, which I can't figure out.
Not sure if getBBox() could help me either in this subject, but I've considered maybe offsetting the points by half their width/height. This seems a bit convoluted though, and I was hoping for an easier/more elegant/cleaner fix.
Any thoughts?
Well, this is awkward. Right after I posted the question, I found an answer in D3.js docs: polygon.centroid().
Basically, I used the return value of this function as the transform: rotate pivot point coordinates and the offset is taken care of. Example (line 99 of the above plunker, rotate() function):
(...)
var textElement = d3.select(this);
return justTranslate+"rotate("+ -value+ textElement.centroid() +")";
(...)
Hope this helps anyone with the same issue.
EDIT: for some reason, Chrome's console says:
Uncaught TypeError: textElement.centroid is not a function
But the behavior is what I was looking for. Have no idea why.
EDIT2: ended up changing the above answer to a getBBox() approach, because the slider movement was bonked because of the previous edit error.
Changed it to this:
text.attr("transform", function(d){
var textElement = d3.select(this);
var current = textElement.attr("transform");
var alreadyRotated = current.indexOf('rotate');
var justTranslate = current.substring(0, alreadyRotated != -1 ? alreadyRotated : current.length);
var bbox = textElement.node().getBBox();
var point = [bbox.x + 0.5*bbox.width, bbox.y + 0.5*bbox.height];
return justTranslate+"rotate("+ -value +" "+ point +")";
});
I use the $(window).resize(function()) to get changes in window size, and acoording to those I want to zoom in and zoom out. Why zooming?!, because I have a lot of dynamically appended divs with absolute coordinate and I want those divs to keep the allignment when window is changed.Basically what one would get, if pressed 'Ctrl' + '-'.
Let's say I have this image
If I use .css to add the following line, which zooms out '-moz-transform': 'scale(0.8)' I get an image like this
But if I use Ctrl + - instead I get
As you see the second image has some coordinates messed up(not changed). Has anyone any idea on why that is, or another function I could use to zoom out?
Here is a jsfiddle to play yourself http://jsfiddle.net/rnhev60f/8/
EDIT:: After the responses, I gave up on the idea. Instead I created a function to calculate the percentage of the changes (newSize / originalSize) and used the percentage to change the position and size of every object in order to avoid all backdoors and bugs. It's a bit more comlicated and ended up with a LOC-wise longer function, but works for me for now. Thanks for the responses tho!
You need to scale both the body and the span
Demo
http://jsfiddle.net/tdov936x/
Code
$('body,span').css({'transform': 'scale(' + currentZoom + ')'});
Result
Consider adding transform-origin: 0% 0%; as 2D transformations can change the x- and y-axis of an element
I have an animated SVG path
I can attach a polyline to the end of the path which works (commented out in the codepen) but when I attach a custom path the Matrix coordinates disappear below the page.
You can see this in chrome dev tools if you inspect the bottom blue dot and below that there is a
g transform="matrix(0.8351,0.5501
If you swap the first coordinates out with 'M246' the feet element will appear (at the end of the animation).
So everthing is working apart from the coordinate mapping is off
Does anyone have any suggestions, thanks in advance
Michael
**Code Pen**
http://codepen.io/michaelcockle/pen/eBCAv?editors=001
Think you've already spotted an answer, but you need to account for the transform baked into the path itself, so
meFeet.transform( 't' + parseInt(movePoint.x - 260) + ',' + parseInt( movePoint.y - 1750) + 'r' + (movePoint.alpha - 90));
example here
Example: http://codepen.io/heroheman/pen/thdBH
Hi,
i have this boxed path, which changes the it corner points every second.. Also i have 4 icons which should be on the corner of the box.
Both is based on an array which recalculates the points, and sets new position.
But the position of the circles seems to have some kind of scaling - I tried absolute and relative paths (t and T seems to make no difference).
Maybe one of you guys could help!
You will need to account for the offset of the centre of the circles...
If you look at 'bubble' for example, its cx,rx attribute is 113,101.6
So ideally the transform for bubbles would logically be (new transform - original position)
't' + ( boxCoords[4] - 113 ) + ',' + (boxCoords[5] - 101.6 )
You could either hard code this in an array or object. Or if there are lots of icons, possibly you could grab the icons respective circle element, and get its element.attr('cx') value (or x if its a rect, or previous transform if its an arbitrary shape, or do a getBBox() on it to get its centre).