Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bulb/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub enum Error {
#[error("No body")]
NoBody(),

#[error("No map")]
NoMap(),

/// Failed to cast element
#[error("Cast failed {0}")]
CastFail(String),
Expand Down
80 changes: 72 additions & 8 deletions bulb/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@
//
use crate::app::{self, DeferredAction};
use crate::asset::Asset;
use crate::card::{self, CardList, CardState};
use crate::card::{self, CardList, CardState, uri_all, uri_one};
use crate::eid;
use crate::error::Result;
use crate::error::{Error, Result};
use crate::fetch::Uri;
use crate::helper::spawn_future;
use crate::mapextent::MapExtent;
use crate::permission::Permission;
use crate::purpose::DedicatedPurpose;
use crate::query::QueryParam;
use crate::sidebar;
use crate::systemattr::SystemAttr;
use crate::util::Doc;
use chrono::{DateTime, Local};
use earthwyrm::{MapEvent, MapPane};
Expand Down Expand Up @@ -63,23 +65,45 @@ pub fn add_listeners() -> Result<()> {
let doc = Doc::new()?;
let layer_menu: HtmlElement = doc.elem("layer-menu")?;
add_change_listener(&layer_menu)?;
let map_extents: HtmlElement = doc.elem("map-extents")?;
add_click_listener(&map_extents)?;
MapPane::new(MAP_PANE)
.with_anchor(ANCHOR_X, ANCHOR_Y)
.with_groups(GROUPS)
.with_click_handler(handle_click)
.with_contextmenu_handler(handle_contextmenu)
.with_zoom_handler(handle_zoom)
.register();
if let Some(map_pane) = MapPane::get(MAP_PANE) {
// FIXME: use default map extent
map_pane.set_position(10, -93.2, 44.95);
set_zoom_level(10);
spawn_future(update_layers_all(10));
}
spawn_future(zoom_to_default());
spawn_future(update_layers_all(10));
spawn_future(add_extent_buttons());
fetch_station_data();
Ok(())
}

/// Zoom to default map extent
async fn zoom_to_default() -> Result<()> {
let name_js = uri_one(Res::SystemAttribute, "map_extent_name_initial")
.get()
.await?;
let extent_name =
serde_wasm_bindgen::from_value::<SystemAttr>(name_js)?.value;
recall_extent(extent_name).await
}

/// Set the map to the specified map extent
async fn recall_extent(name: String) -> Result<()> {
let Some(map_pane) = MapPane::get(MAP_PANE) else {
Err(Error::NoMap())?
};
let extent_js = uri_one(Res::MapExtent, &name).get().await?;
let extent = serde_wasm_bindgen::from_value::<MapExtent>(extent_js)?;
let (zoom, lon, lat) = (extent.zoom, extent.lon, extent.lat);
map_pane.set_position(zoom.into(), lon, lat);
set_zoom_level(zoom.into());
Ok(())
}

/// Handle a `click` event on the map
fn handle_click(me: MapEvent) {
log::debug!("click: {me:?}");
Expand Down Expand Up @@ -220,6 +244,46 @@ fn add_change_listener(el: &Element) -> Result<()> {
Ok(())
}

/// Add buttons for each map extent
async fn add_extent_buttons() -> Result<()> {
let doc = Doc::get();
let extents: Vec<MapExtent> =
serde_wasm_bindgen::from_value(uri_all(Res::MapExtent).get().await?)?;
let div = doc.elem::<HtmlElement>("map-extents")?;
let default = doc.0.create_element("button")?;
default.set_id("default-extent");
default.set_text_content(Some("Default"));
div.append_child(&default)?;
for extent in &extents {
let b = doc.0.create_element("button")?;
b.set_id(&extent.name);
b.set_text_content(Some(&extent.name));
div.append_child(&b)?;
}
Ok(())
}

/// Add a "click" event listener to an element
fn add_click_listener(el: &Element) -> Result<()> {
let closure: Closure<dyn Fn(_)> = Closure::new(|e: Event| {
if let Some(Ok(target)) = e.target().map(|e| e.dyn_into::<Element>()) {
let id = target.id();
if id == "default-extent" {
spawn_future(zoom_to_default());
} else {
spawn_future(recall_extent(id));
}
}
});
el.add_event_listener_with_callback(
"click",
closure.as_ref().unchecked_ref(),
)?;
// can't drop closure, just forget it to make JS happy
closure.forget();
Ok(())
}

/// Handle layer zoom threshold change
async fn handle_layer_zoom(id: String) -> Result<()> {
if let Some((rname, "zoom")) = id.split_once('-')
Expand Down
24 changes: 19 additions & 5 deletions bulb/static/bulb.css
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ menu li {
--locked-display: none;
}

#layer-zoom {
display: none;
#map-controls {
display: flex;
position: fixed;
left: 0;
bottom: 0;
Expand All @@ -273,16 +273,30 @@ menu li {
border-top: 1px solid white;
border-right: 1px solid white;
user-select: none;
max-width: 60%;
text-wrap: nowrap;
}
#layer-zoom button {
#map-controls button {
border: none;
padding: 0;
border-radius: 0;
padding: 0 0.3rem;
margin: 0;
background-color: #899;
color: black;
}
#layer-zoom button:hover {
#map-controls button:hover {
background-color: #677;
}
#map-extents {
border-left: 4px double #677;
overflow-x: scroll;
}
#map-extents button {
border-left: 2px solid #677;
}
#map-extents button:first-child {
border-left: none;
}

#map-menu {
position: absolute;
Expand Down
7 changes: 5 additions & 2 deletions bulb/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@
</div>
<div id="map-pane"></div>
<div id="map-menu" class="no-display"></div>
<div id="layer-zoom">
<button popovertarget="layer-popover">🞁 Layers</button>
<div id="map-controls">
<div id="layer-zoom">
<button popovertarget="layer-popover">🞁 Layers</button>
</div>
<div id="map-extents"></div>
</div>
<div id="layer-popover" popover>
<menu id="layer-menu">
Expand Down
Loading