Last active
February 26, 2022 16:10
-
-
Save kkdd/d18eb75331b2271ca9ab0b0e13be20d6 to your computer and use it in GitHub Desktop.
Leaflet map: reading GeoJSONL/flatgeobuf files dropped-onto
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
<html lang="en"> | |
<head> | |
<title>streaming GeoJSONL/flatgeobuf by dropping-on</title> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"> | |
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> | |
<script src="https://unpkg.com/flatgeobuf@3.21.3/dist/flatgeobuf-geojson.min.js"></script> | |
<style> | |
body { margin:0; padding:0; } | |
#map { position:absolute; top:0; bottom:0; width:100%; } | |
</style> | |
</head> | |
<body> | |
<div id='map'></div> | |
<script> | |
const pointStyle = {radius:2, color:"#a000a0", opacity:0.6}; | |
const otherStyle = {weight:1, color:"#0000ff", opacity:0.6}; | |
const map = L.map('map').setView([40, 0], 2); | |
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
maxZoom: 19, | |
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' | |
}).addTo(map); | |
map.createPane("pane620").style.zIndex = 620; | |
const geojsonStyle = feature => { | |
switch(feature.geometry.type) { | |
case "Point": | |
case "MultiPoint": | |
return {radius:pointStyle["radius"], fillColor:pointStyle["color"], fillOpacity:pointStyle["opacity"], weight:0, color:"#000000", opacity:0}; | |
} | |
return {...otherStyle, fillColor: otherStyle["color"], fillOpacity: otherStyle["opacity"]*0.3}; | |
} | |
const setDropArea = (area) => { | |
const draw = file => drawIterator(getIterator(file.stream(), file.name)); | |
area.ondragover = () => false; | |
area.ondrop = event => { | |
[...event.dataTransfer.files].forEach(draw); | |
return false; | |
}; | |
} | |
setDropArea(document.getElementById('map')); | |
const drawIterator = async (iter) => { | |
if(iter==undefined) return; | |
const layerOptions = { | |
pointToLayer: (_, latlng) => L.circleMarker(latlng, {pane: "pane620"}), | |
style: geojsonStyle | |
}; | |
const drawFeatures = (feas) => L.geoJSON(feas, layerOptions).addTo(map); | |
const wait = () => new Promise(resolve => setTimeout(resolve, 0)); | |
for await (const features of iter) { | |
await wait(); | |
drawFeatures(features); | |
} | |
}; | |
const getIterator = (stream, name) => { | |
const extension = name.split('.').pop(); | |
switch(extension) { | |
case "jsonl": | |
case "geojsonl": | |
return readLines(stream, JSON.parse); | |
case "fgb": | |
const numBunch = 8; | |
return bunchIterator(flatgeobuf.deserialize(stream), numBunch); | |
} | |
} | |
async function* readLines(readableStream, funcYield = (x) => x) { | |
const reader = readableStream.getReader(); | |
const decoder = new TextDecoder('utf-8'); | |
let remaining = ""; | |
try { | |
while (true) { | |
const {done, value} = await reader.read(); | |
if (done) return; | |
const lines = (remaining + decoder.decode(value)).split("\n"); | |
remaining = lines.pop(); | |
yield lines.map(funcYield); | |
} | |
} | |
finally { | |
reader.releaseLock(); | |
} | |
} | |
async function* bunchIterator(iter, numBunch = 1) { | |
let bunch = []; | |
for await (let e of iter) { | |
bunch.push(e); | |
if (bunch.length >= numBunch) {yield bunch; bunch = [];} | |
} | |
yield bunch; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment