//! Tile visibility and data fetching utilities use wasm_bindgen::JsCast; use crate::camera::Camera; /// Fetch tile data with caching pub async fn fetch_cached(url: &str) -> Option> { let window = web_sys::window()?; let caches = window.caches().ok()?; let cache_name = "map-data-v5-sand"; let cache = wasm_bindgen_futures::JsFuture::from(caches.open(cache_name)).await.ok()?; let cache: web_sys::Cache = cache.dyn_into().ok()?; let request = web_sys::Request::new_with_str(url).ok()?; let match_promise = cache.match_with_request(&request); let match_val = wasm_bindgen_futures::JsFuture::from(match_promise).await.ok()?; if !match_val.is_undefined() { let response: web_sys::Response = match_val.dyn_into().ok()?; let buffer_promise = response.array_buffer().ok()?; let buffer = wasm_bindgen_futures::JsFuture::from(buffer_promise).await.ok()?; let array = js_sys::Uint8Array::new(&buffer); return Some(array.to_vec()); } // Network fetch let response_val = wasm_bindgen_futures::JsFuture::from(window.fetch_with_request(&request)).await.ok()?; let response: web_sys::Response = response_val.dyn_into().ok()?; // Clone response for cache let response_clone = response.clone().ok()?; let put_promise = cache.put_with_request(&request, &response_clone); wasm_bindgen_futures::JsFuture::from(put_promise).await.ok()?; let buffer_promise = response.array_buffer().ok()?; let buffer = wasm_bindgen_futures::JsFuture::from(buffer_promise).await.ok()?; let array = js_sys::Uint8Array::new(&buffer); Some(array.to_vec()) } /// Get visible tiles based on current camera position pub fn get_visible_tiles(camera: &Camera) -> Vec<(i32, i32, i32)> { // Select zoom level based on camera zoom // Zoom 6: World/Country view // Zoom 9: Region view // Zoom 12: City view // Zoom 14: Street view let z = if camera.zoom < 100.0 { 2 } else if camera.zoom < 500.0 { 4 } else if camera.zoom < 2000.0 { 6 } else if camera.zoom < 5000.0 { 9 } else if camera.zoom < 10000.0 { 12 } else { 14 }; let n = 2.0f64.powi(z); let half_width = 1.0 * camera.aspect / camera.zoom; let half_height = 1.0 / camera.zoom; let min_x = (camera.x - half_width).max(0.0) as f64; let max_x = (camera.x + half_width).min(1.0) as f64; let min_y = (camera.y - half_height).max(0.0) as f64; let max_y = (camera.y + half_height).min(1.0) as f64; let min_tile_x = (min_x * n).floor() as i32; let max_tile_x = (max_x * n).floor() as i32; let min_tile_y = (min_y * n).floor() as i32; let max_tile_y = (max_y * n).floor() as i32; let mut tiles = Vec::new(); for x in min_tile_x..=max_tile_x { for y in min_tile_y..=max_tile_y { tiles.push((z, x, y)); } } tiles } /// Get parent tile for the tile retention hierarchy pub fn get_parent_tile(z: i32, x: i32, y: i32) -> Option<(i32, i32, i32)> { // Hierarchy: 14 -> 12 -> 9 -> 6 -> 2 let parent_z = match z { 14 => 12, 12 => 9, 9 => 6, 6 => 4, 4 => 2, _ => return None, }; // Calculate scale difference let diff = z - parent_z; let factor = 2i32.pow(diff as u32); Some((parent_z, x / factor, y / factor)) }