I need to rotate the paths in my SVG document around an arbitrary point in 3D. It appears that there are multiple ways to do this by either using a 4x4 transformation matrix or the rotateX or rotateY transforms. I've tried both of these methods, and neither seem to work. Are these supported anywhere?
For my application, a bitmap is going to be the final output, so I'm not worried about browser support. I am open to any tool--I can run a specific browser through selenium, or use a standalone SVG rasterizer.
This is what I've tried so far (using Google Chrome 31):
I would expect this to be a black rectangle, rotated about the X axis, and appearing like a trapezoid.
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000"
transform="rotateX(30 580 100)"></rect>
</svg>
(omitting cy and cz from rotateX gives the same result).
I've also tried with a 4x4 matrix. I don't see any difference from above. I also doubt my math is correct in finding the right matrix elements.
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000"
transform="matrix(102400 0 0 0 0 88681.00134752653 -159.99999999999997 1387899.8652473476 0 159.99999999999997 88681.00134752653 -15986.602540378442)"></rect>
</svg>
I found that there really isn't a way in SVG to do a 3D rotation that is supported in any modern browser (to the best of my knowledge). However, CSS3 does have a similar "transform" property.
The following works for me:
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000" style="-webkit-transform: rotateX(30); -webkit-transform-origin-y: 580px; -webkit-transform-origin-z: 100"></rect>
</svg>
This, obviously, isn't a good cross-browser solution (as it uses prefixed properties), but that isn't something I need in my application.
3d rotations are tricky and i've only just started using them. transform: rotateX() and rotateY() will apply the transformations for you, but to get that perspective of a trapezoid, you'll need to use perspective in the css of the parent element.
Here's a codepen.
The relevant bits are
#parent {
perspective: 4rem;
}
#child {
transform: rotateX(45deg);
}
Think of perspective as the distance the object is from the back of your screen. The lower the value, the more intense the distortion of the perspective will be.
See https://www.w3schools.com/css/css3_3dtransforms.asp :
indeed the CSS code { transform: rotateX(##deg) } and similar for -Y and -Z should work now without prefix in most browsers. But it appears these cannot be combined. So you may want to use the more general method: { transform: rotate3d(x,y,z,angle) } , where you can give an arbitrary rotation axis.
Hope that helps...
Related
I have a moderately large SVG to be displayed as an overlay on a Leaflet map - it's basically a selection of roads from a road network. The leaflet map is instantiated with:
testMap = L.map('mapdiv', { renderer: L.svg({ padding: 100 }) })
.setView([33.085, -96.815], 11);
and the SVG layer is created with:
var imgUrl = url, imgBnds;
L.imageOverlay(imgUrl, imgBnds, {opacity:0.3}).addTo(testMap);
This all displays nicely when zoomed out, but when zooming in, the SVG gets tiled, and only the top-left tile is displayed even though this is not the area being shown in the map.
The SVG has the following:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" x="0" y="0" width="1920" height="767"
clip-path="url(#MapClipRectangle)" style="overflow:hidden;text-rendering:optimizeLegibility" xmlns="http://www.w3.org/2000/svg">
</desc>
<defs>
<clipPath clipPathUnits="userSpaceOnUse" id="MapClipRectangle">
<rect x="0" y="0" width="1920" height="767" />
</clipPath>
<symbol id="1" style="fill:none">
<path d="M985.96 476.76 l-0.26 0.06" />
<!-- ... Many Symbols and Paths, plus some Polygons, Text, Line_artwork, Map_decoration and a Map_frame... -->
And it ends up looking like this (example actually shows the top-left tile, but if I zoom in to the right, you don't actually see anything from the overlay SVG):
How do you stop/control this behaviour?
Sample SVG for which this behaviour occurs
I have not investigated this question in any depth, but in the interest of having some answer at all that might help:
It seems unusual to me that you want to use an svg for geospatial data like a road network.
If someone runs into a similar problem in the future, I would recommend, rather than trying to fix the svg rendering, convert the data to geojson which is more of a standard option for this sort of data display need and then style as needed using the options in leaflet.
To OP, did you ever find a solution?
As a note, it is not clear to me which part of the images posted are svg's vs which parts are basemap or other layers.
I have been trying to get the cross browser compatability working of my svg project. I had a friend test my link on a mobile, but he sais the image doesn't load and he gets a black screen (I assume the black he refers too, is the rect in the background). Does anyone have any idea what is wrong with my code or why the image doesn't display properly on mobile?
svg
<svg viewbox="0 0 3000 2500">
<g transform="translate(225,50)">
<rect width="2550" height="1925" id="background-rect"></rect>
<image href="http://lorempixel.com/output/animals-q-c-640-480-3.jpg" width="2550" height="1925"></image>
</g>
</svg>
Example: https://codepen.io/RobMo/pen/aVvKEP
PS: Just an idea: It might have to do with me not declaring a namespace. I can't test it right now, but that might be what is causing this. Or maybe help people provide inspiration for an answer :).
PPS: To use the <img> tag you need to use xlink:href instead of just href. I should've decared the namespace in the svg tag as well.
What happens when you add a namespace?
<svg viewbox="0 0 3000 2500" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(225,50)">
<rect width="2550" height="1925" id="background-rect"></rect>
<image href="http://lorempixel.com/output/animals-q-c-640-480-3.jpg" width="2550" height="1925"></image>
</g>
</svg>
REF - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
What is the easiest way to transform the (x,y) coordinates of an SVG image in the following way:
x --> x'(x,y)
y --> y'(x,y)
Example:
x --> x^2+y^2
y --> sinx + cosy
The method can either modify the original SVG file or produce a new SVG file containing the modified SVG image.
Remember that SVG includes the following functions:
translate()
rotate()
scale()
skew()
matrix()
I initially thought you could use the matrix transformation function that is available to the SVG system. Because that matrix is static, I'm not positive you will get what you are after. A lot depends on what the transform matrix looks like.
Here's a sample jsfiddle.
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<image x="20" y="20" width="300" height="250" xlink:href="https://upload.wikimedia.org/wikipedia/commons/0/0c/Cow_female_black_white.jpg" />
</svg>
<h2>A skew transformation along the y-axis</h2>
<svg version="1.1" baseProfile="full" width="300" height="400" xmlns="http://www.w3.org/2000/svg">
<image x="20" y="20" width="300" height="250" xlink:href="https://upload.wikimedia.org/wikipedia/commons/0/0c/Cow_female_black_white.jpg"
transform="matrix(1,.5,0,1,0,0)" />
</svg>
Have you looked at the D3.js library for your projection stuff? D3 uses SVG elements, and they've got some pretty good tools. I see folks writing additional tools for that as well. Have you seen the geo projections project for D3 at Github? I do see d3.geo.equirectangular option there. Perhaps that will get you to beer quickly?
I do know you can do much more involved stuff using Canvas. You'd have to convert your SVG image over to Canvas, but that is do-able. Check out this awesome tutorial for swirling an image dynamically, in canvas.
I'm writing a web application which generates SVG images in the browser.
The SVG's I'm generating work fine in ever browser. However, when I download one of the SVG's and try to open it in Adobe Illsutrator, all the transformations are all over the place.
They are in fact so different that you have to zoom right out to see where the shapes are positioned.
This is the contents of the SVG, you can see it's pretty simple. Just a couple of nested SVG's and a few basic shapes:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="592" height="592" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg style="overflow:visible;" x="88.80000305175781" y="88.80000305175781" fill="#777777">
<svg style="overflow:visible;" height="100px" width="100px">
<rect width="100" height="100" style="stroke:#006600;" transform="scale(4.144 4.144)"></rect>
</svg>
</svg>
<svg style="overflow:visible;" width="592" height="592" x="176.60000000000016" y="177.60000000000014" fill="#000000">
<rect width="592" height="592" fill="rgba(0,0,0,0)" stroke="#bbbbbb" transform="scale(0.4 0.4)"></rect>
<svg style="overflow:visible;" x="-0.0000015258789005656581" y="-0.0000015258789005656581">
<svg style="overflow:visible;" height="48px" width="48px">
<ellipse id="SvgjsEllipse1010" rx="24" ry="24" cx="24" cy="24" style="stroke:#006600;fill:#00cc00;" transform="scale(4.933333333333334 4.933333333333334)"></ellipse>
</svg>
</svg>
</svg>
</svg>
I don't know the SVG spec inside out, but I'm doing anything particularly complex, so it all seems good to me. I can't see a reason why Illustrator would render it so differently to browsers.
Does anyone know why this is happening?
Edit
This is what it looks like in Illsutrator, as you can see the scaling and positioning is all off, the small square in the center is the 592 x 592 canvas area, so you can see who far I am zoomed out.
I suspect AI doesn't like/handle/expect nested <svg> elements. Try replacing them with groups. Those with x and y attributes may need to have a transform added to get it to look the same. Also if the overflow is important, you may need to tweak things further as that property is not valid for group elements.
Having two SVG elements ( SVG1 and SVG2 ) where SVG1 is a large area with various elements, that get added, removed and repositioned from time to time. SVG2 on the other hand needs to be used to act as an iconized reppresentation (small) version of SVG1, being quite smaller, but whatever SVG1 shows, SVG2 shows in a very small scale.
<SVG id="SVG1" width=1000 height=1000>
<g transform="scale(1)">
.... elements here....
</g>
</SVG>
<SVG id="SVG2" width=100 height=100>
<g transform="scale(0.1)">
.... elements here....
</g>
</SVG>
I believe the approach is to programmatically synchronize the element changes that end up on SVG1 so they also end up on SVG2, with unique IDs of course.
... but I wonder if there is a simpler way that ensures that, something like a mirroring feature or something that, or alternatively scan down the DOM tree of SVG1 and replicate it into SVG2.
Make the second SVG just a <use> element that points to the first. You can scale the <use> using a transform. It will always reflect whatever you do to the first SVG automatically.
<svg width="100" height="100">
<use transform="scale(0.1)" xlink:href="#SVG1"/>
</svg>