Created
March 21, 2019 05:52
-
-
Save chrisrzhou/df1be3e9b77cad484a4fdd1ce47d28d4 to your computer and use it in GitHub Desktop.
Revisions
-
chrisrzhou created this gist
Mar 21, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,137 @@ function useResponsiveCanvas<T>( initialSize?: MinMaxPair, ): State { const canvasRef = useRef<HTMLCanvasElement>(); const mountRef = useRef<HTMLDivElement>(); const [size, setSize] = useState<MinMaxPair>([0, 0]); // set initial svg and size useEffect(() => { const canvas = document.createElement('canvas'); const mount = mountRef.current; canvas.style.display = 'block'; canvasRef.current = canvas; // update initial size let width = 0; let height = 0; if (initialSize !== undefined) { // Use initialSize if it is provided [width, height] = initialSize; } else { // Use parentElement size if resized has not updated width = mount.offsetWidth; height = mount.offsetHeight; } setSize([width, height]); // update resize using a resize observer const resizeObserver = new ResizeObserver(entries => { if (!entries || !entries.length) { return; } if (initialSize === undefined) { let { width, height } = entries[0].contentRect; setSize([width, height]); } }); resizeObserver.observe(mount); mount.appendChild(canvas); // cleanup return () => { resizeObserver.unobserve(mount); mount.removeChild(canvas); }; }, [initialSize]); return { canvas: canvasRef.current, mountRef, size, }; } function ReactGlobe({ size: initialSize }: Props): React.ReactElement { const { canvas, mountRef, size } = useResponsiveCanvas(initialSize); const [width, height] = size; const aspect = 1; const viewAngle = 45; const near = 0.1; const far = 10000; const rendererRef = useRef<THREE.WebGLRenderer>( new THREE.WebGLRenderer({ canvas }), ); const cameraRef = useRef<THREE.PerspectiveCamera>( new THREE.PerspectiveCamera(viewAngle, aspect, near, far), ); const sceneRef = useRef<THREE.Scene>(new THREE.Scene()); const globeRef = useRef<THREE.Group>(new THREE.Group()); const textureLoaderRef = useRef<THREE.TextureLoader>( new THREE.TextureLoader(), ); const pointLightRef = useRef<THREE.PointLight>( new THREE.PointLight(0xffffff), ); const animationFrameID = useRef<number>(); // init globe useEffect(() => { // get current instances const mount = mountRef.current; const renderer = rendererRef.current; const camera = cameraRef.current; const scene = sceneRef.current; const globe = globeRef.current; const textureLoader = textureLoaderRef.current; const pointLight = pointLightRef.current; //set update function to transform the scene and view function animate(): void { renderer.render(scene, camera); requestAnimationFrame(animate); } const RADIUS = 300; const SEGMENTS = 50; const RINGS = 50; // build globe textureLoader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/e7ff8ca1be184316132f28a7c48d6bfdf26e2db0/examples/textures/land_ocean_ice_cloud_2048.jpg', function(map) { const sphere = new THREE.SphereGeometry(RADIUS, SEGMENTS, RINGS); const material = new THREE.MeshBasicMaterial({ map, }); const mesh = new THREE.Mesh(sphere, material); globe.add(mesh); }, ); globe.position.z = -RADIUS; // position light and camera pointLight.position.x = 10; pointLight.position.y = 50; pointLight.position.z = 400; camera.position.set(0, 0, 500); // update scene scene.add(camera); scene.add(globe); scene.add(pointLight); // mount element and animate mount.appendChild(renderer.domElement); animate(); }, [mountRef]); // update size useEffect(() => { const renderer = rendererRef.current; renderer.setSize(width, height); }, [height, width]); return <div style={{ height: '100%', width: '100%' }} ref={mountRef} />; }