Search code examples
javascriptopenlayers

Open layers tracker doesn't update


I'm building a simple ISS tracker with coordinates from the API using Open layers. The map and the point renders correctly, but I can't update the position of the point on the map without refreshing the page. I paste the code below.

import "ol/ol.css"
import Feature from "ol/Feature"
import Map from "ol/Map"
import Point from "ol/geom/Point"
import View from "ol/View"
import { Circle, Fill, Style } from "ol/style"
import { OSM, Vector as VectorSource } from "ol/source"
import { Tile, Vector } from "ol/layer"
import { fromLonLat } from "ol/proj"


const getISSPosition = () => {
    fetch("https://api.wheretheiss.at/v1/satellites/25544")
        .then(res => res.json())
        .then(data => {
            const ISSPosition = [data.longitude, data.latitude]
            const ISSPositionMercator = fromLonLat(ISSPosition)

            const map = new Map({
                layers: [
                    new Tile({
                        source: new OSM()
                    })
                ],
                target: "map",
                view: new View({
                    center: [ISSPositionMercator[0], ISSPositionMercator[1]],
                    zoom: 2
                })
            })

            const positionFeature = new Feature()

            positionFeature.setStyle(
                new Style({
                    image: new Circle({
                        radius: 4,
                        fill: new Fill({
                            color: "red"
                        })
                    })
                })
            )

            positionFeature.setGeometry(new Point(ISSPositionMercator))

            new Vector({
                map: map,
                source: new VectorSource({
                    features: [positionFeature]
                })
            })
        })
}

getISSPosition()

Solution

  • Separate the call to the service from the construction of the map. Construct the map once, then update the position of the marker periodically by calling the service with setInterval.

    Create map:

    const map = new ol.Map({
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM()
        })
      ],
      target: "map",
      view: new ol.View({
        center: [0, 0],
        zoom: 2
      })
    })
    
    positionFeature.setStyle(
      new ol.style.Style({
        image: new ol.style.Circle({
          radius: 4,
          fill: new ol.style.Fill({
            color: "red"
          })
        })
      })
    )
    
    new ol.layer.Vector({
      map: map,
      source: new ol.source.Vector({ // VectorSource({
        features: [positionFeature]
      })
    });
    

    update marker:

    const updateISSPosition = () => {
      fetch("https://api.wheretheiss.at/v1/satellites/25544")
        .then(res => res.json())
        .then(data => {
          const ISSPosition = [data.longitude, data.latitude]
          const ISSPositionMercator = ol.proj.fromLonLat(ISSPosition);
          positionFeature.setGeometry(new ol.geom.Point(ISSPositionMercator));
          map.getView().setCenter(ISSPositionMercator);
          console.log(ISSPositionMercator);
        });
    }
    

    proof of concept fiddle

    code snippet:

    const positionFeature = new ol.Feature();
    const updateISSPosition = () => {
      fetch("https://api.wheretheiss.at/v1/satellites/25544")
        .then(res => res.json())
        .then(data => {
          const ISSPosition = [data.longitude, data.latitude]
          const ISSPositionMercator = ol.proj.fromLonLat(ISSPosition);
          positionFeature.setGeometry(new ol.geom.Point(ISSPositionMercator));
          map.getView().setCenter(ISSPositionMercator);
          console.log(ISSPositionMercator);
        });
    }
    
    const map = new ol.Map({
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM()
        })
      ],
      target: "map",
      view: new ol.View({
        center: [0, 0],
        zoom: 2
      })
    })
    
    positionFeature.setStyle(
      new ol.style.Style({
        image: new ol.style.Circle({
          radius: 4,
          fill: new ol.style.Fill({
            color: "red"
          })
        })
      })
    )
    
    new ol.layer.Vector({
      map: map,
      source: new ol.source.Vector({ // VectorSource({
        features: [positionFeature]
      })
    });
    updateISSPosition();
    setInterval(updateISSPosition, 5000);
    html,
    body {
      height: 100%;
      width: 100%;
      padding: 0px;
      margin: 0px;
    }
    
    .map {
      height: 90%;
      width: 100%;
    }
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css">
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v5.3.0/build/ol.js"></script>
    <title>OpenLayers example</title>
    <b>My Map</b>
    <div id="map" class="map"></div>