Improve radio globe tile sharpness

This commit is contained in:
Daniel 2026-03-06 12:01:41 +01:00
parent b8268b4999
commit 54a53a98b7

View file

@ -1,7 +1,5 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import Globe from 'globe.gl';
import { CanvasTexture, Color, LinearFilter, SRGBColorSpace } from 'three';
import { TileTextureManager } from './TileTextureManager';
// ── Types ──
interface RadioPlace {
@ -69,8 +67,6 @@ export default function RadioTab({ data }: { data: any }) {
const containerRef = useRef<HTMLDivElement>(null);
const globeRef = useRef<any>(null);
const rotationResumeRef = useRef<ReturnType<typeof setTimeout>>(undefined);
const tileManagerRef = useRef<TileTextureManager | null>(null);
const tileTextureRef = useRef<CanvasTexture | null>(null);
const [theme, setTheme] = useState(() => localStorage.getItem('radio-theme') || 'default');
const [places, setPlaces] = useState<RadioPlace[]>([]);
@ -207,16 +203,13 @@ export default function RadioTab({ data }: { data: any }) {
const initRgb = initStyle.getPropertyValue('--accent-rgb').trim() || '230, 126, 34';
const initAccent = initStyle.getPropertyValue('--accent').trim() || '#e67e22';
// ── Tile-based texture (like Radio Garden) ──
const tileMgr = new TileTextureManager(4096, 2048, () => {
if (tileTextureRef.current) tileTextureRef.current.needsUpdate = true;
});
tileManagerRef.current = tileMgr;
const globe = new Globe(containerRef.current)
.backgroundColor('rgba(0,0,0,0)')
.atmosphereColor(`rgb(${initRgb})`)
.atmosphereAltitude(0.12)
.globeImageUrl('/earth-night.jpg')
.globeTileEngineUrl((x: number, y: number, z: number) => `/api/radio/tile/${z}/${x}/${y}`)
.globeTileEngineMaxLevel(9)
.pointsData(places)
// Radio Garden geo format: [lng, lat]
.pointLat((d: any) => d.geo[1])
@ -233,20 +226,6 @@ export default function RadioTab({ data }: { data: any }) {
.width(containerRef.current.clientWidth)
.height(containerRef.current.clientHeight);
// Apply tile canvas as globe texture
const texture = new CanvasTexture(tileMgr.canvas);
texture.minFilter = LinearFilter;
texture.generateMipmaps = false;
texture.colorSpace = SRGBColorSpace;
tileTextureRef.current = texture;
const mat = globe.globeMaterial() as any;
mat.map = texture;
mat.color = new Color(0xffffff);
mat.needsUpdate = true;
// Start loading tiles (progressive: zoom 1 → 2 → 3)
tileMgr.init();
// Sharp rendering on HiDPI/Retina displays
globe.renderer().setPixelRatio(window.devicePixelRatio);
@ -274,8 +253,6 @@ export default function RadioTab({ data }: { data: any }) {
const base = Math.max(0.12, Math.min(0.45, 0.06 + (d.size ?? 1) * 0.005));
return base * scale;
});
// Load higher-res tiles for visible area
tileManagerRef.current?.loadViewport(pov.lat, pov.lng, alt);
};
controls.addEventListener('change', onControlsChange);
@ -303,7 +280,6 @@ export default function RadioTab({ data }: { data: any }) {
el.removeEventListener('touchstart', onInteract);
el.removeEventListener('wheel', onInteract);
window.removeEventListener('resize', onResize);
tileManagerRef.current?.destroy();
};
}, [places, pauseRotation]);