The new push of the Cloud based View & Data API is coming with an exciting feature that will enable developers to easily componentize their code, reuse and isolate features using a modular approach.
The mechanism is pretty simple: you derive a JavaScript class from Autodesk.Viewing.Extension and then load that extension when the viewer starts or at runtime.
See the code below where I highlighted the portion of the code relevant to the extensions. The viewer.loadExtension / unloadExtension methods allow you even load or unload extensions without reloading the current model loaded in the viewer.
-
function initializeViewer(containerId, documentId, role) {
var viewerContainer = document.getElementById(containerId);
var viewer = new Autodesk.Viewing.Private.GuiViewer3D(
viewerContainer,
{ extensions: ['ADN Simple Extension', '2D Annotation'] });
viewer.start();
-
// extensions can also be loaded/unloaded using
// viewer.loadExtension(extensionId, options);
// viewer.unloadExtension(extensionId);
Autodesk.Viewing.Document.load(documentId,
function (document) {
var rootItem = document.getRootItem();
var geometryItems =
Autodesk.Viewing.Document.getSubItemsWithProperties(
rootItem,
{ 'type': 'geometry', 'role': role },
true);
viewer.load(
document.getViewablePath(geometryItems[0]));
},
// onErrorCallback
function (msg) {
console.log("Error: " + msg);
}
);
}
-
Here is a very simple example of a custom extension which does nothing except logging traces in the browser console when loaded or unloaded:
///////////////////////////////////////////////////////////////////////////////
// Simple viewer Extension
// by Philippe Leefsma, October 2014
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN");
Autodesk.ADN.SimpleExtension = function (viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
_self = this;
_self.load = function () {
console.log("Autodesk.ADN.SimpleExtension loaded");
return true;
};
_self.unload = function () {
console.log("Autodesk.ADN.SimpleExtension unloaded");
return true;
};
};
Autodesk.ADN.SimpleExtension.prototype =
Object.create(Autodesk.Viewing.Extension.prototype);
Autodesk.ADN.SimpleExtension.prototype.constructor =
Autodesk.ADN.SimpleExtension;
Autodesk.Viewing.theExtensionManager.registerExtension(
'ADN Simple Extension',
Autodesk.ADN.SimpleExtension);
-
And here is a more advanced extension that displays 2D annotations facing the view when a component is selected:
///////////////////////////////////////////////////////////////////////////////
// 2D Annotation viewer Extension
// by Philippe Leefsma, October 2014
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN");
Autodesk.ADN.AnnotationExtension = function (viewer, options) {
// base constructor
Autodesk.Viewing.Extension.call(this, viewer, options);
/////////////////////////////////////////////////////////////////
// Private members
//
/////////////////////////////////////////////////////////////////
var _annotationDivId = 'adn-annotation-divId';
var _selectedFragment = null;
var _selectedId = null;
var _viewer = viewer;
var _self = this;
/////////////////////////////////////////////////////////////////
// load callback
//
/////////////////////////////////////////////////////////////////
_self.load = function () {
console.log("Autodesk.ADN.AnnotationExtension loaded");
$("<div></div>").attr('id', _annotationDivId).appendTo('body');
$('#' + _annotationDivId).css({
'position': 'absolute',
'width': '200px',
'height': '50px',
'font-family': 'arial',
'color': '#ED1111',
'font-size': '20px',
'visibility': 'hidden',
'z-index': '100'
});
_viewer = _self.viewer;
_viewer.addEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
_self.onItemSelected);
_viewer.addEventListener(
Autodesk.Viewing.CAMERA_CHANGE_EVENT,
_self.onCameraChanged);
return true;
};
/////////////////////////////////////////////////////////////////
// unload callback
//
/////////////////////////////////////////////////////////////////
_self.unload = function () {
console.log("Autodesk.ADN.AnnotationExtension unloaded");
_viewer.removeEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
_self.onItemSelected);
_viewer.removeEventListener(
Autodesk.Viewing.CAMERA_CHANGE_EVENT,
_self.onCameraChanged);
$('#' + _annotationDivId).remove();
return true;
};
/////////////////////////////////////////////////////////////////
// item selected callback
//
/////////////////////////////////////////////////////////////////
_self.onItemSelected = function (event) {
_selectedId = event.dbIdArray[0];
_selectedFragment = event.fragIdsArray[0];
console.log('Selected id: ' + _selectedId);
console.log('Selected fragment: ' + _selectedFragment);
if (typeof _selectedFragment !== 'undefined') {
if (Array.isArray(_selectedFragment))
_selectedFragment = _selectedFragment[0];
_self.getPropertyValue(_selectedId, 'label',
function (value) {
$('#' + _annotationDivId).text(value);
$('#' + _annotationDivId).css(
{ 'visibility': 'visible' }
);
_self.onCameraChanged();
});
}
else {
$('#adnAnnotationDivId').css({ 'visibility': 'hidden' });
}
}
/////////////////////////////////////////////////////////////////
// world -> screen coords conversion
//
/////////////////////////////////////////////////////////////////
_self.worldToScreen = function (worldPoint, camera) {
var p = new THREE.Vector4();
p.x = worldPoint.x;
p.y = worldPoint.y;
p.z = worldPoint.z;
p.w = 1;
p.applyMatrix4(camera.matrixWorldInverse);
p.applyMatrix4(camera.projectionMatrix);
// Don't want to mirror values with negative z
// if camera is inside the bounding box,
// better to throw markers to the screen sides.
if (p.w > 0) {
p.x /= p.w;
p.y /= p.w;
p.z /= p.w;
}
// This one is multiplying by width/2 and –height/2,
// and offsetting by canvas location
point = _viewer.impl.viewportToClient(p.x, p.y);
// snap to the center of the pixel
point.x = Math.floor(point.x) + 0.5;
point.y = Math.floor(point.y) + 0.5;
return point;
}
/////////////////////////////////////////////////////////////////
// Get Property Value
//
/////////////////////////////////////////////////////////////////
_self.getPropertyValue = function (dbId, displayName, callback) {
function _cb(result) {
if (result.properties) {
for (var i = 0; i < result.properties.length; i++) {
var prop = result.properties[i];
if (prop.displayName === displayName) {
callback(prop.displayValue);
return;
}
}
callback('undefined');
}
}
_viewer.getProperties(dbId, _cb);
};
/////////////////////////////////////////////////////////////////
// camera changed callback
//
/////////////////////////////////////////////////////////////////
_self.onCameraChanged = function (event) {
if (typeof _selectedFragment === 'undefined') {
$('#' + _annotationDivId).css({
'visibility': 'hidden'
});
return;
}
var mesh = _viewer.impl.getRenderProxy(
_viewer,
_selectedFragment);
if (mesh) {
// get position of the mesh
var worldPoint = new THREE.Vector3();
worldPoint.setFromMatrixPosition(mesh.matrixWorld);
var screenPoint = _self.worldToScreen(
worldPoint,
_viewer.getCamera());
$('#' + _annotationDivId).css({
'left': screenPoint.x.toString() + "px",
'top': screenPoint.y.toString() + "px"
});
}
else {
$('#' + _annotationDivId).css({
'visibility': 'hidden'
});
}
};
};
Autodesk.ADN.AnnotationExtension.prototype =
Object.create(Autodesk.Viewing.Extension.prototype);
Autodesk.ADN.AnnotationExtension.prototype.constructor =
Autodesk.ADN.AnnotationExtension;
Autodesk.Viewing.theExtensionManager.registerExtension(
'2D Annotation',
Autodesk.ADN.AnnotationExtension);
-
Attached is a full demo sample using those two extensions.
Hi Philippe,
I run the demo with my model, but the model does not show in the viewer. The urn that I use is:
var urn = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YWRuLTI4LjEwLjIwMTQtMDkuMzIuNDEvVGVzdDAyLnJ2dA=='
I get the token through a node.js server
(https://github.com/Developer-Autodesk/AuthTokenServer_Simple)
The viewer says "Model Structure Loading..." when clicking "Model Structure".
Any idea?
Thanks.
Will
Posted by: Will Song | 10/28/2014 at 11:25 AM
Hi Will,
Looks like the issue is not related to that blog post specifically. Did you already successfully view another model using the same token server? Please post a new thread on our support forum if you can't solve the issue:
http://forums.autodesk.com/t5/view-and-data-api/bd-p/95
Thanks,
Philippe.
Posted by: Philippe Leefsma | 10/28/2014 at 03:11 PM