Category filtering using metadata
Estimated reading time: 2 minutesUse model metadata to create category filtering.
See the manual for setup information.
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link href="https://unpkg.com/[email protected]/dist/maplibre-gl.css" rel="stylesheet" />
<script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
}
#map-container {
height: 100%;
position: relative;
}
#map {
min-height: 500px;
height: 100%;
}
#menu {
font:
12px/20px "Helvetica Neue",
Arial,
Helvetica,
sans-serif;
position: absolute;
width: 175px;
top: 0;
left: 0;
padding: 10px;
background-color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 3px;
padding: 10px;
margin: 10px 10px;
}
#menu input[type="radio"] {
margin: 3px 3px 0px 5px;
}
#menu label {
display: block;
font-weight: bold;
margin: 0 0 5px;
}
.category-filter {
text-transform: capitalize;
}
</style>
</head>
<body>
<div id="map-container">
<div id="map"></div>
<div id="menu"></div>
</div>
<script>
(async () => {
// The property name containing the model id. This property is set by Jawg GIS during import.
const JAWG_MODEL_PROPERTY_NAME = "jawg:model";
// Don't forget to replace <YOUR_GIS_ACCESS_TOKEN> by your own access token
const accessToken = "<YOUR_GIS_ACCESS_TOKEN>";
const mapId = "<YOUR_GIS_MAP_ID>";
const map = new maplibregl.Map({
container: "map",
style: `https://api.jawg.io/gis/maps/${mapId}/versions/latest/style?access-token=${accessToken}`,
zoom: 12,
center: [2.35071554, 48.85826376],
});
const useNavigationControl = new URLSearchParams(window.location.search).get("navigation-control");
if (useNavigationControl !== "false") {
map.addControl(new maplibregl.NavigationControl(), "top-right");
}
// This plugin is used for right to left languages
maplibregl.setRTLTextPlugin("https://unpkg.com/@mapbox/[email protected]/mapbox-gl-rtl-text.min.js");
const metadata = await fetch(
`https://api.jawg.io/gis/maps/${mapId}/versions/latest/metadata?access-token=${accessToken}`,
).then((resp) => resp.json());
// Group model ids by category
const categories = metadata.datasets
.flatMap((dataset) => dataset.models)
.filter((model) => model.metadata.hasOwnProperty("category"))
.reduce((cat, model) => {
(cat[model.metadata["category"]] = cat[model.metadata["category"]] || []).push(model.id);
return cat;
}, {});
// Create the category filter elements
// This is the name of the style layer displaying the points as symbols. Find the layer name in the GIS https://www.jawg.io/gis/styles
const layerName = "paris-places";
const categoryFiltersElement = document.getElementById("menu");
Object.entries(categories).forEach((category) => {
const [categoryName, modelIds] = category;
const input = document.createElement("input");
input.setAttribute("id", categoryName);
input.setAttribute("type", "radio");
input.setAttribute("name", "category-filter");
input.setAttribute("value", categoryName);
// On click we filter points with an "in" expression. See https://maplibre.org/maplibre-gl-js-docs/style-spec/expressions/#in for more informations
const filterExpr = ["in", ["get", JAWG_MODEL_PROPERTY_NAME], ["literal", modelIds]];
input.onclick = () => map.setFilter(layerName, filterExpr);
const label = document.createElement("label");
label.setAttribute("class", "category-filter");
label.appendChild(input);
label.appendChild(document.createTextNode(categoryName));
categoryFiltersElement.appendChild(label);
});
})();
</script>
</body>
</html>