parent
6298cc25ca
commit
506a98cb7d
6 changed files with 164 additions and 27 deletions
@ -0,0 +1,99 @@ |
|||||||
|
import { Html } from '@react-three/drei' |
||||||
|
import { useEffect, useRef, useState } from 'react'; |
||||||
|
import * as THREE from 'three'; |
||||||
|
import gsap from 'gsap'; |
||||||
|
|
||||||
|
|
||||||
|
export const PointScale=200; |
||||||
|
const PointSize=6; |
||||||
|
|
||||||
|
const PointDuration=5; |
||||||
|
const KeywordOffset=0; |
||||||
|
|
||||||
|
export default function Point({point, index, totalPoints, result, showContent}) { |
||||||
|
|
||||||
|
const [payload, setPayload]=useState(); |
||||||
|
const [showPayload, setShowPayload]=useState(false); |
||||||
|
|
||||||
|
const meshRef=useRef(); |
||||||
|
const refText=useRef(); |
||||||
|
|
||||||
|
useEffect(()=>{ |
||||||
|
if(!payload) return; |
||||||
|
const lifeTime=payload.number/payload.total; |
||||||
|
console.log("Point lifeTime:", lifeTime); |
||||||
|
|
||||||
|
// animate point size based on lifeTime |
||||||
|
const targetSize=PointSize *0.2; |
||||||
|
const initialSize=0; |
||||||
|
|
||||||
|
const timeline=gsap.timeline({ repeat:-1}); |
||||||
|
timeline.set(meshRef.current.scale, { |
||||||
|
x: initialSize, y: initialSize, z: initialSize, |
||||||
|
}); |
||||||
|
timeline.set(refText.current, { |
||||||
|
scale: initialSize, |
||||||
|
opacity: 0, |
||||||
|
}); |
||||||
|
timeline.fromTo(meshRef.current.scale, { |
||||||
|
x: initialSize, y: initialSize, z: initialSize, |
||||||
|
}, { |
||||||
|
x: PointSize, y: PointSize, z: PointSize, |
||||||
|
duration:PointDuration, |
||||||
|
delay: lifeTime *5, |
||||||
|
ease: "power3.in", |
||||||
|
onUpdate:()=>{ |
||||||
|
if(refText.current){ |
||||||
|
refText.current.style.transform=`scale(${meshRef.current.scale.x / PointSize})`; |
||||||
|
refText.current.style.opacity=`${meshRef.current.scale.x / PointSize}`; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
timeline.to(meshRef.current.scale, { |
||||||
|
x: targetSize, y: targetSize, z: targetSize, |
||||||
|
duration:PointDuration, |
||||||
|
ease: "power3.out", |
||||||
|
onUpdate:()=>{ |
||||||
|
if(refText.current){ |
||||||
|
refText.current.style.transform=`scale(${meshRef.current.scale.x / PointSize})`; |
||||||
|
refText.current.style.opacity=`${meshRef.current.scale.x / PointSize}`; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
timeline.play(); |
||||||
|
|
||||||
|
return ()=>{ |
||||||
|
timeline.kill(); |
||||||
|
}; |
||||||
|
|
||||||
|
},[payload]); |
||||||
|
|
||||||
|
useEffect(()=>{ |
||||||
|
|
||||||
|
setPayload(JSON.parse(result.payload.text)); |
||||||
|
|
||||||
|
},[point]); |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<mesh ref={meshRef} position={[point[0]*PointScale, point[1]*PointScale, point[2]*PointScale]}> |
||||||
|
<sphereGeometry args={[PointSize, 32, 32]} /> |
||||||
|
<meshStandardMaterial |
||||||
|
color={new THREE.Color().setHSL(1, 0, 0.2)} |
||||||
|
emissive={new THREE.Color().setHSL(1, 0, 0.2)} |
||||||
|
emissiveIntensity={0.5} |
||||||
|
/> |
||||||
|
<Html> |
||||||
|
<div ref={refText} className='text-white p-2 w-[20vw] select-none translate-x-[-50%] translate-y-[-50%] text-center opacity-0'> |
||||||
|
<div className='flex flex-row justify-center flex-wrap'> |
||||||
|
{payload?.keywords.map((el, index)=><span className='px-2' style={{transform: `translate(${Math.random() * KeywordOffset}px,${Math.random() * KeywordOffset}px)`}}>{el}</span>)} |
||||||
|
</div> |
||||||
|
{showContent && <pre className='text-xs w-[25vw] whitespace-pre-wrap bg-gray-300 text-black rounded p-2'>{(()=>{ |
||||||
|
return `${payload?.content}`; |
||||||
|
})()}</pre>} |
||||||
|
</div> |
||||||
|
</Html> |
||||||
|
</mesh> |
||||||
|
) |
||||||
|
} |
||||||
Loading…
Reference in new issue