|
18 | 18 | <script src="../dist/azure-maps-animations.js"></script> |
19 | 19 |
|
20 | 20 | <script type='text/javascript'> |
21 | | - var map, layer; |
22 | | - |
23 | | - //TODO: Migrate to Azure Maps weather tiles. |
24 | | - |
25 | | - //Weather tile url from Iowa Environmental Mesonet (IEM): http://mesonet.agron.iastate.edu/ogc/ |
26 | | - var urlTemplate = 'https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-{timestamp}/{z}/{x}/{y}.png'; |
27 | | - |
28 | | - //The time stamps values for the IEM service for the last 50 minutes broken up into 5 minute increments. |
29 | | - var timestamps = ['900913-m50m', '900913-m45m', '900913-m40m', '900913-m35m', '900913-m30m', '900913-m25m', '900913-m20m', '900913-m15m', '900913-m10m', '900913-m05m', '900913']; |
| 21 | + var map, layer, timer; |
| 22 | + |
| 23 | + //Base weather tile layer URL for radar data. {azMapsDomain} is a placeholder that is set automatically by the map, and will also automatically append the map credentials to the request. |
| 24 | + var urlTemplate = 'https://{azMapsDomain}/map/tile?api-version=2.0&tilesetId={tilesetId}&zoom={z}&x={x}&y={y}&timeStamp={timestamp}&tileSize=256&view=Auto'; |
| 25 | + |
| 26 | + //Details on the availability of the different weather layers. |
| 27 | + var weatherLayers = { |
| 28 | + 'microsoft.weather.infrared.main': { |
| 29 | + interval: 10 * 60 * 1000, //10 minute interval |
| 30 | + past: 3 * 60 * 60 * 1000, //Data available up to 3 hours in the past. |
| 31 | + future: 0 //Forecast data not avaiable. |
| 32 | + }, |
| 33 | + 'microsoft.weather.radar.main': { |
| 34 | + interval: 5 * 60 * 1000, //5 minute interval |
| 35 | + past: 1.5 * 60 * 60 * 1000, //Data available up to 1.5 hours in the past. |
| 36 | + future: 1.5 * 60 * 60 * 1000 //Data available up to 1.5 hours in the future. |
| 37 | + } |
| 38 | + }; |
30 | 39 |
|
31 | 40 | var displayMessages = []; |
32 | 41 |
|
|
47 | 56 |
|
48 | 57 | //Wait until the map resources are ready. |
49 | 58 | map.events.add('ready', function () { |
50 | | - var tlOptions = []; |
| 59 | + //Load the radar layer by default. |
| 60 | + loadWeatherLayer('microsoft.weather.radar.main'); |
| 61 | + }); |
| 62 | + } |
51 | 63 |
|
52 | | - //Create a tile layer option for each time stamp. |
53 | | - for (var i = 0; i < timestamps.length; i++) { |
54 | | - tlOptions.push({ |
55 | | - tileUrl: urlTemplate.replace('{timestamp}', timestamps[i]), |
56 | | - tileSize: 256, |
57 | | - opacity: 0.8 |
58 | | - }); |
| 64 | + function loadWeatherLayer(tilesetId){ |
| 65 | + //If there is already a layer, stop it animating. |
| 66 | + if(layer){ |
| 67 | + layer.stop(); |
| 68 | + clearInterval(timer); |
| 69 | + } |
59 | 70 |
|
60 | | - //Optionally, create a message to display for each frame of the animation based on the time stamp. |
61 | | - var msg = 'Current'; |
| 71 | + //Get the current time. |
| 72 | + var now = new Date().getTime(); |
62 | 73 |
|
63 | | - if (timestamps[i] != '900913') { |
64 | | - msg += ' -' + timestamps[i].replace('900913-m', '') + 'in'; |
65 | | - } |
| 74 | + //Get the details for the requested weather layer. |
| 75 | + var layerInfo = weatherLayers[tilesetId]; |
| 76 | + |
| 77 | + //Calculate the number of timestamps. |
| 78 | + var numTimestamps = (layerInfo.past + layerInfo.future) / layerInfo.interval; |
66 | 79 |
|
67 | | - displayMessages.push(msg); |
| 80 | + var tlOptions = []; |
| 81 | + |
| 82 | + for(var i = 0; i < numTimestamps; i++) { |
| 83 | + //Calculate time period for an animation frame. Shift the interval by one as the olds tile will expire almost immediately. |
| 84 | + var time = (now - layerInfo.past) + (i + 1) * layerInfo.interval; |
| 85 | + |
| 86 | + //Create a tile layer option for each timestamp. |
| 87 | + tlOptions.push(createTileLayer(tilesetId, time)); |
| 88 | + |
| 89 | + //Optionally, create a message to display for each frame of the animation based on the time stamp. |
| 90 | + if(time === now){ |
| 91 | + displayMessages.push('Current'); |
| 92 | + } else { |
| 93 | + var dt = (time - now) / 1000 / 60; |
| 94 | + displayMessages.push(`${dt} minutes`); |
68 | 95 | } |
| 96 | + } |
69 | 97 |
|
70 | | - //Create the animation manager. |
71 | | - layer = new atlas.layer.AnimatedTileLayer({ |
| 98 | + if(layer){ |
| 99 | + layer.setOptions({ |
| 100 | + tileLayerOptions: tlOptions |
| 101 | + }); |
| 102 | + layer.play(); |
| 103 | + } else { |
| 104 | + //Create the animation manager. |
| 105 | + layer = new atlas.layer.AnimatedTileLayer({ |
72 | 106 | tileLayerOptions: tlOptions, |
73 | | - duration: timestamps.length * 1000, //Allow one second for each frame (tile layer) in the animation. |
| 107 | + duration: numTimestamps * 800, //Allow one second for each frame (tile layer) in the animation. |
74 | 108 | autoPlay: true, |
75 | 109 | loop: true |
76 | 110 | }); |
|
81 | 115 | var msg = displayMessages[e.frameIdx]; |
82 | 116 | document.getElementById('messagePanel').innerText = msg; |
83 | 117 | } |
84 | | - }); |
| 118 | + }); |
85 | 119 |
|
86 | 120 | //Add the layer to the map. |
87 | 121 | map.layers.add(layer, 'labels'); |
88 | | - }); |
| 122 | + |
| 123 | + //Setup an interval timer to shift the layers (remove oldest, add newest) based on the update interval of the tile layer. |
| 124 | + timer = setInterval(intervalHandler(tilesetId), layerInfo.interval); |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + function createTileLayer(tilesetId, time){ |
| 129 | + //Create an ISO 8601 timestamp string. |
| 130 | + //JavaScripts format for ISO string includes decimal seconds and the letter "Z" at the end that is not supported. Use slice to remove this. |
| 131 | + var timestamp = new Date(time).toISOString().slice(0, 19); |
| 132 | + |
| 133 | + //Create a tile layer option for each timestamp. |
| 134 | + return { |
| 135 | + tileUrl: urlTemplate.replace('{tilesetId}', tilesetId).replace('{timestamp}', timestamp), |
| 136 | + tileSize: 256, //Weather tiles only available in 256 pixel size. |
| 137 | + opacity: 0.9, |
| 138 | + maxSourceZoom: 15 //Weather tiles only available to zoom level 15. If you zoom in closer, the map may pull tiles from level 15 to fill the map. |
| 139 | + }; |
| 140 | + } |
| 141 | + |
| 142 | + function intervalHandler(tilesetId) { |
| 143 | + return function(){ |
| 144 | + //Get the details for the requested weather layer. |
| 145 | + var layerInfo = weatherLayers[tilesetId]; |
| 146 | + |
| 147 | + //Calculate time period for an animation frame. Shift the interval by one as the olds tile will expire almost immediately. |
| 148 | + var time = (now - layerInfo.past) + (i + 1) * layerInfo.interval; |
| 149 | + |
| 150 | + //Create an ISO 8601 timestamp string. |
| 151 | + //JavaScripts format for ISO string includes decimal seconds and the letter "Z" at the end that is not supported. Use slice to remove this. |
| 152 | + var timestamp = new Date(time).toISOString().slice(0, 19); |
| 153 | + |
| 154 | + //Get the current tile layer options from the animation layer. |
| 155 | + var layers = layer.getOptions().tileLayerOptions; |
| 156 | + |
| 157 | + //Remove the oldest tile layer options. |
| 158 | + tlOptions.shift(); |
| 159 | + |
| 160 | + //Add the newest tile layer options. |
| 161 | + tlOptions.push(createTileLayer(tilesetId, time)); |
| 162 | + |
| 163 | + //Update the animation layer. |
| 164 | + layer.setOptions({ tileLayerOptions: tlOptions }); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + function updateTileLayer(elm){ |
| 169 | + var tilesetId = elm.options[elm.selectedIndex].value; |
| 170 | + loadWeatherLayer(tilesetId); |
| 171 | + } |
| 172 | + |
| 173 | + function setSpeed(elm){ |
| 174 | + var speed = parseFloat(elm.options[elm.selectedIndex].value); |
| 175 | + |
| 176 | + layer.setOptions({ speedMultiplier: speed }); |
89 | 177 | } |
90 | 178 | </script> |
91 | 179 | </head> |
92 | 180 | <body onload="GetMap()"> |
93 | 181 | <div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div> |
94 | 182 |
|
95 | 183 | <div style="position:absolute;top:15px;left:15px;border-radius:5px;padding:5px;background-color:white;"> |
| 184 | + Select weather overlay: |
| 185 | + <select onchange="updateTileLayer(this)"> |
| 186 | + <option value="microsoft.weather.radar.main" selected="selected">Radar</option> |
| 187 | + <option value="microsoft.weather.infrared.main">Infrared</option> |
| 188 | + </select> |
| 189 | + <br/><br/> |
96 | 190 | <input type="button" value="Play" onclick="layer.play();" /> |
97 | 191 | <input type="button" value="Pause" onclick="layer.pause();" /> |
98 | 192 | <input type="button" value="Stop" onclick="layer.stop();" /> |
99 | 193 | <input type="button" value="Reset" onclick="layer.reset();" /> |
| 194 | + <br/><br/> |
| 195 | + Speed: |
| 196 | + <select onchange="setSpeed(this)"> |
| 197 | + <option value="0.5">0.5x</option> |
| 198 | + <option value="1" selected="selected">1x</option> |
| 199 | + <option value="2">2x</option> |
| 200 | + <option value="5">5x</option> |
| 201 | + </select> |
100 | 202 | </div> |
101 | 203 |
|
102 | 204 | <div id="messagePanel" style="position: absolute;top: 20px;right: 20px;background-color: white;padding: 2px;border-radius: 15px;width: 110px;text-align: center;"></div> |
|
105 | 207 | <legend><h1 style="font-size:16px">Animated tile layer</h1></legend> |
106 | 208 | This sample shows how to animate an sequence of tile layers smoothly. |
107 | 209 | This example uses the AnimatedTileLayer to animate through an array of tile layers. |
108 | | - For this sample weather radar tiles from the <a href="https://www.mesonet.agron.iastate.edu/ogc/">Iowa Environmental Mesonet of Iowa State University</a> |
109 | | - over the USA are animated for the last 50 minutes in 5 minute increments. |
| 210 | + For this sample weather data from Azure Maps through the <a href="https://docs.microsoft.com/en-us/rest/api/maps/renderv2/getmaptilepreview">Reader services</a> are used. |
| 211 | + Infrared data is updated every 10 minutes and available for 3 hours in the past. Radar data updated every 5 minutes and available 1.5 hours past and future forecast. |
110 | 212 | This sample uses the open source <a href="https://github.com/Azure-Samples/azure-maps-animations" target="_blank">Azure Maps Animation module</a> |
111 | 213 | </fieldset> |
112 | 214 | </body> |
|
0 commit comments