Applying SVG Mask over shape Fill - javascript

I want to darken the fill of objects according to the defined gradient below. However, when the mask goes over the fill, it lightens it instead. I am assuming this has to be based on the decision on how to blend the colors. Its using additive colors rather than subtractive. Do I need to apply a filter on top of the mask? I feel like there should be an attribute in either the gradient or mask definitions to make it blend the colors the way I want. Code and fiddle link below:
<svg width="400px" height="500px">
<defs>
<linearGradient id="mygradient" gradientUnits="userSpaceOnUse"
x1="0" y1="0" x2="0" y2="100%">
<stop offset="0" stop-color="black"/>
<stop offset="0.5" stop-color="white"/>
<stop offset="1" stop-color="black"/>
</linearGradient>
<mask id="mask1" x="0" y="0" width="400" height="500" MaskUnits="userSpaceOnUse" color-interpolation="sRGB">
<rect x="0" y="0" width="400" height="500"
style="stroke:none; fill: url(#mygradient)"/>
</mask>
</defs>
<g fill="red" mask= "url(#mask1)" stroke="black" stroke-width="4"
feblend="Multiply">
<rect x="5" y="5" width="390" height="90"/>
<rect x="5" y="105" width="390" height="90"/>
<rect x="5" y="205" width="390" height="90"/>
<rect x="5" y="305" width="390" height="90"/>
<rect x="5" y="405" width="390" height="90"/>
</g>
</svg>
https://jsfiddle.net/6q3x8x5u/

You can replace the mask with a simple <rect> with the proper blend mode.
(Below the <g>):
<rect x="0" y="0" width="400" height="500" style="stroke:none;
fill: url(#mygradient); mix-blend-mode: multiply" />
See this fiddle

Why the mask? Masks are used to vary the transparency, not the colour.
You have a gradient in your SVG that you are not using. If you adjust the colours of the gradient, you can get what it sounds like you want.
<svg width="400px" height="500px">
<defs>
<linearGradient id="mygradient" gradientUnits="userSpaceOnUse"
x1="0" y1="0" x2="0" y2="100%">
<stop offset="0" stop-color="black"/>
<stop offset="0.5" stop-color="red"/>
<stop offset="1" stop-color="black"/>
</linearGradient>
</defs>
<g fill="url(#mygradient)" stroke="black" stroke-width="4"
feblend="Multiply">
<rect x="5" y="5" width="390" height="90"/>
<rect x="5" y="105" width="390" height="90"/>
<rect x="5" y="205" width="390" height="90"/>
<rect x="5" y="305" width="390" height="90"/>
<rect x="5" y="405" width="390" height="90"/>
</g>
</svg>

Related

How do I print a list in an SVG element in react?

I am trying to print a list inside of a rectangular element in React. Currently, the list is printing correctly (so I know am formatting everything correctly in regards to including li tags around the items, etc.) above the rectangle, and the rectangle prints below it. The text "Title Here" prints correctly inside the box. The problem is that the list must be represented by a state, and is of unknown size. How do I print this list inside the rectangle?
<div>
<ul>{this.state.ListText}</ul>
<svg width="100%" height="100%" viewBox="0 0 610 150" version="1.1">
<defs>
<linearGradient x1="51.7971499%" y1="47.5635228%" x2="52.4921324%" y2="48.1654036%" id="linearGradient-1">
<stop stopColor="#9198A1" offset="0%"></stop>
<stop stopColor="#888D95" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="610" height="150" rx="7.2"></rect>
</defs>
<g id="Patient-Page" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="Desktop-HD" transform="translate(-732.000000, -106.000000)">
<g id="Medications" transform="translate(732.000000, 106.000000)">
<g id="Rectangle-7">
<use fillOpacity="0.55" fill="url(#linearGradient-1)" fillRule="evenodd" xlinkHref="#path-2"></use>
</g>
<text fontFamily="Helvetica" fontSize="32" fontWeight="normal" fill="#000000">
<tspan x="165" y="39">Title Here</tspan>
</text>
</g>
</g>
</g>
</svg>
</div>
You can use a foreignObject to embed HTML in your SVG.
You can use jQuery to manipulate the foreignObject DOM properties and to append HTML such as your list.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul>{this.state.ListText}</ul>
<span id='cont'>
<svg width="100%" height="100%" viewBox="0 0 610 150" version="1.1">
<defs>
<linearGradient x1="51.7971499%" y1="47.5635228%" x2="52.4921324%" y2="48.1654036%" id="linearGradient-1">
<stop stopColor="#9198A1" offset="0%"></stop>
<stop stopColor="#888D95" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="610" height="150" rx="7.2"></rect>
</defs>
<g id="Patient-Page" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="Desktop-HD" transform="translate(-732.000000, -106.000000)">
<g id="Medications" transform="translate(732.000000, 106.000000)">
<g id="Rectangle-7">
<use fillOpacity="0.55" fill="url(#linearGradient-1)" fillRule="evenodd" xlinkHref="#path-2"></use>
</g>
<text fontFamily="Helvetica" fontSize="32" fontWeight="normal" fill="#000000" >
<tspan x="165" y="39">Title Here</tspan>
</text>
<foreignObject width="100" height="300"
requiredExtensions="http://www.w3.org/1999/xhtml">
<body xmlns="http://www.w3.org/1999/xhtml">
<p>Here is my list</p>
</body>
</foreignObject>
</g>
</g>
</g>
</svg>
</span>
</div>
<script>
var ul = $('<ul>');
["Item 1", "Item 2", "Item 3"].forEach(function(item) {
ul.append($("<li>").text(item));
});
$('foreignObject').append(ul);
$('foreignObject body').append(ul);
</script>

Is the SVG def element editable

I've got an svg with a defs element, like so:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 330" onclick="tweenGloss()">
<defs>
<linearGradient id="grad" x1="174.62" y1="-20.2" x2="75.38" y2="350.2" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#d4af37"/>
<stop offset="0.14" stop-color="#fefdfb"/>
<stop offset="0.27" stop-color="#d6b23f"/>
<stop offset="0.45" stop-color="#816e26"/>
<stop offset="0.59" stop-color="#d6b23f"/>
<stop offset="0.82" stop-color="#d6b23f"/>
<stop offset="0.91" stop-color="#fff"/>
<stop offset="1" stop-color="#d6b23f"/>
</linearGradient>
</defs>
<title>StickerBorder</title>
<rect x="5" y="292.04" width="240" height="30.58" style="fill: #aa4c4e;stroke: #4f2426;stroke-miterlimit: 10;stroke-width: 4px"/>
<polygon points="6.71 4 6.71 53.09 47.54 53.09 68.22 32.41 245 32.41 246.28 4 6.71 4" style="fill: #2680b8"/>
<polyline points="5 54.09 47.06 54.09 67.51 33.41 242.31 33.41" style="fill: none;stroke: #184c66;stroke-miterlimit: 10;stroke-width: 4px"/>
<rect x="5" y="5" width="240" height="320" style="fill: none;stroke-miterlimit: 10;stroke-width: 10px;stroke: url(#grad)"/>
<circle cx="196.64" cy="292.04" r="21.94" style="fill: #fff;stroke: #4f2426;stroke-miterlimit: 10;stroke-width: 4px"/>
<text transform="translate(188.7 304.34)" style="font-size: 28.58350944519043px;fill: #1d1d1b;font-family: KG Second Chances Sketch">7</text>
</svg>
I'm appending a couple of children to this via javascript like so :
<lineargradient id="glossgrad" x1="22.3" y1="342.88" x2="227.7" y2="-12.88" gradientunits="userSpaceOnUse">
<stop offset="0" stop-color="#ff0000"></stop>
<stop offset="0.2" stop-color="#ff0000"></stop>
<stop offset="0.4" stop-color="#ff0000"></stop>
</lineargradient>
<rect x="5" y="5" width="240" height="320" style="fill: none;stroke-miterlimit: 10;stroke-width: 10px;stroke: url(#glossgrad)"></rect>
So the lineargradient "glossgrad" is being added to the defs element and the rect is being added to the svg element. My problem is, the new appended rect doesn't appear at all. However if I change the url of the rect to the original lineargradient url it appears.
So my question is, does the 'defs' element not get updated once it has had it's initial load? Is it sort of cached or something?
I don't know how you append the new linear gradient definitions and rect element. But to answer your question, there are no issues in dynamically appending new elements to svg defs and using them.
Here is a working example:
var svg = document.getElementsByTagName("svg")[0];
var svgNS = svg.namespaceURI;
createGradient(svg,'glossgrad',[
{offset:'5%', 'stop-color':'#f60'},
{offset:'95%','stop-color':'#ff6'}
]);
var rect = document.createElementNS(svgNS,'rect');
rect.setAttribute('x',60);
rect.setAttribute('y',80);
rect.setAttribute('width',50);
rect.setAttribute('height',50);
rect.setAttribute('fill','url(#glossgrad)');
svg.appendChild(rect);
function createGradient(svg,id,stops){
var grad = document.createElementNS(svgNS,'linearGradient');
grad.setAttribute('id',id);
for (var i=0;i<stops.length;i++){
var attrs = stops[i];
var stop = document.createElementNS(svgNS,'stop');
for (var attr in attrs){
if (attrs.hasOwnProperty(attr)) stop.setAttribute(attr,attrs[attr]);
}
grad.appendChild(stop);
}
var defs = svg.querySelector('defs') ||
svg.insertBefore( document.createElementNS(svgNS,'defs'), svg.firstChild);
return defs.appendChild(grad);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 330" onclick="tweenGloss()">
<defs>
<linearGradient id="grad" x1="174.62" y1="-20.2" x2="75.38" y2="350.2" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#d4af37"/>
<stop offset="0.14" stop-color="#fefdfb"/>
<stop offset="0.27" stop-color="#d6b23f"/>
<stop offset="0.45" stop-color="#816e26"/>
<stop offset="0.59" stop-color="#d6b23f"/>
<stop offset="0.82" stop-color="#d6b23f"/>
<stop offset="0.91" stop-color="#fff"/>
<stop offset="1" stop-color="#d6b23f"/>
</linearGradient>
</defs>
<title>StickerBorder</title>
<rect x="5" y="292.04" width="240" height="30.58" style="fill: #aa4c4e;stroke: #4f2426;stroke-miterlimit: 10;stroke-width: 4px"/>
<polygon points="6.71 4 6.71 53.09 47.54 53.09 68.22 32.41 245 32.41 246.28 4 6.71 4" style="fill: #2680b8"/>
<polyline points="5 54.09 47.06 54.09 67.51 33.41 242.31 33.41" style="fill: none;stroke: #184c66;stroke-miterlimit: 10;stroke-width: 4px"/>
<rect x="5" y="5" width="240" height="320" style="fill: none;stroke-miterlimit: 10;stroke-width: 10px;stroke: url(#grad)"/>
<circle cx="196.64" cy="292.04" r="21.94" style="fill: #fff;stroke: #4f2426;stroke-miterlimit: 10;stroke-width: 4px"/>
<text transform="translate(188.7 304.34)" style="font-size: 28.58350944519043px;fill: #1d1d1b;font-family: KG Second Chances Sketch">7</text>
</svg>

How to fill an SVG element half portion by a pattern

I have some SVG elements on which there are some pattern already applied. The pattern is applied as fill color. That means the pattern fills up whole SVG element. Basically i want to partially fill up my element using the pattern.
Example
After applying pattern:
I want this pattern to apply on bottom half of the circle. Is there any way to do that?
What you could do is create two circles and apply mask on one with fill
<svg width="105px" height="105px">
<mask x="0" y="0" id="half">
<rect y="50%" fill="white" width="100%" height="50%" />
</mask>
<circle fill="transparent" stroke="black" stroke-width="3px" cx="50%" cy="50%" r="50"/>
<circle fill="#C04C4C" mask="url(#half)" stroke="black" stroke-width="3px" cx="50%" cy="50%" r="50"/>
</svg>
use something like this
<svg height="300" width="300">
<defs>
<linearGradient id="Gradient-1" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="50%" stop-color= "white" />
<stop offset="51%" stop-color= "red" />
</linearGradient>
<linearGradient id="repeat"xlink:href="#Gradient-1" spreadMethod="repeat" />
</defs>
<circle cx="100" cy="100" r="100"
fill= "url(#repeat)"
stroke="#000000"
stroke-width="1px" />
</svg>

Fill SVG element with a repeating linear gradient color

I have an SVG element - a rectangle.
Now, to color this element, I use fill attribute that works with any color.
Now, I am trying to give it a stripes color by using this property
fill: repeating-linear-gradient(-45deg, #cc2229, #ffffff 4px, #cc2229 2px, #ffffff 8px);
This works for normal DOM elements when assigned to background attribute.
But, IT DOESN'T WORK WITH SVG ELEMENT.
How can i achieve that?
- this is how i am trying my SVG element to look like (I am using d3.js)
Much better solution:
http://jsfiddle.net/mcab43nd/14/
<svg>
<defs>
<pattern id="pattern"
width="8" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(45 50 50)">
<line stroke="#a6a6a6" stroke-width="7px" y2="10"/>
</pattern>
</defs>
<rect x="5" y="5"
width="1000" height="25"
fill= "url(#pattern)"
opacity="0.4"
stroke="#a6a6a6"
stroke-width="2px" />
</svg>
http://jsfiddle.net/mcab43nd/1/ - solution is here
Thanks to Lars and AmeliaBR
Here is the code
<svg>
<defs>
<linearGradient id="Gradient-1"x1="3%" y1="4%" x2="6%" y2="6%">
<stop offset="0%" stop-color= "red" />
<stop offset="50%" stop-color= "white" />
</linearGradient>
<linearGradient id="repeat"xlink:href="#Gradient-1"spreadMethod="repeat" />
</defs>
<rect x="30" y="10"
width="200" height="100"
fill= "url(#repeat)"
stroke="red"
stroke-width="2px" />
</svg>

Apply Gradient to more than one element inside an SVG Element

I am attempting to create an arrow that looks like this using SVG elements:
This is my attempt:
As you can see the gradient gets applied to both the rect & the polygon in my SVG. Is there a way to replicate the gradient effect in the top image in my SVG?
Maybe theres a CSS way to do this? Maybe I HAVE to use a path or single polygon element to create the arrow instead of a rect & polygon?
<svg width="424" height="100">
<defs>
<radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255); stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(13,20,93); stop-opacity:1" />
</radialGradient>
</defs>
<rect x="0" y="25" rx="0" ry="0" width="212" height="50" fill="url(#grad1)"> </rect>
<polygon points="212,0 212,100 424,50" fill="url(#grad1)"></polygon>
</svg>
you can "make" a single path from two shapes by grouping them then apply the gradient to the group
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="424"
height="100"
id="svg2996">
<defs>
<radialGradient cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5" id="grad1">
<stop style="stop-color:#ffffff;stop-opacity:0" offset="0" />
<stop style="stop-color:#0d145d;stop-opacity:1" offset="1" />
</radialGradient>
<radialGradient cx="212" cy="50" r="212" fx="212" fy="50" id="radialGradient3809" xlink:href="#grad1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.23584906,0,38.207547)" />
</defs>
<g style="fill:url(#radialGradient3809);fill-opacity:1">
<rect width="212" height="50" rx="0" ry="0" x="0" y="25" />
<polygon points="424,50 212,0 212,100 " />
</g>
</svg>
codepen
I used two gradients to attempt to recreate what you were trying to do. You can adjust the center of the gradient to align with the edges of the shapes:
<svg width="424" height="100">
<defs>
<radialGradient id="grad1" cx="100%" cy="50%" r="100%" fx="100%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255); stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(13,20,93); stop-opacity:1" />
</radialGradient>
<radialGradient id="grad2" cx="0%" cy="50%" r="50%" fx="0%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255); stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(13,20,93); stop-opacity:1" />
</radialGradient>
</defs>
<rect x="0" y="25" rx="0" ry="0" width="212" height="50" fill="url(#grad1)"> </rect>
<polygon points="212,0 212,100 424,50" fill="url(#grad2)"></polygon>
</svg>
Demo
Is there something wrong with a single polygon though?
<svg width="424" height="100">
<defs>
<radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255); stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(13,20,93); stop-opacity:1" />
</radialGradient>
</defs>
<polygon points="212,0 212,25 0,25 0,75, 212,75 212,100 424,50" fill="url(#grad1)"></polygon>
</svg>

Categories

Resources