Following two lines of SVG code produce the same output:
<rect x="-172" y="270" width="154" height="137" rx="14" ry="14" transform="rotate(-90)" />
<rect x="270" y="18" width="137" height="154" rx="14" ry="14" />
I think, in this particular case (90 degree rotation) a conversion could be performed easily, in theory.
Can InkScape recalculate one into another in this particular case?
Following question Removing transforms in SVG files covers automatic removal of transform="translate()", but it doesn't work for transform="rotate()".
Related
I want to rotate an image in an svg file by x degrees in the very straightforward way, on the command line (not via a gui program), such that if a picture were on your kitchen table the picture would be simply turned around to face to the side, or where ever - i.e. real straightforward (one hopes).
[ADDED INFO]: the svg file is from gnuplot multiplot mode, in particular - but of course gnuplot has many terminals. I say this because multiplot appears unable to rotate the computed image by 90 (in the "do what I mean" sense - even though the statement in plain English does not make sense ); however, multiplot can do that to rgb files - see the famous tutorial page with Tux images.
If an svg file is given to convert to rotate by 90 degrees (for instance) :
convert -rotate 90 test_start.svg test_plus_90.svg
stderr (I guess) is reported:
convert-im6.q16: delegate failed `'potrace' --svg --output '%o' '%i'' # error/delegate.c/InvokeDelegate/1966.
no output is produced and the original file is unchanged. if mogrify is used instead, the same error plus this one is issued [ UPDATE: this has to do with the output file, but I'll leave this as it is trivial]:
mogrify-im6.q16: unable to open image `test_plus_90.svg': No such file or directory # error/blob.c/OpenBlob/2924.
the original file is then appended with a tilde, as test_start.svg~, but appears unchanged.
png and jpg files will process this way fine. It appears that some resources need to be installed, as the "Delegates" for convert do not include svg - or this is the incorrect way to process svg files, I am wrong, etc.
version and system information:
Ubuntu 22, synaptic used to install everything.
ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25
Delegates do NOT include svg, so this appears to be what I need to understand.
gimp version 2.10.30
tl;dr You are better off first rendering your SVG image as a raster image, with the final dimensions for display, and only then flipping it around. Or, depending on your use case, quoting the image in a reference and rotating the result.
Flipping a SVG image by 90° is not a straightforward task, if you want the result to be still in SVG format. At least if you tried to write a tool that covered all the necessary bases for it not to produce seriously botched pictures. Let me give you an example:
<svg xmlns="http://www.w3.org/2000/svg" width="150vh" height="100vh" viewBox="0 0 400 200">
<rect x="1" y="1" width="398" height="198" fill="#ccc" stroke="#000" />
<circle r="10" cx="5%" cy="50%" fill="#00f" />
<circle r="10" cx="50%" cy="50%" fill="#00f" />
<circle r="10" cx="95%" cy="50%" fill="#00f" />
</svg>
How would you change that file to flip it around? You would exchange the width and height attributes on the root element, equally the corresponding values in the viewBox attribute. (If there was a preserveAspectRatio attribute, it would also have to be converted, but I'll leave that out.) Then, the content inside has also to be rotated by 90°. Wrap all content in a <g> element with an appropriate transform attribute:
<svg xmlns="http://www.w3.org/2000/svg" width="100vh" height="150vh" viewBox="0 0 200 400">
<g transform="rotate(90, 100,100)">
<rect x="1" y="1" width="398" height="198" fill="#ccc" stroke="#000" />
<circle r="10" cx="5%" cy="50%" fill="#00f" />
<circle r="10" cx="50%" cy="50%" fill="#00f" />
<circle r="10" cx="95%" cy="50%" fill="#00f" />
</g>
</svg>
Oops. What happened? The cx/cy values of the circles are percentages of width and height of the viewBox, which are already exchanged. But then the rotation is applied, and axis directions for the purpose of positioning are at odds.
This is obviously not the way to go about it. A conversion tool would have to sift through the complete code looking for these sort of pitfalls and correcting attributes. And let me assure you, I can think of a lot of tricky constructs that would trip implementers.
Here is a second attempt. <svg> elements can be nested, and they encapsulate their viewport completely. Instead of changing content, wrap the root element in another one and flip the now inner <svg> as a whole.
But there is a pitfall to avoid: A construct like
<svg ...>
<svg transform="rotate(90)" ...>
is only part of the SVG 2 specification. While browsers mostly have implemented that, other renderers may still disregard the transform attribute on the inner <svg>, as prescribed by the SVG 1.1 spec.
Thus you need to introduce an extra <g transform="..."> element:
<svg xmlns="http://www.w3.org/2000/svg" width="100vh" height="150vh" viewBox="0 0 200 400">
<g transform="rotate(90 100,100)">
<svg width="400" height="200" viewBox="0 0 400 200">
<rect x="1" y="1" width="398" height="198" fill="#ccc" stroke="#000" />
<circle r="10" cx="5%" cy="50%" fill="#00f" />
<circle r="10" cx="50%" cy="50%" fill="#00f" />
<circle r="10" cx="95%" cy="50%" fill="#00f" />
</svg>
</g>
</svg>
Well, it seemed to work. Note that the width/height attributes on the inner <svg> needed to be changed. (I assume there is a valid strategy even if one or two of the sizing attributes are missing in the original file, but haven't tested them all.) But imagine a tool flipping the image multiple times. Would it wrap the previous version each time with new outer elements? Would it try to analyze the structure and fold possible multiple applications of flipping into one? Most developers would probably cringe instead of writing such a tool.
This is not to say that one like this does not exist, But I don't know about it. It is so much easier to change your workflow: stall the flipping to the moment when you render the SVG image to a raster format, and do the flipping afterward and on-the-fly, where it is an easy task.
If you are using the SVG as an image in other content, it is equally easy to combine rotating with referencing. For example in HTML/CSS:
<img src="myImage.svg"
style="width:...;height:...;transform:rotate(90deg);transform-origin:...">
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.
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 have an SVG-based loading animation, aka "spinning weasel" but I'm wondering if I can code this more efficiently by utilizing a base animation (the fading out attributes) and referencing it in my <use> tags?
<defs>
<line
id="bit"
x1="50"
y1="25"
x2="50"
y2="10"
stroke="#000000">
</line>
</defs>
<g>
<use
xlink:href="#bit"
opacity="0.8"
transform="rotate(0 50 50)">
<animate
attributeName="opacity"
values="1;0.2"
dur="2.4s"
repeatCount="indefinite"
begin="0.0s"
/>
</use>
</g>
There are 12 of these <use> tags, I omitted them here for brevity. in the animation tag, only the begin attribute changes each time, the rest is identical.
I tried various approaches that seemed reasonable to me, but none work, so I'm hoping some SVG guru here can point me in the right direction. Or am I basically forced to repeat all the animation attributes on each of the tags?
Knowing just a little about SVG, I realize that there are many ways to accomplish the same result.
Thanks.
--> Fiddle
I don't think you can do exactly what you are trying to do because begin is an attribute of the animation elements and not a property that can be inherited from a use.
Depending on what you mean by "more efficient", there are other ways to achieve a similar effect. For example, you can use scripting:
http://jsfiddle.net/rzAwV/1/
This is a smaller file, but the animation is not as smooth because we are just rotating the spinner, rather than animating the opacity.
In my markup, I have a chunk like this:
<svg width="0" height="0" style="display:none" id="dummy-wedge">
<g class="dummy" transform="translate(100, 100)">
<defs>
<clipPath id="clip1">
<polygon id="clip1Shape" points="-100,-100 0,-100 0,0 -100,-20" />
</clipPath>
</defs>
<circle id="" cx="0" cy="0" r="52" fill-opacity="0"
stroke="#ffffff" stroke-opacity="0.6" stroke-width="50"
pointer-events="visiblePainted" clip-path="url(#clip1)" />
</g>
</svg>
What I'm wanting to do is grab that chunk and clone it into a different svg root element to create a bunch of wedges, each with a different position and clip segment. That part is cool, but the frustration is that each cloned clipPath element will need to receive a new ID which will then have to be inserted into the clip-path attribute of the matching element.
I know that if all the arcs were the same length, I could have a common clip and use rotate transforms, but they aren't necessarily the same length.
Is it possible to declare a clip polygon using a topological relationship rather than by explicitly naming it? Alternatively, is there a better way to define an arc like this outside of using paths?
Thanks.
Why do you need to use clipping? Couldn't you just use path elements with the various arc segments in them?
There's no declarative way (yet) to get the behaviour you are after, but this is what the SVG Parameters specification is meant to address. Look at the examples there and the script implementation provided for processing the content (as a way to support the current browsers). NOTE: it's still a working draft, and is subject to change.