Skip to content

Instantly share code, notes, and snippets.

@faultyagatha
Forked from chrisrzhou/code1.js
Created November 1, 2020 11:40
Show Gist options
  • Save faultyagatha/cfb0b82190e761b6afd52fbdf75cf4f6 to your computer and use it in GitHub Desktop.
Save faultyagatha/cfb0b82190e761b6afd52fbdf75cf4f6 to your computer and use it in GitHub Desktop.

Revisions

  1. @chrisrzhou chrisrzhou created this gist Mar 21, 2019.
    137 changes: 137 additions & 0 deletions code1.js
    Original 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} />;
    }