### Initialize and Load API Data Source: https://github.com/rainviewer/rainviewer-api-example/blob/master/rainviewer-api-example.html Sets up the map, fetches data from the RainViewer API, and initializes the radar display. Ensure the API URL is correct and accessible. ```javascript var TILE_SIZE = window.devicePixelRatio >= 2 ? 512 : 256; var RADAR_OPACITY = 0.8; var ANIMATION_DELAY_MS = 500; var API_URL = "https://api.rainviewer.com/public/weather-maps.json"; var apiData = {}; var mapFrames = []; var animationPosition = 0; var animationTimer = false; var currentLayer = null; var isLoading = false; var layerCache = {}; var map = L.map('mapid', { maxZoom: 12 }).setView([48.8566, 2.3522], 5); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); function wrapPosition(position) { while (position >= mapFrames.length) { position -= mapFrames.length; } while (position < 0) { position += mapFrames.length; } return position; } function formatTime(timestamp) { return new Date(timestamp * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } function createRadarLayer(frame) { return new L.TileLayer(apiData.host + frame.path + '/' + TILE_SIZE + '/{z}/{x}/{y}/2/1_1.png', { tileSize: 256, opacity: 0.001, maxNativeZoom: 7, maxZoom: 12 }); } function clearLayerCache() { stop(); for (var pos in layerCache) { if (parseInt(pos) !== animationPosition) { map.removeLayer(layerCache[pos]); delete layerCache[pos]; } } } function stop() { if (animationTimer) { clearTimeout(animationTimer); animationTimer = false; document.getElementById("playBtn").innerHTML = "▶"; return true; } return false; } function play() { animationTimer = true; document.getElementById("playBtn").innerHTML = "⏸"; showFrame(animationPosition + 1); } function playStop() { if (!stop()) { play(); } } function updateTimestamp(frame) { document.getElementById("timestamp").innerHTML = formatTime(frame.time); } function showFrame(position) { if (isLoading) return; position = wrapPosition(position); var frame = mapFrames[position]; updateTimestamp(frame); var oldLayer = currentLayer; if (layerCache[position]) { if (oldLayer) { oldLayer.setOpacity(0); } layerCache[position].setOpacity(RADAR_OPACITY); currentLayer = layerCache[position]; animationPosition = position; if (animationTimer) { animationTimer = setTimeout(play, ANIMATION_DELAY_MS); } return; } isLoading = true; var newLayer = createRadarLayer(frame); newLayer.on('load', function() { newLayer.setOpacity(RADAR_OPACITY); if (oldLayer) { oldLayer.setOpacity(0); } layerCache[position] = newLayer; currentLayer = newLayer; animationPosition = position; isLoading = false; if (animationTimer) { animationTimer = setTimeout(play, ANIMATION_DELAY_MS); } }); newLayer.addTo(map); } function initialize(api) { clearLayerCache(); currentLayer = null; mapFrames = []; animationPosition = 0; if (!api || !api.radar || !api.radar.past) { return; } mapFrames = api.radar.past; showFrame(mapFrames.length - 1); } function loadApiData() { var apiRequest = new XMLHttpRequest(); apiRequest.open("GET", API_URL, true); apiRequest.onload = function() { apiData = JSON.parse(apiRequest.response); initialize(apiData); }; apiRequest.send(); } map.on('movestart', clearLayerCache); loadApiData(); ``` -------------------------------- ### Initialize MapLibre GL JS Map and Fetch Radar Data Source: https://context7.com/rainviewer/rainviewer-api-example/llms.txt Sets up the MapLibre map with a base style and fetches radar data from the RainViewer API upon map load. Requires MapLibre GL JS CSS and JS. ```html
``` -------------------------------- ### Leaflet Radar Map Implementation Source: https://context7.com/rainviewer/rainviewer-api-example/llms.txt Full HTML implementation including map initialization, radar tile layer creation, and frame animation logic. ```html
``` -------------------------------- ### Construct Radar Tile URLs Source: https://context7.com/rainviewer/rainviewer-api-example/llms.txt Generate tile URLs by combining host, frame path, resolution, and coordinate parameters. ```javascript // Tile URL pattern: // {host}{path}/{size}/{z}/{x}/{y}/{color}/{options}.png var TILE_SIZE = window.devicePixelRatio >= 2 ? 512 : 256; var apiData = {}; // Populated from API response // Construct tile URL for a specific frame function getTileUrl(frame, z, x, y) { // Parameters: // - size: 256 or 512 (tile resolution) // - z/x/y: standard tile coordinates // - color: 2 = Universal Blue (only option for personal use) // - options: 1_1 = smooth edges + snow detection return apiData.host + frame.path + '/' + TILE_SIZE + '/' + z + '/' + x + '/' + y + '/2/1_1.png'; } // Example tile URL: // https://tilecache.rainviewer.com/v2/radar/1234567200/512/5/16/11/2/1_1.png ``` -------------------------------- ### Implement Animation Controls Source: https://context7.com/rainviewer/rainviewer-api-example/llms.txt A timer-based system for cycling through map frames with play/pause functionality and frame navigation. ```javascript var ANIMATION_DELAY_MS = 500; var animationTimer = false; var animationPosition = 0; var mapFrames = []; // Populated from API // Stop animation function stop() { if (animationTimer) { clearTimeout(animationTimer); animationTimer = false; document.getElementById("playBtn").innerHTML = "▶"; return true; } return false; } // Start animation function play() { animationTimer = true; document.getElementById("playBtn").innerHTML = "⏸"; showFrame(animationPosition + 1); } // Toggle play/pause function playStop() { if (!stop()) { play(); } } // Modified showFrame to continue animation function showFrame(position) { position = ((position % mapFrames.length) + mapFrames.length) % mapFrames.length; // ... display frame logic ... animationPosition = position; // Schedule next frame if animating if (animationTimer) { animationTimer = setTimeout(play, ANIMATION_DELAY_MS); } } // Format timestamp for display function formatTime(timestamp) { return new Date(timestamp * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } // Usage in HTML // // // ``` -------------------------------- ### Fetch Weather Map Frames via API Source: https://context7.com/rainviewer/rainviewer-api-example/llms.txt Retrieve the JSON metadata containing available radar frames and host information. ```bash # Fetch available weather map frames curl "https://api.rainviewer.com/public/weather-maps.json" # Response structure: # { # "version": "2.0", # "generated": 1234567890, # "host": "https://tilecache.rainviewer.com", # "radar": { # "past": [ # { "time": 1234567200, "path": "/v2/radar/1234567200" }, # { "time": 1234567800, "path": "/v2/radar/1234567800" } # ] # } # } ``` -------------------------------- ### Rain Viewer Map Integration Logic Source: https://github.com/rainviewer/rainviewer-api-example/blob/master/rainviewer-maplibre-example.html JavaScript implementation for fetching API data, managing map layers, and handling animation frames. ```javascript // === CONFIGURATION === var TILE_SIZE = window.devicePixelRatio >= 2 ? 512 : 256; var RADAR_OPACITY = 0.8; var ANIMATION_DELAY_MS = 500; var API_URL = "https://api.rainviewer.com/public/weather-maps.json"; // === STATE === var apiData = {}; var mapFrames = []; var animationPosition = 0; var animationTimer = false; var currentLayerId = null; var isLoading = false; var loadedPositions = new Set(); // === MAP SETUP === var map = new maplibregl.Map({ container: 'map', style: 'https://maps.rainviewer.com/styles/m2/style.json', center: [2.3522, 48.8566], zoom: 4, maxZoom: 12 }); map.addControl(new maplibregl.NavigationControl()); // === UTILITIES === function wrapPosition(position) { while (position >= mapFrames.length) { position -= mapFrames.length; } while (position < 0) { position += mapFrames.length; } return position; } function formatTime(timestamp) { return new Date(timestamp * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } // === LAYER MANAGEMENT === function createRadarSource(position, frame) { var sourceId = 'radar-' + position; map.addSource(sourceId, { type: 'raster', tiles: [apiData.host + frame.path + '/' + TILE_SIZE + '/{z}/{x}/{y}/2/1_1.png'], tileSize: 256, maxzoom: 7 }); return sourceId; } function createRadarLayer(sourceId, layerId) { map.addLayer({ id: layerId, type: 'raster', source: sourceId, paint: { 'raster-opacity': 0.001, 'raster-opacity-transition': { duration: 0, delay: 0 }, 'raster-fade-duration': 0 } }); } function clearLayerCache() { stop(); loadedPositions.forEach(function(pos) { if (pos !== animationPosition) { var layerId = 'radar-layer-' + pos; var sourceId = 'radar-' + pos; if (map.getLayer(layerId)) map.removeLayer(layerId); if (map.getSource(sourceId)) map.removeSource(sourceId); } }); loadedPositions.clear(); loadedPositions.add(animationPosition); } // === ANIMATION CONTROL === function stop() { if (animationTimer) { clearTimeout(animationTimer); animationTimer = false; document.getElementById("playBtn").innerHTML = "▶"; return true; } return false; } function play() { animationTimer = true; document.getElementById("playBtn").innerHTML = "⏸"; showFrame(animationPosition + 1); } function playStop() { if (!stop()) { play(); } } // === DISPLAY === function updateTimestamp(frame) { document.getElementById("timestamp").innerHTML = formatTime(frame.time); } function showFrame(position) { if (isLoading) return; position = wrapPosition(position); var frame = mapFrames[position]; updateTimestamp(frame); var newSourceId = 'radar-' + position; var newLayerId = 'radar-layer-' + position; var oldLayerId = currentLayerId; if (loadedPositions.has(position)) { if (oldLayerId && oldLayerId !== newLayerId && map.getLayer(oldLayerId)) { map.setPaintProperty(oldLayerId, 'raster-opacity', 0); } map.setPaintProperty(newLayerId, 'raster-opacity', RADAR_OPACITY); currentLayerId = newLayerId; animationPosition = position; if (animationTimer) { animationTimer = setTimeout(play, ANIMATION_DELAY_MS); } return; } isLoading = true; createRadarSource(position, frame); createRadarLayer(newSourceId, newLayerId); currentLayerId = newLayerId; function onSourceData(e) { if (e.sourceId === newSourceId && map.isSourceLoaded(newSourceId)) { map.off('sourcedata', onSourceData); map.once('idle', function() { map.setPaintProperty(newLayerId, 'raster-opacity', RADAR_OPACITY); if (oldLayerId && oldLayerId !== newLayerId && map.getLayer(oldLayerId)) { map.setPaintProperty(oldLayerId, 'raster-opacity', 0); } loadedPositions.add(position); animationPosition = position; isLoading = false; if (animationTimer) { animationTimer = setTimeout(play, ANIMATION_DELAY_MS); } }); } } map.on('sourcedata', onSourceData); } // === INITIALIZATION === function initialize(api) { if (!api || !api.radar || !api.radar.past) { return; } mapFrames = api.radar.past; showFrame(mapFrames.length - 1); } function loadApiData() { var apiRequest = new XMLHttpRequest(); apiRequest.open("GET", API_URL, true); apiRequest.onload = function() { apiData = JSON.parse(apiRequest.response); initialize(apiData); }; apiRequest.send(); } map.on('movestart', clearLayerCache); map.on('load', loadApiData); ``` -------------------------------- ### CSS Styles for Map Controls Source: https://github.com/rainviewer/rainviewer-api-example/blob/master/rainviewer-maplibre-example.html Basic layout styles for the map container and overlay controls. ```css body { margin: 0; font-family: sans-serif; } .controls { position: absolute; top: 0; left: 0; right: 0; height: 50px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; background: white; z-index: 1000; box-sizing: border-box; } .title { font-weight: 400; color: #333; } #timestamp { font-size: 18px; font-weight: 600; color: #333; } .buttons { display: flex; gap: 8px; } .buttons button { width: 36px; height: 36px; border: 1px solid #ddd; border-radius: 4px; background: #fff; cursor: pointer; font-size: 16px; } .buttons button:hover { background: #f5f5f5; } #map { position: absolute; top: 50px; left: 0; bottom: 0; right: 0; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.