Store Locator with Custom Markers Using Data Labels¶
This guide shows how the appearance of the markers style can be customized using properties available in the
data source.
See the example fullscreen
What is needed¶
Magic Lane API key token
Web server
Setup¶
Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide.
This project needs a web server.
If you do not have access to a web server, you can easily install
a local web server, see the
Installing a Local Web Server guide.
In this project we use a local web server.
Adding controls¶
To see how to add data source control, store list control and free text search control check out the guides
Store Locator using a GeoJSON File as Data Source,
Store Locator using SQL Server as Data Source,
Store Locator using Studio Defined Data Source or
Store Locator using GeoJSON Text String as Data Source.
To see how to style the marker groups check out the guide
Store Locator with different Marker Groups Styles.
To learn how to customize the free text search control check out the guide
Free Text Search.
Adding Custom Markers with Data Labels¶
How it works¶
1 let geojsonDataControl = new gem.control.GeoJsonAddedDataControl("Madrid_shops.geojson", "" /*icon*/, ""/*iconFilter*/, {
2 marker: {
3 width: 45,
4 height: 45,
5 hoverWidth: 45,
6 hoverHeight: 45,
7 cssClass: 'store-marker',
8 highlightClass: 'highlight-store-marker',
9 markerFunction: function (itemInfoString) {
10 let labelDiv = document.createElement('div');
11 labelDiv.className = 'store-marker-text';
12 let textlabel = labelDiv.appendChild(document.createElement('span'));
13 let jsonInfo = JSON.parse(itemInfoString);
14 if (jsonInfo.properties.rate)
15 textlabel.innerHTML = 'rate ' + jsonInfo.properties.rate;
16 else
17 textlabel.innerHTML = 'rate n.a.';
18 return labelDiv;
19 }
20 },
21 markerGrouping: {
22 maxLevel: 15,
23 style: gem.control.MarkersGroupStyleType.circle
24 },
25 markerBubble: {
26 title: ['name'],
27 image: ['preview']
28 }
29 });
To customize the markers with data labels you can use the data source control options:
marker.cssClass - specify custom style rules class for markers
marker.markerFunction - specify how to style the marker inner elements and optionally use the item data to add labels or filters to the marker
1 <style>
2 .store-marker {
3 background-image: url(./custom.svg);
4 background-position: center;
5 background-repeat: no-repeat;
6 background-size: contain;
7 width: 45px;
8 height: 45px;
9 position: absolute;
10 margin: 0px auto;
11 cursor: pointer;
12 text-align: center;
13 }
14
15 .store-marker.active {
16 filter: hue-rotate(200deg) contrast(1.5);
17 }
18
19 .store-marker-text {
20 display: inline-block;
21 position: relative;
22 border-radius: 50%;
23 max-width: 30px;
24 min-width: 18px;
25 min-height: 10px;
26 text-align: center;
27 font-weight: 600;
28 top: 5px;
29 line-height: 9px;
30 -webkit-touch-callout: none;
31 -webkit-user-select: none;
32 -khtml-user-select: none;
33 -moz-user-select: none;
34 -ms-user-select: none;
35 user-select: none;
36 color: white;
37 }
38
39 .store-marker-text span {
40 font-size: 0.6rem;
41 margin: 0px;
42 }
43
44 .highlight-store-marker {
45 filter: hue-rotate(80deg) contrast(1.5);
46 }
47 </style>
Complete example code¶
1 // Start by setting your token from https://developer.magiclane.com/api/projects
2 if (gem.core.App.token === undefined)
3 gem.core.App.token = "";
4
5 var defaultAppScreen = gem.core.App.initAppScreen({
6 container: "map-canvas",
7 zoom: 10,
8 center: [40.431404, -3.680445], // Madrid
9 style: "./Printemps.style"
10 });
11
12 let geojsonDataControl = new gem.control.GeoJsonAddedDataControl("Madrid_shops.geojson", "" /*icon*/, ""/*iconFilter*/, {
13 marker: {
14 width: 45,
15 height: 45,
16 hoverWidth: 45,
17 hoverHeight: 45,
18 cssClass: 'store-marker',
19 highlightClass: 'highlight-store-marker',
20 markerFunction: function (itemInfoString) {
21 let labelDiv = document.createElement('div');
22 labelDiv.className = 'store-marker-text';
23 let textlabel = labelDiv.appendChild(document.createElement('span'));
24 let jsonInfo = JSON.parse(itemInfoString);
25 if (jsonInfo.properties.rate)
26 textlabel.innerHTML = 'rate ' + jsonInfo.properties.rate;
27 else
28 textlabel.innerHTML = 'rate n.a.';
29 return labelDiv;
30 }
31 },
32 markerGrouping: {
33 maxLevel: 15,
34 style: gem.control.MarkersGroupStyleType.circle
35 },
36 markerBubble: {
37 title: ['name'],
38 image: ['preview']
39 }
40 });
41
42 let listUIControl = new gem.control.ListControl({
43 sourceControl: geojsonDataControl,
44 container: "menu-list-container",
45 displayCount: true,
46 flyToItemAltitude: 250,
47 menuName: 'Marker Data Labels, GeoJSON data source',
48 titleProperties: ['name'],
49 detailsProperties: ['kinds'],
50 imageProperty: ['preview']
51 });
52
53 defaultAppScreen.addControl(geojsonDataControl);
54 defaultAppScreen.addControl(listUIControl);
55
56 let searchControl = new gem.control.SearchControl({
57 highlightOptions: {
58 contourColor: { r: 0, g: 255, b: 0, a: 0 }
59 },
60 searchPreferences: {
61 maximumMatches: 3,
62 addressSearch: true,
63 mapPoisSearch: true,
64 setCursorReferencePoint: true
65 }
66 });
67 defaultAppScreen.addControl(searchControl);
1 <!DOCTYPE html>
2 <html lang="en-us">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, minimum-scale=1, user-scalable=no, shrink-to-fit=no" />
6 <title>Markers Data Labels</title>
7 <link rel="stylesheet" type="text/css" href="https://www.magiclane.com/sdk/js/gem.css">
8 <link rel="stylesheet" href="/fonts/webfonts.css" type="text/css" media="all" />
9
10 <style>
11 .store-marker {
12 background-image: url(./custom.svg);
13 background-position: center;
14 background-repeat: no-repeat;
15 background-size: contain;
16 width: 45px;
17 height: 45px;
18 position: absolute;
19 margin: 0px auto;
20 cursor: pointer;
21 text-align: center;
22 }
23
24 .store-marker.active {
25 filter: hue-rotate(200deg) contrast(1.5);
26 }
27
28 .store-marker-text {
29 display: inline-block;
30 position: relative;
31 border-radius: 50%;
32 max-width: 30px;
33 min-width: 18px;
34 min-height: 10px;
35 text-align: center;
36 font-weight: 600;
37 top: 5px;
38 line-height: 9px;
39 -webkit-touch-callout: none;
40 -webkit-user-select: none;
41 -khtml-user-select: none;
42 -moz-user-select: none;
43 -ms-user-select: none;
44 user-select: none;
45 color: white;
46 }
47
48 .store-marker-text span {
49 font-size: 0.6rem;
50 margin: 0px;
51 }
52
53 .highlight-store-marker {
54 filter: hue-rotate(80deg) contrast(1.5);
55 }
56 </style>
57 </head>
58
59 <body>
60 <div id="store-locator" style="width: 100%; height: 100%">
61 <div id="menu-list-container" class="menu-list-container" style="width: 30%; height: 100%; position: absolute"></div>
62 <div id="map-canvas" style="width: 70%; left: 30%; height: 100%; position: absolute; overflow: hidden"></div>
63 </div>
64
65 <script src="https://www.magiclane.com/sdk/js/gemapi.js"></script>
66 <script type="text/javascript" src="token.js"></script>
67 <script type="text/javascript" src="storeGeoJSONDataMarkers.js"></script>
68 </body>
69 </html>
Files¶
JavaScript
HTML
Printemps Map Style
GeoJSON data downloaded from OpenTripMap:
Madrid Shops Example GeoJSON
Icon customized from Iconpacks:
Custom Marker Image