Built with blockbuilder.org
Last active
January 23, 2021 13:41
-
-
Save mastersigat/9835cd8398adaceb3b44863681e71d2e to your computer and use it in GitHub Desktop.
#MapboxGL / Clusters thématiques
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
license: mit |
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>Create and style clusters</title> | |
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /> | |
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.js"></script> | |
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.css" rel="stylesheet" /> | |
<style> | |
body { margin: 0; padding: 0; } | |
#map { position: absolute; top: 0; bottom: 0; width: 100%; } | |
</style> | |
</head> | |
<body> | |
<div id="map"></div> | |
<script> | |
mapboxgl.accessToken = 'pk.eyJ1IjoibmluYW5vdW4iLCJhIjoiY2pjdHBoZGlzMnV4dDJxcGc5azJkbWRiYSJ9.o4dZRrdHcgVEKCveOXG1YQ'; | |
var map = new mapboxgl.Map({ | |
container: 'map', | |
style: 'mapbox://styles/mapbox/dark-v10', | |
center: [-1.68, 48.11], | |
zoom: 10.3, | |
pitch : 20, | |
minZoom:10.3, | |
maxZoom:18 | |
}); | |
// CLUSTER THEMATIQUE | |
var mag1 = ['match',['get', 'type'], | |
['Appartement'], | |
false, | |
true | |
]; | |
var mag2 = [ | |
'match', | |
['get', 'type'], | |
['Maison'], | |
false, | |
true | |
]; | |
var colors = ['#79d320', '#fe4fc6']; | |
map.on('load', function () { | |
map.addSource('earthquakes', { | |
'type': 'geojson', | |
'data': 'https://raw.githubusercontent.com/mastersigat/data/main/DVFRM.geojson', | |
'cluster': true, | |
'clusterMaxZoom': 15, | |
'clusterRadius': 50, | |
'clusterProperties': { | |
// keep separate counts for each magnitude category in a cluster | |
'mag1': ['+', ['case', mag1, 1, 0]], | |
'mag2': ['+', ['case', mag2, 1, 0]] | |
} | |
}); | |
map.addLayer({ | |
'id': 'earthquake_label', | |
'type': 'symbol', | |
'source': 'earthquakes', | |
'filter': ['!=', 'cluster', true], | |
'layout': { | |
'text-field': [ | |
'number-format', | |
['get', 'mag'], | |
{ 'min-fraction-digits': 0, 'max-fraction-digits': 0 } | |
], | |
'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'], | |
'text-size': 1 | |
}, | |
'paint': { | |
'text-color': [ | |
'case', | |
['<', ['get', 'mag'], 1], | |
'black', | |
'white' | |
] | |
} | |
}); | |
var markers = {}; | |
var markersOnScreen = {}; | |
function updateMarkers() { | |
var newMarkers = {}; | |
var features = map.querySourceFeatures('earthquakes'); | |
for (var i = 0; i < features.length; i++) { | |
var coords = features[i].geometry.coordinates; | |
var props = features[i].properties; | |
if (!props.cluster) continue; | |
var id = props.cluster_id; | |
var marker = markers[id]; | |
if (!marker) { | |
var el = createDonutChart(props); | |
marker = markers[id] = new mapboxgl.Marker({ | |
element: el | |
}).setLngLat(coords); | |
} | |
newMarkers[id] = marker; | |
if (!markersOnScreen[id]) marker.addTo(map); | |
} | |
for (id in markersOnScreen) { | |
if (!newMarkers[id]) markersOnScreen[id].remove(); | |
} | |
markersOnScreen = newMarkers; | |
} | |
map.on('data', function (e) { | |
if (e.sourceId !== 'earthquakes' || !e.isSourceLoaded) return; | |
map.on('move', updateMarkers); | |
map.on('moveend', updateMarkers); | |
updateMarkers(); | |
}); | |
}); | |
function createDonutChart(props) { | |
var offsets = []; | |
var counts = [ | |
props.mag1, | |
props.mag2 | |
]; | |
var total = 0; | |
for (var i = 0; i < counts.length; i++) { | |
offsets.push(total); | |
total += counts[i]; | |
} | |
var fontSize = | |
total >= 1000 ? 15 : total >= 100 ? 12 : total >= 6 ? 10 : 10; | |
var r = total >= 1000 ? 30 : total >= 100 ? 22 : total >= 10 ? 14 : 18; | |
var r0 = Math.round(r * 0.6); | |
var w = r * 2; | |
var html = | |
'<div><svg width="' + | |
w + | |
'" height="' + | |
w + | |
'" viewbox="0 0 ' + | |
w + | |
' ' + | |
w + | |
'" text-anchor="middle" style="font: ' + | |
fontSize + | |
'px sans-serif; display: block">'; | |
for (i = 0; i < counts.length; i++) { | |
html += donutSegment( | |
offsets[i] / total, | |
(offsets[i] + counts[i]) / total, | |
r, | |
r0, | |
colors[i] | |
); | |
} | |
html += | |
'<circle cx="' + | |
r + | |
'" cy="' + | |
r + | |
'" r="' + | |
r0 + | |
'" fill="white" /><text dominant-baseline="central" transform="translate(' + | |
r + | |
', ' + | |
r + | |
')">' + | |
total.toLocaleString() + | |
'</text></svg></div>'; | |
var el = document.createElement('div'); | |
el.innerHTML = html; | |
return el.firstChild; | |
} | |
function donutSegment(start, end, r, r0, color) { | |
if (end - start === 1) end -= 0.00001; | |
var a0 = 2 * Math.PI * (start - 0.25); | |
var a1 = 2 * Math.PI * (end - 0.25); | |
var x0 = Math.cos(a0), | |
y0 = Math.sin(a0); | |
var x1 = Math.cos(a1), | |
y1 = Math.sin(a1); | |
var largeArc = end - start > 0.5 ? 1 : 0; | |
return [ | |
'<path d="M', | |
r + r0 * x0, | |
r + r0 * y0, | |
'L', | |
r + r * x0, | |
r + r * y0, | |
'A', | |
r, | |
r, | |
0, | |
largeArc, | |
1, | |
r + r * x1, | |
r + r * y1, | |
'L', | |
r + r0 * x1, | |
r + r0 * y1, | |
'A', | |
r0, | |
r0, | |
0, | |
largeArc, | |
0, | |
r + r0 * x0, | |
r + r0 * y0, | |
'" fill="' + color + '" />' | |
].join(' '); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment