Positioning the three.js container as an html div - javascript

I have an article container which has three aside tags inside it. The third aside element id='menuPuzzleType' contains a Three.js script which makes two cube meshes, and renders them in a Canvas renderer.
<article id="popup">
<aside id='close'><img src="img/close.png" onClick="aFunction()" /></aside>
<aside id='msgPuzzleType'>Please choose the puzzle type you want to play</aside>
<aside id='menuPuzzleType'>
<script>
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
cube.rotation.y -= 0.03;
cube2.rotation.y -=0.03;
renderer2.render(scene2, camera2);
}
var container2 = document.getElementById('menuPuzzleType');
//renderer
var renderer2 = new THREE.CanvasRenderer();
renderer2.setSize(400,400);//Was 100,100
container2.appendChild(renderer2.domElement);
//Scene
var scene2 = new THREE.Scene();
//Camera
var camera2 = new THREE.PerspectiveCamera(50,50/50,1,1000);
camera2.position.z = 240;//normal value is 100
camera2.position.y=60;
scene2.add(camera2);
//Axes
var axes2= new THREE.AxisHelper();
//Add texture for the cube
//Use image as texture
var img2 = new THREE.MeshBasicMaterial({ //CHANGED to MeshBasicMaterial
map:THREE.ImageUtils.loadTexture('img/2d.png')
});
img2.map.needsUpdate = true; //ADDED
//Add Cube
var cube = new THREE.Mesh(new THREE.CubeGeometry(40,40,40),img2);
cube.position.x =- 60;
scene2.add(cube);
var img3 = new THREE.MeshBasicMaterial({ //CHANGED to MeshBasicMaterial
map:THREE.ImageUtils.loadTexture('img/3d.png')
});
img3.map.needsUpdate = true; //ADDED
var cube2 = new THREE.Mesh(new THREE.CubeGeometry(40,40,40),img3);
cube2.position.x = 70; cube.position.y = 60; cube2.position.y=60;
scene2.add(cube2);
renderer2.render(scene2,camera2);
animate();
</script>
</aside>
</article>
I need to put the two cubes into the article container tag.
Here is my css code:
body{ overflow:hidden; }
article {
border:solid 1px #00CC33;
width:420px;
height:200px;
font-family: baskerville;
font-size: 16px;
margin-top: 50px;
/*For IE9 compatibility*/
behavior: url(border-radius.htc);
border-radius: 8px;
position:relative;
}
#popup {
bottom:50%;
position:relative;
margin: 0px;
left:30%;
}
#msgPuzzleType{ margin-left:60px; }
img{
behavior: url(border-radius.htc);
border-radius: 8px;
position:relative;
}
#menuPuzzleType{
background-color:#999999;
border:solid 1px #3300CC;
height:200px;
}
How can I move two cubes into the article container tag?

A "Three.js" solution to your problem is to do this:
renderer2.setSize( 400, 150 );
You also have hardwired the aspect ratio of your PerspectiveCamera, so you need to make it match the canvas dimensions.
var camera2 = new THREE.PerspectiveCamera( 50, 400/150, 1, 1000 );
This will make the canvas smaller so it fits. You then can move the camera closer so your objects are of the size you want.

Using your link provided, i changed the following to put the cubes into the article:
canvas {
position: absolute;
top: -80px;
}

Related

How do I get the Mouseover Target's X&Y for a CreateJS Shape

I am trying to change the FILL COLOR of a SHAPE on Mouseover & Mouseout. Most examples I've seen use the events StageX and StageY coordinates. However, those coordinates are the X & Y positions of the mouse at the time of the event. This forces the object to suddently move when "redrawn".
Other examples ask you to call "GetBounds"...which is not available for Shape objects.
I don't want the object to move simply because I am changing the FillColor
I see nothing resembling the top/left in the EVENT.TARGET
Q: How do I calculate or retrieve the Shapes current X/Y (top/left) coordinates?
THE HTML & JAVASCRIPT:
<style>
.dashboard { height:600px; }
.dashboard header { }
.dashboard aside { vertical-align:top; display:inline-block; }
.dashboard aside.control-bar { border: solid 1px black; border-radius: 3px; padding: 5px; height: 100%; width:10%; margin-right: 5px; }
.dashboard aside.control-bar {}
.dashboard aside.control-bar .btn { width:95%; }
.dashboard section { vertical-align:top; display:inline-block; }
.dashboard section.desktop { height:100%; min-width:80%; border:solid 1px black; border-radius: 3px; }
.dashboard section.desktop canvas { height:98%; width:99%; }
.dashboard footer { margin-top:5px; padding:5px; }
</style>
<div class="row">
<div class="col-md-12">
<main role="main" class="dashboard pb-3">
<header qwik-control="header">
<h3>Dashboard</h3>
</header>
<aside class="control-bar">
<center>
<h6>UI Controls</h6>
<a id="btnCreateNode" class="btn btn-sm btn-dark">Create Node</a>
</center>
</aside>
<section class="desktop">
<canvas id="demoCanvas"></canvas>
</section>
<footer>
<center>
<h5 style="color:#C7C9CD;">Button Controls</h5>
</center>
</footer>
</main>
</div>
</div>
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
<script type="text/javascript">
var stage = null,
loader = null;
// GLOBALS
var _PROPERTIES = { node: { y: 100, x: 200, fillColor: '#F9FAFB', fillOverColor: '#FCFCC2', strokeColor: '#000' } };
function node_create(){
console.log('node_create');
var top = Math.random() * 500;
var left = Math.random() * 500;
var width = _PROPERTIES.node.x;
var height = _PROPERTIES.node.y;
// Create
var node = new createjs.Shape();
node.graphics.beginStroke(_PROPERTIES.node.strokeColor);
node.graphics.beginFill(_PROPERTIES.node.fillColor);
node.graphics.setStrokeStyle(1);
node.snapToPixel = true;
node.graphics.drawRect(left, top, width, height);
node.graphics.endFill();
node.name = name;
node.overColor = _PROPERTIES.node.fillOverColor;
node.outColor = _PROPERTIES.node.fillColor;
// Events
node.on("mouseover", node_mouseover);
node.on("mouseout", node_mouseout);
// Display
stage.addChild(node);
stage.update();
};
function node_mouseover(evt) {
console.log('node_mouseover');
// COORDS is the events coordinates...not the targets Top/Left (e.g. cursor)
// How do I get the X/Y of the target? (getBounds does not exist for Shapes)
var target = evt.target;
var coords = { x: evt.stageX, y: evt.stageY };
target.graphics.clear();
target.graphics.beginStroke(_PROPERTIES.node.strokeColor);
target.graphics.beginFill(target.overColor);
target.graphics.drawRect(coords.x, coords.y, _PROPERTIES.node.x, _PROPERTIES.node.y);
target.graphics.endFill();
stage.update();
};
function node_mouseout(evt) {
console.log('node_mouseout');
// COORDS is the events coordinates...not the targets Top/Left (e.g. cursor)
// How do I get the X/Y of the target? (getBounds does not exist for Shapes)
var target = evt.target;
var coords = { x: evt.stageX, y: evt.stageY };
target.graphics.clear();
target.graphics.beginStroke(_PROPERTIES.node.strokeColor);
target.graphics.beginFill(target.outColor);
target.graphics.drawRect(coords.x, coords.y, _PROPERTIES.node.x, _PROPERTIES.node.y);
target.graphics.endFill();
stage.update();
};
$(document).ready(function () {
// Stage
stage = new createjs.Stage('demoCanvas');
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
// Stage - Events
stage.enableMouseOver(10);
// Queue
loader = new createjs.LoadQueue();
// DOM - EVENTS
$('#btnCreateNode').on('click', function(e){
node_create();
});
});
</script>
The solution is to put your Shapes into a Container. Shapes don't have the same properties & methods useful in determining location that other objects do: like images or bitmaps etc.
As such...Containers are the "solution" to that.
THE JAVASCRIPT:
var _PROPERTIES = { node: { y: 100, x: 200, fillColor: '#F9FAFB', fillOverColor: '#FCFCC2', strokeColor: '#000' } };
function node_create(){
console.log('node_create');
var top = Math.random() * 500;
var left = Math.random() * 500;
var width = _PROPERTIES.node.x;
var height = _PROPERTIES.node.y;
// Create
var node = new createjs.Shape();
node.graphics.beginStroke(_PROPERTIES.node.strokeColor);
node.graphics.beginFill(_PROPERTIES.node.fillColor);
node.graphics.setStrokeStyle(1);
node.snapToPixel = true;
node.graphics.drawRect(0, 0, width, height); //<-- changed
node.graphics.endFill();
node.name = name;
node.overColor = _PROPERTIES.node.fillOverColor; //<-- added
node.outColor = _PROPERTIES.node.fillColor; //<-- added
// Events
node.on("mouseover", node_mouseover);
node.on("mouseout", node_mouseout);
// Container
var container = new createjs.Container(); //<-- added
container.x = top;
container.y = left;
container.addChild(node);
// Display
stage.addChild(container); //<-- changed
stage.update();
};
function node_mouseover(evt) {
console.log('node_mouseover');
// Because of the container...you no longer need to calculate a TOP or LEFT
var target = evt.target;
target.graphics.clear();
target.graphics.beginStroke(_PROPERTIES.node.strokeColor);
target.graphics.beginFill(target.overColor);
target.graphics.drawRect(0, 0, _PROPERTIES.node.x, _PROPERTIES.node.y); //<-- changed
target.graphics.endFill();
stage.update();
};
function node_mouseout(evt) {
console.log('node_mouseout');
// Because of the container...you no longer need to calculate a TOP or LEFT
var target = evt.target;
target.graphics.clear();
target.graphics.beginStroke(_PROPERTIES.node.strokeColor);
target.graphics.beginFill(target.outColor);
target.graphics.drawRect(0, 0, _PROPERTIES.node.x, _PROPERTIES.node.y); //<-- changed
target.graphics.endFill();
stage.update();
};

Load 3D Model into Container dynamically via Dropwdown \ JS

Loading this model (example) here seems to nlt work the way I want.
I execute a JS and fill the "var" with an url
that url is in the container to render the 3d model aswell...
Sadly the container-ed script will not take the new var at all it seems.
(if the url is present in script directly it worksy but I want to swap out the model dynamically
<style>
.dropbtn {
background-color: #04AA6D;color: white;padding: 16px;font-size: 16px;border: none;
}
.dropdown {
position: relative;display: inline-block;
}
.dropdown-content {
display: none;position: absolute;background-color: #f1f1f1;min-width: 160px;box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);z-index: 1;
}
.dropdown-content a {
color: black;padding: 12px 16px;text-decoration: none;display: block;
}
.dropdown-content a:hover {background-color: #ddd;}
.dropdown:hover .dropdown-content {display: block;}
.dropdown:hover .dropbtn {background-color: #3e8e41;}
</style>
</head>
<body>
<div class="dropdown">
<button class="dropbtn">Model</button>
<div class="dropdown-content">
Model
Model2
</div>
</div>
</body>
<canvas id="scene"></canvas>
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js'></script>
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/127738/OBJLoader.js'></script>
<script>
//This demo is using the plugin "OBJLoader". Don't forget to include it into your page ;)
//You can find it here : https://github.com/mrdoob/three.js/tree/cf584a60bdfd24c42eaa81d484533364742bda44/examples/js/loaders
var renderer, scene, camera, banana;
var ww = window.innerWidth,
wh = window.innerHeight;
function init(){
renderer = new THREE.WebGLRenderer({canvas : document.getElementById('scene')});
renderer.setSize(ww,wh);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50,ww/wh, 0.1, 10000 );
camera.position.set(0,0,500);
scene.add(camera);
//Add a light in the scene
directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 0, 0, 350 );
directionalLight.lookAt(new THREE.Vector3(0,0,0));
scene.add( directionalLight );
//Load the obj file
loadOBJ();
}
var loadOBJ = function(){
//Manager from ThreeJs to track a loader and its status
var manager = new THREE.LoadingManager();
//Loader for Obj from Three.js
var loader = new THREE.OBJLoader( manager );
//Launch loading of the obj file, addBananaInScene is the callback when it's ready
loader.load( '$model', addBananaInScene);
};
var addBananaInScene = function(object){
banana = object;
//Move the banana in the scene
banana.rotation.x = Math.PI/2;
banana.position.y = -200;
banana.position.z = 50;
//Go through all children of the loaded object and search for a Mesh
object.traverse( function ( child ) {
//This allow us to check if the children is an instance of the Mesh constructor
if(child instanceof THREE.Mesh){
child.material.color = new THREE.Color(0X00FF00);
//Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
child.geometry.computeVertexNormals();
}
});
//Add the 3D object in the scene
scene.add(banana);
render();
};
var render = function () {
requestAnimationFrame(render);
//Turn the banana
banana.rotation.z += .01;
renderer.render(scene, camera);
};
init();
</script>
I tried to pass the url for the model via javascript

place a three.js sceen inside bootstrap grid

I try to understand how to embed three.js scene with few toggles inside of a bootstrap grid, for some reason my canvas which is inside column refuse to be in same row with the text column and i cant figure out why, any help will be much appreciated.
Preview: https://htmlpreview.github.io/?https://github.com/Phoreaka/PlateInGrid/blob/master/index.html
Html:
<section id="intro">
<div class="container-fluid">
<div class="row">
<div class="col-lg-4 col-md-4 textContainer ">
<p>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.</p>
</div> <!-- col end -->
<div class="col-lg-8 col-md-8">
<div id="myCanvas"></div>
<button id="polychrome"></button>
<button id="blue"></button>
<button id='PausePlay'>Pause</button>
</div> <!-- col end --->
</div> <!--row end -->
</div> <!-- container end -->
</section>
Css:
html, body {
direction: rtl;
font-family: 'Heebo', sans-serif;
-webkit-font-smoothing: antialiased;
margin: 0px;
overflow: hidden;
}
.background {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: -99;
background-color: lightgray;
background-repeat: no-repeat;
background-size: cover;
}
#intro {
width: 100wh;
height: 100%;
}
.textContainer {
height: auto;
font-size: 22px;
}
#myCanvas {
}
canvas {
height: 0;
}
#polychrome {
background-color: rgba(246, 244, 231, 1);
border-radius: 50%;
width: 20px;
height: 20px;
bottom: 20px;
border: 2px solid #194E9F;
}
#blue {
background-color: rgba(246, 244, 231, 1);
border-radius: 50%;
width: 20px;
height: 20px;
bottom: 20px;
border: 2px solid #194E9F;
}
#PausePlay {
background-color: transparent;
bottom: 20px;
border-style: none;
}
Javascript:
var container, stats, plate, plateTwo;
//loading objects into scene
var camera, scene, renderer, plate, plateTwo, controls; //loading objects into scene
canvas_width = 700,
canvas_height = 700;
//Pause button toggle-Boolean for start and restart
var initAnim = true;
var runAnim = false;
var isPlay = true;
//tweening
init();
animate();
//init functions for all the scene
function init() {
container = document.getElementById( 'myCanvas' ); //creates div and inside of it canvas
document.body.appendChild( container );
// scene
scene = new THREE.Scene();
//camera
camera = new THREE.PerspectiveCamera( 40,canvas_width / canvas_height, 100, 100000 );
camera.position.set( 0, 0, 1000 );
//lights
var ambient = new THREE.AmbientLight( 0xFFFFf3, 1.1 );
ambient.position.set( 0, 0, 900 ).normalize();
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 );
directionalLight.position.set( 0, 0, 700 ).normalize();
scene.add( directionalLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 );
directionalLight.position.set( 0, 0, -700 ).normalize();
scene.add( directionalLight );
//lights end
//setting renderer
renderer = new THREE.WebGLRenderer({
alpha: true});//background opacity
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( canvas_width, canvas_height );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
//setting render end
//orbit controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(-300,0,0);
controls.minPolarAngle = 1; // radians
controls.maxPolarAngle = Math.PI/2; // radians
controls.minDistance = 500;
controls.maxDistance = 800;
controls.enablePan = false;
//orbit controls end
// model blue
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() ); //helper for texture loading
//texture loader
var mtlLoader = new THREE.MTLLoader();
mtlLoader.crossOrigin = ''; //cross origin-allows to run it on github
mtlLoader.setPath( 'images/new/' );
mtlLoader.load( 'BluePlate.mtl', function( materials ) {
materials.preload();
//model loader
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'images/new/' );
objLoader.load( 'BluePlate.obj', addPlate);
});
//object position setings
var addPlate = function(object){
plate = object;
plate.name = 'blue_plate';
//Move the plate in the scene
plate.rotateX(0);
plate.rotateY(0);
plate.rotateZ(30);
plate.position.x = -300;
plate.position.y = 0;
plate.position.z = 0;
plate.scale.y = 1.8;
plate.scale.x = 1.8;
plate.scale.z = 1.8;
//Add the 3D object in the scene
scene.add(plate);//adds the plate
animate(plate);
render();
};
//model blue end
//model Polychrome inside of button function appears only when "#polychrome is pressed"
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() ); //helper for texture loading
//texture loader
var mtlLoaderTwo = new THREE.MTLLoader();
mtlLoaderTwo.crossOrigin = ''; //cross origin-allows to run it on github
mtlLoaderTwo.setPath( 'images/new/' );
mtlLoaderTwo.load( 'PolychromePlate.mtl', function( materials ) {
materials.preload();
//model loader
var objLoaderTwo = new THREE.OBJLoader();
objLoaderTwo.setMaterials( materials );
objLoaderTwo.setPath( 'images/new/' );
objLoaderTwo.load( 'PolychromePlate.obj', addPlateTwo);
});
//object position setings
var addPlateTwo = function(object){
plateTwo = object;
plateTwo.name = "color_plate";
//Move the plate in the scene
plateTwo.rotateX(0);
plateTwo.rotateY(0);
plateTwo.rotateZ(30);
plateTwo.position.x = -300;
plateTwo.position.y = 0;
plateTwo.position.z = 0;
plateTwo.scale.y = 1.8;
plateTwo.scale.x = 1.8;
plateTwo.scale.z = 1.8;
}
//polychrome model end
//Add the 3D object in the scene
var changeTexture = function(){
if(!(scene.getObjectByName('color_plate')))
{
scene.remove(plate);//removes the blue plate from scene
scene.add(plateTwo);
animate(plateTwo);
render();
}
};
//function for button blue to switch back to blue texture
function changeTextureBlue(){
if(!(scene.getObjectByName('blue_plate')))
{
scene.add(plate);
scene.remove(plateTwo);//removes the polychrome
}
}
//mouse click - running the functions of button click need to appear after the model load
document.getElementById('polychrome').addEventListener('click', changeTexture, false);
document.getElementById('blue').addEventListener('click', changeTextureBlue, false);
//mouse click end
//pause toggle
var startButton = document.getElementById( 'PausePlay' );
// Start Button
startButton.onclick = function StartAnimation() {
// Start and Pause
if (runAnim) {
startButton.innerHTML = 'Pause';
runAnim = false;
isPlay = true;
animate();
} else {
startButton.innerHTML = 'Play';
runAnim = true;
isPlay = false;
}
}//pause toggle end
} // init ends
//settings for window resize
function onWindowResize() {
camera.aspect = canvas_width / canvas_height;
camera.updateProjectionMatrix();
renderer.setSize( canvas_width, canvas_height );
} //window resize settings end
//animate function
function animate() {
if (!isPlay) return;
requestAnimationFrame(animate);
if ( plate !== undefined) {
plate.rotation.y += -.001;
};
if ( plateTwo !== undefined ) {
plateTwo.rotation.y += -.001;
};
render();
controls.update();
} //animate function end
//render
function render() {
renderer.render( scene, camera );
} //render end
You are not adding your renderer to the div.
you have this:
container = document.getElementById( 'myCanvas' );
document.body.appendChild( container );
// then later..
document.body.appendChild( renderer.domElement );
You code is...
getting a reference to myCanvas,
Moving myCanvas div to be the last element in the body,
Then adding the renderer canvas as the last element in the body (which will be after the myCanvas div).
What you probably want it this:
// Get a reference to the container div
container = document.getElementById( 'myCanvas' );
// Add the renderer.domElement, which is a canvas, to the container div.
container.appendChild( renderer.domElement );

Make my three.js animation as my page's background [duplicate]

I've been looking at using three.js for a fun experiment on a site. I would like to use a current experiment (for which I already have the code for) and use it as a background for my site.
Anybody know how to do this?
I saw it done here: http://janjorissen.be/
Three JS API: https://github.com/mrdoob/three.js/wiki/API-Reference
I'm going to add yet another answer. I'd use
canvas {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
Here's why:
Many people use canvas { width: 100%; height: 100% } but that arguably doesn't make a lot of sense. You don't want the canvas to be 100% of the body. You want it to 100% of the screen/window. That's what canvas { width: 100vw; height: 100vh; } does. It's 100% of the viewport width and viewport height.
This means you don't need to set the body to height: 100% which also would not make sense, especially if the page is taller than the window/screen
display: block; fixes some issues with scrollbars on certain browsers. Some pages use html, body { overflow: none; } but again that doesn't make sense if your page ends up needing to be taller than the screen/window.
position: fixed; makes the canvas position relative to the top of window so it won't scroll with the page. If you use position: absolute then the canvas will scroll off the top if the page is taller than the screen/window. For example this page.
top: 0; left 0; puts it at the top left. Without that it would default to it's default position which is inside the body's margins. Often this is solved by setting body { margin: 0; } but generally that means you end up needing some other container to add a margin back in otherwise your normal content gets positioned at the edge of the window.
z-index: -9999; is there to try to force it further back than anything else just in case the page itself is using some negative values for z-index
Here's an example as a snippet
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
var canvas = document.querySelector("canvas");
var renderer = new THREE.WebGLRenderer({canvas: canvas});
renderer.setClearColor(0xF0F0F0);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
wireframe: true,
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 1;
function resize() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (width != canvas.width || height != canvas.height) {
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001;
resize();
cube.rotation.x = time;
cube.rotation.y = time * 0.31;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
canvas {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<canvas></canvas>
<div>
some content that is in front of the canvas
</div>
And here's an example outside SO so you can view it easier full size.
iframes work as well
Note that there's the issue that if your canvas animation is interactive the elements in front of the canvas will eat the mouse/touch events. There's no easy solution I know of for that. You can mark everything but that canvas/iframe as pointer-events: none and mark the canvas/iframe as pointer-events: auto but then you run into the issue that no text on your page can be selected and no links can be clicked. You could then say set <a> tags to have pointer-events: auto so links work but I'm sure there will be issues here and there depending on what info is on your page (trying to copy an email address, or a location address, etc...)
One note: most three.js examples are structured different (less flexible) by referencing window.innerWidth and window.innerHeight and putting the canvas inside a div with an id="canvas" for some reason.
Here's a snippet using that structure. There's several more lines of code, redundant calls to renderer.setSize and setting the camera aspect in 2 places (not very D.R.Y.) but as far as this Q&A is concerned the only difference is #canvas instead of canvas as the CSS to size the div instead of the canvas.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
document.getElementById("canvas").appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xF0F0F0);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
wireframe: true,
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 1;
function onResize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
window.addEventListener('resize', onResize);
function render(time) {
time *= 0.001;
cube.rotation.x = time;
cube.rotation.y = time * 0.31;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
#canvas {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<div id="canvas"></div>
<div>
some content that is in front of the canvas
</div>
usually i use iframe for that. Thus you dont have conflict with the base page.
<style>
iframe {
z-index : -9999;
position: absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
margin : 0;
padding : 0;
}
</style>
<iframe src="http://example.com/"></iframe>
an example of it
https://github.com/jeromeetienne/www.jetienne.com/blob/master/index-webgl.html#L128 for the source
http://jetienne.com/index-webgl.html for the living code
This is not an actual background, but a 100% width/height element that is displaying the animation, with the rest of the content "elevated" using z-index or similar above that fake background.
Following the very basic example on threejs.org (here), I only had to change the canvas style section to:
canvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -9999;
}
That moved the canvas to the background.

Merging javascript code with canvas animation

I’m trying to ‘merge’ some javascript code that changes pictures with a canvas that has also animation to it, without them cancelling eachother out. In this canvas there are some clouds that move and I want to throw kittens into it.
I understand this this might be a basic HTML5 canvas question but I’m terrible using canvas though. This is the first time I’m really working with it. Whenever I try to implement the code that applies to the kittens, the canvas screen just goes white and nothing shows.
I want to stick with most of the code that I have. I really want to keep the canvas the way it is and change nothing there but add those kittens in there too. Can someone puzzle out for me how to appropiately do this?
I'm guessing I would need to tweak the animation function somehow?
function animate(){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
background.render();
foreground.render();
ctx.restore();
}
var animateInterval = setInterval(animate, 30);
}
The code is all in a FIDDLE, because it’s too much to show it on here.
EDIT: To be clear, I'm asking for the pictures of the kittens to be laid over the canvas, but I want the clouds in the canvas to overlay the kittens.
What you need to know is that the canvas element is transparent by default. So notice the minor change I made here :
body{
background:#667;
}
canvas {
width:50vw;
height:50vh;
margin-left: 20%;
}
#image {
border:#000 1px solid;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 33%;
height: 100%;
position: relative;
top:140px;
z-index: -1;
}
#my_canvas{
border:#000 1px solid;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 33%;
height: 100%;
}
<link href="css.css" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img src="" id="image"/>
<script>
var bg = new Image();
bg.src = "http://proverum.ru/templates/oblaka/img/cloud.png";
var fg = new Image();
fg.src = "http://www.tourisme-fumel.com/img_interf/meteo/cloudy.png";
function initCanvas(){
var lastTick = 0;
var position = { x:0, y:0 };
var rain = document.getElementById('rain');
var ctx = document.getElementById('my_canvas').getContext('2d');
var canvas_container = document.getElementById('my_canvas2');
var cW = ctx.canvas.width, cH = ctx.canvas.height;
function Background(){
this.x = 0, this.y = 0, this.w = bg.width, this.h = bg.height;
this.render = function(){
ctx.drawImage(bg, this.x--, 0);
if(this.x <= -250){
this.x = 0;
}
}
}
var background = new Background();
var image1 = "http://www.catsofaustralia.com/images/three_kittens.jpg";
var image2 = "http://thecatpalace.com.au/wp-content/uploads/2015/05/kitten1.jpg";
var image3 = "http://www.keepingkittens.com/images/cute-little-kitten-minka-rose-the-real-cinderella-story-21652512.jpg";
$(function() {
$("#image").prop("src", image1);
setInterval(function() {
$("#image").prop("src", image2);
setTimeout(function() {
$("#image").prop("src", image2);
setTimeout(function() {
$("#image").prop("src", image3);
}, 50);
setTimeout(function() {
$("#image").prop("src", image1);
}, 500);
}, 10);
}, 5000);
});
function Foreground(){
this.x = 0, this.y = 0, this.w = fg.width, this.h = fg.height;
this.render = function(){
ctx.drawImage(fg, this.x--, 0);
if(this.x <= -499){
this.x = 0;
}
}
}
var foreground = new Foreground();
function animate(){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
background.render();
foreground.render();
ctx.restore();
}
var animateInterval = setInterval(animate, 30);
}
window.addEventListener('load', function(event) {
initCanvas();
});
</script>
</head>
<body>
<canvas id="my_canvas" width="611" height="864"></canvas>
<h1 id="status"></h1>
</body>
</html>
I just removed the
background:#FFF;
from the canvas css and the canvas became transparent.
How you will line up the canvas over the kittens is up to you, I just quickly used position:relative and z-index to prove my point.

Categories