| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 | <!-- Licensed under a BSD license. See license.html for license --><!DOCTYPE html><html>  <head>    <meta charset="utf-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">    <title>Three.js - Align HTML Elements w/hiding</title>    <style>    html, body {        margin: 0;        height: 100%;    }    #c {        width: 100%;  /* let our container decide our size */        height: 100%;        display: block;    }    #container {      position: relative;  /* makes this the origin of its children */      width: 100%;      height: 100%;      overflow: hidden;    }    #labels {      position: absolute;  /* let us position ourself inside the container */      left: 0;             /* make our position the top left of the container */      top: 0;      color: white;    }    #labels>div {      position: absolute;  /* let us position them inside the container */      left: 0;             /* make their default position the top left of the container */      top: 0;      cursor: pointer;     /* change the cursor to a hand when over us */      font-size: large;      user-select: none;   /* don't let the text get selected */      text-shadow:         /* create a black outline */        -1px -1px 0 #000,         0   -1px 0 #000,         1px -1px 0 #000,         1px  0   0 #000,         1px  1px 0 #000,         0    1px 0 #000,        -1px  1px 0 #000,        -1px  0   0 #000;    }    #labels>div:hover {      color: red;    }    </style>  </head>  <body>    <div id="container">      <canvas id="c"></canvas>      <div id="labels"></div>    </div>  </body><script type="importmap">{  "imports": {    "three": "../../build/three.module.js",    "three/addons/": "../../examples/jsm/"  }}</script><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';function main() {	const canvas = document.querySelector( '#c' );	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );	const fov = 75;	const aspect = 2; // the canvas default	const near = 1.1;	const far = 20;	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );	camera.position.z = 7;	const controls = new OrbitControls( camera, canvas );	controls.target.set( 0, 0, 0 );	controls.update();	const scene = new THREE.Scene();	{		const color = 0xFFFFFF;		const intensity = 3;		const light = new THREE.DirectionalLight( color, intensity );		light.position.set( - 1, 2, 4 );		scene.add( light );	}	const boxWidth = 1;	const boxHeight = 1;	const boxDepth = 1;	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );	const labelContainerElem = document.querySelector( '#labels' );	function makeInstance( geometry, color, x, name ) {		const material = new THREE.MeshPhongMaterial( { color } );		const cube = new THREE.Mesh( geometry, material );		scene.add( cube );		cube.position.x = x;		const elem = document.createElement( 'div' );		elem.textContent = name;		labelContainerElem.appendChild( elem );		return { cube, elem };	}	const cubes = [		makeInstance( geometry, 0x44aa88, 0, 'Aqua' ),		makeInstance( geometry, 0x8844aa, - 2, 'Purple' ),		makeInstance( geometry, 0xaa8844, 2, 'Gold' ),	];	function resizeRendererToDisplaySize( renderer ) {		const canvas = renderer.domElement;		const width = canvas.clientWidth;		const height = canvas.clientHeight;		const needResize = canvas.width !== width || canvas.height !== height;		if ( needResize ) {			renderer.setSize( width, height, false );		}		return needResize;	}	const tempV = new THREE.Vector3();	const raycaster = new THREE.Raycaster();	function render( time ) {		time *= 0.001;		if ( resizeRendererToDisplaySize( renderer ) ) {			const canvas = renderer.domElement;			camera.aspect = canvas.clientWidth / canvas.clientHeight;			camera.updateProjectionMatrix();		}		cubes.forEach( ( cubeInfo, ndx ) => {			const { cube, elem } = cubeInfo;			const speed = 1 + ndx * .1;			const rot = time * speed;			cube.rotation.x = rot;			cube.rotation.y = rot;			// get the position of the center of the cube			cube.updateWorldMatrix( true, false );			cube.getWorldPosition( tempV );			// get the normalized screen coordinate of that position			// x and y will be in the -1 to +1 range with x = -1 being			// on the left and y = -1 being on the bottom			tempV.project( camera );			// ask the raycaster for all the objects that intersect			// from the eye toward this object's position			raycaster.setFromCamera( tempV, camera );			const intersectedObjects = raycaster.intersectObjects( scene.children );			// We're visible if the first intersection is this object.			const show = intersectedObjects.length && cube === intersectedObjects[ 0 ].object;			if ( ! show || Math.abs( tempV.z ) > 1 ) {				// hide the label				elem.style.display = 'none';			} else {				// unhide the label				elem.style.display = '';				// convert the normalized position to CSS coordinates				const x = ( tempV.x * .5 + .5 ) * canvas.clientWidth;				const y = ( tempV.y * - .5 + .5 ) * canvas.clientHeight;				// move the elem to that position				elem.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;			}		} );		renderer.render( scene, camera );		requestAnimationFrame( render );	}	requestAnimationFrame( render );}main();</script></html>
 |