Set feature state
Feature state is data that your host attaches to one feature at runtime and that style expressions read while the map draws. One styling rule then covers selection, hover, a live value, or a computed status, because each feature supplies its own input to that rule.
Feature state belongs to the render session and applies to its loaded tiles. Set state after the first render update that follows a style load. An earlier call reports an invalid-state status. Every feature-state call runs on the session’s owner thread.
Set state on a feature
Section titled “Set state on a feature”A selector contains the source ID, the source-layer ID for a vector source, and
the feature ID. Feature IDs match as text. Select a feature whose GeoJSON id
is the number 7 with "7".
mln_feature_state_selector selector = {.size = sizeof(selector)};selector.fields = MLN_FEATURE_STATE_SELECTOR_SOURCE_LAYER_ID | MLN_FEATURE_STATE_SELECTOR_FEATURE_ID;selector.source_id = view("places");selector.source_layer_id = view("poi");selector.feature_id = view(feature_id);The state is a JSON object, and each state key holds one JSON value.
const mln_buffer_view state = view(selected ? "{\"selected\":true}" : "{\"selected\":false}");Setting state writes the keys of the object that you pass, leaves the feature’s other keys at their current values, and requests a repaint.
// The call parses or copies the bytes before returning.return mln_render_session_set_feature_state(session, &selector, state);An expression reads one key with feature-state, and its fallback value applies
to every feature that has no value for that key. A circle layer that enlarges
the selected feature reads
["case", ["boolean", ["feature-state", "selected"], false], 10, 5] for
circle-radius.
Removal depends on how much of the selector you supply. A state key removes one entry, a feature ID alone removes that feature’s whole state, and a selector with neither one removes the state of every feature in the source layer.
mln_feature_state_selector selector = select_poi(feature_id);selector.fields |= MLN_FEATURE_STATE_SELECTOR_STATE_KEY;selector.state_key = view("selected");
return mln_render_session_remove_feature_state(session, &selector);Read state back
Section titled “Read state back”Reading state copies the session’s value into a snapshot handle that the host owns. The snapshot contains an empty object when the source or feature has no state.
mln_buffer result = MLN_HANDLE_NULL;const mln_status got = mln_render_session_get_feature_state(session, selector, &result);if (got != MLN_STATUS_OK) return false;The snapshot’s root is a JSON object with one member per state key. Reading one value iterates over those members and compares each key against the one that you want.
// Implement this with the host's JSON library to read the top-level// "selected" boolean from json.data[0..json.size].extern bool host_json_selected(mln_buffer_view json);The root value and everything under it point into the snapshot. Copy any value that you keep, because destroying the snapshot invalidates those pointers.
mln_buffer_view json = {0};bool selected = false;if (mln_buffer_get(result, &json) == MLN_STATUS_OK) { selected = host_json_selected(json);}
mln_buffer_destroy(result);How long state lives
Section titled “How long state lives”Feature state lives with a render session’s rendering resources. A resize or an in-place target replacement preserves those resources, as Attach a render target describes. Changing the scale factor recreates them. Destroying the session and attaching another does the same. Feature state starts empty after either change. To preserve it, keep a host copy and set it again after the next render update.