Maps (MapWidget)
Introduction
MapWidget is a slippy-map widget: a Web-Mercator tile grid you can pan and
zoom, with hooks for tap-to-pin and viewport changes, and projection helpers to
place your own markers. It is the AzulMaps (P3) goal app. Like the other
widgets it owns its state in a RefAny dataset that survives relayout via a
merge callback - you just create it, configure it, and call .dom().
Creating a map
use azul::widgets::{MapWidget, MapViewport, MapTileLayer};
let map = MapWidget::create(MapTileLayer::default())
.with_viewport(MapViewport {
centre_lat_deg: 37.7749, // San Francisco
centre_lon_deg: -122.4194,
zoom: 11.0,
bearing_deg: 0.0,
pitch_deg: 0.0,
})
.dom();
MapTileLayer configures the tile source (and attribution). The widget computes
the visible XYZ tile grid from the viewport and renders one GPU-translated tile
div per tile. Pan (drag) and pinch-zoom are handled by the widget itself -
no wiring needed.
Hooks: observing taps and the viewport
Two backreference-DI hooks (see architecture) let your app react without globals - the callback receives the data and writes back to your state:
with_on_pin_tap(data, cb)- fires when the user taps the map (a press + release with no drag), with the tapped [MapLatLon].with_on_viewport_changed(data, cb)- fires on pan/zoom, with the new [MapViewport] (persist it, sync a minimap, etc.).
use azul::dom::MapPinTapCallback;
use azul::option::OptionRefAny;
let map = MapWidget::create(layer)
.with_viewport(viewport)
.with_on_pin_tap(
state.clone(),
MapPinTapCallback { cb: on_pin_tap, callable: OptionRefAny::None },
)
.dom();
extern "C" fn on_pin_tap(mut data: RefAny, _info: CallbackInfo, coord: MapLatLon) -> Update {
if let Some(mut s) = data.downcast_mut::<MyState>() {
s.pins.push((coord.lat_deg, coord.lon_deg)); // drop a pin
}
Update::RefreshDom
}
The widget does the tap-vs-drag detection and the projection for you, so you just store the lat/lon.
Projection: placing your own markers
To draw markers/overlays on top of the map, convert between lat/lon and screen pixels with the two static helpers (small-angle Web Mercator):
// lat/lon -> screen position (place a pin div here):
let p = MapWidget::px_at_latlon(viewport, MapLatLon { lat_deg, lon_deg }, container_size);
// screen position -> lat/lon (inverse):
let coord = MapWidget::latlon_at_px(viewport, px, container_size);
container_size is the map node's pixel size (e.g. from
CallbackInfo::get_hit_node_rect().size). Re-projecting each layout makes your
pins track the map as it pans and zooms. examples/azul-maps uses exactly this
to render dropped pins + a coordinate readout.
Geolocation
To show „you are here“, drop a Dom::create_geolocation_probe(...) into the map
subtree and read the fix with CallbackInfo::get_location_fix - see
Device Input.
Notes
- Tile fetch + MVT decode + MapCSS-to-SVG are behind the
map-tilesCargo feature; with it off, the grid + viewport bookkeeping still work (the demo shows the projection math without live tiles). - The tile cache lives in the widget's dataset
RefAnyand is carried across relayout by aDatasetMergeCallback, so panning doesn't refetch everything.
See also
- widgets - the widget model.
- callbacks - the hook +
RefAnymechanism. - Device Input - geolocation for the „you are here“ dot.