Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@cognite/3d-viewer
Advanced tools
JavaScript viewer to visualize 3D models on Cognite Data Fusion
Visualize Cognite's 3D models in a web browser with WebGL.
Note: The component will by default send anonymous usage statistics. This is used to improve the 3D viewer. You can opt out from this in the Cognite3DViewer constructor.
You need to install the Cognite SDK which needs to be authenticated before loading the 3D viewer.
Install the package with yarn:
yarn add @cognite/3d-viewer
or npm:
npm install @cognite/3d-viewer
To be able to use this 3D viewer you need to have access to Cognite Data Fusion. You can upload 3D models using Cognite 3D ingestor, or by looking at Cognite's API documentation. You can then use this viewer to visualize the 3D model in any web-based application on desktop or mobile devices.
import { Cognite3DViewer, THREE, TWEEN } from '@cognite/3d-viewer';
// If you are loading a local file, then just pass it in the localPath when you addModel:
const viewer = new Cognite3DViewer();
// If you are loading more than just local file, you would need to specify a sdk:
const viewer = new Cognite3DViewer({ sdk: new CogniteClient({ ... }) })
// Create three.js objects
const vector = new THREE.Vector3();
// Use TWEEN to animate e.g. the camera, see npmjs.com/package/@tweenjs/tween.js
To be able to use this package you need the following polyfills:
Adding model from CDF
// The viewer will render to a canvas inside a wrapper container.
// You can specify the wrapper by setting options.domElement and passing the options argument
// to the Cognite3DViewer constructor. If not set, it will create a div element for you.
const viewer = new Cognite3DViewer({ sdk: new CogniteClient({ ... }) });
// You can then add the div to your existing DOM:
document.body.appendChild(viewer.domElement);
// At this point you will only see a black canvas.
// So let's add a 3D model:
const options = {
modelId, // 3D model id
revisionId, // The model's revision id
};
viewer.addModel(options).then(function(model) {
// Move camera to look at the model
viewer.fitCameraToModel(model, 0);
});
Adding local model
// The viewer will render to a canvas inside a wrapper container.
// You can specify the wrapper by setting options.domElement and passing the options argument
// to the Cognite3DViewer constructor. If not set, it will create a div element for you.
const viewer = new Cognite3DViewer();
// You can then add the div to your existing DOM:
document.body.appendChild(viewer.domElement);
// At this point you will only see a black canvas.
// So let's add a 3D model:
const options = {
localPath: '...',
};
viewer.addModel(options).then(function(model) {
// Move camera to look at the model
viewer.fitCameraToModel(model, 0);
});
Note: You may need additional styling to the wrapper div container to make it fit your use-case. By default, the wrapper will have this style:
{ width: 100vw; height: 100vh; }
The internal canvas will be styled to fill this wrapper.
function onProgress(progress) {
console.log(progress);
}
function onComplete() {
console.log('Model loaded');
}
const options = {
modelId,
revisionId,
onProgress, // optional
onComplete, // optional
};
viewer.addModel(options)...
viewer.on('click', function(event) {
const { offsetX, offsetY } = event;
const intersection = viewer.getIntersectionFromPixel(offsetX, offsetY);
if (intersection !== null) {
const { nodeId, point, model } = intersection;
console.log('User clicked at world coordinate', point);
// highlight the object
model.selectNode(nodeId);
// make the camera zoom to the object
const boundingBox = model.getBoundingBox(nodeId);
viewer.fitCameraToBoundingBox(boundingBox, 2000); // 2 sec
} else {
// Clicked outside the 3D model
model.deselectAllNodes();
}
});
Assume you have the revision object from Cognite Data Fusion which you can get from this endpoint.
Here is a code snippet to use the saved camera position:
const { target, position } = revision.camera;
if (Array.isArray(target) && Array.isArray(position)) {
// Create three.js objects
const positionVector = new THREE.Vector3(...position);
const targetVector = new THREE.Vector3(...target);
// Apply transformation matrix
positionVector.applyMatrix4(model.matrix);
targetVector.applyMatrix4(model.matrix);
// Set on viewer
viewer.setCameraPosition(positionVector);
viewer.setCameraTarget(targetVector);
} else {
viewer.fitCameraToModel(model, 0);
}
Cognite3DViewer
is the root class of a Cognite 3D viewer. It controls all aspects of the 3D viewer.
options
Object (optional, default {}
)
options.domElement
Element? -- An existing DOM element that we will render into. This corresponds to the domElement property below.options.noBackground
boolean? -- Transparent background or not (optional, default false
)options.logMetrics
boolean -- Send anonymous usage statistics. (optional, default true
)options.highlightColor
boolean -- Highlight color of the selected objects (optional, default THREE.Color(0,0,1)
)options.viewCube
string? -- If defined then show a view cube and snap location of the view cube to this value. One of: 'topleft', 'topright', 'bottomleft', 'bottomright'.const viewer = new Cognite3DViewer({
noBackground: true,
sdk: <Instance of CogniteClient>
});
Dispose of WebGL resources. Can be used to free up memory when the viewer is no longer in use.
// Viewer is no longer in use, free up memory
viewer.dispose();
The DOM element the viewer will insert its rendering canvas into. The DOM element can be specified in the options when the viewer is created. If not specified, the DOM element will be created automatically. The DOM element cannot be changed after the viewer has been created.
Check if the viewer supports the current browser
if (!Cognite3DViewer.isBrowserSupported()) {
// create an error message to the user?
}
Add event listener to the viewer call off to remove an event listener
type
string -- Event type ('click' or 'cameraChange')func
function (event:PointerEvent) -- The callback functionconst onClick = event => { ... };
viewer.on('click', onClick);
viewer.on('cameraChange', (position, target) => {
console.log('Camera changed: ', position, target);
});
Remove event listener from the viewer call on to add an event listener
type
string -- Event type ('click' or 'cameraChange')func
function -- The callback function used in onviewer.off('click', onClick);
Add a new 3D model to the viewer. Call fitCameraToModel to focus camera on the model after it has loaded.
options
Object (optional, default {}
)
options.modelId
number -- The model's idoptions.revisionId
number -- The model's revision idoptions.geometryFilter
{ boundingBox?: THREE.Box3 } -- Filter out geometries. We currently only support bounding box filter, i.e. load only geometries inside the given bounding box.options.onProgress
function (progress: Object)? -- Callback for progress eventsoptions.onComplete
function? -- Callback when the model is fully loaded// Load a model and focus camera on the model
const options = {
modelId: 'COGNITE_3D_MODEL_ID',
revisionId: 'COGNITE_3D_REVISION_ID',
};
viewer.addModel(options).then(model => {
viewer.fitCameraToModel(model, 0);
});
// Load only geometries inside a bounding box, then focus camera on that area
const boundingBox = new THREE.Box3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(10, 10, 10)
);
const options = {
modelId: 'COGNITE_3D_MODEL_ID',
revisionId: 'COGNITE_3D_REVISION_ID',
geometryFilter: { boundingBox },
};
viewer.addModel(options).then(model => {
// Transform the bounding box to model space
boundingBox.applyMatrix4(model.matrix);
// Focus camera on bounding box
viewer.fitCameraToBoundingBox(boundingBox);
});
Returns Promise<Cognite3DModel>
Add a THREE.Object3D to the viewer
object
THREE.Object3D -- A three.js objectconst sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry(),
new THREE.MeshBasicMaterial()
);
viewer.addObject3D(sphere);
Remove a THREE.Object3D from the viewer
object
THREE.Object3D -- A three.js objectconst sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry(),
new THREE.MeshBasicMaterial()
);
viewer.addObject3D(sphere);
viewer.removeObject3D(sphere);
Sets per-pixel slicing planes. Pixels behind any of the planes will be sliced away.
slicingPlanes
THREE.Plane[] -- The planes to use for slicing// Hide pixels with values less than 0 in the x direction
const plane = new THREE.Plane(new THREE.Vector3(1, 0, 0), 0);
viewer.setSlicingPlanes([plane]);
// Hide pixels with values greater than 20 in the x direction
const plane = new THREE.Plane(new THREE.Vector3(-1, 0, 0), 20);
viewer.setSlicingPlanes([plane]);
// Hide pixels with values less than 0 in the x direction or greater than 0 in the y direction
const xPlane = new THREE.Plane(new THREE.Vector3(1, 0, 0), 0);
const yPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0);
viewer.setSlicingPlanes([xPlane, yPlane]);
// Hide pixels behind an arbitrary, non axis-aligned plane
const plane = new THREE.Plane(new THREE.Vector3(1.5, 20, -19), 20);
viewer.setSlicingPlanes([plane]);
// Disable slicing planes
viewer.setSlicingPlanes([]);
Returns camera's position
const position = viewer.getCameraPosition();
Returns THREE.Vector3 Position in world space
Returns camera's target
const target = viewer.getCameraTarget();
Returns THREE.Vector3 Target in world space
Set camera's position
position
THREE.Vector3 -- Position in world space// store position, target
const position = viewer.getCameraPosition();
const target = viewer.getCameraTarget();
// restore position, target
viewer.setCameraPosition(position);
viewer.setCameraTarget(target);
Set camera's target
target
THREE.Vector3 -- Target in world space// store position, target
const position = viewer.getCameraPosition();
const target = viewer.getCameraTarget();
// restore position, target
viewer.setCameraPosition(position);
viewer.setCameraTarget(target);
box
THREE.Box3 -- The bounding box in world spaceduration
number? -- The duration of the animation moving the camera. Set this to 0 (zero) to disable animation.radiusFactor
number? -- The ratio of the distance from camera to center of box and radius of the box (optional, default 4
)// Focus camera on bounding box over 500 milliseconds
viewer.fitCameraToBoundingBox(boundingBox, 500);
// Focus camera on bounding box instantaneously
viewer.fitCameraToBoundingBox(boundingBox, 0);
// Place the camera closer to the bounding box
viewer.fitCameraToBoundingBox(boundingBox, 500, 2);
// Animate camera to focus on a specific object with a given node id
const nodeId = 1234;
const boundingBox = model.getBoundingBox(nodeId);
viewer.fitCameraToBoundingBox(boundingBox, 1000);
Disables camera navigation with the keyboard.
// Disable keyboard navigation on textbox focus
inputElement.addEventListener('focus', () => {
viewer.disableKeyboardNavigation();
});
Enables camera navigation with the keyboard.
// Enable keyboard navigation on textbox blur
inputElement.addEventListener('blur', () => {
viewer.enableKeyboardNavigation();
});
Move camera to a place where the 3D model is visible. It uses the bounding box of the 3D model and calls fitCameraToBoundingBox
// Fit camera to model
viewer.fitCameraToModel(model);
// Fit camera to model over 500 milliseconds
viewer.fitCameraToModel(model, 500);
// Fit camera to model instantaneously
viewer.fitCameraToModel(model, 0);
model
Cognite3DModel -- The 3D modelduration
number? -- Same as for fitCameraToBoundingBoxConvert a point in world space to its coordinates in the canvas. This can be used to place HTML objects near 3D objects on top of the 3D viewer.
point
THREE.Vector3 -- World space coordinate.normalize
bool? -- Optional. If true, coordinates are normalized into [0,1]. If false, the values are in the range [0, <canvas_size>). (optional, default false
)// Find canvas coordinates, i.e. where on the screen it is rendered, for an object with a given node id
const boundingBoxCenter = new THREE.Vector3();
// Find center of bounding box in world space
model.getBoundingBox(nodeId).getCenter(boundingBoxCenter);
// Screen coordinates of that point
const screenCoordinates = viewer.worldToScreen(boundingBoxCenter);
// Find normalized canvas coordinates, i.e. where on the screen it is rendered, for an object with a given node id
const boundingBoxCenter = new THREE.Vector3();
// Find center of bounding box in world space
model.getBoundingBox(nodeId).getCenter(boundingBoxCenter);
// Screen coordinates of that point normalized in the range [0,1]
const screenCoordinates = viewer.worldToScreen(boundingBoxCenter, true);
// Find canvas coordinates, i.e. where on the screen it is rendered, for an object with a given node id
const boundingBoxCenter = new THREE.Vector3();
// Find center of bounding box in world space
model.getBoundingBox(nodeId).getCenter(boundingBoxCenter);
// Screen coordinates of that point
const screenCoordinates = viewer.worldToScreen(boundingBoxCenter);
if (screenCoordinates == null) {
// Object not visible on screen
} else {
// Object is visible on screen
}
Returns (THREE.Vector2 | null) -- Returns 2D coordinates if the point is visible on screen, or null
if object is outside screen.
Raycasting model(s) for finding where the ray intersects with the model.
x
number -- X coordinate in pixels (relative to the domElement)y
number -- Y coordinate in pixels (relative to the domElement)cognite3DModel
Cognite3DModel? -- If specified then only give results for this modelconst intersection = viewer.getIntersectionFromPixel(50, 100); // x = 50 pixels from the left, y = 100 pixels from the top
if (intersection)
// it was a hit
console.log(
'You hit model ',
intersection.model,
' at the node with id ',
intersection.nodeId,
' at this exact point ',
intersection.point
);
Returns (Intersection | null) -- If there was an intersection then return the intersection object - otherwise it returns null if there was no intersections.
Take screenshot from the current camera position.
// Add screenshot with resolution of the canvas to the page
const url = await viewer.getScreenshot();
const image = document.createElement('img');
image.src = url;
document.body.appendChild(url);
// Take screenshot with custom resolution
const url = await viewer.getScreenshot(1920, 1080);
width
number? -- Width of the final image. Default is current canvas size.height
number? -- Height of the final image. Default is current canvas size.Returns Promise<string> A Blob URL to the image ('image/png')
Type: object
model
Cognite3DModel -- The node idnodeId
number -- The nodeId of the first intersected nodepoint
THREE.Vector3 -- The 3D position of the intersection point in the world coordinate systemExtends THREE.Object3D
Cognite3DModel
is the class representing a Cognite 3D model and its state
The id of the model in Cognite Data Fusion
The id of the model revision in Cognite Data Fusion
Get all node ids in a subtree where the root node has id 'nodeId'
nodeId
number -- The ID of the root nodesubtreeSize
number? -- If you already know the subtreeSize, this will avoid an extra API callReturns [number] List of nodeIds in the subtree
Get bounding box of a node
nodeId
number -- The node's idbox
THREE.Box3? -- Optional target. Specify this to increase performance if the box can be reused.const box = model.getBoundingBox(nodeId);
const reusableBox = new THREE.Box3();
const box = model.getBoundingBox(nodeId, reusableBox);
// box === reusableBox
Returns THREE.Box3
Go through the node tree and apply an action to each node that has a node ID.
const url = await model.iterateNodes(console.log);
action
Callback -- Callback function taking in a nodeId and treeIdReturns void
Go through the subtree a node of the tree and apply an action to each subtree node that has a node ID.
const url = await viewer.iterateSubtree(1111111111, console.log);
nodeId
number -- The id of the node whose subtree will have action applied toaction
Callback -- Callback function taking in a nodeId and treeIdtreeIndex?
number -- (Optional) The index within the tree for the given nodeIdsubtreeSize?
number -- (Optional) The size of the subtree starting from nodeIdReturns Promise<boolean> Whether a valid nodeId was given or not
Return the color on a node.
nodeId
number -- The node's idReturns {r: number, g: number, b: number} (r, g, b in the range [0, 255])
Set the color on a node.
nodeId
number -- The node's idr
number -- The red color value (0-255)g
number -- The green color value (0-255)b
number -- The blue color value (0-255)Reset a node's color to its original color.
nodeId
number -- The node's idMark a node as selected. Only visible nodes can be selected.
nodeId
number -- The node's idMark a node as deselected.
nodeId
number -- The node's idMark all selected nodes as deselected.
Show a node.
nodeId
number -- The node's idShow all nodes.
Hide all nodes.
ghost
bool -- Hide with ghost effect (optional, default false
)Hide a node.
nodeId
number -- The node's idghost
bool -- Hide with ghost effect (optional, default false
)For support contact mailto:support@cognite.com
FAQs
JavaScript viewer to visualize 3D models on Cognite Data Fusion
We found that @cognite/3d-viewer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 176 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.