Skip to content

Store Locator using Filters Controls

This guide shows you how to add data filters to a store locator using controls.

The finished example will look like this:

See the example fullscreen

When to use

  • The entire store location data set is relatively big.

  • The data set can be filtered using properties or by distance.

What is needed

  • Magic Lane API key token

  • Web server (an example is provided)

  • SVG file of the store logo (or use our sample SVG)

  • Store locator using Magic Lane JavaScript controls

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.

Adding controls

To see how to add Studio Query data control, store list control, free text search control and distance control check out the guide Store Locator using Studio Query Data Source.

You can also use the filters controls with any data source of your choice from our use cases.

Adding category radio type filter

A radio type filter has been added using the data property rate. To add this kind of filter you can use the control gem.control.CategoryFilterControl with the option style: 'radio'. The filter options are defined using categories and the property name should hold a unique identifier for the filter control.

 1 const categoryRadioRateFilter = new gem.control.CategoryFilterControl({
 2     parentContainer: 'filter-category-rate',
 3     name: 'byRate',
 4     style: 'radio',
 5     title: 'Filter by Rate',
 6     categories: [
 7       { label: 'any', filter: { key: '', value: '' } },
 8       { label: '3', filter: { key: 'rate', value: '3' } },
 9       { label: '3h', filter: { key: 'rate', value: '3h' } }
10     ]
11 }, studioQueryControl);
12 defaultAppScreen.addControl(categoryRadioRateFilter);
1...
2<div id="map-canvas" style="width: 75%; left: 25%; height: 100%; position: absolute; overflow: hidden">
3  <div id="filters-container" class="filters-container">
4      <div id="filter-category-rate" class="filter-category2"></div>
5      <div id="filter-distance" class="filter-distance"></div>
6  </div>
7</div>
8...

Adding category checkboxes filter

A filter with the checkboxes style has been added using the data property kinds. To add this kind of filter you can use the control gem.control.CategoryFilterControl with the option style: 'checkboxes'. The filter options are defined using categories and the property name should hold a unique identifier for the filter control.

 1 const categoryCheckboxFilterControl = new gem.control.CategoryFilterControl({
 2     parentContainer: 'filter-category-kind',
 3     name: 'byKindCheckboxes',
 4     style: 'checkboxes',
 5     title: 'Filter by kind',
 6     categories: [
 7       {
 8             label: 'Food', filter: { key: '', value: '' }, children:
 9               [
10                 { label: 'Cafes', filter: { key: 'kinds', value: 'cafes,foods,tourist_facilities' } },
11                 { label: 'Restaurants', filter: { key: 'kinds', value: 'restaurants,foods,tourist_facilities' } },
12                 { label: 'Restaurants, Historic Architecture', filter: { key: 'kinds', value: 'historic_architecture,architecture,interesting_places,restaurants,foods,tourist_facilities,other_buildings_and_structures' } }
13               ]
14       },
15       {
16             label: 'Visit', filter: { key: '', value: '' }, children:
17               [
18                 { label: 'Art Galleries', filter: { key: 'kinds', value: 'national_museums,museums,cultural,interesting_places,art_galleries' } },
19                 { label: 'Museums', filter: { key: 'kinds', value: 'museums,cultural,interesting_places,other_museums' } },
20                 { label: 'Historic Monuments', filter: { key: 'kinds', value: 'fortifications,historic,monuments_and_memorials,interesting_places,castles,monuments' } }
21               ]
22       }
23     ]
24 }, studioQueryControl);
25 defaultAppScreen.addControl(categoryCheckboxFilterControl);
1...
2<div id="map-canvas" style="width: 75%; left: 25%; height: 100%; position: absolute; overflow: hidden">
3  <div id="filters-container" class="filters-container">
4    <div id="filter-category-kind" class="filter-category1"></div>
5    <div id="filter-category-rate" class="filter-category2"></div>
6    <div id="filter-distance" class="filter-distance"></div>
7  </div>
8</div>
9...

Complete example code

 1 // Start by setting your token from https://developer.generalmagic.com/api/projects
 2 if (gem.core.App.token === undefined) gem.core.App.token = '';
 3
 4 const defaultAppScreen = gem.core.App.initAppScreen({
 5     container: 'map-canvas',
 6     zoom: 10,
 7     center: [48.8562, 2.3516, 100000]
 8 });
 9
10 const studioQueryControl = new gem.control.StudioQueryDataControl('1973209755' /* studio data source id */, '', {
11     markerBubble: {
12             title: ['name'],
13             image: ['preview']
14     }
15 });
16 defaultAppScreen.addControl(studioQueryControl);
17
18 const searchControl = new gem.control.DataQuerySearchControl({
19     highlightOptions: {
20             contourColor: { r: 0, g: 255, b: 0, a: 0 }
21     },
22     searchPreferences: {
23             maximumMatches: 3,
24             addressSearch: false,
25             mapPoisSearch: false,
26             setCursorReferencePoint: true
27     },
28     searchResults: {
29             initialPlaceSearch: 'Paris'
30     }
31 }, studioQueryControl);
32 defaultAppScreen.addControl(searchControl);
33
34 const listUIControl = new gem.control.ListControl({
35     sourceControl: studioQueryControl,
36     container: 'stores-list',
37     displayCount: true,
38     flyToItemAltitude: 250,
39     menuName: 'Store Locator Example',
40     titleProperties: ['name'],
41     detailsProperties: ['kinds'],
42     imageProperty: ['preview']
43 });
44 defaultAppScreen.addControl(listUIControl);
45
46 const distanceFilterControl = new gem.control.DistanceFilterControl({
47     parentContainer: 'filter-distance',
48     name: 'byRadius',
49     style: 'dropdown',
50     title: 'Search radius (km)',
51     thresholds: [10, 25, 50, 100, 200],
52     eUnit: 'km'
53 }, studioQueryControl);
54
55 const categoryCheckboxFilterControl = new gem.control.CategoryFilterControl({
56     parentContainer: 'filter-category-kind',
57     name: 'byKindCheckboxes',
58     style: 'checkboxes',
59     title: 'Filter by kind',
60     categories: [
61             {
62                     label: 'Food', filter: { key: '', value: '' }, children:
63                             [
64                                     { label: 'Cafes', filter: { key: 'kinds', value: 'cafes,foods,tourist_facilities' } },
65                                     { label: 'Restaurants', filter: { key: 'kinds', value: 'restaurants,foods,tourist_facilities' } },
66                                     { label: 'Restaurants, Historic Architecture', filter: { key: 'kinds', value: 'historic_architecture,architecture,interesting_places,restaurants,foods,tourist_facilities,other_buildings_and_structures' } }
67                             ]
68             },
69             {
70                     label: 'Visit', filter: { key: '', value: '' }, children:
71                             [
72                                     { label: 'Art Galleries', filter: { key: 'kinds', value: 'national_museums,museums,cultural,interesting_places,art_galleries' } },
73                                     { label: 'Museums', filter: { key: 'kinds', value: 'museums,cultural,interesting_places,other_museums' } },
74                                     { label: 'Historic Monuments', filter: { key: 'kinds', value: 'fortifications,historic,monuments_and_memorials,interesting_places,castles,monuments' } }
75                             ]
76             }
77     ]
78 }, studioQueryControl);
79
80 const categoryRadioRateFilter = new gem.control.CategoryFilterControl({
81     parentContainer: 'filter-category-rate',
82     name: 'byRate',
83     style: 'radio',
84     title: 'Filter by Rate',
85     categories: [
86             { label: 'any', filter: { key: '', value: '' } },
87             { label: '3', filter: { key: 'rate', value: '3' } },
88             { label: '3h', filter: { key: 'rate', value: '3h' } }
89     ]
90 }, studioQueryControl);
91
92 defaultAppScreen.addControl(distanceFilterControl);
93 defaultAppScreen.addControl(categoryCheckboxFilterControl);
94 defaultAppScreen.addControl(categoryRadioRateFilter);
 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>Store Locator Filters Controls - GeneralMagic Maps SDK for JavaScript</title>
 7    <link rel="stylesheet" type="text/css" href="https://www.generalmagic.com/sdk/js/gem.css" />
 8    <link rel="stylesheet" href="/fonts/webfonts.css" type="text/css" media="all" />
 9
10    <style>
11      .filters-container {
12        position: absolute;
13        width: 30%;
14        max-width: 300px;
15        right: 0px;
16        top: 50px;
17        margin: 8px;
18        z-index: 9;
19        font-size: 0.7rem;
20        background-color: white;
21        box-shadow: 0 2px 4px rgb(0 0 0 / 20%), 0 -1px 0 rgb(0 0 0 / 2%);
22      }
23    </style>
24  </head>
25
26  <body>
27    <div id="store-locator" style="width: 100%; height: 100%">
28      <div id="stores-list" class="menu-list-container" style="width: 25%; height: 100%; position: absolute"></div>
29      <div id="map-canvas" style="width: 75%; left: 25%; height: 100%; position: absolute; overflow: hidden">
30        <div id="filters-container" class="filters-container">
31          <div id="filter-category-kind" class="filter-category1"></div>
32          <div id="filter-category-rate" class="filter-category2"></div>
33          <div id="filter-distance" class="filter-distance"></div>
34        </div>
35      </div>
36    </div>
37
38    <script src="https://www.generalmagic.com/sdk/js/gemapi.js"></script>
39    <script type="text/javascript" src="token.js"></script>
40    <script type="text/javascript" src="storeFiltersControls03.js"></script>
41  </body>
42</html>

Files

The finished example consists of the project directory containing 2 files:

  • JavaScript code (.js file extension)

  • HTML code (.html file extension)

To run the example, the HTML file is loaded in a browser.

Source code for this example:

JavaScript
HTML

right-click on the links and select Save As.

JavaScript Examples

Maps SDK for JavaScript Examples can be downloaded or cloned with Git