In this guide, you will learn how to create a map and a Category Widget showing data coming from the map, and reacting to changes in the map, as well as filtering data by using Category Widget.
We will use CARTO-VL and Airship to show how they work together properly.
We will start from scratch creating an empty index.html
file with this scaffolding for this guide.
1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body class="as-app-body"></body>
</html>
To use Airship styles and components we need to include them in our HTML. Since we just want to create a simple app we are going to include Airship components and styles through a CDN by including the following snippet in the <head>
of our application:
1
2
3
4
5
6
<!-- Include CSS -->
<link rel="stylesheet" href="https://libs.cartocdn.com/airship-style/v2.4.1/airship.css">
<!-- Include Icons -->
<link rel="stylesheet" href="https://libs.cartocdn.com/airship-icons/v2.4.1/icons.css">
<!-- Include Web Components -->
<script src="https://libs.cartocdn.com/airship-components/v2.4.1/airship.js"></script>
As pointed in the CARTO-VL docs we can also include CARTO-VL in our app using a CDN
1
2
3
4
5
6
<head>
<!-- Include CARTO VL JS -->
<script src="https://libs.cartocdn.com/carto-vl/v1.4.4/carto-vl.min.js"></script>
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.js"></script>
</head>
A basic layout will just include a container for our map and a sidebar for our future widget.
An airship app always has a container for our main content with .as-content
class and a main
tag with the .as-main
class.
In this case we add a as-map-area
where the map will be displayed and a as-sidebar
to contain our widgets.
1
2
3
4
5
6
7
8
9
10
11
12
<div class="as-app">
<div class="as-content">
<main class="as-main">
<div class="as-map-area">
<div id="map"></div>
</div>
</main>
<aside class="as-sidebar as-sidebar--right">
</aside>
</div>
</div>
For this guide we are going to use the js code of the CARTO-VL basic example at this point you should see a map with an white space on the right.
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
<script>
const map = new mapboxgl.Map({
container: 'map',
style: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',
center: [0, 30],
zoom: 2,
scrollZoom: false,
dragRotate: false,
touchZoomRotate: false
});
const nav = new mapboxgl.NavigationControl({
showCompass: false
});
map.addControl(nav, 'top-left');
// Define user
carto.setDefaultAuth({
user: 'cartovl',
apiKey: 'default_public'
});
// Define layer
const source = new carto.source.Dataset('ne_10m_populated_places_simple');
const viz = new carto.Viz();
const layer = new carto.Layer('layer', source, viz);
layer.addTo(map, 'watername_ocean');
layer.on('loaded', hideLoader);
function hideLoader() {
document.getElementById('loader').style.opacity = '0';
}
</script>
Adding a Category Widget is as simple as including <as-category-widget>
tag within our as-sidebar
element, setting the options you prefer.
1
2
3
4
5
6
7
<aside class="as-sidebar as-sidebar--right">
<as-category-widget
id="cities-widget"
heading="Populated places"
description="Maximun population of the most pouplated cities">
</as-category-widget>
</aside>
The category widget will not show any data unless we provide them. For this example, we will simply show the list sorted by the maximum population of cities that can be seen on the map.
To do this we will use the viewportFeatures expression which allows us to get the list of the visible features in the viewport.
1
2
3
4
// We update the viz to get a new @cities variable with the list of visible cities
const viz = new carto.Viz(`
@cities: viewportFeatures($pop_max, $name),
`);
Then we get a reference to the widget to update the data on every map change:
1
2
const $categoryWidget = document.querySelector('#cities-widget');
layer.on('updated', updateWidgets);
The updateWidgets function will:
{name, value}
1
2
3
4
5
6
7
8
function updateWidgets() {
$categoryWidget.categories = viz.variables.cities.value
.map(feature => ({
name: feature.properties.name,
value: feature.properties.pop_max,
}))
.sort((a, b) => b.value - a.value);
};