Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update fragment hash in URL so you can link to zoomed map #13

Open
simonw opened this issue Aug 13, 2020 · 7 comments
Open

Update fragment hash in URL so you can link to zoomed map #13

simonw opened this issue Aug 13, 2020 · 7 comments
Assignees
Labels
enhancement New feature or request

Comments

@simonw
Copy link
Owner

simonw commented Aug 13, 2020

No description provided.

@simonw simonw added the enhancement New feature or request label Aug 13, 2020
@simonw simonw self-assigned this Aug 13, 2020
@simonw
Copy link
Owner Author

simonw commented Aug 13, 2020

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.

@simonw
Copy link
Owner Author

simonw commented Aug 14, 2020

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.

@simonw
Copy link
Owner Author

simonw commented Aug 14, 2020

I'm going to enable this by default but allow users to disable it using a plugin configuration setting.

@simonw
Copy link
Owner Author

simonw commented Aug 14, 2020

One catch: that plugin doesn't play well with the changes datasette-vega makes to the URL.

@simonw
Copy link
Owner Author

simonw commented Aug 14, 2020

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;
};

@simonw
Copy link
Owner Author

simonw commented Aug 14, 2020

I'm going to use a cm prefix (for cluster-map).

simonw added a commit that referenced this issue Aug 14, 2020
@glasnt
Copy link

glasnt commented Jan 3, 2021

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

de8d788#diff-887aaf7973cd28479fd3326e3777360fb835b5e8d1fe00f55b4a849d54b6dcbcR63-R67

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.

https://github.com/simonw/datasette-vega/blob/1db45bd8f1c3c17f8b05aba7159542bcaffffad8/src/DatasetteVega.js#L125-L131

  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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants