1

After searching for some days I decided to post this question here, hope someone else can give me some hints about a doubt I have. The thing is that I would like to use the Google Bathymetry Service to provide bathymetry/elevation with OpenLayers, ie., as I hover the mouse I would like to have the water depth (negative) or elevation (positive) value close to the longitude, latitude position. I did a simple jsfiddle example showing the longitude/latitude position in OpenLayers, please find it here: http://jsfiddle.net/Gery/LbgzLxg3/13/ (or this one http://jsfiddle.net/Gery/cxf25mkt/2/, but it uses OSM as basemap).

Based on the Google Service, I can get the response as JSON, like here:

http://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&sensor=true_or_false

{
   "results" : [
      {
         "elevation" : 1608.637939453125,
         "location" : {
            "lat" : 39.7391536,
            "lng" : -104.9847034
         },
         "resolution" : 4.771975994110107
      }
   ],
   "status" : "OK"
}

Any ideas how to implement this? is it possible using OL and Google Hybrid as basemap?

Any hints are welcomed,

  • If you do it on mousehover, it would send just too many requests. You should possibly send the request on Mouse down. – Devdatta Tengshe May 8 '15 at 17:23
  • Thanks for the reply, that's a nice idea, but long/lat values are also many requests, so what would be the problem of using the same for elevation/water depth values? I am wondering if the OL code itself handles better that amount of long/lat requests. – Gery May 8 '15 at 17:36
  • 1
    I don't understand what you mean by 'long/lat values are also many requests' Please note that the mouse move event can be called many times per second, and soon you'll reach the 2500 request per day limit with your approach. secondly, it will take some time for the request to come back, and by that time, your mouse will have moved somewhere else. – Devdatta Tengshe May 8 '15 at 18:01
  • 1
    I was trying to combine the elevation API along with an OL map, and was running into Cross-origin issues. After investigation, I realised that Google Allows the use of the API only along with an Google Map, where you need to use their JS API. I won't say that what you want is impossible, just that it is against the ToS of Google Maps, – Devdatta Tengshe May 9 '15 at 13:44
  • 1
    getting the lat lon is not considered many requests since its been calculated in most cases client sided. But elevation is not something that can be "Calculated" so you need to do a request to the api. – elasticrash May 11 '15 at 12:36
2
+100

This probably isn't the type of answer that you are looking for, but I'll try to give a general answer on how one could do this.

If we break down your problem into smaller tasks, then the first thing that you need to do, is to get the point that the user clicks on. There is an sample on the OpenLayers site that shows exactly how to get this done. Click Event Example. This sample will show you how to get the coordinates that the user has clicked on

Now the second challenge, is to convert the coordinates from Web Mercator to Geographic Lat-long. This is easily done by using the transform function on the geometry

Now comes the actual querying of the API by sending the lat-long to it. This could be done by a simple Ajax request, like this:

$.ajax({
  url: "http://maps.googleapis.com/maps/api/elevation/json",
  type: 'GET',
  data:data,
  crossDomain: true,
  dataType: 'json',
  success: function() {
        //Function to show height

   },
  error: function() { alert('Failed!'); }
});

There are two challenges here:

  • Firstly According to Google's ToS,

The Elevation API may only be used in conjunction with displaying results on a Google map; using elevation data without displaying a map for which elevation data was requested is prohibited

This can easily be solved by using a Google Maps Layer in this OpenLayer's map

  • The second challenge is that when you send a request to the Elevation API, it is a different domain, and hence JavaScript does not allow you to make the request. This API does not support JSONP, nor CORS. Hence the only way around this, is to have a Proxy script on your server, which will make the request to the Elevation API endpoint

And finally, you need to show the elevation in the API on the map. This can be done by placing an DIV, and writing to it from Javascript.

All of this is contained in the following code: (I can't use JSfiddle, since it does not have a proxy)

HTML/JS/CSS Code:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
    <title>Simple Map</title>
     <script type="text/javascript" src="OpenLayers/OpenLayers.js" /></script>
     <script type="text/javascript" src="jquery.js" /></script>
     <script src="http://maps.google.com/maps/api/js?v=3&amp;sensor=false"></script>

    <style>
      #map {
        height: 600px;
        width: 900px;
        margin: 0;
        padding: 0;
        position:   relative; 
      }
      body {
        background-color: #FFF;
        overflow: hidden;
        font-family: "Trebuchet MS";
      }

      .olControlMousePosition{
              right:70px !important;
      }
      #height_pos{
         position: absolute;
    bottom: 0;
    right: 2px;
    z-index: 999;
    height: 15px;
    width:  65px;
      font-family: Arial;
   font-size: smaller;
        }
    </style>

    <script>

      OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
      defaultHandlerOptions : {
        'single' : true,
        'double' : false,
        'pixelTolerance' : 0,
        'stopSingle' : false,
        'stopDouble' : false
      },

      initialize : function (options) {
        this.handlerOptions = OpenLayers.Util.extend({}, this.defaultHandlerOptions);
        OpenLayers.Control.prototype.initialize.apply(
          this, arguments);
        this.handler = new OpenLayers.Handler.Click(
            this, {
            'click' : this.trigger
          }, this.handlerOptions);
      },

      trigger : function (e) {
        var lonlat = map.getLonLatFromPixel(e.xy).transform(new OpenLayers.Projection('EPSG:3857'), new OpenLayers.Projection('EPSG:4326'));

        //need to build query URL
        var realurl = "http://maps.googleapis.com/maps/api/elevation/json?sensor=true&locations=" + lonlat.lat + "," + lonlat.lon;
        $.ajax({
          url : "http://localhost/proxy.php?url=" + encodeURIComponent(realurl),
          type : 'GET',
          crossDomain : true,
          dataType : 'json',
          success : function (result) {
            showHeight(result);
          },
          error : function () {
            alert('Failed!');
          }
        });

      }

    });

  function showHeight(result) {
    var ht = "";
    if (result.status == "OK") {
      var ele = result.results[0].elevation;
      if (!isNaN(ele)) {
        ht = ", " + String(ele.toFixed(1));
      }
    }
    //now write this
    $('#height_pos').html(ht);
  }

  function init() {
    var mapOptions = {
      div : "map"
    };

    map = new OpenLayers.Map('map', mapOptions);
    map.addLayer(new OpenLayers.Layer.OSM());
    map.addLayers([
        new OpenLayers.Layer.Google(
          "Google Physical", {
          type : google.maps.MapTypeId.TERRAIN
        }),
        new OpenLayers.Layer.Google(
          "Google Streets", // the default
        {
          numZoomLevels : 20
        })
      ]);
    map.addControl(new OpenLayers.Control.LayerSwitcher());
    var mp = new OpenLayers.Control.MousePosition({
        displayProjection : "EPSG:4326"
      });
    map.addControl(mp);
    map.setCenter(new OpenLayers.LonLat(0, 0), 2);

    var click = new OpenLayers.Control.Click();
    map.addControl(click);
    click.activate();
  }

    </script>

  </head>

 <body onload="init()">
    <div id="map">
      <div id="height_pos"></div>
    </div>
  </body>
</html>

Proxy:

<?php
 $ch = curl_init($_GET['url']);
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 $output = curl_exec($ch);
 curl_close($ch);
 echo $output;
?>
  • Has someone ever told you that you are a total genius? thanks! it woks nicely (y) – Gery May 16 '15 at 4:02
  • 1
    @Gery: Glad to help you out – Devdatta Tengshe May 16 '15 at 5:13
  • Hi DevdattaTengshe, just a small question, in case I stop using div map to plot my map, and start using the whole window browser (ie. with Ext.Viewport), how could I send the #height_pos to the map? I tried CSS solutions, eg. position: fixed, but without success so far. – Gery Jun 7 '15 at 0:35
  • @Gery sorry i don't know much about the framework that you are using. – Devdatta Tengshe Jun 7 '15 at 11:56
  • it was simpler than I thought, the good document.getElementById() did the trick: $(document.getElementById('height_pos')).html(ht);, thanks! – Gery Jun 7 '15 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.