How can I rewrite a gradient with userSpaceOnUse to objectBoundingBox? - svg

I have this gradient that uses userSpaceOnUse.
<svg height="400px" width="800px" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" x1="0" y1="0" x2="800" y2="400" gradientUnits="userSpaceOnUse">
<stop offset="0%" style="stop-color:green;stop-opacity:1" />
<stop offset="50%" style="stop-color:black;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="800" height="400" fill="url(#grad1)"/>
</svg>
I want to rewrite it to use objectBoundingBox but be rendered the same. How can I do this?
I imagine the rewritten SVG would be close to:
<svg height="400px" width="800px" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0%" style="stop-color:green;stop-opacity:1" />
<stop offset="50%" style="stop-color:black;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="800" height="400" fill="url(#grad1)"/>
</svg>
This answer (https://stackoverflow.com/a/50624704/1283776) indicates that I need to use a transform, but I haven't been successful in found a solution.

<!-- https://stackoverflow.com/questions/22214999/svg-linear-gradient-independent-of-the-shape-coordinates -->
<svg height="400px" width="800px" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" x1="0" y1="0" x2="1" y2="0.5" gradientUnits="objectBoundingBox" gradientTransform="scale(1, 2)">
<stop offset="0%" style="stop-color:green;stop-opacity:1" />
<stop offset="50%" style="stop-color:black;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="800" height="400" fill="url(#grad1)"/>
</svg>

Related

SVG pattern size relative to container shape

I am trying to create a svg pattern where size of it is relative to shape to which is applied. Pattern should consist of rect with linearGradient and text elements which repeats in x-axis n-times or every n pixels and is vertically aligned in middle of rect.
The results should look like this.
I have tried following approaches.
<svg width="100%" height="100">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" width="25%" height="100%">
<rect width="100%" height="100%" fill="url(#gradient)"></rect>
<text x="10" y="50%" dx=50 fill="red">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>
This approach gives the result I want but the size of pattern is not relatve to shape to which is applied and fails when shape is resized, to solve this issue I have tried to create a pattern with patternContentUnits="objectBoundingBox" but then I am having problems positioning the text.
<svg width="100%" height="100%">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" patternContentUnits="objectBoundingBox" width="25%" height="100%">
<rect width="1" height="1" fill="url(#gradient)"></rect>
<text x="0.1" y="0.5">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>
objectBoundingBox units are in the range [0, 1] so 10 is too big.
You'll need to use a suitable font-size too.
<svg width="100%" height="100%">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" patternContentUnits="objectBoundingBox" width="25%" height="100%">
<rect width="1" height="1" fill="url(#gradient)"></rect>
<text transform="scale(0.2, 1)" x="0.1" y="0.5" font-size="0.1">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>

How to make the animation smooth in the below SVG?

Im trying to make the below svg animation smooth. I would want to make the white gradient to move through the path indefinitely. Any suggestions would be very helpful.
<svg width="8" height="243" viewBox="0 0 8 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 3L3 240" stroke="url(#paint0_linear)" strokeWidth="5" strokeLinecap="round" strokeLinejoin="round"/>
<defs>
<linearGradient id="paint0_linear" x1="3" y1="3" x2="3" y2="240" gradientUnits="userSpaceOnUse">
<stop offset="0" stopColor="#E8FF00" stopOpacity="1">
<animate attributeName="stop-opacity" values="1;1;1;0;0;0.5;0.8;1;1;1;1;1" dur="1s" repeatCount="indefinite" />
</stop>
<stop offset="0.3" stopColor="#E8FF00" stopOpacity="0">
<animate attributeName="offset" values="0.3;0.2;0.1;0;1;0.9;0.8;0.7;0.6;0.5;0.4;0.3" dur="1s" repeatCount="indefinite" />
</stop>
<stop offset="0.4" stopColor="#E8FF00" stopOpacity="0">
<animate attributeName="offset" values="0.4;0.3;0.2;0.1;0;1;0.9;0.8;0.7;0.6;0.5;0.4" dur="1s" repeatCount="indefinite" />
</stop>
<stop offset="0.5" stopColor="#E8FF00" stopOpacity="0">
<animate attributeName="offset" values="0.5;0.4;0.3;0.2;0.1;0;1;0.9;0.8;0.7;0.6;0.5" dur="1s" repeatCount="indefinite" />
</stop>
<stop offset="1" stopColor="#E8FF00" stopOpacity="1">
<animate attributeName="stop-opacity" values="1;1;1;1;0.8;0.5;0;0;0;1;1;1" dur="1s" repeatCount="indefinite" />
</stop>
</linearGradient>
</defs>
</svg>
Consider solving a gradient animation using gradientTransform
Below is the code showing the position of the white bar in the static version
<svg width="108" height="243" viewBox="0 0 108 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="5" rx="5" height="240" fill="url(#paint0_linear)" />
<defs>
<linearGradient id="paint0_linear" x1="0%" y1="0%" x2="0%" y2="100%"" >
<stop offset="0%" stop-color="grey" />
<stop offset="43%" stop-color="grey" />
<stop offset="50%" stop-color="white" />
<stop offset="57%" stop-color="grey" />
<stop offset="100%" stop-color="grey" />
</linearGradient>
</defs>
</svg>
Add an animation command to move the entire gradient from top to bottom
<animateTransform attributeName="gradientTransform" ... />
<svg width="108" height="243" viewBox="0 0 108 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="5" rx="5" height="240" fill="url(#paint0_linear)" />
<defs>
<linearGradient id="paint0_linear" x1="0%" y1="0%" x2="0%" y2="100%" >
<stop offset="0%" stop-color="grey" />
<stop offset="43%" stop-color="grey" />
<stop offset="50%" stop-color="white" />
<stop offset="57%" stop-color="grey" />
<stop offset="100%" stop-color="grey" />
<animateTransform attributeName="gradientTransform"
type="translate"
from="0 -1"
to="0 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"/>
</linearGradient>
</defs>
</svg>
Update
#tejash jl comments:
animationTransform is not working on line path
I changed your path a little
<svg width="108" height="243" viewBox="0 0 108 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 3L3 240 L6 240 L6 3z" fill="url(#paint0_linear)" stroke-linecap="round" stroke-linejoin="round"/>
<defs>
<linearGradient id="paint0_linear" x1="0%" y1="0%" x2="0%" y2="100%" >
<stop offset="0%" stop-color="grey" />
<stop offset="43%" stop-color="grey" />
<stop offset="50%" stop-color="white" />
<stop offset="57%" stop-color="grey" />
<stop offset="100%" stop-color="grey" />
<animateTransform attributeName="gradientTransform"
type="translate"
from="0 -1"
to="0 1"
begin="0s"
dur="1.5s"
repeatCount="indefinite"/>
</linearGradient>
</defs>
</svg>
The path must be closed for the gradient animation to work. But you can also select a polyline and apply a gradient to the line
<svg width="108" height="243" viewBox="0 0 108 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<polyline points="3,3 3,240" stroke="url(#paint0_linear)" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
<defs>
<linearGradient id="paint0_linear" x1="3" y1="3" x2="3" y2="240" gradientUnits="userSpaceOnUse" >
<stop offset="0" stop-color="grey" />
<stop offset=".43" stop-color="grey" />
<stop offset=".50" stop-color="white" />
<stop offset=".57" stop-color="grey" />
<stop offset="1" stop-color="grey" />
<animateTransform attributeName="gradientTransform"
type="translate"
from="0 -240"
to="0 240"
begin="0s"
dur="1.5s"
repeatCount="indefinite"/>
</linearGradient>
</defs>
</svg>

SVG linear gradients objectBoundingBox vs userSpaceOnUse

I am making two gradients: one in objectBoundingBox units and another in userSpaceOnUse. The idea is to make them look the same. But somehow they are different. Here is the svg file.
<svg width="500" height="500" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="user-grad" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="200" y2="100">
<stop stop-color="orange" offset="0"/>
<stop stop-color="blue" offset="1"/>
</linearGradient>
<linearGradient id="box-grad" x1="0" y1="0" x2="1" y2="1">
<stop stop-color="orange" offset="0"/>
<stop stop-color="blue" offset="1"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="200" height="100" fill="url(#user-grad)"/>
<rect x="250" y="0" width="200" height="100" fill="url(#box-grad)"/>
</svg>
Here is what it looks like
Shouldn't they look the same?
Shouldn't they look the same?
No. When using object bounding box coordinates, you are basically transforming a 1x1 square onto your rectangle. So the 0 to 1 coordinates are stretched to fit the rectangle. Thus causing the gradient to stretch also.
If you want them to look the same, you would need to apply a gradientTransform, to your userSpaceOnUse one, that applies the equivalent stretch.
<svg width="500" height="500" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="user-grad" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="100" y2="100" gradientTransform="scale(2, 1)">
<stop stop-color="orange" offset="0"/>
<stop stop-color="blue" offset="1"/>
</linearGradient>
<linearGradient id="box-grad" x1="0" y1="0" x2="1" y2="1">
<stop stop-color="orange" offset="0"/>
<stop stop-color="blue" offset="1"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="200" height="100" fill="url(#user-grad)"/>
<rect x="250" y="0" width="200" height="100" fill="url(#box-grad)"/>
</svg>

What’s causing the linear-gradient to degrade in image quality when placed on Blogger?

After it is placed on Blogger, the hue of the linear gradient drops/lessens dramatically.
How do I prevent this from happening?
Is there any possible way I can fix this so it stays the same?
https://jsfiddle.net/cs311dLn/1/
https://testpage34567.blogspot.com/
The linear-gradient in the images are the 2 lines in the middle going down.
.html
Screenshot
Blogger:
Screenshot
<svg width="260" height="194">
<defs>
<clippath id="circleView">
<circle cx="130" cy="97" r="85" fill="orange"></circle>
</clippath>
</defs>
<image x="40" y="7" width="180" height="180" xlink:href="https://i.imgur.com/BO6KOvw.jpg" clip-path="url(#circleView)"> </image>
<image x="40" y="7" width="180" height="180" xlink:href="http://i.imgur.com/4HJbzEq.png"></image>
<svg width="260" height="194">
<defs>
<lineargradient id="MyGradient">
<stop offset="0%" stop-color="transparent"></stop>
<stop offset="31.9%" stop-color="transparent"></stop>
<stop offset="31.9%" stop-color="#0059dd"></stop>
<stop offset="33.2%" stop-color="#0059dd"></stop>
<stop offset="33.2%" stop-color="transparent"></stop>
<stop offset="66.8%" stop-color="transparent"></stop>
<stop offset="66.8%" stop-color="#0059dd"></stop>
<stop offset="68.1%" stop-color="#0059dd"></stop>
<stop offset="68.1%" stop-color="transparent"></stop>
<stop offset="100%" stop-color="transparent"></stop>
</lineargradient>
</defs>
<rect fill="url(#MyGradient)" x="0" y="0" width="260" height="194"></rect>
</svg>
</svg>

How to graph a political coordinates graph

I'm trying to program a graph like this one:
I tried with SVG, but it's not very good since I had to use 2 different rectangles and didn't manage to get only the 4 edges to be rounded.
Here's my code:
<svg width="400" height="250">
<defs>
<linearGradient id="solids" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="solids2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
</linearGradient>
</defs>
<text x="135" y="12" style="fill:black;">Conservadorismo
<tspan x="150" y="240">Liberalismo</tspan>
<tspan x="20" y="125">Esquerda</tspan>
<tspan x="305" y="125">Direita</tspan>
</text>
<rect x="100" y="20" rx="20" ry="20" width="200" height="100" style="fill:url(#solids); opacity:0.76" />
<rect x="100" y="120" rx="20" ry="20" width="200" height="100" style="fill:url(#solids2); opacity:0.76" />
<line x1="100" y1="120" x2="300" y2="120" style="stroke:black;stroke-width:2" />
<line x1="200" y1="20" x2="200" y2="220" style="stroke:black;stroke-width:2" />
</svg>
What should I do to fix it or do it better?
I would use ordinary <rect> objects without rounded corners, and apply a clipPath to the whole drawing to round off the corners.
Here's a simple example:
<svg width="400" height="400" viewBox="0 0 400 400">
<defs>
<clipPath id="roundRect">
<rect x="10" y="10" rx="20" ry="20" width="380" height="380"/>
</clipPath>
</defs>
<g clip-path="url(#roundRect)">
<rect fill="#0a0" stroke="none" x="10" y="10" width="190" height="190"/>
<rect fill="#f00" stroke="none" x="200" y="10" width="190" height="190"/>
<rect fill="#0bf" stroke="none" x="10" y="200" width="190" height="190"/>
<rect fill="#fd0" stroke="none" x="200" y="200" width="190" height="190"/>
</g>
</svg>

Resources