Three.js example not displaying on canvas - javascript

i found an example of three.js and I am trying to implement it on a <canvas></canvas> element.
I get a reference to the element but I dont get a visual. I have my canvas element with the Id of "mycanvas".
<canvas id="mycanvas" style="border: 5px solid white" width="600" height="500"></canvas>
an I use an onload function in the body called WebGLStart() which calls the script below.
<script>
function WebGLStart()
{
//Get the canvas and the context
var canvas = document.getElementById('mycanvas');
var canvas_context = canvas.getContext("webgl");
console.log("Canvas: "+canvas.width);
console.log("Canvas: "+canvas.height);
var RENDER_DIST = 1000,
FOV = 75;
var WIDTH = canvas.width,
HEIGHT= canvas.height;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, 0.1, RENDER_DIST);
camera.position.z = 100;
scene.add(camera);
renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH,HEIGHT);
console.log("R info: "+renderer.info);
canvas.appendChild(renderer.domElement);
init();
loopRun();
function init()
{
var geometry = new THREE.SphereGeometry(50);
var material = new THREE.MeshBasicMaterial({color: 0xff0000});
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
}
function loopRun()
{
requestAnimationFrame(loopRun);
renderer.render(scene, camera);
}
}
</script>
Is there any reason why this would not display?
I get outputs on chromes prompt(canvas width and height) but no display. any ideas would be appreciated

Child elements of the canvas element are not visible.
To solve this attach the renderer DOM element to some other DOM element, e.g. document body.
if you change this line:
canvas.appendChild(renderer.domElement);
to this:
document.body.appendChild(renderer.domElement);
You'll get the desired result.

Tade0 was right in the above answer! This is for people who like me had a <canvas></canvas> tags and now have to remove it.
The way I did it was first:
Implement a style tag and call your class something unique:
<style>
canvas_for_three {
width: 600px;
height: 500px;
border: 1px solid white;
position: absolute;
left: 0px;
top: 0px;
z-index: -1;
}
</style>
Next remove your <canvas></canvas> tags and replace them with:
<div id="ctx" class="canvas_for_three">
</div>
From here then on in your onload function use the
var canvas = document.getElementById('ctx');
So when your attaching the render to a DOM element it is now:
canvas.appendChild(renderer.domElement);
Where canvas is your newly created canvas.
This will replace the canvas tags.
Now you should have replaced your canvas tags with divs and the image viewport should be in the same position as where you had your <canvas></canvas> tags

Related

How do I embed an image on a canvas (HTML/JS)

I am trying to embed an image into a canvas so that I can draw lines over the image with the canvas. However, I can't seem to get the image to appear inside the canvas. Here's the code I have (HTML then JS):
<canvas id="myCanvas" style="border:1px solid #d3d3d3; position: relative; z-index:3; top:10em; width: 30em; height: 20em; left: 22em;"></canvas>
<img src="mapfinal.png" id="mapPic" style="display: none;"/>
javascript
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var map = document.getElementById("mapPic");
ctx.drawImage(map, 20, 20);
Thank you so much for any help!
It could be one of two things. The most likely issue is that the image is not yet loaded before you try to draw it. To fix this, add an onload event listener to the img element to draw it once the image has loaded.
<img src="mapfinal.png" id="mapPic" onload="drawCanvas" style="display: none;"/>
<script>
function drawCanvas() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var map = document.getElementById("mapPic");
ctx.drawImage(map, 20, 20);
}
</script>
The other issue might be that since the img element is set to display: none the browser isn't loading the image at all. Depending on the browser it may or may not load it. If you don't want the image to dispaly a better approach would be to create it through JavaScript.
var map = new Image();
map.onload = function() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.drawImage(map, 20, 20);
};
map.src = 'mapfinal.png';

Can't get HTML/Javascript Canvas to work [duplicate]

How to fill the whole HTML5 <canvas> with one color.
I saw some solutions such as this to change the background color using CSS but this is not a good solution since the canvas remains transparent, the only thing that changes is the color of the space it occupies.
Another one is by creating something with the color inside the canvas, for example, a rectangle(see here) but it still does not fill the whole canvas with the color (in case the canvas is bigger than the shape we created).
Is there a solution to fill the whole canvas with a specific color?
Yes, fill in a Rectangle with a solid color across the canvas, use the height and width of the canvas itself:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
canvas{ border: 1px solid black; }
<canvas width=300 height=150 id="canvas">
If you want to do the background explicitly, you must be certain that you draw behind the current elements on the canvas.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Add behind elements.
ctx.globalCompositeOperation = 'destination-over'
// Now draw!
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
You can change the background of the canvas by doing this:
<head>
<style>
canvas {
background-color: blue;
}
</style>
</head>
let canvas = document.getElementById('canvas');
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
let ctx = canvas.getContext('2d');
//Draw Canvas Fill mode
ctx.fillStyle = 'blue';
ctx.fillRect(0,0,canvas.width, canvas.height);
* { margin: 0; padding: 0; box-sizing: border-box; }
body { overflow: hidden; }
<canvas id='canvas'></canvas>
We don't need to access the canvas context.
Implementing hednek in pure JS you would get canvas.setAttribute('style', 'background-color:#00F8'). But my preferred method requires converting the kabab-case to camelCase.
canvas.style.backgroundColor = '#00F8'
You know what, there is an entire library for canvas graphics. It is called p5.js
You can add it with just a single line in your head element and an additional sketch.js file.
Do this to your html and body tags first:
<html style="margin:0 ; padding:0">
<body style="margin:0 ; padding:0">
Add this to your head:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
<script type="text/javascript" src="sketch.js"></script>
The sketch.js file
function setup() {
createCanvas(windowWidth, windowHeight);
background(r, g, b);
}

How to center the three js canvas?

I have this really weird (possibly intended?) bug with my three js canvas.
I want to have it not fill the complete page and center the canvas inside a div.
As you can see in the code below, the canvas is inside the div. I even added some test headings to make sure I'm not going crazy here, but the canvas seems to move itself outside the div and I have no idea how to fix this.
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body { margin: 0; }
#test {
width: 100px;
height:100px;
margin: 0px auto;
border: 1px solid red;
}
</style>
<style type="text/css" src="css/main.css"></style>
</head>
<body>
<div id="test">
<h1>test1</h1>
<canvas id="canvasID"></canvas>
<h2>test2</h2>
</div>
<script src="https://github.com/mrdoob/three.js/blob/master/examples/js/Detector.js"></script>
<script src="three.js-master/build/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var canvas = document.getElementById("canvasID");
var renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.setSize( window.innerWidth*0.9, window.innerHeight*0.9 );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
function render() {
requestAnimationFrame( render );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
render();
if (Detector.webgl) {
init();
animate();
} else {
var warning = Detector.getWebGLErrorMessage();
document.getElementById('container').appendChild(warning);
}
</script>
</body>
As you can see, the canvas has "magically" moved outside of its parent div
In your code you have this line document.body.appendChild( renderer.domElement ); which appends the canvas to the end of the <body> tag. So you are adding the canvas outside of your required div.
You can add your canvas inside that div with a simple javascript selector like:
document.getElementById('test').appendChild( renderer.domElement );
or
document.querySelector('#test').appendChild( renderer.domElement );
That way you are adding the renderer inside the div with the id="test". Let me know if it worked.

set width and height of canvas in fabric.js

I have an image background in my HTML5 canvas.
var canvas = new fabric.Canvas('#canvas1');
canvas.setBackgroundImage(
'http://fabricjs.com/assets/jail_cell_bars.png',
canvas.renderAll.bind(canvas)
);
How to set dimensions of my canvas (width, height) to the dimensions of the background image?
Thanks.
I think the above answer does not use fabric.js, it uses normal canvas.
When you use fabric.js and its Fabric.Canvas class, the code should be:
image.onLoad = function() {
var fabric_canvas = new fabric.Canvas('canvas1');
fabric_canvas.setDimensions({width:image.width, height:image.height});
};
In my case,
var canvas = new fabric.Canvas("test_fabric");
canvas.setDimensions({width:800, height:200});
The result is:
<canvas id="test_fabric" width="800" height="200" class="lower-canvas" style="position: absolute; width: 800px; height: 200px; left: 0px; top: 0px; -webkit-user-select: none;"></canvas>
Both canvas.width and canvas.style.width are set.
These work as well!
canvas.setWidth(500);
canvas.setHeight(400);
You can use CSS or dom properties to set the dimensions of your canvas. If you know the dimensions of your image, you can do it in a stylesheet:
#canvas1 { width: XXXpx; height: YYYpx; }
Or in the dom:
<canvas id="canvas1" width="XXX" height="YYY"></canvas>
If the image is dynamic and want to set the dimensions in JS, you do something like this:
var image = new Image()
image.src = 'http://fabricjs.com/assets/jail_cell_bars.png';
image.onLoad = function () {
var canvas = document.getElementById('canvas1');
canvas.width = image.width;
canvas.height = image.height;
};

Three.js as background of website possible?

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.

Categories

Resources