APS (Forge) Viewer in Sharepoint - Error loading Autodesk Viewer library - autodesk-forge

I am trying to integrate APS Viewer (formerly Forge Viewer) in a Sharepoint webpart using Sharepoint Framework. There is a post in the blog explaining how to do it: https://aps.autodesk.com/blog/sharepoint-online-integration.
I have adapted the code provided, however, I always end up with this error when loading the Viewer. The error occurs when calling Autodesk.Viewing.Initializer function to initialize the viewer. This call fails because
"ReferenceError: Autodesk is not defined"
yet the library is imported correctly. Anyone knows how can I solve this?
These are the steps we did:
Create a webpart with Sharepoint Framework. No Framework template is selected.
Add custom js script with functions to load the viewer.
Import Autodesk js library for Viewer with SPComponentLoader and load custom js script in render() function of our Sharepoint webpart.
SPComponentLoader.loadScript("https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js");
SPComponentLoader.loadScript("./js/ForgeTree.js");
const viewer: any = require("./ForgeViewer.js");
Call custom function launchViewer from custom js script that calls Autodesk.Viewing.Initializer method. This step fails.
export function launchViewer(urn, viewableId, accessToken) {
console.log('launchViewer')
var options = {
env: 'AutodeskProduction',
getAccessToken: callback => {
callback(accessToken, 3600);
},
// api: 'derivativeV2' + (atob(urn.replace('_', '/')).indexOf('emea') > -1 ? '_EU' : '') // handle OSS US and EU regions
api: 'derivativeV2' + (Buffer.from((urn.replace('_', '/')).indexOf('emea') > -1 ? '_EU' : ''), 'base64') // handle OSS US and EU regions
};
if (viewer === undefined) {
Autodesk.Viewing.Initializer(options, () => {
viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer'), { extensions: [ 'Autodesk.DocumentBrowser'] });
viewer.start();
var documentId = 'urn:' + urn;
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
})
} else {
var documentId = 'urn:' + urn;
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
}
}

I think you should simply wait for the SPComponentLoader.loadScript() to finish (use await or then()) as it returns a Promise<TModule>
https://learn.microsoft.com/en-us/javascript/api/sp-loader/spcomponentloader?view=sp-typescript-latest##microsoft-sp-loader-spcomponentloader-loadscript-member(1)
I probably got away with not doing that in my code because the authentication is taking place after that call, which gives extra time for loadScript to finish

Related

Autodesk Forge AggregatedView viewing a "stitched" geometry rather than a smooth one

I have a simple forge app to view 3d models. At first, I initiated the forge viewer with GuiViewer3D class but then wanted to implement AggregatedView instead.
My problem is that AggregatedView shows the model correctly but it shows it as being "stitched" together. Whereas, if I use GuiViewer3D or Viewer3D, the model looks smooth and clean.
I have looked into the globalOffset but in any solution, the globalOffset is the same, and hence should not be the cause here.
This is how the model should look like (GuiViewer3D)
But this is how it looks like instea using AggregatedView
I am not quite sure what the issue here. I am using an .fbx file as the source of 3d model.
This the code of AggregatedView()
var view = new Autodesk.Viewing.AggregatedView();
function launchViewer(urn) {
var options = {
env: 'AutodeskProduction',
getAccessToken: getForgeToken
};
Autodesk.Viewing.Initializer(options, () => {
var htmlDiv = document.getElementById('forgeViewer');
view.init(htmlDiv, options);
var documentId = 'urn:' + urn;
view.unloadAll();
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
}
function onDocumentLoadSuccess(doc) {
var nodes = doc.getRoot().search({ role:'3d', type: 'geometry' });
console.log(nodes);
view.setNodes(nodes[0]);
}
function onDocumentLoadFailure(viewErrorCode, viewErrorMsg) {
console.error('onDocumentLoadFailure() - errorCode:' + viewErrorCode + '\n- errorMessage:' + viewErrorMsg);
}
function getForgeToken(callback) {
fetch('/api/forge/oauth/token').then(res => {
res.json().then(data => {
callback(data.access_token, data.expires_in);
});
});
}
Many thanks in advance!
UPDATE:
After setting the global offset to (0,0,0), the geometry still looks "Stitched" together rather than smooth.
The pivot point is not the global offset. Please use viewer.getAllModels().map( model => model.getGlobalOffset() ) to check that instead. For AggreagateView, you can get the viewer instance via view.viewer;
In addition, AggreagateView loads models in the shared coordinate (applyRefPoint: true), so your model might be far away from the viewer's origin. Could you try this to see if it helps?
const options3d = {
getCustomLoadOptions: (bubble, data) => {
console.log(bubble, data);
return {
applyRefPoint: false //!<<< Disable Share Coordinate
// globalOffset: new THREE.Vector3( 543.0811920166016, 9.154923574611564, -1442.591747316564 ) //!<<< uncomment this to specify your globalOffset, but you need to include `applyRefPoint: false` above together.
// createWireframe: false
};
}
};
view.init(viewerDiv, options3d);

Cannot load SVF2 model in Autodesk Forge Viewer

I just tried out the SVF2 public beta but couldn't get the model to load in the Viewer. I believe the model was translated successfully since the manifest returned has:
"name": "XXXX_ARC.nwd",
"progress": "complete",
"outputType": "svf2",
"status": "success"
However, when I tried to load the model in Viewer, it would fail on this line:
theViewer.loadModel(svfURL, onItemLoadSuccess, onItemLoadFail);
The svfURL is something like this:
https://cdn.derivative.autodesk.com/modeldata/file/urn:adsk.fluent:fs.file:autodesk-360-translation-storage-prod/*MyURN*/output/otg_files/0/output/0/otg_model.json
And the errors I got from Chrome browser:
403 GET errors. Seems like I don't have privilege to access the model?
Is there some additional setting I need to do?
Additional Info:
I have setup the Viewer environment as follows:
var options = {
env: 'MD20ProdUS',
api: 'D3S',
getAccessToken: getForgeToken
};
var documentId = 'urn:' + urn;
Autodesk.Viewing.Initializer(options, function onInitialized() {
var htmlDiv = document.getElementById('forgeViewer');
var config3d = {
extensions: ['ToolbarExtension', 'HandleSelectionExtension', .....a few extensions ],
loaderExtensions: { svf: "Autodesk.MemoryLimited" }
};
theViewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv, config3d);
var startedCode = theViewer.start();
if (startedCode > 0) {
console.error('Failed to create a Viewer: WebGL not supported.');
return;
}
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
I have also tried removing the config3d when creating the viewer but it still returned the same messages. The code got into onDocumentLoadSuccess but failed at theViewer.loadModel(svfURL, onItemLoadSuccess, onItemLoadFail);, jumping into onItemLoadFail.
Because you mention mainly the viewer not loading the SVF2, I can suspect that maybe you have not specified the correct Viewer environment.
Here is some sample code, and pay attention to the options where you have to set env and API:
var viewer;
var options = {
// These are the SVF2 viewing settings during public beta
env: 'MD20ProdUS', // or MD20ProdEU (for EMEA)
api: 'D3S',
getAccessToken: getForgeToken
};
var documentId = 'urn:' + getUrlParameter('urn');
// Run this when the page is loaded
Autodesk.Viewing.Initializer(options, function onInitialized() {
// Find the element where the 3d viewer will live.
var htmlElement = document.getElementById('MyViewerDiv');
if (htmlElement) {
// Create and start the viewer in that element
viewer = new Autodesk.Viewing.GuiViewer3D(htmlElement);
viewer.start();
// Load the document into the viewer.
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
}
});
I am facing the same problem.
Although the model has been converted to SVF2 format, my cloud credits are being used up .
An excerpt from the manifest:
"name": "7085-33cc-9464.rvt",
"progress": "complete",
"outputType": "svf2",
"status": "success"
No matter with which settings, only the SVF format is loaded in the viewer.
I don't get an error message from the viewer, everything works as before, except that SVF is still loaded and not SVF2.
Viewer init options:
const viewerEnv = await this.initialize({
//env: dbModel.env,
env: "MD20ProdEU",
api: "D3S",
//accessToken: "",
});
Not sure if this has been solved on a separate thread, but the issue was probably that acmSessionId was not set in the options for loadModel() - see https://forge.autodesk.com/blog/403-error-when-trying-view-svf2
function onDocumentLoadSuccess(doc) {
let items = doc.getRoot().search({
'type': 'geometry',
'role': '3d'
}, true)
let url = doc.getViewablePath(items[0])
viewer.loadModel(url, { acmSessionId: doc.getAcmSessionId(url) })
}
The best thing is to just use loadDocumentNode() instead of loadModel()

Error in viewing files in Autodesk forge viewer - error calling doc.getRootItem()

When viewing files in Autodesk forge viewer, getting the following errors,
Cannot read property ‘setEndpoint’ of undefined. Screenshot
doc.getRootItem is not a function. Screenshot
And will be able to view after empty cache and hard reload (Ctrl + Shift +R) the page. Sometimes the same errors will persist even after hard reload and clearing browser cache.
Code for the second error.
var options = {
env: 'AutodeskProduction',
accessToken: getAccessToken() //Method to get access token- no errors here
};
var documentId = 'urn:' + urn;
Autodesk.Viewing.Initializer(options, function onInitialized() {
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
//Autodesk.Viewing.Document.load - success function.
function onDocumentLoadSuccess(doc) {
setTimeout(function() {
debugger;
}, 5000);
//Error is thrown in the line below.
var viewables = Autodesk.Viewing.Document.getSubItemsWithProperties(doc.getRootItem(), {
'type': 'geometry'
}, true); //throws error on calling doc.getRootItem()
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
// Choose any of the avialble viewables
var initialViewable = viewables[0];
var svfUrl = doc.getViewablePath(initialViewable);
var modelOptions = {
sharedPropertyDbPath: doc.getPropertyDbPath()
};
var viewerDiv = document.getElementById('divViewer');
viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
viewer.start(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}
You must have unwitting upgraded to Viewer V7 with which getRootItem and several other functions have been deprecated - see here for its release notes and migration guide.
Stick with V6 with <script src="https://developer-stg.api.autodesk.com/modelderivative/v2/viewers/viewer3D.js?v=6.6"></script> - if you don't specify a version by default the latest stable version would be served which is now V7.0.

Autodesk forge viewer pdf error

I am struggling to view a pdf in the forge viewer. All other drawings .rvt .dwg .dxf .nwd are showing without any issue.
Initially I received a error
Cannot read property 'loadFromZip' of undefined
Have managed to evade this by adding "loadOptions" into the modeloptions I send through to the viewer. But now I get a error 6 back from the viewer which is a server error. Please if someone could advise what to do.
loadModel() {
var initialViewable = viewables[indexViewable];
var svfUrl = lmvDoc.getViewablePath(initialViewable);
var modelOptions = {
sharedPropertyDbPath: lmvDoc.getPropertyDbPath(),
loadOptions: {}
};
viewer.loadModel(
svfUrl,
modelOptions,
this.onLoadModelSuccess,
this.onLoadModelError
);
}
Thanks in advance
You have to use ViewingApplication rather than Viewer3D or GuiViewer3D to initialize your viewer to view PDF files since there are some additional configuration values for PDF set up by the ViewingApplication automatically.
Also refer to:
Forge Viewer fails to dispaly PDF's
=== Example for passing configs to Viewer instance via ViewingApplication ===
//--- Method 1:
var viewerConfigs = {
extensions: ['MyAwesomeExtension'],
extOpts: {
MyAwesomeExtension: {
buttonColor: 'red'
}
}
};
var viewerApp = new Autodesk.Viewing.ViewingApplication('MyViewerDiv');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, viewerConfigs);
// In the constructor of the MyAwesomeExtension
class MyAwesomeExtension extends Autodesk.Viewing.Extension {
constructor( viewer, options ) {
super( viewer, options );
// your options here
const opts = options.extOpts.MyAwesomeExtension;
}
}
//--- Method 2:
// After model was loadded,
var viewer = viewerApp.getCurrentViewer();
var extOpts = {
opt1: true
};
viewer.loadExtension( 'Autodesk.ADN.MyExtension', extOpts );
For more details, please refer:
https://developer.autodesk.com/en/docs/viewer/v2/tutorials/extensions/
https://developer.autodesk.com/en/docs/viewer/v2/tutorials/basic-application/

Add JQuery reference to custom function

I want to test calling an API in a custom function for Google Sheets. code.gs is as follows:
function TApi(input) {
var url = "https://api.nytimes.com/svc/search/v2/articlesearch.json";
url += '?' + $.param({
'api-key': "cdaa59fea5f04f6f9fd8fa551e47fdc4",
'q': "MIT"
});
$.ajax({
url: url,
method: 'GET',
}).done(function(result) {
return result;
console.log(result);
}).fail(function(err) {
throw err;
});
}
But when I call =TAPI() in a sheet cell, it returns an error ReferenceError: "$" is not defined. (line 22). I guess we need to add a link to JQuery. Does anyone know how to do this?
You can only use JQuery on client side scripts which use the HTML service. It is not available server side. There is a blurb about using it in the HTML Services Best Practices.
It's not possible. You must build either a web app or custom UI (sidebar or dialog) using HtmlService and do the processing on the client. Because your code runs on Google servers, there are no 'window' or 'document' objects. DOM and BOM are only accessible on the client.
In fact, feel free to do the following little experiment. Open your browser console (I'm using Chrome developer tools) and type in
console.log(this); //this logs global object
Here's the output
This is the 'window' object used by jQuery for navigating the DOM tree. jQuery is simply a JS library that builds on top of existing DOM manipulation methods and CSS selectors.
Next, open any GAS file, run the following function and check the Logs (Ctrl + Enter):
function test() {
Logger.log(this);
}
And here's the output.
As you can see, the global object in this context consists of Google-defined pseudo classes (GAS services).
You can use urlFetch app. Try the below snippet
function fetchURL() {
try {
var url = "https://api.nytimes.com/svc/search/v2/articlesearch.json";
url += '?api-key=cdaa59fea5f04f6f9fd8fa551e47fdc4&q=MIT';
var params = {
'method': 'get',
'contentType': 'application/json',
'muteHttpExceptions': true
}
var response = UrlFetchApp.fetch(url, params);
Logger.log(response)
} catch (e) {
Logger.log(e)
}
}