Apply core concepts

Learn to craft an engaging, interactive experience with Calcite Components and ArcGIS Maps SDK for JavaScript.

Using core web component concepts such as slots, events, and attributes, you will build an interface using Calcite Components and data provided by ArcGIS Maps SDK for JavaScript.

This tutorial will provide an overview of foundational Calcite Component and web component concepts. You will:

  • Scaffold an interface with calcite-shell and related components.

  • Add a with a FeatureLayer containing content.

  • Use Calcite Components to display data provided by the queryTopFeatures() method.

  • Add interactivity to the map and data using the concepts of events and attributes.

  • Customize the look and feel using mode and color tokens.

This tutorial leverages vanilla JavaScript, but these concepts and methods of interaction are applicable across frameworks.

Prerequisites

ArcGIS account
You need a free ArcGIS Online and/or ArcGIS Location Platform account to access the services used in this tutorial.

Steps

Create a new pen

  1. Go to CodePen to create a new pen for your mapping application.

Add HTML

  1. In CodePen > HTML, add HTML and CSS to create a page with the ArcGIS Maps SDK for JavaScript Map components including the arcgis-map, arcgis-home, and arcgis-zoom components, which will display the . The CSS ensures that the map is the full width and height of the browser window.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>Calcite Components: Core concepts</title>

  <style>
    html,
    body,
    #mapEl {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
  </style>

</head>

<body>

  <arcgis-map id="mapEl" basemap="streets-navigation-vector" zoom="3" center="-120, 45">
    <arcgis-home position="top-right"></arcgis-home>
    <arcgis-zoom position="top-right"></arcgis-zoom>
  </arcgis-map>

</body>

<script>
</script>

</html>
  1. In the <head> element, add references to Calcite Components and .
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  <script type="module" src="https://js.arcgis.com/calcite-components/3.0.3/calcite.esm.js"></script>

  <script src="https://js.arcgis.com/4.32/"></script>
  <link rel="stylesheet" href="https://js.arcgis.com/4.32/esri/themes/light/main.css" />
  <script type="module" src="https://js.arcgis.com/map-components/4.32/arcgis-map-components.esm.js"></script>
Expand

Import modules

  1. In the <script> element, import the ArcGIS Maps SDK for JavaScript modules that you will use in this application.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  </arcgis-map>

</body>

<script>

  require([
    "esri/layers/FeatureLayer",
    "esri/symbols/WebStyleSymbol",
    "esri/rest/support/TopFeaturesQuery",
    "esri/rest/support/TopFilter"
  ], (FeatureLayer, WebStyleSymbol, TopFeaturesQuery, TopFilter) => (async () => { })());

</script>

</html>

Get an access token

You need an with the correct privileges to access the used in this tutorial.

  1. Go to the Create an API key tutorial and create an with the following :
  • Privileges
    • Location services > Basemaps
  1. In CodePen, set esriConfig.apiKey to your access token.
1
2
3
4
5
6
<!-- The esriConfig variable must be defined before adding other Esri libraries -->
<script>
  var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN"
  };
</script>

To learn about other ways to get an access token, go to Types of authentification.

Scaffold the application

Next, you will add Calcite Components to scaffold the application.

  1. The calcite-shell component serves as the application frame. Additionally, notice that the calcite-shell-panel, and calcite-panel components have been added.

These layout components help organize content and other components in predictable and repeatable ways, and can be configured to accommodate many desired layouts and use cases.

Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

<body>
  <calcite-shell>
    <calcite-shell-panel slot="panel-start">
      <calcite-panel heading="National Park Visitation"> </calcite-panel>
    </calcite-shell-panel>

    <arcgis-map id="mapEl" basemap="streets-navigation-vector" zoom="3" center="-120, 45">
      <arcgis-home position="top-right"></arcgis-home>
      <arcgis-zoom position="top-right"></arcgis-zoom>
    </arcgis-map>

  </calcite-shell>
</body>
Expand
  1. Pause to understand some core web component concepts in the snippet you added to the application:
    • The panel-start slot you added to the calcite-shell-panel. Defined slots such as this can provide styling or positioning for slotted content or components, making common patterns simple to construct.
    • The heading attribute has been added to the calcite-panel component and populated with the name of the application. Using component attributes to add text helps consistently position and style content.

Display a map

  1. Next, you will add the ArcGIS Maps SDK for JavaScript code, based on the Query top features from a FeatureLayer tutorial using the arcgisViewReadyChange event.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  ], (FeatureLayer, WebStyleSymbol, TopFeaturesQuery, TopFilter) =>
    (async () => {

      const mapEl = document.getElementById("mapEl");

      mapEl.addEventListener("arcgisViewReadyChange", async () => {

      const layer = new FeatureLayer({
        url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/US_National_Parks_Annual_Visitation/FeatureServer/0",
        outFields: ["*"],
        renderer: await setRenderer(),
        popupTemplate: createPopupTemplate()
      });

      mapEl.addLayer(layer);

      const layerView = await mapEl.view.whenLayerView(layer);

      async function setRenderer() {
        const symbol = new WebStyleSymbol({
          name: "park",
          styleName: "Esri2DPointSymbolsStyle"
        });

        const cimSymbol = await symbol.fetchCIMSymbol();
        cimSymbol.data.symbol.symbolLayers[0].size = 24;
        cimSymbol.data.symbol.symbolLayers[1].size = 0;

        return {
          type: "simple",
          symbol: cimSymbol
        };
      }

      function createPopupTemplate() {
        return {
          title: "{Park}",
          content: [
            {
              type: "fields",
              fieldInfos: [
                {
                  fieldName: "F2022",
                  label: "2022",
                  format: { digitSeparator: true }
                },
                {
                  fieldName: "F2021",
                  label: "2021",
                  format: { digitSeparator: true }
                },
                {
                  fieldName: "F2020",
                  label: "2020",
                  format: { digitSeparator: true }
                },
                {
                  fieldName: "F2019",
                  label: "2019",
                  format: { digitSeparator: true }
                }
              ]
            }
          ]
        };
      }


Expand

At this point the is visible behind the calcite-shell-panel you added. Click around the map points and see the data displayed in popups. This configuration is not specific to Calcite Components - you can view the original tutorial for more context.

  1. Add a function to filter the data on the map. The filterItems() function contains a queryTopFeatures() method, which returns a set of results based on a set of filter options. Notice that we have assigned some default values to variables that will later be made configurable in the application.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
      const countDefault = 1;
      const orderByDefault = "DESC";
      const yearDefault = "F2023";

      let count = countDefault;
      let orderBy = orderByDefault;
      let year = yearDefault;

      async function filterItems() {
        const query = new TopFeaturesQuery({
          topFilter: new TopFilter({
            topCount: count,
            groupByFields: ["State"],
            orderByFields: `${year} ${orderBy}`
          }),
          orderByFields: `${year} ${orderBy}`,
          outFields: ["State, F2023, F2022, F2021, F2020, Park"],
          returnGeometry: true,
          cacheHint: false
        });

        query.orderByFields = [""];
        const objectIds = await layer.queryTopObjectIds(query);
        layerView.filter = { objectIds };
      }

      filterItems();
Expand

Add the results list

Next, you will create a list using the results returned from ArcGIS Maps SDK for JavaScript. Clicking on the result items will show an associated popup on the map.

  1. Add a calcite-block with an id attribute. Inside, place a calcite-list, again with an id attribute, that will be used for appending content. Note the collapsible and heading attributes used to customize the component.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  <calcite-shell>
    <calcite-shell-panel slot="panel-start">
      <calcite-panel heading="National Park Visitation">

        <calcite-block collapsible heading="Results" id="result-block">
          <calcite-list id="result-list"></calcite-list>
        </calcite-block>

      </calcite-panel>
    </calcite-shell-panel>
Expand
  1. Next, add logic to create a calcite-list-item for each displayed item in the FeatureLayer.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        document.getElementById("result-list").innerHTML = "";
        document.getElementById("result-block").open = true;

        const results = await layer.queryTopFeatures(query);
        graphics = results.features;

        graphics.forEach((result, index) => {
          const attributes = result.attributes;
          const item = document.createElement("calcite-list-item");
          const chip = document.createElement("calcite-chip");
          chip.label = attributes.State;
          chip.slot = "content-end";
          chip.scale = "m";
          chip.innerText = attributes.State;
          item.label = attributes.Park;
          item.value = index;
          item.description = `${attributes[year].toLocaleString()} visitors`;
          item.addEventListener("click", () => resultClickHandler(result, index));
          item.appendChild(chip);
          document.getElementById("result-list").appendChild(item);
        });
Expand

For each graphic, you are programmatically creating a calcite-list-item, assigning property values to customize the display, and appending to the result container reference you added earlier. You are also creating a calcite-chip with the state name of each result, and placing it in a slot.

  1. An event listener was added to each calcite-list-item created in the previous step. Create the resultClickHandler() function, which will display a ArcGIS Maps SDK for JavaScript popup.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
      function resultClickHandler(result, index) {
        const popup = graphics && graphics[parseInt(index, 10)];
        if (popup) {
          mapEl.view.openPopup({
            features: [popup],
            location: result.geometry
          });
          mapEl.view.goTo({ center: [result.geometry.longitude, result.geometry.latitude], zoom: 4 }, { duration: 400 });
        }
      }
Expand

Build the filters

  1. Add another calcite-block component. Inside, place a set of controls that will adjust the parameters of the queryTopFeatures() query. Each control is wrapped in a calcite-label.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    <calcite-shell-panel slot="panel-start">
      <calcite-panel heading="National Park Visitation">

        <calcite-block heading="Filters" open>
          <calcite-label>
            Data type, per state
            <calcite-segmented-control id="control-visited-type-el" width="full">
              <calcite-segmented-control-item value="DESC" checked>Most visited</calcite-segmented-control-item>
              <calcite-segmented-control-item value="ASC">Least visited</calcite-segmented-control-item>
            </calcite-segmented-control>
          </calcite-label>
          <calcite-label>
            Year data to display
            <calcite-select id="control-year-el">
              <calcite-option label="2023" value="F2023"></calcite-option>
              <calcite-option label="2022" value="F2022"></calcite-option>
              <calcite-option label="2021" value="F2021"></calcite-option>
              <calcite-option label="2020" value="F2020"></calcite-option>
            </calcite-select>
          </calcite-label>
          <calcite-label>
            Max parks per state
            <calcite-slider id="control-count-per-state-el" label-ticks ticks="1" min="1" max="5"></calcite-slider>
          </calcite-label>
        </calcite-block>


        <calcite-block collapsible heading="Results" id="result-block">
          <calcite-list id="result-list"></calcite-list>
        </calcite-block>

      </calcite-panel>
    </calcite-shell-panel>
Expand
  1. Note that you have assigned id attributes to the calcite-segmented-control, calcite-select, and calcite-slider. You will use these references to set up event listeners to determine when to update the results.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
      const controlVisitedTypeEl = document.getElementById("control-visited-type-el");
      const controlYearEl = document.getElementById("control-year-el");
      const controlCountPerStateEl = document.getElementById("control-count-per-state-el");

      controlVisitedTypeEl.addEventListener("calciteSegmentedControlChange", async event => {
        (orderBy = event.target.value), filterItems();
      });
      controlYearEl.addEventListener("calciteSelectChange", async event => {
        (year = event.target.value), filterItems();
      });
      controlCountPerStateEl.addEventListener("calciteSliderChange", async event => {
        (count = event.target.value), filterItems();
      });
Expand

Note that each event listener references a custom Calcite Components event: calciteSelectChange, calciteSliderChange , and calciteSegmentedControlChange.

When that event is fired, you will set the related local variable, and run the filterItems() function. In a production environment, you might make use of more granular filtering functions to improve performance.

Create a reset action

Because you added events that allowed a user to change the view from the default filter parameters, it will be useful to add a way to reset the options.

  1. Add a calcite-action and calcite-tooltip using slots.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
        <calcite-block heading="Filters" open>

          <div slot="control">
            <calcite-action disabled icon="reset" id="control-reset-el"></calcite-action>
            <calcite-tooltip reference-element="control-reset-el" placement="bottom">
              Reset to defaults
            </calcite-tooltip>
          </div>

          <calcite-label>
Expand

You may notice some concepts used in previous tutorial steps. Take note of the icon attribute on the calcite-action. Calcite Components often provide helpers for loading Calcite UI Icons - the full set can be explored using the icon search.

The disabled attribute is also set - you will enable it when the set of parameters a user has created differs from the defaults.

  1. Add a reference and an event listener to the reset action.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
      const controlVisitedTypeEl = document.getElementById("control-visited-type-el");
      const controlYearEl = document.getElementById("control-year-el");
      const controlCountPerStateEl = document.getElementById("control-count-per-state-el");
      const controlResetEl = document.getElementById("control-reset-el");

      controlVisitedTypeEl.addEventListener("calciteSegmentedControlChange", async event => {
        (orderBy = event.target.value), filterItems();
      });
      controlYearEl.addEventListener("calciteSelectChange", async event => {
        (year = event.target.value), filterItems();
      });
      controlCountPerStateEl.addEventListener("calciteSliderChange", async event => {
        (count = event.target.value), filterItems();
      });
      controlResetEl.addEventListener("click", async () => resetFilters());
Expand
  1. Add the functions determineResetActionState(), and resetFilters(), where you will determine the state of the reset action, and reset parameters when requested by a user. The resetFilters() function will reset the parameters of the query, and reset the controls to their initial display. The action will be disabled when the set of filter options matches the initial values, or a user interacts with the calcite-action.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
      function determineResetActionState() {
        if (count !== countDefault || orderBy !== orderByDefault || year !== yearDefault) {
          controlResetEl.removeAttribute("disabled");
          controlResetEl.indicator = true;
        } else {
          controlResetEl.disabled = true;
          controlResetEl.removeAttribute("indicator");
        }
      }

      function resetFilters() {
        count = countDefault;
        orderBy = orderByDefault;
        year = yearDefault;

        const activeSegmentedControlItem = document.querySelector(`calcite-segmented-control-item[value=${orderByDefault}]`);
        activeSegmentedControlItem.checked = true;
        controlYearEl.value = yearDefault;
        controlCountPerStateEl.value = countDefault;

        filterItems();
      }
Expand
  1. Call the determineResetActionState() function in the filterItems() function.
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
      async function filterItems() {
        const query = new TopFeaturesQuery({
          topFilter: new TopFilter({
            topCount: count,
            groupByFields: ["State"],
            orderByFields: `${year} ${orderBy}`
          }),
          orderByFields: `${year} ${orderBy}`,
          outFields: ["State, F2023, F2022, F2021, F2020, Park"],
          returnGeometry: true,
          cacheHint: false
        });

        document.getElementById("result-list").innerHTML = "";
        document.getElementById("result-block").open = true;

        const results = await layer.queryTopFeatures(query);
        graphics = results.features;

        graphics.forEach((result, index) => {
          const attributes = result.attributes;
          const item = document.createElement("calcite-list-item");
          const chip = document.createElement("calcite-chip");
          chip.label = attributes.State;
          chip.slot = "content-end";
          chip.scale = "m";
          chip.innerText = attributes.State;
          item.label = attributes.Park;
          item.value = index;
          item.description = `${attributes[year].toLocaleString()} visitors`;
          item.addEventListener("click", () => resultClickHandler(result, index));
          item.appendChild(chip);
          document.getElementById("result-list").appendChild(item);
        });

        query.orderByFields = [""];
        const objectIds = await layer.queryTopObjectIds(query);
        layerView.filter = { objectIds };

        determineResetActionState();
      }
Expand

Theme the application

By combining the functionality of the ArcGIS Maps SDK for JavaScript with Calcite Components, you created a rich interactive experience for your users. To go one step further, you will add styles to create a custom look and feel.

  1. Add a CSS class to the calcite-shell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  <calcite-shell class="calcite-tutorial">
  1. Target individual components or sections to add custom styles:
Expand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
    }


    .calcite-tutorial {
      --calcite-color-brand: #039851;
      --calcite-color-brand-hover: #008d52;
    }

    .calcite-tutorial calcite-chip {
      --calcite-color-foreground-2: var(--calcite-color-brand);
      --calcite-color-text-1: white;
      margin-inline-end: 0.75rem;
    }
Expand

Run the app

In CodePen, run your code to display the map.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.

You can no longer sign into this site. Go to your ArcGIS portal or the ArcGIS Location Platform dashboard to perform management tasks.

Your ArcGIS portal

Create, manage, and access API keys and OAuth 2.0 developer credentials, hosted layers, and data services.

Your ArcGIS Location Platform dashboard

Manage billing, monitor service usage, and access additional resources.

Learn more about these changes in the What's new in Esri Developers June 2024 blog post.

Close