docs/enterprise/map/index.md
import reflex as rx
import reflex_enterprise as rxe
The map components in Reflex Enterprise provide interactive mapping capabilities built on top of Leaflet, one of the most popular open-source JavaScript mapping libraries. These components enable you to create rich, interactive maps with markers, layers, controls, and event handling.
# All map components are built using Leaflet and react-leaflet, providing a familiar and powerful mapping experience.
For advanced Leaflet features, refer to the [Leaflet documentation](https://leafletjs.com/reference.html).
š View Live Demo - See the map components in action with interactive examples.
Map components are included with reflex-enterprise. No additional installation is required.
Here's a simple example of creating a map with a marker:
import reflex as rx
import reflex_enterprise as rxe
class MapState(rx.State):
center: rxe.map.LatLng = rxe.map.latlng(lat=51.505, lng=-0.09)
zoom: float = 13.0
def basic_map():
return rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
),
rxe.map.marker(
rxe.map.popup("Hello from London!"),
position=MapState.center,
),
id="basic-map",
center=MapState.center,
zoom=MapState.zoom,
height="400px",
width="100%",
)
The rxe.map() component is the primary container that holds all other map elements:
rxe.map(
# Child components (markers, layers, controls)
id="my-map",
center=rxe.map.latlng(lat=51.505, lng=-0.09),
zoom=13,
height="400px",
width="100%",
)
Key Properties:
center: Initial map center coordinateszoom: Initial zoom level (0-18+ depending on tile provider)bounds: Alternative to center/zoom, fits map to boundsheight/width: Map container dimensionsTile layers provide the base map imagery. The most common is OpenStreetMap:
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
)
Add point markers to specific locations:
import reflex as rx
import reflex_enterprise as rxe
def markers_example():
return rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
rxe.map.marker(
rxe.map.popup(
rx.vstack(
rx.text("Big Ben", weight="bold"),
rx.text("Famous clock tower in London"),
spacing="2",
)
),
position=rxe.map.latlng(lat=51.4994, lng=-0.1245),
),
rxe.map.marker(
rxe.map.popup("London Eye"),
position=rxe.map.latlng(lat=51.5033, lng=-0.1196),
),
id="markers-map",
center=rxe.map.latlng(lat=51.501, lng=-0.122),
zoom=14,
height="400px",
width="100%",
)
Draw shapes and areas on the map:
import reflex as rx
import reflex_enterprise as rxe
def vectors_example():
return rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
# Circle (radius in meters)
rxe.map.circle(
center=rxe.map.latlng(lat=51.505, lng=-0.09),
radius=500,
path_options=rxe.map.path_options(
color="#ff0000", fill_color="#ff3333", fill_opacity=0.3, weight=2
),
),
# Polygon
rxe.map.polygon(
positions=[
rxe.map.latlng(lat=51.515, lng=-0.08),
rxe.map.latlng(lat=51.515, lng=-0.07),
rxe.map.latlng(lat=51.520, lng=-0.07),
rxe.map.latlng(lat=51.520, lng=-0.08),
],
path_options=rxe.map.path_options(
color="#0000ff", fill_color="#3333ff", fill_opacity=0.3
),
),
# Polyline
rxe.map.polyline(
positions=[
rxe.map.latlng(lat=51.500, lng=-0.095),
rxe.map.latlng(lat=51.510, lng=-0.085),
rxe.map.latlng(lat=51.515, lng=-0.095),
],
path_options=rxe.map.path_options(color="#00ff00", weight=4),
),
id="vectors-map",
center=rxe.map.latlng(lat=51.510, lng=-0.08),
zoom=13,
height="400px",
width="100%",
)
Maps support comprehensive event handling for user interactions:
import reflex as rx
import reflex_enterprise as rxe
class InteractiveMapState(rx.State):
last_click: str = "No clicks yet"
current_zoom: float = 13.0
def handle_map_click(self, event):
lat = event.get("latlng", {}).get("lat", 0)
lng = event.get("latlng", {}).get("lng", 0)
self.last_click = f"Clicked at: {lat:.4f}, {lng:.4f}"
def handle_zoom_change(self, event):
self.current_zoom = float(event.get("target", {}).get("_zoom", 13.0))
def interactive_example():
return rx.vstack(
rx.text(f"Last click: {InteractiveMapState.last_click}"),
rx.text(f"Current zoom: {InteractiveMapState.current_zoom}"),
rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
id="interactive-map",
center=rxe.map.latlng(lat=51.505, lng=-0.09),
zoom=InteractiveMapState.current_zoom,
height="350px",
width="100%",
on_click=InteractiveMapState.handle_map_click,
on_zoom=InteractiveMapState.handle_zoom_change,
),
spacing="3",
)
Add UI controls for enhanced user interaction:
import reflex as rx
import reflex_enterprise as rxe
def controls_example():
return rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
rxe.map.zoom_control(position="topright"),
rxe.map.scale_control(position="bottomleft"),
rxe.map.attribution_control(position="bottomright"),
id="controls-map",
center=rxe.map.latlng(lat=51.505, lng=-0.09),
zoom=13,
height="400px",
width="100%",
)
# Create latitude/longitude coordinates
center = rxe.map.latlng(lat=51.505, lng=-0.09, nround=4)
# Create bounds
bounds = rxe.map.latlng_bounds(
corner1_lat=51.49, corner1_lng=-0.11, corner2_lat=51.52, corner2_lng=-0.07
)
The Map API provides programmatic control over your maps, allowing you to manipulate the map programmatically from your Reflex state methods.
To access the Map API, you need to get a reference to your map using its ID:
map_api = rxe.map.api("my-map-id")
Here are some commonly used API methods demonstrated in action:
import reflex as rx
import reflex_enterprise as rxe
map_api = rxe.map.api("api-demo-map")
class MapAPIState(rx.State):
current_location: str = "London"
def fly_to_london(self):
yield map_api.fly_to([51.505, -0.09], 13)
self.current_location = "London"
def fly_to_paris(self):
yield map_api.fly_to([48.8566, 2.3522], 13)
self.current_location = "Paris"
def map_api_example():
return rx.vstack(
rx.text(f"Current location: {MapAPIState.current_location}"),
rx.hstack(
rx.button("Fly to London", on_click=MapAPIState.fly_to_london),
rx.button("Fly to Paris", on_click=MapAPIState.fly_to_paris),
rx.button("Zoom Out", on_click=map_api.set_zoom(8)),
rx.button(
"Log Center", on_click=map_api.get_center(callback=rx.console_log)
),
spacing="2",
),
rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
id="api-demo-map",
center=rxe.map.latlng(lat=51.505, lng=-0.09),
zoom=13.0,
height="350px",
width="100%",
),
spacing="3",
)
View Control:
fly_to(latlng, zoom, options) - Smooth animated movement to locationset_view(latlng, zoom, options) - Instant movement to locationset_zoom(zoom) - Change zoom levelzoom_in() / zoom_out() - Zoom by one levelfit_bounds(bounds, options) - Fit map to specific boundsLocation Services:
locate(options) - Get user's current locationstop_locate() - Stop location trackingInformation Retrieval:
get_center(callback) - Get current map centerget_zoom(callback) - Get current zoom levelget_bounds(callback) - Get current map boundsget_size(callback) - Get map container sizeLayer Management:
add_layer(layer) - Add a layer to the mapremove_layer(layer) - Remove a layer from the maphas_layer(layer) - Check if layer exists on map# The Map API provides access to the complete Leaflet map API. Any method available on a Leaflet map instance can be called through the MapAPI instance.
Function names are automatically converted from snake_case (Python) to camelCase (JavaScript).
This means you can use any method from the Leaflet Map documentation. For example:
Python (snake_case) ā JavaScript (camelCase):
map_api.pan_to(latlng) ā map.panTo(latlng)map_api.set_max_bounds(bounds) ā map.setMaxBounds(bounds)map_api.get_pixel_bounds() ā map.getPixelBounds()map_api.container_point_to_lat_lng(point) ā map.containerPointToLatLng(point)import reflex as rx
import reflex_enterprise as rxe
class AdvancedMapState(rx.State):
constraints_applied: bool = False
location_tracking: bool = False
location_status: str = "Location tracking disabled"
def set_location_status(self, status: str):
self.location_status = status
def setup_map_constraints(self):
map_api = rxe.map.api("advanced-demo-map")
# Set maximum bounds (restrict panning to London area)
max_bounds = rxe.map.latlng_bounds(
corner1_lat=51.4, corner1_lng=-0.3, corner2_lat=51.6, corner2_lng=0.1
)
yield map_api.set_max_bounds(max_bounds)
# Set min/max zoom levels
yield map_api.set_min_zoom(10)
yield map_api.set_max_zoom(16)
# Disable scroll wheel zoom
yield map_api.scroll_wheel_zoom(False)
self.constraints_applied = True
def remove_constraints(self):
map_api = rxe.map.api("advanced-demo-map")
# Remove bounds restriction
yield map_api.set_max_bounds(None)
# Reset zoom limits
yield map_api.set_min_zoom(1)
yield map_api.set_max_zoom(18)
# Re-enable scroll wheel zoom
yield map_api.scroll_wheel_zoom(True)
self.constraints_applied = False
def toggle_location_tracking(self):
map_api = rxe.map.api("advanced-demo-map")
if self.location_tracking == False:
# Start location tracking
locate_options = rxe.map.locate_options(
set_view=True,
max_zoom=16,
timeout=10000,
enable_high_accuracy=True,
watch=False, # Single location request
)
yield map_api.locate(locate_options)
self.location_tracking = True
self.location_status = "Requesting location..."
else:
# Stop location tracking
yield map_api.stop_locate()
self.location_tracking = False
self.location_status = "Location tracking disabled"
def advanced_example():
return rx.vstack(
rx.hstack(
rx.button(
rx.cond(
AdvancedMapState.constraints_applied,
"Remove Constraints",
"Apply Constraints",
),
on_click=rx.cond(
AdvancedMapState.constraints_applied,
AdvancedMapState.remove_constraints,
AdvancedMapState.setup_map_constraints,
),
color_scheme="blue",
),
rx.button(
rx.cond(
AdvancedMapState.location_tracking,
"Disable Location",
"Enable Location",
),
on_click=AdvancedMapState.toggle_location_tracking,
color_scheme="green",
),
spacing="3",
),
rx.text(f"Status: {AdvancedMapState.location_status}"),
rx.text(
rx.cond(
AdvancedMapState.constraints_applied,
"Constraints: Applied (restricted to London area, zoom 10-16, no scroll wheel)",
"Constraints: None",
)
),
rxe.map(
rxe.map.tile_layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© OpenStreetMap contributors",
),
rxe.map.marker(
rxe.map.popup("Try panning and zooming when constraints are applied!"),
position=rxe.map.latlng(lat=51.505, lng=-0.09),
),
id="advanced-demo-map",
center=rxe.map.latlng(lat=51.505, lng=-0.09),
zoom=12.0,
height="400px",
width="100%",
on_locationfound=lambda e: AdvancedMapState.set_location_status(
"Location found!"
),
on_locationerror=lambda e: AdvancedMapState.set_location_status(
"Location error - permission denied or unavailable"
),
),
spacing="3",
)
Many API methods that retrieve information require callbacks to handle the results:
class CallbackMapState(rx.State):
map_info: str = ""
def handle_center_result(self, result):
lat = result.get("lat", 0)
lng = result.get("lng", 0)
self.map_info = f"Center: {lat:.4f}, {lng:.4f}"
def handle_bounds_result(self, result):
# result will contain bounds information
self.map_info = f"Bounds: {result}"
def get_map_info(self):
map_api = rxe.map.api("info-map")
yield map_api.get_center(self.handle_center_result)
# or
yield map_api.get_bounds(self.handle_bounds_result)
The map components support a comprehensive set of events:
Map Events:
on_click, on_dblclick - Mouse click eventson_zoom, on_zoom_start, on_zoom_end - Zoom eventson_move, on_move_start, on_move_end - Pan eventson_resize - Map container resizeon_load, on_unload - Map lifecycleLocation Events:
on_locationfound, on_locationerror - GeolocationLayer Events:
on_layeradd, on_layerremove - Layer managementPopup Events:
on_popupopen, on_popupclose - Popup lifecycleon_tooltipopen, on_tooltipclose - Tooltip lifecycleclass DynamicMapState(rx.State):
markers: list[dict] = [
{"lat": 51.505, "lng": -0.09, "title": "London"},
{"lat": 48.8566, "lng": 2.3522, "title": "Paris"},
{"lat": 52.5200, "lng": 13.4050, "title": "Berlin"},
]
def dynamic_markers():
return rxe.map(
rxe.map.tile_layer(url="..."),
rx.foreach(
DynamicMapState.markers,
lambda marker: rxe.map.marker(
rxe.map.popup(marker["title"]),
position=rxe.map.latlng(lat=marker["lat"], lng=marker["lng"]),
),
),
# ... map configuration
)