How can I use an SVG image as a map marker in OpenLayers-3?
Asked Answered
F

6

9

I am trying to create map "pin-drops" (ie. map markers) in OpenLayers-3 (OL3) using SVG images.

Currently, I am using PNG images as the pindrops that reference the ol.style.Icon source (“src”) property attribute just fine. However, this fails using an SVG image. Is there some other way to use an SVG in the same manner? Maybe by using a reference besides ol.style.Icon even? There is already a lot of built-in SVG in Open Layers so this should be possible, but I haven't found a way to get this working in OL3. Is there some other way to do this in OL3 that I should consider?

Please note: we already tried using an ol.Vector layer, however when the user zooms in/out, the size of the SVG image grows/shrinks which is an inadequate workaround.


OL3 (fails):

var createMapMarkerImage = function() {
    return function(feature, resolution) {
        var iconStyle = new ol.style.Style({
            image: new ol.style.Icon( ({
                src: 'img/map_pindrop.svg'   // OL3 doesn’t like this, but accepts a .PNG just fine
            }))
        });
        return [iconStyle];
    };
};

Very similar functionality, is the below example I found online, is almost perfect if it weren’t for the fact that the example uses OpenLayers-2 (OL2) functionality which calls openlayers.js library (instead of OL3’s ol.js library). Sadly, swapping these javascript files out fails.


OL2 (works -but is the old OL library):

http://dev.openlayers.org/sandbox/camptocamp/tipi/examples/vector-symbols.html


Searching online for a solution to this seems to produce only other confused people searching for a solution.

Please help,

FreeBeer

Foresight answered 19/3, 2015 at 18:33 Comment(1)
FYI, SVG was a supported renderer in OpenLayers 2, but not in OpenLayers 3. The supported renderers in ol3 are: DOM, Canvas and WebGL.Anastice
M
10

Based on @ahocevar answer, you can use data URIs for SVG:

new ol.style.Style({
  image: new ol.style.Icon({
    anchor: [0, 0],
    src: 'data:image/svg+xml;utf8,<svg>/* SVG DATA */</svg>'
  })
});
Margenemargent answered 12/1, 2016 at 12:14 Comment(1)
Great solution, better than the base64 one as you can even change the raw SVG content easily (change fill and stroke colors). To scale the SVG, it is possible to do it directly via the "scale" (0-1 = 0%-100%) property of the Icon styleChosen
C
5

I had the same issue, but not even serving the image with the proper mime type helped.

It boiled down to the SVG not defining width and height properly.

I added the width and height attributes to the <svg> tag, like:

<svg width="100px" height="100px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0.75 0 30 45" xml:space="preserve">

After that I was able to use my svg just like any other image.

Cynar answered 17/2, 2016 at 13:27 Comment(1)
This worked for me, as long as I remembered to add the 'px' in the width and height values. An hour well spent debugging...Sadden
D
5

Convert the SVG to Base 64 . This (Link) helped me.

copied the base 64 and used it as a string in javascript .

Eg : var svg = "convertedBase64";

Then

var icon = new ol.style.Icon({
        src:'data:image/svg+xml;base64,'+svg ,
        other props
});

And you are done, may be a few Kbs more than SVG but this did work perfect for me .

Dryer answered 29/2, 2016 at 10:25 Comment(0)
M
4

SVG icons work fine as long as the content-type of your SVG image file is image/svg+xml. Also note that no external references are supported inside the SVG. OpenLayers 3 simply uses the drawImage function of the 2d context. You can find more details on the requirements of SVG content here: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas.

Musicianship answered 22/3, 2015 at 19:45 Comment(1)
Does this mean a local filesystem OL3 map cannot use SVG icons? I certainly can't get it to work.Riyadh
S
1

I also had issues to show the icon image, ahocevar answer helped me to solve my problem but I had also to search for the php header, for SVG In case you are or others who see this answer are using php to generate the SVG you have to use header function to identify the content-type

header('Content-type: image/svg+xml'); /* this line will do the magic */
echo '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>';
Sampler answered 25/5, 2015 at 12:50 Comment(0)
G
0

Building upon SoonDead's answer, I had to come up with a way to add the width and height to the svg without touching the source. Using angular, this is sort of what I did:

$http.get('path/to/image.svg').then(function (response) {
  // create element
  var svgEl = angular.element(response.data);

  // set width and height
  svgEl.attr('width', '50px');
  svgEl.attr('height', '50px');

  // base64 encode
  var base64Svg = btoa(unescape(encodeURIComponent(svgEl[0].outerHTML)));

  // create the style
  var style = new ol.style.Style({
    image: new ol.style.Icon({
      src: 'data:image/svg+xml;base64,'+base64Svg,
      imgSize: [50, 50],
      size: [50, 50],
    })
  });

 // apply the style
 feature.setStyle(style);
});

It's a little verbose, but it seems to do the job.

Gridiron answered 24/3, 2016 at 18:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.