Sorry, you need to enable JavaScript to visit this website.

Store Locator

Overview

This tutorial shows you how to build your company's stores locator. You can choose an address from a side menu to see where an exact store is located on a map. Alternatively, you can select the store on the map to see its details in the side menu.

Prerequisites

To start using the TomTom Maps SDK for Web, you need the following:

  • An SDK that can be downloaded from here: Downloads. Unzip it and save it in a folder. This tutorial assumes your folder is named ‘sdk’. If you choose another name, remember to change the provided paths to match.

    Check out the current file structure

    .
    └── sdk-tutorial
        └── sdk
            ├── LICENSE.txt
            ├── README.md
            ├── glyphs
            ├── images
            ├── map.css
            ├── mapbox-gl-js
            ├── sprites
            ├── styles
            ├── tomtom.min.js
            └── tomtom.min.js.map
        
  • API key

    Create your API key now

    To create a new API key you need to first register on the portal. Once you are logged in there are only two steps remaining:

    Create a new application in your Dashboard:

    Choose all the APIs:

    All set up. You can now click on your newly created app and copy your API key:

  • Coordinates

    How to find your company location coordinates?

    The simplest way for obtaining these coordinates is to go to api_explorer. First, click on Fuzzy Search and then on a Try it out button. Let's assume your company address is: '100 Century Center Ct 210, San Jose, CA 95112, USA'. You have to place it in a query field and clear other pre-populated fields, then scroll down and press the Execute button. Please take into account that you should not use special HTML characters (like '$','?',&','#') in address. In the response you can find section and there you can see that the very first item from the list of items matched your query. Look at the property below address fields. There you can see the data you need:

        <position>
        	<lat>37.36729</lat>
        	<lon>-121.91595</lon>
        	</position>
  • GeoJson data

    Create json file with data

    This tutorial uses sample coordinates and addresses stored in the stores.js file. You can download this file and adapt it for your application. Replace example coordinates and addresses with your stores' coordinates and addresses. Of course, you can add some more data to your application. You can add more data to your application. For example, if you want to have a phone number in your store list, just include the "phone" property in your GeoJSON file like this:

    "properties": { 
    	"address": "Valkensteeg 3, 1012 MH", 
    	"city": "Amsterdam", 
    	"phone": "0123456789" 
    	 } 
    

    For more information about GeoJSON and Leaflet, see: Using GeoJSON with Leaflet.

Displaying the map

Step 1. First, divide the screen into two parts.

  • There will be the map on the right side and all store's locations grouped by cities in the list on the left side.
  • If you want to add yours company logo above the list:
    • Create a folder named img next to the sdk directory.
    • Put the logo there.
  • Remember to set the correct path to your logo in the index.html file. See line 16 in the following HTML5 code example:
<!DOCTYPE html>
<html>
<head> 
	<title>Store Locator</title> 
	<link rel='stylesheet' type='text/css' href='sdk/map.css'/> 
	<link rel='stylesheet' href='http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css'/>
	<script src='sdk/tomtom.min.js'></script>
	<script type='text/javascript' src='stores.js'></script>  
	<link rel='stylesheet' type='text/css' href='styles.css'/>
	<script src='https://code.jquery.com/jquery-1.12.4.js'></script> 
	<script src='https://code.jquery.com/ui/1.12.1/jquery-ui.js'></script>
</head> 
<body>
	<div class='control-panel'></div>   
	  <div class='heading'></div>
	    <img src='img/logo.png'></div> 
	  </div>
 	  <div id='store-list'></div>
	</div>
  <div id='map' class='map'></div>
  <script> 
    var map = tomtom.L.map('map', {
       key: '<your-api-key>',
       basePath: '>',
       center: [52.138950, 4.573040],
       zoom: 10 
    });     
  </script> 
</body>
</html>

Step 2. Now include your styles in styles.css file:

 html {   
	-webkit-box-sizing: border-box;
  box-sizing: border-box;   
 }
 
 *, *: before, *: after {     
 	box-sizing: inherit;
 }  

 body { 	
	color: #707070;
	font-size: 14px;
	margin: 0;
	padding: 0;
 }

 . map { 
	bottom: 0;
	left: 25%;
	position: absolute;
	top: 0;
	width: 75%;
	z-index: -1;
 }

 . control-panel { 
	-webkit-box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.3);
	box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.3);
	height: 100%;
	left: 0;
	overflow: hidden;
	position: absolute;
	top: 0;
	width: 25%;
 }

 . heading { 
	background: #fff;
	border-bottom: 1px solid #eee;
	-webkit-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.16);
	box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.16);
	position: relative;
	z-index: 1;
 }   

 . heading>img { 
	height: auto;
	margin: 10px 0 8px 0;
	width: 150px;
 }        

You will see:

  • The map on the right side of your application.
  • The heading on the left side in a white space.

You will build the list with stores there later.

Adding markers to the map

Step 1. To create markers on the map, copy and paste the following code to your index.html file:

stores.features.forEach(function (store) {
	var address = store.properties.address;	
	var location = store.geometry.coordinates
	var marker = tomtom.L.marker(location);
	var city = store.properties.city;
	var cityStoresList = document.getElementById(city);
	marker.bindPopup(address);
	marker.addTo(map);
}); 

Step 2. The following script creates markers by iterating through the JSON file.

  1. You need to define the address, location, marker, city, and cityStoresList variables and get that data from your JSON.
    • For now, you will see markers on the map and pop-ups showing up after clicking the specific marker.
  2. Now, add the names of the cities to the menu on the left and event listeners to them.
    • After doing this, you will be zoomed in on this city on the map after clicking the city on the list.
  3. When the script finds a new city in the store list, it creates:
    • a HTML5 h3 element (heading with the name of the city) and
    • a div (the container for all stores in this city) and adds them to the application.
  4. If the script adds a store with the city that already exists on the list, then an else statement is executed where we add the marker to the appropriate featureGroup.
    • By using leaflet’s featureGroups, which is defined first as an empty array, you can properly group your JSON data by city.
    • By adding an event listener on cityStoresListHeading (line: 14), you can capture a click on a city header and set a map view on this city.
var featureGroups = []; 
var list = document.getElementById('storeList');
  
stores.features.forEach(function (store) {
[..]
	var cityStoresList = document.getElementById(city);
	if (cityStoresList === null) { 
	  var cityStoresListHeading = list.appendChild(document.createElement('h3'));		
	  cityStoresListHeading.innerHTML = city;     

	  cityStoresList = list.appendChild(document.createElement('div'));
	  cityStoresList.id = city;
	  cityStoresList.className = 'list-entries-container';
	  featureGroups[city] = new L.featureGroup([marker]);
	  cityStoresListHeading.addEventListener('click', function (e) {
	  map.fitBounds(featureGroups[city].getBounds());
	  });
	} else {
	  featureGroups[city].addLayer(marker);
	}
	marker.addTo(map);
	var details = buildLocation(cityStoresList, address);
[..]
});     

Now you should see the map and markers placed in Amsterdam and Rotterdam, and the names of cities on the left side.

  • Click Amsterdam to zoom-in on the markers located in Amsterdam.
  • Click Rotterdam to zoom-in on the markers located in Rotterdam.

Adding the list of stores

Step 1. To build the list with all your stores,

  1. Create the buildLocation function.
  2. Define the details variable.
  3. Create a new element (a) using the HTML DOM appendChild() method. See the following code example:
  4. function buildLocation(htmlParent, text) {
    	var details = htmlParent.appendChild(document.createElement('a'));
    	details.href = '#';
    	details.className = 'list-entry';
    	details.innerHTML = text;
    	return details;
    };
    
  5. Now each address has the attribute a href="#" and a class "list-entry".
    • All addresses related to one city are packed in a div that have has a class named "city-holder".
  6. Here is the code that executes the buildLocation function:
  7. var details = buildLocation(cityStoresList, address);
    

Step 2. Style your store-list element. See at the following CSS code:

#store-list {
	height: 100%;
	overflow: auto;
}

#store-list .list-entries-container .list-entry {
	border-bottom: 1px solid #e8e8e8;
	display: block;
	padding: 10px 50px 10px;
}

#store-list .list-entries-container .list-entry:nth-of-type(even) {
	background-color: #f5f5f5;
}

#store-list .list-entries-container .list-entry:hover,
#store-list .list-entries-container .list-entry.selected {
	background-color: #CDDE75;
	border-bottom-color: #CDDE75;
}

Defining interactive functions on the markers and the list

Step 1. After defining the details variable, and before adding the buildLocation function:

  1. Add the event listener on marker.
  2. After clicking on the marker, we can see the relevant element on the list. See the following code example:
marker.addEventListener('click',
	(function (details, city) {
	  var activeItem = document.getElementsByClassName('selected');
	  return function () {
	    if (activeItem[0]) {
	      activeItem[0].classList.remove('selected');
	    }
	    details.classList.add('selected');
    }
	}) (details, city)
);

The function is enclosed in brackets. This is an “immediately-invoked function expression (IIFE)”.

IIFE is a very useful construct which allows to execute functions immediately, as soon as they are created. They also let us isolate variable declarations so there is no need to create global variables.

If you want to read more about immediately-invoked function expressions, see the Mozilla documentation: IIFE.

Step 2. Now, do the same thing for the details variable. See the following code example:

details.addEventListener('click',
	(function (marker) {
	  var activeItem = document.getElementsByClassName('selected');
	  return function () {
	    if (activeItem[0]) {
	      activeItem[0].classList.remove('selected');
	    }
	    details.classList.add('selected');
	    map.setView(marker.getLatLng(),18);
	    marker.openPopup();
	  }
	}) (marker)
);

Step 3. Style your pop-ups with CSS:

.leaflet-popup {
	padding-bottom: 10px;
}
.leaflet-popup .leaflet-popup-content-wrapper {
	border-radius: 4px;
	-webkit-box-shadow: 0px 2px 11px 0px rgba(0, 0, 0, 0.16);
	box-shadow: 0px 2px 11px 0px rgba(0, 0, 0, 0.16);
}
.leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content {
	margin: 25px;
}

Now, if you click on the address on the list you will be zoomed-in on the relevant marker, and the pop-up will show up.

Adding jQuery UI accordion to the app

Use the jQuery UI accordion to display collapsible content panels. See more about accordion and how to use it at: JQuery UI - Accordion..

$(function () {
	$("#store-list").accordion({ 
	   "icons": { "header": "ui-icon-plus", "activeHeader": "ui-icon-minus" },
	    "heightStyle": "content",
	    "collapsible": true,
	    "active": false
	 });
});

Add CSS styles for your accordion:

.ui-accordion h3.ui-accordion-header {
	background-color: #F4F6F8;
	border-color: #dddfe0;
	border-style: solid;
	border-width: 0 0 3px 0;
	color: #707070;
	display: block;
	font-size: 1.143em;
	margin: 0;
	padding: 15px 20px;
}
.ui-accordion h3.ui-accordion-header.ui-state-active {
	color: #fff; 
	background-color: #BDD731;
	border-bottom-color: #a2ba24;
}
.ui-accordion .ui-accordion-content {
	border: none;
	padding: 0;
}
.ui-icon, .ui-widget-content .ui-icon {
	margin-right: 15px;
}

Your application is almost ready! But you can still improve one thing.

  1. Notice that when you have Amsterdam list dropped down and you click on some marker located in Rotterdam, you cannot see the relevant element on the list because the Rotterdam stores list is collapsed.
  2. You can fix this by adding the following function:
function openCityTab(selected_id) {
	var index = $('#store-list').find('div.list-entries-container');
	for (var j = 0; j < index.length; j++) {
	  if (index[j].id == selected_id) {
	    $("#store-list").accordion( "option", { "active": j } );
	  }
	}
}

Add the openCityTab function execution within the event listener attached to the marker:

marker.addEventListener('click',
	(function (details, city) {
	  var activeItem = document.getElementsByClassName('selected');
	  return function () {
	     if (activeItem[0]) {
	       activeItem[0].classList.remove('selected');
	     }
	     details.classList.add('selected');
	     openCityTab(city);
	  }
	})(details, city)
);

See the result!

Summary

From this tutorial you have learned:

  • How to create a list with your stores and their locations using GeoJSON.
  • How to show your stores on the map.
  • How to define pop-ups for each of the markers.
  • How to build a side-menu listing your stores (grouped by city).
  • How to use jQuery UI accordion to create collapsible drop-down lists for each group.
  • How to attach event listeners: click on group, click on marker, click on list - in order to allow different application interactions.

You can find all the source code here: GitHub.