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-tiles Cargo 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 RefAny and is carried across relayout by a DatasetMergeCallback, so panning doesn't refetch everything.

See also

Back to guide index