Skip to main content

Map

Struct Map 

Source
pub struct Map {
    pub raster_mode: RasterMode,
    pub center: Option<(f64, f64, f64)>,
    pub retry: RetryPolicy,
    /* private fields */
}
Expand description

A map: sources, style and custom layers, feature state, and how raster layers draw. See the module docs.

Fields§

§raster_mode: RasterMode

How raster layers draw (cell colors unless set to kitty images).

§center: Option<(f64, f64, f64)>

The starting view (lon, lat, zoom) a style suggests.

§retry: RetryPolicy

When to ask again for tiles that failed to load.

Implementations§

Source§

impl Map

Source

pub fn new() -> Self

An empty map.

Examples found in repository?
examples/hello_map.rs (line 15)
14async fn main() -> anyhow::Result<()> {
15    let mut map = Map::new();
16    map.add_source("omt", MapSource::vector(Source::open(mapterm::source::OPENFREEMAP).await?))?;
17    map.add_source("pin", MapSource::geojson(&json!({"type": "Feature", "id": 1, "properties": {"name": "Washington Monument"},
18        "geometry": {"type": "Point", "coordinates": [-77.0353, 38.8895]}}))?)?;
19    map.add_layer(StyleLayer::background("bg").color("#101418"))?;
20    map.add_layer(StyleLayer::fill("park", "omt").source_layer("park").color("#1a3220"))?;
21    map.add_layer(StyleLayer::fill("water", "omt").source_layer("water").color("#16304a"))?;
22    map.add_layer(StyleLayer::line("roads", "omt").source_layer("transportation").color(json!(
23        ["match", ["get", "class"], "motorway", "#eb6e3c", "trunk", "#e1a046", "primary", "#d2c36e", "#5a5a5a"])))?;
24    map.add_layer(StyleLayer::symbol("places", "omt").source_layer("place").text(json!(["get", "name"]))
25        .sort_key(json!(["get", "rank"])).color("#e1e1e1"))?;
26    map.add_layer(StyleLayer::symbol("pin", "pin").glyph("◆").text("{name}")
27        .color(json!(["case", ["boolean", ["feature-state", "hover"], false], "yellow", "cyan"])))?;
28    let mut events = Events::new(&["pin", "places"]).hover_state("hover");
29
30    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
31    let mut status = String::new();
32    let mut term = ratatui::init();
33    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
34    loop {
35        ctl.tick(Instant::now());
36        let area = term.get_frame().area();
37        ctl.set_area(area);
38        let _ = map.load_tiles(&ctl.cam, area).await; // a real app loads in the background
39        term.draw(|f| {
40            f.render_widget(map.view(&ctl.cam), area);
41            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
42        })?;
43        events.pointer(&mut map, &ctl.cam, area, ctl.pointer()); // hover: the pin turns yellow
44        if let Some(click) = ctl.take_click() {
45            for e in events.click(&map, &ctl.cam, area, &click) {
46                if let MapEvent::Click { layer, features, .. } = e {
47                    status = format!("{layer}: {}", features[0].title());
48                }
49            }
50        }
51        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
52            match event::read()? {
53                Event::Key(k) if k.code == KeyCode::Char('q') => break,
54                Event::Key(k) => _ = ctl.key(k),
55                Event::Mouse(m) => _ = ctl.mouse(m),
56                _ => {}
57            }
58        }
59    }
60    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
61    ratatui::restore();
62    Ok(())
63}
Source

pub fn add_source( &mut self, id: impl Into<String>, src: MapSource, ) -> Result<()>

Add a source under id (an error if the id is taken).

Examples found in repository?
examples/hello_map.rs (line 16)
14async fn main() -> anyhow::Result<()> {
15    let mut map = Map::new();
16    map.add_source("omt", MapSource::vector(Source::open(mapterm::source::OPENFREEMAP).await?))?;
17    map.add_source("pin", MapSource::geojson(&json!({"type": "Feature", "id": 1, "properties": {"name": "Washington Monument"},
18        "geometry": {"type": "Point", "coordinates": [-77.0353, 38.8895]}}))?)?;
19    map.add_layer(StyleLayer::background("bg").color("#101418"))?;
20    map.add_layer(StyleLayer::fill("park", "omt").source_layer("park").color("#1a3220"))?;
21    map.add_layer(StyleLayer::fill("water", "omt").source_layer("water").color("#16304a"))?;
22    map.add_layer(StyleLayer::line("roads", "omt").source_layer("transportation").color(json!(
23        ["match", ["get", "class"], "motorway", "#eb6e3c", "trunk", "#e1a046", "primary", "#d2c36e", "#5a5a5a"])))?;
24    map.add_layer(StyleLayer::symbol("places", "omt").source_layer("place").text(json!(["get", "name"]))
25        .sort_key(json!(["get", "rank"])).color("#e1e1e1"))?;
26    map.add_layer(StyleLayer::symbol("pin", "pin").glyph("◆").text("{name}")
27        .color(json!(["case", ["boolean", ["feature-state", "hover"], false], "yellow", "cyan"])))?;
28    let mut events = Events::new(&["pin", "places"]).hover_state("hover");
29
30    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
31    let mut status = String::new();
32    let mut term = ratatui::init();
33    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
34    loop {
35        ctl.tick(Instant::now());
36        let area = term.get_frame().area();
37        ctl.set_area(area);
38        let _ = map.load_tiles(&ctl.cam, area).await; // a real app loads in the background
39        term.draw(|f| {
40            f.render_widget(map.view(&ctl.cam), area);
41            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
42        })?;
43        events.pointer(&mut map, &ctl.cam, area, ctl.pointer()); // hover: the pin turns yellow
44        if let Some(click) = ctl.take_click() {
45            for e in events.click(&map, &ctl.cam, area, &click) {
46                if let MapEvent::Click { layer, features, .. } = e {
47                    status = format!("{layer}: {}", features[0].title());
48                }
49            }
50        }
51        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
52            match event::read()? {
53                Event::Key(k) if k.code == KeyCode::Char('q') => break,
54                Event::Key(k) => _ = ctl.key(k),
55                Event::Mouse(m) => _ = ctl.mouse(m),
56                _ => {}
57            }
58        }
59    }
60    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
61    ratatui::restore();
62    Ok(())
63}
Source

pub fn add_map( &mut self, other: Map, before: Option<&str>, ) -> Result<Vec<String>>

Move another map’s sources and layers into this one, its layers just below before (or on top): e.g. a style loaded with Map::from_style on another task, swapped in under your own layers. Returns the ids of the layers added. Nothing changes if a source or layer id is already taken.

Source

pub fn remove_source(&mut self, id: &str) -> bool

Remove a source; layers that use it stay but draw nothing.

Source

pub fn sources(&self) -> impl Iterator<Item = (&str, &MapSource)>

Every source with its id, in the order added.

Source

pub fn source(&self, id: &str) -> Option<&MapSource>

A source by id.

Source

pub fn set_attribution(&mut self, id: &str, text: &str) -> Result<()>

Set a source’s credit (plain text, or HTML that crate::source::plain_attribution turns into text); empty removes it. Raster sources keep theirs on the shared source.

Source

pub fn set_feature_state( &mut self, source: &str, id: &Value, state: &Json, ) -> Result<()>

Set feature state (MapLibre’s setFeatureState): the keys of state (a JSON object) are merged into the feature’s state, which paint expressions read with ["feature-state", key]. id is the feature’s id, or its promoteId property.

Source

pub fn remove_feature_state( &mut self, source: &str, id: Option<&Value>, key: Option<&str>, )

Remove feature state: one key of one feature, all of one feature’s state, or (with no id) all state of the source.

Source

pub fn feature_state(&self, source: &str, id: &Value) -> Json

A feature’s state as a JSON object (empty when none is set).

Source

pub fn attributions(&self, zoom: f64) -> Vec<String>

The credits of the sources that the layers shown at zoom draw from, in source order and without repeats, as MapLibre’s attribution control lists them.

Source

pub fn cluster_expansion_zoom( &self, source: &str, cluster_id: u64, ) -> Option<f64>

The zoom at which a cluster of a clustered GeoJSON source splits into its parts (MapLibre’s getClusterExpansionZoom): fly there when a cluster is clicked.

Source

pub fn set_data(&mut self, id: &str, doc: &Json) -> Result<()>

Replace a GeoJSON source’s data (MapLibre’s setData).

Source

pub fn source_bounds(&self, id: &str) -> Option<(f64, f64, f64, f64)>

Lon/lat bounds (west, south, east, north) of a GeoJSON source, for fitting the view.

Source

pub fn tile_requests(&self, cam: &Camera, area: Rect) -> Vec<TileRequest>

Tiles the view needs that aren’t loaded yet, for sources that shown layers use and the map can fetch itself (vector sources from MapSource::vector, raster sources).

Source

pub fn insert_loaded( &mut self, source: &str, id: TileId, loaded: Result<Loaded>, ) -> Result<()>

Store a tile loaded with TileRequest::load. A failed load returns its error and the tile is requested again after a growing wait (Map::retry); after the last attempt it is stored empty. Lower-zoom tiles stand in until then.

Source

pub async fn load_tiles(&mut self, cam: &Camera, area: Rect) -> Result<()>

Fetch the missing tiles one at a time (simple apps; see Map::tile_requests to load in the background). Failed tiles are retried later (see Map::retry) and the first error is returned.

Examples found in repository?
examples/style.rs (line 26)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
More examples
Hide additional examples
examples/hello_map.rs (line 38)
14async fn main() -> anyhow::Result<()> {
15    let mut map = Map::new();
16    map.add_source("omt", MapSource::vector(Source::open(mapterm::source::OPENFREEMAP).await?))?;
17    map.add_source("pin", MapSource::geojson(&json!({"type": "Feature", "id": 1, "properties": {"name": "Washington Monument"},
18        "geometry": {"type": "Point", "coordinates": [-77.0353, 38.8895]}}))?)?;
19    map.add_layer(StyleLayer::background("bg").color("#101418"))?;
20    map.add_layer(StyleLayer::fill("park", "omt").source_layer("park").color("#1a3220"))?;
21    map.add_layer(StyleLayer::fill("water", "omt").source_layer("water").color("#16304a"))?;
22    map.add_layer(StyleLayer::line("roads", "omt").source_layer("transportation").color(json!(
23        ["match", ["get", "class"], "motorway", "#eb6e3c", "trunk", "#e1a046", "primary", "#d2c36e", "#5a5a5a"])))?;
24    map.add_layer(StyleLayer::symbol("places", "omt").source_layer("place").text(json!(["get", "name"]))
25        .sort_key(json!(["get", "rank"])).color("#e1e1e1"))?;
26    map.add_layer(StyleLayer::symbol("pin", "pin").glyph("◆").text("{name}")
27        .color(json!(["case", ["boolean", ["feature-state", "hover"], false], "yellow", "cyan"])))?;
28    let mut events = Events::new(&["pin", "places"]).hover_state("hover");
29
30    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
31    let mut status = String::new();
32    let mut term = ratatui::init();
33    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
34    loop {
35        ctl.tick(Instant::now());
36        let area = term.get_frame().area();
37        ctl.set_area(area);
38        let _ = map.load_tiles(&ctl.cam, area).await; // a real app loads in the background
39        term.draw(|f| {
40            f.render_widget(map.view(&ctl.cam), area);
41            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
42        })?;
43        events.pointer(&mut map, &ctl.cam, area, ctl.pointer()); // hover: the pin turns yellow
44        if let Some(click) = ctl.take_click() {
45            for e in events.click(&map, &ctl.cam, area, &click) {
46                if let MapEvent::Click { layer, features, .. } = e {
47                    status = format!("{layer}: {}", features[0].title());
48                }
49            }
50        }
51        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
52            match event::read()? {
53                Event::Key(k) if k.code == KeyCode::Char('q') => break,
54                Event::Key(k) => _ = ctl.key(k),
55                Event::Mouse(m) => _ = ctl.mouse(m),
56                _ => {}
57            }
58        }
59    }
60    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
61    ratatui::restore();
62    Ok(())
63}
Source

pub fn zoom_range(&self) -> (u8, u8)

The zoom range of the vector sources (min of minimums, max of maximums).

Source

pub fn kitty_commands( &mut self, cam: &Camera, area: Rect, state: &mut KittyState, ) -> String

Kitty graphics commands that place the shown raster layers under the text for this frame (images are sent once, then only moved). Write them after the frame’s cells, in the same synchronized update. Empty unless Map::raster_mode is kitty.

Source

pub fn insert_tile( &mut self, source: &str, id: TileId, bytes: Option<&[u8]>, ) -> Result<()>

Add a vector tile (MVT bytes, or None for an empty tile) to a vector source.

Source

pub fn add_layer(&mut self, layer: StyleLayer) -> Result<()>

Add a style layer on top.

Examples found in repository?
examples/hello_map.rs (line 19)
14async fn main() -> anyhow::Result<()> {
15    let mut map = Map::new();
16    map.add_source("omt", MapSource::vector(Source::open(mapterm::source::OPENFREEMAP).await?))?;
17    map.add_source("pin", MapSource::geojson(&json!({"type": "Feature", "id": 1, "properties": {"name": "Washington Monument"},
18        "geometry": {"type": "Point", "coordinates": [-77.0353, 38.8895]}}))?)?;
19    map.add_layer(StyleLayer::background("bg").color("#101418"))?;
20    map.add_layer(StyleLayer::fill("park", "omt").source_layer("park").color("#1a3220"))?;
21    map.add_layer(StyleLayer::fill("water", "omt").source_layer("water").color("#16304a"))?;
22    map.add_layer(StyleLayer::line("roads", "omt").source_layer("transportation").color(json!(
23        ["match", ["get", "class"], "motorway", "#eb6e3c", "trunk", "#e1a046", "primary", "#d2c36e", "#5a5a5a"])))?;
24    map.add_layer(StyleLayer::symbol("places", "omt").source_layer("place").text(json!(["get", "name"]))
25        .sort_key(json!(["get", "rank"])).color("#e1e1e1"))?;
26    map.add_layer(StyleLayer::symbol("pin", "pin").glyph("◆").text("{name}")
27        .color(json!(["case", ["boolean", ["feature-state", "hover"], false], "yellow", "cyan"])))?;
28    let mut events = Events::new(&["pin", "places"]).hover_state("hover");
29
30    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
31    let mut status = String::new();
32    let mut term = ratatui::init();
33    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
34    loop {
35        ctl.tick(Instant::now());
36        let area = term.get_frame().area();
37        ctl.set_area(area);
38        let _ = map.load_tiles(&ctl.cam, area).await; // a real app loads in the background
39        term.draw(|f| {
40            f.render_widget(map.view(&ctl.cam), area);
41            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
42        })?;
43        events.pointer(&mut map, &ctl.cam, area, ctl.pointer()); // hover: the pin turns yellow
44        if let Some(click) = ctl.take_click() {
45            for e in events.click(&map, &ctl.cam, area, &click) {
46                if let MapEvent::Click { layer, features, .. } = e {
47                    status = format!("{layer}: {}", features[0].title());
48                }
49            }
50        }
51        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
52            match event::read()? {
53                Event::Key(k) if k.code == KeyCode::Char('q') => break,
54                Event::Key(k) => _ = ctl.key(k),
55                Event::Mouse(m) => _ = ctl.mouse(m),
56                _ => {}
57            }
58        }
59    }
60    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
61    ratatui::restore();
62    Ok(())
63}
Source

pub fn add_layer_before( &mut self, layer: StyleLayer, before: &str, ) -> Result<()>

Add a style layer just below before.

Source

pub fn add_custom_layer<T: CustomLayer + Any + Send>( &mut self, id: impl Into<String>, layer: T, before: Option<&str>, ) -> Result<()>

Add a custom layer (see CustomLayer) on top, or below before.

Source

pub fn add_layers( &mut self, layers: Vec<StyleLayer>, before: Option<&str>, ) -> Result<()>

Add several style layers at once (on top, or below before), restyling loaded tiles only once. Nothing is added if any id is taken.

Source

pub fn remove_layers(&mut self, ids: &[&str]) -> usize

Remove several layers at once, restyling only once. Returns how many were removed.

Source

pub fn remove_layer(&mut self, id: &str) -> bool

Remove a layer; false if there was none.

Source

pub fn move_layer(&mut self, id: &str, before: Option<&str>) -> Result<()>

Move a layer below before, or to the top.

Source

pub fn layer_ids(&self) -> Vec<&str>

Layer ids, bottom first.

Examples found in repository?
examples/style.rs (line 19)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
Source

pub fn layer(&self, id: &str) -> Option<&StyleLayer>

A style layer by id (None for custom layers).

Source

pub fn custom_layer_mut<T: CustomLayer + Any + Send>( &mut self, id: &str, ) -> Option<&mut T>

A custom layer by id and type, to change its state.

Source

pub fn set_paint(&mut self, id: &str, name: &str, v: &Json) -> Result<()>

Set a paint property of a style layer (MapLibre’s setPaintProperty).

Source

pub fn set_layout(&mut self, id: &str, name: &str, v: &Json) -> Result<()>

Set a layout property of a style layer (MapLibre’s setLayoutProperty).

Source

pub fn set_filter(&mut self, id: &str, f: Option<&Json>) -> Result<()>

Replace a layer’s filter (None draws every feature).

Source

pub fn set_visibility(&mut self, id: &str, visible: bool) -> Result<()>

Show or hide a layer.

Source

pub fn set_zoom_range(&mut self, id: &str, min: f64, max: f64) -> Result<()>

Draw a layer only from min up to (not including) max zoom.

Source

pub fn warnings(&self) -> &[String]

Problems met while building the style (unsupported expressions and the like).

Examples found in repository?
examples/style.rs (line 15)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
Source

pub fn view<'a>(&'a self, camera: &'a Camera) -> MapView<'a>

A widget that draws the map with this camera.

Examples found in repository?
examples/style.rs (line 28)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
More examples
Hide additional examples
examples/hello_map.rs (line 40)
14async fn main() -> anyhow::Result<()> {
15    let mut map = Map::new();
16    map.add_source("omt", MapSource::vector(Source::open(mapterm::source::OPENFREEMAP).await?))?;
17    map.add_source("pin", MapSource::geojson(&json!({"type": "Feature", "id": 1, "properties": {"name": "Washington Monument"},
18        "geometry": {"type": "Point", "coordinates": [-77.0353, 38.8895]}}))?)?;
19    map.add_layer(StyleLayer::background("bg").color("#101418"))?;
20    map.add_layer(StyleLayer::fill("park", "omt").source_layer("park").color("#1a3220"))?;
21    map.add_layer(StyleLayer::fill("water", "omt").source_layer("water").color("#16304a"))?;
22    map.add_layer(StyleLayer::line("roads", "omt").source_layer("transportation").color(json!(
23        ["match", ["get", "class"], "motorway", "#eb6e3c", "trunk", "#e1a046", "primary", "#d2c36e", "#5a5a5a"])))?;
24    map.add_layer(StyleLayer::symbol("places", "omt").source_layer("place").text(json!(["get", "name"]))
25        .sort_key(json!(["get", "rank"])).color("#e1e1e1"))?;
26    map.add_layer(StyleLayer::symbol("pin", "pin").glyph("◆").text("{name}")
27        .color(json!(["case", ["boolean", ["feature-state", "hover"], false], "yellow", "cyan"])))?;
28    let mut events = Events::new(&["pin", "places"]).hover_state("hover");
29
30    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
31    let mut status = String::new();
32    let mut term = ratatui::init();
33    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
34    loop {
35        ctl.tick(Instant::now());
36        let area = term.get_frame().area();
37        ctl.set_area(area);
38        let _ = map.load_tiles(&ctl.cam, area).await; // a real app loads in the background
39        term.draw(|f| {
40            f.render_widget(map.view(&ctl.cam), area);
41            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
42        })?;
43        events.pointer(&mut map, &ctl.cam, area, ctl.pointer()); // hover: the pin turns yellow
44        if let Some(click) = ctl.take_click() {
45            for e in events.click(&map, &ctl.cam, area, &click) {
46                if let MapEvent::Click { layer, features, .. } = e {
47                    status = format!("{layer}: {}", features[0].title());
48                }
49            }
50        }
51        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
52            match event::read()? {
53                Event::Key(k) if k.code == KeyCode::Char('q') => break,
54                Event::Key(k) => _ = ctl.key(k),
55                Event::Mouse(m) => _ = ctl.mouse(m),
56                _ => {}
57            }
58        }
59    }
60    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
61    ratatui::restore();
62    Ok(())
63}
Source

pub fn query_rendered_features( &self, cam: &Camera, area: Rect, target: (f64, f64), layers: Option<&[&str]>, ) -> Vec<Pick>

Features drawn under target (braille dots relative to area: 2 per column, 4 per row), top layer first and, within a layer, points before lines before polygons. layers limits the search to those layer ids. Custom layers answer with their pick.

Examples found in repository?
examples/style.rs (line 33)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
Source

pub fn query_features( &self, cam: &Camera, area: Rect, target: (f64, f64), ) -> Vec<Pick>

Every feature of every source under target (dots relative to area), drawn or not, for inspecting data. Sources come in the order of their topmost layer, top first; within a source, points, then lines, then polygons from smallest to largest. Each pick’s style_layer is the top shown layer that draws it, and drawn says whether one does.

Source§

impl Map

Source

pub async fn from_style(spec: &str) -> Result<Map>

A map from a style: mapterm-dark or mapterm-light (the built-in terminal styles over OpenFreeMap), an OpenFreeMap name (OPENFREEMAP_STYLES), a URL or a file.

Examples found in repository?
examples/style.rs (line 14)
12async fn main() -> anyhow::Result<()> {
13    let spec = std::env::args().nth(1).unwrap_or_else(|| "liberty".into());
14    let mut map = Map::from_style(&spec).await?;
15    for w in map.warnings() {
16        eprintln!("warning: {w}");
17    }
18    let mut ctl = Controller::new(Camera::new(-77.0353, 38.8895, 13.0), 0.0, 17.0);
19    let mut status = format!("{spec}: {} layers", map.layer_ids().len());
20    let mut term = ratatui::init();
21    crossterm::execute!(std::io::stdout(), event::EnableMouseCapture)?;
22    loop {
23        ctl.tick(Instant::now());
24        let area = term.get_frame().area();
25        ctl.set_area(area);
26        let _ = map.load_tiles(&ctl.cam, area).await;
27        term.draw(|f| {
28            f.render_widget(map.view(&ctl.cam), area);
29            f.render_widget(ratatui::text::Line::from(status.as_str()), area);
30        })?;
31        if let Some(click) = ctl.take_click() {
32            let dot = Viewport::new(&ctl.cam, area).dot_ll(click.lon, click.lat);
33            let hits = map.query_rendered_features(&ctl.cam, area, dot, None);
34            let names: Vec<String> = hits.iter().take(4).map(|p| format!("{}: {}", p.style_layer.as_deref().unwrap_or("?"), p.title())).collect();
35            status = names.join(" | ");
36        }
37        if event::poll(Duration::from_millis(if ctl.animating() { 16 } else { 250 }))? {
38            match event::read()? {
39                Event::Key(k) if k.code == KeyCode::Char('q') => break,
40                Event::Key(k) => _ = ctl.key(k),
41                Event::Mouse(m) => _ = ctl.mouse(m),
42                _ => {}
43            }
44        }
45    }
46    crossterm::execute!(std::io::stdout(), event::DisableMouseCapture)?;
47    ratatui::restore();
48    Ok(())
49}
Source

pub fn terminal(src: Source, schema: Schema, dark: bool) -> Result<Map>

A map drawing src with the built-in terminal style for its schema.

Source

pub async fn from_style_json(doc: &Json) -> Result<Map>

A map from a parsed style document. Vector sources that fail to open are errors; source types mapterm can’t draw yet (raster, raster-dem, image, video) become warnings.

Source

pub fn add_style_layers(&mut self, doc: &Json) -> Result<()>

Add a style document’s layers on top of the current ones.

Trait Implementations§

Source§

impl Default for Map

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Map

§

impl !Sync for Map

§

impl !UnwindSafe for Map

§

impl Freeze for Map

§

impl Send for Map

§

impl Unpin for Map

§

impl UnsafeUnpin for Map

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more