'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
window.addEventListener('mousedown', OnMouseDown, false);
var cubeGeometry = new THREE.CubeGeometry( 220, 220, 220 );
var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0x000088 } );
var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.scale.x = 4;
scene.add(cube);
function OnMouseDown (event,time){
time *= 0.001;
event.preventDefault();
if (cars) {
for (const car of cars.children) {
car.rotation.x = time;
}
}
addAnnotation(event);
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
function frameArea(sizeToFitOnScreen, boxSize, boxCenter, camera) {
const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
const halfFovY = THREE.Math.degToRad(camera.fov * .5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
const direction = (new THREE.Vector3())
.subVectors(camera.position, boxCenter)
.multiply(new THREE.Vector3(1, 0, 1))
.normalize();
camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
camera.near = boxSize / 100;
camera.far = boxSize * 100;
camera.updateProjectionMatrix();
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}
let cars;
{
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load('https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf', (gltf) => {
const root = gltf.scene;
scene.add(root);
cars = root.getObjectByName('Cars');
// compute the box that contains all the stuff
// from root and below
const box = new THREE.Box3().setFromObject(root);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
// set the camera to frame the box
frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
// update the Trackball controls to handle the new size
controls.maxDistance = boxSize * 10;
controls.target.copy(boxCenter);
controls.update();
});
}
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;
}
var mouse = new THREE.Vector2(), num=0;
var spriteArray=[];
var labelCnt=0;
function addAnnotation(event)
{
console.log('in update mouse', mouse);
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
// var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
console.log('in update x', mouse.x);
mouse.x = ((event.clientX - renderer.domElement.offsetLeft ) / window.innerWidth) * 2 - 1;
mouse.y = -((event.clientY - renderer.domElement.offsetTop ) / window.innerHeight) * 2 + 1;
var ray = new THREE.Raycaster();
ray.setFromCamera( mouse, camera );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( scene.children,true );
console.log('intersect',intersects);
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
// if the closest object intersected is not the currently stored intersection object
if ( intersects[ 0 ].object.type== 'Mesh' ) {
// update text, if it has a "name" field.
if ( intersects[ 0 ].object.name ) {
var intersectedPoint = intersects[0].point;
var offset = (intersectedPoint.x > 0 ? .5 : -1 );
console.log('offset',offset);
//textAlign=(intersectedPoint.x >= 0 ? "left" : "");
var labelValue = 'label'+num;
var sprite = makeTextSprite(labelValue ,"canvas"+ num++);
sprite.userData = {
"id": num,
"label": labelValue};
sprite.position.set((intersectedPoint.x + offset)*1.2 ,
(intersectedPoint.y +.2)*1.2 ,
(intersectedPoint.z)*1.2);
sprite.name = "label"+ labelCnt;
sprite.userData.sourceName = intersects[ 0 ].object.name;
//adding to scene does place sprite
scene.add( sprite );
//intersects[0].object.add( sprite );
spriteArray.push(sprite);
}
}
}
}
function makeTextSprite(message, canvasId, textAlign, opts) {
var parameters = opts || {};
var fontface = parameters.fontface || 'Arial';
var fontsize = parameters.fontsize || 10;
var canvas = document.createElement('canvas');
canvas.id =canvasId;
// Add event listener for `click` events.
canvas.onclick=function(e){ e.preventDefault; alert('hello')}
var context = canvas.getContext('2d');
context.globalCompositeOperation='destination-over';
context.font = fontsize + "px " + fontface;
context.fillStyle = "white";
context.globalCompositeOperation = "source-out"
context.textAlign = "left";
// get size data (height depends only on font size)
var metrics = context.measureText(message);
var textWidth = metrics.width;
context.fillText(message, 0, fontsize);
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas)
texture.minFilter = THREE.LinearFilter;
texture.userData={"value":message};
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture ,
transparent: true,
useScreenCoordinates: true});
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set( 10, 5, 1.0 );
sprite.center.set( 0,1 );
return sprite;
}
function render(time) {
time *= 0.001; // convert to seconds
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
/* if (cars) {
for (const car of cars.children) {
car.rotation.x = time;
}
} */
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
Can you please describe in more detail your issue? It’s always a good approach to explain the expected and actual result.
BTW: A title should be short and expressive. It’s no good approach to put the actual description into the title. Maybe something like this: How to implement 3D-annotations with text input?
This is my code,
<html>
<head>
<title></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" type="text/css" href="dynamic.css">
</head>
<body>
<div class="row">
<canvas id="canvasLabel"
name ="canvasLabel"
type="text" class="tooltip"></canvas>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" />
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src=".https://threejs.org/examples/js/exporters/GLTFExporter.js" ></script>
<script src="https://threejs.org/examples/js/loaders/GLTFLoader.js" ></script>
<script src="dynamic.js"></script>
</body>
</html>
var renderer, scene, camera , mouse = new THREE.Vector2(), num=0; labelCnt=0;
var canvas = $('#canvasLabel');
var typingTimer; //timer identifier
var spriteArray=[];
init();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.gammaOutput = true;
// scene
scene = new THREE.Scene();
// camera
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
// controls
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.minDistance = 10;
controls.maxDistance = 50;
controls.enablePan = false;
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, .2 ) );
// light
var light = new THREE.PointLight( 0xffffff, 1.5 );
camera.add( light );
const color = 0xFFFFFF;
const intensity = 1;
var lights = new THREE.DirectionalLight(color, intensity);
lights.position.set(5, 10, 2);
scene.add(lights);
scene.add(lights.target);
/* var cubeGeometry = new THREE.CubeGeometry( 282, 282, 282 );
var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0x000088 } );
cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.name = "Cube"; */
//uncomment below code (scale) - the sprite will not be placed correctly.
/* cube.scale.x = 2;
scene.add(cube); */
updateRender(renderer,scene,camera,controls);
function frameArea(sizeToFitOnScreen, boxSize, boxCenter, camera) {
const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
const halfFovY = THREE.Math.degToRad(camera.fov * .5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
const direction = (new THREE.Vector3())
.subVectors(camera.position, boxCenter)
.multiply(new THREE.Vector3(1, 0, 1))
.normalize();
camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
camera.near = boxSize / 100;
camera.far = boxSize * 100;
camera.updateProjectionMatrix();
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}
window.addEventListener('mousedown', OnMouseDown, false);
let cars;
{
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load('https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf', (gltf) => {
const root = gltf.scene;
scene.add(root);
cars = root.getObjectByName('Cars');
// compute the box that contains all the stuff
// from root and below
const box = new THREE.Box3().setFromObject(root);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
// set the camera to frame the box
frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
// update the Trackball controls to handle the new size
controls.maxDistance = boxSize * 10;
controls.target.copy(boxCenter);
controls.update();
});
}
}
function updateRender(renderer,scene,camera,controls) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
controls.update();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
requestAnimationFrame(function () {
updateRender(renderer, scene, camera,controls);
})
}
function render() {
renderer.render( scene, camera );
}
function OnMouseDown (event){
event.preventDefault();
addAnnotation(event);
}
function addAnnotation(event)
{
var para = document.createElement("TEXTAREA");
para.innerText = "This is a paragraph.";
//scene(para);
console.log('in update mouse', mouse);
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
// var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
mouse.x = ((event.clientX - renderer.domElement.offsetLeft ) / window.innerWidth) * 2 - 1;
mouse.y = -((event.clientY - renderer.domElement.offsetTop ) / window.innerHeight) * 2 + 1;
var ray = new THREE.Raycaster();
ray.setFromCamera( mouse, camera );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( scene.children,true );
console.log('intersect',intersects);
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
// if the closest object intersected is not the currently stored intersection object
if ( intersects[ 0 ].object.type== 'Mesh' ) {
// update text, if it has a "name" field.
if ( intersects[ 0 ].object.name ) {
var intersectedPoint = intersects[0].point;
var offset = (intersectedPoint.x > 0 ? .5 : -1 );
console.log('offset',offset);
textAlign=(intersectedPoint.x >= 0 ? "left" : "");
var labelValue = num;
sprite = makeTextSprite(labelValue ,"canvas"+ num++);
sprite.userData = {
"id": num,
"label": labelValue};
sprite.position.set((intersectedPoint.x + offset)*1.2 ,
(intersectedPoint.y +.2)*1.2 ,
(intersectedPoint.z)*1.2);
sprite.name = "label"+ labelCnt;
sprite.userData.sourceName = intersects[ 0 ].object.name;
//adding to scene does place sprite
scene.add( sprite );
//intersects[0].object.add( sprite );
spriteArray.push(sprite);
}
}
}
}
//document.body.appendChild(btn);
function makeTextSprite(message, canvasId, textAlign, opts) {
var parameters = opts || {};
var fontface = parameters.fontface || 'Arial';
var fontsize = parameters.fontsize || 100;
var canvas = document.createElement('canvas');
canvas.id =canvasId;
// Add event listener for `click` events.
canvas.onclick=function(e){ e.preventDefault; alert('hello')}
var context = canvas.getContext('2d');
context.globalCompositeOperation='destination-over';
context.font = fontsize + "px " + fontface;
context.fillStyle = "white";
context.globalCompositeOperation = "source-out"
context.textAlign = "left";
context.width="1000px";
// get size data (height depends only on font size)
var metrics = context.measureText(message);
var textWidth = metrics.width;
context.fillText(message, 0, fontsize);
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas)
texture.minFilter = THREE.LinearFilter;
texture.userData={"value":message};
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture ,
transparent: true,
useScreenCoordinates: true});
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set( 10, 5, 1.0 );
sprite.center.set( 0,1 );
sprite.width="1000px";
return sprite;
}
3 D models implemented that perfect working.But in that models on mousedown i want add textareabox in exact x and y poisition.right now i did on (mouseDown) numbers increment. how to replace textarea.i tried so many ways…