3

I have drawn a floor map of a super market using MS Visio 2013. I have converted it to a svg file. What i want to do is to pin point some locations of the floor map using another svg file.

I have tried this by many other means. I created a html 5 canvas and drew the map using javascript commands.Then i used a svg image to show the locations.

ctx.drawSvg('location.svg', x_coordinate , y_coordinate , 10, 14);

//x_coordinate,y_coordinate is defining the multiple locations which this location.svg file will be drawn.

But results of that method was low in quality. Not to mention the fact that it gets more low quality when you zoom in to the map.

I know the method of embedding a svg to a html page or using a svg file as a background.But with those two how can i use another svg file to pinpoint the multiple locations?

Is there any way of doing this using svg files? :)

direndd
  • 642
  • 2
  • 16
  • 47

1 Answers1

8

This is actually quite simple. There are several ways to do it, but the following way is probably one of the simplest. It doesn't use Canvas at all, just pure SVG.

I am going to assume that when you say the "pin" is another file, that is not really a strict requirement. Ie. that there is no reason you couldn't include the pin picture in your map SVG file.

Here's a sample SVG map file. I will assume for now that it is embedded in the HTML file, but an external file should work as well.

<html>
<body>
<svg id="map" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     width="500" height="400" viewBox="0 0 500 400">

  <defs>
      <!-- Define our map "pin". Just a circle in this case.
           The circle is centred on (0,0) to make positioning at the destination point simpler. -->
      <g id="pin">
          <circle cx="0" cy="0" r="7" fill="white" stroke="green" stroke-width="2"/>
      </g>
  </defs>

  <!-- A simple floorplan map -->
  <g id="floor" fill="#ddd" stroke="black" stroke-width="3">
      <rect x="50" y="50" width="200" height="150" />
      <rect x="100" y="200" width="150" height="150" />
      <rect x="250" y="100" width="200" height="225" />
  </g>

  <!-- A group to hold the created pin refernces. Not necessary, but keeps things tidy. -->
  <g id="markers">
  </g>
</svg>
</body>
</html>

The group "floor" is our floor plan, and the pin image has been included in the <defs> section. Stuff defined in the <defs> section is not rendered itself. It has to be referenced elsewhere in the file.

From here all you need is a simple Javascript loop which uses the DOM to add one <use> element for each pin.

var  markerPositions = [[225,175], [75,75], [150,225], [400,125], [300,300]];

var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";

for (var i=0; i<markerPositions.length; i++) {
    // Create an SVG <use> element
    var  use = document.createElementNS(svgNS, "use");
    // Point it at our pin marker (the circle)
    use.setAttributeNS(xlinkNS, "href", "#pin");
    // Set it's x and y
    use.setAttribute("x", markerPositions[i][0]);
    use.setAttribute("y", markerPositions[i][1]);
    // Add it to the "markers" group
    document.getElementById("markers").appendChild(use);
}

The <use> allows us to make a reference to another element in the SVG file. So we create a <use> element for each pin we want to place. Each <use> references our predefined pin symbol.

Here is a demo: http://jsfiddle.net/6cFfU/3/

Update:

To use an external "pin" file, referencing it from an image should work.

<g id="pin">
  <image xlink:href="pin.svg"/>
</g>

Demo here: http://jsfiddle.net/6cFfU/4/

If you are not even allowed to reference the pin file from your map file. Then you just need to insert this marker definition using a bit of DOM manipulation. Something like:

var  grp = document.createElementNS(svgNS, "g");
grp.id = "pin";
var  img = document.createElementNS(svgNS, "image");
img.setAttributeNS(xlinkNS, "href", "pin.pvg");
grp.appendChild(img);
document.getElementsByTagName("defs")[0].appendChild(grp);

Demo here: http://jsfiddle.net/7Mysc/1/

That's assuming you want to go the pure SVG route. There are other ways. For instance you could do a similar thing using HTML. Wrap your PIN file in a <div> and use jQuery to clone the div, then use absolute positioning to position them them in the correct place. However you then have to worry about adjusting for the map scale etc.

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • I understand your solution but i have two external svg files. The map is also and svg and the pin is also an svg file. Ho can i use those two and show multiple locations in the map.svg using pin.svg? – direndd Sep 05 '13 at 07:07
  • Updated with an example of how to use an external SVG file. – Paul LeBeau Sep 05 '13 at 18:10
  • Using Instead of Didn't work. And i didn't understand the "bit of DOM manipulation" part Where should i use that code? I am trying to display the map.svg file and multiple pin.svg files on top of that map.svg. Is it possible? – direndd Sep 05 '13 at 18:26
  • 1
    Using an image does work. Were you using a valid URL? I've updated my answer with a couple of demos to show that (a) it does work, and (b) how to use DOM functions to add a marker into a map file. The PIN image is just a random SVG file I found via Google. – Paul LeBeau Sep 06 '13 at 06:44
  • Great! It works. But i also need to add the floor plan as an external svg. I tried the same method by removing the content of the group floor and doing the same thing you did for the pin external image. This is the code i used. But when i do this changes even the pins are not displayed. Can you please point out any mstakes i have done here? – direndd Sep 07 '13 at 04:09
  • ok now i have added the map also from an external svg. But it draws multiple maps. I am sure it's something to do with the for loop. But i can't figure out where to change my code to avoid multiple maps.This is what i have up to now. http://jsfiddle.net/Diren/9EweK/ and as you will see i have changed the for loop to reduce the muliple drawings and i have changed the first marker position to 0,0 because earlier the map also was drawn at the x,y coordinates of first marker. That's why i made it 0,0 you will see the shadow if the first pin at top left corner. – direndd Sep 07 '13 at 04:54
  • Exactly! :D Just one more thing to add. Is there any way i can draw a line or multiple lines on this when i give starting x,y coordinates and ending x,y coordinates. Something similar to this. http://code4solutions.heliohost.org/jdirendd/Capture.PNG This is just an edit of the png file. – direndd Sep 08 '13 at 02:58
  • 1
    The format for a line in SVG is ``. It should be fairly obvious from the `` example you already have, what you need to do to add lines to the document. I'll leave that as an exercise for you. – Paul LeBeau Sep 08 '13 at 06:32
  • As far as i understood i did these changes to your previous example. This is what i got, http://jsfiddle.net/Diren/AL8Pa/1/ How can i change the x1,y1,x2,y2 parameters from the use.setAttribute? It only displays the 'line' defined in the defs section. Please help me with this last step. :) – direndd Sep 08 '13 at 06:56
  • 1
    You don't need to use `` and `` for the lines. That was only so that we could define the pin once and re-use it. Just add the lines themselves to the diagram. See http://jsfiddle.net/TAbbn/ – Paul LeBeau Sep 09 '13 at 02:20
  • Perfect! :) Now i understand the concept of and . Thank you very Much! :D – direndd Sep 09 '13 at 02:47
  • I'm using your code. http://jsfiddle.net/kwoxer/5uc17jwr/13/ But somehow I'm not able to set it to the same position as my coordinates from the topojson. Do you have an idea about my case? – kwoxer Jan 29 '15 at 14:59