Files
test/test.html
2025-11-27 22:25:36 +00:00

1571 lines
40 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>RLX Ver Helper</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js" integrity="sha256-6XMVI0zB8cRzfZjqKcD01PBsAy3FlDASrlC8SxCpInY=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.1/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<script src="https://cdn.rawgit.com/hayeswise/Leaflet.PointInPolygon/v1.0.0/wise-leaflet-pip.js"></script>
<script src="https://unpkg.com/@mapbox/leaflet-pip@latest/leaflet-pip.js"></script>
<script>
</script>
</head>
<body>
<style type="text/css">
#selectable-list {
list-style-type: none;
padding: 0;
z-index: 9999;
}
#selectable-list li {
padding: 10px;
margin: 5px 0;
background-color: #f0f0f0;
cursor: pointer;
}
#selectable-list li.selected {
background-color: #007bff;
color: white;
}
body {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
width: 100%
}
#mapid {
height: 100%;
background: none !important;
z-index: 1;
}
#pickwwa {
position: absolute;
top: 100px;
width: 300px;
background: 'none' !important;
z-index: 9998;
}
.my-label {
font-size: 6;
//font-weight: bold;
//background-color: transparent;
border: 0px solid #ccc;
border-radius: 1px;
padding: 1px 2px;
}
.list-label {
font-weight: bold;
margin-bottom: 10px;
}
</style>
<div id="mapid">
<div id="pickwwa">
<p class="list-label">Will automatically consider only the latest time for the same lat/lon, but has no buffer so they need to be exactly the same<br>Green: Advisory Verifying/Verified Zone<br>Yellow: Warning Verifying/Verified Zone</p>
<label for="yeartowork">Choose a year:</label>
<select name="yeartowork" id="yeartowork" onchange="getwwas()">
<option value="2025">2025</option>
<option value="2024">2024</option>
<option value="2023">2023</option>
<option value="2022">2022</option>
</select>
<ul id="selectable-list"></ul>
<label for="lsrbuffer">Buffer LSR hrs on back end of product</label>
<input id="lsrbuffer" name="lsrbuffer" type="input" value="24">
<input id="LSR" type="button" value="Load LSRs" onclick="loadlsr();" />
</div>
</div>
<script>
const warnings = [
{ warningType: "Tornado Warning", id: 2, colorName: "Red", rgb: "255 0 0", hexCode: "FF0000", code: ["T","H","D","N","G"]},
{ warningType: "Extreme Wind Warning", id: 3, colorName: "Darkorange", rgb: "255 140 0", hexCode: "FF8C00", code: ["G", "O", "N"] },
{ warningType: "Severe Thunderstorm Warning", id: 4, colorName: "Orange", rgb: "255 165 0", hexCode: "FFA500",code: ["T","H","D","N","G"] },
{ warningType: "Flash Flood Warning", id: 5, colorName: "Darkred", rgb: "139 0 0", hexCode: "8B0000", code: ["F", "E", "R", "0","x"]},
{ warningType: "Blizzard Warning", id: 22, colorName: "Orangered", rgb: "255 69 0", hexCode: "FF4500",code: ["S", "O", "5", "Z", "s","q"] },
{ warningType: "Snow Squall Warning", id: 23, colorName: "Mediumvioletred", rgb: "199 21 133", hexCode: "C71585",code: ["S", "O", "5", "Z", "s","q"]},
{ warningType: "Ice Storm Warning", id: 24, colorName: "Darkmagenta", rgb: "139 0 139", hexCode: "8B008B", code: ["q", "O", "5"]},
{ warningType: "Winter Storm Warning", id: 26, colorName: "Hotpink", rgb: "255 105 180", hexCode: "FF69B4",code: ["S", "O", "5", "Z", "s","q"]},
{ warningType: "High Wind Warning", id: 30, colorName: "Goldenrod", rgb: "218 165 32", hexCode: "DAA520",code: ["G", "O", "N"]},
{ warningType: "Flood Warning", id: 39, colorName: "Lime", rgb: "0 255 0", hexCode: "00FF00",code: ["F", "E", "R", "0","x"]},
{ warningType: "Flood (Forecast Points) Warning", id: 39, colorName: "Lime", rgb: "0 255 0", hexCode: "00FF00",code: ["E","R"]},
{ warningType: "Excessive Heat Warning", id: 44, colorName: "Mediumvioletred", rgb: "199 21 133", hexCode: "C71585",code: ["6","7","I"]},
{ warningType: "Extreme Cold Warning", id: 50, colorName: "Blue", rgb: "0 0 255", hexCode: "0000FF",code: ["6","7","I"] },
{ warningType: "Freeze Warning", id: 51, colorName: "Darkslateblue", rgb: "72 61 139", hexCode: "483D8B",code: ["6","7","I"] },
{ warningType: "Red Flag Warning", id: 52, colorName: "Deeppink", rgb: "255 20 147", hexCode: "FF1493" },
{ warningType: "Winter Weather Advisory", id: 60, colorName: "Mediumslateblue", rgb: "123 104 238", hexCode: "7B68EE",code: ["S", "O", "5", "Z", "s","q"] },
{ warningType: "Cold Weather Advisory", id: 62, colorName: "Paleturquoise", rgb: "175 238 238", hexCode: "AFEEEE",code: ["6","7","I"] },
{ warningType: "Heat Advisory", id: 63, colorName: "Coral", rgb: "255 127 80", hexCode: "FF7F50",code: ["6","7","I"]},
{ warningType: "Wind Advisory", id: 76, colorName: "Tan", rgb: "210 180 140", hexCode: "D2B48C",code: ["G", "O", "N"]},
{ warningType: "Frost Advisory", id: 77, colorName: "Cornflowerblue", rgb: "100 149 237", hexCode: "6495ED",code: ["6","7","I"] },
{ warningType: "Flood Watch", id: 89, colorName: "Seagreen", rgb: "46 139 87", hexCode: "2E8B57" },
];
var templsr = []
const criteria = [
{
"state_zone": "WV020",
"shortname": "Doddridge",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV027",
"shortname": "Clay",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV018",
"shortname": "Calhoun",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV006",
"shortname": "Cabell",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV028",
"shortname": "Braxton",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV026",
"shortname": "Boone",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV017",
"shortname": "Wirt",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV032",
"shortname": "Taylor",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV009",
"shortname": "Wood",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV034",
"shortname": "Wyoming",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV040",
"shortname": "Barbour",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV005",
"shortname": "Wayne",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV039",
"shortname": "Upshur",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV011",
"shortname": "Tyler",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV016",
"shortname": "Roane",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV019",
"shortname": "Ritchie",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "KY105",
"shortname": "Lawrence",
"state": "KY",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "KY103",
"shortname": "Boyd",
"state": "KY",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "KY102",
"shortname": "Carter",
"state": "KY",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "KY101",
"shortname": "Greenup",
"state": "KY",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH075",
"shortname": "Athens",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH086",
"shortname": "Gallia",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH083",
"shortname": "Jackson",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH087",
"shortname": "Lawrence",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH067",
"shortname": "Morgan",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH085",
"shortname": "Meigs",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH066",
"shortname": "Perry",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH084",
"shortname": "Vinton",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "OH076",
"shortname": "Washington",
"state": "OH",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "VA003",
"shortname": "Dickenson",
"state": "VA",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "VA004",
"shortname": "Buchanan",
"state": "VA",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV014",
"shortname": "Putnam",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV010",
"shortname": "Pleasants",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV007",
"shortname": "Mason",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV024",
"shortname": "Mingo",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV025",
"shortname": "Logan",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV033",
"shortname": "McDowell",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV013",
"shortname": "Lincoln",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV030",
"shortname": "Lewis",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV015",
"shortname": "Kanawha",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV008",
"shortname": "Jackson",
"state": "WV",
"advisory": 2,
"warning": 4,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV031",
"shortname": "Harrison",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV029",
"shortname": "Gilmer",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV522",
"shortname": "Southeast Webster",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -20,
"advcold": -10
},
{
"state_zone": "WV524",
"shortname": "Southeast Pocahontas",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV515",
"shortname": "Northwest Raleigh",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV523",
"shortname": "Northwest Pocahontas",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -20,
"advcold": -10
},
{
"state_zone": "WV519",
"shortname": "Northwest Nicholas",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV526",
"shortname": "Southeast Randolph",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -20,
"advcold": -10
},
{
"state_zone": "WV517",
"shortname": "Northwest Fayette",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV521",
"shortname": "Northwest Webster",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV525",
"shortname": "Northwest Randolph",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV520",
"shortname": "Southeast Nicholas",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -20,
"advcold": -10
},
{
"state_zone": "WV516",
"shortname": "Southeast Raleigh",
"state": "WV",
"advisory": 3,
"warning": 5,
"warncold": -15,
"advcold": -5
},
{
"state_zone": "WV518",
"shortname": "Southeast Fayette",
"state": "WV",
"advisory": 4,
"warning": 6,
"warncold": -15,
"advcold": -5
}
];
const lsrtype = [
{phenomena: "Flash Flood", abv: "F", style: "FF", color: 'green', fillColor: 'green', passvalue: false},
{phenomena: "Flood", abv: "E", style: "F", color: 'green', fillColor: 'green', passvalue: false},
{phenomena: "Extreme Cold", abv: "6", style: "EC", color: 'blue', fillColor: 'transparent', passvalue: true, resolvelsr: extremecold},
{phenomena: "Extreme Heat", abv: "I", style: "EH", color: 'red', fillColor: 'transparent', passvalue: true, resolvelsr: extremeheat, advbottom: 100, advtop: 104 , warnbottom: 105, warntop: 999 },
{phenomena: "Snow", abv: "S", style: "FF", color: 'green', fillColor: 'transparent', passvalue: true, resolvelsr: snow},
{phenomena: "Thunderstorm Wind Damage", abv: "D", style: "TS", color: 'orange', fillColor: 'orange', passvalue: false},
{phenomena: "Hail", abv: "H", style: "H", color: 'green', fillColor: 'transparent', passvalue: true, resolvelsr: hail},
{phenomena: "Non Thunderstorm Wind Gust", abv: "N", style: "N", color: 'brown', fillColor: 'transparent', passvalue: true, resolvelsr: wind, advbottom: 45, advtop: 57 , warnbottom: 58, warntop: 999},
{phenomena: "Rain", abv: "R", style: "R", color: 'green', fillColor: 'transparent', passvalue: true, resolvelsr: rain},
{phenomena: "Tornado", abv: "T", style: "Tor", color: 'purple', fillColor: 'red', passvalue: false},
{phenomena: "Thunderstorm Wind Gust", abv: "G", style: "TSG", color: 'orange', fillColor: 'transparent', passvalue: true, resolvelsr: wind, advbottom: 45, advtop: 57 , warnbottom: 58, warntop: 999},
{phenomena: "Debris Flow", abv: "x", style: "DB", color: 'green', fillColor: 'brown', passvalue: false},
{phenomena: "Landslide", abv: "0", style: "LS", color: 'green', fillColor: 'brown', passvalue: false},
{phenomena: "Freezing Rain", abv: "5", style: "FZRA", color: 'green', fillColor: 'transparent', passvalue: true, resolvelsr: fzra, advbottom: 0.001, advtop: 0.25, warnbottom: 0.25, warntop: 999},
{phenomena: "Snow Squall", abv: "q", style: "SQ", color: 'blue', fillColor: 'blue', passvalue: false},
{phenomena: "Flash Flood", abv: "F", style: "FF", color: 'green', fillColor: 'green', passvalue: false},
{phenomena: "Ice/Snow Damage", abv: "O", style: "SD", color: 'blue', fillColor: 'blue', passvalue: false},
{phenomena: "Blizzard", abv: "Z", style: "BZ", color: 'blue', fillColor: 'red', passvalue: false},
{phenomena: "Funnel Cloud", abv: "C", style: "FC", color: 'purple', fillColor: 'red', passvalue: false},
]
var lsrstartobj = null
var lsrendobj = null
var wwalsrtypes = []
function extremecold(zone,value) {
for (i in criteria) {
if (criteria[i].state_zone == zone) {
if (criteria[i].warncold >= value) {
return {fillColor: 'blue'}
} else if (criteria[i].advcold >= value)
return {fillColor: 'lightblue'}
}
}
}
function extremeheat(zone,value) {
if (value >= 105) {
return {fillColor: 'purple'}
}
if (value>=100) {
return {fillColor: 'red'}
}
return {fillColor: 'white'}
}
function snow(zone,value) {
for (i in criteria) {
if (criteria[i].state_zone == zone) {
if (criteria[i].advisory > value) {
fillColor = 'white'
}
if (criteria[i].advisory <= value) {
fillColor = "green"
}
if (criteria[i].warning <= value) {
fillColor = "yellow"
}
}}
return {fillColor: fillColor}
}
function hail(zone,value) {
if (value >= 1) {
return {fillColor: 'green'}
}
else {
return {fillColor: 'white'}
}
}
function wind(zone,value) {
if(value >= 58) {
return {fillColor: 'red'}
}
else if (value >= 45) {
return {fillColor: 'brown'}
}
else {
return {fillColor: 'white'}
}
}
function fzra(zone,value) {
if (value >= 0.25) {
return {fillColor: 'purple'}
}
else {
return {fillColor: 'pink'}
}
}
function rain(zone,value) {
if (value >= 1) {
return {fillColor: 'green'}
}
else {
return {fillColor: 'transparent'}
}
}
function styleLSR(latlng,value,zone,properties) {
const warning = lsrtype.find(w => w.abv === properties.type);
var color = warning ? warning.color : 'blue';
var passvalue = warning ? warning.passvalue : false;
var fillColor = warning ? warning.fillColor : 'transparent';
var tempvalue = warning ? warning.style : '';
var lsrscript = warning.resolvelsr
if (passvalue) {
fillColor = lsrscript(zone,value).fillColor
}
if (!passvalue) {
value = tempvalue
}
var circleMarker = L.circleMarker(latlng, {
radius: 10, // Adjust size of the circle
fillColor: fillColor,
color: "#0033cc", // Outline color
weight: 1,
opacity: .5,
fillOpacity: 0.7
});
var labelIcon = L.divIcon({
className: 'circle-label',
html: value,
iconSize: [10, 10], // Size should match or be slightly less than circleMarker's radius
iconAnchor: [10, 10] // Center the icon
});
var labelMarker = L.marker(latlng, {
icon: labelIcon,
zIndexOffset: 1000 // Ensure label appears above the circle
});
labelMarker.bindPopup(properties.valid + "<br>" + properties.typetext + "<br>" + properties.magnitude + properties.unit + "<br>" + properties.remark);
//circleMarker.bindPopup(properties.valid + "<br>" + properties.typetext + "<br>" + properties.magnitude + properties.unit + "<br>" + properties.remark);
var group = L.layerGroup([circleMarker, labelMarker]);
return group;
}
var update_position_timeout = null;
var mymap = L.map('mapid', {zoomDelta: 0.25, zoomSnap: 0}).setView([38.508, -82.652480], 8.0);
var geoJSONcounties = L.geoJSON(false, {
onEachFeature: function(feature, layer) {
layer.bindTooltip(feature.properties.shortname, {permanent: true, direction: 'center', className: 'my-label'});
layer.on({
contextmenu: function(e) {
clickdown(feature, layer, e);
},
click: function(e) {
clickup(feature, layer, e);
},
});
},
style: function (feature) {
return {
fillColor: 'red',
color: 'navy',
weight: 3,
opacity: 1,
fillOpacity: .50
};
}
}).addTo(mymap);
//var countiesjson = 'rlxtest.json'
var countiesjson = 'https://wx.stoat.org/ver.php'
const sbwprods = ["TO","SV","EW","SQ","FA","FL","FF"]
const phenomenonCodes = {
"AF": "Ashfall (land)",
"AS": "Air Stagnation",
"BH": "Beach Hazard",
"BW": "Brisk Wind",
"BZ": "Blizzard",
"CF": "Coastal Flood",
"CW": "Cold Weather",
"DF": "Debris Flow",
"DS": "Dust Storm",
"DU": "Blowing Dust",
"EC": "Extreme Cold",
"EH": "Excessive Heat",
"EW": "Extreme Wind",
"FA": "Flood",
"FF": "Flash Flood",
"FG": "Dense Fog (land)",
"FL": "Flood (Forecast Points)",
"FR": "Frost",
"FW": "Fire Weather",
"FZ": "Freeze",
"GL": "Gale",
"HF": "Hurricane Force Wind",
"HT": "Heat",
"HU": "Hurricane",
"HW": "High Wind",
"HY": "Hydrologic",
"HZ": "Hard Freeze",
"IS": "Ice Storm",
"LE": "Lake Effect Snow",
"LO": "Low Water",
"LS": "Lakeshore Flood",
"LW": "Lake Wind",
"MA": "Marine",
"MF": "Dense Fog (marine)",
"MH": "Ashfall (marine)",
"MS": "Dense Smoke (marine)",
"RP": "Rip Current Risk",
"SC": "Small Craft",
"SE": "Hazardous Seas",
"SM": "Dense Smoke (land)",
"SR": "Storm",
"SS": "Storm Surge",
"SQ": "Snow Squall",
"SU": "High Surf",
"SV": "Severe Thunderstorm",
"TO": "Tornado",
"TR": "Tropical Storm",
"TS": "Tsunami",
"TY": "Typhoon",
"UP": "Heavy Freezing Spray",
"WC": "Wind Chill",
"WI": "Wind",
"WS": "Winter Storm",
"WW": "Winter Weather",
"ZF": "Freezing Fog",
"ZR": "Freezing Rain",
"ZY": "Freezing Spray"
};
function getPhenSig(code,sig) {
// Convert the code to uppercase to ensure case-insensitive lookup
code = code.toUpperCase();
// Check if the code exists in the phenomenonCodes object
if (code in phenomenonCodes) {
var phenomenon = phenomenonCodes[code];
}
if (sig in sigCodes) {
var significance = sigCodes[sig];
}
return phenomenon + " " + significance
}
sigCodes = {
"W": "Warning",
"A": "Watch",
"Y": "Advisory",
"S": "Statement",
}
//TODO
//Plot LRS, auto count ones crossing criteria
var Esri_WorldStreetMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri'
});
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
var Esri_WorldTopoMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community'
});
var CartoDB_Positron = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
});
var USGS_USImageryTopo = L.tileLayer('https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}', {
maxZoom: 20,
attribution: 'Tiles courtesy of the <a href="https://usgs.gov/">U.S. Geological Survey</a>'
});
function getwwas() {
var e = document.getElementById("yeartowork");
var value = e.options[e.selectedIndex].value;
year = value
url = `https://mesonet.agron.iastate.edu/json/vtec_events.py?wfo=RLX&year=${year}`
$.getJSON(url, function(data) {
events = []
for (i in data.events) {
if (data.events[i].significance != "A") {
events.push(data.events[i])
}
}
createEventSelector(events);
});
}
function createEventSelector(events) {
if ($("#eventSelector").length > 0) {
$("#eventSelector").remove();
}
const select = document.createElement('select');
select.id = 'eventSelector';
select.multiple = true; // This allows multiple selections
// Add size attribute to show more than one option at a time
select.size = Math.min(events.length, 25); // Display up to 10 options or all if fewer
// Populate the select with options from the events array
events.forEach(event => {
const option = document.createElement('option');
var whatitis = getPhenSig(event.phenomena,event.significance) + " " + event.eventid
//option.value = event.eventid;
option.value = whatitis;
option.text = `${whatitis} ${event.issue.slice(0, -4) + 'Z'}-${event.expire.slice(0, -4) + 'Z'}`;
select.add(option);
});
// Find the 'pickwwa' div to append the select to
const pickwwaDiv = document.getElementById('pickwwa');
if (pickwwaDiv) {
pickwwaDiv.appendChild(select);
} else {
console.error('Div with ID "pickwwa" not found.');
}
// Event listener for handling multiple selections
select.addEventListener('change', function() {
markersLayer.clearLayers()
geoJSONwwas.clearLayers()
geoJSONwwa1.setStyle({fillColor: 'transparent'})
var selectedOptions = Array.from(this.selectedOptions);
var selectedEvents = selectedOptions.map(option =>
events.find(e => getPhenSig(e.phenomena,e.significance) + " " + e.eventid == option.value)
);
const sortedEvents = selectedEvents.sort((a, b) => {
const significanceA = a.significance;
const significanceB = b.significance;
// Assign sorting weights: "W" has higher priority (lower value) than "Y"
if (significanceA === "Y" && significanceB !== "Y") return -1; // a comes first
if (significanceB === "Y" && significanceA !== "Y") return 1; // b comes first
// If both are the same or neither is "W", keep original order
return 0;
});
startend = getEarliestAndLatest(sortedEvents)
lsrstartobj = new Date(startend.earliestIssue)
lsrendobj = new Date(startend.latestExpire)
plotselectedproducts(sortedEvents)
});
return select;
}
function getEarliestAndLatest(events) {
let earliestIssue = null;
let latestExpire = null;
// Loop through each event
for (const event of events) {
// Check for the earliest issue date
if (!earliestIssue || new Date(event.issue) < new Date(earliestIssue)) {
earliestIssue = event.issue;
}
// Check for the latest expire date
if (!latestExpire || new Date(event.expire) > new Date(latestExpire)) {
latestExpire = event.expire;
}
}
return {
earliestIssue,
latestExpire
};
}
function plotselectedproducts(events) {
geoJSONwwas.clearLayers()
for (i in events) {
year = yearfromissue(events[i].issue)
if (sbwprods.includes(events[i].phenomena)) {
url = `https://mesonet.agron.iastate.edu/geojson/vtec_event.py?wfo=RLX&phenomena=${events[i].phenomena}&significance=${events[i].significance}&etn=${events[i].eventid}&year=${year}&sbw=1`
} else {
url = `https://mesonet.agron.iastate.edu/geojson/vtec_event.py?wfo=RLX&phenomena=${events[i].phenomena}&significance=${events[i].significance}&etn=${events[i].eventid}&year=${year}`
}
$.getJSON(url, function(data) {
var geojsonFeature = data
geoJSONwwas.addData(geojsonFeature);
})
}
}
var baselayers = {
"Black and White": CartoDB_Positron,
"Esri Street Map": Esri_WorldStreetMap,
"Esri Satellite": Esri_WorldImagery,
"Esri Topo": Esri_WorldTopoMap,
"USGS Sat/Topo": USGS_USImageryTopo,
}
var controllayer = L.control.layers(baselayers,null,{collapsed: false}).addTo(mymap);
const markersLayer = L.layerGroup().addTo(mymap);
function verifyshade(feature) {
console.log(feature.properties.phenomena)
if (sbwprods.includes(feature.properties.phenomena)) {
markersLayer.eachLayer(function(layer) {
console.log(layer)
});
//loop through LSRs and color wwas polygons
//markersLayer
//isMarkerInsidePolygon(latlng, polygon)
}
return 'transparent'
}
var geoJSONwwas = L.geoJSON(false, {
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.phenomena + feature.properties.significance + " " + feature.properties.eventid)
},
/* onEachFeature: function(feature, layer) {
layer.bindTooltip(feature.properties.shortname, {permanent: true, direction: 'center', className: 'my-label'});
layer.on({
contextmenu: function(e) {
clickdown(feature, layer, e);
},
click: function(e) {
clickup(feature, layer, e);
},
});
},*/
style: function (feature) {
return {
//fillColor: 'transparent',
fillColor: 'transparent',
color: wwacolor(feature),
weight: 3,
opacity: 1,
fillOpacity: .50
};
}
}).addTo(mymap);
function getRGBByWarningType(warningType) {
const warning = warnings.find(w => w.warningType === warningType);
return warning ? warning.colorName : null;
}
function getLSRbyWarnType(warningType) {
const warning = warnings.find(w => w.warningType === warningType);
return warning ? warning.code : null;
}
function wwacolor(feature) {
code = feature.properties.phenomena
sig = feature.properties.significance
product = getPhenSig(code,sig)
producthex = getRGBByWarningType(product)
lsrcodes = getLSRbyWarnType(product)
wwalsrtypes = lsrcodes
if (producthex != null) {
return producthex
}
else {
return 'purple'
}
}
var geoJSONwwa1 = L.geoJSON(false, {
/* onEachFeature: function(feature, layer) {
layer.bindTooltip(feature.properties.shortname, {permanent: true, direction: 'center', className: 'my-label'});
layer.on({
contextmenu: function(e) {
clickdown(feature, layer, e);
},
click: function(e) {
clickup(feature, layer, e);
},
});
},*/
style: function (feature) {
return {
fillColor: 'transparent',
color: 'black',
weight: 1,
opacity: 1,
fillOpacity: .50
};
}
}).addTo(mymap);
$.getJSON('https://wx.stoat.org/ver.php', function(data) {
var geojsonFeature = data;
geoJSONwwa1.addData(geojsonFeature);
geoJSONwwa1.bringToFront();
});
function yearfromissue(issue) {
var date = new Date(issue)
return date.getFullYear()
}
function deduplicateGeoJSON(geojson) {
const toTimestamp = (dateStr) => new Date(dateStr).getTime();
let featuresArray = geojson.features;
featuresArray.sort((a, b) => {
return toTimestamp(b.properties.utc_valid) - toTimestamp(a.properties.utc_valid);
});
const seenCoords = new Set();
const uniqueFeatures = featuresArray.filter(feature => {
const coords = JSON.stringify(feature.geometry.coordinates);
if (!seenCoords.has(coords)) {
seenCoords.add(coords);
return true;
}
return false;
});
return {
type: "FeatureCollection",
features: uniqueFeatures
};
}
function isMarkerInsidePolygon(latlng, polygon) {
leafletPip.bassackwards = true
return leafletPip.pointInLayer(latlng, polygon, true); // If results has length, the point is inside
}
function convertTimestamp(timestamp) {
// Remove the 'Z' from the end and split the date and time
const dateTimeParts = timestamp.split('T'); // Split into date and time
const date = dateTimeParts[0]; // YYYY-MM-DD
const time = dateTimeParts[1].slice(0, 5); // HH:mm (from HH:mm:ss)
const [year, month, day] = date.split('-'); // [YYYY, MM, DD]
const formatted = `${year}${month}${day}${time.replace(":", "")}`; // YYYYMMDDHHmm
return formatted;
}
function addHoursToDate(date, hours) {
let newDate = new Date(date);
newDate.setHours(newDate.getHours() + hours);
return newDate;
}
function loadlsr() {
padding = parseInt(document.getElementById('lsrbuffer').value)
var lsrendbuffer = addHoursToDate(lsrendobj,padding)
lsrend = convertTimestamp(lsrendbuffer.toISOString())
lsrstart = convertTimestamp(lsrstartobj.toISOString())
lsrendbuffer = lsrendobj
markersLayer.clearLayers()
geoJSONwwa1.setStyle({fillColor: 'transparent'})
templsr = []
var newlsr = []
var templsrnotin = []
var verarray = []
var markers = []
var url = `https://mesonet.agron.iastate.edu/geojson/lsr.geojson?sts=${lsrstart}&ets=${lsrend}&wfos=RLX`
$.getJSON(url, function(data) {
data = deduplicateGeoJSON(data);
values = wwalsrtypes
//if we have lsr types we want, only show those
if (values) {
for(var i in data.features) {
if (values.includes(data.features[i].properties.type)) {
var returnval = isMarkerInsidePolygon(data.features[i].geometry.coordinates.reverse(),geoJSONwwa1);
if (returnval.length > 0) {
//data.features[i].properties.state_zone = (returnval[0].feature.id).replace(/Z/g, '')
data.features[i].properties.state_zone = returnval[0].feature.properties.state_zone
templsr.push(data.features[i])
}
}
}
}
//if we don't have lsr types we want, show everything
if (!values) {
for(var i in data.features) {
var returnval = isMarkerInsidePolygon(data.features[i].geometry.coordinates.reverse(),geoJSONwwa1);
if (returnval.length > 0) {
data.features[i].properties.state_zone = returnval[0].feature.properties.state_zone
templsr.push(data.features[i])
}
}
}
console.log(templsr)
for (k in templsr) {
var marker = styleLSR(templsr[k].geometry.coordinates,templsr[k].properties.magnitude,templsr[k].properties.state_zone,templsr[k].properties)
markersLayer.addLayer(marker)
var flag = newflag(templsr[k].properties.type,templsr[k].properties.state_zone,templsr[k].properties.magf)
var sbwflag = 'test'
//var flag = checkagainstcriteria(templsr[k].properties.state_zone,templsr[k].properties.magf)
//create a second array or combine for polygon based products
if (flag != null) {
verarray.push([templsr[k].properties.state_zone,flag])
}
}
console.log(verarray)
zones = processZones(verarray)
console.log(verarray,zones)
geoJSONwwa1.eachLayer(function(layer) {
zone = layer.feature.properties.state + layer.feature.properties.zone
for (var l in zones) {
//console.log(zones[l],zone)
if (zone == zones[l][0]) {
if (zones[l][1].warning >= 2) {
layer.setStyle({fillColor: 'gold'});
}
else if (zones[l][1].advisory >= 2) {
layer.setStyle({fillColor: 'green'});
}
}
}
});
geoJSONwwas.eachLayer(function(layer) {
if (sbwprods.includes(layer.feature.properties.phenomena)) {
console.log(layer)
}
});
//add lsr autoupdate for products that are less than 24hrs from expiration
});
}
function sbwflag(feature,latlng,value) {
flag = null
const warning = lsrtype.find(w => w.abv === type);
warning ? warning.code : null
const advbottom = warning.advbottom;
const advtop = warning.advtop;
const warnbottom = warning.warnbottom;
const warntop = warning.warntop;
}
function newflag(type,zone,value) {
flag = null
//if passvalue is true in the lsr lookup, then compare values
//if not then go to another table for verification
const warning = lsrtype.find(w => w.abv === type);
warning ? warning.code : null
const advbottom = warning.advbottom;
const advtop = warning.advtop;
const warnbottom = warning.warnbottom;
const warntop = warning.warntop;
switch(warning.abv) {
case "S":
for (i in criteria) {
if (criteria[i].state_zone == zone) {
if (criteria[i].warning <= value) {
flag = "warning"
} else if (criteria[i].advisory <= value)
flag = "advisory"
}
}
break;
case "6":
for (i in criteria) {
if (criteria[i].state_zone == zone) {
if (value <= criteria[i].advcold) {
flag = "advisory"
}
if (value <= criteria[i].warncold) {
flag = "warning"
} }
}
break;
case "I":
case "N":
if (warnbottom <= value && warntop >= value) {
flag = "warning"
} else if (advbottom <= value && advtop > value) {
flag = "advisory"
}
break;
case "O":
flag = "warning"
break;
case "5":
if (value >= warnbottom) {
flag = "warning"
} else if (value >= advbottom) {
flag = "advisory"
}
break;
}
//style non numerics
//count for verification
return flag
//Check if type numerically verifies, if it does compare against criteria
//Highlight non numeric lsrs as another color
}
function processZones(zones) {
if (zones.length === 0) {
return [];
}
const zoneCounts = {};
for (const [zone, type] of zones) {
if (!zoneCounts[zone]) {
zoneCounts[zone] = { advisory: 0, warning: 0 };
}
zoneCounts[zone][type]++;
}
return Object.entries(zoneCounts).map(([zone, counts]) => [zone, counts]);
}
getwwas()
</script>
</body>
</html>