Yone
Yone

Reputation: 2134

Threejs, div innerWidth and innerHeight changes by its own after setting it with plane's width and height?

Hello I have one doubt.

I am trying to set the innerWidth and innerHeight of the div, the container whichs has inside the canvas, with the following code, the important code is the inner loader.load function, which get executed when we have the plane finished loading in the page.

// this class handles the load and the canva for a nrrd
// Using programming based on prototype: https://javascript.info/class
// This class should be improved:
//   - Canvas Width and height

InitCanvas = function (IdDiv, Filename) {


    this.IdDiv = IdDiv;
    this.Filename = Filename
}

InitCanvas.prototype = {

    constructor: InitCanvas,

    init: function () {

        this.container = document.getElementById(this.IdDiv);

        // this should be changed.
        debugger;
        this.container.innerHeight = 600;
        this.container.innerWidth = 800;

        //These statenments should be changed to improve the image position
        this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
        this.camera.position.z = 300;

        let scene = new THREE.Scene();
        scene.add(this.camera);

        // light

        let dirLight = new THREE.DirectionalLight(0xffffff);
        dirLight.position.set(200, 200, 1000).normalize();

        this.camera.add(dirLight);
        this.camera.add(dirLight.target);


        // read file

        let loader = new THREE.NRRDLoader();
        loader.load(this.Filename, function (volume) {

            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));

            debugger;
            this.container.innerWidth = sliceZ.iLength;
            this.container.innerHeight = sliceZ.jLength;

            sliceZ.mesh.material.color.setRGB(0,1,1);


            console.log('Our slice is: ', sliceZ);

            scene.add(sliceZ.mesh);
        this.scene = scene;

        // renderer

        this.renderer = new THREE.WebGLRenderer({alpha: true});
        this.renderer.setPixelRatio(this.container.devicePixelRatio);
        debugger;
        this.container.appendChild(this.renderer.domElement);
        }.bind(this));





    },

    animate: function () {

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

}

As you see I am binding this in the loader.load asynchronous call, because we would like to access this.container into it, which is a property in the class InitCanvas.

Then we are getting the width and height of the plane which has just finished loading, with the sentences:

 this.container.innerWidth = sliceZ.iLength;
 this.container.innerHeight = sliceZ.jLength;

And I have seen using the web debugger that it does load the plane's width and height into the container, into the div:

enter image description here

We see that the this.container.innerWidth is being changed with 3128 and this.container.innerHeight is being changed with 1760.

However, then we see that after plane's rendering the container div is 300x150:

enter image description here

How is this possible?

In addition, why our web console reports us:

Uncaught TypeError: Cannot read property 'render' of undefined
    at InitCanvas.animate (InitCanvas.js:79)
    at animate (logic.js:63)

I think, it is because we do have access to this.renderer into loader.load function because of we have a bind(this), however in the animate() function, the InitCanvas' class scope has been lost.

How could we fix it?

Thank you for your help!

Additional code which would be relevant:

logic.js

if (!Detector.webgl) Detector.addGetWebGLMessage();

// global variables for this scripts
let OriginalImg,
    SegmentImg;

var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var mousePressed = false;
var clickCount = 0;


init();
animate();


// initilize the page
function init() {
    let filename = "models/nrrd/columna01.nrrd"; // change your nrrd file
    let idDiv = 'original';
    OriginalImg = new InitCanvas(idDiv, filename);
    OriginalImg.init();
    console.log(OriginalImg);

    filename = "models/nrrd/columnasegmentado01.nrrd"; // change your nrrd file
    idDiv = 'segment';
    SegmentImg = new InitCanvas(idDiv, filename);
    SegmentImg.init();
}

let originalCanvas = document.getElementById('original');
originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
originalCanvas.addEventListener('mouseup', onDocumentMouseUp, false);


function onDocumentMouseDown(event) {
    mousePressed = true;

    clickCount++;

    mouse.x = ( ( event.clientX - OriginalImg.renderer.domElement.offsetLeft ) / OriginalImg.renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( ( event.clientY - OriginalImg.renderer.domElement.offsetTop ) / OriginalImg.renderer.domElement.clientHeight ) * 2 + 1

    console.log('Mouse x position is: ', mouse.x, 'the click number was: ', clickCount);
    console.log('Mouse Y position is: ', mouse.y);

    raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
    var objects = raycaster.intersectObjects(OriginalImg.scene.children);

    console.log(objects);
}

function onDocumentMouseUp(event) {
    mousePressed = false
}


function animate() {


    requestAnimationFrame(animate);
    OriginalImg.animate();
    SegmentImg.animate();


}   

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Prototype: three.js without react.js</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link rel="stylesheet" href="css/styles.css">

        <!-- load the libraries and js -->
        <script src="js/libs/three.js"></script>

        <script src="js/Volume.js"></script>
        <script src="js/VolumeSlice.js"></script>
        <script src="js/loaders/NRRDLoader.js"></script>

        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src="js/libs/gunzip.min.js"></script>
        <script src="js/libs/dat.gui.min.js"></script>

        <script src="js/InitCanvas.js"></script>


    </head>

    <body>
        <div id="info">
            <h1>Prototype: three.js without react.js</h1> 
        </div>

        <!-- two canvas -->
        <div class="row">
            <div class="column" id="original">
            </div>

            <div class="column" id="segment">

            </div>
          </div> 

        <script src="js/logic.js"></script>

    </body>
</html>

styles.css

body {
    font-family: Monospace;
    margin: 0px;
    overflow: hidden;
}

#info {
    color: rgb(137, 145, 192);
    position: absolute;
    top: 10px;
    width: 100%;
    text-align: center;
    z-index: 5;
    display:block;
}

.column {
    float: left;
    width: 50%;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

canvas {
    width: 200px;
    height: 200px;
    margin: 100px;
    padding: 0px;
    position: static; /* fixed or static */
    top: 100px;
    left: 100px;
}

EDIT: I have done what @Mugen87 tell us and it makes the canvas have the loaded model's width and height. However I did not expect that the model was offset from top left canvas part. It is being displayer on bottom right corner, and as there is no scrollbar it hiders most of it.

enter image description here

enter image description here

How could we add a scrollbar to the page to be able to see the canvas well?

Also here I post the code which resizes the canvas as @Mugen87 suggested:

 let loader = new THREE.NRRDLoader();
        loader.load(this.Filename, function (volume) {

            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));

            debugger;
            this.container.innerWidth = sliceZ.iLength;
            this.container.innerHeight = sliceZ.jLength;
            this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);

            sliceZ.mesh.material.color.setRGB(0,1,1);


            console.log('Our slice is: ', sliceZ);

            scene.add(sliceZ.mesh);
        }.bind(this));

Upvotes: 0

Views: 153

Answers (1)

Mugen87
Mugen87

Reputation: 31026

Just resizing the container won't resize the renderer. You have to call renderer.setSize( width, height ); otherwise the size of the respective canvas stays the same.

Besides, devicePixelRatio is a window property. this.container.devicePixelRatio returns undefined.

Upvotes: 1

Related Questions