1

I have an svg file that has all the countries in the world. Each country has their own individual paths for example:

<path
      inkscape:connector-curvature="0"
      id="PH"
      data-name="Philippines"
      data-id="PH"
      d="m 1684.6,518.6 -0.6,-2.3 -0.8,-3.2 -4.8,-3 0.8,4.9 -3.9,0.2 -0.7,2.8 -4.2,1.7 -2.2,-2.8 -2.8,2.4 -3.4,1.7 -1.9,5.4 1.1,1.9 3.9,-3.6 2.7,0.3 1.5,-2.7 3.8,3 -1.5,3.1 1.9,4.6 6.8,3.7 1.4,-3 -2.1,-4.7 2.4,-3.2 2.5,6.4 1.5,-5.8 -0.6,-3.5 -0.8,-4.3 z m -14.5,-11.8 0,-6.1 -3.6,6.1 0.5,-4.2 -3,0.3 -0.3,4 -1.2,1.8 -1,1.7 3.8,4.4 1.6,-1.9 1.4,-4 1.8,-2.1 z m -30.1,6.1 2.6,-4.4 3.4,-3.5 -1.5,-5.2 -2.4,6.3 -2.9,4.4 -3.8,4 -2.4,4.4 7,-6 z m 17.4,-16.4 1.2,3 -0.1,3.3 0.5,2.9 3.3,-1.9 2.4,-2.7 -0.2,-2.6 -3.6,0 -3.5,-2 z m 20,-1.7 -1.8,-2.4 -5.4,-0.1 4,4.8 0.3,2.4 -3.3,-0.5 1.2,3.9 1.7,0.3 0.7,4.5 2.5,-1.4 -1.7,-4 -0.4,-2.1 4.5,1.7 -2.3,-7.1 z m -22.9,-5.8 -2.2,-2.3 -4.8,-0.2 3.4,4.8 2.8,3.2 0.8,-5.5 z m -6.4,-34.6 -3.3,0 -0.9,5.8 1.1,9.9 -2.6,-2 1.2,6 1.2,2.8 3.3,3.7 0.4,-2.3 1.8,1.4 -1.5,1.7 0.1,2.6 2.9,1.4 5,-0.9 4,3.8 1.1,-2.4 2.5,3.4 4.8,3.1 0.2,-2.9 -2,-1.6 0.1,-3.4 -7.5,-3.6 -2.3,0.8 -3.1,-0.7 -2,-5.1 0.1,-5.1 3,-2.1 0.6,-5.3 -2.7,-4.6 0.4,-2.6 -0.7,-1.6 -1.5,1.6 -3.7,-1.8 z"
      style="fill:#1abc9c;fill-rule:evenodd;" />

<path
      inkscape:connector-curvature="0"
      id="PL"
      data-name="Poland"
      data-id="PL"
      d="m 1069.4,228.3 -4.6,-0.1 -0.5,-1.4 -4.8,-1.1 -5.7,2.1 -7.1,2.8 -3.1,1.7 1.4,3.1 -1.2,1.6 2,2.2 1.4,3.3 -0.1,2.1 2.3,3.9 2.4,1.9 3.7,0.6 -0.1,1.7 2.7,1.2 0.6,-1.5 3.4,0.6 0.7,2 3.6,0.3 2.6,3.1 0.3,0.4 1.9,-0.9 2.7,2.2 2.8,-1.3 2.4,0.6 3.4,-0.8 4.9,2.3 1.1,0.4 -1.6,-2.8 3.8,-5.1 2.3,-0.7 0.3,-1.8 -3.1,-5.3 -0.5,-2.7 -1.9,-2.9 2.7,-1.2 -0.3,-2.4 -1.7,-2.3 -0.6,-2.7 -1.4,-1.9 -2.5,-0.6 -8.7,0.1 -5.9,-0.7 z"
      style="fill:#f2f2f2;fill-rule:evenodd" />

Now I want to access each country through a function in JS. So I added a href before the country:

<a href = "#" onclick = "SelectCountry('ph');" id = 'country_ph'> 
   <path
      inkscape:connector-curvature="0"
      id="PH"
      data-name="Philippines"
      data-id="PH"
      d="m 1684.6,518.6 -0.6,-2.3 -0.8,-3.2 -4.8,-3 0.8,4.9 -3.9,0.2 -0.7,2.8 -4.2,1.7 -2.2,-2.8 -2.8,2.4 -3.4,1.7 -1.9,5.4 1.1,1.9 3.9,-3.6 2.7,0.3 1.5,-2.7 3.8,3 -1.5,3.1 1.9,4.6 6.8,3.7 1.4,-3 -2.1,-4.7 2.4,-3.2 2.5,6.4 1.5,-5.8 -0.6,-3.5 -0.8,-4.3 z m -14.5,-11.8 0,-6.1 -3.6,6.1 0.5,-4.2 -3,0.3 -0.3,4 -1.2,1.8 -1,1.7 3.8,4.4 1.6,-1.9 1.4,-4 1.8,-2.1 z m -30.1,6.1 2.6,-4.4 3.4,-3.5 -1.5,-5.2 -2.4,6.3 -2.9,4.4 -3.8,4 -2.4,4.4 7,-6 z m 17.4,-16.4 1.2,3 -0.1,3.3 0.5,2.9 3.3,-1.9 2.4,-2.7 -0.2,-2.6 -3.6,0 -3.5,-2 z m 20,-1.7 -1.8,-2.4 -5.4,-0.1 4,4.8 0.3,2.4 -3.3,-0.5 1.2,3.9 1.7,0.3 0.7,4.5 2.5,-1.4 -1.7,-4 -0.4,-2.1 4.5,1.7 -2.3,-7.1 z m -22.9,-5.8 -2.2,-2.3 -4.8,-0.2 3.4,4.8 2.8,3.2 0.8,-5.5 z m -6.4,-34.6 -3.3,0 -0.9,5.8 1.1,9.9 -2.6,-2 1.2,6 1.2,2.8 3.3,3.7 0.4,-2.3 1.8,1.4 -1.5,1.7 0.1,2.6 2.9,1.4 5,-0.9 4,3.8 1.1,-2.4 2.5,3.4 4.8,3.1 0.2,-2.9 -2,-1.6 0.1,-3.4 -7.5,-3.6 -2.3,0.8 -3.1,-0.7 -2,-5.1 0.1,-5.1 3,-2.1 0.6,-5.3 -2.7,-4.6 0.4,-2.6 -0.7,-1.6 -1.5,1.6 -3.7,-1.8 z"
      style="fill:#1abc9c;fill-rule:evenodd;" />
   </a>

and access them here:

var phCountry = document.getElementById("PH");

function SelectCountry(country)
{
    alert(country);
}

However I want to scale the country the user clicks on. I tried phCountry.setAttribute("height", "100px");
phCountry.style.height = "100px"; I'm very new to svg and js so I may probably be doing this in the wrong way. How can I fix this? Thanks a ton!

Dran Dev
  • 529
  • 3
  • 20
  • `phCountry` is an element, and every element has its own `height` and `width` attribute. did you try that already? – r3wt Aug 29 '19 at 02:51
  • @r3wt yes I have tried that one as well. I think adjusting the element wouldn't work or something. I even tried putting `style = "width: 100px;"` in the tag on the svg itself. I guess one has to really modify the svg properties or something? Or maybe contain the element inside an object and then scale it? I dunno ._. – Dran Dev Aug 29 '19 at 02:54
  • 1
    have you tried using javascript to insert css targeting the specific path? `like path[id="PH"] { // your css }` – r3wt Aug 29 '19 at 03:14
  • 2
    @r3wt that's not true of SVG elements. Most don't support height and width. – Robert Longson Aug 29 '19 at 03:30
  • 1
    You may want to take a look at this answer: https://stackoverflow.com/questions/57579893/the-selected-item-svg-must-rise-above-the-other-items#57581468 It may be what you need. – enxaneta Aug 29 '19 at 06:38

1 Answers1

2

<path> elements do not have a width or height attribute you can change. What you have to do is apply a transform that scales the country paths when you click on them.

Also, you don't need to add <a> tags to your SVG. Just add a click handler to each path.

See the example below. I've described how it works in the code comments.

// Look for all <path> elements in the SVG and add a click handler to each one
document.querySelectorAll("svg path").forEach(function(item) {
  item.addEventListener("click", countryClick);
});


function countryClick(e) {
  // e.target is the path we clicked on.
  // classList.toggle("enlarge") will cause the "enlarge" class to be added then removed on alternate clicks
  e.target.classList.toggle("enlarge");
}
.enlarge {
  /* Use the bounds of the path to calculate the transform origin */
  transform-box: fill-box;
  /* Set the origin for scaling to the centre of the path bounds */
  transform-origin: 50% 50%;
  /* Scale up by 2 in both the x and y directions */
  transform: scale(2, 2);
}
<svg viewBox="1000 200 800 400">

  <path
      inkscape:connector-curvature="0"
      id="PH"
      data-name="Philippines"
      data-id="PH"
      d="m 1684.6,518.6 -0.6,-2.3 -0.8,-3.2 -4.8,-3 0.8,4.9 -3.9,0.2 -0.7,2.8 -4.2,1.7 -2.2,-2.8 -2.8,2.4 -3.4,1.7 -1.9,5.4 1.1,1.9 3.9,-3.6 2.7,0.3 1.5,-2.7 3.8,3 -1.5,3.1 1.9,4.6 6.8,3.7 1.4,-3 -2.1,-4.7 2.4,-3.2 2.5,6.4 1.5,-5.8 -0.6,-3.5 -0.8,-4.3 z m -14.5,-11.8 0,-6.1 -3.6,6.1 0.5,-4.2 -3,0.3 -0.3,4 -1.2,1.8 -1,1.7 3.8,4.4 1.6,-1.9 1.4,-4 1.8,-2.1 z m -30.1,6.1 2.6,-4.4 3.4,-3.5 -1.5,-5.2 -2.4,6.3 -2.9,4.4 -3.8,4 -2.4,4.4 7,-6 z m 17.4,-16.4 1.2,3 -0.1,3.3 0.5,2.9 3.3,-1.9 2.4,-2.7 -0.2,-2.6 -3.6,0 -3.5,-2 z m 20,-1.7 -1.8,-2.4 -5.4,-0.1 4,4.8 0.3,2.4 -3.3,-0.5 1.2,3.9 1.7,0.3 0.7,4.5 2.5,-1.4 -1.7,-4 -0.4,-2.1 4.5,1.7 -2.3,-7.1 z m -22.9,-5.8 -2.2,-2.3 -4.8,-0.2 3.4,4.8 2.8,3.2 0.8,-5.5 z m -6.4,-34.6 -3.3,0 -0.9,5.8 1.1,9.9 -2.6,-2 1.2,6 1.2,2.8 3.3,3.7 0.4,-2.3 1.8,1.4 -1.5,1.7 0.1,2.6 2.9,1.4 5,-0.9 4,3.8 1.1,-2.4 2.5,3.4 4.8,3.1 0.2,-2.9 -2,-1.6 0.1,-3.4 -7.5,-3.6 -2.3,0.8 -3.1,-0.7 -2,-5.1 0.1,-5.1 3,-2.1 0.6,-5.3 -2.7,-4.6 0.4,-2.6 -0.7,-1.6 -1.5,1.6 -3.7,-1.8 z"
      style="fill:#1abc9c;fill-rule:evenodd;" />

  <path
      inkscape:connector-curvature="0"
      id="PL"
      data-name="Poland"
      data-id="PL"
      d="m 1069.4,228.3 -4.6,-0.1 -0.5,-1.4 -4.8,-1.1 -5.7,2.1 -7.1,2.8 -3.1,1.7 1.4,3.1 -1.2,1.6 2,2.2 1.4,3.3 -0.1,2.1 2.3,3.9 2.4,1.9 3.7,0.6 -0.1,1.7 2.7,1.2 0.6,-1.5 3.4,0.6 0.7,2 3.6,0.3 2.6,3.1 0.3,0.4 1.9,-0.9 2.7,2.2 2.8,-1.3 2.4,0.6 3.4,-0.8 4.9,2.3 1.1,0.4 -1.6,-2.8 3.8,-5.1 2.3,-0.7 0.3,-1.8 -3.1,-5.3 -0.5,-2.7 -1.9,-2.9 2.7,-1.2 -0.3,-2.4 -1.7,-2.3 -0.6,-2.7 -1.4,-1.9 -2.5,-0.6 -8.7,0.1 -5.9,-0.7 z"
      style="fill:#f2f2f2;fill-rule:evenodd" />
      
</svg>

However there is one extra step you'll inevitably need to do. If you clicked on the square I have added in the first example, then you will have discovered it already. Elements in an SVG have a draw order. Earlier paths in the file are drawn before later ones. So you will find when you enlarge one country, it may be behind another un-enlarged country.

That's probably not what you want. So to fix that, you also need to move the country you are enlarging to the front. You do that by moving it to the end of the SVG.

In the next example, I've added the code to do that.

// Look for all <path> elements in the SVG and add a click handler to each one
document.querySelectorAll("svg path").forEach(function(item) {
  item.addEventListener("click", countryClick);
});


function countryClick(e) {
  // e.target is the path we clicked on.
  // classList.toggle("enlarge") will cause the "enlarge" class to be added then removed on alternate clicks
  e.target.classList.toggle("enlarge");
  
  // If we are enlarging, then also move the path to the end of the SVG
  if (e.target.classList.contains("enlarge")) {
    var svg = e.target.ownerSVGElement;
    // appendChild() adds an element to the end of the SVG.
    // If it is already in the SVG, it gets moved from it's current position in the order.
    svg.appendChild(e.target);
  }
}
.enlarge {
  /* Use the bounds of the path to calculate the transform origin */
  transform-box: fill-box;
  /* Set the origin for scaling to the centre of the path bounds */
  transform-origin: 50% 50%;
  /* Scale up by 2 in both the x and y directions */
  transform: scale(2, 2);
}
<svg viewBox="1000 200 800 400">

  <path
      inkscape:connector-curvature="0"
      id="PH"
      data-name="Philippines"
      data-id="PH"
      d="m 1684.6,518.6 -0.6,-2.3 -0.8,-3.2 -4.8,-3 0.8,4.9 -3.9,0.2 -0.7,2.8 -4.2,1.7 -2.2,-2.8 -2.8,2.4 -3.4,1.7 -1.9,5.4 1.1,1.9 3.9,-3.6 2.7,0.3 1.5,-2.7 3.8,3 -1.5,3.1 1.9,4.6 6.8,3.7 1.4,-3 -2.1,-4.7 2.4,-3.2 2.5,6.4 1.5,-5.8 -0.6,-3.5 -0.8,-4.3 z m -14.5,-11.8 0,-6.1 -3.6,6.1 0.5,-4.2 -3,0.3 -0.3,4 -1.2,1.8 -1,1.7 3.8,4.4 1.6,-1.9 1.4,-4 1.8,-2.1 z m -30.1,6.1 2.6,-4.4 3.4,-3.5 -1.5,-5.2 -2.4,6.3 -2.9,4.4 -3.8,4 -2.4,4.4 7,-6 z m 17.4,-16.4 1.2,3 -0.1,3.3 0.5,2.9 3.3,-1.9 2.4,-2.7 -0.2,-2.6 -3.6,0 -3.5,-2 z m 20,-1.7 -1.8,-2.4 -5.4,-0.1 4,4.8 0.3,2.4 -3.3,-0.5 1.2,3.9 1.7,0.3 0.7,4.5 2.5,-1.4 -1.7,-4 -0.4,-2.1 4.5,1.7 -2.3,-7.1 z m -22.9,-5.8 -2.2,-2.3 -4.8,-0.2 3.4,4.8 2.8,3.2 0.8,-5.5 z m -6.4,-34.6 -3.3,0 -0.9,5.8 1.1,9.9 -2.6,-2 1.2,6 1.2,2.8 3.3,3.7 0.4,-2.3 1.8,1.4 -1.5,1.7 0.1,2.6 2.9,1.4 5,-0.9 4,3.8 1.1,-2.4 2.5,3.4 4.8,3.1 0.2,-2.9 -2,-1.6 0.1,-3.4 -7.5,-3.6 -2.3,0.8 -3.1,-0.7 -2,-5.1 0.1,-5.1 3,-2.1 0.6,-5.3 -2.7,-4.6 0.4,-2.6 -0.7,-1.6 -1.5,1.6 -3.7,-1.8 z"
      style="fill:#1abc9c;fill-rule:evenodd;" />

  <path
      inkscape:connector-curvature="0"
      id="PL"
      data-name="Poland"
      data-id="PL"
      d="m 1069.4,228.3 -4.6,-0.1 -0.5,-1.4 -4.8,-1.1 -5.7,2.1 -7.1,2.8 -3.1,1.7 1.4,3.1 -1.2,1.6 2,2.2 1.4,3.3 -0.1,2.1 2.3,3.9 2.4,1.9 3.7,0.6 -0.1,1.7 2.7,1.2 0.6,-1.5 3.4,0.6 0.7,2 3.6,0.3 2.6,3.1 0.3,0.4 1.9,-0.9 2.7,2.2 2.8,-1.3 2.4,0.6 3.4,-0.8 4.9,2.3 1.1,0.4 -1.6,-2.8 3.8,-5.1 2.3,-0.7 0.3,-1.8 -3.1,-5.3 -0.5,-2.7 -1.9,-2.9 2.7,-1.2 -0.3,-2.4 -1.7,-2.3 -0.6,-2.7 -1.4,-1.9 -2.5,-0.6 -8.7,0.1 -5.9,-0.7 z"
      style="fill:#f2f2f2;fill-rule:evenodd" />

  <path d="M 1100,228 h 30 v 30 h -30 z" fill="#ccaa88"/>

</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • Thank you so much, this is actually what I needed! Got one more inquiry in regards to this: 1. How to make the selected country reposition towards the center. 2. And how to pass/get in the country id once clicked? Thank you once again! :D – Dran Dev Aug 30 '19 at 06:27
  • 1
    You can get the id of the thing you clicked on using `event.target.id`. As for moving the path to the centre, you'll need to do include a `translate()` operation in the `transform` attribute in addition to the `scale()`. However it will be different for each path because they need to move from different places. There is plenty of information around on how to do that. So I'll leave that part for you to have a go at. Good luck. You can always ask another question if you get stuck. But it is pretty simple. – Paul LeBeau Aug 31 '19 at 02:42
  • Thanks a lot! And sorry for the late response! :) God Bless! – Dran Dev Sep 02 '19 at 06:45
  • sir what if I wanted to make the other countries dim/adjust the opacity when one is clicked? – Dran Dev Sep 02 '19 at 07:05
  • One way would be to give the one you selected a class (eg. "selected"). Then you can have a CSS rule like: `svg > :not(.selected) { opacity: 0.5; }` – Paul LeBeau Sep 03 '19 at 09:10