Skip to content

Instantly share code, notes, and snippets.

@jonathanlurie
Created July 27, 2023 10:03
Show Gist options
  • Save jonathanlurie/709b4e6741ef12e60585d7121a698085 to your computer and use it in GitHub Desktop.
Save jonathanlurie/709b4e6741ef12e60585d7121a698085 to your computer and use it in GitHub Desktop.
Using MapTiler Weather library and SDK to visualise global population density
<!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