Source: sources/react/displays/medias/TViewport3D_.js

/**
 * @author [Tristan Valcke]{@link https://github.com/Itee}
 * @license [BSD-3-Clause]{@link https://opensource.org/licenses/BSD-3-Clause}
 *
 * @file Todo
 *
 * @example Todo
 *
 */

import React from 'react'

import {
    AmbientLight,
    BoxBufferGeometry,
    GridHelper,
    Mesh,
    MeshPhongMaterial,
    PerspectiveCamera,
    Scene,
    Vector3,
    WebGLRenderer
} from 'three'

class TViewport3D extends React.Component {

    constructor ( props ) {

        super( props )

        this._frameId  = undefined
        this._renderer = new WebGLRenderer( { antialias: true } )
        this._scene    = new Scene()
        this._camera   = new PerspectiveCamera()
        this._cube     = undefined

        // Handler
        this._resize = this._resize.bind( this )

    }

    /**
     * React lifecycle
     */
    componentWillMount () {

        window.addEventListener( 'resize', this._resize, false )

    }

    componentWillReceiveProps ( nextProps ) {}

    componentWillUpdate ( nextProps, nextState ) {

        //        this._resize()

    }

    componentDidUpdate ( prevProps, prevState ) {}

    componentDidCatch ( error, info ) {
        console.error( error )
    }

    componentDidMount () {

        this._resize()

        // Set renderer
        this._renderer.setClearColor( 0x777777 )
        this._renderer.autoClear = true

        // Add renderer canvas
        this._container.appendChild( this._renderer.domElement )

        // Set camera position
        this._camera.fov        = 50
        this._camera.near       = 0.01
        this._camera.far        = 10000
        this._camera.position.x = 0.0
        this._camera.position.y = 5.0
        this._camera.position.z = 7.0
        this._camera.setRotationFromAxisAngle( new Vector3( 1.0, 0.0, 0.0 ), -0.610865 )
        this._camera.updateProjectionMatrix()

        // Add light
        this._scene.add( new AmbientLight( 0xC8C8C8 ) )

        // Create the scene
        const geometry = new BoxBufferGeometry( 1, 1, 1 )
        const material = new MeshPhongMaterial( '0x0096FF' )
        this._cube     = new Mesh( geometry, material )
        this._scene.add( this._cube )

        const gridHelper = new GridHelper( 100, 100 )
        this._scene.add( gridHelper )

        // Add listener

        // Start rendering
        this._startLoop()

    }

    componentWillUnmount () {

        this._stopLoop()

        window.removeEventListener( 'resize', this._resize, false )

    }

    shouldComponentUpdate ( nextProps, nextState ) {}

    render () {

        const props = this.props

        const _style = {
            width:    '100%',
            height:   '100%',
            overflow: 'hidden'
        }

        return (
            <div ref={( container ) => {this._container = container}} id={'myViewport3D'} className={'tViewport3D'} style={_style}></div>
        )

    }

    /**
     * Component methods
     */
    _startLoop () {

        if ( this._frameId ) {
            return
        }

        this._frameId = window.requestAnimationFrame( this._loop.bind( this ) )

    }

    _loop () {

        this._frameId = window.requestAnimationFrame( this._loop.bind( this ) )

        // Perform loop work here
        const SPEED = 0.01
        this._cube.rotation.x -= SPEED * 2
        this._cube.rotation.y -= SPEED
        this._cube.rotation.z -= SPEED * 3

        this._renderer.render( this._scene, this._camera )

    }

    _stopLoop () {

        window.cancelAnimationFrame( this._frameId )

    }

    _resize () {

        const containerWidth  = this._container.clientWidth
        const containerHeight = this._container.clientHeight || 1 // In case height === 0 set to 1

        this._renderer.setSize( containerWidth, containerHeight )
        this._camera.aspect = ( containerWidth / containerHeight )
        this._camera.updateProjectionMatrix()

    }

}

export { TViewport3D }