I am using angular 7. I have 2 svgs: one is black and i would like to show the color on the other when it is being hovered.
This is my test snippet:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
title = 'menu-svg';
svgCouleur="none";
svgNb="block";
//affiche le svg couleur et cache le noir et blanc
cacheSvg(e){
this.svgCouleur = "block";
this.svgNb = "none";
}
//affiche le svg noir et blanc et on cache la couleur
revientSvg(e){
this.svgCouleur ="none";
this.svgNb = "block";
}
}
/*no at the moment*/
<svg (mouseover)="cacheSvg($event)" [style.display]="svgNb" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="4" fill="gray" />
Sorry, your browser does not support inline SVG.
</svg>
<svg (mouseleave)="revientSvg($event)" [style.display]="svgCouleur" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
<svg (mouseover)="cacheSvg($event)" [style.display]="svgNb" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="4" fill="gray" />
Sorry, your browser does not support inline SVG.
</svg>
<svg (mouseleave)="revientSvg($event)" [style.display]="svgCouleur" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="red" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
The effect is applied on all svgs, instead of the current one.
You could try giving your svg an id (or class) and then styling it like so:
#test{
opacity:0;
}
#test:hover{
opacity:1;
}
the id should be inside your svg:
<svg id="test" .............. >
</svg>
Im not sure if this is what you exactly mean but its an easy way to do it
I would suggest taking a look at ngx-svg which allows to create containers and add multiple elements within those containers - in your case circles. It has other elements as well, and there is a documentation, which allows to understand what you have to do as well.
Related
We use Umbraco for our customers, and we want to allow them to change icons for certain content.
It's possible to upload and select a custom SVG.
Because we work on a template base, we want to control the color of the icons.
Using javascript, we transform the <img> with an SVG to a HTML <svg>-tag.
That way, we can alter the fill of stroke in the SVG's using regular CSS.
But we ran into an issue, where a customer had uploaded multiple SVG icons which were all having internal CSS and using the same class-names for paths, circles and what not.
The problem is, the last SVG that's on the page overrules the CSS for all SVG's.
For example:
<svg ...>
<defs>
<style>.a{fill: red;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
<svg ...>
<defs>
<style>.a{fill: blue;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
The customer expects a red and a blue circle, because that's what he selected within the CMS.
But this renders to 2 blue circles.
Is there any way to keep CSS found in an SVG within that same SVG?
With a hint from #Lain, I have changed the to script.
It now add's a random-generated classname to the SVG, and prepends that classname to every class in the tag like this:
let styleTag = $svg.find('style');
if (styleTag.length) {
let svgClass = GenerateClassname(8);
const regex = /\.([a-z]{1})/ig; // Get every . followed by a letter
styleTag[0].innerHTML = styleTag[0].innerHTML.replace(regex, "." + svgClass +" .$1");
}
When you inject the svg into the html document, you can add a unique id to each svg and then use it in the css selector.
<svg id="svg-1">
<defs>
<style>#svg-1 .a{fill: red;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
<svg id="svg-2">
<defs>
<style>#svg-2 .a{fill: blue;}</style>
</defs>
<circle class="a" cx="50" cy="50" r="50" />
</svg>
And then, in your near future, you do want to style those individual elements with (global) styling.
shadowDOM (optional part of the native Web Components spec aka Custom Elements)
was created for use-cases like these
supported in all modern browsers
"outside/global" CSS does not leak in
"inside" CSS does not leak out
and inheritable styles, CSS properties and CSS :part can style shadowDOM
customElements.define("svg-circle", class extends HTMLElement{
connectedCallback(){
this.style.display = "inline-block";
this.style.width = "15vw";
this.attachShadow({mode:"open"})
.innerHTML = `<svg viewBox="0 0 100 100">
<style>.a { fill:${this.getAttribute("color")} }</style>
<circle class="a" cx="50" cy="50" r="45" />
<circle part="inner" class="a" cx="50" cy="50" r="20" />
</svg>`;
}
});
<style>
*::part(inner){ fill:rebeccapurple } /* higher Specificity */
</style>
<h2>Who is afraid of</h2>
<svg-circle color="red" ></svg-circle>
<svg-circle color="yellow" ></svg-circle>
<svg-circle color="blue" ></svg-circle>
I am trying (in javascript) to access parts of a list of SVG components in a little test page, but I am not sure I can achieve what I want this way. The main question is:
Can I have sub-components having the same id in the two SVG top components?
In the code hereafter I want to change the color inside the first disk and the first rectangle. Here is what I tried, but it is not working.
Any tip would be appreciated.
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name=viewport content='width=device-width, initial-scale=1'>
<title>SVG-ID-Test</title>
</head>
<body>
<svg id="theSVGOne" width="200" height="300" fill="#d55">
<circle id="theCircle" cx="100" cy="75" r="50"
stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect id="theRectangle" x="30" y="140" width="110" height="30"
stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<svg id="theSVGTwo" width="200" height="200">
<circle id="theCircle" cx="100" cy="75" r="50"
stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect id="theRectangle" x="30" y="140" width="110" height="30"
stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<div id="status"></div>
<script type='text/javascript'>
let svgOne = document.getElementById('theSVGOne')
let svgTwo = document.getElementById('theSVGTwo')
let statusPane = document.getElementById('status')
statusPane.innerHTML = 'svgOne => '+svgOne.childElementCount.toString()
let circOne = svgOne.firstChild
let rctOne = svgOne.lastChild
circOne.setAttribute(('fill', '#ec3'))
rctOne.setAttribute(('fill', '#e3c'))
</script>
</body>
You can use a class instead of id on the child elements (you can have as many duplicate class attributes as you want in the document) and then use querySelector on each svg to target specific children.
let svgOne = document.getElementById('theSVGOne')
let svgTwo = document.getElementById('theSVGTwo')
let statusPane = document.getElementById('status')
statusPane.innerHTML = 'svgOne => '+svgOne.childElementCount.toString()
let circOne = svgOne.querySelector(".theCircle")
let rctOne = svgOne.querySelector(".theRectangle")
circOne.setAttribute('fill', '#ec3')
rctOne.setAttribute('fill', '#e3c')
let circTwo = svgTwo.querySelector(".theCircle")
let rctTwo = svgTwo.querySelector(".theRectangle")
circTwo.setAttribute('fill', 'blue')
rctTwo.setAttribute('fill', 'green')
<svg id="theSVGOne" width="200" height="300" fill="#d55">
<circle class="theCircle" cx="100" cy="75" r="50" stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect class="theRectangle" x="30" y="140" width="110" height="30" stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<svg id="theSVGTwo" width="200" height="200">
<circle class="theCircle" cx="100" cy="75" r="50" stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect class="theRectangle" x="30" y="140" width="110" height="30" stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<div id="status"></div>
Don't use IDs
While technically you can have duplicate ids in the DOM (and make it work), this is very bad practise. Id stands for identifier and should be unique to be able to "tell them apart". You can't do that with identical ids (which theCircle are we talking about?).
Problem is, html won't complain about duplicate ids (no errors are thrown).
To actually get feedback on right or wrong markup you can go to w3's validator and check your html there.
Eg. Error: Duplicate ID theCircle.
Working (but wrong) example using id:
let svgOne = document.getElementById('theSVGOne')
let svgTwo = document.getElementById('theSVGTwo')
let statusPane = document.getElementById('status')
statusPane.innerHTML = 'svgOne => '+svgOne.childElementCount.toString()
let circOne = svgOne.getElementById("theCircle")
let rctOne = svgOne.getElementById("theRectangle")
circOne.setAttribute('fill', '#ec3')
rctOne.setAttribute('fill', '#e3c')
let circTwo = svgTwo.getElementById("theCircle")
let rctTwo = svgTwo.getElementById("theRectangle")
circTwo.setAttribute('fill', 'pink')
rctTwo.setAttribute('fill', 'teal')
<svg id="theSVGOne" width="200" height="300" fill="#d55">
<circle id="theCircle" cx="100" cy="75" r="50" stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect id="theRectangle" x="30" y="140" width="110" height="30" stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<svg id="theSVGTwo" width="200" height="200">
<circle id="theCircle" cx="100" cy="75" r="50" stroke="firebrick" fill="#ddd" stroke-width="3" />
<rect id="theRectangle" x="30" y="140" width="110" height="30" stroke="black" fill="#ddd" stroke-width="3" />
</svg>
<div id="status"></div>
I have a SVG with circles inside it. And I want them to be increasing and decreasing in radius for ever (like a pulsating circle).
My problem is, can I do it with #keyframes? Or do I need jquery? And if so, how?
Here is my code:
<div class="mapa">
<svg (svg code here......)
<circle opacity="0.3" cx="842" cy="451.814" r="25.582" id="1"/>
<circle opacity="0.3" cx="542" cy="405.814" r="25.582" id="1"/>
</svg>
</div>
How do I style the 'r' parameter?
I read I cannot style the 'r' parameter, but this worked:
<circle cx="168" cy="179" r="59"
fill="white" stroke="black"
onmouseover="evt.target.setAttribute('r', '72');"
onmouseout="evt.target.setAttribute('r', '59');"
/>
However, I want to do it with continuous increase and decrease in radius? And not on mouseover/mouseleave. Something like (r=25, then r=30, then back to 25, and goes on forever). How do I do this?
Thanks for your time, if you can give me any tips I'd apreciate it a lot!
Try to use svg smil animate
<svg width="150" height="150">
<circle opacity="0.3" cx="84%" cy="45%" r="3" id="1">
<animate attributeName="r" values="3; 10; 3" keyTimes="0; 0.5; 1" dur="1s" repeatCount="indefinite" />
</circle>
<circle opacity="0.3" cx="50%" cy="50%" r="10" id="2">
<animate attributeName="r" values="10; 3; 10" keyTimes="0; 0.5; 1" dur="1s" repeatCount="indefinite"/>
</circle>
</svg>
The easiest solution in CSS with a little hack around SVG containers. You change the container, not the svg. The circle element just fills 100% of the container. And the container artificially makes a circle with a border-radius.
svg {
border-radius: 50%;
transition: all 1s;
}
svg:hover {
width: 200px;
height: 200px;
}
<svg width="100" height="100">
<circle cx="50" cy="50" r="100%"
fill="green" />
</svg>
You can figure out how to implement your own keyframes, if this solution works for you.
And just to be clear, JQuery is a framework. You shouldn't bring up JQuery unless this question is about JQuery's framework. The language you're looking for is "Javascript" and it's in all major browsers by default. You can use Javascript to do this.
const grow = function(radius) {
var circle = document.getElementsByTagName("circle")[0];
circle.setAttribute('r', radius);
}
setTimeout(function() {
grow(100);
setTimeout(function() {
grow(40);
}, 2000);
}, 2000);
circle {
transition: all 1s;
}
<svg width="200" height="200">
<circle cx="100" cy="100" r="40"
fill="green" />
</svg>
I just generated myself an SVG-based loading indicator using an online service, but every time a page loads that uses it I get a warning from Chrome which informs me that SMIL animations are getting deprecated, which is rather obnoxious. In an attempt to get rid of it I decided to look into replacing the <animate> tags with Web Animations. Below is the original SVG:
<svg width='200px' height='200px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-ring-alt">
<circle cx="50" cy="50" r="40" stroke="white" fill="none" stroke-width="10" stroke-linecap="round"/>
<circle cx="50" cy="50" r="40" stroke="#808080" fill="none" stroke-width="6" stroke-linecap="round">
<animate attributeName="stroke-dashoffset" dur="2s" repeatCount="indefinite" from="0" to="502"/>
<animate attributeName="stroke-dasharray" dur="2s" repeatCount="indefinite" values="150.6 100.4;1 250;150.6 100.4"/>
</circle>
</svg>
And here is what I ended up with:
<svg width='200px' height='200px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="40" stroke="white" fill="none" stroke-width="10" stroke-linecap="round"/>
<circle cx="50" cy="50" r="40" stroke="#808080" fill="none" stroke-width="6" stroke-linecap="round" id="line"/>
<script type="text/javascript" xlink:href="https://cdn.rawgit.com/web-animations/web-animations-js/45d8e40300e82ff02ccfbbc78c89500de0f5616f/web-animations.min.js"></script>
<script type="text/javascript"><![CDATA[
var line = document.getElementById("line");
line.animate(
[
{strokeDashoffset:0},
{strokeDashoffset:502}
],
{ duration: 2000, iterations: Infinity }
);
line.animate(
[
{strokeDasharray:"150.6 100.4"},
{strokeDasharray:"1 250"},
{strokeDasharray:"150.6 100.4"}
],
{ duration: 2000, iterations: Infinity }
);
]]></script>
</svg>
I was about to be really excited that I managed to make it work, then my smile froze on my face as soon as I noticed that the exact same SVG, when used as a background-image in CSS, refuses to animate at all (demo below; note that I inlined the SVG using a data URI here, but the same happens when the SVG is loaded using a regular URL).
body:before {
content: '';
display: block;
width: 200px;
height: 200px;
background: url('data:image/svg+xml;utf8,<svg width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" xmlns:xlink="http://www.w3.org/1999/xlink"><circle cx="50" cy="50" r="40" stroke="white" fill="none" stroke-width="10" stroke-linecap="round"/><circle cx="50" cy="50" r="40" stroke="#808080" fill="none" stroke-width="6" stroke-linecap="round" id="line"/><script type="text/javascript" xlink:href="https://cdn.rawgit.com/web-animations/web-animations-js/45d8e40300e82ff02ccfbbc78c89500de0f5616f/web-animations.min.js"></script><script type="text/javascript"><![CDATA[var line = document.getElementById("line");line.animate([{strokeDashoffset:0},{strokeDashoffset:502}],{ duration: 2000, iterations: Infinity });line.animate([{strokeDasharray:"150.6 100.4"},{strokeDasharray:"1 250"},{strokeDasharray:"150.6 100.4"}],{ duration: 2000, iterations: Infinity });]]></script></svg>') no-repeat center center;
background-size: contain;
}
Should I just ignore the warning and stay with SMIL or is there a way to make Web Animations work inside SVGs?
Unfortunately there is not support yet for animation with backgrounImage property.
While CSS Backgrounds and Borders Module Level 3 Editor’s Draft says
“Animatable: no” for background-image at the time of writing, support
for crossfading images in CSS appeared in Chrome 19 Canary. Until
widespread support arrives this can be faked via image sprites and
background-position or opacity. To animate gradients they must be the
same type
You can read more in the following articles:
http://oli.jp/2010/css-animatable-properties/
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties
I have many elements on the same position and I want to listen for hover event on every element behind even if they are behind other elements, is there a way I can do this?
(They are not hierarchically related and sometimes they are circles, polygons, etc, so checking for bounding rect is not ok)
http://jsfiddle.net/4NdNS/4/
$circles.on("mouseover",function(){console.log(this);});
this is the solution:
FIDDLE
html:
<div id=response></div>
<svg id="mycircle Area">
<circle id="C1" fill="none" r="20" stroke="black" stroke-width="4" cx="100" cy="100"></circle>
<circle fill="none" r="20" stroke="black" stroke-width="4" cx="100" cy="100"></circle>
<circle fill="none" r="20" stroke="black" stroke-width="4" cx="100" cy="100"></circle>
</svg>
jq:
$('circle').on("mousedown",function(e){
$("#response").append($(e).attr('id')+' ');
e.preventDefault();
});
css:
circle{
pointer-events: all;
}
this is your edited fiddle