Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Property undefined in Three JS creating 3D canvas as a class

I’m trying to create a web 3D scene using Three.js, in the hope of better future maintainability I opted to code it as a class

export class RenderCanvas {

    #canvas;             // document.querySelector(idOfCanvas)
    #renderer;            // WebgL renderer
    #scene;
    #controls            // Trackball control
    #camera
    // ... other properties 
    
    constructor(){ /* ... */ } 
    startup() { 
        this.#renderer = new THREE.WebGLRenderer({
            antialias: true,
            canvas: this.#canvas
        });
        // Other initializations 
    }
    loadGeometries() { /* add models and lights into the scene */ }

    update(time) {
        const canvas = this.#renderer.domElement;
        this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
        this.#camera.updateProjectionMatrix();
        // This is for resizing the render area and fit the resolution

        requestAnimationFrame(this.update);
        this.#controls.update();

        this.#renderer.render(this.#scene, this.#camera);
    }

    main() {
        this.startup();
        this.addLights();
        this.loadGeometries(); 

        requestAnimationFrame(this.update);
    }
}

And in another script I can just do let rc = new RenderCanvas(); and rc.main();.

But in the update method, on line const canvas = this.#renderer.domElement;, I received a console error saying Uncaught TypeError: Cannot read properties of undefined (reading '#renderer').

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I thought that by the time update gets called, the renderer is already initiated. But the error seems to indicate otherwise. Am I misunderstanding the execution order? Or is there something about scope in Javascript at play here?

>Solution :

the issue seems to be with the update function you have .. you should do it like on of those two ways :

bind:

update(time) {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update.bind(this)); // Bind the context here
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}

OR – using arrow function:

update = (time) => {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update); // Context is automatically preserved
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading