1

Say I have an SVG image with several top-level "g" elements like this:

<svg>
<g id="id1">...</g>
<g id="id2">...</g>
<g id="id3">...</g>
...
</svg>

Now I'd like to show only the one with id1 in the beginning, sliding through id2, id3 and so on as the user repeatedly clicks on the image (similar to a powerpoint presentation). I tried this as a first step:

 <animate xlink:href="#id2" attributeName="opacity" from="0" to="0"  dur="0s" begin="0s"/>
 <animate xlink:href="#id3" attributeName="opacity" from="0" to="0"  dur="0s" begin="0s"/>
...

 <animate xlink:href="#id2" attributeName="opacity" from="0" to="100" dur="0.25s"  begin="click" id="anim1"/>
 <animate xlink:href="#id1" attributeName="opacity" from="100" to="0" dur="0.25s"  begin="anim1.begin" id="anim2"/>
...

The first lines are supposed to make all images transparent except the id1 image - which works fine. The next two lines are supposed to make id1 transparant and show id2 - which doesn't work. I assume that the transparent images with higher ids are on higher levels (in z-direction) and block the click events of the lower images. But I don't know how to make them "dissappear" completely or whatever.

And probably there's a better way to do this anyway...?

Duke
  • 410
  • 7
  • 15
  • Also, if the approach I sugested worked, I wouldn't really know how to proceed with more images. So maybe there's a completely different way to do this...? – Duke Dec 25 '16 at 13:34
  • Personally I would use javascript if its available to it, there are libs to help like Snap.svg or SVG.js. Chrome is deprecating it's support for SVG Animate (there is a polyfill for it). I think the route being promoted is for CSS animation or Javascript. http://stackoverflow.com/questions/30965580/deprecated-smil-svg-animation-replaced-with-css-or-web-animations-effects-hover – Ian Dec 25 '16 at 17:16
  • Javascript is not an option, I have to use SVG. I have an SVG graphics box which is the only place where I can make alterations. All the HTML around it is fixed. – Duke Dec 25 '16 at 17:30
  • Although, wait... That's not really the point... You mean, I should provide the SVG image as mentioned and then use Javascript to flip through the "g"s? That I could do... But how would that go? I'm quite bad in Javascript... – Duke Dec 25 '16 at 17:34
  • you need something.click where something is the id of the element you're clicking on. begin="click" won't work. – Robert Longson Dec 25 '16 at 19:43
  • Depending on what you mean by "SVG graphics box", this might not be possible, irrespectively of whether you are using `` or JavaScript. Can you go into more detail about that? – Thomas W Dec 25 '16 at 20:53
  • I just meant the ... part with "SVG graphics box". But I'm flexible there, I can build it as I want. It's just that I want to have this part embeddable into different HTML pages, not having to use Javascript at all these places. (But this is not a hard constraint, I COULD use Javascript, it would just be nicer without.) – Duke Dec 26 '16 at 23:29

1 Answers1

1

You can do it with SMIL animation. We just need a couple of <set> elements for each state. Each of the two is triggered by a click. One shows the next group, and the other hides the last one.

<svg>
  <g id="id1">
     <rect width="100%" height="100%" fill="red"/>
  </g>
  <g id="id2" display="none">
     <rect width="100%" height="100%" fill="orange"/>
  </g>
  <g id="id3" display="none">
     <rect width="100%" height="100%" fill="yellow"/>
  </g>
  <g id="id4" display="none">
     <rect width="100%" height="100%" fill="green"/>
  </g>

  <set xlink:href="#id2" attributeType="XML" attributeName="display" 
       to="block" begin="id1.click" />
  <set xlink:href="#id1" attributeType="XML" attributeName="display" 
       to="none" begin="id1.click" />

  <set xlink:href="#id3" attributeType="XML" attributeName="display" 
       to="block" begin="id2.click" />
  <set xlink:href="#id2" attributeType="XML" attributeName="display" 
       to="none" begin="id2.click" />

  <set xlink:href="#id4" attributeType="XML" attributeName="display" 
       to="block" begin="id3.click" />
  <set xlink:href="#id3" attributeType="XML" attributeName="display" 
       to="none" begin="id3.click" />

  <set xlink:href="#id1" attributeType="XML" attributeName="display" 
       to="block" begin="id4.click" />
  <set xlink:href="#id4" attributeType="XML" attributeName="display" 
       to="none" begin="id4.click"/>

</svg>

It is also very easy - and perhaps more flexible - to do with Javascript.

// Get the SVG element
var mysvg = document.getElementById("mysvg");

// Get all the G elements that are children of our SVG
var groups = mysvg.querySelectorAll("g");

// Which G is currently shown
var current = 0;

// Show that G and hide the others
showGroup(current);

// Add the click event handler to the SVG
mysvg.addEventListener("click", groupSwitcher);



// Define the click handler that we will attach to the SVG.
function groupSwitcher(evt)
{
  // When we receive a click, select the next group
  current += 1;
  // Wrap naround to the beginning if we go past the last one
  if (current === groups.length)
    current = 0;
  
  // Show the new group (and hide the old one);
  showGroup(current);
}


// The function that shows one group and hides the others.
function showGroup(groupNumber)
{
  for (var i=0; i < groups.length; i++) {
    if (i === groupNumber) {
      // If this is the one we want to show then make it visible
      groups[i].setAttribute("visibility", "visible");
    } else {
      // It's one of the others, hide it
      groups[i].setAttribute("visibility", "hidden");
    }
  }
}
<svg id="mysvg">
  <g id="id1">
     <rect width="100%" height="100%" fill="red"/>
  </g>
  <g id="id2">
     <rect width="100%" height="100%" fill="orange"/>
  </g>
  <g id="id3">
     <rect width="100%" height="100%" fill="yellow"/>
  </g>
  <g id="id4">
     <rect width="100%" height="100%" fill="green"/>
  </g>
</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181