Created
July 27, 2023 10:03
-
-
Save jonathanlurie/709b4e6741ef12e60585d7121a698085 to your computer and use it in GitHub Desktop.
Using MapTiler Weather library and SDK to visualise global population density
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 lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Cloud coverage displayed from radar data</title> | |
<script src="https://cdn.maptiler.com/maptiler-sdk-js/v1.1.1/maptiler-sdk.umd.min.js"></script> | |
<link href="https://cdn.maptiler.com/maptiler-sdk-js/v1.1.1/maptiler-sdk.css" rel="stylesheet" /> | |
<script src="https://cdn.maptiler.com/maptiler-weather/v1.0.0/maptiler-weather.umd.min.js"></script> | |
<style> | |
body { margin: 0; padding: 0; font-family: sans-serif; } | |
#map { position: absolute; top: 0; bottom: 0; width: 100%; } | |
#pointer-data { | |
z-index: 1; | |
position: fixed; | |
font-size: 20px; | |
font-weight: 900; | |
margin: 27px 0px 0px 10px; | |
color: #fff; | |
text-shadow: 0px 0px 10px #0007; | |
} | |
#variable-name { | |
z-index: 1; | |
position: fixed; | |
font-size: 20px; | |
font-weight: 500; | |
margin: 5px 0px 0px 10px; | |
color: #fff; | |
text-shadow: 0px 0px 10px #0007; | |
} | |
#time-info { | |
position: fixed; | |
width: 60vw; | |
bottom: 0; | |
z-index: 1; | |
margin: 10px; | |
text-shadow: 0px 0px 5px black; | |
color: white; | |
font-size: 18px; | |
font-weight: 500; | |
text-align: center; | |
left: 0; | |
right: 0; | |
margin: auto; | |
padding: 20px; | |
} | |
#time-text { | |
font-size: 22px; | |
font-weight: 600; | |
} | |
#time-slider { | |
width: 100%; | |
height: fit-content; | |
left: 0; | |
right: 0; | |
z-index: 1; | |
filter: drop-shadow(0 0 7px #000a); | |
margin-top: 10px; | |
} | |
.button { | |
cursor: pointer; | |
width: auto; | |
padding: 8px; | |
border-radius: 3px; | |
font-size: 10px; | |
text-align: center; | |
color: #fff; | |
background: #3174ff; | |
font-family: sans-serif; | |
font-weight: bold; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="time-info"> | |
<span id="time-text"></span> | |
<!-- <button id="play-pause-bt" class="button">Play 3600x</button> --> | |
<input type="range" id="time-slider" min="0" max="0" step="1"> | |
</div> | |
<div id="variable-name">Population per km²</div> | |
<div id="pointer-data"></div> | |
<div id="map"></div> | |
<script> | |
maptilersdk.config.apiKey = 'YOUR_API_KEY'; | |
const map = new maptilersdk.Map({ | |
container: 'map', // container's id or the HTML element to render the map | |
style: maptilersdk.MapStyle.DATAVIZ.DARK, | |
zoom: 1, | |
center: [-15.5, 15.2], | |
hash: true, | |
}); | |
// map.showTileBoundaries = true; | |
const timeInfoContainer = document.getElementById("time-info"); | |
const timeTextDiv = document.getElementById("time-text"); | |
const timeSlider = document.getElementById("time-slider"); | |
// const playPauseButton = document.getElementById("play-pause-bt"); | |
const pointerDataDiv = document.getElementById("pointer-data"); | |
let pointerLngLat = null; | |
timeSlider.min = Date.parse("2000-01-01T00:00:00.000Z"); | |
timeSlider.max = Date.parse("2020-01-01T00:00:00.000Z"); | |
timeSlider.addEventListener("input", etv => { | |
customLayer.setAnimationTime(parseInt(timeSlider.value)) | |
timeTextDiv.innerText = (new Date(parseInt(timeSlider.value)).toString()) | |
}) | |
const customLayer = new maptilerweather.TileLayer('population', {minZoom: 0, maxZoom: 7}, | |
[ | |
new maptilerweather.GradientColoringFragment({ | |
decode: { | |
channel: 'r', | |
min: 0, | |
max: 255, | |
}, | |
stops: maptilerweather.ColorRamp.builtin.TURBO.scale(0, Math.sqrt(45000)), // we want to cap at 45k ppl/sqkm | |
smooth: true, | |
opacity: 1 | |
}), | |
] | |
); | |
// Adding data corresping to different timestamps | |
customLayer.addSource(Date.parse("2000-01-01T00:00:00.000Z"), "https://api.maptiler.com/tiles/4a89ae95-4eb6-44d7-9715-7a53fc564797/{zxy}.png?key=bod4IIn9bwK8mnZIk49v"); // year 2000 | |
customLayer.addSource(Date.parse("2005-01-01T00:00:00.000Z"), "https://api.maptiler.com/tiles/c57a9cc4-cfb0-4738-a9c0-276ac815a423/{zxy}.png?key=bod4IIn9bwK8mnZIk49v"); // year 2005 | |
customLayer.addSource(Date.parse("2010-01-01T00:00:00.000Z"), "https://api.maptiler.com/tiles/3e534c43-a302-4581-b848-9e02c8dea624/{zxy}.png?key=bod4IIn9bwK8mnZIk49v"); // year 2010 | |
customLayer.addSource(Date.parse("2015-01-01T00:00:00.000Z"), "https://api.maptiler.com/tiles/2ea93b9f-64d3-47f6-bf20-093eceae2bcb/{zxy}.png?key=bod4IIn9bwK8mnZIk49v"); // year 2015 | |
customLayer.addSource(Date.parse("2020-01-01T00:00:00.000Z"), "https://api.maptiler.com/tiles/000cdae8-516f-4f4a-81da-c8fcc7d35e9f/{zxy}.png?key=bod4IIn9bwK8mnZIk49v"); // year 2020 | |
// https://api.maptiler.com/tiles/4a89ae95-4eb6-44d7-9715-7a53fc564797/{z}/{x}/{y}.png?key=bod4IIn9bwK8mnZIk49v | |
customLayer.animate(0); | |
map.on('load', function () { | |
// Some layers are adding too much noise, so we remove them | |
map.removeLayer('Building') | |
map.removeLayer('Cemetery') | |
map.removeLayer('Stadium') | |
map.removeLayer('Building top') | |
map.setPaintProperty("Water", 'fill-color', "rgba(0, 0, 0, 0.6)"); | |
// We also want to reduce the opacity of some other layers | |
const roadInfraLayers = [ | |
"Aeroway", | |
"Tunnel outline", | |
"Tunnel path", | |
"Tunnel", | |
"Railway tunnel", | |
"Railway tunnel dash", | |
// "Pier", // fill | |
"Pier road", | |
// "Bridge", // fill | |
"Road network outline", | |
"Road network", | |
"Path outline", | |
"Path", | |
"Railway", | |
"Railway dash", | |
] | |
roadInfraLayers.forEach(el => { | |
map.setPaintProperty(el, 'line-color', "rgba(0, 0, 0, 0.1)"); | |
}) | |
// And eventually adding our population density layer | |
map.addLayer(customLayer, 'Water'); | |
}); | |
map.on('mousemove', (e) => { | |
const values = customLayer.pick(e.lngLat.lng, e.lngLat.lat); | |
if (!values) return; | |
pointerDataDiv.innerText = ~~(values[0] * values[0]) | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment