0

I am trying to set the externalGraphic property of a vector layer's style to an SVG sprite that has various viewboxes to position the icons dynamically by creating different views within my SVG file:

<view id="bikeview" viewBox="0 0 52 52"></view>
<view id="boatview" viewBox="52 0 52 52"></view>

...and then accessing them like so:

var defPoiStyle = {
    externalGraphic: 'images/activities/activitySprite.svg#boatview',
    pointRadius: 30,
    cursor: "pointer"
}

The problem is that this only works in Firefox, although with Chrome and Safari I can access each view by entering the URL directly into the browser like this, just not in the map.

I have also noticed that in Chrome's network log (and likely Safari's) that the #boatview part of my image path gets stripped out, but not so in Firefox. I assume it is some kind of XML request issue or something, but I feel like I got my declarations right:

<?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">
<svg
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   x="0px"
   y="0px"
   width="52px"
   height="52px"
   id="svg3753"
   version="1.1">

Sorry, kinda complicated for jsFiddle, but here is my map. Give it a go in Chrome and then in Firefox, and you should see what I mean (the boat icon is what is supposed to display). Any help is appreciated!

1

I was unaware that support for SVG fragment identifiers is not so hot, so I found somewhat of a workaround in the form of Base64 encoding (thanks to these doppnet and CSS Tricks posts).

So, after optimizing my SVG in Inkscape I converted it to base64 using Mobilefish's converter (if you use this, make sure to set max characters per line to 0 so you don't have line breaks), and then added them as strings in a JSON array:

var activityURI = [
    {"activity":"All","uri":"oZWlnaH..."},
    {"activity":"Hiking","uri":"4bWxucz..."},
    ...
];

And then accessed them like this:

//for minor extra efficiency, set prefix of URI common to every item in array:
    var uriRoot = "data:image/svg+xml;base64,PD94bWwgdmVy...";

//set full URI using desired index:
    var uriPath = uriRoot + activityURI[//desired index# goes here\\].uri;
    var defPoiStyle = {
        externalGraphic: uriPath
    }

Drawbacks

  1. Long, ugly strings in my code (thank goodness for word wrap).
  2. Bigger JS file.
  3. Tedious to maintain SVG since Base64 converter must be used every time.

Benefits:

  1. It works in Chrome.
  2. No more individual HTTP requests for individual SVG files. EDIT: not true at all! I incorrectly assumed that this method would not trigger an additional HTTP request since it is included within my JS. Back to the drawing board...
  3. Base64 may be comparable in performance to unencoded SVG.

Here is a working result. Any thoughts on how to do this better? All ears.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.