I am learning to use the library "Three.js". I am using texture and sprite with canvas to create labels that show information depending on the object that I have selected with the mouse.
The problem is that I don´t get show all the content on the browser screen.
You can see the problem here:
The code is here:
<html lang="en">
<head>
<title>Prueba</title>
<!-- Eliminación de la mal interpretación de signos. -->
<meta charset="utf-8">
<!-- Adaptación a la pantalla de los dispositivos móviles.-->
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<!-- Librería principal de "Three.js". -->
<script src="js/Three.js"></script>
<!-- Librería para la creación de un elemento detector. -->
<script src="js/Detector.js"></script>
<!-- Lbrería para el control de la cámara. -->
<script src="js/OrbitControls.js"></script>
<!-- Librería para el "render" ocupe toda la ventana del navegador. -->
<script src="js/THREEx.FullScreen.js"></script>
<!-- Librería para rediemnsionalizar los cambios de tamaño de la ventana del navegador. -->
<script src="js/THREEx.WindowResize.js"></script>
<!-- jQuery para proporcionar información de los objetos que hay en la escena cuando el ratón está sobre ellos. -->
<script src="js/jquery-1.9.1.js"></script>
</head>
<body>
<div id="ThreeJS" style="position: absolute; left:0px; top:0px">
</div>
<script>
// Declaración global delas variables estándar.
var container, scene, camera, renderer, controls, stats;
// Declaración global de las variables que se customizarán.
var projector, mouse = { x: 0, y: 0 }, INTERSECTED;
var sprite1;
var canvas1, context1, texture1;
// Llamada inicial de las funciones "init()" y "animate()".
init();
animate();
// Funciones:
function init() {
// Creación de la escena.
scene = new THREE.Scene();
// Creación de la cámara.
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);
// Posicionamiento de la cámara.
camera.position.set(0,150,400);
camera.lookAt(scene.position);
// Creación del renderer (detección del navegador usado).
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 );
// Eventos de ajuste del renderer a la ventana del navegador.
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
// Control de la cámara con el ratón.
controls = new THREE.OrbitControls( camera, renderer.domElement );
// Definir las esferas (vértices o nodos).
var sphere = [];
var nummero_nodos = 48;
for (i=1;i<=nummero_nodos;i++) {
// SphereGeometry(radio esfera, ancho segemento, altura segmento)
var sphereGeometry = new THREE.SphereGeometry(8, 20, 20);
// Decidimos como se verá el plano.
var sphereMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff}); // color azul
// Creamos un objeto tipo esfera.
sphere[i] = new THREE.Mesh(sphereGeometry, sphereMaterial);
// Posicionamos la esfera en la escena.
if(i%2!=0) {
// Si la esfera es impar.
sphere[i].position.x = -50;
sphere[i].position.y = 200-50*i;
sphere[i].position.z = 0;
}else{
// Si la esfera tiene i par.
sphere[i].position.x = 50;
sphere[i].position.y = 150-50*i;
sphere[i].position.z = 0;
}
// Añadir una etiqueta a las esferas.
sphere[i].name="ESFERA "+i.toString()+", texto de relleno para mostrar el error o el fallo.";
// Añadimos la esfera a la escena.
scene.add(sphere[i]);
}
// Conocer la posición X de las esferas.
/* for(i=1;i<=nummero_nodos;i++) {
console.log(sphere[i].position.x);
} */
// Definir los tubos (relaciones).
var tube =[]
var j=1;
for(i=1;i<=nummero_nodos;i++) {
// Los vértices impares generan relaciones.
if(i%2==1) {
// Relación nodo impar-impar.
if(sphere[i-1]!=undefined && sphere[i-1]!="") {
// Definir la línea (usamos un tubo).
// Creamos el cammino que va a seguir el tubo (es decir la línea).
// Indicamos los vértices que formarán la línea.
var start = new THREE.Vector3(sphere[i].position.x,sphere[i].position.y, sphere[i].position.z);
var end = new THREE.Vector3(sphere[i-1].position.x,sphere[i-1].position.y, sphere[i-1].position.z);
// Creamos la línea.
var line = new THREE.LineCurve( start, end )
// Indicamos el número de puntos que compondrán el tubo.
var numPoints = 100;
// Decidimos como se verá el tubo.
var tubeGeometry = new THREE.TubeGeometry( line, numPoints, 2, 8, false );
var tubeMaterial = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
tube[j] = new THREE.Mesh( tubeGeometry, tubeMaterial );
tube[j].name="TUBO "+j.toString();
scene.add( tube[j] );
j+=1;
}
// Relación nodos impar-impar.
if(sphere[i+2]!=undefined && sphere[i+2]!="") {
// Definir la línea (usamos un tubo).
// Creamos el cammino que va a seguir el tubo (es decir la línea).
// Indicamos los vértices que formarán la línea.
var start = new THREE.Vector3(sphere[i].position.x, sphere[i].position.y, sphere[i].position.z);
var end = new THREE.Vector3(sphere[i+2].position.x, sphere[i+2].position.y, sphere[i+2].position.z);
// Creamos la línea.
var line = new THREE.LineCurve( start, end )
// Indicamos el número de puntos que compondrán el tubo.
var numPoints = 100;
// Decidimos como se verá el tubo.
var tubeGeometry = new THREE.TubeGeometry( line, numPoints, 2, 8, false );
var tubeMaterial = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
tube[j] = new THREE.Mesh( tubeGeometry, tubeMaterial );
tube[j].name="TUBO "+j.toString();
scene.add( tube[j] );
j+=1;
}
}
};
// Inicializar un objeto para realizar cálculos de la relación "pantalla / mundo".
projector = new THREE.Projector();
// Cuando el ratón se mueve llamamos a la función onDocumentMouseMove().
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
/////// Dibujar el texto en un elemento canvas: /////////
// Creamos el elemento tipo canvas.
canvas1 = document.createElement('canvas');
context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);
// El contenido del elemento canvas será utilizado por un elemento del tipo textura.
texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;
// Creamos un elemento tipo sprite donde pondremos nuestro elemento tipo textura que contiene el texto.
var spriteMaterial = new THREE.SpriteMaterial( { map: texture1, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft } );
sprite1 = new THREE.Sprite( spriteMaterial );
sprite1.scale.set(200,100,1.0);
sprite1.position.set( 50, 50, 0 );
// Añadir el sprite a la escena.
scene.add( sprite1 );
}
function onDocumentMouseMove( event ) {
// Corregimos la posición del sprite al mover el ratón.
sprite1.position.set( event.clientX, event.clientY - 20, 0 );
// Modificamos los valores de la variable mouse.
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
}
function animate() {
requestAnimationFrame( animate );
// Rellamada de las funciones.
render();
update();
}
function update() {
// Creación de una línea (ray) con origen en la posición del ratón y con dirección hacia la escena (dirección de la cámara).
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// Creamos una matriz que contenga todos los objetos en la escena con la que la línea se cruza en su trayectoria.
var intersects = ray.intersectObjects( scene.children );
// INTERSECTED : es el objeto en la escena actualmente más cercano a la cámara e intersectado por el rayo (línea) proyectado desde la posición del ratón.
// Si hay una (o más) intersecciones.
if(intersects.length > 0) {
// Si el objeto más cercano intersectado no es el objeto de intersección actualmente almacenado.
if(intersects[ 0 ].object != INTERSECTED) {
// Restaurar el objeto de intersección anterior (si existe) a su color original.
if(INTERSECTED) {
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
}
// Almacena la referencia al objeto más cercano como objeto de intersección actual.
INTERSECTED = intersects[ 0 ].object;
// Almacena el color del objeto más cercano (para una restauración posterior).
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
// Establece un nuevo color para el objeto más cercano.
INTERSECTED.material.color.setHex( 0xffff00 );
// Actualiza el texto, si tiene un campo "name" el objeto.
if(intersects[ 0 ].object.name) {
context1.clearRect(0,0,640,480);
var message = intersects[ 0 ].object.name;
var metrics = context1.measureText(message);
var width = metrics.width;
context1.fillStyle = "rgba(0,0,0,0.95)"; // color del borde (negro)
context1.fillRect( 0,0, width+8,20+8);
context1.fillStyle = "rgba(255,255,255,0.95)"; // color del fondo (blanco)
context1.fillRect( 2,2, width+4,20+4 );
context1.fillStyle = "rgba(0,0,0,1)"; // color del texto (negro)
context1.fillText( message, 4,20 );
texture1.needsUpdate = true;
}else{
// No existe texto ni itiqueta.
context1.clearRect(0,0,300,300);
texture1.needsUpdate = true;
}
}
// Si no hay intersección.
}else{
// Restaura el objeto de intersección anterior (si existe) a su color original.
if(INTERSECTED) {
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
}
// Elimina la referencia de objeto de intersección anterior estableciendo el objeto de intersección actual en "nada".
INTERSECTED = null;
context1.clearRect(0,0,300,300);
texture1.needsUpdate = true;
}
// Modificación de la cámara al mover el ratón.
controls.update();
}
// Renderización de la escena.
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
I have tried solving the problem by modifying the size of the canvas with "fillRect()" but it doesn't show all the rectangle.
I have also modified the scale of the sprite but this only distorts the letters.
Finally, I have tried to put the information in different lines but in the end the same thing happens, only in vertical.
Anybody knows how to resolve the problem? Any idea?
Thanks in advance!