Skip to content

Instantly share code, notes, and snippets.

@superstes
Last active April 7, 2024 21:42
Show Gist options
  • Save superstes/0e8ec446715d993014cb3a92b975f8a8 to your computer and use it in GitHub Desktop.
Save superstes/0e8ec446715d993014cb3a92b975f8a8 to your computer and use it in GitHub Desktop.
ThreeJS - Let HTML-Element follow point (<model-viewer> annotation-like)
/*
NOTES:
basic source: https://codepen.io/lamb_1128/pen/xxQogxj
this functionality can be compared to the annotations seen at: https://modelviewer.dev/examples/annotations/index.html
but this has a very minimalistic approach
*/
/* css
.annotation {
position: absolute;
# optional
background-color: #606060;
color: whitesmoke;
border-radius: 25%;
padding: 10px;
overflow: hidden;
opacity: 80%;
max-width: 10vw;
font-size: small;
}
*/
/* html
...
<body>
<div id="annotation-anchor"></div><!-- there might be a cleaner approach -->
</body>
*/
const ANNOTATION_ID = 'annotation1';
const ANCHOR_ID = 'annotation-anchor';
const ANNOTATION_CLS = 'annotation';
_createAnnotation() {
let popup = document.createElement("div");
popup.id = ANNOTATION_ID;
popup.classList.add(ANNOTATION_CLS);
popup.setAttribute("hidden", "hidden");
popup.innerText = "Test Annotation";
document.body.insertBefore(popup, document.getElementById(ANCHOR_ID));
return popup;
}
updateAnnotation(camera, follow) {
let popup = document.getElementById(ANNOTATION_ID);
if (popup === null) {
popup = _createAnnotation();
}
let target = new THREE.Vector3();
target.copy(follow);
target.project(camera);
target.x = Math.round((0.57 + target.x / 2) * (window.innerWidth / window.devicePixelRatio));
target.y = Math.round((0.57 - target.y / 2) * (window.innerHeight / window.devicePixelRatio));
popup.style.top = `${target.y}px`;
popup.style.left = `${target.x}px`;
popup.removeAttribute("hidden");
}
removeAnnotation() {
try {
document.getElementById(ANNOTATION_ID).remove();
} catch {
// already deleted
}
}
const CAM_FOV = 60;
const aspect = 1920 / 1080;
const near = 1;
const far = 25000.0;
const camera = new THREE.PerspectiveCamera(CAM_FOV, aspect, near, far);
let pointToFollow = new THREE.Vector3(1, 1, 1);
// fov-check source: https://gist.github.com/superstes/4f11649ff089b45a29bc44f147c226c2
...
if (inFrontOfCamera(camera.position, cameraDirection, pointToFollow)) {
updateAnnotation(camera);
} else {
removeAnnotation();
}
@superstes
Copy link
Author

superstes commented Apr 7, 2024

Using window.innerWidth and window.innerHeight assuming the 3js canvas is filling the whole screen!
Otherwise use the width/height of renderer.domElement (WebGL renderer instance)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment