0

I found a cool animation on codepen that takes a map (img) and reconstruct it with blocks. The js files needed is three.min.js and TweenMax.min.js I took the links from codepen and pasted it into my head within <script src=""></script>. After copying every css and html (not much) it apears that three.min.js got an error(?). I opened google chrome console and saw three.min.js:536 Uncaught TypeError: Cannot read property 'width' of null.

heres the codepen animation im reffering to: http://codepen.io/Mamboleoo/pres/JYJPJr

My code:

<!DOCTYPE html>
<html>
<head>

    <?php include $_SERVER["DOCUMENT_ROOT"] . "/assets/head.php"; ?>
    <title><?php echo $address; ?> - Credits</title>
</head>
<body>
    <?php include $_SERVER["DOCUMENT_ROOT"] . "/navigationbar.php"; ?>

<script>
    var renderer, scene, camera, ww, wh, particles;

ww = window.innerWidth,
wh = window.innerHeight;

var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0;

var getImageData = function(image) {

    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);

    return ctx.getImageData(0, 0, image.width, image.height);
}

var drawTheMap = function() {

    var geometry = new THREE.Geometry();
    var material = new THREE.PointsMaterial({
        size: 3,
        color: 0x313742,
        sizeAttenuation: false
    });
    for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
        for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
            if (imagedata.data[(x * 4 + y * 4 * imagedata.width) + 3] > 128) {

                var vertex = new THREE.Vector3();
                vertex.x = Math.random() * 1000 - 500;
                vertex.y = Math.random() * 1000 - 500;
                vertex.z = -Math.random() * 500;

                vertex.destination = {
                    x: x - imagedata.width / 2,
                    y: -y + imagedata.height / 2,
                    z: 0
                };

                vertex.speed = Math.random() / 200 + 0.015;

                geometry.vertices.push(vertex);
            }
        }
    }
    particles = new THREE.Points(geometry, material);

    scene.add(particles);

    requestAnimationFrame(render);
};

var init = function() {
    THREE.ImageUtils.crossOrigin = '';
    renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById("map"),
        antialias: true
    });
    renderer.setSize(ww, wh);
    renderer.setClearColor(0x1d1f23);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(50, ww / wh, 0.1, 10000);
    camera.position.set(-100, 0, 220);
    camera.lookAt(centerVector);
    scene.add(camera);

    texture = THREE.ImageUtils.loadTexture("http://mamboleoo.be/lab/transparentMap.png", undefined, function() {
        imagedata = getImageData(texture.image);
        drawTheMap();
    });
  window.addEventListener('resize', onResize, false);

};
var onResize = function(){
    ww = window.innerWidth;
    wh = window.innerHeight;
    renderer.setSize(ww, wh);
    camera.aspect = ww / wh;
    camera.updateProjectionMatrix();
};

var render = function(a) {

    requestAnimationFrame(render);

    for (var i = 0, j = particles.geometry.vertices.length; i < j; i++) {
        var particle = particles.geometry.vertices[i];
        particle.x += (particle.destination.x - particle.x) * particle.speed;
        particle.y += (particle.destination.y - particle.y) * particle.speed;
        particle.z += (particle.destination.z - particle.z) * particle.speed;
    }

    if(a-previousTime>100){
        var index = Math.floor(Math.random()*particles.geometry.vertices.length);
        var particle1 = particles.geometry.vertices[index];
        var particle2 = particles.geometry.vertices[particles.geometry.vertices.length-index];
        TweenMax.to(particle, Math.random()*2+1,{x:particle2.x, y:particle2.y, ease:Power2.easeInOut});
        TweenMax.to(particle2, Math.random()*2+1,{x:particle1.x, y:particle1.y, ease:Power2.easeInOut});
        previousTime = a;
    }

    particles.geometry.verticesNeedUpdate = true;
    camera.position.x = Math.sin(a / 5000) * 100;
    camera.lookAt(centerVector);

    renderer.render(scene, camera);
};

init();
</script>

<style>
    canvas{width:100%;height:100%;padding:0;margin:0;overflow: hidden;}
</style>


<div class="wrapper">
    <canvas id="map"></canvas>
</div>




<div style="position:relative; clear:both;"></div>
        <!--</body>-->
    <?php include $_SERVER["DOCUMENT_ROOT"] . "/footer.php"; ?>
</body>
</html>
Volcan 3
  • 99
  • 1
  • 2
  • 11
  • It sounds like you're attempting to parse the (in this case, ThreeJS) code before your canvas element is loaded. This is an assumption on my part, if you provided your current code it could be a more percise and educated assumption – N.J.Dawson Sep 13 '16 at 15:19
  • @N.J.Dawson I have added my code at the bottom now. `head.php` is where i store the scripts and most my css (``) footer and navigationbar is pritty basic and only contain html. – Volcan 3 Sep 13 '16 at 15:24
  • I am also reciving this above the error in google chrome `THREE.WebGLRenderer 72` – Volcan 3 Sep 13 '16 at 15:25
  • I am not seeing any message other than THREE.WebGLRenderer 72 – Naga Sai A Sep 13 '16 at 15:27
  • are you getting uncaught error in other browsers ?? – Naga Sai A Sep 13 '16 at 15:27
  • THREE.WebGLRenderer 72 is a console log message and it is not an error – Naga Sai A Sep 13 '16 at 15:29
  • You should move `` into the bottom of the `body` tag. Your code executes before the DOM loads the canvas. Put this in a HTML file for an example of how Javascript loads vs. the DOM. http://pastebin.com/raw/S25ziTbs You will notice one fails, whilst the other one works. (it outputs to your console). You may need to move your ThreeJS related (the inline stuff) code below your canvas element too. – N.J.Dawson Sep 13 '16 at 15:30
  • @N.J.Dawson thanks alot, moving the script under the html worked :) – Volcan 3 Sep 13 '16 at 15:34

2 Answers2

2

The problem was worked out in the comments, but for the sake of not leaving a question technically unanswered I will explain the process for anyone stumbling across this page after searching for the error posted in the question.

In the example which was posted in the question (which is utilizing PHP to load the Javascript, but that matters little for the actual problem at hand) the Javascript relating to ThreeJS is being executed before the DOM has loaded the canvas element. Obviously ThreeJS requires the Canvas element, as it attaches its various listeners and objects to it, so when attempting to access members related to the canvas element it was simply getting undefined.

The fix for this was to load ThreeJS and all code related to it after the DOM had loaded the elements, there are multiple methods of doing that (which you should search for, as I'm afraid I don't have the time to explain them all), but I will highlight one which I deem the easiest. The method is to put all of your DOM specific code (Javascript that interacts with the DOM) at the bottom of your body tag (not below it, inside it at the very bottom. As Vikas Kapadiya pointed out, it would not be valid HTML if it was below it)

The below snippet shows how Javascript is loaded in relation to the DOM:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script>
            var p = document.getElementById('example');
            console.log("In head " + p);
        </script>
    </head>
    <body>
        <p id="example">Hello</p>
        <script>
            var p = document.getElementById('example');
            console.log("In body " + p.innerHTML);
        </script>
    </body>
</html>

Output:

In head null
In body Hello

As dictated by the above, the code within the head tag could not access the innerHTML (refering to the text content of the p tag) due to being executed before the DOM was loaded. The code found at the bottom of the body tag could, as the DOM was loaded and then the browser stumbled upon the Javascript.

Here are some related links which could shed more light than I have:

Where should I put <script> tags in HTML markup?

Where to place JavaScript functions: <head>? <body>? or, after </html>?

Community
  • 1
  • 1
N.J.Dawson
  • 1,220
  • 10
  • 28
0

Just move wrapper div to just after body tag . then include all js .

Like this

<body>
<div class="wrapper">
    <canvas id="map"></canvas>
</div>
  • The question was answered by @N.J.Dawson in the comment field. He have not posted it as a answer so i cant accept it. but the the answer was to move the script under the html. – Volcan 3 Sep 13 '16 at 16:17
  • you should not have anything after

    tag . it will not validate w3 standards . moving your wrapper over js tag is better option . and its fine if you dont accept this answer .

    – Vikas Kapadiya Sep 13 '16 at 16:22
  • when i said under the html that was what i ment. i have placed the ` – Volcan 3 Sep 13 '16 at 16:33