Search code examples
javascriptnode.jsnpmgpxopenlayers-5

get trkpt details with openlayers


I'm showing a map with a GPX-track using openlayers 5.3. Trackpoints in OL default to a MultiLineString geometry type. The GPX-example has a gpx-file that is double the size because all <trkpt> tags are duplicated as <rtept> tags. Routepoints get a Point geometry type in OL.

Now I'd like to add a layer showing the trkpt's as a Point type and to create popups showing the values of the <ele> and <time> tags inside the <trkpt> tags in my "regular" gpx-file.

Is there a quick and/or dirty solution to convince OL to treat my trackpoints as routepoints so I can use them as a Point-type and read the <ele> and <time> features from the source? Or is some other operation required to accomplish this, and if so, what would be my options?

Any help much appreciated!


Solution

  • You can create points from the coordinates in the linestrings

    var map = new ol.Map({
        target: "map",
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          })
        ],
        view: new ol.View({
          center: ol.proj.fromLonLat([1.3313627, 52.1062152]),
          zoom: 15
        })
      });
    
      var displayFeatureInfo = function(pixel) {
        var features = [];
        map.forEachFeatureAtPixel(pixel, function(feature) {
          features.push(feature);
        }, {
          layerFilter: function(candidate) { return candidate === gpxPointLayer; }
        });
        if (features.length > 0) {
          var info = [];
          var i, ii;
          for (i = 0, ii = features.length; i < ii; ++i) {
            // display lat, lon, ele and time from the point coordinates
            var coordinates = features[i].getGeometry().getCoordinates();
            var ll = ol.proj.toLonLat(coordinates.slice(0,2));
            var d = new Date();
            d.setTime(coordinates[3]*1000);
            var llet = ll[1].toFixed(7) + ', ' + ll[0].toFixed(7) + ', ' + coordinates[2] + 'm, ' + d.toUTCString();
            info.push(llet);
          }
          document.getElementById('info').innerHTML = info.join('<br>') || '(unknown)';
          map.getTargetElement().style.cursor = 'pointer';
        } else {
          document.getElementById('info').innerHTML = '&nbsp;';
          map.getTargetElement().style.cursor = '';
        }
      };
    
      var gpxPointLayer = new ol.layer.Vector({
        source: new ol.source.Vector(),
        style: new ol.style.Style({
          image: new ol.style.Circle({
            fill: new ol.style.Fill({color: 'red'}),
            radius: 4
          })
        })
      });
    
      gpxTrackVector = new ol.source.Vector({
        url: 'https://www.mikenunn.net/data/melton2bawdsey.gpx',
        format: new ol.format.GPX()
      });
    
      function addPoints(linestring) {
        linestring.getCoordinates().forEach(function(coordinates) {
          gpxPointLayer.getSource().addFeature(new ol.Feature(new ol.geom.Point(coordinates)));
        });
      }
    
      gpxTrackVector.on('addfeature', function(evt){
        // create point features from GPX linestring coordinates
        if (evt.feature.getGeometry().getType() == 'LineString') {
          addPoints(evt.feature.getGeometry());
        } else if (evt.feature.getGeometry().getType() == 'MultiLineString') {
          evt.feature.getGeometry().getLineStrings().forEach(function(linestring){
            addPoints(linestring);
          });
        }
      });
    
      var gpxTrackLayer = new ol.layer.Vector({
        source: gpxTrackVector,
        style: new ol.style.Style({
          stroke: new ol.style.Stroke({
            color: 'black',
             width: 4
          }),
          image: new ol.style.Circle({
            fill: new ol.style.Fill({color: 'green'}),
            radius: 6
          })
    
        })
      });
    
      map.addLayer(gpxTrackLayer);
      map.addLayer(gpxPointLayer);
    
      map.on('pointermove', function(evt) {
        if (evt.dragging) {
          return;
        }
        var pixel = map.getEventPixel(evt.originalEvent);
        displayFeatureInfo(pixel);
      });
    html, body {
        width: 100%;
        height: 100%;
    }
    .map {
        width: 100%;
        height: 80%;
    }
    <link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <div id="map" class="map"></div>
    <div id="info">&nbsp;</div>