Volcan 3 Volcan 3 - 1 year ago 148
jQuery Question

not able to use three.js

I found a cool animation on codepen that takes a map (img) and reconstruct it with blocks. The js files needed is

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
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:

My code:

<!DOCTYPE html>

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

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;

particles = new THREE.Points(geometry, material);



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

scene = new THREE.Scene();

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

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

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

var render = function(a) {


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;

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;

renderer.render(scene, camera);


canvas{width:100%;height:100%;padding:0;margin:0;overflow: hidden;}

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

<div style="position:relative; clear:both;"></div>
<?php include $_SERVER["DOCUMENT_ROOT"] . "/footer.php"; ?>

Answer Source

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">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
            var p = document.getElementById('example');
            console.log("In head " + p);
        <p id="example">Hello</p>
            var p = document.getElementById('example');
            console.log("In body " + p.innerHTML);


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 is the best place to put <script> tags in HTML markup?

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