# Maps

> MapContainer, pins, shapes, routes and utilities — with the key, null and thread pitfalls.

Source: https://crossfly.dev/docs/data-and-services/maps — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Maps

Embedded native map with **`MapContainer`** (a `Component`) over the `Map` interface. Supports Google and
OSM as engines.

## ⚠️ Four pitfalls that prevent bugs
1. **Set the key** (static) before creating the map: `MapContainer.googleMapsKey = "...";`.
2. **`map` may be `null`** — access `mc.map` **only after** `onMapLoad` (and handle `null`: Web/TeaVM
   **does not support** the native map).
3. **All map operations on the render (paint) thread** — come back with `onUI(...)` if it comes from the background.
4. The old `phone.GoogleMaps` (external viewer) **was removed**.

## Create and center
```java
MapContainer.googleMapsKey = "SUA_CHAVE";

MapContainer mc = new MapContainer(Map.MapEngine.GOOGLE, 0, () -> {   // onMapLoad
   if (mc.map == null) return;                          // Web/TeaVM: no native map
   mc.map.centerOnLocation(new LatLon(-23.55, -46.63), 14);
   mc.map.setMapType(Map.LayerType.NORMAL);
});
tela.add(LAY_FILL, mc);
```
`MapEngine`: `GOOGLE` · `OSM`. `LayerType`: `NORMAL` · `TERRAIN` · `HYBRID` · `SATELLITE`.

## Pins (fluent API)
```java
mc.map.add(new MapPin()
   .position(-23.55, -46.63)
   .title("São Paulo")
   .snippet("Centro")
   .draggable(false)
   .onClick(p -> { Hint.show(p.title, 2000); return true; }));   // true = suppresses info window
```

## Shapes — `MapShape.Line/Polygon/Circle`
```java
// 500 m circle (colors in ARGB 0xAARRGGBB)
MapShape.Circle c = new MapShape.Circle(2, 0xFF2196F3, 0x402196F3);
c.setPolygon(new LatLon(-23.55, -46.63), 500.0);   // center + radius in meters
mc.map.add(c);
```
`Line(thick, color)` and `Polygon(borderWidth, borderColor, fillColor)` follow the same pattern.

## Routes and utilities
```java
double metros = MapUtils.distanceInMeters(new LatLon(-23.55,-46.63), new LatLon(-22.90,-43.20));
Image thumb = MapUtils.getMapImage(-23.55, -46.63, false, 13, 600, 400);   // static image (null on error/no key)
```
Real directions (HTTP + **Jackson**) come from `DirectionsFetcher` (callback `onRouteReady(List<LatLon>)`),
combined with `MapRoute(lineShape, pins)` — marshal the result with `onUI(...)`. Detailed in
Chapter 25.

## Best practices
- Key **before** instantiating; access `mc.map` **only** in `onMapLoad`.
- Handle `mc.map == null` (Web) and `getMapImage(...) == null`.
- Map operations on the render thread; network results via `onUI(...)`.

## Common mistakes
- Accessing `mc.map` in the constructor (still `null`).
- Forgetting `MapContainer.googleMapsKey`.
- Using `phone.GoogleMaps` (removed).

## See also
- [Location and GPS](/docs/data-and-services/device-location-gps) · [LocationView](/docs/ui/widgets/locationview)
