📜 ⬆️ ⬇️

We write mashup using Nokia Maps JS API and Twitter Search API

Last week, Nokia Maps were integrated into the most popular photo hosting site Flickr, which resulted in an interesting mashup , where you can see photos with geotags on the map.



We decided to continue the theme of Nokia Maps mashaps, and today we will show how using the Nokia Maps JS API + Twitter Search API combination to display the intensity of using various hashtags on Twitter on the map. Such a mashup will look like the image below.


')
By tradition, let's start by creating index.html, in which our map will be initialized:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Nokia Maps Heatmap demo</title> <link rel="stylesheet" href="main.css"> </head> <body> <div id="annotations"> <h2></h2> </div> <div id="map" class="map"><div id="map-loading" class="map-loading"></div></div> <script src="http://api.maps.nokia.com/2.2.1/jsl.js?with=all"></script> <script src="places-heatmap.js"></script> <script src="process-tweets.js"></script> </body> </html> 


As you can see, we immediately identified three javascript scripts. First script api.maps.nokia.com/2.2.1/jsl.js api.maps.nokia.com/2.2.1/jsl.js you may already be familiar with the last post - it loads the Nokia Maps JS API.

The places-heatmap.js is responsible for drawing and adding an intensity overlay to the map. The following process-tweets.js script process-tweets.js for tweets with a given hashtag containing geolocation data, as well as subsequent geocoding of these tweets with entering information about them (latitude / longitude, city) into the data structure of the intensity map.

An explanation of these scripts will be given directly in the comments to the code.

places-heatmap.js


 var HH = {}; //      Nokia Maps JS API nokia.Settings.set("appId", "_peU-uCkp-j8ovkzFGNU"); nokia.Settings.set("authenticationToken", "gBoUkAMoxoqIWfxWA5DuMQ"); nokia.Settings.set("defaultLanguage", "ru-RU"); HH.HeatmapLoader = function () { var self = this, map, mapLoad, heatmapLoad, heatmapProvider; //   ,       mapLoad = function () { var mapContainer = document.getElementById("map"); self.map = new nokia.maps.map.Display(mapContainer, { //     ,    zoomLevel: 3     center: [55, 37], zoomLevel: 3, components: [ new nokia.maps.map.component.Behavior() ] }); }; //    ,      heatmapLoad = function () { var color_range = { //       . //      1,   — 0. stops: { //    ,        —  ,       "0": "rgba(0, 0, 64, 1)", "0.15": "rgba(0, 0, 64, 1)", "0.3": "rgb(32, 32, 96)", "0.4": "rgb(96, 96, 128)", "0.5": "rgb(255, 255, 255)" }, //      ,     interpolate: true }; try { if(!self.heatmapProvider) { //     heatmapProvider = new nokia.maps.heatmap.Overlay({ //     colors: color_range, //   ,     max: 20, //   ,    opacity: 1, //     type: "density", //       coarseness: 1, //  ,   , ,     assumeValues: true }); } } catch (e) { //       , //      canvas alert(e); } //            if (heatmapProvider && HH.tweetheatmap) { //      heatmapProvider.clear(); heatmapProvider.addData(HH.tweetheatmap.allPlaces); //      self.map.overlays.add(heatmapProvider); } }; //      return { map: map, mapLoad: mapLoad, heatmapLoad: heatmapLoad, heatmapProvider: heatmapProvider }; }; //   HeatmapLoader HH.heatmap = new HH.HeatmapLoader(); 


You can read more about the used class nokia.maps.heatmap.Overlay on the Nokia Maps API Reference site, however, in the comments to the code all parameters were listed, not including some of the overlay settings, which are set via nokia.maps.heatmap.Overlay.Options .

process-tweets.js


 HH.TweetHeatmap = function () { "use strict"; var self, init, pageSetup, switchInput, changeHash, allPlaces = [], addPlaces, addSearch, tweetPlace, getLocation, addToPlace, futureCheck, futureCount = 0, rendered = false, locationsObj = {}, locationsTweets = [], displayHeatmap; init = function () { var locations, i; self = this; //     ,       if (nokia.maps && HH.heatmap) { HH.heatmap.mapLoad(); } //    ,   #nokia if (window.location.hash === '') { window.location.hash = 'nokia'; } pageSetup(); //   Twitter Search API    ,        locations = [[55.75697, 37.61502], [0, 100], [0, 50], [0, 0], [0, -50], [0, -100], [0, -150], [50, 150], [50, 100], [50, 50], [50, 0], [50, -50], [50, -100], [50, -150], [-50, 150], [-50, 100], [-50, 50], [-50, 0], [-50, -50], [-50, -100], [-50, -150]]; //    ,   ,    document.getElementById('map-loading').style.display = 'block'; //    ,   locations,      Twitter Search API    for (i in locations) { self.addSearch(locations[i], window.location.hash.substring(1)); } //           , //   ,  ,    setTimeout(displayHeatmap, 8000); }; //  JSONP-     ,  Twitter Search API //     addPlaces addSearch = function (location, hashtag) { //  Twitter Search API   : https://dev.twitter.com/docs/api/1/get/search var url = 'http://search.twitter.com/search.json?geocode=' + location[0] + ',' + location[1] + ',8000km&q=%23' + hashtag + '&rpp=100&callback= HH.tweetheatmap.addPlaces', script = document.createElement("script"); script.setAttribute("src", url); document.body.appendChild(script); }; //     ,       addPlaces = function (data) { var i; if (data && data.results && data.results.length) { //    . self.futureCount += data.results.length; for (i = data.results.length - 1; i >= 0; i--) { var location = data.results[i].location if (location) { location = location.replace('iPhone: ','') self.getLocation(location); } else { //       ,     self.futureCount--; } }; } }; //  JSONP-  Nokia Maps geocode API    Twitter       getLocation = function (location) { // q —  , vi —  , dv —  , to —     var url = 'http://where.desktop.mos.svc.ovi.com/json?q=' + encodeURI(location) + '&to=1&vi=address&dv=NokiaMapsAPI&callback_func=HH.tweetheatmap.addToPlace', script = document.createElement("script"); script.setAttribute("src", url); document.body.appendChild(script); }; //      ,  //       addToPlace = function (data) { if (data.results && data.results.length) { var location_title = data.results[0].properties.title, type = data.results[0].properties.type, lon = data.results[0].properties.geoLongitude, lat = data.results[0].properties.geoLatitude; if (type != 'Country' && type != 'State' && type != 'Continent'){ if (locationsObj[location_title]) { locationsTweets[locationsObj[location_title]].tweets += 1; } else { locationsObj[location_title] = locationsTweets.length locationsTweets.push({ 'city': location_title, 'tweets': 1, 'longitude': lon, 'latitude': lat }); } } if (!rendered) { allPlaces.push({ "latitude" : lat, "longitude" : lon, "city" : location_title, "country" : data.results[0].properties.addrCountryName }); } } self.futureCheck(); }; //      ,   . //   ,       futureCheck = function () { self.futureCount--; if (self.futureCount<=0) { displayHeatmap(); } }; //   ,       displayHeatmap = function() { if(!rendered) { rendered = true; document.getElementById('map-loading').style.display = 'none'; HH.heatmap.heatmapLoad(); } }; // ,             switchInput = function(e){ this.style.display='none'; var h = document.createElement('input');h.setAttribute('type', 'text'); this.parentNode.insertBefore(h,this); h.focus(); h.addEventListener('keydown', changeHash, false); }; changeHash = function(e){ if(e.keyCode===13) { window.location.hash='#'+e.target.value.replace('#',''); } else if(e.keyCode===27) { e.target.parentNode.removeChild(e.target); document.getElementsByTagName('h2')[0].style.display='block'; } }; pageSetup = function() { if (!(document.getElementsByTagName('body')[0].classList.length === 1)) { //       URL document.getElementsByTagName('h2')[0].innerHTML = '#' + window.location.hash.substring(1); //  event listener      document.getElementsByTagName('h2')[0].addEventListener('click', switchInput, false) //  event listener        window.addEventListener("hashchange", function (e) {window.location.reload(); }, false); } }; //      return { init: init, addSearch: addSearch, addPlaces : addPlaces, addToPlace : addToPlace, getLocation: getLocation, futureCount : futureCount, futureCheck : futureCheck, allPlaces : allPlaces, locationsTweets : locationsTweets }; }; HH.tweetheatmap = new HH.TweetHeatmap(); HH.tweetheatmap.init(); 


When working with the Twitter Search API, it is worth considering that in it, although you can specify an arbitrary radius (even equal to the radius of the Earth), in which tweets are to be searched, it returns no more than 100 tweets in its output. Thus, it is better to specify the coordinates of a set of points, otherwise a large number of messages will fall out of the search.

At the end of the process-tweets.js you might notice features that are not directly related to the Twitter Search API. They are responsible for the interface of our map and allow clicking on the current hashtag (in the upper left corner) to determine a new searchable one. Via document.getElementsByTagName('h2')[0].innerHTML = '#' + window.location.hash.substring(1); we define the hashtag through the URL - so our index.html can be inserted into any site as an iframe, using any hashtag.

View source


See a live example here . Sources can be downloaded from github .

API materials used


Source: https://habr.com/ru/post/149320/


All Articles