Improve radio globe tile sharpness
This commit is contained in:
parent
b8268b4999
commit
54a53a98b7
1 changed files with 3 additions and 27 deletions
|
|
@ -1,7 +1,5 @@
|
||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import Globe from 'globe.gl';
|
import Globe from 'globe.gl';
|
||||||
import { CanvasTexture, Color, LinearFilter, SRGBColorSpace } from 'three';
|
|
||||||
import { TileTextureManager } from './TileTextureManager';
|
|
||||||
|
|
||||||
// ── Types ──
|
// ── Types ──
|
||||||
interface RadioPlace {
|
interface RadioPlace {
|
||||||
|
|
@ -69,8 +67,6 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const globeRef = useRef<any>(null);
|
const globeRef = useRef<any>(null);
|
||||||
const rotationResumeRef = useRef<ReturnType<typeof setTimeout>>(undefined);
|
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 [theme, setTheme] = useState(() => localStorage.getItem('radio-theme') || 'default');
|
||||||
const [places, setPlaces] = useState<RadioPlace[]>([]);
|
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 initRgb = initStyle.getPropertyValue('--accent-rgb').trim() || '230, 126, 34';
|
||||||
const initAccent = initStyle.getPropertyValue('--accent').trim() || '#e67e22';
|
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)
|
const globe = new Globe(containerRef.current)
|
||||||
.backgroundColor('rgba(0,0,0,0)')
|
.backgroundColor('rgba(0,0,0,0)')
|
||||||
.atmosphereColor(`rgb(${initRgb})`)
|
.atmosphereColor(`rgb(${initRgb})`)
|
||||||
.atmosphereAltitude(0.12)
|
.atmosphereAltitude(0.12)
|
||||||
|
.globeImageUrl('/earth-night.jpg')
|
||||||
|
.globeTileEngineUrl((x: number, y: number, z: number) => `/api/radio/tile/${z}/${x}/${y}`)
|
||||||
|
.globeTileEngineMaxLevel(9)
|
||||||
.pointsData(places)
|
.pointsData(places)
|
||||||
// Radio Garden geo format: [lng, lat]
|
// Radio Garden geo format: [lng, lat]
|
||||||
.pointLat((d: any) => d.geo[1])
|
.pointLat((d: any) => d.geo[1])
|
||||||
|
|
@ -233,20 +226,6 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
.width(containerRef.current.clientWidth)
|
.width(containerRef.current.clientWidth)
|
||||||
.height(containerRef.current.clientHeight);
|
.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
|
// Sharp rendering on HiDPI/Retina displays
|
||||||
globe.renderer().setPixelRatio(window.devicePixelRatio);
|
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));
|
const base = Math.max(0.12, Math.min(0.45, 0.06 + (d.size ?? 1) * 0.005));
|
||||||
return base * scale;
|
return base * scale;
|
||||||
});
|
});
|
||||||
// Load higher-res tiles for visible area
|
|
||||||
tileManagerRef.current?.loadViewport(pov.lat, pov.lng, alt);
|
|
||||||
};
|
};
|
||||||
controls.addEventListener('change', onControlsChange);
|
controls.addEventListener('change', onControlsChange);
|
||||||
|
|
||||||
|
|
@ -303,7 +280,6 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
el.removeEventListener('touchstart', onInteract);
|
el.removeEventListener('touchstart', onInteract);
|
||||||
el.removeEventListener('wheel', onInteract);
|
el.removeEventListener('wheel', onInteract);
|
||||||
window.removeEventListener('resize', onResize);
|
window.removeEventListener('resize', onResize);
|
||||||
tileManagerRef.current?.destroy();
|
|
||||||
};
|
};
|
||||||
}, [places, pauseRotation]);
|
}, [places, pauseRotation]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue