Skip to content

Instantly share code, notes, and snippets.

@kkdd
Last active March 24, 2024 03:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kkdd/34f691afbf089e92a2cb4b1cca4cb582 to your computer and use it in GitHub Desktop.
Save kkdd/34f691afbf089e92a2cb4b1cca4cb582 to your computer and use it in GitHub Desktop.
deck.gl trips-layer animation: reading trips files dropped-onto

getting trips-json files

$ cat trips.json 
[{"vendor":0,"path":[[139.8007914,35.5144044],[139.9108676,35.4396142]],"timestamps":[0,600]},{"vendor":1,"path":[[139.9108139,35.439529],[139.8008987,35.5140027]],"timestamps":[0,600]}]
$ wget https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/trips/trips-v7.json
<html>
<head>
<script src="https://unpkg.com/deck.gl@^8.6.5/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/carto@^8.6.5/dist.min.js"></script>
<script src="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.js"></script>
<link href="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@5/turf.min.js"></script>
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; background-color: black;}
</style>
</head>
<body><div id='map'></div></body>
<script type="text/javascript">
const ANIMATION_SPEED = 20;
const INITIAL_PAUSE = 1;
const colors = {0: [253, 128, 93], 'others': [23, 184, 190]};
const getColor = i => {
if (typeof i === 'undefined' || !(i in colors)) {i = 'others'};
return colors[i];
}
new deck.DeckGL({
container: 'map',
mapStyle: deck.carto.BASEMAP.DARK_MATTER,
initialViewState: {longitude: 60, latitude: 0, zoom: 1}
});
drawTrips([{"vendor":0,"path":[[139.8007914,35.5144044],[139.9108676,35.4396142]],"timestamps":[0,600]},{"vendor":1,"path":[[139.9108139,35.439529],[139.8008987,35.5140027]],"timestamps":[0,600]}]);
const setDropArea = (area) => {
area.ondragover = () => false;
area.ondrop = async event => {
event.preventDefault();
const promises = [];
for (const file of event.dataTransfer.files) {
if (file.name.split('.').pop() == 'json') {
promises.push(file.text());
}
}
const results = await Promise.all(promises);
drawTrips(results.map(JSON.parse).flat());
return false;
};
}
setDropArea(document.getElementById('map'));
function bbox(json) {
let points = [];
for (let e of json){
points = points.concat(e.path);
}
const b = turf.bbox(turf.multiPoint(points))
return [[b[0], b[3]], [b[2], b[1]]];
}
function interval_timestamps(json) {
let timestamps = [];
for (let e of json){
timestamps = timestamps.concat(e.timestamps);
}
return [Math.min(...timestamps), Math.max(...timestamps)];
}
function drawTrips(json) {
const interval = interval_timestamps(json);
interval[0] -= ANIMATION_SPEED * INITIAL_PAUSE;
const view = new deck.WebMercatorViewport({width: document.body.clientWidth, height: document.body.clientHeight});
deck.carto.setDefaultCredentials({
username: 'public',
apiKey: 'default_public',
});
const deckgl = new deck.DeckGL({
container: 'map',
mapStyle: deck.carto.BASEMAP.DARK_MATTER,
initialViewState: view.fitBounds(bbox(json)),
controller: true
});
const map = deckgl.getMapboxMap();
map.addControl(new mapboxgl.ScaleControl({
maxWidth: 160,
unit: 'metric'
}));
let time = 0;
const RATE_ANIMATION_FRAME = 50;
function animate() {
time = (time + ANIMATION_SPEED/RATE_ANIMATION_FRAME) % (interval[1] - interval[0]);
window.requestAnimationFrame(animate);
}
setInterval(() => {
deckgl.setProps({
layers: [
new deck.TripsLayer({
id: 'trips-layer',
data: json,
getPath: d => d.path,
getTimestamps: d => d.timestamps,
getColor: d => getColor(d.vendor),
opacity: 0.8,
widthMinPixels: 3,
jointRounded: true,
capRounded: true,
trailLength: 180,
currentTime: time + interval[0],
shadowEnabled: false
})
]
});
}, 50);
window.requestAnimationFrame(animate);
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment