Files
planet/frontend/public/earth/js/mobile-center-country-highlight.js
linkong e1984c7a35 release: bump version to 0.49.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:42:27 +08:00

129 lines
2.7 KiB
JavaScript

import * as THREE from "three";
import {
clearCountryBoundaryHover,
getShowCountryBoundaries,
updateCountryBoundaryHover,
} from "./country-boundaries.js";
import { screenToEarthCoords, vector3ToLatLon } from "./utils.js";
const UPDATE_INTERVAL_MS = 120;
const MIN_COORD_DELTA_DEGREES = 0.05;
const BLOCKING_BODY_CLASSES = [
"earth-mobile-drawer-open",
"earth-search-open",
"earth-settings-open",
"earth-media-open",
"earth-info-open",
];
const centerRaycaster = new THREE.Raycaster();
const centerMouse = new THREE.Vector2();
let ownsHighlight = false;
let lastUpdateAt = 0;
let lastLat = null;
let lastLon = null;
function isMobileLayout() {
return document.body.classList.contains("layout-mode-mobile");
}
function hasBlockingForegroundUi() {
return BLOCKING_BODY_CLASSES.some((className) =>
document.body.classList.contains(className),
);
}
function resetCachedCenter() {
lastUpdateAt = 0;
lastLat = null;
lastLon = null;
}
export function clearMobileCenterCountryHighlight() {
if (ownsHighlight) {
clearCountryBoundaryHover();
}
ownsHighlight = false;
resetCachedCenter();
}
function clearAnyMobileCountryHighlight() {
clearCountryBoundaryHover();
ownsHighlight = false;
resetCachedCenter();
}
function shouldSkipForSmallMovement(coords) {
if (lastLat === null || lastLon === null) return false;
return (
Math.abs(coords.lat - lastLat) < MIN_COORD_DELTA_DEGREES &&
Math.abs(coords.lon - lastLon) < MIN_COORD_DELTA_DEGREES
);
}
export function updateMobileCenterCountryHighlight({
camera,
earth,
renderer,
now = performance.now(),
isBlocked = false,
} = {}) {
const mobile = isMobileLayout();
if (!mobile) {
clearMobileCenterCountryHighlight();
return null;
}
if (
!camera ||
!earth ||
!renderer?.domElement ||
isBlocked ||
hasBlockingForegroundUi() ||
!getShowCountryBoundaries()
) {
clearAnyMobileCountryHighlight();
return null;
}
if (now - lastUpdateAt < UPDATE_INTERVAL_MS) {
return null;
}
const rect = renderer.domElement.getBoundingClientRect();
if (rect.width <= 0 || rect.height <= 0) {
clearMobileCenterCountryHighlight();
return null;
}
const earthPoint = screenToEarthCoords(
rect.left + rect.width / 2,
rect.top + rect.height / 2,
camera,
earth,
renderer.domElement,
centerRaycaster,
centerMouse,
);
lastUpdateAt = now;
if (!earthPoint) {
clearMobileCenterCountryHighlight();
return null;
}
const coords = vector3ToLatLon(earthPoint);
if (shouldSkipForSmallMovement(coords)) {
return null;
}
lastLat = coords.lat;
lastLon = coords.lon;
ownsHighlight = true;
return updateCountryBoundaryHover(coords);
}