From 50509f80e14889fea0f0081323ca2b577bcec935 Mon Sep 17 00:00:00 2001 From: SSP6904 Date: Sat, 11 May 2024 17:03:22 -0400 Subject: [PATCH] added files --- index.html | 58 +++++++++++ src/leaflet-radar.css | 15 +++ src/leaflet-radar.js | 229 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+) create mode 100644 index.html create mode 100644 src/leaflet-radar.css create mode 100644 src/leaflet-radar.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..a3b4f7f --- /dev/null +++ b/index.html @@ -0,0 +1,58 @@ + + + +Radar application + + + + + + + + + + +
+

Radar application

+

A simple radar application in HTML

+
+
+ + + + + \ No newline at end of file diff --git a/src/leaflet-radar.css b/src/leaflet-radar.css new file mode 100644 index 0000000..c75b683 --- /dev/null +++ b/src/leaflet-radar.css @@ -0,0 +1,15 @@ +.leaflet-radar { + + /* from leaflet-control-layers */ + border-radius: 5px; + background: #fff; + border: 2px solid rgba(0, 0, 0, 0.2); + background-clip: padding-box; + color: black; + padding: 5px; + height: 67.5px; +} + +.leaflet-radar .leaflet-radar-timestamp { + text-align: center; +} diff --git a/src/leaflet-radar.js b/src/leaflet-radar.js new file mode 100644 index 0000000..e5664b4 --- /dev/null +++ b/src/leaflet-radar.js @@ -0,0 +1,229 @@ +// TODO add refresh (reload time layers) +// TODO add buffer time to load layers where radar turned on + +L.Control.Radar = L.Control.extend({ + + NEXRAD_URL: `https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0q.cgi`, + NEXRAD_LAYER: `nexrad-n0q-900913`, + + isPaused: false, + timeLayerIndex: 0, + timeLayers: [], + + options: { + position: `topright`, + opacity: 0.575, + zIndex: 200, + transitionMs: 750, + playHTML: `►`, + pauseHTML: `▐`, + }, + + onRemove: function () { + L.DomUtil.remove(this.container); + }, + + onAdd: function (map) { + this.map = map; + + // setup control container + this.container = L.DomUtil.create(`div`, "leaflet-radar"); + + L.DomEvent.disableClickPropagation(this.container); + L.DomEvent.on(this.container, `control_container`, function (e) { + L.DomEvent.stopPropagation(e); + }); + L.DomEvent.disableScrollPropagation(this.container); + + // add control elements within container + checkbox_div = L.DomUtil.create( + `div`, + `leaflet-radar-toggle`, + this.container + ); + + this.checkbox = document.createElement(`input`); + this.checkbox.id = `leaflet-radar-toggle`; + this.checkbox.type = `checkbox`; + this.checkbox.checked = false; + this.checkbox.onclick = () => this.toggle(); + + checkbox_div.appendChild(this.checkbox); + + let checkbox_label = document.createElement(`span`); + checkbox_label.innerText = `Radar`; + + checkbox_div.appendChild(checkbox_label); + + let slider_div = L.DomUtil.create( + `div`, + `leaflet-radar-slider`, + this.container + ); + + this.slider = document.createElement(`input`); + this.slider.id = `leaflet-radar-slider`; + this.slider.type = `range`; + this.slider.min = 0; + + slider_div.appendChild(this.slider); + + this.timestamp_div = L.DomUtil.create( + `div`, + `leaflet-radar-timestamp`, + this.container + ); + + this.setDisabled(true); + this.isPaused = true; + + return this.container; + }, + + hideLayerByIndex: function (index) { + this.timeLayers[index].tileLayer.setOpacity(0); + this.timestamp_div.innerHTML = ``; + }, + + showLayerByIndex: function (index) { + this.timeLayers[index].tileLayer.setOpacity( + this.options.opacity + ); + this.timestamp_div.innerHTML = this.timeLayers[index].timestamp; + }, + + setDisabled: function (disabled) { + this.slider.disabled = disabled; + this.timestamp_div.innerText = ``; + }, + + toggle: function () { + if (!this.checkbox.checked) { + this.setDisabled(true); + this.removeLayers(); + return; + } + + this.setDisabled(false); + + this.timeLayers = this.generateLayers(); + this.addLayers(this.timeLayers); + + this.slider.max = `${this.timeLayers.length - 1}`; + + this.timeLayerIndex = 0; + + this.isPaused = false; + + this.slider.oninput = () => { + + this.hideLayerByIndex(this.timeLayerIndex); + this.timeLayerIndex = +this.slider.value; + this.showLayerByIndex(this.timeLayerIndex); + + this.isPaused = true; + }; + + this.setTransitionTimer(); + }, + + + setTransitionTimer: function () { + setTimeout(() => { + if (this.isPaused) { + return; + } + + this.timeLayers.forEach(timeLayer => { + timeLayer.tileLayer.setOpacity(0); + timeLayer.tileLayer.addTo(this.map); + }); + + if (this.checkbox.checked) { + + this.hideLayerByIndex(this.timeLayerIndex); + this.incrementLayerIndex(); + this.showLayerByIndex(this.timeLayerIndex); + + this.slider.value = `${this.timeLayerIndex}`; + + this.setTransitionTimer(); + } else { + this.setDisabled(true); + this.removeLayers(); + } + }, this.options.transitionMs); + }, + + incrementLayerIndex: function () { + this.timeLayerIndex++; + if (this.timeLayerIndex > this.timeLayers.length - 1) { + this.timeLayerIndex = 0; + } + }, + + addLayers: function () { + this.timeLayers.forEach(timeLayer => { + timeLayer.tileLayer.setOpacity(0); + timeLayer.tileLayer.addTo(this.map); + }); + }, + + removeLayers: function () { + this.timeLayers.forEach(timeLayer => + timeLayer.tileLayer.removeFrom(this.map) + ); + this.timeLayers = []; + this.timeLayerIndex = 0; + }, + + generateLayers: function () { + let timeLayers = []; + + const TOTAL_INTERVALS = 10; + const INTERVAL_LENGTH_HRS = 5; + + const currentTime = new Date(); + + for (let i = 0; i <= TOTAL_INTERVALS; i++) { + + const timeDiffMins = + TOTAL_INTERVALS * INTERVAL_LENGTH_HRS - + INTERVAL_LENGTH_HRS * i; + + const suffix = (function(time) { + switch(time) { + case 0: + return ''; + case 5: + return '-m05m'; + default: + return '-m' + time + 'm'; + } + })(timeDiffMins); + + const layerRequest = this.NEXRAD_LAYER + suffix; + + const layer = L.tileLayer.wms(this.NEXRAD_URL, { + layers: layerRequest, + format: `image/png`, + transparent: true, + opacity: this.options.opacity, + zIndex: this.options.zIndex + }); + + const timeString = new Date( + currentTime.valueOf() - timeDiffMins * 60 * 1000 + ).toLocaleTimeString(); + timeLayers.push({ + timestamp: `${timeString} (-${timeDiffMins} min)`, + tileLayer: layer + }); + } + return timeLayers; + } +}); + +L.control.radar = function (options) { + return new L.Control.Radar(options); +}; \ No newline at end of file