Open simonw opened 4 years ago
https://github.com/kluizeberg/Leaflet.Map-hash does exactly what I want here. It's not rate-limited but it doesn't affect browser history so that's not a problem.
I'm going to enable this by default but allow users to disable it using a plugin configuration setting.
One catch: that plugin doesn't play well with the changes datasette-vega
makes to the URL.
datasette-vega
has functions that specifically try to play well with other plugins through namespacing (the #g.xxx
convention):
https://github.com/simonw/datasette-vega/blob/1db45bd8f1c3c17f8b05aba7159542bcaffffad8/src/DatasetteVega.js#L5-L22
const serialize = (obj, prefix) => Object.keys(obj).filter(key => obj[key]).map(
key => `${prefix}.${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`
).join('&');
const unserialize = (s, prefix) => {
if (s && s[0] === '#') {
s = s.slice(1);
}
if (!s) {
return {};
}
var obj = {};
s.split('&').filter(bit => bit.slice(0, prefix.length + 1) === `${prefix}.`).forEach(bit => {
let pair = bit.split('=');
obj[decodeURIComponent(pair[0]).replace(new RegExp(`^${prefix}\\.`), '')] = decodeURIComponent(pair[1]);
});
return obj;
};
I'm going to use a cm
prefix (for cluster-map).
I had a go at this (I have a datasette deployment with the hashmap working with some edits to the map-hash
branch), but trying to get different plugins operating within the same document.location.hash
is going to take edits.
Specifically in this case: datasette-vega
may have namespacing, but it overrides the entire hashmap.
https://github.com/simonw/datasette-vega/blob/master/src/DatasetteVega.js#L168
document.location.hash = '#' + this.serializeState();
(where serializeState
contains only vega-specific state)
I suspect alterations to the vendored leaflet-map-hash will have to also happen, as that script directly removes any hash data
window.history.replaceState(null, '', '#' + [ // no history
'lng=' + center.lng.toFixed(decimals),
'lat=' + center.lat.toFixed(decimals),
'zoom=' + zoom
].join(';'));
I suspect changes to onPopStateChange
will also need to happen, as you can no longer expect the hash to contain only the state of the current plugin.
onPopStateChange(ev) {
window.lastPopEv = ev;
const expected = '#' + this.serializeState();
if (expected !== document.location.hash && this.state.mark) {
this.setState(
unserialize(document.location.hash, 'g'), this.renderGraph.bind(this)
);
}
}
I can have a go at this, if this isn't in your immediate radar.
I suspect my implementation would require some alteration to the current serialise/unserialise methods, as I think there would have to be context-aware serialisation for the plugins to actually work together.
(I'm also presuming datasette-vega is using g
for graph
, and datasette-cluster-map is using cm
for cluster-map
)
Should this add to the history so that the back button works? Yes, maybe - but only if it's severely rare limited, maybe adding a history checkpoint every few seconds.