我在codepen上发现了一个很酷的动画,它采用了一个地图(img)并用块重建它。所需的js文件是three.min.js
和TweenMax.min.js
我从codepen中获取了链接并将其粘贴到<script src=""></script>
内的头部。在复制每个css和html(不多)后,它会发现three.min.js
出错(?)。
我打开谷歌Chrome控制台并看到了three.min.js:536 Uncaught TypeError: Cannot read property 'width' of null
。
继承人的代码动画影响: http://codepen.io/Mamboleoo/pres/JYJPJr
我的代码:
<!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>
答案 0 :(得分:1)
这个问题在评论中得到了解决,但是为了不留下技术上没有答案的问题,我会在搜索问题中发布的错误后解释在这个页面上遇到障碍的人的过程。
在问题中发布的示例(利用PHP加载Javascript,但对于手头的实际问题很少),在DOM加载{{1}之前,正在执行与ThreeJS相关的Javascript。元素。显然ThreeJS需要Canvas元素,因为它将各种侦听器和对象附加到它,因此当试图访问与canvas
元素相关的成员时,它只是获得canvas
。
对此的修复是加载ThreeJS以及与相关的所有代码在DOM加载元素之后,有多种方法(你应该搜索,因为我&#39)我担心我没有时间解释所有这些,但我会强调一个我认为最容易的。该方法是将您的所有DOM特定代码(与DOM交互的Javascript)放在undefined
代码的底部(不在其下方,内部)它位于最底层。As Vikas Kapadiya pointed out,如果它低于它,它将不是有效的HTML)
以下代码段显示了如何相对于DOM加载Javascript:
body
&#13;
输出:
<!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>
根据上述规定,In head null
In body Hello
代码中的代码由于被执行而无法访问head
(请参阅innerHTML
代码的文字内容)之前加载了DOM。在p
标记的底部找到的代码可以,因为DOM已加载,然后浏览器偶然发现了Javascript。
以下是一些相关的链接,可能比我有更多的亮点:
Where should I put <script> tags in HTML markup?
Where to place JavaScript functions: <head>? <body>? or, after </html>?
答案 1 :(得分:0)
只需将包装 div移到 body 标记之后。然后包括所有的js。
喜欢这个
<body>
<div class="wrapper">
<canvas id="map"></canvas>
</div>