286 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html>
 | |
| <head>
 | |
|     <title>RainViewer MAP</title>
 | |
| 
 | |
|     <meta charset="utf-8"/>
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | |
| 
 | |
|     <link rel="stylesheet" href="https://gpslog.famzur.de/js/leaflet/leaflet.css"/>
 | |
|     <script src="https://gpslog.famzur.de/js/leaflet/leaflet.js"></script>
 | |
|     <style type="text/css">
 | |
|         li {
 | |
|             list-style: none;
 | |
|             display: inline-block;
 | |
|         }
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
| 
 | |
| <ul style="text-align:center; position: absolute;top: 0; left: 0; right: 0; height: 50px;">
 | |
|     <li>
 | |
|         <input type="radio" name="kind" onchange="setKind('radar')">Radar (Past + Future)
 | |
|         <input type="radio" name="kind" onchange="setKind('radarPast')">Radar (Past)
 | |
|         <input type="radio" name="kind" checked="checked" onchange="setKind('radarFuture')">Radar (Future)
 | |
|         <input type="radio" name="kind" onchange="setKind('satellite')">Infrared Satellite
 | |
|     </li>
 | |
| 
 | |
|     <li><input type="button" onclick="stop(); showFrame(animationPosition - 1); return;" value="<" /></li>
 | |
|     <li><input type="button" onclick="playStop();" value="Play / Stop" /></li>
 | |
|     <li><input type="button" onclick="stop(); showFrame(animationPosition + 1); return;" value=">" /></li>
 | |
| 
 | |
|     <li><select id="colors" onchange="setColors(); return;">
 | |
|         <option value="0">Black and White Values</option>
 | |
|         <option value="1">Original</option>
 | |
|         <option value="2" selected="selected">Universal Blue</option>
 | |
|         <option value="3">TITAN</option>
 | |
|         <option value="4">The Weather Channel</option>
 | |
|         <option value="5">Meteored</option>
 | |
|         <option value="6">NEXRAD Level-III</option>
 | |
|         <option value="7">RAINBOW @ SELEX-SI</option>
 | |
|         <option value="8">Dark Sky</option>
 | |
|     </select></li>
 | |
| </ul>
 | |
| 
 | |
| <div id="timestamp" style="text-align:center; position: absolute;top: 50px; left: 0; right: 0; height: 80px;">FRAME TIME</div>
 | |
| 
 | |
| <div id="mapid" style="position: absolute; top: 80px; left: 0; bottom: 0; right: 0;"></div>
 | |
| 
 | |
| <script>
 | |
|     var map = L.map('mapid').setView([48.678154534097324, 9.283021551577976], 12);
 | |
| 
 | |
|     L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
 | |
|         attributions: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'
 | |
|     }).addTo(map);
 | |
|     
 | |
|     L.marker([48.678154534097324, 9.283021551577976]).addTo(map);
 | |
| 
 | |
|     /**
 | |
|      * RainViewer radar animation part
 | |
|      * @type {number[]}
 | |
|      */
 | |
|     var apiData = {};
 | |
|     var mapFrames = [];
 | |
|     var lastPastFramePosition = -1;
 | |
|     var radarLayers = [];
 | |
| 
 | |
|     var optionKind = 'radar'; // can be 'radar' or 'satellite'
 | |
| 
 | |
|     var optionTileSize = 256; // can be 256 or 512.
 | |
|     var optionColorScheme = 2; // from 0 to 8. Check the https://rainviewer.com/api/color-schemes.html for additional information
 | |
|     var optionSmoothData = 1; // 0 - not smooth, 1 - smooth
 | |
|     var optionSnowColors = 1; // 0 - do not show snow colors, 1 - show snow colors
 | |
| 
 | |
|     var animationPosition = 0;
 | |
|     var animationTimer = false;
 | |
| 
 | |
|     /**
 | |
|      * Load all the available maps frames from RainViewer API
 | |
|      */
 | |
|     var apiRequest = new XMLHttpRequest();
 | |
|     apiRequest.open("GET", "https://api.rainviewer.com/public/weather-maps.json", true);
 | |
|     apiRequest.onload = function(e) {
 | |
|         // store the API response for re-use purposes in memory
 | |
|         apiData = JSON.parse(apiRequest.response);
 | |
|         initialize(apiData, optionKind);
 | |
|     };
 | |
|     apiRequest.send();
 | |
| 
 | |
|     /**
 | |
|      * Initialize internal data from the API response and options
 | |
|      */
 | |
|     function initialize(api, kind) {
 | |
|         // remove all already added tiled layers
 | |
|         for (var i in radarLayers) {
 | |
|             map.removeLayer(radarLayers[i]);
 | |
|         }
 | |
|         mapFrames = [];
 | |
|         radarLayers = [];
 | |
|         animationPosition = 0;
 | |
| 
 | |
|         if (!api) {
 | |
|             return;
 | |
|         }
 | |
|         switch (kind) {
 | |
|             case 'satellite':
 | |
|                 if (api.satellite && api.satellite.infrared) {
 | |
|                     mapFrames = api.satellite.infrared;
 | |
| 
 | |
|                     lastPastFramePosition = api.satellite.infrared.length - 1;
 | |
|                     showFrame(lastPastFramePosition);
 | |
|                 }
 | |
|                 break;
 | |
|             case 'radar':
 | |
|                 if (api.radar && api.radar.past) {
 | |
|                     mapFrames = api.radar.past;
 | |
|                     if (api.radar.nowcast) {
 | |
|                         mapFrames = mapFrames.concat(api.radar.nowcast);
 | |
|                     }
 | |
| 
 | |
|                     // show the last "past" frame
 | |
|                     lastPastFramePosition = api.radar.past.length - 1;
 | |
|                     showFrame(lastPastFramePosition);
 | |
|                 }
 | |
|                 break;
 | |
|             case 'radarPast':
 | |
|                 if (api.radar && api.radar.past) {
 | |
|                     mapFrames = api.radar.past;
 | |
| 
 | |
|                     // show the last "past" frame
 | |
|                     lastPastFramePosition = api.radar.past.length - 1;
 | |
|                     showFrame(lastPastFramePosition);
 | |
|                 }
 | |
|                 break;
 | |
|             case 'radarFuture':
 | |
|                 if (api.radar && api.radar.past) {
 | |
|                     mapFrames = mapFrames.concat(api.radar.past[api.radar.past.length - 1]);
 | |
|                     if (api.radar.nowcast) {
 | |
|                         mapFrames = mapFrames.concat(api.radar.nowcast);
 | |
|                     }
 | |
| 
 | |
|                     // show the last "past" frame
 | |
|                     lastPastFramePosition = 0;
 | |
|                     showFrame(lastPastFramePosition);
 | |
|                 }
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Animation functions
 | |
|      * @param path - Path to the XYZ tile
 | |
|      */
 | |
|     function addLayer(frame) {
 | |
|         if (!radarLayers[frame.path]) {
 | |
|             var colorScheme = optionKind == 'satellite' ? 0 : optionColorScheme;
 | |
|             var smooth = optionKind == 'satellite' ? 0 : optionSmoothData;
 | |
|             var snow = optionKind == 'satellite' ? 0 : optionSnowColors;
 | |
| 
 | |
|             radarLayers[frame.path] = new L.TileLayer(apiData.host + frame.path + '/' + optionTileSize + '/{z}/{x}/{y}/' + colorScheme + '/' + smooth + '_' + snow + '.png', {
 | |
|                 tileSize: 256,
 | |
|                 opacity: 0.001,
 | |
|                 zIndex: frame.time
 | |
|             });
 | |
|         }
 | |
|         if (!map.hasLayer(radarLayers[frame.path])) {
 | |
|             map.addLayer(radarLayers[frame.path]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Display particular frame of animation for the @position
 | |
|      * If preloadOnly parameter is set to true, the frame layer only adds for the tiles preloading purpose
 | |
|      * @param position
 | |
|      * @param preloadOnly
 | |
|      */
 | |
|     function changeRadarPosition(position, preloadOnly) {
 | |
|         while (position >= mapFrames.length) {
 | |
|             position -= mapFrames.length;
 | |
|         }
 | |
|         while (position < 0) {
 | |
|             position += mapFrames.length;
 | |
|         }
 | |
| 
 | |
|         var currentFrame = mapFrames[animationPosition];
 | |
|         var nextFrame = mapFrames[position];
 | |
| 
 | |
|         addLayer(nextFrame);
 | |
| 
 | |
|         if (preloadOnly) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         animationPosition = position;
 | |
| 
 | |
|         if (radarLayers[currentFrame.path]) {
 | |
|             radarLayers[currentFrame.path].setOpacity(0);
 | |
|         }
 | |
|         radarLayers[nextFrame.path].setOpacity(100);
 | |
| 
 | |
| 
 | |
|         var pastOrForecast = nextFrame.time > Date.now() / 1000 ? 'FORECAST' : 'PAST';
 | |
| 
 | |
|         document.getElementById("timestamp").innerHTML = pastOrForecast + ': ' + (new Date(nextFrame.time * 1000)).toString();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Check avialability and show particular frame position from the timestamps list
 | |
|      */
 | |
|     function showFrame(nextPosition) {
 | |
|         var preloadingDirection = nextPosition - animationPosition > 0 ? 1 : -1;
 | |
| 
 | |
|         changeRadarPosition(nextPosition);
 | |
| 
 | |
|         // preload next next frame (typically, +1 frame)
 | |
|         // if don't do that, the animation will be blinking at the first loop
 | |
|         changeRadarPosition(nextPosition + preloadingDirection, true);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Stop the animation
 | |
|      * Check if the animation timeout is set and clear it.
 | |
|      */
 | |
|     function stop() {
 | |
|         if (animationTimer) {
 | |
|             clearTimeout(animationTimer);
 | |
|             animationTimer = false;
 | |
|             return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     function play() {
 | |
|         showFrame(animationPosition + 1);
 | |
| 
 | |
|         // Main animation driver. Run this function every 500 ms
 | |
|         animationTimer = setTimeout(play, 500);
 | |
|     }
 | |
| 
 | |
|     function playStop() {
 | |
|         if (!stop()) {
 | |
|             play();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Change map options
 | |
|      */
 | |
|     function setKind(kind) {
 | |
|         optionKind = kind;
 | |
|         initialize(apiData, optionKind);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     function setColors() {
 | |
|         var e = document.getElementById('colors');
 | |
|         optionColorScheme = e.options[e.selectedIndex].value;
 | |
|         initialize(apiData, optionKind);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Handle arrow keys for navigation between next \ prev frames
 | |
|      */
 | |
|     document.onkeydown = function (e) {
 | |
|         e = e || window.event;
 | |
|         switch (e.which || e.keyCode) {
 | |
|             case 37: // left
 | |
|                 stop();
 | |
|                 showFrame(animationPosition - 1);
 | |
|                 break;
 | |
| 
 | |
|             case 39: // right
 | |
|                 stop();
 | |
|                 showFrame(animationPosition + 1);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 return; // exit this handler for other keys
 | |
|         }
 | |
|         e.preventDefault();
 | |
|         return false;
 | |
|     }
 | |
| </script>
 | |
| 
 | |
| </body>
 | |
| </html>
 | 
