SVG LinearGradient - How to fade from bottom to top? - javascript

New to working with SVG. I have a working demo that has a linear gradient fade from left to right on the x axis, however I'm trying to get the same affect going from bottom to top on the y axis. Tried several different ways but can't get it to work the same.
https://codepen.io/joshuaeelee/pen/bqYmEG
HTML
<div class="share">
<ul>
<li>
<svg class="svg" style="width:100%;height:100%;position:fixed;top:0;bottom:0;left:0;">
<defs>
<linearGradient id="gradient-0">
<stop offset="0.8" stop-color="#fff"/>
<stop offset="1" stop-color="#000"/>
</linearGradient>
<mask id="gradient-mask-0" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<rect class="js-rect" x="-2" y="0" width="2" height="1" fill="url(#gradient-0)" />
</mask>
</defs>
<image class="js-images" x="0" y="0" width="100%" height="100%" xlink:href="http://68.media.tumblr.com/ef71091b57992c63cd6b6371160694b7/tumblr_o9c283SMGZ1st5lhmo1_1280.jpg" / mask="url(#gradient-mask-0)" preserveAspectRatio="xMidYMid slice">
</svg>
</li>
</ul>
JS - Using TweenMax to change attribute on Rect
const tl = new TimelineMax()
let firstRect = document.querySelector('.js-rect')
tl.to(firstRect, 5, {
attr: {
x: 0
}
})

You'd need to specify x2 and y2 values on the linearGradient element e.g.
<linearGradient id="gradient-0" x2="0%" y2="100%">
The default values are x2="100%" and y2="0%" which produce a horizontal gradient.
I guess another option would be to use a gradientTransform to rotate the gradient but the solution I've illustrated is simpler given your use case.

Related

SVG - Obtaining ordered list of IDs that appear under mouse/touch hove/click/tap in an SVG

I am trying to extract all layer/group ID names and metadata from the top layer as well as all layers underneath it.
Desired result: Get a list of IDs and Group IDs from an SVG.
In example SVG would see, if hovering over the center of the image, something like this:
Poly 1
Star
Group Begin: Bright Shapes
Group Begin: Gradient Shapes
Gradient Poly Small
Gradient Poly Large
Gradient Star
End Group: Gradient Shapes
Pink Ellipse
Green Square
End Group: Bright Shapes
Ellipse 2
I've also looked at CSS pointer-events.. but that seems limited to extracting from 1 layer.
Modified from: Determine which element the mouse pointer is on top of in Javascript
http://jsfiddle.net/coq4eg0d/1/
setInterval(function(){
var element = $(':hover');
if(element.length)
{
var domElement = element[element.length - 1];
var tagName = domElement.tagName;
var id = domElement.id ? ' id="' + domElement.id + '"' : "";
document.getElementById('test').innerHTML =
"hover: <" + tagName.toLowerCase() + id + ">";
}
}, 100);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="test"></div>
<svg version="1.1" id="Shapes" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 368 373" style="enable-background:new 0 0 368 373;" xml:space="preserve">
<style type="text/css">
.st0{stroke:#FFFFFF;stroke-miterlimit:10;}
.st1{fill:#4BB749;stroke:#1F451F;stroke-miterlimit:10;}
.st2{fill:#CB3694;stroke:#FFFFFF;stroke-miterlimit:10;}
.st3{fill:url(#Gradient_Star_1_);stroke:#FFFFFF;stroke-miterlimit:10;}
.st4{fill:url(#Gradient_Poly_Large_1_);stroke:#FFFFFF;stroke-miterlimit:10;}
.st5{fill:url(#Gradient_Poly_Small_1_);stroke:#FFFFFF;stroke-miterlimit:10;}
</style>
<ellipse id="Ellipse_2" class="st0" cx="261" cy="212" rx="94" ry="79"/>
<g id="Bright_Shapes">
<rect id="Green_Square" x="98" y="161.22" class="st1" width="184" height="174.5"/>
<ellipse id="Pink_Ellipse" class="st2" cx="115.59" cy="268.59" rx="94" ry="79"/>
<g id="Gradient_Shapes">
<radialGradient id="Gradient_Star_1_" cx="115.5932" cy="189.5899" r="147.9309" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#1C75BC"/>
</radialGradient>
<polygon id="Gradient_Star" class="st3" points="109.37,335.15 68.3,238.41 -34.67,217.41 44.63,148.46 32.79,44.03 122.87,98.15
218.53,54.61 194.9,157.01 265.86,234.53 161.17,243.7 "/>
<radialGradient id="Gradient_Poly_Large_1_" cx="167" cy="171" r="88.1134" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#1C75BC"/>
</radialGradient>
<polygon id="Gradient_Poly_Large" class="st4" points="234,233 146.81,260.02 79.81,198.02 100,109 187.19,81.98 254.19,143.98
"/>
<radialGradient id="Gradient_Poly_Small_1_" cx="209.5932" cy="248.4668" r="30.3834" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#1C75BC"/>
</radialGradient>
<polygon id="Gradient_Poly_Small" class="st5" points="236.59,265.88 208.02,280.55 181.02,263.14 182.59,231.06 211.17,216.38
238.17,233.79 "/>
</g>
</g>
<g id="Pointed_Dark_Shapes">
<polygon id="Star" class="st0" points="249,229 142.84,198.45 57.49,268.59 53.74,158.19 -39.34,98.69 64.5,61 92.32,-45.91
160.25,41.21 270.53,34.63 208.67,126.16 "/>
<polygon id="Poly1" class="st0" points="220,251 124.55,266.33 63.55,191.33 98,101 193.45,85.67 254.45,160.67 "/>
</g>
</svg>
One way to find all elements at a location is to call elementFromPoint() to find the topmost element, and then use the fact that..
Elements with pointer-events set to none will be ignored, and the element below it will be returned.
So, once you've found an element, set its pointer-events: none and then call elementFromPoint() again to find the next element. Repeat until you reach the main SVG element:
function hitTest(e) {
const x = e.clientX,
y = e.clientY,
elms = [];
let elm;
while(true) {
elm = document.elementFromPoint(x, y);
if(!svg.contains(elm)) {
break;
}
elms.push(elm);
//Hide the element from the next round of `elementFromPoint()`:
elm.style.pointerEvents = 'none';
}
output.textContent = elms.map(printElement).join(' ');
//Cleanup:
elms.forEach(elm => elm.style.pointerEvents = '');
}
http://jsfiddle.net/r9k1bgnu/

Is it possible to bind SVG fill attribute that uses url() in VueJS?

I'd need to dynamically bind fill attribute of a SVG rect element but it doesn't work. Here is my simple VueJS component to demonstrate what I am trying to do (also available in codepen)
<template>
<div>
<!-- this works but id and fill attributes are hardcoded -->
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient1">
<stop stop-color="red" offset="0%" />
<stop stop-color="blue" offset="100%" />
</linearGradient>
<rect width="100" height="50" fill="url(#gradient1)" />
</svg>
<!-- this doesn't work... -->
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient :id="myid">
<stop stop-color="red" offset="0%" />
<stop stop-color="blue" offset="100%" />
</linearGradient>
<rect width="100" height="50" :fill="myfill" />
</svg>
</div>
</template>
<script>
new Vue({
el: 'body',
data: {
title: 'Vuejs SVG binding example',
myid: 'gradient2',
myfill: 'url(#gradient2)'
},
});
</script>
Notice that fill attribute uses url() which takes element id as argument which complicates the thing. As far as I know the only way for fill attribute to use linearGradient defined in the same component is to reference it by element id attribute.
The reason I am trying to do this is because I want to avoid hardcoding ids inside components. Since I will have many instance of this component on the webpage, there will be multiple elements with same id value which should not happen.
Yes it is possible to do what want to do. I have done something a bit similar but with just a div not and not svg.
The theory
Bind a dynamic css class name to the svg and and put the fill in that class. this link shows how to us css for a css CSS - Style svg fill with class name
My proposed solution assumes are passing in some value to the component via props
The solution
<template>
...
<rect width="100" height="50" :class="myfill" />
...
</template>
<script>
new Vue({
el: 'body',
data: {
title: 'Vuejs SVG binding example',
myid: 'gradient2',
myfill: somePropYouPassedIn
},
});
</script>
Modification To First Answer
On trying out your fiddle, I think your were doing the coding correctly, you were just using an old version of Vuejs (this I notice when I was trying to get your fiddle to work). Anyway, I could not get your pen to work with vue so I created a totally new fiddle here https://jsfiddle.net/nkalait/ohmzxb7L/
Code
<div>
{{ title }}
<!-- this works but id and fill attributes are hardcoded -->
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="50" :fill="gradient1" />
</svg>
<!-- this doesn't work... -->
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="50" :fill="gradient2" />
</svg>
// I HAVE PUT THE GRADIENTS IN THERE OWN SVG
<svg aria-hidden="true" focusable="false" style="width:0;height:0;position:absolute;">
<linearGradient id="gradient1">
<stop stop-color="yellow" offset="0%" />
<stop stop-color="blue" offset="100%" />
</linearGradient>
<linearGradient id="gradient2">
<stop stop-color="red" offset="0%" />
<stop stop-color="green" offset="100%" />
</linearGradient>
</svg>
</div>

Change the x-y coordinates of svg text with a media query in either css or javascript?

I have svg text embedded on my home page. There is Main Head and a subHead (see below). I want to change the x-y coordinates of the subHead, which uses tagline_class, in a media query.
<div class="logo">
<svg viewBox="0 0 240 220" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="rgb(71,164,71)"/>
<stop offset="95%" stop-color="white"/>
</linearGradient>
</defs>
<text x="0" y="25" class="logo_class three">Main Head</text>
<text id="subHead" fill="url(#MyGradient)" x="24" y="33" width="33" height="24" class="tagline_class fadeIn animate_behind">subHead</text>
</svg>
</div>
I know I can change svg elements with javascript, but it would be easier if I could use css.
Can I change the x-y coordinates of subHead (tagline_class) using only css, in a media query?
If not, I can use this javascript:
document.getElementById("jqx-chart-axis-text").setAttribute("x", "10");
but I'm not clear on whether the javascript should be called from a media query, or the media query used in the javascript code. I also don't know what event to use to change the svg coordinates.
To summarize, how to change the x-y coordinates of svg text using a media query in either css or javascript.
you can use the id of svg element also in css:
<div class="logo">
<style>
#media(max-width: 500px){
#subHead{
transform: translateX(-20px);
}
}
#media(min-width: 1000px){
#subHead{
transform: translateX(20px);
}
}
</style>
<svg viewBox="0 0 240 220" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="rgb(71,164,71)"/>
<stop offset="95%" stop-color="white"/>
</linearGradient>
</defs>
<text x="0" y="25" class="logo_class three">Main Head</text>
<text id="subHead" fill="url(#MyGradient)" x="24" y="33" width="33" height="24" class="tagline_class fadeIn animate_behind">subHead</text>
</svg>
</div>

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>

javascript + svg : get fill when it has been declared outside of a style

I want to replace a gradient for another in a svg so I need to iterate (probably recursively) over each svg item to get
I looked at the svg doc # MDN
https://developer.mozilla.org/fr/SVG/Element/ellipse
but it is broken (access denied, no exemple, lots of broken links)
and quite different of the one at MSDN
http://msdn.microsoft.com/en-us/library/ie/ff972071%28v=vs.85%29.aspx
so I search for any pointer on how to access fill property of a svg element however it has been defined.
something like a getComputedFill function
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
>
<defs>
<script>
<![CDATA[
function infothis(ref)
{
alert(ref + " " + ref.fill + " " + ref.fillOpacity); // why can't I get "url(#grad1)" and 0.5 when clicking ellipse1
//alert(ref.style.getPropertyValue("fill")); // somewhat okwhy can't I get "url(#grad2)" when clicking ellipse2
}
]]>
</script>
<linearGradient
dc:title="red black filter"
dc:rights="CC-BY"
dc:description="basic filter ranging from black to red"
id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,255);stop-opacity:1" />
</linearGradient>
<ellipse id="ellipse0" cx="150" cy="170" rx="85" ry="55" fill="url(#grad2)" />
</defs>
<ellipse id="ellipse1" cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" fill-opacity="0.5" onclick="infothis(this)" />
<ellipse id="ellipse2" cx="100" cy="70" rx="85" ry="55" style="fill:url(#grad2)" onclick="infothis(this)" />
<use xlink:href="#ellipse0"/>
</svg>
How about this...
alert(document.defaultView.getComputedStyle(ref, null).getPropertyValue("fill"));

Categories

Resources