Search code examples
javascriptopenlayersopenlayers-6

SVG Icon is not visible in OpenLayers, while the other SVG is working correctly


I have an issue with displaying SVG image as icon in OL6. I've seen all similar issues here but it wasn't helpful. Here's the code of working icon image:

const workingIconFeature = new ol.Feature({
  geometry: new ol.geom.Point([0, 0])
});

const workingSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="91.19" style="fill: #fff"> <g> <g> <path d="M15,0A49,49,0,0,0,0,35L.2,70H29.8L30,35A49,49,0,0,0,15,0Z"/> <rect y="71.19" width="30" height="20"/> </g> </g> </svg>`;

const workingStyle = new ol.style.Style({
  image: new ol.style.Icon({
    opacity: 1,
    src: 'data:image/svg+xml;utf8,' + workingSvg,
    scale: 0.3
  })
});

workingIconFeature.setStyle(workingStyle);

Here's the icon that I can't display:

const notWorkingIconFeature = new ol.Feature({
  geometry: new ol.geom.Point([20, 20])
});

const notWorkingSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="45" height="110" viewBox="0 0 40 102">
          <defs>
              <style>
                  .a{fill:none;stroke:#fff;stroke-miterlimit:10;stroke-width:2px;}.a,.b{opacity:0.7;}.b{fill:#fff;}.c{fill:#031120;}
              </style>
          </defs>
          <line class="a" x1="20" y1="12" x2="20" y2="62" />
          <circle class="b" cx="20" cy="6" r="6" />
          <circle class="c" cx="20" cy="6" r="5" />
          <circle class="b" cx="20" cy="82" r="20" />
          <circle class="c" cx="20" cy="82" r="15" />
      </svg>`;

const notWorkingStyle = new ol.style.Style({
  image: new ol.style.Icon({
    opacity: 1,
    src: 'data:image/svg+xml;utf8,' + notWorkingSvg,
    scale: 0.3
  })
});

workingIconFeature.setStyle(notWorkingStyle);

http://jsfiddle.net/8afskcL2/2/

As you can see width and height attributes were added to not working but still with no effect. Maybe you know what can be an issue?


Solution

  • Your "working" style isn't working for me either (I see the default styled icon). You need to URL encode the svg. You can use escape.

    working example with SVG icon

    const workingStyle = new ol.style.Style({
      image: new ol.style.Icon({
        opacity: 1,
        src: 'data:image/svg+xml;utf8,' + escape(workingSvg),
        scale: 0.3
      })
    });
    
    const notWorkingStyle = new ol.style.Style({
      image: new ol.style.Icon({
        opacity: 1,
        src: 'data:image/svg+xml;utf8,' + escape(notWorkingSvg),
        scale: 0.3
      })
    });
    

    proof of concept fiddle

    screenshot of map

    code snippet:

    const workingIconFeature = new ol.Feature({
      geometry: new ol.geom.Point([-1000, -1000])
    });
    
    const workingSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="91.19" style="fill: #0f0"> <g> <g> <path d="M15,0A49,49,0,0,0,0,35L.2,70H29.8L30,35A49,49,0,0,0,15,0Z"/> <rect y="71.19" width="30" height="20"/> </g> </g> </svg>`;
    
    const workingStyle = new ol.style.Style({
      image: new ol.style.Icon({
        opacity: 1,
        src: 'data:image/svg+xml;utf8,' + escape(workingSvg),
        scale: 0.3
      })
    });
    
    workingIconFeature.setStyle(workingStyle);
    
    const notWorkingIconFeature = new ol.Feature({
      geometry: new ol.geom.Point([1000, 1000])
    });
    
    const notWorkingSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="45" height="110" viewBox="0 0 40 102">
              <defs>
                  <style>
                      .a{fill:none;stroke:#f00;stroke-miterlimit:10;stroke-width:2px;}.a,.b{opacity:0.7;}.b{fill:#f00;}.c{fill:#031120;}
                  </style>
              </defs>
              <line class="a" x1="20" y1="12" x2="20" y2="62" />
              <circle class="b" cx="20" cy="6" r="6" />
              <circle class="c" cx="20" cy="6" r="5" />
              <circle class="b" cx="20" cy="82" r="20" />
              <circle class="c" cx="20" cy="82" r="15" />
          </svg>`;
    
    const notWorkingStyle = new ol.style.Style({
      image: new ol.style.Icon({
        opacity: 1,
        src: 'data:image/svg+xml;utf8,' + escape(notWorkingSvg),
        scale: 0.3
      })
    });
    
    notWorkingIconFeature.setStyle(notWorkingStyle);
    
    const vectorSource = new ol.source.Vector({
      features: [workingIconFeature, notWorkingIconFeature]
    });
    
    const vectorLayer = new ol.layer.Vector({
      source: vectorSource
    });
    
    const rasterLayer = new ol.layer.Tile({
      source: new ol.source.OSM()
    });
    
    const map = new ol.Map({
      layers: [rasterLayer, vectorLayer],
      target: document.getElementById('map'),
      view: new ol.View({
        center: [0, 0],
        zoom: 12
      })
    });
    html,
    body {
      height: 100%;
      width: 100%;
      padding: 0px;
      margin: 0px;
    }
    
    .map {
      height: 100%;
      width: 100%;
    }
    <html lang="en">
    
    <head>
      <link rel="stylesheet" href="https://openlayers.org/en/v6.4.2/css/ol.css" type="text/css">
      <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.2/build/ol.js"></script>
      <title>OpenLayers example</title>
    </head>
    
    <body>
      <div id="map" class="map"></div>
    </body>
    
    </html>