I have a set of dynamically created svg objects. Some of them have rather complicated transformations applied to. I mean this is meaningless that I want to calculate maximum and minimums of X & Y of these objects. I want viewbox (or any similar tag that may be useful) to show all these objects without engaging me in calculating extents of drawing objects.
Could you please help?
Thanks
You can use getBBox() on the path element to get the extents of your drawing.
var clientrect = path.getBBox();
var viewBox = clientrect.x+' '+clientrect.y+' '+clientrect.width+' '+clientrect.height;
You can then set the viewbox to these co-ordinates.
n.b. i think you can change the viewbox of an svg after it's rendered so you may have to re-render the svg.
Related
I am using Inkscape to make SVG image and a little confused about the "transform-center-x" attribute like below:
<circle
style="display:inline;fill:#0000ff;fill-opacity:1;stroke:#000000;stroke-width:1.13386"
id="beacon-21737"
cx="-121.04593"
cy="42.20393"
r="1.9999999"
inkscape:transform-center-x="-0.6614634"
inkscape:transform-center-y="-10.318751"
inkscape:label="beacon"
transform="rotate(-90)">
</circle>
It seems not equal to rotate(angle, x, y). Please help me understand the meaning of the "transform-center-x/y".
This is a property of the grafical interface. If you click twice on a grafical object, you can rotate or skew it around a center indicated by a cross:
The cross can be moved by dragging it. Its position is stored in the inkscape:transform-center attribute. The value is in coordinates relative to the center of the bounding box of the grafical object. This position will also be used for other transforms, for example when you use the Object -> Transformation... dialog.
The SVG namespace transform will not reflect that center. Inkscape has an internal optimization algorithm to express rotations and other transforms, so the grafical and the standardized center might not coincide.
As always, other renderers will simply ignore tags and attributes in the inkscape namespace.
I am looking for a way to determine the actual value of attributes such as fill or stroke of elements contained in an SVG (path, circle, ...). I know of several ways to parse an SVG and access direct element attributes, but I can't find an easy way to determine the value of an attribute as it will be displayed taking into account cascading styles and xlink:href references.
The method window.getComputedStyle applied to the element does exactly that!
My objective here is to allow users to specify territories or regions given a background world-map overlay, which is an SVG generated from GeoJSON data using D3. I have done the part where the territories' points are pinpointed by the user, and an SVG is generated. This works well.
Now I would like to save the territory's coordinates, using the background map's projection, scale and translation. I saw a lot of documentation about translating GeoJSON data to SVG s, but nothing about the other way. Is it even possible ?
Thanks Ben Lyall, eventually I used the native SVG functions getTotalLength() and getPointAtLength() to convert my path to an array of top/left positions (in pixels), then d3's projection.invert() to translate them into coordinates.
I'm trying to rotate and scale shapes within an SVG around their center point. I've looked into several libraries, including Jquery, Greensock, D3, RaphaelJS, but I haven't been able to find any that provide a straightforward way to accomplish this. Each animates the shape from the origin point (which I understand is the default). I want to be able to spin a shape around its center point or scale it up or down from the center point.
Here are a couple examples using Greensock and D3 that illustrate the default behavior: http://jsbin.com/AHEXiPa/1/edit?html,js,output
Each of these examples bounce in and out from the top left as opposed to remaining stationary and expanding from the center of the triangle out in all directions.
Can one of the libraries I mentioned accomplish this, or is there another library or method I should consider?
Ideally, I need to be able to apply the animation/transform to an existing object in the DOM. D3 is good at this for instance, but Raphael seems to require converting an SVG to Raphael first prior to injecting it into the DOM.
Really its a case of pick the library that suits your needs, and then you will figure a way. As BigBadaboom says, if you do a search, there are lots of solutions.
To try and combine your questions, as sometimes the tricky bit is using an existing DOM object, I've included an example in Snap.svg. You can often do something similar in most libraries.
jsfiddle here Fiddle using your existing html.
s = Snap("#mySVGContainer1"); // create a canvas from existing svg
var triangle1 = s.select("#myShape1").transform("r90"); //select&transform existing object
p = Snap("#mySVGContainer2");
var triangle2 = p.select("#myShape2");
var bbox = triangle2.getBBox(); //bounding box, centre cx/cy
//rotate and scale with transform string (raphael/snap format)
triangle2.animate({ transform: "r180," + bbox.cx + ',' + bbox.cy + "s3,3," + bbox.cx + "," + bbox.cy }, 2000);
For rotations, as #Ian points out, you can specify the center of rotation. For other transformations, changes are defined relative to the path's (0,0) point.
The easiest way to get transformations to work relative to the path's center is to either:
Define the path so that it is centered around the (0,0) point; or
Wrap the path in a <g> element, and then translate it so it is centered on the (0,0) point of the <g> element's coordinate system.
Then, you can apply rotations, scales and transforms (on the <g> element, if using) and they will all be nicely centred.
The trickiest part is figuring out the "center" of an arbitrary shape. #Ian's approach of using the center of the bounding box will usually give decent results. If your shape is a polygon there are d3 functions you could use.
Example showing a shape moving with the mouse, rotating and changing scale, all centered around the center of the bounding box:
http://fiddle.jshell.net/LgfE3/
Edit: simplier jsfiddle
I've been looking for a long time, and will settle for the following.
1. Design your svg shape at coordinate x:0,y:0.
2. Identify by hand the center of rotation, by example, center = [ x:50,y:100].
3. Build a spinIt() function such :
function spinIt() {
needle.transition()
.duration(2000)
.attrTween("transform", tween);
function tween() {
return d3.interpolateString("rotate(-180, 50, 100)", "rotate(90, 50, 100)");
}
}
4. Use it on a triger:
svg.on("click", spinIt);
http://jsfiddle.net/SHF2M/79/
I'm trying to draw a map of NYC using d3. I've downloaded a bunch of shapefiles from http://www.nyc.gov/html/dcp/html/bytes/dwndistricts.shtml. I've converted them to geoJSON using http://converter.mygeodata.eu/, such that they're in WGS 84 (aka, I think, latitude and longitude).
I'm pretty sure the geoJSON is valid: I can plot it using matplotlib and it looks like NYC, and the numbers seem to be in a valid range. Here's my javascript:
var path = d3.geo.path()
d3.select("body")
.append("svg")
.attr("height", 1000)
.attr("width", 1000)
.append("g")
.selectAll("path")
.data(data.features)
.enter()
.append("path")
.attr("d", path)
.style("stroke","black")
.style("stroke-width","1px")
This plots, as advertised, the Albers projection of NYC. Trouble is, I think, that the scale of the projection is chosen so that the US fits onto a nice webpage, making the paths for NYC a little squiggle at the right-hand-side of the screen.
What's the 'correct' way (lemme try to claim to be the first to say d3onic) to scale a geo.path() such that the extents of my lat/lon scale onto the width and height of my SVG?
(little disclaimer: apologies if I've missed something obvious, this is for a project I'm trying to complete at the extreme ends of the day)
First, you'll want to create a projection, and assign that to the d3.geo.path, so that you can customize the projection settings.
var albers = d3.geo.albers(),
path = d3.geo.path().projection(albers);
The default projection is d3.geo.albersUsa, which is actually a composite projection (with four different discontinuous areas) designed for showing the 48 states, Alaska, Hawaii and Puerto Rico. Ah, ethnocentrism. ;)
Use the albers example in the git repository to determine the correct projection settings interactively. The settings you need to set are:
the origin should be NYC's latitude and longitude (perhaps 73.98°, 40.71°)
the translate should be the center of your display area (so, if you're drawing something 960×500, you can use the default 480,250; this will be the pixel location of the origin)
the scale is some number that specifies how much to zoom-in; since you're drawing a city-scale map, you probably want a value more like 10000
Lastly, you'll need to pick some parallels. You can use the defaults provided by d3.geo.albers(), but there might be more suitable ones for NYC. Possibly check with the USGS, because they often publish standard parallels for different map areas.