简体   繁体   中英

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

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

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>'
  })
});

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 .

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 .

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.

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>';

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM