[GIS] OpenLayers 3: Zoom and center at map startup

coordinatesgeolocationopenlayers

I have a simple map setup and I've been reading the documentation to find out how to set the center and zoom at the current geo location. I initialize my map's view to center at [0, 0] with zoom of 2, but I don't know which event to hook up the following code to center and zoom:

var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ?
    new ol.geom.Point(coordinates) : null);
map.setView(new ol.View({
  center: geolocation.getPosition(),
  zoom: 15

I tried many on and once events for my Map and GeoLocation objects, but it seems that the location has yet to be properly set before these events are fired. Or they continually fire which calls the zoom and center functionality constantly.

The map works perfectly as is minus this issue. Is there an event that will fire after the entire map is loaded including the geo location?

I've added the code below for more clarity:

<html>
  <head>
    <title>Accessible Map</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v4.2.0/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v4.2.0/build/ol.js"></script>
    <style>
      a.skiplink {
        position: absolute;
        clip: rect(1px, 1px, 1px, 1px);
        padding: 0;
        border: 0;
        height: 1px;
        width: 1px;
        overflow: hidden;
      }
      a.skiplink:focus {
        clip: auto;
        height: auto;
        width: auto;
        background-color: #fff;
        padding: 0.3em;
      }
      #map:focus {
        outline: #4A74A8 solid 0.15em;
      }
    </style>
  </head>
  <body>
    <a class="skiplink" href="#map">Go to map</a>
    <div id="map" class="map" tabindex="0"></div>
    <script>
      // Heatmap data
      var vector = new ol.layer.Heatmap({
        source: new ol.source.Vector({
          url: 'https://openlayers.org/en/v4.2.0/examples/data/kml/2012_Earthquakes_Mag5.kml',
          format: new ol.format.KML({
            extractStyles: false
          })
        }),
        blur: parseInt(15, 10),
        radius: parseInt(5, 10)
      });

      vector.getSource().on('addfeature', function(event) {
        // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a
        // standards-violating <magnitude> tag in each Placemark.  We extract it from
        // the Placemark's name instead.
        var name = event.feature.get('name');
        var magnitude = parseFloat(name.substr(2));
        event.feature.set('weight', magnitude - 5);
      });


      // Map
      var map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          }),
          vector
        ],
        target: 'map',
        controls: ol.control.defaults({
          attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
            collapsible: false
          })
        }),
        view: new ol.View({
          center: [0, 0],
          zoom: 2
        })
      });

      // Begin geolocation
      var geolocation = new ol.Geolocation({
        projection: map.getView().getProjection(),
        tracking: true,
        trackingOptions: {
          enableHighAccuracy: true,
          maximumAge: 2000
        }
      });

      // handle geolocation error.
      geolocation.on('error', function(error) {
        var info = document.getElementById('info');
        info.innerHTML = error.message;
        info.style.display = '';
      });

      // When the coordinates update
      geolocation.on("change:position", function() {
        var coordinates = geolocation.getPosition();
        positionFeature.setGeometry(coordinates ?
            new ol.geom.Point(coordinates) : null);
      });

      // Detail the accuracy of the location
      var accuracyFeature = new ol.Feature();
      geolocation.on('change:accuracyGeometry', function() {
        accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
      });

      // Style of the location icon
      var positionFeature = new ol.Feature();
      positionFeature.setStyle(new ol.style.Style({
        image: new ol.style.Circle({
          radius: 6,
          fill: new ol.style.Fill({
            color: '#3399CC'
          }),
          stroke: new ol.style.Stroke({
            color: '#fff',
            width: 2
          })
        })
      }));

      // Layout map
      new ol.layer.Vector({
        map: map,
        source: new ol.source.Vector({
          features: [accuracyFeature, positionFeature]
        })
      });

      // After rendering the map, center and zoom user's location
      map.once("change", function(){
        var coordinates = geolocation.getPosition();
        positionFeature.setGeometry(coordinates ?
            new ol.geom.Point(coordinates) : null);
        map.setView(new ol.View({
          center: geolocation.getPosition(),
          zoom: 15
        }));
      });
    </script>
  </body>
</html>

Best Answer

From this discussion, it seems there is no event when the map is "ready" (at least for openlayers3).

A solution is to add a map.setView() function to your geolocalisation layer:

  // Layout map
  var layer = new ol.layer.Vector({
    map: map,
    source: new ol.source.Vector({
      features: [accuracyFeature, positionFeature]
    })
  });

  layer.once("change", function(){
    map.setView(new ol.View({
      center: geolocation.getPosition(),
      zoom: 15
    }));
  });
Related Question