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

586 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RLX Weather Camera List</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
background-color: #f0f0f0;
color: #333;
}
#menu {
background-color: #003366;
color: white;
width: 180px;
height: 100%;
position: fixed;
padding: 5px;
box-shadow: 2px 0 5px rgba(0,0,0,0.3);
transition: width 0.3s;
overflow-x: hidden;
}
#menu.collapsed {
width: 40px;
}
#menu.collapsed .menu-content {
display: none;
}
#toggle-menu {
cursor: pointer;
padding: 8px;
margin-bottom: 10px;
text-align: center;
background-color: #002244;
border-radius: 4px;
}
#menu a {
color: white;
text-decoration: none;
display: block;
margin: 8px 0;
padding: 8px;
transition: background 0.3s;
}
#menu a:hover {
background-color: #005599;
}
#container {
margin-left: 180px; /* Adds space for the menu */
padding: 12px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(275px, 1fr));
gap: 5px;
transition: margin-left 0.3s;
}
#container.expanded {
margin-left: 180px;
}
#container.collapsed {
margin-left: 40px;
}
.image {
position: relative;
background-color: #fff;
border-radius: 5px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: transform 0.3s;
}
.image:hover {
transform: scale(1.04);
z-index:9999;
}
.image img {
width: 100%;
height: auto;
display: block;
}
.label {
position: absolute;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 5px 10px;
font-size: 12px;
width: 100%;
}
select, input[type=number] {
width: calc(100% - 20px);
padding: 8px 10px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 4px;
}
label {
margin: 10px 0 5px;
display: block;
}
input[type="checkbox"] {
margin-right: 5px;
}
</style>
</head>
<body>
<div id="menu">
<div id="toggle-menu" onclick="toggleMenu()"></div>
<div class="menu-content">
<h2>Menu</h2>
<a href="map.html">Map</a>
<a href="db.html">Wunderground obs</a>
<a href="5min.html">5m ASOS obs</a>
<a href="outage.html">Power Outages</a>
<a href="https://docs.google.com/forms/d/1-2rTBkNyyBVe08G1vN1hcSOEOvvLUcS1Vs2SmmaudlU" target="_blank">Questions / Comments</a>
<label for="filters">Filters:</label>
<label for="states">States:</label>
<select id="filters" name="filters" onchange="filter()" multiple>
<option selected="selected" value="WV">WV</option>
<option selected="selected" value="KY">KY</option>
<option selected="selected" value="VA">VA</option>
<option selected="selected" value="OH">OH</option>
</select>
<label for="cwa">
<input type="checkbox" id="cwa" name="cwa" value="RLX" checked onchange="filter()"> RLX only
</label>
<label>Misc Filters:</label>
<label for="hydro">
<input type="checkbox" id="hydro" name="hydro" value="true" onchange="filter()"> Hydro
</label>
<label for="airport">
<input type="checkbox" id="airport" name="airport" value="true" onchange="filter()"> Airports
</label>
<label for="sort">Sorting:</label>
<select id="sort" name="sort" onchange="sortcams()">
<option selected="selected" value="elevd">Elev Descending</option>
<option value="eleva">Elev Ascending</option>
<option value="countyaz">County A-Z</option>
<option value="countyza">County Z-A</option>
<option value="westeast">West to East</option>
<option value="northsouth">North to South</option>
</select>
<label for="numberofimages">Frames for Loops</label>
<input type="number" id="numberofimages" name="numberofimages" value="20" onchange="setcams()">
<p>Archive: 240 hours</p>
<p id="camcount"></p>
</div>
</div>
<div id="container">
<!-- Dynamic content will be populated here -->
</div>
<script>
// Function to set a cookie
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
// Function to get a cookie
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
// Toggle menu function
function toggleMenu() {
var menu = document.getElementById('menu');
var container = document.getElementById('container');
if (menu.classList.contains('collapsed')) {
menu.classList.remove('collapsed');
container.classList.remove('collapsed');
container.classList.add('expanded');
setCookie('menuCollapsed', 'false', 365);
} else {
menu.classList.add('collapsed');
container.classList.remove('expanded');
container.classList.add('collapsed');
setCookie('menuCollapsed', 'true', 365);
}
}
// Load settings from cookies
function loadSettings() {
// Load menu state
var menuCollapsed = getCookie('menuCollapsed');
if (menuCollapsed === 'true') {
document.getElementById('menu').classList.add('collapsed');
document.getElementById('container').classList.add('collapsed');
document.getElementById('container').classList.remove('expanded');
} else {
document.getElementById('menu').classList.remove('collapsed');
document.getElementById('container').classList.add('expanded');
document.getElementById('container').classList.remove('collapsed');
}
// Load number of images
var savedImages = getCookie('numberofimages');
if (savedImages) {
document.getElementById('numberofimages').value = savedImages;
camimages = savedImages;
} else {
camimages = 20;
}
// Load states filter
var savedStates = getCookie('statesFilter');
if (savedStates) {
var statesArray = JSON.parse(savedStates);
var statesSelect = document.getElementById('filters');
for (var i = 0; i < statesSelect.options.length; i++) {
statesSelect.options[i].selected = statesArray.includes(statesSelect.options[i].value);
}
}
// Load RLX checkbox
var savedRLX = getCookie('rLXOnly');
if (savedRLX !== null) {
document.getElementById('cwa').checked = (savedRLX === 'true');
}
// Load hydro checkbox
var savedHydro = getCookie('hydroFilter');
if (savedHydro !== null) {
document.getElementById('hydro').checked = (savedHydro === 'true');
}
// Load airport checkbox
var savedAirport = getCookie('airportFilter');
if (savedAirport !== null) {
document.getElementById('airport').checked = (savedAirport === 'true');
}
// Load sort option
var savedSort = getCookie('sortOption');
if (savedSort) {
document.getElementById('sort').value = savedSort;
}
}
// Save settings to cookies
function saveSettings() {
// Save number of images
setCookie('numberofimages', document.getElementById('numberofimages').value, 365);
// Save states filter
var statesSelect = document.getElementById('filters');
var selectedStates = [];
for (var i = 0; i < statesSelect.options.length; i++) {
if (statesSelect.options[i].selected) {
selectedStates.push(statesSelect.options[i].value);
}
}
setCookie('statesFilter', JSON.stringify(selectedStates), 365);
// Save RLX checkbox
setCookie('rLXOnly', document.getElementById('cwa').checked, 365);
// Save hydro checkbox
setCookie('hydroFilter', document.getElementById('hydro').checked, 365);
// Save airport checkbox
setCookie('airportFilter', document.getElementById('airport').checked, 365);
// Save sort option
setCookie('sortOption', document.getElementById('sort').value, 365);
}
camimages = 20;
function setcams() {
camimages = document.getElementById("numberofimages").value;
saveSettings(); // Save when changed
refreshcams();
}
var showcams = [];
function filter() {
saveSettings(); // Save when filter changes
showcams = [];
var x = document.getElementById("filters");
options = x.getElementsByTagName('option');
var y = document.getElementById("cwa").checked;
var hydroFilter = document.getElementById("hydro").checked;
var airportFilter = document.getElementById("airport").checked;
values = [];
for (var i=options.length; i--;) {
if (options[i].selected) values.push(options[i].value)
}
console.log('Hydro filter checked:', hydroFilter); // Debug
console.log('Airport filter checked:', airportFilter); // Debug
for(var k in allcams) {
// Check state filter
var stateMatch = false;
for(var l in values) {
if (allcams[k].state == values[l]) {
stateMatch = true;
break;
}
}
// Check RLX filter
var rlxMatch = true;
if (y) {
rlxMatch = ('RLX' == allcams[k].cwa);
}
// Check hydro filter
var hydroMatch = true;
if (hydroFilter) {
// Only show if hydro is true when filter is selected
console.log('Camera:', allcams[k].camid, 'hydro value:', allcams[k].hydro); // Debug
// Handle cases where hydro might be undefined or not present
// If hydro field doesn't exist or is not true, don't show
hydroMatch = (allcams[k].hasOwnProperty('hydro') && allcams[k].hydro === true);
} else {
// When hydro filter is not selected, show all (both true and false)
hydroMatch = true;
}
// Check airport filter
var airportMatch = true;
if (airportFilter) {
// Only show if airport is true when filter is selected
console.log('Camera:', allcams[k].camid, 'airport value:', allcams[k].airport); // Debug
// Handle cases where airport might be undefined or not present
// If airport field doesn't exist or is not true, don't show
airportMatch = (allcams[k].hasOwnProperty('airport') && allcams[k].airport === true);
} else {
// When airport filter is not selected, show all (both true and false)
airportMatch = true;
}
if (stateMatch && rlxMatch && hydroMatch && airportMatch) {
showcams.push(allcams[k].camid);
}
// Hide all first
document.getElementById(allcams[k].camid).style.display = 'none';
}
// Show matching cams
for(var o in showcams) {
document.getElementById(showcams[o]).style.display = '';
}
console.log('Number of cams to show:', showcams.length); // Debug
// Show a message if no cameras match
if (showcams.length === 0) {
console.log('No cameras match the current filters');
}
}
function sortcams() {
saveSettings(); // Save when sort changes
var sortcams = allcams;
var x = document.getElementById("sort");
options = x.getElementsByTagName('option');
values = [];
for (var i=options.length; i--;) {
if (options[i].selected) {
switch(options[i].value) {
case "elevd":
sortcams.sort(function(a,b) {
return b.elevation-a.elevation
})
break;
case "eleva":
sortcams.sort(function(a,b) {
return a.elevation-b.elevation
})
// code block
break;
case "westeast":
sortcams.sort(function(a,b) {
if (a.lon > b.lon) {
return -1;
}
if (b.lon > a.lon) {
return 1;
}
return 0;
})
break;
case "northsouth":
sortcams.sort(function(a,b) {
if (a.lat> b.lat) {
return -1;
}
if (b.lat > a.lat) {
return 1;
}
return 0;
})
break;
case "countyza":
sortcams.sort(function(a,b) {
if (a.county > b.county) {
return -1;
}
if (b.county > a.county) {
return 1;
}
return 0;
})
break;
case "countyaz":
sortcams.sort(function(a,b) {
if (a.county > b.county) {
return 1;
}
if (b.county > a.county) {
return -1;
}
return 0;
})
break;
default:
}
}
}
for (var ii in sortcams) {
//console.log(sortcams[ii].camid);
//var xx = document.getElementsByTagName("Figure");
var x = document.getElementById(sortcams[ii].camid);
x.style.order=ii
}
}
// Load settings when the page loads
window.onload = function() {
loadSettings();
$.getJSON('cam.php', function(data) {
var wild = Math.random();
allcams = data;
console.log('Camera data:', data); // Debug: log camera data
// Check if hydro field exists in any camera
var hasHydroField = false;
for (var i in data) {
if (data[i].hasOwnProperty('hydro')) {
hasHydroField = true;
break;
}
}
console.log('Does camera data have hydro field?', hasHydroField);
for (var i in data) {
var div = document.createElement('div');
var a = document.createElement('a');
div.className = "image";
div.id = data[i].camid;
var img = document.createElement('img');
img.src = 'camdata/' + data[i].camid + "/latest.jpg" //?" + wild;
a.href = 'one.php?camid=' + data[i].camid + '&camimages=' + camimages;
a.target = "_blank";
a.appendChild(img);
div.appendChild(a);
var span = document.createElement('span');
span.className = 'label';
span.innerHTML = data[i].description + ' / ' + data[i].county + ' ' + data[i].state + ' / ' + data[i].elevation + ' ft';
div.appendChild(span);
document.getElementById('container').appendChild(div);
}
filter();
sortcams(); // Apply saved sort
$.getJSON('camapi.php?camdb', function(data){
document.getElementById("camcount").textContent = "Total Images: " + data[0].count;
});
});
};
function refreshcams() {
$.getJSON('cam.php', function(data){
var wild = Math.random();
//console.log(data);
for(var i in data){
var updatefigure = document.getElementById(data[i].camid);
if (updatefigure != null) {
if(updatefigure.hasChildNodes()) {
var children = updatefigure.childNodes;
for (var m = 0; m < children.length; m++) {
children[m].href = 'one.php?camid=' + data[i].camid + '&camimages=' + camimages;
if (children[m].nodeName == 'A') {
children[m].firstElementChild.src = 'camdata/' + data[i].camid + "/latest.jpg"//?" + wild
//children[m].firstElementChild.src = 'camdata/' + data[i].lastimage;
}
}
}
}}
});
$.getJSON('camapi.php?camdb', function(data){
document.getElementById("camcount").textContent = "Total Images: " + data[0].count;
});
}
window.setInterval(function() {
refreshcams();
}, 30000);
</script>
</body>
</html>