Printing an SVG from HTML in landscape mode - html

Okay so my setup is a window object created on the fly.
I'm writing to it with window.document.write() and building out this:
<style>
#page{
size: landscape;
max-height: 100%;
max-width: 100%;}
svg{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display: block;
overflow: visible;
transform: scale(1, 1.3737);}
</style>
and then I clone the SVG from the page it's on and document.write(svgClone.innerHTML).
I end up with this: https://jsfiddle.net/je0ssLm2/1/
Please excuse the mess but that contains the entire code for the SVG and displays how it renders. The reason I'm scaling by 1.3737 on the Y axis is because the image is 1280 x 720 but 1280 x 989 is close to an aspect ratio of 1:3 which is approximately the AR of US letter.
Anyway, as you can see the display is not very attractive, and when it prints for some reason the margins are very large and the image is quite small and not quite centered in the screen. Is there some crucial CSS I am missing? This is driving me nuts, I've seen a few other answers about this and tried various but I just can't get it to print correctly.
I'm not as worried about size as I am positioning. I can monkey with the scaling to get the size right but if I make the image bigger then I'll cut off axis labels or the title because the graph doesn't center on the page. I also ALWAYS get an extra blank page, which isn't the end of the world but definitely isn't desirable.

You need to modify attributes on the <svg> element for a clean solution.
SVG has two attributes that let you describe scale-to-fit operations declaratively without computing transforms yourself: viewBox and preserveAspectRatio.
Instead of the attributes you have
<svg width="1280" height="720">
you can write
<svg viewBox="0 0 1280 720" preserveAspectRatio="none">
If you cannot get at the source text, you can simply wrap the <svg> in a second one:
<svg viewBox="0 0 1280 720" preserveAspectRatio="none">
<svg width="1280" height="720">...</svg>
</svg>,
and, as long as you define sensible sizes, should work in all media, including the page the SVG originally comes from.
The area defined by the viewBox in SVG userspace coordinates will then be fitted into the size of the <svg> element itself - since you have it defined in CSS with width:100%;height:100%;, it is fitted into the containing element.
preserveAspectRatio="none" does the uneven scaling for you. This didn't work before because as a default, the aspect ratio was preserved (and only after being scaled-down-to-fit, the CSS transform cut in).

Related

How do I scale an SVG to adjust with screen size? [duplicate]

I want to have an inline svg element's contents scale when size is non-native. Of course I could have it as a separate file and scale it like that.
index.html: <img src="foo.svg" style="width: 100%;" />
foo.svg: <svg width="123" height="456"></svg>
However, I want to add additional styles to the SVG thru CSS, so linking an external one is not an option. How do I make an inline SVG scale?
To specify the coordinates within the SVG image independently of the scaled size of the image, use the viewBox attribute on the SVG element to define what the bounding box of the image is in the coordinate system of the image, and use the width and height attributes to define what the width or height are with respect to the containing page.
For instance, if you have the following:
<svg>
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
It will render as a 10px by 20px triangle:
Now, if you set only the width and height, that will change the size of the SVG element, but not scale the triangle:
<svg width=100 height=50>
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
If you set the view box, that causes it to transform the image such that the given box (in the coordinate system of the image) is scaled up to fit within the given width and height (in the coordinate system of the page). For instance, to scale up the triangle to be 100px by 50px:
<svg width=100 height=50 viewBox="0 0 20 10">
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
If you want to scale it up to the width of the HTML viewport:
<svg width="100%" viewBox="0 0 20 10">
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
Note that by default, the aspect ratio is preserved. So if you specify that the element should have a width of 100%, but a height of 50px, it will actually only scale up to the height of 50px (unless you have a very narrow window):
<svg width="100%" height="50px" viewBox="0 0 20 10">
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
If you actually want it to stretch horizontally, disable aspect ratio preservation with preserveAspectRatio=none:
<svg width="100%" height="50px" viewBox="0 0 20 10" preserveAspectRatio="none">
<polygon fill=red stroke-width=0
points="0,10 20,10 10,0" />
</svg>
(note that while in my examples I use syntax that works for HTML embedding, to include the examples as an image in StackOverflow I am instead embedding within another SVG, so I need to use valid XML syntax)
After like 48 hours of research, I ended up doing this to get proportional scaling:
NOTE: This sample is written with React. If you aren't using that, change the camel case stuff back to hyphens (ie: change backgroundColor to background-color and change the style Object back to a String).
<div
style={{
backgroundColor: 'lightpink',
resize: 'horizontal',
overflow: 'hidden',
width: '1000px',
height: 'auto',
}}
>
<svg
width="100%"
viewBox="113 128 972 600"
preserveAspectRatio="xMidYMid meet"
>
<g> ... </g>
</svg>
</div>
Here's what is happening in the above sample code:
VIEWBOX
MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
min-x, min-y, width and height
ie: viewbox="0 0 1000 1000"
Viewbox is an important attribute because it basically tells the SVG what size to draw and where. If you used CSS to make the SVG 1000x1000 px but your viewbox was 2000x2000, you would see the top-left quarter of your SVG.
The first two numbers, min-x and min-y, determine if the SVG should be offset inside the viewbox.
My SVG needs to shift up/down or left/right
Examine this: viewbox="50 50 450 450"
The first two numbers will shift your SVG left 50px and up 50px, and the second two numbers are the viewbox size: 450x450 px. If your SVG is 500x500 but it has some extra padding on it, you can manipulate those numbers to move it around inside the "viewbox".
Your goal at this point is to change one of those numbers and see what happens.
You can also completely omit the viewbox, but then your milage will vary depending on every other setting you have at the time. In my experience, you will encounter issues with preserving aspect ratio because the viewbox helps define the aspect ratio.
PRESERVE ASPECT RATIO
MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
Based on my research, there are lots of different aspect ratio settings, but the default one is called xMidYMid meet. I put it on mine to explicitly remind myself. xMidYMid meet makes it scale proportionately based on the midpoint X and Y. This means it stays centered in the viewbox.
WIDTH
MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
Look at my example code above. Notice how I set only width, no height. I set it to 100% so it fills the container it is in. This is what is probably contributing the most to answering this Stack Overflow question.
You can change it to whatever pixel value you want, but I'd recommend using 100% like I did to blow it up to max size and then control it with CSS via the parent container. I recommend this because you will get "proper" control. You can use media queries and you can control the size without crazy JavaScript.
SCALING WITH CSS
Look at my example code above again. Notice how I have these properties:
resize: 'horizontal', // you can safely omit this
overflow: 'hidden', // if you use resize, use this to fix weird scrollbar appearance
width: '1000px',
height: 'auto',
This is additional, but it shows you how to allow the user to resize the SVG while maintaining the proper aspect ratio. Because the SVG maintains its own aspect ratio, you only need to make width resizable on the parent container, and it will resize as desired.
We leave height alone and/or set it to auto, and we control the resizing with width. I picked width because it is often more meaningful due to responsive designs.
Here is an image of these settings being used:
If you read every solution in this question and are still confused or don't quite see what you need, check out this link here. I found it very helpful:
https://css-tricks.com/scale-svg/
It's a massive article, but it breaks down pretty much every possible way to manipulate an SVG, with or without CSS. I recommend reading it while casually drinking a coffee or your choice of select liquids.
You'll want to do a transform as such:
with JavaScript:
document.getElementById(yourtarget).setAttribute("transform", "scale(2.0)");
With CSS:
#yourtarget {
transform:scale(2.0);
-webkit-transform:scale(2.0);
}
Wrap your SVG Page in a Group tag as such and target it to manipulate the whole page:
<svg>
<g id="yourtarget">
your svg page
</g>
</svg>
Note: Scale 1.0 is 100%
Messing around & found this CSS seems to contain the SVG in Chrome browser up to the point where the container is larger than the image:
div.inserted-svg-logo svg { max-width:100%; }
Also seems to be working in FF + IE 11.
Here's an easy way:
Type 1: Most SVGs have a viewbox, like so:
<svg viewBox="0 0 24 30" ...>
And you can easily control their size in css:
svg {
height: 20px;
}
Type 2: If the svg has width and height, but doesn't have a viewport, like so:
<svg width="810" height="540">
Then you can just manually add a viewbox that's exactly the same as its width and hegith, like so:
<svg width="810" height="540" viewBox="0 0 810 540">
Then you can do the same as type 1.
Another simple way is
transform: scale(1.5);
changing the SVG file was not a fair solution for me so instead, I used relative CSS units.
vh, vw, % are very handy. I used a CSS like height: 2.4vh; to set a dynamic size to my SVG images.
If you want to scale SVG without preserveAspectRatio attribute.
This way SVG will always stretch to fill both width and height, and to do so, it will resize just width or height, if necessary, was looking for this for days, so thought to share it here in case someone else is looking for this
You have to remove width and height from <svg> and add viewBox attribute and add preserveAspectRatio="none"
example
<?xml version="1.0" encoding="utf-8"?>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 5.8208332 15.9"
preserveAspectRatio="none">
<polygon points="480.4,200 0,200 0,0 480.4,0 599.9,100 " fill="#E1E1E1"/>
</svg>
Adjusting the currentScale attribute works in IE ( I tested with IE 11), but not in Chrome.

Gap in vertical repeat of svg background

I have a simple div, with an SVG set as background image with vertical repeat. On Chrome and Firefox, depending on the screen size, I see a gap in varying sizes (please resize the window).
https://jsfiddle.net/bartadaniel/ejtvy7po/9/
.bg {
width: 50%;
height: 2000px;
display: block;
background-repeat: repeat;
background-size: contain;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='272' height='171' viewBox='0 0 272 171'> <rect class='cls-1' width='272' height='171' fill='green'/></svg>");
}
<div class="bg"></div>
Is there a reason for this?
That's happening due to a combination of background-size:contain and the pixel dimensions of your svg.
You're seeing the browser try to scale the image so that nothing overflows the bounds of your <div>. When you combine that scaling with image pixel dimensions of 171 (can't be evenly multiplied into 2000px) you get lines showing you the sub pixels you're browser is trying to display.
Simply remove the background-size:contain to solve it.
Edit:
In the case where you need to contain width, there are a few tricks to help get a better result.
Make the background image dimensions multiples of 10. Square would be best with something like 100x100px but it could also be a rectangle (try to get close to your target width) like 1000x100px.
Set background-size: 100% auto instead of contain. This will stretch the image proportionalty to fill the container width.
Use background-repeat: repeat-y to force a vertical repeat so the browser is only doing the math on one axis.
It is a problem of subpixel rendering.
Each browser rounds differently and SVG subpixel rendering is pretty messed up.
I suggest you to edit your SVG content to make it slightly bigger than your viewbox.
<svg xmlns='http://www.w3.org/2000/svg' width='272' height='171' viewBox='0 0 272 171'>
<rect class='cls-1' y='-.5' width='272' height='172' fill='green'/>
</svg>
Obviously this trick doesn't work for all the background SVG, but might be useful in your case.
Unfortunately, the only solution that reliably tackled this issue was to convert the SVG to a pixel-based format, like JPG. Apparently, the browsers have no problem scaling pixels but causes side effects at edges when scaling vector-based formats.
If your SVG will still look acceptable with less anti-aliasing, you can change the anti-aliasing of the shapes in your SVG using the shape-rendering property. Example:
<rect shape-rendering="crispEdges">
You can use this on these elements: <circle>, <ellipse>, <line>, <path>, <polygon>, <polyline>, and <rect>.

Can you make a responsive viewbox?

If you have a view box set too large, the page will scroll. Is there a way to make a view box fit the size of any given browser? For example, I am on a 1600 x 1900 browser right now with this view box:
<svg viewBox="-300 0 1920 995">
and my page scrolls. I made the webpage on a 1080p monitor originally and the page did not scroll.
You've kind of got things the wrong way round. The viewBox is what you use to make SVGs responsive. It tells the browser how to scale the contents of your SVG to fit the parent.
The width and height attributes are what sets the size of the SVG.
What you need to do is restrict the size of the SVG to your window. Then the viewBox will let you size the content to fit.
For example:
html, body {
margin: 0;
overflow: hidden;
height: 100%
}
<svg width="100%" height="100%" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="50" fill="rebeccapurple"/>
</svg>
In this example. I've forced the <body> to match the window size. Then made the SVG fill that.
Make the example full screen. Then try enlarging and shrinking the window. Make it narrow or wide. The circle will automatically resize so it fits in the window.

SVG CSS | SVG only works in chrome

Having issues with an SVG I have made.
It works great in chrome and does exactly what i want and expect it too but I cannot get it working in any other browser (tried IE and Firefox so far).
My SVG is an image with a clip path cutting it out into the shape I want and this works on different resolutions spanning the full page width. Below is how it looks in chrome including an image of when the page width expands
The html for the SVG looks as follows
<svg id="mobile-svg" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 875.67 321.8" preserveAspectRatio="none">
<defs>
<style>.cls-1{fill:#60b6e1;}</style>
</defs>
<clipPath id="myClip">
<path d="M0,0S1,7.68,12.63,18.54,364.25,297.4,364.25,297.4s30.77,27.3,84.06.38,379.59-192,379.59-192S873.34,87.5,875.67,0H0Z" transform="translate(0)"></path>
</clipPath>
<image class="cls-image" xlink:href="http://localhost:63342/Carfinance247Rebrand/Content/img/carDrivingImage.png" clip-path="url(#myClip)"/>
</svg>
The CSS for the SVG (.SCSS)
#mobile-svg {
margin-bottom: -3px;
background-color: #5fb6e0;
.cls-image {
width: 100%;
height: 115%;
}
}
All works in chrome as expected but see image below for Firefox, the same thing also happens in IE (version 9 - 11)
I have tried changing position types and display types, also setting set width and ehights but cant get it to appear in other browsers.
I ahve an SVG that uses clip paths at a different point in the page and this one works fine, hence the confusion for this one. See image below of my working SVG
inb4 I am relatively new to SVG's
In SVG 1.1 an <image> element must have height and width attributes i.e. you can't set the height and width via CSS.
In SVG 2 it is proposed that image elements have width and height that are CSS properties.
Only Chrome has so far implemented this part of the SVG 2 specification.

SVG won't render as CSS background-image

I am trying to implement a close button using a SVG image as background-image. Below is the code I am using:
.close-button {
width: 16px;
height: 16px;
background-image: url(data:image/svg+xml;base64,[The data for the image]);
background-size: 16px 16px;
background-position: center center;
}
<span class="close-button"></span>
You can test it here.
It becomes a 16 by 16 span but the image does not render. Why is this happening? Also, the image is originally black-filled. I want to change its fill to white. Is there any way to achieve this?
So, my questions are:
Why doesn't the image render as background?
How to change the SVG fill on :hover? (given my configuration - available in the link above)
You need to set either the width and height, or the viewBox attribute on the <svg>. I would recommend the viewBox, because you do not to scale the graphics to fit in. Of course you are free to set all of them, but that easily leads to confusion for your purposes.
Please note, to gain an SVG that fits into each element, do not use width and height and use viewBox. Here is a nice explanation for the viewBox.
For the SVG you posted a possible viewBox could roughly be like that:
<svg viewBox="16 104 170 170" >
I do not know how you generate your SVG but to fix those Issues I use inkscape. Just open the file > document Properties > resize document to content and save.
Than, if you want, open the svg in an text editor, create a such a viewBox="0 0 <value of width> <value of height>" and remove the width and height attributes.
Good Luck!