protomaps / protomaps-leaflet

Lightweight vector map rendering + labeling and symbology for Leaflet
https://protomaps.com/docs/frontends/leaflet
BSD 3-Clause "New" or "Revised" License
767 stars 43 forks source link

Feature picking implementation support #160

Open claustres opened 4 months ago

claustres commented 4 months ago

According to some discussions (eg https://github.com/protomaps/protomaps-leaflet/issues/134) it appears this library should remain focus on basic rendering while more complex features are delegated to MapLibreGL. However, I would like to get some insights and possible small adjustements to the library so it can be implemented externally.

You will find on this fork a proof of concept (PoC) https://github.com/kalisio/protomaps-leaflet/commit/4a303d74251354c7e92da47a4bfa42574580c13c.

Capture vidéo du 2024-07-13 15-55-53.webm

You are right that trying to manage this at the geometrical level independently of the rendering process can not work well because you will never exactly know what symbolizers and canvas will do (dashed lines, antialiasing, etc.). So it should be somewhat "part of the drawing" process. Fortunately, the canvas API has a isPointInStroke() and isPointInPath() specifically designed for that. This is the workflow of the current PoC to validate the concept: 1) detect leaflet click event on map 2) retrieve pointer target tile and pointer coordinates within tile 3) send pointer information to the paint/draw functions for target tile only 4) if pointer information is available in draw function it is checked against the draw path 5) if picked feature is detected it is highlighted then sent back to caller 6) the picked features are accumulated in a list

Current limitations are the following and should be suppressed in final implementation with proposed enhancements in the library: 1) a whole redraw is currently required to get it work, we should only target a set of selectable features and without requiring a redraw 2) clearing picking information is done using a timeout as I don't know how to detect that the whole rendering is finished 3) the picking feature has been only implemented in line symbolizer for now

If you are ok to make easier implementing this feature with your library here is the optimal process I guess: 1) during drawing a feature can be tagged as "selectable" (possibly based on something like the filter function) and its paths stored for picking 2) on mouse events (move, click) the selectable features (i.e. paths) are checked against the pointer, then possibly highlighted with a specific symbolizer or so

Managing Leaflet events is not mandatory in the library and can be done by extending the pmtiles layer class I guess. Similarly check against the pointer or highlighting can be done externally, what we need is: 1) a way to "hook" the draw function, typically with before/after draw hooks 2) a way to get back the drawn paths, typically using Path2D objects instead of using beginPath()

Let me know what you think and I'd be please to open a PR to continue working on this. Any help is welcome.

claustres commented 4 months ago

@bdon At least any feedback from you would be helpful to know if it is worth it to start a PR or if we should do this entirely as a side feature without changing anything in the library. Just to be compliant with the warning message "Please do not open PRs for new features if you're a first time contributor; first open an issue to confirm that the new feature is appropriate".

Thanks in advance.