Building a realtime checkins discovery app with Google Maps and AngularJS

rishi shah
All things #search
Published in
5 min readJan 22, 2016

During last week, we wrote about Now — a realtime Foursquare like checkins discovery app. We received a lot of interest around how the app was built including some companies who were interested in building a similar realtime maps based discovery experience.

So in this post, we will re-create Now from scratch in a step-by-step tutorial.

Now app UI — realtime checkins discovery

Overview

Regular readers will remember that Now is a realtime checkins discovery app built using Google Maps API with AngularJS.

For this tutorial post, we won’t talk about the backend worker as it’s not necessary for building the checkins UI/Ux. The worker is responsible for ingesting checkins data from Twitter’s streaming API and inserting into Appbase. You can read more about it here.

The focus will be on building the checkins discovery UI/Ux. For keeping things simple, we will break down this post further into two parts:

  1. In the first half, we will start with installing the dependencies, go over the code structure and talk the Google Maps API integration with Angular.
  2. In the second part, we will be querying appbase.io for live checkins data and see how it integrates with AngularJS.

Setup and Maps Integration

We will use bower for managing all our code dependencies and will set it up under the src/ directory.

src/
|_ _assets/js/
| |_ _index.js
| |_ _dataController.js
| |_ _helperFactory.js
|
|_ _index.html
|
|_ _bower_components/ /* we won't
|_ _assets/css/custom.css edit
|_ _assets/img/<color>_marker.png these files */

You should keep in mind the above code directory structure as we make progress towards building the app.

Grabbing Dependencies and setting up the HTML

Once you’re ready, run the following commands in your terminal to grab the necessary dependencies from bower.

bower install angular#1.4.8
bower install appbase-js#0.10.4
bower install bootstrap#3.3.6
bower install font-awesome#4.5.0
bower install jquery#2.1.4
bower install ngmap#1.14.16

Alternately, you can copy the bower.json file and run bower install.

Bower should install the dependencies under the app/bower_components folder structure by default. Remember to put them under src/bower_components or use a .bowerrc file to ensure this.

Next, we will copy the css and img files to their respective paths and create the following empty javascript files. We will come to them later.

touch src/assets/js/index.js
touch src/assets/js/dataController.js
touch src/assets/js/helperFactory.js

Now paste the following code snippet to your index.html file.

  • Here, L16-L18 loads the maps interface. The <map> element provides controllers related to styling, zooming and panning (Snazzy Maps lets you conveniently style map tiles). <marker> element is used for annotating maps (think images, text, events).
  • L35-L41 shows a datastreams signal which changes colors as the frequency of new checkins changes.
  • L43 onwards, we write the markup for showing the city search UI. Specifically, L48–55 represents the “Search City” box, L57–62 shows the UI for auto-suggestions and L64–79 shows the UI for checkins categories (You can skip these if all you want to show is realtime data).

Initializing Maps in Javascript

At this point, we should have all of our HTML initialized with Google Maps and a snazzy UI.

Next we will edit the index.js file, create our angular module and inject the external ngMap module. This module helps us use different Google Maps components.

var myApp = angular.module('myApp', ['ngMap']);

The mapInitialized event lets us modify viewport and set the zoom level.

$scope.$on('mapInitialized', function(event, map) {
$scope.mapobj = map;
$scope.mapobj.setZoom(3);
$scope.mapobj.setOptions({
minZoom: 2,
maxZoom: 15 // avoid extra zoom out
});
$scope.mapobj.setCenter({
lat: 0,
lng: 0
});
});

Querying Appbase.io for Live Checkins

In our second part, we will be creating realtime continuous queries for streaming live checkins and searching for existing checkins by categories.

Let’s start with creating an appbase.io app, we will use it for querying live checkins data.

Fetch username:password credentials from the app’s dashboard.
A checkins JSON data looks like this, insert a few records like this in your newly created app.

Paste the following entirely into the dataController.js file.

dataController.js

Let’s see what’s happening here. We start with creating a dataClient service where we initialize the Appbase object (use your newly created app and credentials) and call the following methods on it.

L12–26: getSuggestions(city_prefix) creates an auto-complete city list as the user types the city name in the “Search City” box. It uses the suggest query type. You can read more about suggestions from the ElasticSearch docs here.

L28–40: getSearchCheckin(city_name) makes a search query for finding checkins by the city. It uses the search endpoint.

L42–51: getLiveData() subscribes to a search stream of new checkins. It’s very much like search, except it operates in a continuous flow as new data arrives.

L53–67: getDragData(lat, lng) geo-queries for checkins in the vicinity of the [lat, lng] where the user has zoomed in. It uses the geo distance filter, you can read more about it here.

Integrating appbase.io queries with maps

We just learnt about searching and subscribing to realtime queries from appbase.io. Next, we will use these queries to update the Maps UI.

For brevity, we will not go over the entire 300+ lines of index.js code. The entire file is available here.

We will first walk through the city search UI. When the user searches for a city, we call getSuggestions(city_prefix) method for autocomplete recommendations and then call getSearchCheckin(city_name) for getting historical checkins of the city.

Rendering city wide checkins as pins with details showing up on popover
Plot checkins in a city

The searchProcess(response) function above takes the response from the city search query and pushes all the results inside an array object with their respective [lat, lng] co-ordinates and pin’s icon link.

The rendered array is passed to $scope.places variable which is then synced with the html in the <marker> element to annotate our checkins’ details.

<marker ng-repeat="place in places" id="mark" title="{{place[0]}}" icon="{{place[9]}}" position="{{place[1]}}, {{place[2]}}" z-index="{{place[3]}}" on-click="opencheckin(event,place[5])" on-mouseover="showwindow(event,place,true)"></marker>

Now let’s take a look at streaming new checkins.

Similar to searchProcess, streamProcess() function takes the response from the live data query and pushes all the results inside an array object. In addition, we also render streamStatus and color values in a notifier as shown below to indicate the frequency of new checkins.

Realtime notifier

You can follow the drag process code here. We won’t go over the details as it’s very similar in nature to the searchProcess and streamProcess code snippets.

Conclusion

If you have been following from the start, you should have a working Now app and a fair understanding of how we integrate Google Maps with AngularJS and Appbase.io — all in less than 15 minutes. For reference, the entire code is here, and you can check the live demo here.

Whether you are building the next Uber or displaying your city’s landmarks, what we have learnt here about integrating maps interface and a realtime backend functionality should be directly applicable.

Happy hacking!

Thanks to Siddharth Kothari for reading drafts of this.

Published in All things #search

A blog about building search UIs and apps with ReactiveSearch. For Elasticsearch, OpenSearch, Solr and MongoDB search engines

No responses yet

What are your thoughts?