SVG rendering (auto-bluring) - svg

When i try to render this svg sample, the line is bluring automatically and has 2px height:
<svg xmlns="http://www.w3.org/2000/svg" width="500px" height="500px" >
<line x1="100" x2="400" y1="250" y2="250" stroke="black" />
</svg>
But when Y coordinates becomes 250.5, all is OK - line has 1px height.
It would be a solution (adding 0.5 pixels), but I need to use scale transform on elemets. On transformed elemets the problem again.
How to solve it?
Thanks.

By blurring you mean anti-aliasing. Try the crisp-edges rendering mode, e.g.:
<svg xmlns="http://www.w3.org/2000/svg" width="500px" height="500px" >
<line x1="100" x2="400" y1="250" y2="250" stroke="black" shape-rendering="crispEdges" />
</svg>

Related

GSAP: SVG not centering as expected

2 questions about this CodePen
Why isn't the red balloon ending up centered on the crosshairs, given that I've set transformOrigin:"50% 50%"?
Why does the green balloon seem to have its origin set to "left top" when, according to this doc, it should default to "50% 50%"?
Relevant code (I think)
HTML
<svg class="container" fill="#f0c0c0" style="background: linear-gradient(to top, #ddfdff, #6dd5fa, #2980b9);
;" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g id="green-balloon">
<path … />
<path … />
<text …>🕊</text>
</g>
<g id="red-balloon">
<path …/>
<path …/>
<text …>⚡️</text>
</g>
<line x1="0" y1="100" x2="200" y2="100" stroke="white" stroke-width=".5px"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="white" stroke-width=".5px" />
<defs>…</defs>
</svg>
JS
var redBalloon = $("#red-balloon");
var greenBalloon = $("#green-balloon");
var tl = new TimelineLite({onUpdate:updateSlider});
tl.set(greenBalloon, {x:100, y:200})
.set(redBalloon, {transformOrigin:"50% 50%", x:100,y:200})
.to(greenBalloon, 1, {scale:2, y:100})
.to(redBalloon, 1, {scale:2, y:100})
CSS
Not applicable.
Per OUSblake's answer on the GreenSock forums:
transformOrigin/svgOrigin affect scale, rotation, and skew. And svgOrigin uses the <svg> element's coordinate system. So svgOrigin: 50% 50% means everything is going to transform around 100,150 in the svg. transformOrigin: 50% 50% would be the center of the balloon. To center your element, use xPercent: -50 and yPercent: -50.
After providing a demo on Codepen, he continues:
It sounds like you were expecting transformOrigin to behave like in Adobe products, where changing the registration point causes the element to move. It doesn't, but that's what xPercent/yPercent are for. 😃
Just use those with a transformOrigin: 50% 50%, and everything should be pretty easy with curves.
He even went so far as to demonstrate motion along a path. Super helpful!

How do I make a SVG stretch to left and right, while maintaining aspect ratio in the middle?

I have a three-part SVG. I would like to stretch the left and right parts infinitely, but keep the middle part intact.
Here’s the illustration.
I think my answer lies somewhere around viewbox tag preserveAspectRatio attribute of SVG. I haven't worked with them though, and could use a nudge in the right direction.
Here is the code for the unstretched SVG, which I think I need to somehow augment with viewboxes to achieve the desired stretching.
<svg width="48" height="17" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<line y1="0.5" x2="32" y2="0.5" stroke="#FF0000"/>
<line x1="16" y1="8.5" x2="32" y2="8.5" stroke="#00FF00"/>
<line x1="16" y1="16.5" x2="48" y2="16.5" stroke="#0000FF"/>
</svg>
Here is the Codepen for code experiments: https://codepen.io/jaanus1/pen/aboQpeB
Set: width="100%" height="100%" preserveAspectRatio="none"
<svg width="100%" height="100%" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
<line y1="0.5" x2="32" y2="0.5" stroke="#FF0000"/>
<line x1="16" y1="8.5" x2="32" y2="8.5" stroke="#00FF00"/>
<line x1="16" y1="16.5" x2="48" y2="16.5" stroke="#0000FF"/>
</svg>
Update
I tried to make a new option.
Two lines red and green are included in one SVG block which is scaled.
The green line enters another SVG block, which has a fixed size: width="48" height="17"
To keep all lines the same width when zooming in, I added the property vector-effect ="non-scaling-stroke"
.one {
position:relative;
}
.two {
position:absolute;
top:35%;
left:50%;
}
<div class="one">
<svg width="100%" height="5%" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
<line vector-effect="non-scaling-stroke" y1="0.5" x2="32" y2="0.5" stroke="#FF0000"/>
<line vector-effect="non-scaling-stroke" x1="16" y1="16.5" x2="48" y2="16.5" stroke="#0000FF"/>
</svg>
<div class="two">
<svg width="48" height="17" viewBox="0 0 48 17">
<line x1="16" y1="8.5" x2="32" y2="8.5" stroke="#00FF00"/>
</svg>
</div>
</div>

SVG - top section fixed, middle section variable, bottom section fixed

I am trying to create an svg object with top, middle and bottom sections, where top and bottom are of fixed height, and fixed should occupy all the space between top and bottom (depending on the height of the browser window or other containing object). Here is some code that does NOT work:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="mainSvg" xmlns="http://www.w3.org/2000/svg" version="1.1"
width="100%" height="100%"
viewbox="0 0 1000 500"
preserveAspectRatio="none"
xmlns:xlink="http://www.w3.org/1999/xlink"
style="background-color: #cccccc;">
<svg id="top" x="0" y="0" width="100%" height="50"
style="overflow: visible;">
<line x1="0" y1="0" x2="100%" y2="100%"
style="stroke-width:5; stroke: red;"/>
<line x1="0" y1="100%" x2="100%" y2="0"
style="stroke-width:5; stroke: red;"/>
</svg>
<svg id="middle" x="0" y="50" width="100%"
style="overflow: visible;">
<line x1="0" y1="0" x2="100%" y2="100%"
style="stroke-width:5; stroke: blue;"/>
<line x1="0" y1="100%" x2="100%" y2="0"
style="stroke-width:5; stroke: blue;"/>
</svg>
<svg id="bottom" x="0" y="100%" width="100%" height="50"
style="overflow: visible;">
<line x1="0" y1="0" x2="100%" y2="-100%"
style="stroke-width:5; stroke: red;"/>
<line x1="0" y1="-100%" x2="100%" y2="0"
style="stroke-width:5; stroke: red;"/>
</svg>
</svg>
If you run that, you will see that top appears at the top and bottom is at the bottom (with the assistance of a little "-100%" hack).
Middle starts below top (y="50") but because its height is defaults to "100%", it overlaps bottom and indeed extends below the available rendering area. Clearly, its height needs to be "100% - 50 - 50", but there is no way to express that. Css has a nice feature where you can say
height: calc(100% - 50 - 50);
but in svg "height" is not a property that can be specified within css. So there I am stuck.
Note that in the intended application, the whole thing will be embedded within an html page, the insides of the sections will contain complicated svg, and I require that the whole thing can be resized vertically with automatic scaling of "middle", mainly because that will be necessary in order to print the page on some given size of paper.
Making such a structure with three 'div's in HTML is easily done, and at a pinch I could create three such 'div's and embed three pieces of svg within them, but that would be messy. I hope there is an easier way.

Round-cap lines used in a SVG pattern

Currently using an SVG <pattern> element with a bunch of <line> elements will cause it to have a sort of tapered-off edge. I've tried a bunch of different CSS stylings to get around this, but nothing's really worked. Here's the code to a circle with a stitch masked on it:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
<defs>
<pattern id="stripe" patternUnits="userSpaceOnUse" width="20" height="20">
<line x1="0" y1="0" x2="20" y2="20" />
</pattern>
<mask id="mask">
<rect height="500" width="500" style="fill: url(#stripe)" />
</mask>
<style>
#stripe line {
fill: white;
stroke: white;
stroke-linecap: square;
stroke-linejoin: miter;
stroke-width: 10px;
}
g {
mask: url(#mask);
stroke-linecap: square;
stroke-linejoin: miter;
}
circle {
fill: green;
}
</style>
</defs>
<g>
<circle cx="250" cy="250" r="200" style="fill: rgba(0, 255, 0, 0.2);" />
</g>
</svg>
And here's a fiddle of what this looks like. No combination of stoke-linecap and stroke-linejoin has worked for me. Do I instead need to draw a full <path> across the entire mask?
Thanks for any help.
Well I know that this answer isn't far off 2 years late, but I stumbled across this question while researching another problem and thought I'd throw in my 2 cents for anyone who might come across it.
The problem here is as highlighted by Duopixel: the pattern just doesn't tile right.
Your solution certainly masks the problem by overlaying two non-tiling patterns to hide the non-tiling corners, but if you make the pattern wider and add additional lines offset from one another, and offset so as to ensure they never overlap a corner of the tile you can create a functioning pattern. You can up the stroke width on this all the way up without any problems with the corners.
<pattern id="stripe" patternUnits="userSpaceOnUse" width="40" height="20">
<line x1="-10" y1="0" x2="10" y2="20" />
<line x1="10" y1="0" x2="30" y2="20" />
<line x1="30" y1="0" x2="50" y2="20" />
</pattern>
See this fiddle
I actually like the pattern made by the original problem though! I might have to find a use for it somewhere :)
Woo! What a ride.
After seeing Duopixel's answer, I got started on a trail. I didn't know it was possible to achieve this effect until I understood the bounding box that applies to patterns.
Googling brought me to this mailing list answer which didn't make much sense at first until the original author returned with gained insight (sorry, too many links). I looked back at the answer and saw potential in solving this problem.
Solution:
You have to overlay two patterns on-top of eachother in the right coordinates!
Code: (demo - http://jsfiddle.net/66UDU/)
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
<defs>
<pattern id="stripe1" class="stripe" patternUnits="userSpaceOnUse" width="20" height="20">
<line x1="0" y1="0" x2="20" y2="20" />
</pattern>
<pattern id="stripe2" class="stripe" patternUnits="userSpaceOnUse" x="6" y="6" width="20" height="20">
<line x1="0" y1="0" x2="20" y2="20" />
</pattern>
<mask id="mask">
<rect height="500" width="500" style="fill: url(#stripe1)" />
<rect height="500" width="500" style="fill: url(#stripe2)" />
</mask>
<style>
.stripe line {
fill: white;
stroke: white;
stroke-width: 4px;
}
g {
mask: url(#mask);
}
circle {
fill: rgba(0, 255, 0, 0.25);
}
</style>
</defs>
<g>
<circle cx="250" cy="250" r="200" />
</g>
</svg>
=)
That's an interesting problem. It looks like a line-cap issue but the actual problem is that the line corners of your pattern lie outside of the coordinates. Here is a diagram to understand what is happening:
You can either make the pattern larger with <pattern id="stripe" patternUnits="userSpaceOnUse" width="30" height="30"> or move the coordinates of your lines. In a cursory search I couldn't find any directive that would allow your pattern to overlap or display the overflow, but someone else might know of a workaround.
The post is old, but as I searched for a solution maybe someone also needs another solution like me.
As described above, a diagonal pattern has problems, thats why I created a straight horizontal line pattern and tranformed it with patternTransform="rotate(45)".
Then only 1 <line /> is needed instead of 2 overlapping ones.
Example:
<pattern id="stripe45" className="stripe-pattern" patternUnits="userSpaceOnUse" patternTransform="rotate(45)" width=".2" height=".2">
<line x1="0" y1=".1" x2=".2" y2=".1" />
</pattern>

SVG viewBox is not working with nested svgs at a negative position

In this example, the green circle is cut off
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" version="1.1" style="background-color: pink" viewBox="-300 -300 500 500">
<svg width="500" height="500" x="0" y="0"><circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" /></svg>
<svg width="500" height="500" x="0" y="0"><circle cx="0" cy="0" r="40" stroke="black" stroke-width="2" fill="green" /></svg>
</svg>
</body>
</html>
See: http://jsfiddle.net/sCzZT/
Notice each circle is wrapped in its own svg
In this example (no nested svgs), the green circle is not cut off
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" version="1.1" style="background-color: pink" viewBox="-300 -300 500 500">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
<circle cx="0" cy="0" r="40" stroke="black" stroke-width="2" fill="green" />
</svg>
</body>
</html>
http://jsfiddle.net/jVH9q/
How do I get the green circle to not get cut off when using nested svgs?
The inner svg has a default viewport which is 0, 0, 500, 500 (x, y, width, height) and by default anything that overflows this area is hidden/clipped.
There are several things you could do...
add an overflow="visible" attribute on the inner svg elements
change the x, y values so that the circle is within the viewport
add a viewBox so that you define an explicit viewport showing the area you want to see in the inner svg.

Resources