<x-discover> - Geo Location based custom Polymer element

After creating the <x-flickr> Polymer element here's my latest creation - strictly work in progress - but I'd like to share the details of it because I find it exciting.

It is an extension of Eric Bidelman's geo-location with quite a lot of extra added features.

So what does this element do exactly? It gets the latitude & longitude pair using the nagivator.geolocation property and based on that it does a geo lookup to determine the location of the user - this includes a query to the Yahoo Geo API. But the fun does not stop here. Again, based on the latitude & longitude pair another query is made, this time to the FourSquare API to collect the top 10 attractions around the location - henceforth the 'x-discover' name for the element.

I am still working on some features but I am also leveraging the nagivator.geolocation.watchPosition() function so the location and list of attractions are automatically updated when the user is travelling. But of course querying two, 3rd party APIs, on every latitude or longitude change would be quite expensive so I have implemented the haversine formula to monitor the distance between the latitude & longitude point at startup and the user's current latitude & longitude point. At the moment the user needs to travel 100 units (an angular distance between the two points) to trigger updates.

<polymer-jsonp id="location" on-polymer-response="{{getLocationName}}" url="http://query.yahooapis.com/v1/public/yql?q=select%20neighborhood,city,countrycode%20from%20geo.placefinder%20where%20text%3D%22{{latitude}}%2C{{longitude}}%22%20and%20gflags%3D%22R%22&format=json&callback="></polymer-jsonp>
<core-ajax id="poi" handleAs="json" on-core-response="{{getpoi}}" url="https://api.foursquare.com/v2/venues/explore?client_id={{clientid}}&client_secret={{clientsecret}}&v=20130815&ll={{latitude}},{{longitude}}&query=outdoor&limit=10&venuePhotos=1"></core-ajax>
onPosition: function(pos) { //gets current position
    var radius = 6371; // Earth's radius in km
    if (init) {
        this.latitude = pos.coords.latitude;
        this.longitude = pos.coords.longitude;
        this.$.location.go();
        init = false;
    }
    if (distance > 100) { //limit the querying
        this.latitude = pos.coords.latitude;
        this.longitude = pos.coords.longitude;
        this.$.location.go();
    }
    //calculate the distance using the haversine formula
    var actualLatitude = pos.coords.latitude,//now
        storedLatitude = this.latitude, //stored
        actualLongitude = pos.coords.longitude, //now
        storedLongitude = this.longitude, //stored
        deltaLatitude = storedLatitude - actualLatitude, //distance between lats
        deltaLongitude = storedLongitude - actualLongitude, //distance between longs
        a = Math.sin(deltaLatitude/2) * Math.sin(deltaLatitude / 2) + Math.cos(actualLatitude) * Math.cos(storedLatitude) * Math.sin(deltaLongitude/2) * Math.sin(deltaLongitude/2),
        c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); //final formula

    distance = radius * c; //distance between two points
    distance = Number(distance.toFixed(0)); //distance trick with toFixed();
}

Another throttling method that I have implemented is a comparision between the neighbourhood value returned by the Yahoo Geo API. If, between two queries that have not changed, the application does not make another query to FourSquare's API.

getLocationName: function(e, r) { //gets city and countrycode
    if (this.neighborhood !== r.response.query.results.Result.neighborhood) { //only collect POI when neighborhood changes
        this.$.poi.go();
    }
    this.neighborhood = r.response.query.results.Result.neighborhood;
    this.city = r.response.query.results.Result.city;
    this.country = r.response.query.results.Result.countrycode;
    this.location = 'You are around: ' + this.neighborhood + ' - ' + this.city + ', ' + this.country;
},

Here's a teaser screencap - please note that I'm still working on the actual <template> portion of the element - not much has been done so far as you can see.

I would like to extend the features of this element with some cool features such as being able to determine if someone is actually walking or driving and base the refresh times based on that number. I would also like to add a feature when users can overwrite the latitude & longitude pair coming from navigator.geolocation so that as opposed to calling the element via <x-discover> you could say <x-discover latitude=[lat] longitude=[lng]><x-discover> and "explore" what's around your predefined location.

The only problem I have at the moment is unfortunately with the FourSqare API. They require a clientid and a client secret for all their REST endpoints which means implementing those via a Polymer element also exposes that to the public - viewing the source of x-discover.html does reveal the secret codes. At the moment I am not too sure on how to overcome this particular issues but I will have a think about it.

Once the code is cleared up a bit I will push the codebase to GitHub. Stay tuned.

Show Comments