大幅调整的一个版本,待测试
parent
088529d6c4
commit
66fceb03de
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Cosmo - 深空探测器可视化</title>
|
<title>Cosmo - 深空探测器可视化</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<!-- Dark space background -->
|
||||||
|
<rect width="100" height="100" fill="#0a0a1f"/>
|
||||||
|
|
||||||
|
<!-- Galaxy spiral -->
|
||||||
|
<defs>
|
||||||
|
<radialGradient id="galaxyGlow" cx="50%" cy="50%">
|
||||||
|
<stop offset="0%" style="stop-color:#88ccff;stop-opacity:0.8"/>
|
||||||
|
<stop offset="50%" style="stop-color:#4488aa;stop-opacity:0.4"/>
|
||||||
|
<stop offset="100%" style="stop-color:#0a0a1f;stop-opacity:0"/>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient id="coreGlow" cx="50%" cy="50%">
|
||||||
|
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1"/>
|
||||||
|
<stop offset="30%" style="stop-color:#88ccff;stop-opacity:0.8"/>
|
||||||
|
<stop offset="100%" style="stop-color:#0a0a1f;stop-opacity:0"/>
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Outer galaxy glow -->
|
||||||
|
<circle cx="50" cy="50" r="40" fill="url(#galaxyGlow)" opacity="0.3"/>
|
||||||
|
|
||||||
|
<!-- Galaxy core -->
|
||||||
|
<ellipse cx="50" cy="50" rx="28" ry="18" fill="url(#galaxyGlow)" opacity="0.6" transform="rotate(30 50 50)"/>
|
||||||
|
<ellipse cx="50" cy="50" rx="24" ry="14" fill="url(#galaxyGlow)" opacity="0.7" transform="rotate(30 50 50)"/>
|
||||||
|
|
||||||
|
<!-- Bright center -->
|
||||||
|
<circle cx="50" cy="50" r="8" fill="url(#coreGlow)"/>
|
||||||
|
|
||||||
|
<!-- Stars -->
|
||||||
|
<circle cx="20" cy="25" r="1.5" fill="#ffffff" opacity="0.9"/>
|
||||||
|
<circle cx="75" cy="30" r="1" fill="#88ccff" opacity="0.8"/>
|
||||||
|
<circle cx="85" cy="65" r="1.2" fill="#ffffff" opacity="0.9"/>
|
||||||
|
<circle cx="15" cy="70" r="1" fill="#88ccff" opacity="0.7"/>
|
||||||
|
<circle cx="30" cy="85" r="1.5" fill="#ffffff" opacity="0.8"/>
|
||||||
|
<circle cx="70" cy="20" r="0.8" fill="#ffffff" opacity="0.9"/>
|
||||||
|
<circle cx="90" cy="45" r="1" fill="#88ccff" opacity="0.8"/>
|
||||||
|
<circle cx="12" cy="50" r="1.2" fill="#ffffff" opacity="0.7"/>
|
||||||
|
|
||||||
|
<!-- Tiny sparkles -->
|
||||||
|
<circle cx="35" cy="20" r="0.5" fill="#ffffff" opacity="0.6"/>
|
||||||
|
<circle cx="65" cy="75" r="0.5" fill="#88ccff" opacity="0.6"/>
|
||||||
|
<circle cx="25" cy="60" r="0.5" fill="#ffffff" opacity="0.5"/>
|
||||||
|
<circle cx="80" cy="80" r="0.5" fill="#88ccff" opacity="0.6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -117,7 +117,7 @@ function App() {
|
||||||
// Filter probes and planets from all bodies
|
// Filter probes and planets from all bodies
|
||||||
const probes = bodies.filter((b) => b.type === 'probe');
|
const probes = bodies.filter((b) => b.type === 'probe');
|
||||||
const planets = bodies.filter((b) =>
|
const planets = bodies.filter((b) =>
|
||||||
b.type === 'planet' || b.type === 'dwarf_planet' || b.type === 'satellite' || b.type === 'comet'
|
b.type === 'planet' || b.type === 'dwarf_planet' || b.type === 'satellite' || b.type === 'comet' || b.type === 'star'
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBodySelect = (body: CelestialBody | null) => {
|
const handleBodySelect = (body: CelestialBody | null) => {
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,8 @@ interface BodyDetailOverlayProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom camera control for automatic rotation
|
// No auto-rotation - user controls the view
|
||||||
function AutoRotateCamera() {
|
// Removed AutoRotateCamera to allow user to control the view angle
|
||||||
useFrame((state) => {
|
|
||||||
state.camera.position.x = Math.sin(state.clock.elapsedTime * 0.1) * 3;
|
|
||||||
state.camera.position.z = Math.cos(state.clock.elapsedTime * 0.1) * 3;
|
|
||||||
state.camera.lookAt(0, 0, 0);
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function BodyDetailOverlay({ bodyId, onClose }: BodyDetailOverlayProps) {
|
export function BodyDetailOverlay({ bodyId, onClose }: BodyDetailOverlayProps) {
|
||||||
|
|
@ -74,21 +67,21 @@ export function BodyDetailOverlay({ bodyId, onClose }: BodyDetailOverlayProps) {
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="absolute inset-0 flex items-center justify-center text-blue-300">加载中...</div>
|
<div className="absolute inset-0 flex items-center justify-center text-blue-300">加载中...</div>
|
||||||
) : (
|
) : (
|
||||||
<Canvas camera={{ position: [3, 2, 3], fov: 60 }}>
|
<Canvas camera={{ position: [0, 0, 5], fov: 50 }}>
|
||||||
<ambientLight intensity={0.5} />
|
<ambientLight intensity={0.6} />
|
||||||
<pointLight position={[10, 10, 10]} intensity={1} />
|
<pointLight position={[10, 10, 10]} intensity={1.2} />
|
||||||
<pointLight position={[-10, -10, -10]} intensity={0.5} color="#88aaff" />
|
<pointLight position={[-10, -10, -10]} intensity={0.6} color="#88aaff" />
|
||||||
<directionalLight position={[0, 0, 5]} intensity={0.5} /> {/* Frontal light */}
|
<directionalLight position={[5, 0, 5]} intensity={0.8} />
|
||||||
<directionalLight position={[0, 0, -5]} intensity={0.2} /> {/* Back light */}
|
<directionalLight position={[-5, 0, -5]} intensity={0.4} />
|
||||||
|
|
||||||
<AutoRotateCamera /> {/* Auto rotate for presentation */}
|
|
||||||
|
|
||||||
<OrbitControls
|
<OrbitControls
|
||||||
enableZoom={true}
|
enableZoom={true}
|
||||||
enablePan={false}
|
enablePan={false}
|
||||||
enableRotate={true}
|
enableRotate={true}
|
||||||
minDistance={0.5}
|
minDistance={1}
|
||||||
maxDistance={10}
|
maxDistance={8}
|
||||||
|
maxPolarAngle={Math.PI}
|
||||||
|
minPolarAngle={0}
|
||||||
/>
|
/>
|
||||||
<BodyViewer body={bodyData} />
|
<BodyViewer body={bodyData} />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,39 @@ export function BodyViewer({ body }: BodyViewerProps) {
|
||||||
const [modelScale, setModelScale] = useState<number>(1.0);
|
const [modelScale, setModelScale] = useState<number>(1.0);
|
||||||
const [loadError, setLoadError] = useState<boolean>(false);
|
const [loadError, setLoadError] = useState<boolean>(false);
|
||||||
|
|
||||||
// Determine size and appearance
|
// Determine size and appearance - use larger sizes for detail view with a cap
|
||||||
const appearance = useMemo(() => {
|
const appearance = useMemo(() => {
|
||||||
|
const baseSize = getCelestialSize(body.name, body.type);
|
||||||
|
|
||||||
|
// Detail view scaling strategy:
|
||||||
|
// - Small bodies (< 0.15): scale up 3x for visibility
|
||||||
|
// - Medium bodies (0.15-0.3): scale up 2x
|
||||||
|
// - Large bodies (> 0.3): use base size with max cap of 1.2
|
||||||
|
let finalSize: number;
|
||||||
|
|
||||||
if (body.type === 'star') {
|
if (body.type === 'star') {
|
||||||
return { size: 0.4, emissive: '#FDB813', emissiveIntensity: 1.5 };
|
finalSize = 1.0; // Fixed size for stars
|
||||||
|
} else if (baseSize < 0.15) {
|
||||||
|
// Small bodies: scale up for visibility
|
||||||
|
finalSize = baseSize * 3.0;
|
||||||
|
} else if (baseSize < 0.3) {
|
||||||
|
// Medium bodies: moderate scaling
|
||||||
|
finalSize = baseSize * 2.0;
|
||||||
|
} else {
|
||||||
|
// Large bodies: minimal or no scaling with a cap
|
||||||
|
finalSize = Math.min(baseSize * 1.2, 1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.type === 'star') {
|
||||||
|
return { size: finalSize, emissive: '#FDB813', emissiveIntensity: 1.5 };
|
||||||
}
|
}
|
||||||
if (body.type === 'comet') {
|
if (body.type === 'comet') {
|
||||||
return { size: getCelestialSize(body.name, body.type), emissive: '#000000', emissiveIntensity: 0 };
|
return { size: finalSize, emissive: '#000000', emissiveIntensity: 0 };
|
||||||
}
|
}
|
||||||
if (body.type === 'satellite') {
|
if (body.type === 'satellite') {
|
||||||
return { size: getCelestialSize(body.name, body.type), emissive: '#888888', emissiveIntensity: 0.4 };
|
return { size: finalSize, emissive: '#888888', emissiveIntensity: 0.4 };
|
||||||
}
|
}
|
||||||
return { size: getCelestialSize(body.name, body.type), emissive: '#000000', emissiveIntensity: 0 };
|
return { size: finalSize, emissive: '#000000', emissiveIntensity: 0 };
|
||||||
}, [body.name, body.type]);
|
}, [body.name, body.type]);
|
||||||
|
|
||||||
// Fetch resources (texture or model)
|
// Fetch resources (texture or model)
|
||||||
|
|
@ -113,9 +134,9 @@ function ProbeModelViewer({ modelPath, modelScale }: { modelPath: string; modelS
|
||||||
const size = new THREE.Vector3();
|
const size = new THREE.Vector3();
|
||||||
box.getSize(size);
|
box.getSize(size);
|
||||||
const maxDimension = Math.max(size.x, size.y, size.z);
|
const maxDimension = Math.max(size.x, size.y, size.z);
|
||||||
const targetSize = 0.35; // Standardize view
|
const targetSize = 1.2; // Increased from 0.35 to 1.2 for detail view - larger probes
|
||||||
const calculatedScale = maxDimension > 0 ? targetSize / maxDimension : 0.3;
|
const calculatedScale = maxDimension > 0 ? targetSize / maxDimension : 0.8;
|
||||||
const finalScale = Math.max(0.2, Math.min(1.0, calculatedScale));
|
const finalScale = Math.max(0.5, Math.min(3.0, calculatedScale)); // Increased range for larger display
|
||||||
return finalScale * modelScale;
|
return finalScale * modelScale;
|
||||||
}, [scene, modelScale]);
|
}, [scene, modelScale]);
|
||||||
|
|
||||||
|
|
@ -373,13 +394,57 @@ function PlanetModelViewer({ body, size, emissive, emissiveIntensity, texturePat
|
||||||
{/* Saturn Rings */}
|
{/* Saturn Rings */}
|
||||||
{body.id === '699' && <SaturnRings />}
|
{body.id === '699' && <SaturnRings />}
|
||||||
|
|
||||||
{/* Sun glow effect */}
|
{/* Sun glow effect - multi-layer scattered light */}
|
||||||
{body.type === 'star' && (
|
{body.type === 'star' && (
|
||||||
<>
|
<>
|
||||||
<pointLight intensity={10} distance={400} color="#fff8e7" />
|
<pointLight intensity={10} distance={400} color="#fff8e7" />
|
||||||
|
|
||||||
|
{/* Inner bright corona */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 1.3, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FDB813"
|
||||||
|
transparent
|
||||||
|
opacity={0.6}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Middle glow layer */}
|
||||||
<mesh>
|
<mesh>
|
||||||
<sphereGeometry args={[size * 1.8, 32, 32]} />
|
<sphereGeometry args={[size * 1.8, 32, 32]} />
|
||||||
<meshBasicMaterial color="#FDB813" transparent opacity={0.35} />
|
<meshBasicMaterial
|
||||||
|
color="#FDB813"
|
||||||
|
transparent
|
||||||
|
opacity={0.3}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Outer diffuse halo */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 2.5, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FFD700"
|
||||||
|
transparent
|
||||||
|
opacity={0.15}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Far scattered light */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 3.5, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FFA500"
|
||||||
|
transparent
|
||||||
|
opacity={0.08}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -355,13 +355,57 @@ function PlanetMesh({ body, size, emissive, emissiveIntensity, scaledPos, textur
|
||||||
{/* Saturn Rings */}
|
{/* Saturn Rings */}
|
||||||
{body.id === '699' && <SaturnRings />}
|
{body.id === '699' && <SaturnRings />}
|
||||||
|
|
||||||
{/* Sun glow effect */}
|
{/* Sun glow effect - multi-layer scattered light */}
|
||||||
{body.type === 'star' && (
|
{body.type === 'star' && (
|
||||||
<>
|
<>
|
||||||
<pointLight intensity={10} distance={400} color="#fff8e7" />
|
<pointLight intensity={10} distance={400} color="#fff8e7" />
|
||||||
|
|
||||||
|
{/* Inner bright corona */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 1.3, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FDB813"
|
||||||
|
transparent
|
||||||
|
opacity={0.6}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Middle glow layer */}
|
||||||
<mesh>
|
<mesh>
|
||||||
<sphereGeometry args={[size * 1.8, 32, 32]} />
|
<sphereGeometry args={[size * 1.8, 32, 32]} />
|
||||||
<meshBasicMaterial color="#FDB813" transparent opacity={0.35} />
|
<meshBasicMaterial
|
||||||
|
color="#FDB813"
|
||||||
|
transparent
|
||||||
|
opacity={0.3}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Outer diffuse halo */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 2.5, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FFD700"
|
||||||
|
transparent
|
||||||
|
opacity={0.15}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* Far scattered light */}
|
||||||
|
<mesh>
|
||||||
|
<sphereGeometry args={[size * 3.5, 32, 32]} />
|
||||||
|
<meshBasicMaterial
|
||||||
|
color="#FFA500"
|
||||||
|
transparent
|
||||||
|
opacity={0.08}
|
||||||
|
blending={THREE.AdditiveBlending}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
@ -369,18 +413,18 @@ function PlanetMesh({ body, size, emissive, emissiveIntensity, scaledPos, textur
|
||||||
{/* Name label using CanvasTexture */}
|
{/* Name label using CanvasTexture */}
|
||||||
{labelTexture && (
|
{labelTexture && (
|
||||||
<Billboard
|
<Billboard
|
||||||
position={[0, size + 1.0, 0]} // Raised slightly
|
position={[0, size + 0.8, 0]} // Slightly closer to body
|
||||||
follow={true}
|
follow={true}
|
||||||
lockX={false}
|
lockX={false}
|
||||||
lockY={false}
|
lockY={false}
|
||||||
lockZ={false}
|
lockZ={false}
|
||||||
>
|
>
|
||||||
<mesh scale={[2.5, 1.25, 1]}>
|
<mesh scale={[1.8, 0.9, 1]}>
|
||||||
<planeGeometry />
|
<planeGeometry />
|
||||||
<meshBasicMaterial
|
<meshBasicMaterial
|
||||||
map={labelTexture}
|
map={labelTexture}
|
||||||
transparent
|
transparent
|
||||||
opacity={isSelected ? 1 : 0.6}
|
opacity={isSelected ? 1 : 0.6}
|
||||||
depthWrite={false}
|
depthWrite={false}
|
||||||
toneMapped={false} // Keep colors bright
|
toneMapped={false} // Keep colors bright
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Search, Globe, Rocket, Moon, Asterisk, Sparkles } from 'lucide-react';
|
import { ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Search, Globe, Rocket, Moon, Asterisk, Sparkles, Star } from 'lucide-react';
|
||||||
import type { CelestialBody } from '../types';
|
import type { CelestialBody } from '../types';
|
||||||
|
|
||||||
interface ProbeListProps {
|
interface ProbeListProps {
|
||||||
|
|
@ -38,9 +38,8 @@ export function ProbeList({ probes, planets, onBodySelect, selectedBody, onReset
|
||||||
if (!b.positions || b.positions.length === 0) {
|
if (!b.positions || b.positions.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter by search term and type
|
// Filter by search term - include all types including stars
|
||||||
return (b.name_zh || b.name).toLowerCase().includes(searchTerm.toLowerCase()) &&
|
return (b.name_zh || b.name).toLowerCase().includes(searchTerm.toLowerCase());
|
||||||
b.type !== 'star'; // Exclude Sun from list
|
|
||||||
})
|
})
|
||||||
.map(body => ({
|
.map(body => ({
|
||||||
body,
|
body,
|
||||||
|
|
@ -53,6 +52,7 @@ export function ProbeList({ probes, planets, onBodySelect, selectedBody, onReset
|
||||||
const allBodies = [...planets, ...probes];
|
const allBodies = [...planets, ...probes];
|
||||||
const processedBodies = processBodies(allBodies);
|
const processedBodies = processBodies(allBodies);
|
||||||
|
|
||||||
|
const starList = processedBodies.filter(({ body }) => body.type === 'star');
|
||||||
const planetList = processedBodies.filter(({ body }) => body.type === 'planet');
|
const planetList = processedBodies.filter(({ body }) => body.type === 'planet');
|
||||||
const dwarfPlanetList = processedBodies.filter(({ body }) => body.type === 'dwarf_planet');
|
const dwarfPlanetList = processedBodies.filter(({ body }) => body.type === 'dwarf_planet');
|
||||||
const satelliteList = processedBodies.filter(({ body }) => body.type === 'satellite');
|
const satelliteList = processedBodies.filter(({ body }) => body.type === 'satellite');
|
||||||
|
|
@ -107,6 +107,20 @@ export function ProbeList({ probes, planets, onBodySelect, selectedBody, onReset
|
||||||
|
|
||||||
{/* List Content */}
|
{/* List Content */}
|
||||||
<div className="flex-1 overflow-y-auto custom-scrollbar p-2 space-y-2">
|
<div className="flex-1 overflow-y-auto custom-scrollbar p-2 space-y-2">
|
||||||
|
{/* Stars Group */}
|
||||||
|
{starList.length > 0 && (
|
||||||
|
<BodyGroup
|
||||||
|
title="恒星"
|
||||||
|
icon={<Star size={12} />}
|
||||||
|
count={starList.length}
|
||||||
|
bodies={starList}
|
||||||
|
isExpanded={expandedGroup === 'star'}
|
||||||
|
onToggle={() => toggleGroup('star')}
|
||||||
|
selectedBody={selectedBody}
|
||||||
|
onBodySelect={onBodySelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Planets Group */}
|
{/* Planets Group */}
|
||||||
{planetList.length > 0 && (
|
{planetList.length > 0 && (
|
||||||
<BodyGroup
|
<BodyGroup
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ export function CelestialBodies() {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane tab="详细信息 (Markdown)" key="details">
|
<Tabs.TabPane tab="详细信息" key="details">
|
||||||
<Form.Item name="details" style={{ marginBottom: 0 }}>
|
<Form.Item name="details" style={{ marginBottom: 0 }}>
|
||||||
<MdEditor
|
<MdEditor
|
||||||
value={form.getFieldValue('details')}
|
value={form.getFieldValue('details')}
|
||||||
|
|
|
||||||
|
|
@ -240,20 +240,14 @@ export function SystemSettings() {
|
||||||
styles={{ body: { padding: 16 } }}
|
styles={{ body: { padding: 16 } }}
|
||||||
>
|
>
|
||||||
<Alert
|
<Alert
|
||||||
title="重要操作说明"
|
title="清除缓存会清空所有内存缓存和 Redis 缓存,包括:"
|
||||||
description={
|
description={
|
||||||
<div>
|
<div>
|
||||||
<p style={{ marginBottom: 8 }}>
|
|
||||||
清除缓存会清空所有内存缓存和 Redis 缓存,包括:
|
|
||||||
</p>
|
|
||||||
<ul style={{ marginBottom: 0, paddingLeft: 20 }}>
|
<ul style={{ marginBottom: 0, paddingLeft: 20 }}>
|
||||||
<li>位置数据缓存(当前位置和历史位置)</li>
|
<li>* 位置数据缓存(当前位置和历史位置)</li>
|
||||||
<li>NASA API 响应缓存</li>
|
<li>* NASA API 响应缓存</li>
|
||||||
<li>所有其他临时缓存数据</li>
|
<li>* 所有其他临时缓存数据</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p style={{ marginTop: 8, marginBottom: 0, color: '#fa8c16' }}>
|
|
||||||
<WarningOutlined /> 清除后下次查询会重新从数据库或 NASA API 获取数据,可能会较慢
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
type="warning"
|
type="warning"
|
||||||
|
|
@ -279,10 +273,6 @@ export function SystemSettings() {
|
||||||
清除所有缓存
|
清除所有缓存
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
|
||||||
<Button icon={<ReloadOutlined />} onClick={loadData}>
|
|
||||||
刷新数据
|
|
||||||
</Button>
|
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,37 +27,37 @@ export function createLabelTexture(name: string, subtext: string | null, distanc
|
||||||
// Center the single name vertically
|
// Center the single name vertically
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
// Use a slightly larger font for simple labels (like stars/constellations)
|
// Use a slightly larger font for simple labels (like stars/constellations)
|
||||||
ctx.font = 'bold 72px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
ctx.font = 'bold 48px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fillText(name, 256, 128);
|
ctx.fillText(name, 256, 128);
|
||||||
} else {
|
} else {
|
||||||
// Complex Label Mode (Name + Subtext + Distance)
|
// Complex Label Mode (Name + Subtext + Distance)
|
||||||
ctx.textBaseline = 'top';
|
ctx.textBaseline = 'top';
|
||||||
|
|
||||||
// 1. Name (Large, Top)
|
// 1. Name (Large, Top)
|
||||||
ctx.font = 'bold 64px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
ctx.font = 'bold 42px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fillText(name, 256, 10);
|
ctx.fillText(name, 256, 10);
|
||||||
|
|
||||||
let nextY = 90;
|
let nextY = 65;
|
||||||
|
|
||||||
// 2. Subtext/Offset (Medium, Middle)
|
// 2. Subtext/Offset (Medium, Middle)
|
||||||
if (subtext) {
|
if (subtext) {
|
||||||
ctx.font = 'bold 42px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
ctx.font = 'bold 32px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif';
|
||||||
ctx.fillStyle = '#ffaa00'; // Orange for warning/info
|
ctx.fillStyle = '#ffaa00'; // Orange for warning/info
|
||||||
ctx.fillText(subtext, 256, nextY);
|
ctx.fillText(subtext, 256, nextY);
|
||||||
nextY += 60;
|
nextY += 48;
|
||||||
} else {
|
} else {
|
||||||
// Add some spacing if no subtext
|
// Add some spacing if no subtext
|
||||||
nextY += 20;
|
nextY += 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Distance (Small, Bottom)
|
// 3. Distance (Small, Bottom)
|
||||||
if (distance) {
|
if (distance) {
|
||||||
ctx.font = '36px "SF Mono", "Roboto Mono", Menlo, monospace';
|
ctx.font = '28px "SF Mono", "Roboto Mono", Menlo, monospace';
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
// Reduce opacity for distance to make it less distracting
|
// Reduce opacity for distance to make it less distracting
|
||||||
ctx.globalAlpha = 0.7;
|
ctx.globalAlpha = 0.7;
|
||||||
ctx.fillText(distance, 256, nextY);
|
ctx.fillText(distance, 256, nextY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue