-
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cluster.html): add example HTML file to demonstrate clustering w…
…ith MapLibre GL JS for visualizing earthquake data
- Loading branch information
Showing
1 changed file
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Create and style clusters</title> | ||
<meta property="og:description" content="Use MapLibre GL JS' built-in functions to visualize points as clusters." /> | ||
<meta charset='utf-8'> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css' /> | ||
<script src='https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js'></script> | ||
<style> | ||
body { margin: 0; padding: 0; } | ||
html, body, #map { height: 100%; } | ||
</style> | ||
</head> | ||
<body> | ||
<div id="map"></div> | ||
|
||
<script> | ||
const map = new maplibregl.Map({ | ||
container: 'map', | ||
style: 'https://tiles.openfreemap.org/styles/positron', | ||
center: [-103.59179687498357, 40.66995747013945], | ||
zoom: 3 | ||
}); | ||
|
||
map.on('load', () => { | ||
// Add a new source from our GeoJSON data and | ||
// set the 'cluster' option to true. GL-JS will | ||
// add the point_count property to your source data. | ||
map.addSource('earthquakes', { | ||
type: 'geojson', | ||
// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes | ||
// from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program. | ||
data: 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', | ||
cluster: true, | ||
clusterMaxZoom: 14, // Max zoom to cluster points on | ||
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50) | ||
}); | ||
|
||
map.addLayer({ | ||
id: 'clusters', | ||
type: 'circle', | ||
source: 'earthquakes', | ||
filter: ['has', 'point_count'], | ||
paint: { | ||
// Use step expressions (https://maplibre.org/maplibre-style-spec/#expressions-step) | ||
// with three steps to implement three types of circles: | ||
// * Blue, 20px circles when point count is less than 100 | ||
// * Yellow, 30px circles when point count is between 100 and 750 | ||
// * Pink, 40px circles when point count is greater than or equal to 750 | ||
'circle-color': [ | ||
'step', | ||
['get', 'point_count'], | ||
'#51bbd6', | ||
100, | ||
'#f1f075', | ||
750, | ||
'#f28cb1' | ||
], | ||
'circle-radius': [ | ||
'step', | ||
['get', 'point_count'], | ||
20, | ||
100, | ||
30, | ||
750, | ||
40 | ||
] | ||
} | ||
}); | ||
|
||
map.addLayer({ | ||
id: 'cluster-count', | ||
type: 'symbol', | ||
source: 'earthquakes', | ||
filter: ['has', 'point_count'], | ||
layout: { | ||
'text-field': '{point_count_abbreviated}', | ||
'text-font': ['Noto Sans Regular'], | ||
'text-size': 12 | ||
} | ||
}); | ||
|
||
map.addLayer({ | ||
id: 'unclustered-point', | ||
type: 'circle', | ||
source: 'earthquakes', | ||
filter: ['!', ['has', 'point_count']], | ||
paint: { | ||
'circle-color': '#11b4da', | ||
'circle-radius': 4, | ||
'circle-stroke-width': 1, | ||
'circle-stroke-color': '#fff' | ||
} | ||
}); | ||
|
||
// inspect a cluster on click | ||
map.on('click', 'clusters', async (e) => { | ||
const features = map.queryRenderedFeatures(e.point, { | ||
layers: ['clusters'] | ||
}); | ||
const clusterId = features[0].properties.cluster_id; | ||
const zoom = await map.getSource('earthquakes').getClusterExpansionZoom(clusterId); | ||
map.easeTo({ | ||
center: features[0].geometry.coordinates, | ||
zoom | ||
}); | ||
}); | ||
|
||
// When a click event occurs on a feature in | ||
// the unclustered-point layer, open a popup at | ||
// the location of the feature, with | ||
// description HTML from its properties. | ||
map.on('click', 'unclustered-point', (e) => { | ||
const coordinates = e.features[0].geometry.coordinates.slice(); | ||
const mag = e.features[0].properties.mag; | ||
let tsunami; | ||
|
||
if (e.features[0].properties.tsunami === 1) { | ||
tsunami = 'yes'; | ||
} else { | ||
tsunami = 'no'; | ||
} | ||
|
||
// Ensure that if the map is zoomed out such that | ||
// multiple copies of the feature are visible, the | ||
// popup appears over the copy being pointed to. | ||
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) { | ||
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360; | ||
} | ||
|
||
new maplibregl.Popup() | ||
.setLngLat(coordinates) | ||
.setHTML( | ||
`magnitude: ${mag}<br>Was there a tsunami?: ${tsunami}` | ||
) | ||
.addTo(map); | ||
}); | ||
|
||
map.on('mouseenter', 'clusters', () => { | ||
map.getCanvas().style.cursor = 'pointer'; | ||
}); | ||
map.on('mouseleave', 'clusters', () => { | ||
map.getCanvas().style.cursor = ''; | ||
}); | ||
}); | ||
</script> | ||
</body> | ||
</html> |