Skip to content

Instantly share code, notes, and snippets.

@AbelVM
Last active August 10, 2021 12:39
Show Gist options
  • Save AbelVM/fded95cd4699d086cc0e294a00cc440f to your computer and use it in GitHub Desktop.
Save AbelVM/fded95cd4699d086cc0e294a00cc440f to your computer and use it in GitHub Desktop.
[UNTESTED] Live source for MapLibreGL JS

[UNTESTED] Live source for MapLibreGL JS

Lets say you need to refresh your tiles every X seconds to render live information, let's make use of Custom Protocos support.

Let's say your tiles are timestamped using epoc, and the endpoint reacts to URI params like this example

https://example.com/12/2005/1545.pbf?timestamp=1628597308254

Then you just

map.on('load', () => {

  map.addLiveSource(
    'test-livesource', 
    {
      "sourcelayer": 'test-livelayer',
      "tiles": ['live://example.com/{z}/{x}/{y}.pbf'],
      "timeparam": 'timestamp'
      "lifespan": 60000
      ...
    }
  );

  map.addLayer({
    "id": 'livelayer',
    "source": 'test-livesource',
    "source-layer": 'test-livelayer',
    ...
    }
  });

  ...

});

THIS IS UNTESTED

I have no live source to test agaist. I made it just for inspiration, so if you want to use it you will need to work on it... maybe a lot.

/* jshint esversion: 9 */
var tilebelt = require('@mapbox/tilebelt');
const livesource = function (name, options) {
const defaults = {
"timeparam": 'timestamp',
"lifespan": 30000,
"https": true
};
const o = Object.assign({}, defaults, options);
// https://github.com/AbelVM/mapworkbox/blob/05564f27df26b15c16f73085e3a323bc342b8e06/mapworkbox.mjs#L46
const isVisible = zxy => {
const
bb = this.getBounds(),
b = [bb._sw.lng, bb._sw.lat, bb._ne.lng, bb._ne.lat],
tbb = tilebelt.tileToBBOX(zxy),
tf = [
{ x: tbb[0], y: tbb[1] },
{ x: tbb[0], y: tbb[3] },
{ x: tbb[2], y: tbb[1] },
{ x: tbb[2], y: tbb[3] }
],
bf = [
{ x: b[0], y: b[1] },
{ x: b[0], y: b[3] },
{ x: b[2], y: b[1] },
{ x: b[2], y: b[3] }
],
contains = (box, p) => {
if (p.x < box[0] || p.x > box[2] || p.y < box[1] || p.y > box[3]) {
return false;
} else {
return true;
}
};
for (let i = 0; i < 4; i++) {
if (contains(bba, tf[i])) {
return true;
}
}
for (let i = 0; i < 4; i++) {
if (contains(tbb, bf[i])) {
return true;
}
}
};
maplibregl.addProtocol('live', (params, callback) => {
const u = `http${(o.https === false) ? '' : 's'}://${params.url.split('://')[1]}`;
const refresher = url => {
const s = url.split(/\/|\./i);
const l = s.length;
const zxy = s.slice(l - 4, l - 1).map(k => k * 1);
let intvl;
if (isVisible(zxy)) {
fetch(url+`&${o.timeparam}=${Date.now()}`)
.then(tile => {
intvl = setInterval(refresher, o.lifespan, url);
callback(null, tile, null, null);
})
.catch(e => {
clearInterval(intvl);
callback(new Error(e));
});
}else{
clearInterval(intvl);
}
};
refresher(u);
});
};
maplibregl.Map.prototype.addLiveSource = livesource;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment