Search code examples
javascriptopenstreetmapopenlayers-3

OL3 - Trouble detecting clicks on features


My aim is to create a map for my work in OpenLayers 3 with several layers. One takes a basic feed from OpenStreetMaps. Another will be a transparent layer showing outlines of regions (not done yet). The third one, which is the one I'm having trouble with, shows a series of icons representing indivudal sites of interest on the map. I load the sites from a JS data stucture included as a separate script file. I have managed to get my code to add features that appear at the correct lat/lon. My next step is to get a HTML box (div) to appear in front of the map when they click on an icon (to display details of the site). However, I cannot get this to work. Apologies for my noobish coding, but it's really got me stumped and I'd really appreciate any help.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="ol.css" type="text/css">
    <link rel="stylesheet" href="map.css" type="text/css">
    <script src="ol.js" type="text/javascript"></script>
    <script src="sites.js" type="text/javascript"></script>
<script type="text/javascript">


function buildLayerFromSites(allSites)
// allSites is just an array of data structures
{
  var count, site;
  // for each site in the array, make a feature
  for (count=0;count<allSites.length;count++)
  {
    geom = new ol.geom.Point(ol.proj.fromLonLat([allSites[count].longitude,allSites[count].latitude]));
    site = new ol.Feature(geom);
    site.Name = allSites[count].siteName; // <-- can I assign further details in the structure like this?


    var siteStyle = new ol.style.Style({
      image: new ol.style.Icon ({
        src: 'icon-blue.png',
        scale: 0.1,
        opacity: 0.9,
        })
      })
    site.setStyle(siteStyle);
    siteFeatures[count] = site;
  }
  siteSource = new ol.source.Vector ({
    features: siteFeatures
  })
  siteLayer = new ol.layer.Vector({
    source: siteSource
  });
  map.addLayer(siteLayer);
}

</script>
    <title>Map</title>
  </head><body>
...
<div id="map" class="map">
...

<script type="text/javascript">


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([115.51, -31.57]),
    zoom: 8
  })
});
buildLayerFromSites(includeSites);  // adds the second layer with the sites


// click event handler, basically same as http://openlayers.org/en/v3.12.1/examples/icon.html
map.on('click', function(evt) {
  var feature = map.forEachFeatureAtPixel(evt.pixel,
    function(feature,layer) {
      return feature;
    });
  if (feature) {
    console.log("feature got clicked on"); // do stuff
  } else {
    console.log("didn't click a feature");
  }
});
</script>
</body>
</html>

The map and the icons load, but when I click the icons, no matter how zoomed in or out I am, it doesn't detect a match with the icon I'm clicking on. The thing is, the event handler code is the same as in the official example, which make me think it's the way I'm creating the features. On the other hand, the features display fine as icons, its just the click event that doesn't seem to work. Similar weird stuff happens for the mouse cursor change from the example. I sorta guess it's because I don't understand the way the data/functions are structured in OL, and I find the documentation doesn't fully explain how it all works, so I've been writing snippets like this trying to take a look:

var myLayers = map.getLayers();
console.log("keys - " + myLayers.getKeys);  // prints out 'function (){return Object.keys(this.B)}' - what does that mean?
var mySource = myLayers.getSource;
console.log("source" + mySource.getProjection); // doesn't work
var features = mySource.getFeatures;  // says mySource is undefined

Of course it fails totally.

How do I get it to detect the clicks on the icons/features so I can tell a div to appear and display my data at the right time? Am I doing this right? What don't I understand about the way the data/functions work? I'm a big JS noob so I hope I'm not doing something stupid, but it's causing me massive problems and I could really use your help! Thanks all!


Solution

  • After long hours staring at my screen and hitting my head on my desk, I've stumbled across the solution to my problem. It's a little obscure but mind-numbingly simple/stupid/silly. I thought I'd post the solution here for others.

    I wrote a couple of lines of code to resize the viewport when the page is loading and again when the window is resized, so the map would adjust to the available user's browser window space. Unfortunately, as far as I can work out, OL doesn't know about it so the icons and the features are no longer in the same place after the resize. I didn't know this though, until after countless hours I was randomly clicking and resizing it detected a feature click.

    Luckily there is an easy way to solve it once you figure out this is the problem. Basically just add map.updateSize() to the part of your code that resizes the viewport. So far this seems to have solved the problem.