Map view (external piece)

Authoring

use day_piece_map::map;

let where_to = Signal::new((37.7749, -122.4194)); // San Francisco

button("San Francisco").action(move || where_to.set((37.7749, -122.4194)));
button("New York").action(move || where_to.set((40.7128, -74.0060)));

map()
    .center_signal(where_to)      // preset buttons recenter the map live
    .span(0.05)                   // ~5 km across (smaller = more zoomed in)
    .marker(37.7749, -122.4194)   // drop a pin
    .frame(320.0, 240.0)          // a map is a growing leaf, so constrain it
    .id("map")

map() starts at (0, 0) with the default span (a few city blocks). Set a fixed region at build with .center(lat, lon) + .span(degrees) and drop a pin with .marker(lat, lon). The center can also be bound reactively with .center_signal(signal), which takes a Signal<(f64, f64)> or a Fn() -> (f64, f64), so a preset row or a location feed recenters the map live (a Center patch to the native view; a Const center from .center seeds once and never patches). .center and .center_signal are last-writer-wins. Map implements Piece, so .id() / .a11y() / .frame() chain via Decorate. It’s a growing leaf (Flex { grow_w, grow_h } + day_pieces::fill_measure), so put it in a .frame(w, h) (or last in a column) and it fills the space it’s offered.

The span is a coarse zoom knob (a MKCoordinateSpan latitude/longitude delta). v1 keeps a single marker and no delegate callbacks (tap/region-change readback); the Event::custom channel is where those would be added later.

Per-backend native realization

AppKitUIKitGTK / Qt / Android / XAML
controlMKMapView (NSView)MKMapView (UIView)— (placeholder leaf)
native codeobjc2-map-kit typed bindinghand-rolled extern_class! + msg_send!none
regionsetRegion(MKCoordinateRegion)setRegion:animated:
markerMKPointAnnotation + addAnnotationMKPointAnnotation + addAnnotation:
recentersetCenterCoordinate:animated:setCenterCoordinate:animated:

Backend notes:

  • AppKit: objc2-map-kit binds MKMapView as an NSView subclass (macOS only). The region is an MKCoordinateRegion { center: CLLocationCoordinate2D, span: MKCoordinateSpan } built from the props; a marker is an MKPointAnnotation added via the typed addAnnotation. MapKit renders without a key: no developer token or entitlement is needed for a plain map. The recenter patch uses setCenterCoordinate:animated: (keeps the current zoom).
  • UIKit: objc2-map-kit generates the MKMapView struct for macOS only (the WKWebView / AVPlayerViewController situation again), so the piece hand-rolls the class via extern_class! + msg_send! and reuses the crate’s cross-platform MKCoordinateRegion / MKPointAnnotation. MapKit
    • CoreLocation must be linked for the ObjC classes to register; they’re declared via [package.metadata.day.ios] frameworks = ["MapKit", "CoreLocation"] and linked by the generated DayPieces SwiftPM package (the framework-contribution mechanism).
  • GTK / Qt / Android / XAML / mock: the features exist (so an app can enable day-piece-map/<feature> uniformly per backend) but register no renderer; the map kind falls back to day’s placeholder leaf. There is no de-facto native slippy-map widget in these toolkits without a heavy external dependency (a WebView + tile provider, osm-gps-map, QtLocation, Google Maps SDK, MapControl), each with different API-key and licensing requirements, which is out of scope for a small reference piece. This piece is the reference example of one that supports a subset of platforms; the placeholder leaf keeps the gap visible.

What it shows about the extension system

day-piece-map is the counterpart to day-piece-lottie: a piece whose demo page is #[cfg]-gated to the platforms it supports (macos + ios). The front-end compiles everywhere (it depends only on core day crates), but the map page and the crate’s backend features are enabled only for the Apple backends; every other backend renders the placeholder leaf for the day.piece.map kind. It also exercises the iOS framework-contribution mechanism (added for the webview/media work, docs/extending.md): [package.metadata.day.ios] frameworks = ["MapKit", "CoreLocation"] links the system frameworks the hand-rolled MKMapView needs, with no changes to any core Day crate.

Testing

The crate’s test boots the piece on the mock toolkit (which realizes unknown kinds as plain widgets and ignores unknown patches, just like a backend built without the feature), moves the bound center (a Center patch), and must never panic: cargo test -p day-piece-map.

For a live check, wire the showcase map page and use the media/webview walkthrough recipe on appkit/macOS: navigate to the route, pause so the map tiles arrive, then screenshot.