Search code examples
javascriptopenlayersopenlayers-7

How to tell if a point is visible on current OpenLayers map


Hi I'm trying to figure out if a given point is currently visible on my map. I'm using open layers 7 and have a simple map with a marker on it. User can move both the map and the marker independently. Every time the either the map or the marker are moved there as an output updated that shows the lon/lat of both the center of the map and the marker position. I would also like to output whether or not the marker is actually on the currently visible map.

I'm not sure how to go about doing this although i suspect its about capturing the boundaries of the mapview somehow.

Here's the code I have so far and a link to the JSFiddle.

var london = [-0.1276474, 51.507321899999994];
var isOnMap = true;  

document.getElementById('marker').innerHTML = london[0].toFixed(5) + ", " + london[1].toFixed(5);
document.getElementById('center').innerHTML = london[0].toFixed(5) + ", " + london[1].toFixed(5);
    const baseMapTile = new ol.layer.Tile({
            source: new ol.source.OSM(),
            visible: true,
            title: 'OSMStandard'
    });
    
    
    const marker = new ol.Feature({
        geometry: new ol.geom.Point(ol.proj.fromLonLat(london)),
        name: 'Somewhere near Nottingham',
    });
    
    
    const map = new ol.Map({
    view: new ol.View({
            
      center: (ol.proj.fromLonLat(london)),
      zoom: 15,
    }),
        layers: [
            baseMapTile,
            new ol.layer.Vector({
                source: new ol.source.Vector({
                    features: [marker]
                }),
                style: new ol.style.Style({
                    image: new ol.style.Icon({
                        anchor: [0.5, 46],
                        anchorXUnits: 'fraction',
                        anchorYUnits: 'pixels',
                        src: 'https://openlayers.org/en/latest/examples/data/icon.png'
                    })
                })
            })
        ],
    target: 'map'
    
  });

var translate = new ol.interaction.Translate({
    features: new ol.Collection([marker])
});

map.addInteraction(translate);

translate.on('translating', function (evt) {
        var lonlat = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
                document.getElementById("marker").innerHTML = lonlat[0].toFixed(5) + ", " + lonlat[1].toFixed(5);               
                
                //check here to see if marker is still visible on map and update output
                
});

map.getView().on(['change:center', 'change:resolution', 'change:rotation'], function() {
    var center = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
                
            document.getElementById("center").innerHTML = center[0].toFixed(5) + ", " + center[1].toFixed(5);
            //check here to see if marker is still visible on map and update output
});
#map {
  width: 300px;
  height: 300px;
  border: 1px solid black;
  padding: 5px;
  float: left;
}

#info {
  width: calc(100% - 330px);
  margin-left: 5px;
  padding: 5px;
  height: 100px;
  border: 1px solid black;
  float: left;
}

.info h2 {
  font-size: small;
  text-decoration: underline;
  font-weight: 600;
  margin: 0 0 10px 0;
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>

<div id="map" class="map"></div>
<div id="info" class="info">
  <h2>Map Info Output</h2>
  Center: <span id=center></span><br> Marker: <span id=marker></span><br>
  <span id=update>*update if the marker is on the map or not here.</span>
</div>

Any help is always appreciated. Thanks.


Solution

  • If you need to handle rotation of the map you can create a polygon from the corners of the map and check if that intersects the coordinate of the marker

    function checkVisible() {
        const size = map.getSize();
        const tl = map.getCoordinateFromPixel([0, 0]);
        const tr = map.getCoordinateFromPixel([size[0], 0]);
        const bl = map.getCoordinateFromPixel([0, size[1]]);
        const br = map.getCoordinateFromPixel(size);
        const polygon = new ol.geom.Polygon([[tl, tr, br, bl, tl]]);
        if (polygon.intersectsCoordinate(marker.getGeometry().getCoordinates())) {
            document.getElementById('update').innerHTML = 'Marker on map';
        } else {
            document.getElementById('update').innerHTML = 'Marker not on map';
        }
    }
    

    Without rotation you could simply use the view extent

    ol.extent.containsCoordinate(
       map.getView().calculateExtent(),
       marker.getGeometry().getCoordinates()
    )
    

    var london = [-0.1276474, 51.507321899999994];
    var isOnMap = true;  
    
    document.getElementById('marker').innerHTML = london[0].toFixed(5) + ", " + london[1].toFixed(5);
    document.getElementById('center').innerHTML = london[0].toFixed(5) + ", " + london[1].toFixed(5);
        const baseMapTile = new ol.layer.Tile({
                source: new ol.source.OSM(),
                visible: true,
                title: 'OSMStandard'
        });
        
        
        const marker = new ol.Feature({
            geometry: new ol.geom.Point(ol.proj.fromLonLat(london)),
            name: 'Somewhere near Nottingham',
        });
        
        
        const map = new ol.Map({
        view: new ol.View({
                
          center: (ol.proj.fromLonLat(london)),
          zoom: 15,
        }),
            layers: [
                baseMapTile,
                new ol.layer.Vector({
                    source: new ol.source.Vector({
                        features: [marker]
                    }),
                    style: new ol.style.Style({
                        image: new ol.style.Icon({
                            anchor: [0.5, 46],
                            anchorXUnits: 'fraction',
                            anchorYUnits: 'pixels',
                            src: 'https://openlayers.org/en/latest/examples/data/icon.png'
                        })
                    })
                })
            ],
        target: 'map'
        
      });
    
    var translate = new ol.interaction.Translate({
        features: new ol.Collection([marker])
    });
    
    map.addInteraction(translate);
    
    function checkVisible() {
        const size = map.getSize();
        const tl = map.getCoordinateFromPixel([0, 0]);
        const tr = map.getCoordinateFromPixel([size[0], 0]);
        const bl = map.getCoordinateFromPixel([0, size[1]]);
        const br = map.getCoordinateFromPixel(size);
        const polygon = new ol.geom.Polygon([[tl, tr, br, bl, tl]]);
        if (polygon.intersectsCoordinate(marker.getGeometry().getCoordinates())) {
            document.getElementById('update').innerHTML = 'Marker on map';
        } else {
            document.getElementById('update').innerHTML = 'Marker not on map';
        }
    }
    
    translate.on('translating', function (evt) {
            var lonlat = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
                    document.getElementById("marker").innerHTML = lonlat[0].toFixed(5) + ", " + lonlat[1].toFixed(5);               
                    
                    //check here to see if marker is still visible on map and update output
                    checkVisible();
                    
    });
    
    map.getView().on(['change:center', 'change:resolution', 'change:rotation'], function() {
        var center = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
                    
                document.getElementById("center").innerHTML = center[0].toFixed(5) + ", " + center[1].toFixed(5);
                //check here to see if marker is still visible on map and update output
                checkVisible();
    });
    
    map.once('rendercomplete', checkVisible);
    map.on('change:size', checkVisible);
    #map {
      width: 300px;
      height: 300px;
      border: 1px solid black;
      padding: 5px;
      float: left;
    }
    
    #info {
      width: calc(100% - 330px);
      margin-left: 5px;
      padding: 5px;
      height: 100px;
      border: 1px solid black;
      float: left;
    }
    
    .info h2 {
      font-size: small;
      text-decoration: underline;
      font-weight: 600;
      margin: 0 0 10px 0;
    }
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
    
    <div id="map" class="map"></div>
    <div id="info" class="info">
      <h2>Map Info Output</h2>
      Center: <span id=center></span><br> Marker: <span id=marker></span><br>
      <span id=update>*update if the marker is on the map or not here.</span>
    </div>