see this simple code code:
<svg width="400" height="400" viewBox="0 0 50 200">
<rect width="50" height="200" style="fill:blue"/>
</svg>
expected result:
the viewBox settings will perfectly crop the rectangle, then stretch it across 400x400 svg viewPort.
resulting in 400x400 blue square.
actual result
blue rectangle, in the middle of the svg viewport, with white marigins in the sides.
what did i miss?
Related
I currently have an svg path that only shows about 50%. How can I get it to show 100%?
Here is my code:
<div className="svgPathContainer">
<svg width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
<path d="M82 88L0 0H123V170H0L82 88Z" fill="#F9B300" />
</svg>
</div>
I have className="svgPath" set as:
.svgPathContainer{
width: 100%;
height: 100%;
}
Here is also an example of the svg only showing at 50%:
https://codesandbox.io/s/svg-scaling-fff1q?file=/src/App.js:93-357
The problem: Why wont the svg path scale to 100% of the .svgPathContainer?
The viewBox is like a canvas size. So drawings outside of this view box will be clipped. Like css overflow: hidden. And your drawing has a size of width 123px and height 170px. So you have to change the view box to this value. Check our some docs.
If you want to keep the viewbox of 100 x 100 px, you need to change your drawing element size (path).
The view box has nothing to do with the scale. It's just the canvas size. A rect clip with width, height and offset (x y w h) for the SVG elements inside. And the SVG tag's width and height attributes are for scale the rendered image.
<div className="svgPathContainer">
<svg width="100%" height="100%" viewbox="0 0 123 170" preserveAspectRatio="none">
<path d="M82 88L0 0H123V170H0L82 88Z" fill="#F9B300" />
</svg>
</div>
I want to fill a viewport with an svg, and add a fill to a path in this svg.
When I set preserveAspectRatio="xMinYMin slice" to the image pattern, it will preserve it's aspect ratio nicely, but the path will not scale.
If I then add preserveAspectRatio="none" to the svg element, the whole element will fit to the viewport, but my image will not scale properly.
What am I overlooking?
<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 750" preserveAspectRatio="none">
<defs>
<pattern id='home' width="1" height="1" preserveAspectRatio="xMinYMin slice">
<image xlink:href='https://i.imgur.com/4AiXzf8.jpg' width="100%" height="100%" preserveAspectRatio="xMinYMin slice"></image>
</pattern>
</defs>
<path id="bg" class="cls-1" d="M0,0V622.58S250,711,683,711s683-88.42,683-88.42V0Z"style="fill: url(#home)"></path>
</svg>
If you set the whole SVG to preserveAspectRatio="none", then everything inside the SVG will stretch and there is no way to counteract that. So you have to do it a different way.
What we have to do is remove the viewBox and the preserveAspectRatio and just set the width of the SVG to 100% and the height to the height of our <path> (711px). That way the SVG viewport fills the width of the page and keeps it's height at the size we want.
The next step is to move the <image> out of the <pattern>, make its width and height 100% x 100% and set preserveAspectRatio="xMinYMin slice". So it now scales to fill our wide SVG, and keeps its aspect ratio.
The last step is to apply a <clipPath> to the image to give it the shape we want. To get the clip path to automatically fit itself to the <image>, we need to use clipPathUnits="objectBoundingBox".
The thing with objetBoundingBox units is that (0,0) represents the top left of the element it is applied to, and (1,1) corresponds to the bottom-right of the element it is applied to. But our path is much bigger than that. It has a width and height of 1366x711.
To fix that, we need to scale the path so that it is only 1x1 in size, instead of 1366x711. So we apply a transform and scale it by 1/1366 in X, and 1/711 in Y.
transform="transform="scale(0.000732, 0.001406)"
The final result is this:
body {
margin: 0;
padding: 0;
}
<svg width="100%" height="711px" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<path d="M0,0V622.58S250,711,683,711s683-88.42,683-88.42V0Z"
transform="scale(0.000732, 0.001406)"></path>
</clipPath>
</defs>
<image xlink:href='https://i.imgur.com/4AiXzf8.jpg' width="100%" height="100%" preserveAspectRatio="xMinYMin slice"
clip-path="url(#clip)"></image>
</svg>
remove height and preserveAspectRatio but keep viewBox as it is and width at 100%.
Given this code of svg, a blue rectangle is being drawn.
<svg>
<rect width="50" height="200" style="fill:blue"/>
</svg>
The blue rectangle size varies depending on the view port.
I assume that the unit 50 for the width property, is not just plain pixels. Otherwise it would have been the same across different screens.
So what is exactly the meaning of this unit?
The unit of measurement is pixels. You are not getting the correct result due to the behaviour of vector drawing in the svg element.
If you specify a height and width on your svg you will find the rectangle behaves as expected.
<svg width="400" height="400">
<rect width="50" height="200" style="fill:blue"/>
</svg>
The svg size should be the maximum extent of all content contained within it.
If only a rectangle resides inside it then you can make the containing svg the size you desire and simply use height / width 100% on your rectangle.
<svg width="50" height="200">
<rect width="100%" height="100%" style="fill:blue"/>
</svg>
I am working with SVGs, and would like to create one with a transparent background. The following example, should appear as just a white circle with a path in it. However, the whole 300px white canvas appears as a square, how do I get the result I want, as I can't really see where the canvas is defined?
<?xml version="1.0"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" height="300" width="300" version="1.1" xml:space="preserve">
<circle fill="#FFFFFF" cx="150.267" cy="149.854" r="111.303" fill-opacity="1"/>
<g transform="translate(0.000000,632.000000) scale(0.100000,-0.100000)" fill-opacity="1">
<path fill="#54534A" d="M2204.344,4414.691v-122.67h81.643h81.642l-1.237,6.804c-0.619,3.505-1.649,10.515-2.474,15.462l-1.443,8.659
h-61.438h-61.644v38.141v38.141h54.635h54.635v16.493v16.494h-54.635h-54.635v36.079v36.08h60.613h60.407l1.443,10.515
c0.825,5.979,2.062,13.401,2.68,16.493l1.237,5.979h-80.818h-80.612V4414.691z"/>
<!-- Other paths omitted -->
</g>
</svg>
Appears as a 300 x 300px rectangle with a transparent background here with a smaller white circle inside and the letter E(path).
You sure you're not giving the svg element a white background with CSS by accident?
The canvas is the <svg> element itself, you can change its background using CSS:
svg {
background: red;
}
I am trying to use Turkey's map which was created before here.
I have changed the dimensions of svg element
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
width="800"
height="600"
style="shape-rendering:geometricPrecision;
text-rendering:geometricPrecision;
image-rendering:optimizeQuality;
fill-rule:evenodd;
clip-rule:evenodd"
viewBox="0 0 180 180">
When I change viewBox values to
viewBox="0 0 200 200"
the map is rendered in smaller size.
If I set the values to "0 0 10 10" image is not displayed.
If I set the values to "0 0 50 50" a huge image comes overflowing the page
If I set the values to "0 0 100 100" image is fine.
But I don't understand how it is working.
An SVG canvas is basically an endless plain, where you can put all your objects in.
The width and height you define the size of the image as shown in the browser. This works pretty much like with any other image you can include in HTML.
With the viewBox attribute on the other hand you select the part of that plain, you currently want to view.
So with a value of "0 0 10 10" you set the upper left point of the shown image to the point 0/0 and from there select 10 units to the right and bottom for your image. In your example in those upper 10 times 10 units area there is nothing, hence you see just a transparent area, which you perceive as "not being displayed".
With a value of "0 0 50 50" the shown area gets bigger and you'll start to see the upper left corner of the picture. The first parts of the map become visible.
Finally with "0 0 100 100" you can see pretty much half of the upper map.
The area you select using viewBox is the scaled to the height and width of the SVG element. With both combined you can enabled stuff like zooming into an SVG.
You can control the scaling with the attribute preserveAspectRatio.
You can add the following code at the bottom of the SVG file and see the displayed boxes (make sure to set the viewBox="0 0 180 180" before):
<rect x="0" y="0" width="100" height="100" style="stroke: blue; stroke-width: 1; fill: white; opacity: 0.8" />
<rect x="0" y="0" width="50" height="50" style="stroke: green; stroke-width: 1; fill: none;" />
<rect x="0" y="0" width="10" height="10" style="stroke: red; stroke-width: 1; fill: none;" />
<text x="5" y="97" style="fill: blue; font-size: 5px;">100x100</text>
<text x="5" y="47" style="fill: green; font-size: 5px;">50x50</text>
<text x="5" y="15" style="fill: red; font-size: 5px;">10x10</text>
So to conclude the purpose of viewBox is to select that part of the endless SVG plane, that should actually be rendered. If you choose the wrong values here, you might just see an empty space.
Links:
preserveAspectRatio #MDN
viewBox #MDN
Viewbox with the width and height values are how you can do zooming, and panning with SVG.
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
width="800"
height="600"
viewBox="0 0 800 600">
no scaling 800 pixels width in the viewbox equals 800 pixel width on the screen
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
width="800"
height="600"
viewBox="0 0 1600 1200">
Everything is scaled down so that a line 1600 pixels wide only shows up as 800 pixels wide.
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
width="800"
height="600"
viewBox="400 300 400 300">
Zoom into the bottom right hand 1/4 of the 800 by 600 screen making that portion fill the entire svg, don't show anything above the 300 pixel line or to the left of the 400 pixel line.