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>
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>?
Just move wrapper div to just after body tag . then include all js .
Like this
<body>
<div class="wrapper">
<canvas id="map"></canvas>
</div>
Related
I've been having this similar issue with a few of my other three.js codes as well. I set up the js within html but the objects are not showing up. There's just a black screen showing up when I run the file.
The file is supposed to show rain drops falling off the sky when it is run.
I used atom to build it. I tried html preview on atom, atom live server internet explorer chrome and they all showed the same black screen when i tried running it.
<!DOCTYPE html>
<html>
<head>
<meta charset=UTF-8 />
<link rel="stylesheet" type="text/css" href="styles.css" />
<title>RAIN ON ME BABY</title>
</head>
<body>
<script src="js/three.min.js"></script>
<script>
let scene,camera, renderer, cloudParticles = [], flash, rain, rainGeo, rainCount = 15000;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 1;
camera.rotation.x = 1.16;
camera.rotation.y = -0.12;
camera.rotation.z = 0.27;
ambient = new THREE.AmbientLight(0x555555);
scene.add(ambient);
directionalLight = new THREE.DirectionalLight(0xffeedd);
directionalLight.position.set(0,0,1);
scene.add(directionalLight);
flash = new THREE.PointLight(0x062d89, 30, 500 ,1.7);
flash.position.set(200,300,100);
scene.add(flash);
renderer = new THREE.WebGLRenderer();
scene.fog = new THREE.FogExp2(0x11111f, 0.002);
renderer.setClearColor(scene.fog.color);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
rainGeo = new THREE.Geometry();
for(let i=0;i<rainCount;i++) {
rainDrop = new THREE.Vector3(
Math.random() * 400 -200,
Math.random() * 500 - 250,
Math.random() * 400 - 200
);
rainDrop.velocity = {};
rainDrop.velocity = 0;
rainGeo.vertices.push(rainDrop);
}
rainMaterial = new THREE.PointsMaterial({
color: 0xaaaaaa,
size: 0.1,
transparent: true
});
rain = new THREE.Points(rainGeo,rainMaterial);
scene.add(rain);
let loader = new THREE.TextureLoader();
loader.load("smoke.png", function(texture){
cloudGeo = new THREE.PlaneBufferGeometry(500,500);
cloudMaterial = new THREE.MeshLambertMaterial({
map: texture,
transparent: true
});
for(let p=0; p<25; p++) {
let cloud = new THREE.Mesh(cloudGeo,cloudMaterial);
cloud.position.set(
Math.random()*800 -400,
500,
Math.random()*500 - 450
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random()*360;
cloud.material.opacity = 0.6;
cloudParticles.push(cloud);
scene.add(cloud);
}
animate();
});
}
function animate() {
cloudParticles.forEach(p => {
p.rotation.z -=0.002;
});
rainGeo.vertices.forEach(p => {
p.velocity -= 0.1 + Math.random() * 0.1;
p.y += p.velocity;
if (p.y < -200) {
p.y = 200;
p.velocity = 0;
}
});
rainGeo.verticesNeedUpdate = true;
rain.rotation.y +=0.002;
if(Math.random() > 0.93 || flash.power > 100) {
if(flash.power < 100)
flash.position.set(
Math.random()*400,
300 + Math.random() *200,
100
);
flash.power = 50 + Math.random() * 500;
}
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
</script>
</body>
</html>
Your issue is actually a duplicate of: https://stackoverflow.com/a/57114890/5250847
With R016, it's not possible to create THREE.Points with THREE.Geometry. This is already fixed in dev and eventually with the next release R107 at the end of July.
I've copied your code to the following fiddle and replaced the build file with the current dev version which fixes the issue.
https://jsfiddle.net/76tw2jL0/
BTW: The best fix is actually the usage of THREE.BufferGeometry.
EDIT:i will post all my code the html and js,and excuse me for too many comments
I am trying to create rectangles in canvas by for loop (there is input user)
and I want to access them in another function to do some stuff,
the main problem is how to access the shapes's name after loop I have tried this but when i call them in another function it gives me,
undefined "object name"
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = document.getElementById("myCanvas");
//drawing the base off the towers
var base_twr1 = c.getContext("2d");
base_twr1.beginPath();
base_twr1.moveTo(550, 500);
base_twr1.lineTo(300, 500);
base_twr1.lineWidth = 10;
base_twr1.strokeStyle = '#ff0000';
base_twr1.closePath();
base_twr1.stroke();
var base_twr2 = c.getContext("2d");
base_twr2.beginPath();
base_twr2.moveTo(900, 500);
base_twr2.lineTo(650, 500);
base_twr2.closePath();
base_twr2.stroke();
var base_twr3 = c.getContext("2d");
base_twr3.beginPath();
base_twr3.moveTo(1250, 500);
base_twr3.lineTo(1000, 500);
base_twr3.closePath();
base_twr3.stroke();
//drawing the towers
var twr1 = c.getContext("2d");
twr1.beginPath();
twr1.moveTo(430, 300);
twr1.lineTo(430, 500);
twr1.closePath();
twr1.stroke();
var twr2 = c.getContext("2d");
twr2.beginPath();
twr2.moveTo(780, 300);
twr2.lineTo(780, 500);
twr2.closePath();
twr2.stroke();
var twr3 = c.getContext("2d");
twr3.beginPath();
twr3.moveTo(1130, 300);
twr3.lineTo(1130, 500);
twr3.closePath();
twr3.stroke();
//array to know each tower what contains
//to avoid collisions
var disks_in_twrs = [];
var twr1_holder = [];
var twr2_holder = [];
var twr3_holder = [];
//start function check the user input
//and call another function if everthing
//is fine
function btn_start() {
disks_number = document.getElementById("disk_input").value;
disks_number = parseInt(disks_number);
if (disks_number > 0) {
if (disks_number < 8)
put_disks(disks_number);
} else
alert('write number');
}
var width_disks_start = 305;
var height_disks_start = 490;
var disk_width = 220;
function put_disks(disks) {
for (i = 0; i < disks; i++) {
// var r = Math.floor((Math.random() * 256));
// var g = Math.floor((Math.random() * 256));
// var b = Math.floor((Math.random() * 256));
str1 = "disk";
width_disks_start = width_disks_start + 10;
height_disks_start = height_disks_start - 20;
disk_width = disk_width - 30;
// eval("disks_in_twrs.push(str1 + i)" );
// disks_in_twrs[i]=c.getContext("2d");
// disks_in_twrs[i].rect((Math.random)*100,(Math.random)*100,150,100);
// disks_in_twrs[i].stroke();
// alert(disks_in_twrs);
twr1_holder.push(str1 + i);
// ctx.fillStyle = 'rgb(' + r + ',' + g + ', ' + b + ')';
// alert(str1 + i);
//twr1_holder[i] = c.getContext("2d");
eval("var disk"+i+"= c.getContext('2d');");
// twr1_holder[i].rect(width_disks_start, height_disks_start, disk_width, 20);
eval("disk"+i+".rect(width_disks_start, height_disks_start, disk_width, 20);");
// twr1_holder[i].strokeStyle = "black";
eval("disk"+i+".strokeStyle = 'black';");
// twr1_holder[i].stroke();
eval("disk"+i+".stroke();");
// alert(disk1.toSource());
}
}
function hide_me(){
alert("byeeeeeeeeeeeeeeeee");
twr1.fillRect(430, 500, 250, 250);
// disk2.rect(515, 51, 6, 20);
// disk2.strokeStyle = 'red';
}
<!DOCTYPE html>
<html>
<head>
<title>tower of Hanoi</title>
<style type="text/css">
canvas{
border : 1px solid black;
}
</style>
</head>
<body>
<label>how many disk do you want ?</label>
<input type="text" id="disk_input">
<button id="start" onclick="btn_start()">start</button>
<label>note that maximum disk is 8 :P</label>
<button id="make_hidden" onclick="hide_me()" >make me hide</button>
<canvas id="myCanvas" >
</canvas>
<script src="tower.js">
</script>
</body>
</html>
There's a lot going on here! I recommend attacking each issue in your code separately and building up understanding gradually, because this is an application that requires a lot of different components (DOM manipulation/event handlers, JS canvas, objects/arrays/loops, design, etc). If you're uncomfortable with any of these concepts, pick one area (such as DOM manipulation) and spend time working on simple, understandable examples, then apply what you learned to the main application.
Firstly, almost always avoid eval entirely. Mozilla says never to use it! If you're using it, it probably means your design has gone haywire somewhere along the line, which I would contend is the case here.
As for event handlers and document manipulation, I recommend avoiding onclick. Adding event listeners in your script can take care of the job; you'll likely be listening for clicks on the canvas to enable interaction later on.
Next: using canvas. You generally only need to retrieve the context once per application, not before each drawing. Your drawing code looks good other than this, except that it's not very DRY, which is usually a signal to redesign.
The hardest part is designing your code to meet your goals, which I'm not entirely clear on. Are you making an interactive Towers of Hanoi app, or one that simply animates a solver algorithm and requires no user input? Either way, I opted to use object constructors to represent Towers and Disks. Using arrays to hold these objects means you identify towers and disks by their position in an array rather than evaling a string name. Whenever you want to perform an action on your towers, such as drawing them, all you need to do is loop through the towers and call draw on each one. Later, when it comes to handling user input or writing a solver algorithm, it should be fairly easy to manipulate these arrays to suit your needs (e.g., figuring out which disk was clicked on, moving disks between towers, etc).
Keep in mind the below example is just a quick sketch to get you going and may not follow best design principles or ones that meet your needs. For example, I've hard-coded most drawing coordinate values, so it's non-responsive, so many exercises are left for the reader to improve on.
const Disk = function(width, color) {
this.width = width;
this.color = color;
};
const Tower = function(x, disks) {
this.x = x;
this.disks = [];
this.width = 20;
};
Tower.prototype.draw = function(c, ctx) {
ctx.lineWidth = this.width;
ctx.strokeStyle = "#000";
ctx.beginPath();
ctx.moveTo(this.x, 0);
ctx.lineTo(this.x, c.height);
ctx.stroke();
this.disks.forEach((e, i) => {
ctx.fillStyle = e.color;
ctx.fillRect(
this.x - e.width / 2,
c.height - (i + 1) * this.width,
e.width, this.width
);
});
};
const draw = (c, ctx, towers) => {
ctx.clearRect(0, 0, c.width, c.height);
towers.forEach(t => t.draw(c, ctx));
};
const initialize = disks => {
const towers = [
new Tower(c.width / 5),
new Tower(c.width / 2),
new Tower(c.width - c.width / 5)
];
for (let i = disks; i > 0; i--) {
towers[0].disks.push(
new Disk(i * 30, `hsl(${Math.random() * 360}, 50%, 50%`)
);
}
return towers;
};
document.getElementById("initialize-form")
.addEventListener("submit", e => {
e.preventDefault();
towers = initialize(parseInt(e.target.elements[0].value), towers);
draw(c, ctx, towers);
});
document.getElementById("btn-hide").addEventListener("click",
e => document.getElementById("menu").style.display = "none"
);
const c = document.getElementById("hanoi");
c.width = 600;
c.height = 200;
const ctx = c.getContext("2d");
let towers;
body {
margin: 0;
}
#hanoi {
padding: 0.5em;
}
#initialize-form {
display: inline-block;
}
#menu {
padding: 0.5em;
display: inline-block;
}
<div id="menu">
<form id="initialize-form">
<label>Enter disks:</label>
<input type="number" min="1" max="8" value="6">
<button type="submit">start</button>
</form>
<button id="btn-hide">hide</button>
</div>
<canvas id="hanoi"></canvas>
For what you are trying to do you should consider using a canvas library, maybe Konva:
https://konvajs.github.io/
Here is an example:
<script src="https://cdn.rawgit.com/konvajs/konva/2.1.7/konva.min.js"></script>
<div id="container"></div>
<script>
function KonvaRect(x, y, fill, draggable) {
return new Konva.Rect({
x: x, y: y, width: 50, height: 50,
fill: fill, stroke: 'black',
strokeWidth: 4, draggable: draggable
});
}
var boxes = [];
boxes.push(KonvaRect(50, 10, '#00D2FF', true));
boxes.push(KonvaRect(200, 10, '#0000FF', true));
boxes.push(KonvaRect(125, 10, '#FF0000', false));
var layer = new Konva.Layer();
boxes.forEach(function(b) { layer.add(b) });
var stage = new Konva.Stage({
container: 'container', width: 600, height: 170
});
stage.add(layer);
function moveCenter() {
boxes.forEach(function(b) { b.move({ x:0, y: Math.random() * 10 }) });
layer.batchDraw();
}
boxes[0].on('mouseover', function() {
moveCenter();
});
</script>
On this example I put 3 boxes in an array and when we detect the mouse over the light blue box all boxes move randomly down, also both blue boxes you can click and drag around the canvas.
And for the record there are many many other libraries out there...
Hy!
I'm working with three js(webgl). I was trying to embed html webpage, but somehow it don't wants to work.
Tutorials that I was checking:
http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/
http://stemkoski.github.io/Three.js/CSS3D.html
The stemkoski one was working with three js v58, also v60. But it don't realy wants to work using v68(newest version). I don't get any error message, just a black screen where the website should be.
Also I'm able to do something similiar like http://threejs.org/examples/#css3d_youtube .
My question is is there a workaround, or "hot fix" for this problem because I'm out of ideas.
Thanks for your answers.
---UPDATE---
Then let's say I'm using this code:
<!doctype html>
<html lang="en">
<head>
<title>CSS3D (Three.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/base.css"/>
</head>
<body>
<script src="js/Three58.js"></script>
<script src="js/Detector.js"></script>
<script src="js/Stats.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/THREEx.KeyboardState.js"></script>
<script src="js/THREEx.FullScreen.js"></script>
<script src="js/THREEx.WindowResize.js"></script>
<!-- new for this example -->
<script src="js/CSS3DRenderer.js"></script>
<!-- jQuery code to display an information button and box when clicked. -->
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery-ui.js"></script>
<link rel=stylesheet href="css/jquery-ui.css" />
<link rel=stylesheet href="css/info.css"/>
<script src="js/info.js"></script>
<div id="infoButton"></div>
<div id="infoBox" title="Demo Information">
This three.js demo is part of a collection at
http://stemkoski.github.io/Three.js/
</div>
<!-- ------------------------------------------------------------ -->
<div id="ThreeJS" style="position: absolute; left:0px; top:0px"></div>
<script>
/*
Three.js "tutorials by example"
Author: Lee Stemkoski
Date: July 2013 (three.js v58)
This demo is based on the work of Jerome Etienne:
http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/
*/
// MAIN
// standard global variables
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
// custom global variables
var rendererCSS;
init();
animate();
// FUNCTIONS
function init()
{
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
// RENDERER
if ( Detector.webgl )
renderer = new THREE.WebGLRenderer( {antialias:true} );
else
renderer = new THREE.CanvasRenderer();
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// EVENTS
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
// CONTROLS
controls = new THREE.OrbitControls( camera, renderer.domElement );
// STATS
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(0,250,0);
scene.add(light);
// FLOOR
var floorTexture = new THREE.ImageUtils.loadTexture( 'images/checkerboard.jpg' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
var floorMaterial = new THREE.MeshBasicMaterial( { map: floorTexture, side: THREE.DoubleSide } );
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = -0.5;
floor.rotation.x = Math.PI / 2;
scene.add(floor);
////////////
// CUSTOM //
////////////
var planeMaterial = new THREE.MeshBasicMaterial({color: 0x000000, opacity: 0.1, side: THREE.DoubleSide });
var planeWidth = 360;
var planeHeight = 120;
var planeGeometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
var planeMesh= new THREE.Mesh( planeGeometry, planeMaterial );
planeMesh.position.y += planeHeight/2;
// add it to the standard (WebGL) scene
scene.add(planeMesh);
// create a new scene to hold CSS
cssScene = new THREE.Scene();
// create the iframe to contain webpage
var element = document.createElement('iframe')
// webpage to be loaded into iframe
element.src = "index.html";
// width of iframe in pixels
var elementWidth = 1024;
// force iframe to have same relative dimensions as planeGeometry
var aspectRatio = planeHeight / planeWidth;
var elementHeight = elementWidth * aspectRatio;
element.style.width = elementWidth + "px";
element.style.height = elementHeight + "px";
// create a CSS3DObject to display element
var cssObject = new THREE.CSS3DObject( element );
// synchronize cssObject position/rotation with planeMesh position/rotation
cssObject.position = planeMesh.position;
cssObject.rotation = planeMesh.rotation;
// resize cssObject to same size as planeMesh (plus a border)
var percentBorder = 0.05;
cssObject.scale.x /= (1 + percentBorder) * (elementWidth / planeWidth);
cssObject.scale.y /= (1 + percentBorder) * (elementWidth / planeWidth);
cssScene.add(cssObject);
// create a renderer for CSS
rendererCSS = new THREE.CSS3DRenderer();
rendererCSS.setSize( window.innerWidth, window.innerHeight );
rendererCSS.domElement.style.position = 'absolute';
rendererCSS.domElement.style.top = 0;
rendererCSS.domElement.style.margin = 0;
rendererCSS.domElement.style.padding = 0;
document.body.appendChild( rendererCSS.domElement );
// when window resizes, also resize this renderer
THREEx.WindowResize(rendererCSS, camera);
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = 0;
// make sure original renderer appears on top of CSS renderer
renderer.domElement.style.zIndex = 1;
rendererCSS.domElement.appendChild( renderer.domElement );
}
function animate()
{
requestAnimationFrame( animate );
render();
update();
}
function update()
{
if ( keyboard.pressed("z") )
{
// do something
}
controls.update();
stats.update();
}
function render()
{
// remember to call both renderers!
rendererCSS.render( cssScene, camera );
renderer.render( scene, camera );
}
</script>
</body>
</html>
As I mentioned above, this is the code from http://stemkoski.github.io/Three.js/CSS3D.html, and he made his code from another tutorial: http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/ this one.
The problem is, theese are working on three js r58-r60(Let's say theese are old codes). I want to do the same thing with three js r68(the newest version). But somehow, when I launch the same code on r68 that screen goes black instead of showing a html page. This is a known bug, you can check it http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/ here:
Hi Jerome, thanks for your interest. Here are a couple of jsfiddles
copied from stemkoski's github showing the results of Three r58 and
r68. Observe that the only difference between the samples is the
library in use: Threejs 58 (working) - http://jsfiddle.net/jL48v/2/
Threejs 68 (broken) - http://jsfiddle.net/jL48v/3/
I've tried several approaches to get this technique working in r68,
but without much luck so far.
Just realized that I messed up the dependency load order. Here's a
"fixed" broken version of r68 - http://jsfiddle.net/jL48v/4/
But he/she forgot to write the solution. and the v4 not working either.
here's my HTML
<html>
<head>
<meta charset="UTF-8" />
<script src="script.js"></script>
</head>
....
and here's the javascript. everything was fine when i had the script inline, but when i move it outside of the html file it breaks. just a simple html canvas drawing but not sure the issue. ideas?
// Canvas 1
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
photo = document.getElementById("red");
function drawImage() {
context.drawImage(photo, 0, 0);
}
window.addEventListener("load", drawImage, false);
// Canvas 2
var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext("2d");
context2.fillStyle = "darkRed";
context2.fillRect(0, 2, 800, 500);
context2.moveTo(0, 0);
context2.lineTo(400, 300);
// Canvas 3
var canvas3 = document.getElementById("canvas3");
var context3 = canvas3.getContext("2d");
photo3 = document.getElementById("red2");
function drawImage() {
for (var x = 0; x < 6; x++) {
for (var y =0; y < 6; y++ ) {
context3.drawImage(photo3, x * 100, y * 75, 100, 75);
}
}
}
window.addEventListener("load", drawImage, false);
Since you're loading the script in the <head>, everything is running before the DOM is loaded, so all your getElementBuId() calls are failing. You either need to put the <script> tag at the end of the <body>, or put all the code into a window.onload function, e.g.
window.onload = function() {
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
photo = document.getElementById("red");
function drawImage() {
context.drawImage(photo, 0, 0);
}
window.addEventListener("load", drawImage, false);
...
};
This has the added benefit of not polluting the global namespace.
I'll second what Barmar said. In general, I load my JavaScript at the end of the html for better performance, and so I'm sure I won't have this issue.
I have an example, i want to create animation with easel.js Bitmap but it seems not working. In this project, i use preload.js to load image; crop card in cards picture; create Bitmap object and try to animate this bitmap by using tween.js Anyone can help me. Thank you!
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="Scripts/CanvasLib/easeljs-0.6.1.min.js"></script>
<script src="Scripts/CanvasLib/preloadjs-0.3.1.min.js"></script>
<script src="Scripts/CanvasLib/soundjs-0.4.1.min.js"></script>
<script src="Scripts/CanvasLib/tweenjs-0.4.1.min.js"></script>
</head>
<body>
<canvas id="CanvasDemo" width ="1024" height="768" style="border:1px solid #000000;"> </canvas>
<script>
var queue = new createjs.LoadQueue(),
stage = new createjs.Stage("CanvasDemo"),
text = new createjs.Text("Welcome to canvas demo!", "40px Bold Aria"),
image = {},
card = {};
stage.addChild(text);
//stage.autoClear = false;
queue.addEventListener("complete", handleComplete);
queue.loadManifest([
{ id: "myImage", src: "Images/card.png" }
]);
function handleComplete() {
image = queue.getResult("myImage");
card = new createjs.Bitmap(image);
card.sourceRect = new createjs.Rectangle(56, 74, 56, 74);
stage.addChild(card);
createjs.Tween.get(card).to({ x: 600, y: 1000 }, createjs.Ease.linear);
createjs.Ticker.addListener(this);
}
function tick() {
text.x += 5;
if (text.x >= 1024) {
text.x = 0;
}
text.y = 50 + Math.cos(text.x * 0.1) * 10;
text.color = createjs.Graphics.getHSL(360 * Math.random(), 50, 50);
stage.update();
}
</script>
</body>
</html>
This works just fine - except you skipped the "duration" parameter on the Tween.to call (and instead specified the ease, which is the 3rd parameter). This makes it a 0-duration tween, which ends up off-stage (so you never see it).
Try this instead:
createjs.Tween.get(card).to({ x: 600, y: 1000 }, 1000, createjs.Ease.linear);