Creating THREE js extrudeGeometry from svg path - svg

I'm trying to generate a 3d map of the boroughs of London using Three js. I've reverse engineered this example: http://threejs.org/examples/webgl_geometry_extrude_shapes2.html
using this svg file: https://upload.wikimedia.org/wikipedia/commons/2/29/London-boroughs.svg
So, I'm passing svg path strings such as:
M130.833,250.833L135.5,262.5l14,42.667l-6.333,4l-4.667,3.667l1,3.666l-14.333,3 c0,0,0.333,3.334,4.667,5.667s16,2.667,17,3.667s0.667,6.333,0.667,6.333l-5.667,6.333l-0.667,6.667l-1.667,2l-3.333,1.333l-4.667,6 l-1.333,10l-2.667,8l-4-0.333c0,0,0.667,6.001-0.333,9.667s-2,9.666-5,11.333S112.5,396,112.5,396"
into the transformSVGPath function, and it kind of works except the vertices seem to be interpolated badly.
I get the console error "three.js:34023 THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()" and it looks like this:

On examination of the SVG, it is a collection of lines over a primary closed shape. The primary shape is the first element in the SVG file and encompasses all of London. The rest of the paths are simply lineTo and bezier curves which define the borders. This is done so that the svg file size will be efficient and that shared edges of boroughs are not doubled - a classic 2d mapping issue. 3d is a different problem space - extrude path in Three.js requires discrete outline shapes to form a complete closed shape. This SVG file is unusable for 3d or polygons. You're better off finding each borough as a single SVG/polygon and importing them each individually if you can find them.
I believe you will find this file more usable as each borough is a discrete shape, but it will still need tayloring to remove the strokes: https://commons.wikimedia.org/wiki/File:London_boroughs.svg

Related

Recalculating path's array after modification - fabricjs

After moving, rescaling or rotating a path in fabricjs, I would like to recalculate the path's array coordinates in order to use them later to draw the exact same path on a plain HTML5 canvas.
I have gotten around rotation by storing the angle and then performing a transformation of the whole html canvas. For translation I tried recalculating the points like so:
point[1] = (point[1] + modifiedObject.left - oldState.left);
point[2] = (point[2] + modifiedObject.top - oldState.top);
but this messes up with rescaling on fabric.
I also tried using the transformation matrix on the points, but this didn't work either and I think it's because I am missing some steps in between.
Any help would be appreciated.
Here's a simple demo of what I'm trying to do in essence: https://jsfiddle.net/1b68eLdr/86688/

Is it possible to translate an SVG path to GeoJSON?

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.

How do I rotate or scale (transform) an SVG path relative to its center point?

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/

D3 Sunburst clip path of text

I am trying to implement a d3 visualization based on the sunburst diagram, and i have found an almost perfect online example of this which i have got working http://tributary.io/inlet/4127332/:
My main issue is that I need to also Clip the text to the segment,I have tried using the svg clip path but my meager d3 skills have let me down. Any help with this is appreciated.
So my first attempt to clip the text did not work and I think this is because the arc's coordinate space does not line up with the text's coordinate space in the way that you want if you are using the arc generator, as you are.
I found that if I apply the clip to the groups you make for each node then it worked like a charm. There was one caveat. When I tried generating my clip path and then applying them the order that the nodes were joined to the elements differed and so the wrong path were clipping the wrong text. I got around this by adding an id to each data element. You can see the final version here
The important parts are adding the clip paths (note the use of the new id field):
svg.append('defs')
.selectAll("clipPath")
.data(partition.nodes)
.enter().append('svg:clipPath')
.attr('id', function(d,i) { return d.id;})
.append('path').attr('d', arc);
Then you simply have to reference them on your node groups (again using the id):
group =
svg.selectAll("g")
.data(partition.nodes)
.enter().append('svg:g')
.attr('clip-path', function(d,i) { return 'url(#' + d.id + ')';});
In the tributary I put the svg data join first so that the "defs" node would appear in the usual place (first after the svg tag), but I do not think this is technically necessary.

Transform SVG group to create perspective ("trapezoid transform")

Is there any way to create an SVG transform that would transform a square into an isosceles trapezoid to give the illusion of perspective?
I have a project (visible here) where I have one element group in the svg (the breadboard) that I would like to skew so that the bottom looks like it's a closer to the user.
I can transform the top-level SVG DOM element with a CSS transform (in supporting browsers) using something like "-webkit-transform: perspective(1000px) rotateX(40deg);", but this doesn't work in the nested group element.
Any suggestions appreciated, thanks!

Resources