javascript to show/hide SVG elements when you click other SVG elements - javascript

I am making an interactive map and want to show hide different SVG elements when others are clicked. [I started with this}(https://stackoverflow.com/questions/30484743/show-and-hide-elements-inside-svgs) but I don't want all the 'g' elements to hide, only specific ones. I tried changing the getelement tag to id but it didn't seem to work.
updated: got it to target classes and updated my code info. The one textbox I want to stay open is not. I hope I made things more clear, thank you.
<script type="text/javascript">
<![CDATA[
var id = 'name';
function place(id) {
var gs = document.getElementsByClassName("textboxes");
// Hide all the elements
for (var i = 0; i < gs.length; i++) {
gs[i].classList.add("hidden");
}
// But make sure the one with "id" is visible
document.getElementById(id).classList.remove("hidden");
}
]]>
</script>
my map item with the onclick:
<g onclick="place('accelerator')" id="accelerator-n">
<a xlink:href="#">
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="539.1322" y1="175.0099" x2="543.4789" y2="175.0099">
<stop offset="0" style="stop-color:#A7A9AC"/>
<stop offset="2.965399e-02" style="stop-color:#ACAEB1"/>
<stop offset="0.1582" style="stop-color:#BCBEC0"/>
<stop offset="0.3016" style="stop-color:#C6C7C9"/>
<stop offset="0.4888" style="stop-color:#C9CACC"/>
<stop offset="0.8212" style="stop-color:#CCCDCF"/>
<stop offset="1" style="stop-color:#D1D3D4"/>
</linearGradient>
<polygon class="st4" points="544.2,340.9 542.9,341.8 542.8,160.8 544.3,159.3 "/>
<polygon class="st6" points="542.4,175.6 539.1,175.3 540.2,174.4 543.5,174.4 "/>
<polygon class="st5" points="539.3,341.9 543,341.9 543,160.6 538.7,160.5 "/>
</a>
</g>
two textboxes, the introinfo box should be seen on loading and others hide/show depending on what map element you click on:
<g id="introinfo" class="textboxes">
<rect x="28.8" y="33.8" class="st32" width="345.7" height="251.7"/>
<foreignobject x="34" y="40" width="338" height="238">
<div xmlns="http://www.w3.org/1999/xhtml" >Here is a long text that runs more than one line and works as a paragraph</div>
<br />
<div>This is <u>UNDER LINE</u> one</div>
<br />
<div>This is <b>BOLD</b> one</div>
<br />
<div>This is <i>Italic</i> one</div>
</foreignobject>
</g>
<g id="accelerator" class="textboxes">
<rect fill="red" x="28.8" y="33.8" class="st32a" width="345.7" height="251.7"/>
<foreignobject x="34" y="40" width="338" height="238">
<div xmlns="http://www.w3.org/1999/xhtml" >accelerator BOX of text.</div>
<br />
<div>This is <u>accelerator BOX of text.</u> one</div>
<br />
<div>This is <b>accelerator BOX of text.</b> one</div>
<br />
<div>This is <i>accelerator BOX of text.</i> one</div>
</foreignobject>
</g>

As per #enxaneta's suggestion, using classes is a little cleaner.
However, you might prefer to use a "hidden" class rather than one named "visible". Depending on whether your elements are normally visible or hidden. Your choice.
.hidden {
display: none;
}
Then your code would become
var id = 'name';
function place(id) {
var gs = document.getElementsByTagName("g");
// Hide all the elements
for (var i = 0; i < gs.length; i++) {
gs[i].classList.add("hidden");
}
// But make sure the one with "id" is visible
document.getElementById(id).classList.remove("hidden");
}
Working demo
function place(id) {
var gs = document.getElementsByTagName("g");
// Hide all the elements
for (var i = 0; i < gs.length; i++) {
gs[i].classList.add("hidden");
}
// But make sure the one with "id" is visible
document.getElementById(id).classList.remove("hidden");
}
function reset() {
document.querySelectorAll("g").forEach(g => g.classList.remove("hidden"));
}
.hidden {
display: none;
}
<svg width="400" height="100">
<g id="one" onclick="place('one')">
<circle cx="50" cy="50" r="40" fill="red"/>
</g>
<g id="two" onclick="place('two')">
<circle cx="150" cy="50" r="40" fill="orange"/>
</g>
<g id="three" onclick="place('three')">
<circle cx="250" cy="50" r="40" fill="gold"/>
</g>
<g id="four" onclick="place('four')">
<circle cx="350" cy="50" r="40" fill="green"/>
</g>
</svg>
<br/>
<button type="button" onclick="reset()">Reset circles</button>

Related

SVG pause/play Can not figure out why this isn't working...?

I need code to work just like on this page.
Play and pausing of an SVG. I went into inspect and pulled all the code I could, which seemed to be HTML. I could not see or find CSS or Javascript. Not sure if that is normal.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="80 0 1024 768" onload="t=setInterval(updateTimer, 100)">
<script>
var time = 0;
function updateTimer() {
//document.getElementById("t").textContent = document.documentElement.getCurrentTime().toFixed(0) + "s";
}
function pause() {
time = document.documentElement.getCurrentTime();
document.documentElement.pauseAnimations();
clearInterval(t);
}
function play() {
if(time > 0)
document.documentElement.setCurrentTime(time);
clearInterval(t);
t=setInterval(updateTimer, 100);
document.documentElement.unpauseAnimations();
}
function stop() {
time = 0;
clearInterval(t);
document.documentElement.setCurrentTime(0);
document.documentElement.pauseAnimations();
}
</script>
<linearGradient id="grad">
<stop stop-color="rgb(10%,80%,10%)" offset="0"/>
<stop stop-color="rgb(10%,40%,20%)" offset="0.4"/>
<stop stop-color="rgb(10%,90%,30%)" offset="0.7"/>
<stop stop-color="rgb(10%,50%,40%)" offset="1"/>
</linearGradient>
<rect fill="url(#grad)" width="0%" height="50" x="100" y="300" rx="5">
<animate attributeName="width" to="100%" begin="0s" dur="30s"/>
</rect>
<text id="t" style="font:24px Arial Black;fill:white;stroke:black" transform="translate(100 334)"/>
<animateTransform type="translate" attributeName="transform" xlink:href="#t" begin="1s" dur="29s" from="100 334" to="1024 334"/>
<g transform="translate(100 500)">
<!-- Play -->
<g onclick="play()">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5"/>
<path id="play" d="M12 5l20 15l-20 15Z" fill="white" pointer-events="none"/>
</g>
<!-- Pause -->
<g transform="translate(50 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="pause();"/>
<path id="pause" d="M14 10l0 20M26 10l0 20" stroke="white" fill="none" stroke-width="8" pointer-events="none"/>
</g>
<!-- Stop (rewind and pause) -->
<g transform="translate(100 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="stop()"/>
<rect x="10" y="10" width="20" height="20" fill="white" pointer-events="none"/>
</g>
</g>
</svg>
When I attempt playback on Code pen, the SVG plays but buttons don't work. At all. I thought the "onclick" would do it...?
Is this because the JS isn't accessible/applied? I don't see any "DIV" or "DOM" so I assume its not a CSS thing...
I have a basic knowledge of HTML, less of CSS and know NOTHING about JavaScript
Short version: getCurrentTime & setCurrentTime must be called on the SVG node.
const mySvg = document.getElementById("mySvg")
function updateTimer() {
const t = `${mySvg.getCurrentTime().toFixed(0)}s`;
document.getElementById("t").textContent = t;
}
function setCurrentTime(t) {
mySvg.setCurrentTime(t)
}
function pause() {
mySvg.pauseAnimations()
}
function play() {
mySvg.unpauseAnimations()
}
function stop() {
clearInterval();
setCurrentTime(0);
mySvg.pauseAnimations()
updateTimer();
}
<svg id="mySvg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="80 0 1024 768" onload="t=setInterval(updateTimer, 100)">
<linearGradient id="grad">
<stop stop-color="rgb(10%,80%,10%)" offset="0"/>
<stop stop-color="rgb(10%,40%,20%)" offset="0.4"/>
<stop stop-color="rgb(10%,90%,30%)" offset="0.7"/>
<stop stop-color="rgb(10%,50%,40%)" offset="1"/>
</linearGradient>
<rect fill="url(#grad)" width="0%" height="50" x="100" y="300" rx="5">
<animate attributeName="width" to="100%" begin="0s" dur="30s"/>
</rect>
<text id="t" style="font:24px Arial Black;fill:white;stroke:black" transform="translate(100 334)"/>
<animateTransform type="translate" attributeName="transform" xlink:href="#t" begin="1s" dur="29s" from="100 334" to="1024 334"/>
<g transform="translate(100 500)">
<!-- Play -->
<g onclick="play()">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5"/>
<path id="play" d="M12 5l20 15l-20 15Z" fill="white" pointer-events="none"/>
</g>
<!-- Pause -->
<g transform="translate(50 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="pause();"/>
<path id="pause" d="M14 10l0 20M26 10l0 20" stroke="white" fill="none" stroke-width="8" pointer-events="none"/>
</g>
<!-- Stop (rewind and pause) -->
<g transform="translate(100 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="stop()"/>
<rect x="10" y="10" width="20" height="20" fill="white" pointer-events="none"/>
</g>
</g>
</svg>
Long version: After all that, why wasn't it working in Codepen?
I can see that the link you posted is to an SVG document with it's own inline JavaScript (in the script tag).
The script calls some SVGElement methods on the SVG root element with document.documentElement.pauseAnimations();.
But what exactly is document element?
Document.documentElement returns the Element that is the root element of the document (for example, the element for HTML documents).
Because this code was called inside an SVG document, document.documentElement returns the SVG root node. However, because codepen is an HTML document, document.documentElement will return the HTML root node.
And you can't call methods like pauseAnimations() on an HTML root node because the HTML root node doesn't understand those methods.
So modern browsers can display SVG documents, HTML documents (and more) but here's the kicker: SVG documents can live inside of HTML documents.
You can see how document.documentElement could refer to two potential things depending on what type of document the JavaScript code was run from.

Transitioning the gradient fill of a single node among many

Let's say I have an SVG with a structure similar to this:
<svg>
<defs>
<linearGradient id="gradient-red">...</linearGradient>
<linearGradient id="gradient-blue">...</linearGradient>
</defs>
<g class="node">
<circle r="50" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="100" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="150" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="200" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="250" style="fill: url('#gradient-red');"></circle>
</g>
</svg>
I now have five circles with reddish gradients. I understand how to change the color of a selected node -- I just target it (via d3.select) and alter its style to 'fill', 'url("#gradient-blue"). But how would I go about transitioning the gradient fill from red to blue for that one node?
Something like this results in no tween/transition and instead causes an instant color swap:
d3.transition().duration(1000)
.tween('start', () => {
let test = d3.select(currentTarget);
test.transition().duration(1000).style('fill', 'url("#gradient-blue")');
And if I were to transition the stop-color of the gradients themselves, it changes all of the nodes/circles (because you're altering the <defs>).
What am I doing wrong?
Transition's interpolation
In D3, a transition basically interpolates a start value to an end value. This can be easy to demonstrate if we interpolate numbers. For instance, let's transition from 50 to 2000:
const interpolator = d3.interpolate(50, 2000);
d3.range(0, 1.05, 0.05).forEach(function(d) {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
We can also interpolate strings:
const interpolator = d3.interpolate("March, 2000", "March, 2020");
d3.range(0, 1.05, 0.05).forEach(function(d) {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
The problem
Now, let's have a look at your case: you want to interpolate from this:
url("#gradient-red")
To this:
url("#gradient-blue")
What are the possible intermediates here? Can you see that this is impossible? Here is the proof:
const interpolator = d3.interpolate("url(#gradient-red)", "url(#gradient-blue)");
d3.range(0, 1.1, 0.1).forEach(function(d) {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
As you can see, the very first interpolation will instantly lead to the end value.
Possible solutions
The most obvious solution is interpolating the stop colour. However, as you just discovered, this will change the gradient of all circles.
So, the naive fix is creating several gradients, one for each circle, with unique IDs. While this may be an adequate solution for 3 or 4 circles, it's clearly not a clever solution if you have tens or hundreds of elements.
That being said, this is my suggestion:
Create a temporary gradient, let's give it the ID #gradient-temporary, just like the red one.
Then, when you select (or filter it somehow) a circle, change it's fill from "url(#gradient-red)" to "url(#gradient-temporary)". This change is immediate, no effect is obvious on the screen.
Do the transition on the stop colour of this temporary gradient.
When the transition finishes, change the circle's fill from "url(#gradient-temporary)" to "url(#gradient-blue)". Again, this is immediate. Also, change the stop colour of the temporary gradient back to red.
That way, you can have hundreds of circles, but you just need 3 gradients to transition them.
Here is a demo with that approach, click on each circle to transition it:
const circles = d3.selectAll("circle");
circles.on("click", function() {
const element = this;
d3.select(element).style("fill", "url(#gradient-temporary)");
d3.select("#gradient-temporary").select("stop:nth-child(2)")
.transition()
.duration(1000)
.style("stop-color", "rgb(0,0,255)")
.on("end", function() {
d3.select(element).style("fill", "url(#gradient-blue)");
d3.select("#gradient-temporary").select("stop:nth-child(2)")
.style("stop-color", "rgb(255,0,0)")
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<defs>
<linearGradient id="gradient-red" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(211,211,211);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-temporary" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(211,211,211);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-blue" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(211,211,211);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
</linearGradient>
</defs>
<g class="node">
<circle r="20" cx="20" cy="70" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="20" cx="80" cy="70" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="20" cx="140" cy="70" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="20" cx="200" cy="70" style="fill: url('#gradient-red');"></circle>
</g>
<g class="node">
<circle r="20" cx="260" cy="70" style="fill: url('#gradient-red');"></circle>
</g>
</svg>

How to implement a html element inside a javascript code?

I am trying to design a sample web page, and I'm facing some issues with svg....
I have created an svg circle with a line over it which will rotate with in the circle. Here is the sample code.
<?xml version="1.0" encoding="iso-8859-1"?>
<svg width="100%" height="100%">
<circle cx="200" cy="200" r="100" stroke="black" stroke-width="4" fill="black" />
<g transform="translate(200,200)">
<line x1="0" y1="0" x2="100" y2="0" style="stroke:rgb(255,255,255);stroke-width:2">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="25" to="360" dur="100s"/>
</line>
</svg>
In the sample code above the 'line' will start rotating immediately when the page is launched, but I want the line to be rotated after I press the START button, something like this...
<input type="button" value=" START " onclick="start()" class="control-menu-top-btn" id="green-btn">
<script language="javascript" type="text/javascript">
function start()
{
.. ?
}
</script>
The beginElement method will start an animation. Setting the begin attribute to indefinite in the markup will stop it from running before the javascript starts it.
html, body {
width: 100%;
height: 100%;
}
<input type="button" value=" START " onclick="start()" class="control-menu-top-btn" id="green-btn">
<script>
function start()
{
document.getElementById("transform").beginElement();
}
</script>
<svg width="100%" height="100%">
<circle cx="200" cy="200" r="100" stroke="black" stroke-width="4" fill="black" />
<g transform="translate(200,200)">
<line x1="0" y1="0" x2="100" y2="0" style="stroke:rgb(255,255,255);stroke-width:2">
<animateTransform id="transform" attributeName="transform"
attributeType="XML"
type="rotate"
from="25" to="360" dur="100s" begin="indefinite" />
</line>
</g>
</svg>

Interacting with a .svg image

I have an image in the format .svg like the one below.
I want to make a webpage where the user can interact with a image like this, but with more nodes. The structure will be similar to a tree.
Is it possible to interact with this .svg image directly, using javascript/html/css?
If so, how?
Note: By interact I mean being able to click on the nodes -and the webpage recognizing it- and when one node is selected the color of the other nodes change.
Note2: I just have the .svg file, I don't know if I'm able to define this as a inline svg on html.
Note3: This image will have many nodes (80+), so I would rather not having to define a clickable area for each one of them and so on... But if this is the only solution, no problem.
Edit:
Here is the content of my .svg file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: g Pages: 1 -->
<svg width="134pt" height="116pt"
viewBox="0.00 0.00 134.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-112 130,-112 130,4 -4,4"/>
<!-- a -->
<g id="node1" class="node"><title>a</title>
<ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"/>
<text text-anchor="middle" x="27" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">a</text>
</g>
<!-- b -->
<g id="node2" class="node"><title>b</title>
<ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
</g>
<!-- a->b -->
<g id="edge1" class="edge"><title>a->b</title>
<path fill="none" stroke="black" d="M27,-71.6966C27,-63.9827 27,-54.7125 27,-46.1124"/>
<polygon fill="black" stroke="black" points="30.5001,-46.1043 27,-36.1043 23.5001,-46.1044 30.5001,-46.1043"/>
</g>
<!-- c -->
<g id="node3" class="node"><title>c</title>
<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
</g>
<!-- b->c -->
<g id="edge2" class="edge"><title>b->c</title>
<path fill="none" stroke="black" d="M54,-18C56.6147,-18 59.2295,-18 61.8442,-18"/>
<polygon fill="black" stroke="black" points="61.9297,-21.5001 71.9297,-18 61.9297,-14.5001 61.9297,-21.5001"/>
</g>
</g>
</svg>
The SVG would need to be inline to have interaction on a page. If you embed an image then the image (.svg) is treated as a single object. For the inline SVG each node should have a separate ID if you want to select them individually.
Here's one I created for another answer.
svg {
display: block;
width: 20%;
margin: 25px auto;
border: 1px solid grey;
stroke: #006600;
}
#buttons polygon:hover {
fill: orange;
}
#buttons rect:hover {
fill: blue
}
#center {
fill: #00cc00;
}
#top {
fill: #cc3333;
}
#right {
fill: #663399;
}
#left {
fill: #bada55;
}
<svg viewbox="0 0 100 100">
<g id="buttons">
<rect id="center" x="25" y="25" height="50" width="50" />
<polygon id="top" points="0,0 100,0 75,25 25,25" />
<polygon id="right" points="100,0 75,25 75,75 100,100" />
<polygon id="bottom" points="0,100 25,75 75,75 100,100" />
<polygon id="left" points="0,0 25,25 25,75 0,100" />
</g>
</svg>
You don't necessarily need to have the svg inline, you could have it in an object tag.
So the html would look like...
<div id="svgdiv">
<object id="svgobject" data="objectclicktest.svg"></object>
</div>
and correspending js
var mySvg = document.getElementById("svgobject").contentDocument.querySelectorAll('svg');
var myNodes = mySvg[0].querySelectorAll('.node');
for( var i = 0; i < myNodes.length; i++ ) {
myNodes[i].addEventListener('click', changeStyle );
}
function changeStyle() {
this.style.fill="blue";
}
Example Click on letters and they should go blue. Note, (I don't think this would work in a setup like a fiddle though)
inline svg elements can interact like other html elements, you can set css rules on them and apply js on them too, you dont need areas
svg is a markup language, meaning that you can use css selector libraries such as jquery to interact with the given svg. You can query the svg in order to get an element by its id, or get an array of elements selected by class. You can attach event handlers to them such as click, mouseover, mouseenter, etc. You can even style them with css.

Changing colour using Javascript [duplicate]

I created a SVG file contains 5 polygons, then I need to embed Javascript so 4 of the polygons' color changes to Red when mouseover, and when mouseout, the color changes to Green. I tried to write the code but it didn't work, what could be the problem? Thanks for help and tips!
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="26cm" height="24cm" viewBox="0 0 2600 2400" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink= "http://www.w3.org/1999/xlink">
<script type="text/javascript">
<![CDATA[
document.getElementById("test").onmouseover = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.color = "red";
}
document.getElementById("test").onmouseout = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.color = "green";
}
]]>
</script>
<circle cx="1600" cy="700" r="600" fill="yellow" stroke="black" stroke-width="3"/>
<ellipse id="test" cx="1300" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<ellipse id="test" cx="1850" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<rect id="test" x="1510" y="650" width="160" height="160" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<polygon id="test" points="1320,800 1370,1080 1820,1080 1870,800 1820,1000 1370,1000" name="mouth" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
</svg>
For what you are doing I would recommend using pure CSS.
Here is some working code.
svg:hover .recolor {
fill: red;
}
As you see, you can just use the :hover event in CSS to recolor the necessary elements. And set them to your default color (green), which will take effect when the user is not hovered.
You have various errors
you've two functions called changeColor, functions must have unique names
SVG does not use color to colour elements, instead it uses fill (and stroke).
id values must be unique, you probably want to replace id by class and then use getElementsByClassName instead of getElementById. If you do that you'll need to cope with more than one element though. I've not completed that part, you should try it yourself so you understand what's going on.
I've removed all but one id from my version so you can see it working on the left eye.
document.getElementById("test").onmouseover = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.fill = "red";
}
document.getElementById("test").onmouseout = function(){changeColor2()};
function changeColor2() {
document.getElementById("test").style.fill = "green";
}
<svg width="26cm" height="24cm" viewBox="0 0 2600 2400" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink= "http://www.w3.org/1999/xlink">
<circle cx="1600" cy="700" r="600" fill="yellow" stroke="black" stroke-width="3"/>
<ellipse id="test" cx="1300" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3"/>
<ellipse cx="1850" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" />
<rect x="1510" y="650" width="160" height="160" fill="blue" stroke="black" stroke-width="3" />
<polygon points="1320,800 1370,1080 1820,1080 1870,800 1820,1000 1370,1000" name="mouth" fill="blue" stroke="black" stroke-width="3"/>
</svg>

Categories