Events and feature state
MapLibre apps write map.on("click", "sites", ...) and light features up on
hover with feature state. mapterm has the same two pieces. Rust apps poll
instead of registering callbacks: you feed events::Events the pointer and
clicks each frame, and act on the events it returns.
Layer events
Section titled “Layer events”use mapterm::events::{Events, MapEvent};
// The layers you care about; set the "hover" feature state on the feature under the pointer.let mut events = Events::new(&["sites", "route"]).hover_state("hover");
loop { // ... handle input with the Controller, draw ...
// The pointer moved: Enter and Leave events, and the hover state updated. for e in events.pointer(&mut map, &ctl.cam, area, ctl.pointer()) { match e { MapEvent::Enter { layer, feature } => status = format!("{layer}: {}", feature.title()), MapEvent::Leave { .. } => status.clear(), _ => {} } } // A click: every feature under it, per layer, top first. if let Some(click) = ctl.take_click() { for e in events.click(&map, &ctl.cam, area, &click) { if let MapEvent::Click { layer, features, lon, lat } = e { // open a popup for features[0] ... } } }}| Event | When |
|---|---|
Click { layer, features, lon, lat } |
A click on the layer’s features; all of them under the click, top first |
Enter { layer, feature } |
The pointer moved onto a feature (the top one under it) |
Leave { layer, feature } |
The pointer left that feature |
Repeats with nothing new are skipped, so you get one Enter per feature, not
one per mouse move. Controller::pointer() is the pointer position the
controller tracked from mouse events.
Feature state
Section titled “Feature state”Feature state is per-feature data that paint expressions can read, without
touching the source data. hover_state("hover") sets it for you; you can also
set any state yourself:
use mapterm::mvt::Value;use serde_json::json;
map.set_feature_state("sites", &Value::Num(42.0), &json!({"selected": true}))?;map.remove_feature_state("sites", Some(&Value::Num(42.0)), Some("selected"));let state = map.feature_state("sites", &Value::Num(42.0)); // {} when none is setRead it in a layer with the feature-state expression:
map.add_layer(StyleLayer::fill("sites", "sites").color(json!( ["case", ["boolean", ["feature-state", "hover"], false], "#ffcc00", "#204060"])))?;Only layers that read feature state are re-evaluated when it changes.
Feature ids
Section titled “Feature ids”Feature state needs ids. They come from:
- GeoJSON features’
id, - vector tile feature ids,
- or a property you choose, MapLibre’s
promoteId:MapSource::geojson(&doc)?.with_promote_id("site_code"), orpromoteIdon a source in style JSON.
Picks carry the id too (Pick::id, and _id in the JSON from
--pick and to_json).
A complete example
Section titled “A complete example”examples/hello_map.rs does all of this in about 60 lines: a pin that turns
yellow under the pointer, and clicks on the pin or a place name reported in
the status line. See Your first map.