dioxus_leaflet/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// Represents a geographical position with zoom level
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct MapPosition {
7    pub lat: f64,
8    pub lng: f64,
9    pub zoom: f64,
10}
11
12impl MapPosition {
13    /// Creates a new MapPosition
14    pub fn new(lat: f64, lng: f64, zoom: f64) -> Self {
15        Self { lat, lng, zoom }
16    }
17}
18
19impl Default for MapPosition {
20    fn default() -> Self {
21        Self::new(51.505, -0.09, 13.0)
22    }
23}
24
25/// Represents a marker on the map
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
27pub struct MapMarker {
28    pub lat: f64,
29    pub lng: f64,
30    pub title: String,
31    pub description: Option<String>,
32    pub icon: Option<MarkerIcon>,
33    pub popup_options: Option<PopupOptions>,
34    pub custom_data: Option<HashMap<String, String>>,
35}
36
37impl MapMarker {
38    /// Creates a new MapMarker with basic information
39    pub fn new(lat: f64, lng: f64, title: impl Into<String>) -> Self {
40        Self {
41            lat,
42            lng,
43            title: title.into(),
44            description: None,
45            icon: None,
46            popup_options: None,
47            custom_data: None,
48        }
49    }
50
51    /// Adds a description to the marker
52    pub fn with_description(mut self, description: impl Into<String>) -> Self {
53        self.description = Some(description.into());
54        self
55    }
56
57    /// Adds a custom icon to the marker
58    pub fn with_icon(mut self, icon: MarkerIcon) -> Self {
59        self.icon = Some(icon);
60        self
61    }
62
63    /// Adds custom popup options
64    pub fn with_popup_options(mut self, options: PopupOptions) -> Self {
65        self.popup_options = Some(options);
66        self
67    }
68
69    /// Adds custom data
70    pub fn with_custom_data(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
71        if self.custom_data.is_none() {
72            self.custom_data = Some(HashMap::new());
73        }
74        if let Some(ref mut data) = self.custom_data {
75            data.insert(key.into(), value.into());
76        }
77        self
78    }
79}
80
81impl Default for MapMarker {
82    fn default() -> Self {
83        Self {
84            lat: 0.0,
85            lng: 0.0,
86            title: String::new(),
87            description: None,
88            icon: None,
89            popup_options: None,
90            custom_data: None,
91        }
92    }
93}
94
95/// Custom marker icon configuration
96#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
97pub struct MarkerIcon {
98    pub icon_url: String,
99    pub icon_size: Option<(u32, u32)>,
100    pub icon_anchor: Option<(u32, u32)>,
101    pub popup_anchor: Option<(i32, i32)>,
102    pub shadow_url: Option<String>,
103    pub shadow_size: Option<(u32, u32)>,
104}
105
106impl MarkerIcon {
107    /// Creates a new MarkerIcon with just the URL
108    pub fn new(icon_url: impl Into<String>) -> Self {
109        Self {
110            icon_url: icon_url.into(),
111            icon_size: None,
112            icon_anchor: None,
113            popup_anchor: None,
114            shadow_url: None,
115            shadow_size: None,
116        }
117    }
118}
119
120/// Popup configuration options
121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122pub struct PopupOptions {
123    pub max_width: Option<u32>,
124    pub min_width: Option<u32>,
125    pub max_height: Option<u32>,
126    pub auto_pan: Option<bool>,
127    pub keep_in_view: Option<bool>,
128    pub close_button: Option<bool>,
129    pub auto_close: Option<bool>,
130    pub close_on_escape_key: Option<bool>,
131    pub class_name: Option<String>,
132}
133
134impl Default for PopupOptions {
135    fn default() -> Self {
136        Self {
137            max_width: Some(300),
138            min_width: Some(50),
139            max_height: None,
140            auto_pan: Some(true),
141            keep_in_view: Some(false),
142            close_button: Some(true),
143            auto_close: Some(true),
144            close_on_escape_key: Some(true),
145            class_name: None,
146        }
147    }
148}
149
150/// Map configuration options
151#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
152pub struct MapOptions {
153    pub zoom_control: Option<bool>,
154    pub scroll_wheel_zoom: Option<bool>,
155    pub double_click_zoom: Option<bool>,
156    pub touch_zoom: Option<bool>,
157    pub dragging: Option<bool>,
158    pub keyboard: Option<bool>,
159    pub attribution_control: Option<bool>,
160    pub tile_layer: Option<TileLayer>,
161}
162
163impl Default for MapOptions {
164    fn default() -> Self {
165        Self {
166            zoom_control: Some(true),
167            scroll_wheel_zoom: Some(true),
168            double_click_zoom: Some(true),
169            touch_zoom: Some(true),
170            dragging: Some(true),
171            keyboard: Some(true),
172            attribution_control: Some(true),
173            tile_layer: Some(TileLayer::default()),
174        }
175    }
176}
177
178impl MapOptions {
179    /// Creates a new MapOptions with all fields set to None (minimal configuration)
180    pub fn new() -> Self {
181        Self {
182            zoom_control: None,
183            scroll_wheel_zoom: None,
184            double_click_zoom: None,
185            touch_zoom: None,
186            dragging: None,
187            keyboard: None,
188            attribution_control: None,
189            tile_layer: None,
190        }
191    }
192
193    /// Gets the zoom control setting, falling back to default if None
194    pub fn zoom_control(&self) -> bool {
195        self.zoom_control.unwrap_or(true)
196    }
197
198    /// Gets the scroll wheel zoom setting, falling back to default if None
199    pub fn scroll_wheel_zoom(&self) -> bool {
200        self.scroll_wheel_zoom.unwrap_or(true)
201    }
202
203    /// Gets the double click zoom setting, falling back to default if None
204    pub fn double_click_zoom(&self) -> bool {
205        self.double_click_zoom.unwrap_or(true)
206    }
207
208    /// Gets the touch zoom setting, falling back to default if None
209    pub fn touch_zoom(&self) -> bool {
210        self.touch_zoom.unwrap_or(true)
211    }
212
213    /// Gets the dragging setting, falling back to default if None
214    pub fn dragging(&self) -> bool {
215        self.dragging.unwrap_or(true)
216    }
217
218    /// Gets the keyboard setting, falling back to default if None
219    pub fn keyboard(&self) -> bool {
220        self.keyboard.unwrap_or(true)
221    }
222
223    /// Gets the attribution control setting, falling back to default if None
224    pub fn attribution_control(&self) -> bool {
225        self.attribution_control.unwrap_or(true)
226    }
227
228    /// Gets the tile layer, falling back to default if None
229    pub fn tile_layer(&self) -> TileLayer {
230        self.tile_layer.clone().unwrap_or_default()
231    }
232}
233
234/// Tile layer configuration
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236pub struct TileLayer {
237    pub url: String,
238    pub attribution: String,
239    pub max_zoom: u8,
240    pub subdomains: Vec<String>,
241}
242
243impl TileLayer {
244    /// OpenStreetMap tile layer (default)
245    pub fn openstreetmap() -> Self {
246        Self {
247            url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png".to_string(),
248            attribution: "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors".to_string(),
249            max_zoom: 19,
250            subdomains: vec!["a".to_string(), "b".to_string(), "c".to_string()],
251        }
252    }
253
254    /// Satellite imagery tile layer
255    pub fn satellite() -> Self {
256        Self {
257            url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}".to_string(),
258            attribution: "Tiles &copy; Esri".to_string(),
259            max_zoom: 18,
260            subdomains: vec![],
261        }
262    }
263}
264
265impl Default for TileLayer {
266    fn default() -> Self {
267        Self::openstreetmap()
268    }
269}