Store Locator using GeoJSON Data Source with Custom List Control¶
This guide shows you how to customize a previously added list control for your stores data source. A GeoJSON file with stores locations and properties is used as an example data source.The finished example will look like this:
See the example fullscreen
What is needed¶
Magic Lane API key token
Web server (an example is provided)
GeoJSON file containing the store locations (or use our sample GeoJSON)
Setup¶
Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide.
Adding controls¶
To see how to add GeoJSON data control, store list control and free text search control check out the guides Store Locator using a GeoJSON File as Data Source or Store Locator using GeoJSON Text String as Data Source.
Customizing the list control¶
To customize your stores list you can use the list control options:
cssClasses
for specifying your own style rules for the list container with the options:divMenu
for specifying menu container style rules,listHeader
for specifying the menu name style,divListCountCss
for specifying the items count style,divList
for specifying the style rules for the scrollable items list and thedivItem
option for specifying style for the item cards.populateItemFunction
for customizing your store cards layout.
1let listUIControl = new gem.control.ListControl({
2 sourceControl: geojsonDataControl,
3 container: 'menu-list-container',
4 menuName: 'Store locations example',
5 titleProperties: ['name'], // geojson property key selected for usage as title
6 detailsProperties: ['kinds'],
7 cssClasses: {
8 divMenu: {
9 className: 'list-menu',
10 type: 'div'
11 },
12 listHeader: {
13 className: 'list-name',
14 type: 'div'
15 },
16 divListCountCss: {
17 className: 'list-count',
18 type: 'div'
19 },
20 divList: {
21 className: 'list-group',
22 type: 'div'
23 },
24 divItem: {
25 className: 'card',
26 type: 'div'
27 }
28 },
29 populateItemFunction: function (divItemObj, jsonProperties) {
30 divItemObj.innerHTML = '<img class="card-img-top" src="' + jsonProperties.preview + '"/>' +
31 '<div class="card-body">' +
32 '<h5 class="card-title">' + jsonProperties.name + '</h5>' +
33 '<p class="card-text">' + jsonProperties.kinds + '</p> </div>'
34 }
35});
1<style>
2 .list-menu {
3 background-color: #f8f8f8;
4 overflow: hidden;
5 position: absolute;
6 height: 100%;
7 }
8 .list-name {
9 padding: 0.4rem;
10 overflow-y: auto;
11 word-break: break-word;
12 -webkit-overflow-scrolling: touch;
13 }
14 .list-name h2 {
15 font-size: 1.2rem;
16 margin-bottom: 0.1rem;
17 }
18 .list-count {
19 text-align: center;
20 }
21 .list-group {
22 max-height: 100%;
23 overflow-y: auto;
24 overflow-x: hidden;
25 scrollbar-width: thin;
26 word-break: break-word;
27 -webkit-overflow-scrolling: touch;
28 }
29 .card {
30 flex-direction: row;
31 cursor: pointer;
32 font-size: 0.7rem;
33 padding: 0.2rem;
34 }
35 .card h5 {
36 font-size: 0.8rem;
37 }
38 .card img {
39 width: 35%;
40 cursor: pointer;
41 object-fit: cover;
42 padding-top: 0.4rem;
43 padding-bottom: 0.4rem;
44 padding-left: 0.2rem;
45 }
46 .card-body {
47 padding: 0.7rem;
48 }
49 .card:hover {
50 background-color: gold;
51 }
52 .card.active {
53 background-color: #ceede1;
54 }
55</style>
Complete example code¶
1// Start by setting your token from https://www.magiclane.com/api/projects
2if (gem.core.App.token === undefined) gem.core.App.token = "";
3
4defaultAppScreen = gem.core.App.initAppScreen({
5 container: "map-canvas"
6});
7
8let geojsonDataControl = new gem.control.GeoJsonAddedDataControl("Paris.geojson", "" /*icon default*/, "" /*no icon filter*/,
9 {
10 markerBubble: {
11 title: ['name'],
12 image: ['preview']
13 }
14 });
15let listUIControl = new gem.control.ListControl({
16 sourceControl: geojsonDataControl,
17 container: 'menu-list-container',
18 menuName: 'Store locations example',
19 titleProperties: ['name'], // geojson property key selected for usage as title
20 detailsProperties: ['kinds'],
21 cssClasses: {
22 divMenu: {
23 className: 'list-menu',
24 type: 'div'
25 },
26 listHeader: {
27 className: 'list-name',
28 type: 'div'
29 },
30 divListCountCss: {
31 className: 'list-count',
32 type: 'div'
33 },
34 divList: {
35 className: 'list-group',
36 type: 'div'
37 },
38 divItem: {
39 className: 'card',
40 type: 'div'
41 }
42 },
43 populateItemFunction: function (divItemObj, jsonProperties) {
44 divItemObj.innerHTML = '<img class="card-img-top" src="' + jsonProperties.preview + '"/>' +
45 '<div class="card-body">' +
46 '<h5 class="card-title">' + jsonProperties.name + '</h5>' +
47 '<p class="card-text">' + jsonProperties.kinds + '</p> </div>'
48 }
49});
50defaultAppScreen.addControl(geojsonDataControl);
51defaultAppScreen.addControl(listUIControl);
52
53let searchControl = new gem.control.SearchControl({
54 highlightOptions: {
55 contourColor: { r: 0, g: 255, b: 0, a: 0 }
56 },
57 searchPreferences: {
58 exactMatch: true,
59 maximumMatches: 3,
60 addressSearch: true,
61 mapPoisSearch: true,
62 setCursorReferencePoint: true
63 }
64});
65defaultAppScreen.addControl(searchControl);
1<html>
2 <meta charset="utf-8" />
3 <link rel="stylesheet" type="text/css" href="https://www.magiclane.com/sdk/js/gem.css" />
4 <link
5 rel="stylesheet"
6 href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
7 integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
8 crossorigin="anonymous"
9 />
10 <title>Store Locator Geojson Controls</title>
11
12 <head>
13 <style>
14 .list-menu {
15 background-color: #f8f8f8;
16 overflow: hidden;
17 position: absolute;
18 height: 100%;
19 }
20 .list-name {
21 padding: 0.4rem;
22 overflow-y: auto;
23 word-break: break-word;
24 -webkit-overflow-scrolling: touch;
25 }
26 .list-name h2 {
27 font-size: 1.2rem;
28 margin-bottom: 0.1rem;
29 }
30 .list-count {
31 text-align: center;
32 }
33 .list-group {
34 max-height: 100%;
35 overflow-y: auto;
36 overflow-x: hidden;
37 scrollbar-width: thin;
38 word-break: break-word;
39 -webkit-overflow-scrolling: touch;
40 }
41 .card {
42 flex-direction: row;
43 cursor: pointer;
44 font-size: 0.7rem;
45 padding: 0.2rem;
46 }
47 .card h5 {
48 font-size: 0.8rem;
49 }
50 .card img {
51 width: 35%;
52 cursor: pointer;
53 object-fit: cover;
54 padding-top: 0.4rem;
55 padding-bottom: 0.4rem;
56 padding-left: 0.2rem;
57 }
58 .card-body {
59 padding: 0.7rem;
60 }
61 .card:hover {
62 background-color: gold;
63 }
64 .card.active {
65 background-color: #ceede1;
66 }
67 </style>
68 <script
69 src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
70 integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
71 crossorigin="anonymous"
72 ></script>
73 <script
74 src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
75 integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
76 crossorigin="anonymous"
77 ></script>
78 <script
79 src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
80 integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
81 crossorigin="anonymous"
82 ></script>
83 </head>
84
85 <body>
86 <div id="store-locator" style="width: 100%; height: 100%">
87 <div id="menu-list-container" style="width: 35%; height: 100%; position: absolute"></div>
88 <div id="map-canvas" style="width: 65%; height: 100%; position: absolute; left: 35%"></div>
89 </div>
90 <script type="text/javascript" src="https://www.magiclane.com/sdk/js/gemapi.js"></script>
91 <script type="text/javascript" src="token.js"></script>
92 <script type="text/javascript" src="jsStoreLocatorCustomList.js"></script>
93 </body>
94</html>
Files¶
The finished example consists of the project directory containing these files:
JavaScript code (
.js
file extension)HTML code (
.html
file extension)Store locations in GeoJSON format (
.geojson
file extension)
To run the example, the HTML file is loaded in a browser.
Source code for this example:
JavaScriptHTML
Store locations in GeoJSON format
right-click on the links and select Save As.