@colneo/infohub-3dview
A 3D viewer for .cnjson models with integrated toolbar and tree panel.
Installation
npm install @colneo/infohub-3dview
<link rel="stylesheet" href="./node_modules/@colneo/infohub-ui/dist/css/style.css" />
Quick Start
import { createViewer3D, CN3D_READY_EVENT } from '@colneo/infohub-3dview';
// This event fires once when the package is imported (useful if your app loads viewers dynamically)
window.addEventListener(CN3D_READY_EVENT, (e) => {
console.log('cn3dready:', e.detail); // { timestamp, version }
initViewer();
});
function initViewer() {
const viewer3d = createViewer3D({
container: '#app',
showToolbar: true,
showTree: true,
toolbarCollapsed: false,
treeCollapsed: false,
treeTitle: 'write your title here...',
// Viewer events (from cnloader)
onSelectionChanged: (ids) => console.log('onSelectionChanged:', [...ids]),
onPointClicked: (point) => console.log('onPointClicked:', point),
// Toolbar events
onToolbarAction: (action, data) => console.log('onToolbarAction:', action, data),
onFileLoad: (file, modelData, treeData) => console.log('onFileLoad:', file.name, { modelData, treeData }),
// Tree events
onTreeSelect: (nodeId, node) => console.log('onTreeSelect:', nodeId, node),
onTreeAction: (action, node) => console.log('onTreeAction:', action, node),
// Viewer instance ready
onReady: () => {
console.log('onReady: Viewer is ready!');
viewer3d.setConfig({
backgroundColor: 0x1a1a2e,
renderMode: 'defaultLit',
edges: true,
grid: [
{ style: { color: 0x444444, width: 1 }, interval: [-10000, 10000, 10], direction: 'x' },
{ style: { color: 0x444444, width: 1 }, interval: [-10000, 10000, 10], direction: 'y' },
],
});
},
});
// Optional: await viewer3d.ready then call APIs
// viewer3d.ready.then(() => viewer3d.zoomAll());
}
Multiple Viewers
Create many viewers inside the same initViewer() (each has its own onReady and ready):
import { createViewer3D } from '@colneo/infohub-3dview';
const viewerA = createViewer3D({ container: '#appA', onReady: () => console.log('viewerA ready') });
const viewerB = createViewer3D({ container: '#appB', onReady: () => console.log('viewerB ready') });
// Optional
Promise.all([viewerA.ready, viewerB.ready]).then(() => console.log('all viewers ready'));
Events
| Event | Parameters | Description |
|---|---|---|
onSelectionChanged |
(ids: Set) |
Selection changed |
onSelectionAdd |
(id: string) |
Object added to selection |
onSelectionRemove |
(id: string) |
Object removed from selection |
onCompositeSelectionChanged |
(composites[]) |
Composite selection changed |
onVisibilityChanged |
(ids: Set) |
Visibility changed |
onPointClicked |
(point: {x,y,z}) |
Point clicked in 3D |
onKeyUpdate |
(keys: {}) |
Keyboard state changed |
onToolbarAction |
(action, data) |
Toolbar button clicked |
onFileLoad |
(file, modelData, treeData) |
File loaded |
onTreeSelect |
(nodeId, node) |
Tree node selected |
onTreeAction |
(action, node) |
Tree action triggered |
onReady |
() |
Viewer ready |
APIs
Lifecycle
viewer3d.ready // Promise - resolves when ready
viewer3d.isReady // boolean
viewer3d.destroy() // Cleanup
Layout
viewer3d.toggleToolbar()
viewer3d.toggleTree()
viewer3d.isToolbarCollapsed()
viewer3d.isTreeCollapsed()
Model
// Add to viewer. If tree panel is enabled, the tree auto-updates too.
await viewer3d.addObjects(nodes)
// Or provide explicit tree data (optional)
await viewer3d.addObjects(nodes, treeData)
// Or fine control (optional)
await viewer3d.addObjects(nodes, { treeData, appendTree: true, renderTree: true })
viewer3d.removeObject(id)
viewer3d.removeObjects(ids)
Camera
viewer3d.zoomAll()
viewer3d.zoomObjects(ids)
viewer3d.zoomPoints(xyzArray)
viewer3d.resetView()
viewer3d.getCamera()
viewer3d.setCamera(config)
Visibility
viewer3d.showAll()
viewer3d.hideAll()
viewer3d.showObjects(ids)
viewer3d.hideObjects(ids)
viewer3d.isolateObjects(ids)
viewer3d.getVisible()
Selection
viewer3d.getSelected()
viewer3d.selectObjects(ids)
viewer3d.selectObjectsOnly(ids)
viewer3d.clearSelection()
Colors
viewer3d.setColor(ids, '#ff0000')
viewer3d.getColor(id)
viewer3d.resetColor(ids)
viewer3d.resetAllColors()
Configuration
viewer3d.setConfig({ background: 0x000000, edges: true })
viewer3d.getConfig()
viewer3d.resetConfig()
viewer3d.setRenderMode('defaultLit') // 'wireframe', 'xray', 'original'
Grid
viewer3d.createGridLines(config)
viewer3d.deleteGridLines(gridId)
viewer3d.gridLines // all grids
Clipping / Sections
viewer3d.createSection(axis, normal, constant)
viewer3d.deleteSection(sectionId)
viewer3d.getClippingPlanes()
viewer3d.setClippingPlanes(planes)
viewer3d.resetClipping()
Measurements
viewer3d.createLengthMeasurement(point1, point2)
viewer3d.deleteLengthMeasurement(id)
viewer3d.getLengthMeasurements()
viewer3d.getLengthMeasurementSize(id)
viewer3d.createAreaMeasurement(points)
viewer3d.deleteAreaMeasurement(id)
viewer3d.getAreaMeasurements()
viewer3d.getAreaMeasurementSize(id)
Point & Face Picking
viewer3d.startPickedPointsLog()
viewer3d.stopPickedPointsLog()
viewer3d.getPickedPoints()
viewer3d.clearPickedPoints()
viewer3d.startPickedFacesLog()
viewer3d.stopPickedFacesLog()
viewer3d.getPickedFaces()
viewer3d.clearPickedFaces()
Lights & Screenshot
viewer3d.getLights()
viewer3d.setLights(config)
viewer3d.getScreenshot() // PNG data URL
Dynamic Events
viewer3d.on('onSelectionChanged', handler)
viewer3d.off('onSelectionChanged')
Keyboard Shortcuts
| Key | Action |
|---|---|
A |
Show all |
G |
Toggle grid |
Esc |
Reset view |
- |
Hide selected |
# |
Isolate selected |
Ctrl+Drag |
Box selection |