Map in Progress
* {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
font-family: sans-serif;
}
#map-box {
width: 100%;
height: 100vh;
max-height: 100vh;
border: none;
background-color: #011c6b;
overflow: hidden;
display: flex;
touch-action: none;
cursor: pointer;
position: relative;
}
select {
max-width: 50vw;
position: absolute;
top: 10px;
left: 10px;
z-index: 20;
padding: 6px 6px;
font-size: 14px;
border-radius: 6px;
border: 2px solid #9b9b9b;
background: rgb(255, 255, 255);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
#plant-select{
max-width: 50vw;
padding: 6px;
font-size: 14px;
border-radius: 6px;
border: 2px solid #9b9b9b;
background: rgb(255, 255, 255);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
margin: 0;
}
#back-button{
background: rgb(255, 255, 255);
height:30px;
border: 2px solid #9b9b9b;
border-radius: 6px;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
color: #333;
font-size: 14px;
font-family: sans-serif;
padding: 0 10px;
display: flex;
align-items: center;
text-decoration: none;
white-space: nowrap;
}
#manual-coords input {
padding: 6px;
font-size: 14px;
border-radius: 4px;
border: 1px solid #9b9b9b;
}
#manual-coords button {
padding: 6px 10px;
font-size: 14px;
border-radius: 4px;
border: 1px solid #9b9b9b;
background: #f0f0f0;
cursor: pointer;
}
#manual-coords button:hover {
background: #e0e0e0;
}
.flash {
fill: yellow !important;
transition: fill 0.2s ease-in-out;
}
svg {
width: 100%;
height: 100%;
display: block;
}
.zone {
fill: rgb(75, 232, 91);
opacity: 0.6;
stroke: rgb(12, 28, 122);
stroke-width: 2;
transition: all 0.2s ease-in-out;
display: none; /* Hide zones by default */
}
.zone:not(.hidden) {
display: block; /* Show zones when not hidden */
}
.zone:hover,
.zone:focus {
fill: rgb(237, 233, 3);
opacity: 0.5;
stroke: rgb(12, 28, 122);
stroke-width: 3;
cursor: pointer;
}
.zone:active {
opacity: 1;
stroke: red;
stroke-width: 4;
}
#zone-popup {
height: 25vh; /* Fixed size; adjust as needed */
overflow-y: auto; /* Allow scrolling if content overflows */
position: fixed;
bottom: 0;
width: 100%;
background: white;
border-top: 1px solid #ccc;
display: none; /* Hidden by default */
transition: transform 0.3s ease-in-out; /* Smooth slide animation */
transform: translateY(0); /* Default position */
}
#zone-popup.minimized {
transform: translateY(calc(100% - 60px)); /* Show only the button area */
height: 60px; /* Height of minimized state */
overflow: hidden;
}
#zone-popup .popup-minimize {
position: absolute;
top: 5px;
right: 5px;
font-size: 16px;
padding: 5px;
width: 30px;
height: 30px;
text-align: center;
border: none;
background: #f0f0f0;
cursor: pointer;
border-radius: 4px;
}
#zone-popup .popup-minimize:hover {
background: #e0e0e0;
}
#zone-popup .popup-content {
padding: 30px;
}
#zone-popup h4 {
margin: 0 0 10px;
font-size: 18px;
font-weight: bold;
}
#zone-popup ul {
margin: 0;
padding: 0 0 0 20px;
list-style-type: disc;
}
#zone-popup li {
margin: 5px 0;
}
#zone-popup a {
color: #0066cc;
text-decoration: none;
}
#zone-popup a:hover {
text-decoration: underline;
}
a {
color: #007BFF;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#user-marker, #accuracy-circle {
pointer-events: none; /* Prevents interfering with zone clicks or panning */
}
#status {
position: absolute;
bottom: 10px;
left: 10px;
z-index: 20;
color: white;
font-size: 14px;
background: rgba(0, 0, 0, 0.7);
padding: 5px 10px;
border-radius: 4px;
}
.help-button {
position: absolute;
top: 10px;
right: 10px;
z-index: 20;
width: 30px;
height: 30px;
border-radius: 4px;
background: #f0f0f0;
border: 2px solid #9b9b9b;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
color: #333;
font-size: 18px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.help-popup {
display: none;
position: fixed;
transform: translate(-50%, -50%);
background: white;
border: 1px solid #ccc;
padding: 20px;
width: 400px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1000;
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.help-popup-content {
margin-bottom: 20px;
}
.help-popup-content h2 {
margin: 0 0 10px;
font-size: 20px;
font-weight: bold;
}
.help-popup-content ul {
margin: 0;
padding: 0 0 0 20px;
list-style-type: disc;
}
.help-popup-content li {
margin: 5px 0;
}
.close-help-button {
background: #0066cc;
color: white;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
display: block;
margin: 0 auto;
width: 100%;
}
.close-help-button:hover {
background: #0055a5;
}
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-VVMT4J6LN6');
What are you looking for?
?
<!---->
Requesting location...
const svg = document.getElementById('svg-map');
let isPanning = false;
let startX = 0;
let startY = 0;
let velocityX = 0;
let velocityY = 0;
let momentumActive = false;
let lastTouchMove = 0;
let viewBox = { x: 1400, y: 600, width: 1700, height: 1368 };
const initialViewBoxWidth = 1700; // Initial viewBox width for scaling reference
const imageWidth = 5000;
const imageHeight = 4037;
const minZoom = 200;
const maxZoom = 3000;
const baseMarkerRadius = 30; // Base radius of the user marker
const baseStrokeWidth = 5; // Base stroke width of the user marker
let isFirstHelpClose = true; // Flag to track first help popup close
let plantLocations = []; // Will be populated from Google Sheet
async function loadPlantLocations() {
const APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbxjTkjnuc7V6PVlYXZsjuEJyrSSPAYY-kBGR0MZZj8oC_YhxTQIyN0oZv2aSJZEoRDffw/exec'; // {
const plant = String(row.plant ?? row.Plant ?? '').trim();
const information = String(row.Information ?? row.information ?? '').trim();
const locations = String(row.location ?? row.Location ?? '').trim();
if (!plant || !locations) return [];
return locations.split(',').map(loc => ({
plant,
Information: information,
location: loc.trim()
}));
});
console.log(`Loaded ${plantLocations.length} plant locations`);
} catch (err) {
console.error('Failed to load plant locations:', err);
document.getElementById('status').textContent = 'Error loading map data. Please refresh.';
}
}
const popup = document.getElementById('zone-popup');
function applyZoom(scale, originX, originY) {
const newWidth = viewBox.width * scale;
const newHeight = viewBox.height * scale;
if (newWidth >= minZoom && newWidth {
if (Math.abs(velocityX) < 0.10 && Math.abs(velocityY) imageWidth ? (viewBox.width - imageWidth) / 2 : 0;
const overflowY = viewBox.height > imageHeight ? (viewBox.height - imageHeight) / 2 : 0;
const minX = viewBox.width > imageWidth ? -overflowX : 0;
const maxX = viewBox.width > imageWidth ? imageWidth + overflowX - viewBox.width : imageWidth - viewBox.width;
const minY = viewBox.height > imageHeight ? -overflowY : 0;
const maxY = viewBox.height > imageHeight ? imageHeight + overflowY - viewBox.height : imageHeight - viewBox.height;
viewBox.x = Math.min(Math.max(viewBox.x, minX), maxX);
viewBox.y = Math.min(Math.max(viewBox.y, minY), maxY);
}
function updateMarkerSize() {
const marker = document.getElementById('user-marker');
if (marker) {
const zoomFactor = viewBox.width / initialViewBoxWidth;
const scaledRadius = baseMarkerRadius * zoomFactor;
const scaledStrokeWidth = baseStrokeWidth * zoomFactor;
marker.setAttribute('r', scaledRadius);
marker.setAttribute('stroke-width', scaledStrokeWidth);
}
}
function highlightAndZoomToPlant(plantName) {
const zones = document.querySelectorAll('.zone');
const cleanPlantName = plantName.replace(/]+>/g, '');
const matchingPlants = plantLocations.filter(item =>
item.plant.replace(/]+>/g, '').toLowerCase() === cleanPlantName.toLowerCase()
);
console.log(matchingPlants);
const matchingLocations = [...new Set(matchingPlants.map(item => item.location))];
const targets = matchingLocations
.map(location => document.getElementById(location))
.filter(target => target);
zones.forEach(zone => zone.classList.add('hidden'));
if (!matchingLocations.length || !targets.length) {
popup.innerHTML = `
`;
popup.style.display = 'block';
popup.style.maxHeight = '30vh';
popup.classList.remove('minimized');
return;
}
targets.forEach(target => target.classList.remove('hidden'));
let flashes = 0;
const flashInterval = setInterval(() => {
targets.forEach(target => target.classList.toggle('flash'));
flashes++;
if (flashes === 10) {
clearInterval(flashInterval);
targets.forEach(target => target.classList.remove('flash'));
}
}, 350);
const bboxes = targets.map(target => target.getBBox());
const combinedBbox = {
x: Math.min(...bboxes.map(bbox => bbox.x)),
y: Math.min(...bboxes.map(bbox => bbox.y)),
xMax: Math.max(...bboxes.map(bbox => bbox.x + bbox.width)),
yMax: Math.max(...bboxes.map(bbox => bbox.y + bbox.height))
};
combinedBbox.width = combinedBbox.xMax - combinedBbox.x;
combinedBbox.height = combinedBbox.yMax - combinedBbox.y;
const zoomFactor = 10;
const targetWidth = combinedBbox.width * zoomFactor;
const targetHeight = combinedBbox.height * zoomFactor;
const targetX = combinedBbox.x + (combinedBbox.width / 2);
const targetY = combinedBbox.y + (combinedBbox.height / 2);
const clampedWidth = Math.min(Math.max(targetWidth, minZoom), maxZoom);
const aspectRatio = imageHeight / imageWidth;
const clampedHeight = clampedWidth * aspectRatio;
const start = { ...viewBox };
const end = {
x: targetX - clampedWidth / 2,
y: targetY - clampedHeight / 4,
width: clampedWidth,
height: clampedHeight
};
const duration = 300;
const startTime = performance.now();
function animate(time) {
const t = Math.min((time - startTime) / duration, 1);
const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
viewBox.x = start.x + (end.x - start.x) * ease;
viewBox.y = start.y + (end.y - start.y) * ease;
viewBox.width = start.width + (end.width - start.width) * ease;
viewBox.height = start.height + (end.height - start.height) * ease;
svg.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`);
updateMarkerSize(); // Update marker size during zoom animation
if (t item.location === firstLocation)
.map(item => ({ plant: item.plant, Information: item.Information }));
const plantListItems = matchingZonePlants.length > 0
? matchingZonePlants.map(item => `
${item.plant}${item.Information ? `${item.Information} ` : ''} `).join('')
: '
No plants found ';
popup.innerHTML = `
`;
popup.style.display = 'block';
popup.style.maxHeight = '30vh';
popup.classList.remove('minimized');
}
function resetMap() {
const zones = document.querySelectorAll('.zone');
zones.forEach(zone => zone.classList.add('hidden'));
popup.style.display = 'none';
document.getElementById('plant-select').value = '';
}
function openHelpPopup() {
document.getElementById('help-popup').style.display = 'block';
document.getElementById('help-overlay').style.display = 'block';
}
function closeHelpPopup() {
document.getElementById('help-popup').style.display = 'none';
document.getElementById('help-overlay').style.display = 'none';
if (isFirstHelpClose && lastSvgX !== 0 && lastSvgY !== 0) {
isFirstHelpClose = false;
const targetWidth = 1000; // Slightly zoomed in
const aspectRatio = imageHeight / imageWidth;
const targetHeight = targetWidth * aspectRatio;
const start = { ...viewBox };
const end = {
x: lastSvgX - targetWidth / 2,
y: lastSvgY - targetHeight / 2,
width: targetWidth,
height: targetHeight
};
const duration = 300;
const startTime = performance.now();
function animate(time) {
const t = Math.min((time - startTime) / duration, 1);
const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
viewBox.x = start.x + (end.x - start.x) * ease;
viewBox.y = start.y + (end.y - start.y) * ease;
viewBox.width = start.width + (end.width - start.width) * ease;
viewBox.height = start.height + (end.height - start.height) * ease;
svg.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`);
updateMarkerSize();
if (t {
isPanning = true;
startX = e.clientX;
startY = e.clientY;
velocityX = 0;
velocityY = 0;
});
svg.addEventListener('mouseup', () => {
isPanning = false;
startMomentum();
});
svg.addEventListener('mouseleave', () => {
isPanning = false;
});
svg.addEventListener('mousemove', (e) => {
if (!isPanning) return;
const scaleX = viewBox.width / svg.clientWidth;
const scaleY = viewBox.height / svg.clientHeight;
const scale = Math.max(scaleX, scaleY);
const dx = (e.clientX - startX) * scale;
const dy = (e.clientY - startY) * scale;
viewBox.x -= dx;
viewBox.y -= dy;
clampViewBox();
svg.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`);
velocityX = dx * 0.4;
velocityY = dy * 0.4;
startX = e.clientX;
startY = e.clientY;
});
svg.addEventListener('wheel', (e) => {
e.preventDefault();
const scale = e.deltaY > 0 ? 1.1 : 0.9;
const pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
const cursor = pt.matrixTransform(svg.getScreenCTM().inverse());
applyZoom(scale, cursor.x, cursor.y);
}, { passive: false });
let touchStart = [];
svg.addEventListener('touchstart', (e) => {
if (e.touches.length === 1) {
isPanning = true;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
lastTouchMove = Date.now();
} else if (e.touches.length === 2) {
touchStart = [...e.touches].map(t => ({ x: t.clientX, y: t.clientY }));
}
});
svg.addEventListener('touchmove', (e) => {
e.preventDefault();
if (isPanning && e.touches.length === 1) {
const now = Date.now();
const scaleX = viewBox.width / svg.clientWidth;
const scaleY = viewBox.height / svg.clientHeight;
const scale = Math.max(scaleX, scaleY);
const dx = (e.touches[0].clientX - startX) * scale;
const dy = (e.touches[0].clientY - startY) * scale;
viewBox.x -= dx;
viewBox.y -= dy;
clampViewBox();
svg.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`);
velocityX = dx * 0.4;
velocityY = dy * 0.4;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
lastTouchMove = now;
} else if (e.touches.length === 2 && touchStart.length === 2) {
const distStart = Math.hypot(
touchStart[0].x - touchStart[1].x,
touchStart[0].y - touchStart[1].y
);
const distNow = Math.hypot(
e.touches[0].clientX - e.touches[1].clientX,
e.touches[0].clientY - e.touches[1].clientY
);
const scale = distStart / distNow;
const currMidX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
const currMidY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
const pt = svg.createSVGPoint();
pt.x = currMidX;
pt.y = currMidY;
const svgPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
applyZoom(scale, svgPoint.x, svgPoint.y);
touchStart = [...e.touches].map(t => ({ x: t.clientX, y: t.clientY }));
}
}, { passive: false });
svg.addEventListener('touchend', () => {
isPanning = false;
touchStart = [];
startMomentum();
});
svg.addEventListener('click', function (e) {
if (e.target.classList.contains('zone')) {
const zone = e.target;
const zoneID = zone.getAttribute('id');
const href = zone.getAttribute('data-href');
const label = zone.getAttribute('aria-label') || 'No Zone Found';
const matchingPlants = plantLocations
.filter(item => item.location === zoneID)
.map(item => ({ plant: item.plant, Information: item.Information }));
const plantListItems = matchingPlants.length > 0
? matchingPlants.map(item => `
${item.plant}${item.Information ? `${item.Information} ` : ''} `).join('')
: '
No plants found ';
popup.innerHTML = `
`;
popup.style.display = 'block';
popup.style.maxHeight = '30vh';
popup.classList.remove('minimized');
}
});
function populatePlantSelect() {
const select = document.getElementById('plant-select');
select.innerHTML = 'What are you looking for?';
const plantMap = new Map();
plantLocations
.filter(item => item.plant !== '')
.forEach(item => {
const cleanName = item.plant.replace(/]+>/g, '');
plantMap.set(cleanName, item.plant);
});
const uniquePlants = [...plantMap.entries()];
uniquePlants.forEach(([cleanName, originalPlant]) => {
const option = document.createElement('option');
option.value = originalPlant;
option.textContent = cleanName;
select.appendChild(option);
});
}
document.addEventListener('DOMContentLoaded', async () => { try {
const zones = document.querySelectorAll('.zone');
if (!svg) {
console.error('SVG map element not found');
return;
}
if (!popup) {
console.error('Zone popup element not found');
return;
}
// Show help popup on page load
await loadPlantLocations();
// Show help popup on page load
document.getElementById('help-popup').style.display = 'block'; document.getElementById('help-overlay').style.display = 'block';
resetMap();
populatePlantSelect();
document.getElementById('plant-select').addEventListener('change', function () {
const selectedId = this.value;
console.log(selectedId);
if (!selectedId) {
resetMap();
return;
}
highlightAndZoomToPlant(selectedId);
});
popup.addEventListener('click', (e) => {
if (e.target.classList.contains('popup-minimize')) {
const isMinimized = popup.classList.contains('minimized');
popup.classList.toggle('minimized');
e.target.textContent = isMinimized ? '-' : '+';
}
});
document.getElementById('plot-manual-coords')?.addEventListener('click', () => {
const latInput = document.getElementById('manual-lat')?.value;
const lngInput = document.getElementById('manual-lng')?.value;
const lat = parseFloat(latInput);
const lng = parseFloat(lngInput);
if (!isNaN(lat) && !isNaN(lng)) {
const position = {
coords: {
latitude: lat,
longitude: lng,
accuracy: 0
}
};
plotPosition(position, true);
} else {
const status = document.getElementById('status');
status.textContent = 'Invalid coordinates entered.';
}
});
} catch (error) {
console.error('Initialization error:', error);
document.getElementById('status').textContent = 'Error loading map. Please try again.';
}
});
const MAP_BOUNDS = {
minLat: 34.159362,
maxLat: 34.163412,
minLng: -84.333950,
maxLng: -84.328934
};
const IMAGE_WIDTH = 5000;
const IMAGE_HEIGHT = 4037;
const metersPerDegLat = 111132;
const avgLat = (MAP_BOUNDS.minLat + MAP_BOUNDS.maxLat) / 2;
const metersPerDegLng = metersPerDegLat * Math.cos(avgLat * Math.PI / 180);
const deltaLat = MAP_BOUNDS.maxLat - MAP_BOUNDS.minLat;
const deltaLng = MAP_BOUNDS.maxLng - MAP_BOUNDS.minLng;
const scaleX = IMAGE_WIDTH / deltaLng;
const scaleY = IMAGE_HEIGHT / deltaLat;
const pxPerMeterX = scaleX / metersPerDegLng;
const pxPerMeterY = scaleY / metersPerDegLat;
const averagePxPerMeter = (pxPerMeterX + pxPerMeterY) / 2;
let watchId = null;
let lastPosition = null;
let lastSvgX = 0;
let lastSvgY = 0;
function startWatchingLocation() {
const status = document.getElementById('status');
if (navigator.geolocation) {
watchId = navigator.geolocation.watchPosition(
(position) => plotPosition(position, false),
showError,
{
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
}
);
status.textContent = "Watching location...";
} else {
status.textContent = "Geolocation is not supported by this browser.";
}
}
function stopWatchingLocation() {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
const status = document.getElementById('status');
status.textContent = "Stopped watching location.";
}
}
function plotPosition(position, isManual = false) {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
const accuracy = position.coords.accuracy || 0;
const status = document.getElementById('status');
status.textContent = isManual
? `Manual Location: Lat ${lat.toFixed(6)}, Lng ${lng.toFixed(6)}`
: `Location: Lat ${lat.toFixed(6)}, Lng ${lng.toFixed(6)} (Accuracy: ${accuracy.toFixed(0)}m)`;
if (!isManual && lastPosition && calculateDistance(lastPosition, position) = 0 && normX = 0 && normY <= 1) {
const svgX = normX * IMAGE_WIDTH;
const svgY = normY * IMAGE_HEIGHT;
lastSvgX = svgX;
lastSvgY = svgY;
let accuracyMarker = document.getElementById('accuracy-circle');
if (!accuracyMarker) {
accuracyMarker = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
accuracyMarker.setAttribute('id', 'accuracy-circle');
accuracyMarker.setAttribute('fill', 'blue');
accuracyMarker.setAttribute('fill-opacity', '0.2');
accuracyMarker.setAttribute('stroke', 'blue');
accuracyMarker.setAttribute('stroke-width', '2');
svg.appendChild(accuracyMarker);
}
const r = accuracy * averagePxPerMeter;
accuracyMarker.setAttribute('cx', svgX);
accuracyMarker.setAttribute('cy', svgY);
accuracyMarker.setAttribute('r', r);
accuracyMarker.style.transition = 'cx 0.5s ease, cy 0.5s ease, r 0.5s ease';
let marker = document.getElementById('user-marker');
if (!marker) {
marker = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
marker.setAttribute('id', 'user-marker');
marker.setAttribute('fill', 'red');
marker.setAttribute('stroke', 'white');
marker.setAttribute('stroke-width', baseStrokeWidth);
svg.appendChild(marker);
}
marker.setAttribute('cx', svgX);
marker.setAttribute('cy', svgY);
updateMarkerSize();
marker.style.transition = 'cx 0.5s ease, cy 0.5s ease';
} else {
status.textContent += ' (Location is outside map bounds)';
}
}
function calculateDistance(pos1, pos2) {
const R = 6371000;
const dLat = (pos2.coords.latitude - pos1.coords.latitude) * Math.PI / 180;
const dLng = (pos2.coords.longitude - pos1.coords.longitude) * Math.PI / 180;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(pos1.coords.latitude * Math.PI / 180) * Math.cos(pos2.coords.latitude * Math.PI / 180) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function showError(error) {
const status = document.getElementById('status');
switch (error.code) {
case error.PERMISSION_DENIED:
status.textContent = "User denied the request for Geolocation.";
break;
case error.POSITION_UNAVAILABLE:
status.textContent = "Location information is unavailable.";
break;
case error.TIMEOUT:
status.textContent = "The request to get user location timed out.";
break;
case error.UNKNOWN_ERROR:
status.textContent = "An unknown error occurred.";
break;
}
}
startWatchingLocation();
window.addEventListener('beforeunload', stopWatchingLocation);