updated radar layer
This commit is contained in:
parent
3f4c4adc11
commit
6478d95a1a
33
index.html
33
index.html
@ -1,17 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>US Map | Shaun</title>
|
<title>US Map</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
||||||
<script src="//files.shaunhoffer.cc/states.js"></script>
|
<script src="//files.shaunhoffer.cc/states.js"></script>
|
||||||
<script src="//files.shaunhoffer.cc/counties.js"></script>
|
<script src="//files.shaunhoffer.cc/counties.js"></script>
|
||||||
<meta content="#e8e8e8" name="theme-color"/>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
<link href="https://cdn.jsdelivr.net/npm/halfmoon@2.0.1/css/halfmoon.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/halfmoon@2.0.1/css/halfmoon.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="src/leaflet-radar.css"></script>
|
||||||
|
<script src="src/leaflet-radar.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Set theme to the user's preferred color scheme
|
// Set theme to the user's preferred color scheme
|
||||||
function updateTheme() {
|
function updateTheme() {
|
||||||
@ -29,35 +30,36 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', upd
|
|||||||
<body style="min-height: 100vh">
|
<body style="min-height: 100vh">
|
||||||
<div class="container-fluid p-2">
|
<div class="container-fluid p-2">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">Simple map with leaflet</div>
|
<div class="card-header">US map</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div id="app" style="height: 600px;"></div>
|
<div id="app" style="height: 600px;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<a href="https://git.ttnrtsite.me/ssp6904/usmap">View source code</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
var leafletRadarAttribution = '<a href="https://github.com/rwev/leaflet-radar">Radar source code</a>';
|
||||||
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution: '© OpenStreetMap'
|
attribution: ['© OpenStreetMap | '+ leafletRadarAttribution]
|
||||||
});
|
});
|
||||||
|
|
||||||
var topo = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}g', {
|
var topo = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}g', {
|
||||||
maxZoom: 19
|
maxZoom: 19,
|
||||||
|
attribution: ['© Arcgis maps | '+ leafletRadarAttribution]
|
||||||
});
|
});
|
||||||
|
|
||||||
var arcgissatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
var arcgissatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||||
maxZoom: 19
|
|
||||||
});
|
|
||||||
|
|
||||||
var radaroverlay = L.tileLayer('https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/ridge::USCOMP-N0Q-0/{z}/{x}/{y}.png', {
|
|
||||||
maxZoom: 19
|
|
||||||
});
|
|
||||||
|
|
||||||
var google = L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
|
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
|
attribution: ['© Arcgis maps | '+ leafletRadarAttribution]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var map = L.map('app', {
|
var map = L.map('app', {
|
||||||
center: [37.8, -96],
|
center: [37.8, -96],
|
||||||
zoom: 4,
|
zoom: 4,
|
||||||
@ -74,10 +76,11 @@ var defaultStyle = {
|
|||||||
var countiesL = L.geoJson(counties, {style: defaultStyle});
|
var countiesL = L.geoJson(counties, {style: defaultStyle});
|
||||||
var statesL = L.geoJson(statesData, {style: defaultStyle});
|
var statesL = L.geoJson(statesData, {style: defaultStyle});
|
||||||
var baseMaps = {"OpenStreetMap": osm,"Arcgis Satellite": arcgissatellite,"Topo": topo};
|
var baseMaps = {"OpenStreetMap": osm,"Arcgis Satellite": arcgissatellite,"Topo": topo};
|
||||||
var overlayMaps = {"Counties": countiesL,"States": statesL, "Radar overlay": radaroverlay};
|
var overlayMaps = {"Counties": countiesL,"States": statesL};
|
||||||
|
|
||||||
var layerControl = L.control.layers(baseMaps, overlayMaps, {collapsed: false});
|
var layerControl = L.control.layers(baseMaps, overlayMaps, {collapsed: false});
|
||||||
layerControl.addTo(map);
|
layerControl.addTo(map);
|
||||||
|
L.control.radar({}).addTo(map);
|
||||||
|
|
||||||
// FeatureGroup is to store editable layers
|
// FeatureGroup is to store editable layers
|
||||||
var drawnItems = new L.FeatureGroup();
|
var drawnItems = new L.FeatureGroup();
|
||||||
|
20
src/leaflet-radar.css
Normal file
20
src/leaflet-radar.css
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
.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: #333;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-radar .leaflet-radar-timestamp {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#leaflet-radar-toggle {
|
||||||
|
margin-top: 2px;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
229
src/leaflet-radar.js
Normal file
229
src/leaflet-radar.js
Normal file
@ -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 = ` Toggle 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);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user