Search code examples
javascripthtmlthymeleafopenlayersopenstreetmap

OpenLayers Icon does not show up


I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file. I have a Thymeleaf that shows a map with OpenLayers 4 library with an Icon, but the Icon does not show up anywhere in the map

<div id="Map" class="map"></div>
<div id="popup"></div>
<div></div>
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<script th:inline="javascript">
  /*<![CDATA[*/

  var lat = /*[[${lat}]]*/ ;
  var lng = /*[[${lng}]]*/ ;

  var iconFeature = new ol.Feature({
    geometry: new ol.geom.Point([lng, lat]),
    name: 'The icon',
    population: 4000,
    rainfall: 500
  });

  var iconStyle = new ol.style.Style({
    image: new ol.style.Icon( /** @type {olx.style.IconOptions} */ ({
      anchor: [0.5, 46],
      anchorXUnits: 'fraction',
      anchorYUnits: 'pixels',
      src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png'
    }))
  });

  iconFeature.setStyle(iconStyle);

  var vectorSource = new ol.source.Vector({
    features: [iconFeature]
  });

  var vectorLayer = new ol.layer.Vector({
    source: vectorSource
  });

  var rasterLayer = new ol.layer.Tile({
    source: new ol.source.TileJSON({
      url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
      crossOrigin: ''
    })
  });

  var map = new ol.Map({
    layers: [rasterLayer, vectorLayer,
      new ol.layer.Tile({
        source: new ol.source.OSM()
      })
    ],
    target: 'Map',
    controls: ol.control.defaults({
      attributionOptions: {
        collapsible: false
      }
    }),
    view: new ol.View({
      center: ol.proj.fromLonLat([lng, lat]),
      zoom: 14
    })
  });
  /*]]>*/

</script>
</div>

Solution

  • You have a couple of issues:

    1. you haven't projected the coordinates to the correct projection:
    var iconFeature = new ol.Feature({
      geometry: new ol.geom.Point(ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857')),
      name: 'The icon',
      population: 4000,
      rainfall: 500
    });
    
    1. Once I do that the icon appears briefly then disappears unless I change this:
    var map = new ol.Map({
      layers: [rasterLayer, vectorLayer],
      target: 'Map',
      controls: ol.control.defaults({
        attributionOptions: {
          collapsible: false
        }
      }),
      view: new ol.View({
        center: ol.proj.fromLonLat([lng, lat]),
        zoom: 5
      })
    });
    

    proof of concept fiddle

    screenshot of resulting map

    If you don't want the 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure' tiles, change:

    var rasterLayer = new ol.layer.Tile({
      source: new ol.source.TileJSON({
        url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
        crossOrigin: ''
      })
    });
    

    To:

    var rasterLayer = new ol.layer.Tile({
      source: new ol.source.OSM()
    });
    

    proof of concept fiddle

    screenshot of resulting map

    code snippet:

    var lat = 42;
    var lng = -75;
    
    var iconFeature = new ol.Feature({
      geometry: new ol.geom.Point(ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857')),
      name: 'The icon',
      population: 4000,
      rainfall: 500
    });
    
    var iconStyle = new ol.style.Style({
      image: new ol.style.Icon( /** @type {olx.style.IconOptions} */ ({
        anchor: [0.5, 46],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png'
      }))
    });
    
    iconFeature.setStyle(iconStyle);
    
    var vectorSource = new ol.source.Vector({
      features: [iconFeature]
    });
    
    var vectorLayer = new ol.layer.Vector({
      source: vectorSource
    });
    
    var rasterLayer = new ol.layer.Tile({
      source: new ol.source.OSM()
    });
    
    var map = new ol.Map({
      layers: [rasterLayer, vectorLayer],
      target: 'Map',
      controls: ol.control.defaults({
        attributionOptions: {
          collapsible: false
        }
      }),
      view: new ol.View({
        center: ol.proj.fromLonLat([lng, lat]),
        zoom: 5
      })
    });
    html,
    body,
    .map {
      height: 100%;
      width: 100%;
      margin: 0px;
      padding: 0px
    }
    <div id="Map" class="map"></div>
    <div id="popup"></div>
    <script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>