129 lines
2.7 KiB
JavaScript
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);
|
|
}
|