1

This is my html page that I want to modify:

I'm trying to change the color of an svg image built with snap.svg and I want to use jQuery to achieve that effect, but apparently it is not what is going to happen.

This is my code so far:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Test</title>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
    <script src="dist/snap.svg-min.js"></script>
</head>
<body>
    <div style="width: 70%">
        <svg id="snapSvg" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
        <button id="button">Click</button>
    </div>



    <script>
       $(window).load(function() {


        var s = Snap('#snapSvg'); 

        s.attr({viewBox: "0 0 1200 600"});

        var snapSvg = Snap.load("world.svg", function (world) {
            world.select("#italy").attr({fill: "green"});
            world.select("#usa").attr({fill: "blue"});
            world.select("#germany").attr({fill: "yellow"});
            s.append(world);
        });

    });
    </script>

</body>
</html>

My intention is to use a button to trigger the effect to change the color of the single country instead of loading them with snap, something like $('#button').click(function () { world.select("#italy").attr({fill: "green"}); }); after I loaded the external svg.

This world.svg file was taken from wikipedia.

benomatis
  • 5,536
  • 7
  • 36
  • 59
Porcellino80
  • 447
  • 7
  • 32

2 Answers2

1

There's two basic approaches here:

  1. add the click binding in the Snap.load callback for the external SVG:

    Snap.load("world.svg", function(world) {
        //...
    
        // appending to the DOM might destroy the id so # selector will break
        // so first save a reference for it
        var italy = world.select('#italy');
        s.append(world);
    
        $('#button').click(function() {
            italy.attr({fill: "green"});
        });
    });
    
  2. use the closure to share a reference to the loaded external SVG:

    $(window).load(function() {
        var italy;
    
        $('#button').click(function() {
           italy.attr(...);
        });
    
        //...
    
        Snap.load("world.svg", function(world) {
            italy = world.select('#italy');
            s.append(world);
        });
    });
    

The advantage of the first one is that you do not need to handle the case that the button is clicked before the SVG is loaded. The click event will simply be ignored.

Check whether document.ready would be better than window.load.

Community
  • 1
  • 1
szym
  • 5,606
  • 28
  • 34
  • I'm trying both approaches: With the first one I receive an "ReferenceError: world is not defined" $(document).ready(function() { var s = Snap('#snapSvg'); s.attr({viewBox: "0 0 1200 600"}); var snapSvg = Snap.load("world.svg", function (world) { s.append(world); }); $('#button').click(function() { world.select("#italy").attr({fill: "green"}); }); }); – Porcellino80 Mar 25 '16 at 00:51
  • 1
    This is not quite following the first approach. Note that in the first approach the `$('#button').click(....);` statement is **within** the scope of the `function(world) {... }` callback. – szym Mar 25 '16 at 00:58
  • Sorry, I had to answer below ⬇️ – Porcellino80 Mar 25 '16 at 01:21
0

I'm trying both approaches: With the first one I receive an "ReferenceError: world is not defined"

$(document).ready(function() {
         var s = Snap('#snapSvg'); 

         s.attr({viewBox: "0 0 1200 600"});
         var snapSvg = Snap.load("world.svg", function (world) {
             s.append(world);
         });
         $('#button').click(function() {
             world.select("#italy").attr({fill: "green"});
         });
     });
Porcellino80
  • 447
  • 7
  • 32
  • 1
    This is not quite following the first approach. Note that in the first approach the `$('#button').click(....);` statement is **within** the scope of the `function(world) {... }` callback. – szym Mar 25 '16 at 00:57
  • I tried in this way: $(document).ready(function() { var s = Snap('#snapSvg'); s.attr({viewBox: "0 0 1200 600"}); var snapSvg = Snap.load("world.svg", function (world) { $('#button').click(function() { world.select("#italy").attr({fill: "green"}); }); s.append(world); }); }); But when I click my button I receive an "TypeError: world.select(...) is null" – Porcellino80 Mar 25 '16 at 01:12
  • And I tried the second approach too, but I receive another error: theWorld.select(...) is null $(window).load(function() { var theWorld; $('#button').click(function() { theWorld.select("#italy").attr({fill: "blue"}); }); var s = Snap('#snapSvg'); Snap.load("world.svg", function(world) { s.append(world); theWorld = world; }); }); – Porcellino80 Mar 25 '16 at 01:21
  • 1
    I updated my answer. I think you can't use the #italy selector after appending to the DOM. – szym Mar 25 '16 at 01:33
  • Great! It works! $(document).ready(function() { var s = Snap('#snapSvg'); Snap.load("world.svg", function(world) { var italy = world.select('#italy'); s.append(world); $('#button').click(function() { italy.attr({fill: "green"}); }); }); }); – Porcellino80 Mar 25 '16 at 01:52