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!
Related
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
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 working with nokia HERE maps and I want to add an additional layer of visualization graphics on top of a map. Since the possibilities to interact, manipulate and customize the graphics created by the HERE api are limited, I would like to work with d3.js/SVG for my visualizations.
My straight forward and obvious solution would have been to just add an absolute positioned SVG element on top of the map and giving it the same dimensions. But of course that takes every possibility to interact with the map. Is there any solution to add an overlay to the map which allows me to put SVG on it while maintaining the full interactivity (panning, zooming, clicking) of the map? Also it should be possible to interact with the SVG.
I know that there is a possibility to add a custom overlay of tiles provided by a tile server to HERE maps but that's not really what I'm looking for. I'm looking for something like the solution google has to offer to this problem. A set of custom layers which are always in sync with the corresponding map and have their own initialize, draw and remove methods. Is there something similar for HERE maps?
I think you are after the nokia.maps.map.provider.CanvasProvider class. This class provides a ground overlay bound to a specific area which offers a draw() method. The attach() method is the equivalent of your intialize I think, and you can refresh the overlay using update().
Depending upon your use case, I've also found the following techniques useful regarding SVG, Images and HERE Maps:
For an SVG marker which is anchored to a point and doesn't resize
use: SVG Markers
Alternatively override the Marker class and write using the low
level graphics commands to add flexibility to the rendering of a
marker anchored to a point. Like this: Defaced Marker
To add an image bound to a specific area use the ImageProvider class
To add a series of tiled images from a TMS (Tile Map Service) use the ImgTileProvider class
Alternatively if the [zoom][col][row] is useful to you and you
want to write SVG based stuff yourself try something like this example - which combines
SVG with 256x256 pixel markers.
Note that the HERE Maps API for JavaScript only supports SVG Tiny.
A class like the old nokia.maps.map.provider.CanvasProvider isn't even available on the new v3 API from Here.
Your best bet is on Leaflet using custom providers loading Here map tiles. Then you just load this Custom Overlay class and you're all set to draw D3, WebGL, whatever you need. Leaflet only loads the tiles from the providers and exposes some simple APIs. You will not have to deal with any of the providers' APIs.
Just don't forget to add your app_id and app_code to the provider class.
I am new to svg, as far as I saw everywhere they using svg elements within g tag, is there any particular reason for using svg elements within g tag other than applying transformation for whole set of elements?
That's a pretty important and useful reason. But other reasons you might do it are so you can:
apply the same styling (eg. fill="blue") to a set of elements,
reference to the group of objects from a use.
Not to mention the simple organisational reasons.
http://tutorials.jenkov.com/svg/g-element.html says:
The <g> element is used to group SVG shapes together. Once grouped you can transform the whole group of shapes as if it was a single shape. This is an advantage compared to a nested <svg> element which cannot be the target of transformation by itself.
I am using RaphaelJS for a project that requires vector drawing for visualization of some data.
I am not able to figure out how to push and pop transformation states.
(equivalent of context.save() and context.restore() in html5 canvas)
Can someone point me in the right direction?
thanks.
Could you explain why you need to push and pop transformation state?
In svg you don't really need to do that, the browsers do it for you. If you want a particular transform to apply to an element then just add a transform attribute to it. You can make a transform apply to many elements by using <g> elements (in Raphaël there's Paper.set, which can be used like a <g> element, and you have the Element.transform method to set the transforms).
Update:
context.save() - in svg terms this would be to take the current transformation matrix (CTM) of the element at a given time and storing it somewhere, in Raphaël I guess this might be Element.transform() (I'm not 100% sure if it includes whole stack of transformations or not, anyway, in pure svg the CTM can be fetched via the getCTM() method which is available on all elements). One way of doing this would be to insert a <g> element with the transformation you want.
context.restore() - in svg this would be equivalent to removing a transformation from the list of transforms, but note that in svg siblings don't "inherit" the transformation (this is unlike html5 canvas or OpenGL where the currently set matrix is just applied to anything you draw after setting the transform). If you want a transform to apply to many elements then you create a <g> which has the transformation that should apply to all the children of that element, and to restore you just insert elements to the parent of the <g> instead. Raphaël doesn't have any built-in support for the <g> element (unless you count Element.set, which is a similar concept), a guess for why Raphaël does this is that it's to prevent people from trying to do things like this since it becomes very easy to bloat the DOM without realizing it (remember, SVG is a retained mode graphics format, unlike canvas and OpenGL).