1
0
Fork 0
mirror of https://github.com/noerw/sentinel_fire synced 2025-03-13 02:30:27 +01:00
sentinel2_pipeline/visualization/leaflet_villages.html.template

153 lines
5.5 KiB
Text

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<style>
html, body, #map {
margin: 0;
padding: 0;
height: 100%;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" crossorigin=""/>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/GuillaumeAmat/leaflet-overpass-layer/dist/OverPassLayer.css" type="text/css">
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet-src.js" crossorigin=""></script>
<!-- OSM overlay -->
<script src="https://cdn.jsdelivr.net/gh/GuillaumeAmat/leaflet-overpass-layer/dist/OverPassLayer.bundle.js" crossorigin=""></script>
<!-- geotiff visualization -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.3.4/chroma.min.js"></script>
<script src="https://npmcdn.com/geotiff@0.3.6/dist/geotiff.js"></script>
<script src="https://unpkg.com/leaflet-canvaslayer-field@1.4.1/dist/leaflet.canvaslayer.field.js" crossorigin=""></script>
<!-- for the time slider -->
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<script src="https://cdn.jsdelivr.net/gh/dwilhelm89/LeafletSlider/dist/leaflet.SliderControl.min.js" crossorigin=""></script>
<!-- the variables below are inserted via %%templating%% -->
<!-- IMPORTANT! TIFs must be in EPGS:4326! -->
<script type="application/javascript">
const aoi = %%AOI%%
const tifs = [%%TIFS%%].sort()
</script>
<script type="application/javascript">
const initialZoom = 12
const bgOsm = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
})
const bgSat = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png', {
attribution: 'Sources: Esri, DigitalGlobe, GeoEye, i-cubed, USDA FSA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community'
})
const aoiLayer = L.geoJSON(aoi, {
style: {
interactive: false,
fillColor: '#aaa',
opacity: 0,
}
})
const map = L.map('map', { scale: true })
.addLayer(bgSat)
.addLayer(aoiLayer)
.setView(aoiLayer.getBounds().getCenter(), initialZoom)
.setMaxBounds(aoiLayer.getBounds())
// load village / city placemarks from OSM
const villagesLayer = new L.OverPassLayer({
loadedBounds: [aoiLayer.getBounds()],
minZoom: initialZoom,
minZoomIndicatorEnabled: false,
endPoint: 'https://overpass-api.de/api/',
query: 'node [place~"(village|town|suburb|city)"]({{bbox}}); out;',
// customize marker size & popup content
onSuccess(data) {
for (let i = 0; i < data.elements.length; i++) {
const e = data.elements[i]
if (e.id in this._ids) continue
this._ids[e.id] = true
const marker = L.circle(L.latLng(e.lat, e.lon), 100, {
stroke: false,
fillColor: 'lightblue',
fillOpacity: 0.8,
})
const popupDiv = document.createElement('div');
popupDiv.innerHTML = `${e.tags['place']}:&nbsp;&nbsp;<b>${e.tags['name']}</b>&nbsp;&nbsp;(${e.tags['name:en']})`
const popup = L.popup().setContent(popupDiv)
marker.bindPopup(popup);
this._markers.addLayer(marker);
}
},
}).addTo(map)
L.control.scale().addTo(map)
L.control.layers({
'OpenStreetMap Dark': bgOsm,
'ESRI World Imagery': bgSat,
}, {
'area of interest': aoiLayer,
// 'dNBR timeseries': timeseriesLayer, // buggy
'OSM villages': villagesLayer,
}).addTo(map);
function tif2Layer (url) {
// extract date from filename
const time = url.split('/').pop().split('.')[0]
console.log(`fetching TIF for ${time} at ${url}`)
return fetch(url)
.then(res => res.arrayBuffer())
.then(tifData => {
console.log(`parsing TIF at ${url}`)
const scalarField = L.ScalarField.fromGeoTIFF(tifData, bandIndex = 0)
console.log(`creating layer for TIF at ${url}`)
const layer = L.canvasLayer.scalarField(scalarField, {
time, // time is used as display name in timeslider plugin
color: chroma.scale(['#ddc739', '#e59f27', '#f21602']).domain([1, 3]),
opacity: 0.7
})
layer.setFilter(v => v >= 1)
layer.on('click', function (e) {
if (e.value !== null) {
const dnbr = e.value.toFixed(0)
const popup = L.popup()
.setLatLng(e.latlng)
.setContent(`<span class="popupText">dNBR: ${dnbr}</span>`)
.openOn(map)
}
})
return layer
})
}
// load all TIF files
Promise.all(tifs.map(url => tif2Layer(url)))
// create a layer group for the time slider plugin with all TIFs
.then(layers => {
const sliderControl = L.control.sliderControl({
layer: L.layerGroup(layers),
follow: true
})
map.addControl(sliderControl)
sliderControl.startSlider()
})
.catch(console.error)
</script>
</body>
</html>