dioxus_leaflet/
utils.rs

1use crate::types::*;
2
3/// Generates a unique map ID
4pub fn generate_map_id() -> String {
5    format!("dioxus_leaflet_map_{}", fastrand::u32(..))
6}
7
8/// Generates the JavaScript initialization script for the map
9pub fn generate_map_script(
10    map_id: &str,
11    initial_position: &MapPosition,
12    markers: &[MapMarker],
13    options: &MapOptions,
14) -> String {
15    let markers_json = serde_json::to_string(markers).unwrap_or_else(|_| "[]".to_string());
16    let escaped_markers = escape_json_for_js(&markers_json);
17    
18    format!(
19        r#"
20        (function() {{
21            function initializeDioxusLeafletMap() {{
22                function tryInitialize() {{
23                    if (typeof L === 'undefined') {{
24                        setTimeout(tryInitialize, 100);
25                        return;
26                    }}
27                    
28                    var mapElement = document.getElementById('{}');
29                    if (!mapElement) {{
30                        setTimeout(tryInitialize, 100);
31                        return;
32                    }}
33                    
34                    try {{
35                        // Initialize the map with options
36                        var map = L.map('{}', {{
37                            zoomControl: {},
38                            scrollWheelZoom: {},
39                            doubleClickZoom: {},
40                            touchZoom: {},
41                            dragging: {},
42                            keyboard: {},
43                            attributionControl: {}
44                        }}).setView([{}, {}], {});
45
46                        // Add tile layer
47                        L.tileLayer('{}', {{
48                            attribution: '{}',
49                            maxZoom: {},
50                            subdomains: {}
51                        }}).addTo(map);
52
53                        // Add markers
54                        var markersData = "{}";
55                        var markers = JSON.parse(markersData);
56                        
57                        markers.forEach(function(markerData) {{
58                            var markerOptions = {{}};
59                            
60                            // Custom icon if provided
61                            if (markerData.icon) {{
62                                var iconOptions = {{
63                                    iconUrl: markerData.icon.icon_url
64                                }};
65                                
66                                if (markerData.icon.icon_size) {{
67                                    iconOptions.iconSize = markerData.icon.icon_size;
68                                }}
69                                if (markerData.icon.icon_anchor) {{
70                                    iconOptions.iconAnchor = markerData.icon.icon_anchor;
71                                }}
72                                if (markerData.icon.popup_anchor) {{
73                                    iconOptions.popupAnchor = markerData.icon.popup_anchor;
74                                }}
75                                if (markerData.icon.shadow_url) {{
76                                    iconOptions.shadowUrl = markerData.icon.shadow_url;
77                                }}
78                                if (markerData.icon.shadow_size) {{
79                                    iconOptions.shadowSize = markerData.icon.shadow_size;
80                                }}
81                                
82                                markerOptions.icon = L.icon(iconOptions);
83                            }}
84                            
85                            var marker = L.marker([markerData.lat, markerData.lng], markerOptions).addTo(map);
86                            
87                            // Add popup if title or description exists
88                            if (markerData.title || markerData.description) {{
89                                var popupContent = '';
90                                if (markerData.title) {{
91                                    popupContent += '<b>' + markerData.title + '</b>';
92                                }}
93                                if (markerData.description) {{
94                                    if (markerData.title) popupContent += '<br>';
95                                    popupContent += markerData.description;
96                                }}
97                                
98                                var popupOptions = {{}};
99                                if (markerData.popup_options) {{
100                                    Object.assign(popupOptions, markerData.popup_options);
101                                }}
102                                
103                                marker.bindPopup(popupContent, popupOptions);
104                            }}
105                        }});
106                        
107                        // Force resize to ensure proper display
108                        setTimeout(function() {{
109                            map.invalidateSize();
110                        }}, 100);
111                        
112                        // Store map reference for potential future use
113                        window.dioxusLeafletMaps = window.dioxusLeafletMaps || {{}};
114                        window.dioxusLeafletMaps['{}'] = map;
115                        
116                    }} catch (error) {{
117                        console.error('Error initializing Dioxus Leaflet map:', error);
118                    }}
119                }}
120                
121                tryInitialize();
122            }}
123            
124            // Initialize when DOM is ready
125            if (document.readyState === 'loading') {{
126                document.addEventListener('DOMContentLoaded', initializeDioxusLeafletMap);
127            }} else {{
128                initializeDioxusLeafletMap();
129            }}
130        }})();
131        "#,
132        map_id,
133        map_id,
134        bool_to_js(options.zoom_control()),
135        bool_to_js(options.scroll_wheel_zoom()),
136        bool_to_js(options.double_click_zoom()),
137        bool_to_js(options.touch_zoom()),
138        bool_to_js(options.dragging()),
139        bool_to_js(options.keyboard()),
140        bool_to_js(options.attribution_control()),
141        initial_position.lat,
142        initial_position.lng,
143        initial_position.zoom,
144        options.tile_layer().url,
145        options.tile_layer().attribution,
146        options.tile_layer().max_zoom,
147        serde_json::to_string(&options.tile_layer().subdomains).unwrap_or_else(|_| "[]".to_string()),
148        escaped_markers,
149        map_id
150    )
151}
152
153/// Escapes JSON string for safe inclusion in JavaScript
154pub fn escape_json_for_js(json: &str) -> String {
155    json.replace('\\', "\\\\")
156        .replace('"', "\\\"")
157        .replace('\n', "\\n")
158        .replace('\r', "\\r")
159        .replace('\t', "\\t")
160}
161
162/// Converts Rust bool to JavaScript boolean string
163pub fn bool_to_js(value: bool) -> &'static str {
164    if value { "true" } else { "false" }
165}