How to set SVG polygon to be fully stretched on any screen resolution? - svg

i need to create polygon which will be responsive to any screen resolution and it will be always fully stretched to screen.
I started with this demo but as you can see it is woriking only for fixed width (1000px) of screen.
Is it possible to set polygon's coordinates with percentage units or is there any other way how to accomplish that?

You need to set a viewBox rather than a fixed width and height.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 20" preserveAspectRatio="none" width="100%" height="100%">
<polygon points="0,0 1000,0 500,20"
style="fill:#cc3333;"/>
</svg>

Related

SVG Scaling and viewBox

Here is a simple SVG file:
<svg xmlns="http://www.w3.org/2000/svg" width="100mm" height="100mm" version="1.1" viewBox="0 0 377.95 377.95">
<rect x="0" width="189" height="189" stroke="black" stroke-width="6" fill="red"/>
</svg>
This renders a 100mm x 100mm box with the top left corner at the origin as expected.
If I change the viewbox to:
viewBox="0 0 177.95 177.95"
then the box is scaled up, still with the top left corner at the origin, as expected.
However, if I change only the width of the view box like so:
viewBox="0 0 177.95 377.95"
then then box is not scaled but is moved along the X axis.
I thought only the first two parameters of the viewbox affected the translation? Also why isn't the box stretched in the X direction?
Does the viewbox scaling only work correctly if the scaling is the same in both X and Y directions?
Thanks!
How the viewport is scaled in actual dimensions (embed frame) of the SVG is governed by preserveAspectRatio attribute.
See MDN entry and/or refer too Understanding SVG Coordinate Systems and Transformations by Sara Soueidan.

Clipping an image with a preserved aspect ratio using a polygon that doesn't need to have its aspect ratio preserved

I'd like to create a responsive SVG that consists of an image clipped by a polygon.
The image needs to preserve its aspect ratio and get cropped, while the polygon needs to adapt in width to its container but preserve the same height.
I don't want the whole thing to scale homothetically.
visual explanation of the issue
If I set preserveAspectRatio="none" to the svg, the polygon stretches like planned, but the image is then distorted. I've tried setting preserveAspectRatio="xMidYmid slice" to the image, but since the svg is set not to have its aspect ratio preserved it doesn't work as planned.
Here's my current code:
<svg viewBox="0 0 1440 810" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="clip">
<polygon points="0 750,1440 810,1440 60,0 0" />
</clipPath>
</defs>
<g aria-hidden="true" clip-path="url(#clip)">
<image
opacity="0.75"
preserveAspectRatio="xMinYMid slice"
xlink:href="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Monasterio_Khor_Virap%2C_Armenia%2C_2016-10-01%2C_DD_25.jpg/2880px-Monasterio_Khor_Virap%2C_Armenia%2C_2016-10-01%2C_DD_25.jpg"
/>
</g>
</svg>
Thanks in advance for your help.

Programmatically centering svg path

I'm working on a PHP script that generates a jpg wallpaper from an SVG-file according to the screen resolution of the visitor. The wallpaper consists of a circular gradient (rectangle) background and a path on top of it. How would you go about centering the path horizontally and vertically to the rectangle? Remember that the rectangle's size and proportions are not a constant. Should I separate the background and path to different svg files or is there an easy way to center paths? Maybe a framework?
This is easilly achieved by using nested <svg> elements and the preserveAspectRatio attribute. Put your background in the outer svg and your path in the inner one.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%">
<rect id="background" width="100%" height="100%" fill="grey"/>
<svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 30 40" width="100%" height="100%">
<g>
<circle cx="15" cy="20" r="10" fill="yellow"/>
<circle cx="12" cy="17" r="1.5" fill="black"/>
<circle cx="18" cy="17" r="1.5" fill="black"/>
<path d="M 10 23 A 8 13 0 0 0 20 23" stroke="black" stroke-width="2" fill="none"/>
</g>
</svg>
</svg>
Run this snippet and try resizing the window.
To get this to work, all you need to ensure is that the viewBox attribute on the inner <svg> element is correctly set.
If you know the coordinates of the paths, you could take the total of the x/y coordinates and divide by the number of coordinates, this will give you the average position for the coordinate set. Then, offset each coordinate by the coordinates for half the width/height of the square, plus any offset, minus the difference between the center of the coordinate set and half the width/height of the square.
This should result in your coordinates being centered within the square, I think (it is rather early here, and I've just started my first coffee, so I could be wrong). This is of course assuming you know all the variables in play (the width/height of the square, any offset applied and the coordinates of the path).

How to get correct SVG dimensioning / aspect ratio?

I'm making some pointers by hand coding svgs. I have defined a polygon using points in a 100x100 square and gotten the aspect ratio that I want by setting the width and height attributes of the outer SVG element. Here is a jsfiddle of the graphic: http://jsfiddle.net/62WpR/.
Unfortunately, the text is being compressed by the width and height attributes. Is there any way to use these without compressing text, or doing something silly like applying a transform to it?
If this is not possible, I guess I will have to define paths in a coordinate space with the final aspect ratio that I want. Disappointing.
Solved it kind of.
By setting the viewbox to a 1:2 ratio and using transforms on both of the polygons in the svg, I was able to get the dimensions I wanted. As long as the dimensions in the CSS are set to a 2:1 ratio, the graphic will display right.
I have also made judicious use of the preserveAspectRatio property to keep the image at the same aspect ratio. I'm only setting the width in the CSS: http://jsfiddle.net/62WpR/3/
<svg baseProfile="full" contentScriptType="text/ecmascript" contentStyleType="text/css" id="svg" preserveAspectRatio="xMinYMin meet" version="1.2" viewBox="0 0 100 50" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(1 .5)" stroke-linejoin="bevel" stroke="black">
<polygon vector-effect="non-scaling-stroke" fill="#666" id="tab" points="20.0,95.0 5.0,50.0 20.0,5.0 90.0,5.0 95.0,15.0 95.0,85.0 90.0,95.0"></polygon>
<polygon vector-effect="non-scaling-stroke" fill="#FFEA00" id="insert" points="25.0,95.0 10.0,50.0 25.0,5.0" visibility="visible"></polygon>
</g>
<text fill="white" font-size="30" text-anchor="middle" x="60" y="36">999</text>
</svg>​

Fixed stroke width in SVG

I would like to be able to set the stroke-width on an SVG element to be "pixel-aware", that is always be 1px wide regardless of the current scaling transformations applied. I am aware that this may well be impossible, since the whole point of SVG is to be pixel independent.
Context follows:
I have an SVG element with its viewBox and preserveAspectRatio attributes set. It looks something like this
<svg version="1.1" baseProfile="full"
viewBox="-100 -100 200 200" preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg" >
</svg>
This means that when I scale that element, the actual shapes inside it scale accordingly (so far so good).
As you can see, I have set up the viewBox so that the origin is in the center. I would like to draw an x- and a y-axis within that element, which I do thus:
<line x1="-1000" x2="1000" y1="0" y2="0" />
Again, this works fine. Ideally, though, this axis would always be only 1px wide. I have no interest in the axes getting fatter when i scale the parent svg element.
So am I screwed?
You can use the vector-effect property set to non-scaling-stroke, see the docs. Another way is to use transform(ref).
That will work in browsers that support those parts from SVG Tiny 1.2, for example Opera 10. The fallback includes writing a small script to do the same, basically inverting the CTM and applying it on the elements that shouldn't scale.
If you want sharper lines you can also disable antialiasing (shape-rendering=optimizeSpeed or shape-rendering=crispEdges) and/or play with the positioning.
Here is a more concise answer based on Erik's answer to help you get started quickly.
<div style="background: blue; width: 100%; height: 130px;">
<svg xml:id="root" viewBox="0 0 100 100" width="100%" height="100%" preserveAspectRatio="none">
<rect xml:id="r" vector-effect="non-scaling-stroke" x="0" y="0" width="100" height="100" fill="none" stroke="#88CE02"
stroke-linecap="square" stroke-width="10" stroke-miterlimit="30"/>
</svg>
</div>
Adding the vector-effect="non-scaling-stroke" to the SVG rect makes the border size (or stroke size) fixed.

Resources