Overview
Threadbox provides a comprehensive interaction system for 3D objects and fill-extrusion features. Enable mouse interactions to allow users to select, drag, rotate, and interact with objects on your map.
Enabling Interactions
Configure interactions when creating your Threebox instance:
const tb = new Threebox ( map , gl , {
defaultLights: true ,
enableSelectingObjects: true , // Enable object selection
enableDraggingObjects: true , // Enable object dragging
enableRotatingObjects: true , // Enable object rotation
enableSelectingFeatures: true , // Enable fill-extrusion selection
enableTooltips: true , // Enable default tooltips
enableHelpTooltips: true // Enable help tooltips during interactions
});
enableSelectingObjects must be true for dragging and rotating to work.
Object Selection
Basic Selection
Click on objects to select them:
const model = await tb . loadObj ({
obj: '/models/building.glb' ,
type: 'gltf' ,
scale: 1 ,
units: 'meters'
});
model . setCoords ([ - 122.4194 , 37.7749 ]);
tb . add ( model );
// Object can now be selected by clicking
Selection Events
Listen to selection state changes:
model . addEventListener ( 'SelectedChange' , ( e ) => {
const isSelected = e . detail . selected ;
if ( isSelected ) {
console . log ( 'Object selected:' , e . detail . uuid );
// Fly camera to object
if ( e . detail . userData . feature ) {
map . flyTo ({
center: e . detail . userData . feature . properties . camera ,
zoom: 18 ,
pitch: 60
});
}
} else {
console . log ( 'Object deselected' );
}
}, false );
Programmatic Selection
Select/deselect objects programmatically:
// Select object
model . selected = true ;
// Deselect object
model . selected = false ;
// Check selection state
if ( model . selected ) {
console . log ( 'Object is selected' );
}
Object Dragging
Horizontal Dragging
Hold Shift + Click & Drag to move objects horizontally:
const tb = new Threebox ( map , gl , {
enableSelectingObjects: true ,
enableDraggingObjects: true
});
// Object can now be dragged horizontally
model . addEventListener ( 'ObjectDragged' , ( e ) => {
const action = e . detail . draggedAction ;
const coords = e . detail . coordinates ;
if ( action === 'translate' ) {
console . log ( 'Object moved to:' , coords );
}
}, false );
Vertical Dragging
Hold Ctrl + Click & Drag to change object altitude:
model . addEventListener ( 'ObjectDragged' , ( e ) => {
const action = e . detail . draggedAction ;
if ( action === 'altitude' ) {
const altitude = e . detail . coordinates [ 2 ];
console . log ( 'Object altitude:' , altitude , 'meters' );
}
}, false );
Drag Configuration
Configure dragging behavior:
// Set grid step (precision in decimal places)
tb . gridStep = 6 ; // 6 decimals = ~11.1cm precision
// Set altitude step
tb . altitudeStep = 0.1 ; // 0.1 meters = 10cm
Object Rotation
Hold Alt + Click & Drag to rotate objects around their Z-axis:
const tb = new Threebox ( map , gl , {
enableSelectingObjects: true ,
enableRotatingObjects: true
});
model . addEventListener ( 'ObjectDragged' , ( e ) => {
const action = e . detail . draggedAction ;
if ( action === 'rotate' ) {
const rotation = e . detail . rotation ;
console . log ( 'Object rotated to:' , rotation . z , 'degrees' );
}
}, false );
// Configure rotation step size
tb . rotationStep = 5 ; // 5 degrees per step
Mouse Hover Events
Mouse Over
Detect when the mouse enters an object:
model . addEventListener ( 'ObjectMouseOver' , ( e ) => {
console . log ( 'Mouse over object:' , e . detail . uuid );
// Change cursor
map . getCanvasContainer (). style . cursor = 'pointer' ;
// Show additional info
displayObjectInfo ( e . detail );
}, false );
Mouse Out
Detect when the mouse leaves an object:
model . addEventListener ( 'ObjectMouseOut' , ( e ) => {
console . log ( 'Mouse left object' );
// Reset cursor
map . getCanvasContainer (). style . cursor = tb . defaultCursor ;
// Hide info
hideObjectInfo ();
}, false );
Hover State
Access and control hover state:
// Check if object is being hovered
if ( model . over ) {
console . log ( 'Mouse is over this object' );
}
// Programmatically set hover state (not recommended)
model . over = true ;
Fill-Extrusion Features
Interact with Mapbox fill-extrusion layers:
const tb = new Threebox ( map , gl , {
enableSelectingFeatures: true ,
enableTooltips: true
});
// Listen for feature selection
map . on ( 'SelectedFeatureChange' , ( e ) => {
const feature = e . detail ;
console . log ( 'Selected building:' , feature . properties . name );
console . log ( 'Height:' , feature . properties . height );
});
Bounding Boxes
Visual feedback for selected/hovered objects:
// Enable bounding box on object creation
tb . loadObj ({
obj: '/models/car.glb' ,
type: 'gltf' ,
bbox: true // Show bounding box when selected/hovered
}, ( model ) => {
model . setCoords ( origin );
tb . add ( model );
});
// Access bounding box elements
if ( model . boundingBox ) {
console . log ( 'Bounding box exists' );
}
if ( model . boundingBoxShadow ) {
console . log ( 'Shadow box exists' );
}
Custom Cursor
Customize the default cursor:
// Set default cursor
tb . defaultCursor = 'grab' ;
// Change cursor on interaction
model . addEventListener ( 'ObjectMouseOver' , () => {
map . getCanvasContainer (). style . cursor = 'pointer' ;
});
model . addEventListener ( 'ObjectMouseOut' , () => {
map . getCanvasContainer (). style . cursor = tb . defaultCursor ;
});
Raycasted Property
Control whether objects can be selected:
// Disable raycasting for specific object
model . raycasted = false ; // Object won't be selectable
// Re-enable raycasting
model . raycasted = true ;
// Check raycasting state
if ( model . raycasted ) {
console . log ( 'Object can be selected' );
}
Complete Interaction Example
map . on ( 'load' , () => {
const tb = new Threebox ( map , gl , {
defaultLights: true ,
enableSelectingObjects: true ,
enableDraggingObjects: true ,
enableRotatingObjects: true ,
enableTooltips: true ,
enableHelpTooltips: true
});
map . addLayer ({
id: 'custom-layer' ,
type: 'custom' ,
renderingMode: '3d' ,
onAdd : function ( map , gl ) {
tb . loadObj ({
obj: '/models/building.glb' ,
type: 'gltf' ,
scale: 1 ,
units: 'meters' ,
rotation: { x: 90 , y: 0 , z: 0 },
bbox: true ,
tooltip: true
}, ( model ) => {
const origin = [ - 122.4194 , 37.7749 , 0 ];
model . setCoords ( origin );
tb . add ( model );
// Selection event
model . addEventListener ( 'SelectedChange' , ( e ) => {
if ( e . detail . selected ) {
console . log ( 'Building selected' );
// Update UI
document . getElementById ( 'info-panel' ). style . display = 'block' ;
document . getElementById ( 'building-name' ). textContent = 'Custom Building' ;
} else {
document . getElementById ( 'info-panel' ). style . display = 'none' ;
}
});
// Drag event
model . addEventListener ( 'ObjectDragged' , ( e ) => {
const action = e . detail . draggedAction ;
const coords = e . detail . coordinates ;
switch ( action ) {
case 'translate' :
console . log ( 'Moved to:' , coords );
updateCoordinatesDisplay ( coords );
break ;
case 'altitude' :
console . log ( 'Altitude:' , coords [ 2 ]);
updateAltitudeDisplay ( coords [ 2 ]);
break ;
case 'rotate' :
console . log ( 'Rotation:' , e . detail . rotation . z );
updateRotationDisplay ( e . detail . rotation . z );
break ;
}
// Save new position
saveObjectPosition ( model . uuid , coords , e . detail . rotation );
});
// Mouse over event
model . addEventListener ( 'ObjectMouseOver' , () => {
map . getCanvasContainer (). style . cursor = 'pointer' ;
showBuildingHighlight ( model );
});
// Mouse out event
model . addEventListener ( 'ObjectMouseOut' , () => {
if ( ! model . selected ) {
map . getCanvasContainer (). style . cursor = tb . defaultCursor ;
hideBuildingHighlight ( model );
}
});
});
},
render : function ( gl , matrix ) {
tb . update ();
}
});
});
Keyboard Controls Summary
Shift + Drag Move object horizontally (X/Y plane)
Ctrl + Drag Move object vertically (altitude)
Alt + Drag Rotate object around Z-axis
Enabling interactions adds event listeners and raycasting. For scenes with many objects:
Only enable interactions when needed
Use raycasted: false for non-interactive objects
Consider disabling bbox for objects that don’t need visual feedback
See Also