Built with blockbuilder.org
Created
January 21, 2021 17:41
-
-
Save mastersigat/f76282a6a336ff954fc5b7a037b8da62 to your computer and use it in GitHub Desktop.
MapboxGL / Variation Cartographique
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 a heatmap layer</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.0/mapbox-gl.js"></script> | |
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css" rel="stylesheet" /> | |
<style> | |
body { margin:0; padding:0; } | |
#map { position:absolute; top:0; bottom:0; width:100%; z-index: 1} | |
.map-overlay-2 { | |
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; | |
position: absolute; | |
width: 400 px; | |
top: 50px; | |
left: 30px; | |
padding: 2px; | |
z-index: 2 | |
} | |
.map-overlay-2 .map-overlay-inner { | |
background-color: #fff; | |
box-shadow:0 1px 2px rgba(0, 0, 0, 0.10); | |
border-radius: 3px; | |
padding: 10px; | |
margin-bottom: 10px; | |
} | |
.map-overlay-inner fieldset { | |
border: none; | |
padding: 0; | |
margin: 0 0 10px; | |
} | |
.map-overlay-inner .categoryLabel { | |
display: block; | |
font-weight: bold; | |
margin: 0 0 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id='map'> | |
<div class='map-overlay-2 top'> | |
<div class='map-overlay-inner'> | |
<fieldset> | |
<label class="categoryLabel">Dotmap</label> | |
<div> | |
<input type="checkbox" id="classiqueCB" value="classique" onchange="switchlayer('classique')" /> | |
<label for="classiqueCB">Classique</label> | |
</div> | |
<div> | |
<input type="checkbox" id="categoriseCB" value="categorise" onchange="switchlayer('categorise')" /> | |
<label for="categoriseCB">Catégorisées</label> | |
</div> | |
<div> | |
<input type="checkbox" id="gradueeCB" value="graduee" onchange="switchlayer('graduee')" /> | |
<label for="gradueeCB">Graduées</label> | |
</div> | |
<div> | |
<input type="checkbox" id="tailleCB" value="taille" onchange="switchlayer('taille')" /> | |
<label for="tailleCB">Cercle gradués</label> | |
</div> | |
<div> | |
<input type="checkbox" id="combineCB" value="combine" onchange="switchlayer('combine')" /> | |
<label for="combineCB">Cercle gradués et variation de couleur</label> | |
</div> | |
</fieldset> | |
<fieldset> | |
<label class="categoryLabel">Heatmap</label> | |
<div> | |
<input type="checkbox" id="heatmapCB" value="heatmap" onchange="switchlayer('heatmap')" /> | |
<label for="heatmapCB">Classique</label> | |
</div> | |
<div> | |
<input type="checkbox" id="heatmap3CB" value="heatmap3" onchange="switchlayer('heatmap3')" /> | |
<label for="heatmap3CB">Pondérée par le prix de vente</label> | |
</div> | |
<div> | |
<input type="checkbox" id="heatmap2CB" value="heatmap2" onchange="switchlayer('heatmap2')" /> | |
<label for="heatmap2CB">Pondérée par le prix au m2</label> | |
</div> | |
</fieldset> | |
<fieldset> | |
<label class="categoryLabel">Cluster</label> | |
<div> | |
<input type="checkbox" id="clusterCB" value="cluster" onchange="switchlayer('cluster')" /> | |
<label for="cluster">Clusters classiques</label> | |
</div> | |
<div> | |
<input type="checkbox" id="earthquake_labelCB" value="earthquake_label" onchange="switchlayer('earthquake_label')" /> | |
<label for="earthquake_labelCB">Clusters thématiquees</label> | |
</div> | |
</fieldset> | |
</div> | |
</div> | |
</div> | |
<script> | |
mapboxgl.accessToken = 'pk.eyJ1IjoibWFzdGVyc2lnYXQiLCJhIjoiY2tpaXJsaTNsMmEyZjJ4cGU2dmoxMHBoeiJ9.hn9mX2nLGbnlFflMLfme8w'; | |
var map = new mapboxgl.Map({ | |
container: 'map', | |
style: 'mapbox://styles/mastersigat/cj1dmrd0700gp2rqmxdtjmjiw', | |
center: [-1.68, 48.11], | |
zoom: 10.3, | |
pitch : 20, | |
minZoom:10.3, | |
maxZoom:18 | |
}); | |
map.on('load', function() { | |
// LIMITES RM | |
map.addSource('limites', { | |
type: 'vector', | |
url: 'mapbox://mastersigat.52ukmnob'}); | |
map.addLayer({ | |
'id': 'communeslimites', | |
'type': 'line', | |
'source': 'limites', | |
'source-layer': 'limites-communales-referentie-14yj4j', | |
'layout': {'visibility': 'visible', | |
'line-join': 'round','line-cap': 'round'}, | |
'paint': {'line-color': '#ffffff'}, | |
'maxzoom':14 | |
}); | |
map.setPaintProperty('communeslimites', 'line-width', ["interpolate",["exponential", 1],["zoom"],11,0.5,14,0.7]); | |
// SOURCE DVF | |
map.addSource('DVF', { | |
type: 'vector', | |
url: 'mapbox://mastersigat.csfnbrl5'}); | |
// DOTMAP Classique | |
map.addLayer({ | |
'id': 'classique', | |
'type': 'circle', | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
'paint': {'circle-blur':0, 'circle-radius': {'base': 1.15,'stops': [[11, 1], [18, 5]]}, 'circle-color': '#3bb2d0'} | |
}); | |
// DOTMAP CATEGORISEE | |
map.addLayer({ | |
'id': 'categorise', | |
'type': 'circle', | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
'paint': {'circle-radius': {'base': 1.15, 'stops': [[11, 1.2], [18, 5]]}, | |
'circle-color': ['match', ['get', 'type'], | |
'Maison', '#79d320', 'Appartement', '#fe4fc6', '#ccc']} | |
}); | |
// DOTMAP GRADUEE COULEUR | |
map.addLayer({ | |
'id': 'graduee', | |
'type': 'circle', | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
'paint': {'circle-radius': {'base': 1.15, 'stops': [[11, 1.2], [18, 5]]}, | |
'circle-color': {property: 'Prixm2OK',type: 'exponential', | |
stops: [ | |
[0, '#1a9641'], | |
[1800, '#a6d96a'], | |
[2180, '#ffffbf'], | |
[2520, '#fdae61'], | |
[3000, '#d7191c'],] | |
}} | |
}); | |
// DOTMAP GRADUEE TAILLE | |
map.addLayer({ | |
'id': 'taille', | |
'type': 'circle', | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
'paint': {'circle-color': '#ffd100', | |
'circle-radius': { property: 'PrixOK', stops: [ [{zoom: 11, value: 10000}, 0.2], [{zoom: 11, value: 1600000}, 3], [{zoom: 18, value: 10000}, 2], [{zoom: 18, value: 1600000}, 15] ]}, | |
'circle-opacity': 0.8} | |
}); | |
// DOTMAP GRADUEE TAILLE + COULEUR | |
map.addLayer({ | |
'id': 'combine', | |
'type': 'circle', | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
'paint': {'circle-color': {property: 'Prixm2OK',type: 'exponential', | |
stops: [ | |
[0, '#1a9850'], | |
[2000, '#66bd63'], | |
[2250, '#a6d96a'], | |
[2500, '#d9ef8b'], | |
[2750, '#fee08b'], | |
[3000, '#fdae61'], | |
[3250, '#f46d43'], | |
[3500, '#d73027'],]}, | |
'circle-radius': { property: 'PrixOK', stops: [ [{zoom: 11, value: 10000}, 0.3], [{zoom: 11, value: 1600000}, 3.5], [{zoom: 18, value: 10000}, 2], [{zoom: 18, value: 1600000}, 15] ]}, | |
'circle-opacity': 0.8} | |
}); | |
// HEATMAP CLASSIQUE | |
map.addLayer({ | |
"id": "heatmap", | |
"type": "heatmap", | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
"paint": { | |
// Increase the heatmap color weight weight by zoom level | |
// heatmap-intensity is a multiplier on top of heatmap-weight | |
"heatmap-intensity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
16,2 | |
], | |
// Color ramp for heatmap. Domain is 0 (low) to 1 (high). | |
// Begin color ramp at 0-stop with a 0-transparancy color | |
// to create a blur-like effect. | |
"heatmap-color": [ | |
"interpolate", | |
["linear"], | |
["heatmap-density"], | |
0, "rgba(33,102,172,0)", | |
0.3, "rgb(103,169,207)", | |
0.5, "rgb(209,229,240)", | |
0.7, "rgb(253,219,199)", | |
0.9, "rgb(239,138,98)", | |
1, "rgb(178,24,43)" | |
], | |
// Adjust the heatmap radius by zoom level | |
"heatmap-radius": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 3, 17,20 | |
], | |
// Transition from heatmap to circle layer by zoom level | |
"heatmap-opacity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
15, 0.7 | |
], | |
} | |
} | |
); | |
// HEATMAP PONDERE | |
map.addLayer({ | |
"id": "heatmap2", | |
"type": "heatmap", | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
"paint": { | |
'heatmap-weight': [ | |
'interpolate',['linear'],['get', 'Prixm2OK'],1000,0, 2000,0.2, 3000,0.5,5000,0.7], | |
// Increase the heatmap color weight weight by zoom level | |
// heatmap-intensity is a multiplier on top of heatmap-weight | |
"heatmap-intensity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
16,2 | |
], | |
// Color ramp for heatmap. Domain is 0 (low) to 1 (high). | |
// Begin color ramp at 0-stop with a 0-transparancy color | |
// to create a blur-like effect. | |
"heatmap-color": [ | |
"interpolate", | |
["linear"], | |
["heatmap-density"], | |
0, "rgba(33,102,172,0)", | |
0.3, "rgb(145,207,96)", | |
0.8, "rgb(217,239,139)", | |
0.9, "rgb(253,224,239)", | |
0.95, "rgb(233,163,201)", | |
1, "rgb(197,27,125)" | |
], | |
// Adjust the heatmap radius by zoom level | |
"heatmap-radius": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 5, 17,20 | |
], | |
// Transition from heatmap to circle layer by zoom level | |
"heatmap-opacity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
15, 0.7 | |
], | |
} | |
} | |
); | |
// HEATMAP PONDERE PRIX | |
map.addLayer({ | |
"id": "heatmap3", | |
"type": "heatmap", | |
'source': 'DVF', | |
'source-layer': 'DVFRM-3fci8x', | |
'layout': {'visibility': 'none'}, | |
"paint": { | |
'heatmap-weight': [ | |
'interpolate',['linear'],['get', 'PrixOK'],100000,0,1600000,1], | |
// Increase the heatmap color weight weight by zoom level | |
// heatmap-intensity is a multiplier on top of heatmap-weight | |
"heatmap-intensity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
16,2 | |
], | |
// Color ramp for heatmap. Domain is 0 (low) to 1 (high). | |
// Begin color ramp at 0-stop with a 0-transparancy color | |
// to create a blur-like effect. | |
"heatmap-color": [ | |
"interpolate", | |
["linear"], | |
["heatmap-density"], | |
0, "rgba(33,102,172,0)", | |
0.3, "rgb(145,207,96)", | |
0.5, "rgb(217,239,139)", | |
0.7, "rgb(254,224,139)", | |
0.9, "rgb(252,141,89)", | |
1, "rgb(215,48,39)" | |
], | |
// Adjust the heatmap radius by zoom level | |
"heatmap-radius": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 5, 17,20 | |
], | |
// Transition from heatmap to circle layer by zoom level | |
"heatmap-opacity": [ | |
"interpolate", | |
["linear"], | |
["zoom"], | |
10.3, 1, | |
15, 0.7 | |
], | |
} | |
} | |
); | |
// CLUSTER | |
map.addSource('DVFGIT', { | |
type: 'geojson', | |
data: 'https://raw.githubusercontent.com/mastersigat/data/main/DVFRM.geojson', | |
cluster: true, | |
clusterMaxZoom: 17, | |
clusterRadius: 40 | |
}); | |
map.addLayer({ | |
'id': 'cluster', | |
'type': 'circle', | |
'source': 'DVFGIT', | |
'layout': {'visibility': 'none'}, | |
filter: ['has', 'point_count'], | |
paint: {'circle-color': ['step',['get', 'point_count'], | |
'#51bbd6',50, | |
'#f1f075',500, | |
'#f28cb1'], | |
'circle-radius': ['step',['get', 'point_count'],5,50, 10,100,20,1000,30]} | |
}); | |
// Configuration etiquette | |
map.addLayer({ id: 'cluster-count', | |
type: 'symbol', | |
source: 'DVFGIT', | |
filter: ['has', 'point_count'], | |
layout: {'visibility': 'none', 'text-field': '{point_count_abbreviated}', 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],'text-size': 12} | |
}); | |
switchlayer = function (lname) { | |
if (document.getElementById(lname + "CB").checked) { | |
map.setLayoutProperty(lname, 'visibility', 'visible'); | |
} else { | |
map.setLayoutProperty(lname, 'visibility', 'none'); | |
} | |
} | |
}); | |
// 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': {'visibility': 'none', '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(); | |
}); | |
switchlayer = function (lname) { | |
if (document.getElementById(lname + "CB").checked) { | |
map.setLayoutProperty(lname, 'visibility', 'visible'); | |
} else { | |
map.setLayoutProperty(lname, 'visibility', 'none'); | |
} | |
} | |
}); | |
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