90 lines
2.1 KiB
TypeScript
90 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { Canvas, useFrame } from "@react-three/fiber";
|
|
import { Line, OrbitControls, useTexture } from "@react-three/drei";
|
|
import { useMemo, useRef } from "react";
|
|
|
|
type RotatableGroup = {
|
|
rotation: { y: number };
|
|
};
|
|
|
|
function Globe() {
|
|
const groupRef = useRef<RotatableGroup | null>(null);
|
|
const cloudTexture = useTexture("/images/cloud1.png");
|
|
|
|
// Rotate the globe slowly
|
|
useFrame(() => {
|
|
if (groupRef.current) {
|
|
groupRef.current.rotation.y += 0.002;
|
|
}
|
|
});
|
|
|
|
// Coordinates for markers (half-globe)
|
|
const markers = [
|
|
[0, 1, 0],
|
|
[0.7, 0.5, 0.2],
|
|
[-0.5, 0.4, 0.5],
|
|
[0.4, 0.3, -0.7],
|
|
[-0.6, -0.1, 0.3],
|
|
[0.3, -0.2, 0.8],
|
|
];
|
|
const arcPoints = useMemo(() => {
|
|
const radius = 2.5;
|
|
const verticalRadius = radius / 2;
|
|
const segments = 120;
|
|
|
|
return Array.from({ length: 8 }, () => {
|
|
const points: number[] = [];
|
|
for (let i = 0; i < segments; i++) {
|
|
const t = (i / (segments - 1)) * Math.PI;
|
|
const x = Math.cos(t) * radius;
|
|
const z = Math.sin(t) * verticalRadius;
|
|
const y = Math.sin(x / radius) * 0.5;
|
|
points.push(x, y, z);
|
|
}
|
|
return points;
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<group ref={groupRef}>
|
|
{/* Cyan arcs */}
|
|
{arcPoints.map((points, i) => (
|
|
<Line
|
|
key={i}
|
|
points={points}
|
|
color="#00e5ff"
|
|
lineWidth={1}
|
|
transparent
|
|
opacity={0.5}
|
|
/>
|
|
))}
|
|
|
|
{/* Cloud markers */}
|
|
{markers.map(([x, y, z], i) => (
|
|
<mesh key={i} position={[x * 2.5, y * 2.5, z * 2.5]}>
|
|
<planeGeometry args={[0.3, 0.3]} />
|
|
<meshBasicMaterial
|
|
map={cloudTexture}
|
|
transparent
|
|
opacity={1}
|
|
side={2 /* DoubleSide */}
|
|
/>
|
|
</mesh>
|
|
))}
|
|
</group>
|
|
);
|
|
}
|
|
|
|
export function HalfGlobe() {
|
|
return (
|
|
<div className="w-full h-[500px] bg-white flex items-center justify-center">
|
|
<Canvas camera={{ position: [0, 1.5, 4], fov: 45 }}>
|
|
<ambientLight intensity={0.8} />
|
|
<Globe />
|
|
<OrbitControls enableZoom={false} enablePan={false} />
|
|
</Canvas>
|
|
</div>
|
|
);
|
|
}
|