Firstly I set up variables for each type of modal box I would like to position on the map.

var modal;

These variables will hold the position of a clicked object, which is brought in from a separate ‘onClick’ function. The positionTrackingOverlay function is then constructed as below:

function positionTrackingOverlay()
{
var visibleWidth, visibleHeight, p, v, percX, percY, left, top,
widthPercentage, heightPercentage;
if(modal != null){
modal.geometry.computeBoundingBox();
var boundingBox = modal.geometry.boundingBox;
var position = new THREE.Vector3();
position.subVectors( boundingBox.max, boundingBox.min );
position.multiplyScalar( 0.5 );
position.add( boundingBox.min );
position.applyMatrix4( modal.matrixWorld );

After checking that ‘modal’ is not empty, the function computes the bounding box of the selected object in order to find its position. This is then used below to project the 3D coordinates onto the 2D screen.

p = position.clone();
// projectVector will translate position to 2d
v = projector.projectVector(p, camera);
// translate our vector so that percX=0 represents
// the left edge, percX=1 is the right edge,
// percY=0 is the top edge, and percY=1 is the bottom edge.
percX = (v.x + 1) / 2;
percY = (-v.y + 1) / 2;
// scale these values to our viewport size
left = percX * WIDTH;
top = percY * HEIGHT;

I can then use the ‘WIDTH’ and ‘HEIGHT’ variables to calculate the position of the modal box as a percentage (this is so that its position will change on window resize).

widthPercentage = (left - $("#modalpanel").width() / 2) / WIDTH * 100;
heightPercentage = (top - $("#modalpanel").height()) / HEIGHT * 100;

Finally I use JQuery to update the css of the HTML element according to the position of the 3D object.

$("#modalpanel")
.css('left', widthPercentage + '%')
.css('top', heightPercentage + '%');

The function ‘positionTrackingOverlay()’ is called in the render loop so that it is constantly updated at runtime.