Files
byuiars-reop-net/mesh/eimeshcore.htm
T

379 lines
17 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Radio Mobile Coverage – BYU-Idaho Amateur Radio Society</title>
<link rel="stylesheet" href="/style.css" />
<script src="/script.js" defer></script>
<style>
/* OpenLayers & Map Overrides */
.ol-map-container {
position: relative;
width: 100%;
height: 650px;
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
margin-top: 1rem;
}
2026-02-15 14:42:42 -07:00
.ol-popup {
display: none;
position: absolute;
background-color: var(--bg-color);
color: var(--text-color);
padding: 15px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
border-radius: var(--border-radius);
}
2026-02-15 14:42:42 -07:00
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
2026-02-15 14:42:42 -07:00
.ol-popup:after {
border-top-color: var(--bg-color);
border-width: 10px;
left: 48px;
margin-left: -10px;
}
2026-02-15 14:42:42 -07:00
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
2026-02-15 14:42:42 -07:00
.ol-popup-content {
min-width: 170px;
max-height: 200px;
overflow-x: auto;
}
2026-02-15 14:42:42 -07:00
.ol-popup-closer {
position: absolute;
top: 2px;
right: 2px;
font-size: 120%;
padding: 0 4px;
color: gray;
text-decoration: none;
}
2026-02-15 14:42:42 -07:00
.ol-popup-closer:after {
content: "✕";
}
2026-02-15 14:42:42 -07:00
.ol-mouse-position { top: 8px; right: 8px; position: absolute; }
.ol-scale-line { background: rgba(0,60,136,.3); border-radius: 4px; bottom: 8px; left: 8px; padding: 2px; position: absolute; }
.ol-scale-line-inner { border: 1px solid #eee; border-top: none; color: #eee; font-size: 10px; text-align: center; margin: 1px; padding: 0 2px; }
.ol-control { position: absolute; background-color: rgba(255,255,255,.4); border-radius: 4px; padding: 2px; }
.ol-control:hover { background-color: rgba(255,255,255,.6); }
.ol-zoom { top: .5em; left: .5em; }
.ol-control button { display: block; margin: 1px; padding: 0; color: #fff; font-size: 1.14em; font-weight: 700; text-align: center; height: 1.375em; width: 1.375em; background-color: rgba(0,60,136,.5); border: none; border-radius: 2px; cursor: pointer; }
.ol-zoomslider { position: absolute; top: 4.5em; left: .5em; background: rgba(255,255,255,.4); width: 24px; height: 200px; }
.ol-zoomslider-thumb { position: absolute; background: rgba(0,60,136,.5); border-radius: 2px; cursor: pointer; height: 10px; width: 22px; margin: 3px; }
</style>
<script type="text/javascript">
var map, layers = [], mapkey, mapgrey;
var infowindow, ie, marker, rmap1, rmap2, rmap3, rmap4, mlat, mlon, job;
var ti, link, cover, txt, txtm, icon = 0;
var no = 'N', so = 'S', es = 'E', ws = 'W';
function initialize(lat, lon, zoom, j, mode) {
job = j;
createmapstyles();
switch (job) {
case 0:
map = initmap('map_canvas', 'test', 'ladeg', 'lodeg', 'ladms', 'lodms', mode);
setlltags(lat, lon, 'ladeg', 'lodeg', 'ladms', 'lodms');
icon = 3;
marker = addmarker(map, icon, lat, lon);
break;
case 1:
icon = 4;
map = initmap('map_canvas', 'test', null, null, null, null, mode);
mlat = lat; mlon = lon;
do_overlays();
break;
case 2:
icon = 4;
marker = new Array(); link = new Array(); link2 = new Array(); cover = new Array(); txt = new Array(); txtm = new Array();
map = initmap('map_canvas', 'test', null, null, null, null, mode);
init(true);
multi();
break;
}
setmap(map, lat, lon, zoom);
}
2026-02-15 14:42:42 -07:00
function multi() {
var i;
var s = document.getElementById('sc');
if (s) {
for (i = 1; i < s.length; ++i) cover[i - 1].setVisible(s.options[i].selected);
}
s = document.getElementById('sl');
if (s) {
for (i = 1; i < s.length; ++i) link[i - 1].setVisible(s.options[i].selected);
}
s = document.getElementById('sm');
if (s) {
for (i = 1; i < s.length; ++i) marker[i - 1].setVisible(s.options[i].selected);
}
}
2026-02-15 14:42:42 -07:00
function switchtiles(ind) {
selectmaptiles(map, ind);
}
2026-02-15 14:42:42 -07:00
function findZoom() {
if (document.form1) {
document.form1.m_lat.value = getmarkerlat(marker);
document.form1.m_lon.value = getmarkerlon(marker);
document.form1.m_zoom.value = getmapzoom(map);
}
}
2026-02-15 14:42:42 -07:00
function centerit() {
setmap(map, getmarkerlat(marker), getmarkerlon(marker), getmapzoom(map));
}
2026-02-15 14:42:42 -07:00
function centercursor() {
var lat = getmaplat(map);
var lon = getmaplon(map);
setlltags(lat, lon, 'ladeg', 'lodeg', 'ladms', 'lodms');
setmarker(marker, lat, lon);
}
2026-02-15 14:42:42 -07:00
function initmap(mapdiv, session, latag, lotag, ladms, lodms, src) {
var inter;
if (latag && lotag && ladms && lodms) {
initdrag(latag, lotag, ladms, lodms);
inter = ol.interaction.defaults().extend([new app.Drag()]);
}
if (!src) src = 0;
2026-02-15 14:42:42 -07:00
var map = new ol.Map({
interactions: inter,
layers: layers,
target: mapdiv
});
selectmaptiles(map, src);
map.addControl(new ol.control.ZoomSlider());
return map;
}
2026-02-15 14:42:42 -07:00
function createmapstyles() {
layers[0] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.OSM({ url: 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png', maxZoom: 19 })
});
layers[1] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({
tileUrlFunction: function (tileCoord) {
var z = tileCoord[0], x = tileCoord[1], y = tileCoord[2];
return 'https://r0.ortho.tiles.virtualearth.net/tiles/r' + quadkey(x, y, z) + '.png?g=1';
}, maxZoom: 19
})
});
layers[2] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({
tileUrlFunction: function (tileCoord) {
var z = tileCoord[0], x = tileCoord[1], y = tileCoord[2];
return 'https://a0.ortho.tiles.virtualearth.net/tiles/a' + quadkey(x, y, z) + '.jpeg?g=1';
}, maxZoom: 19
})
});
layers[3] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({ url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}', maxZoom: 16 })
});
layers[4] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({ url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}', maxZoom: 16 })
});
layers[5] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({ url: 'https://tile.opentopomap.org/{z}/{x}/{y}.png', maxZoom: 17 })
});
layers[6] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({ url: 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', maxZoom: 19 })
});
layers[7] = new ol.layer.Tile({
2026-02-15 14:42:42 -07:00
visible: false,
source: new ol.source.XYZ({ url: 'https://mt.google.com/vt/lyrs=r&x={x}&y={y}&z={z}', maxZoom: 19 })
2026-02-15 14:42:42 -07:00
});
layers[8] = new ol.layer.Tile({
visible: false,
source: new ol.source.XYZ({ url: 'https://mt.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', maxZoom: 19 })
2026-02-15 14:42:42 -07:00
});
}
var quadkey = function (x, y, z) {
var quadKey = [];
for (var i = z; i > 0; i--) {
var digit = '0';
var mask = 1 << (i - 1);
if ((x & mask) != 0) digit++;
if ((y & mask) != 0) { digit++; digit++; }
quadKey.push(digit);
}
return quadKey.join('');
};
2026-02-15 14:42:42 -07:00
function selectmaptiles(map, src) {
for (var i = 0, ii = layers.length; i < ii; ++i) layers[i].setVisible(i == src);
2026-02-15 14:42:42 -07:00
}
function getmaplat(map) {
var c = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
return c[1];
2026-02-15 14:42:42 -07:00
}
function getmaplon(map) {
var c = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
return c[0];
2026-02-15 14:42:42 -07:00
}
function getmapzoom(map) {
return map.getView().getZoom();
2026-02-15 14:42:42 -07:00
}
function setmap(map, lat, lon, z) {
map.setView(new ol.View({
center: ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'),
zoom: z, minZoom: 2, maxZoom: 19
}));
2026-02-15 14:42:42 -07:00
}
function addimage(map, src, lamin, lomin, lamax, lomax) {
var c1 = ol.proj.transform([lomin, lamin], 'EPSG:4326', 'EPSG:3857');
var c2 = ol.proj.transform([lomax, lamax], 'EPSG:4326', 'EPSG:3857');
var cx = ol.proj.transform([(lomin + lomax) / 2, (lamin + lamax) / 2], 'EPSG:4326', 'EPSG:3857');
var dx = (c2[0] - c1[0]) / 2;
var dy = (c2[1] - c1[1]) / 2;
c1[0] = cx[0] - dx;
c2[0] = cx[0] + dx;
c1[1] = cx[1] - dy;
c2[1] = cx[1] + dy;
var ov = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: src,
imageExtent: [c1[0], c1[1], c2[0], c2[1]]
})
});
map.addLayer(ov);
return ov;
2026-02-15 14:42:42 -07:00
}
function addmarker(map, iconindex, lat, lon, label, html) {
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'))
});
2026-02-15 14:42:42 -07:00
var iconStyle = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1.0],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.9,
src: ico[iconindex]
}),
text: new ol.style.Text({
font: '12px helvetica,sans-serif',
text: label,
fill: new ol.style.Fill({ color: '#000' }),
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
})
});
2026-02-15 14:42:42 -07:00
iconFeature.setStyle(iconStyle);
iconFeature.setId(html);
var vectorSource = new ol.source.Vector({ features: [iconFeature] });
var vectorLayer = new ol.layer.Vector({ source: vectorSource });
map.addLayer(vectorLayer);
return vectorLayer;
}
2026-02-15 14:42:42 -07:00
function setlltags(lat, lon, latag, lotag, ladms, lodms) {
var a;
var t = ol.coordinate.toStringHDMS([lon, lat]).split(" ");
if (latag && document.getElementById(latag)) document.getElementById(latag).innerHTML = lat.toFixed(8);
while (lon < -180) lon += 360; while (lon > 180) lon -= 360;
if (lotag && document.getElementById(lotag)) document.getElementById(lotag).innerHTML = lon.toFixed(8);
a = (lat < 0) ? so : no;
if (ladms && document.getElementById(ladms)) document.getElementById(ladms).innerHTML = t[0] + " " + t[1] + " " + t[2] + " " + a;
a = (lon < 0) ? ws : es;
if (lodms && document.getElementById(lodms)) document.getElementById(lodms).innerHTML = t[4] + " " + t[5] + " " + t[6] + " " + a;
}
2026-02-15 14:42:42 -07:00
var ico = [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAuCAMAAAB6WzuLAAADAFBMVEUAbv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0AbPoAZvAAYOYAWtsAVNMAUc0ATsgATcYATMUATMQAS8QAS8MAS8MAS8MAS8MAS8MAS8MATMMBUcEBVb8BV70BWLoBVa0BT6ABR5IBQooCQIcCPoUDO38GNnIING0NLmsRK2wYMnIjPnsoQn0tRoEySYM1TIU7UYhBW5BIZZhUbp1ZdKBhfKZpha1uirBzjrB2kK9+lLCImLOMmrSPm7WQnLaTn7eYpLmdq7yiscGquMSxv8m4xM69yNPDzdfH0dzK09/N1uHP1+TU2ujY3enb3urg4evj4uzm5O3o5u3q6O7t6+7w7vDy8PH08/P29vX4+Pb6+vj7+/j8/Pn+/vn+/vn///n///j///j///f///j///v///z///7////////////////9///8///+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+9nfC1AAABAHRSTlP///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfaoGpAAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAUBJREFUOI2NlD2OwyAQhbmFj0OZZoqIwtooQkuxoXASaWlIE1nu3WyTE83FYsB2MAx4X4f0aebNHwx3xeJHf9PfSqrOFpChOwngTgCtsgSiBefNKi7UI0GMhGYrLvQG6QRvMoGKkJvIgQ/jECsOJNKAXhBFZAkSfUDuqdPIswrIuRgkhGFoy0FCGDaWnTi1LsqpUM6cySJ70T1ZBFdkz5qVyYxGZnYQ9S/ksY8MO3bvU9FtHeknpN66L9e6qhm4+DHWMoEfI3aVZZBhGSo1gZm37qdk2AfxSHGS8LtegC64UdEdnUlC2PjUqDA8PjX6To5DjIzPY+71mvwMl+zs5Zggf2kqYbL/JTlsN78USaqSSCCogEqz/Q4/dkAjjZhlVkvTcmStPE6TIPM8Qb/KiLezTZMhKPlB9nWk19JgHSH0BsTENRFLsv6lAAAAAElFTkSuQmCC",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAuCAMAAAB6WzuLAAADAFBMVEUReP4ReP4ReP4QeP4Pd/4Ndv4LdP4Jc/4Gcf4DcP4CcP4Bb/4Ab/4Ab/4Ab/4Abv4Abv4Abv4Abv4Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0AavYAY+sAXOAAWNgAVNEAUcwAT8kATscATcUATMQATMQAS8MAS8MAS8MAS8MAS8MAS8MAS8MAS8MAS8MATMMATMMATMIATcIAUMABVb4BWLwBW7oBXrcCXrICWqsBU6ABSpQBQ4sBQokBQYgCQIcCP4UEPIIFOH0JMnMLLW0NL28PMnIUNnUZOnghQHwnRYAqSIIuS4QyToc2U4o+W5BEYpZKaZpPbp5WdKJceqZng6xvi7BwjbByjrB3kbGBl7KGmbKKmrOMm7ONm7OOm7SPnLWQnbWRnraVormZp7ydrL+hssOnuciqvcuwwc+3x9S/zdrF09/J1uLL1+PN2eTR2+bV3ejZ3+nd4evg4+vj5Ozl5u3l5+3m6e/k6/Dh7vLZ8PTP9Pe7+fu2+vy1+/21+/21+/21+/21+/21+/21+/23+/26+/2//P3H/P3b/f32/v3+//3///z///z///z///v///z///3///7///7////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////1DM8mAAABAHRSTlP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAA//////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApx8BhgAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAVxJREFUOI2F1L2KwzAMAGA/wC2d825+gI5atIUrNORM4Qqe0rvFlGRyZo/lIA/iV7n8R5adVFvgQ7YsKcK/DUE/7EN/qVJV9Q5pqwuCHAIgV3WCaJQyW0OiahgxBWRhSNQBqVBmUYAi5IEx2MxAajwnSQZ6ISpxyhRoJ/LLb0rurCZypUmEc46lEb6mST5cSIY0oqM3OTlGsnzIctnKGXOEBBsvXtubOBcTeHhhgYuASO2FeUMUI+IUkZsXDSFzSTxLG7QwIvDTF50fE9uToIkR+RyeroEDAvectjfkRaUdSwS6R5TQMtCZG4DlP3bfcIWOSkZBOhgTMugEa0kSRPbomCdZ01VITLumqpfcEW0o6G+9jP2/hn+EerX3RMfLHj0IT/V/YYg/944RVVfgE8YoYfCYJqRy0TxOzVL48WkzWyrdqIjL3E/Rrn/ib5MdExJfyXNpjYnVh/DFJxD+xZNmYMqLlMgAAAABJRU5ErkJggg=="
];
</script>
2026-02-15 14:42:42 -07:00
</head>
<body onload="if(typeof initialize === 'function') initialize(43.8231, -111.7924, 11, 1, 0);">
<!-- Announcement Banner -->
<div id="banner" class="banner-bg hidden">
<strong id="banner-title"></strong>: <span id="banner-content"></span>
</div>
<!-- Navigation Bar -->
<nav class="navbar accent-bg">
<div class="nav-container">
<a href="/" class="nav-brand">BYU-I Amateur Radio Society</a>
<!-- Mobile Hamburger Toggle -->
<button id="menu-toggle" class="icon-button mobile-only" aria-label="Toggle Navigation Menu">
<svg id="icon-hamburger" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="icon-close" class="icon hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<!-- Desktop Links -->
<div id="desktop-links" class="nav-links desktop-only"></div>
<!-- Desktop Dark Mode Toggle -->
<button class="theme-toggle icon-button desktop-only" aria-label="Toggle Dark Mode">
<svg class="icon icon-sun hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m8.66-8.66h-1M4.34 12H3m15.36 6.36l-.71-.71M6.34 6.34l-.71-.71m12.02 0l-.71.71M6.34 17.66l-.71.71M12 5a7 7 0 100 14 7 7 0 000-14z" />
</svg>
<svg class="icon icon-moon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12.79A9 9 0 1111.21 3a7 7 0 009.79 9.79z" />
</svg>
</button>
</div>
<!-- Mobile Dropdown Menu -->
<div id="mobile-menu" class="mobile-menu mobile-only hidden">
<div id="mobile-links"></div>
<button class="theme-toggle mobile-theme-btn" aria-label="Toggle Dark Mode">
<span class="theme-text">🌙 Dark Mode</span>
</button>
</div>
</nav>
<!-- Main Content -->
<main class="main-