了解Autodesk Forge
通过我们的快速入门指南,了解身份验证,数据管理,文件翻译和模型渲染的基础知识。
它是什么?
Forge使公司能够利用设计和工程数据来开发定制软件应用程序以及用于制造,媒体/娱乐,建筑,工程和施工的连接工作流程。
l 直接在浏览器中查看3D模型:Viewer允许您直接在浏览器中以50多种格式嵌入,交互和检索有关设计文件的元数据,而无需安装额外的软件。
l 集中管理数据:Data Management API允许您通过A360,Fusion和对象存储服务访问您的数据。
l 将您的设计文件转换为可发挥其潜力的格式:使用模型衍生API为50种不同的行业标准格式的查看器准备文件,提取几何图形,检索元数据等等。
本教程中的内容是什么?
l 开始编码之前:创建并激活您的帐户。
l 工具:创建使用Autodesk Forge的Web应用程序所需的开发工具。
l OAuth:关于安全性和身份验证的几句话。
l 以下教程的分步教程:
2 查看您的模型:在网络上上传和展示3D模型。
2 查看BIM 360和Fusion模型:访问并在您自己的web应用程序上显示BIM 360和Fusion模型。
2 运行和调试:在本地执行代码并提示和技巧。
2 查看器扩展:将按钮和面板添加到查看器。
2 部署:AWS,Heroku和AppHarbor分步部署。
准备好开始了吗?
开始编码之前
Autodesk帐户
您的Autodesk Forge帐户是您的主要身份。
创建您的Forge帐户
进入Forge开发者门户网站,点击“注册”按钮创建一个帐户或“登录”以使用现有帐户。如果您创建了新帐户,请务必点击验证电子邮件中将发送给您的链接。
激活订阅
在使用任何付费API(例如ModelDerivative)之前,您需要激活您的试用版。 在右上角,你会看到你的名字。 点击展开菜单并转到我的订阅。 在打开的页面上,点击START FREE TRIAL。 而已。
创建一个应用
在右上角,你会看到你的名字。 点击展开菜单并转到我的应用程序。 点击“创建应用程序”按钮。
选择你要使用的API(你可以选择所有的现在)。 输入您的应用程序名称和描述,然后输入回调URL:http://localhost:3000 / api / forge / callback / oauth(本教程不会使用此回调,但这是在其他Autodesk Forge示例wink上使用的URL)
一旦你建立了一个应用程序,你将在你新创建的应用程序页面中看到一个客户端ID和客户端密码。您将在所有其他OAuth流程中使用这些流程,并且最终完成本网站上的所有其他教程!
Ø 不要分享你的客户秘密,这应该保密。
工具
本节介绍如何准备机器以使用Autodesk Forge或任何其他云API。 如果您已经有了偏好设置的IDE,则可以跳至验证。
选择你的语言:NodeJS | .NET | 转到| PHP |Java的
安装NodeJS引擎来运行你的代码。 安装NPM依赖关系管理器来安装软件包。
现在我们需要一个IDE来编写代码。 有很多选项,本教程将使用Visual Studio代码。
对于本教程,请使用所有默认安装选项。
OAuth
OAuth,尤其是OAuth2,是整个Forge平台中用于基于标记的身份验证和授权的开放标准。
两腿与三腿
了解有关双腿使用的详细信息查看您的模型教程和View BIM 360和Fusion模型教程中使用的三腿工作流程。
领域
范围是在令牌上设置的权限,该令牌可以用作该令牌的上下文。例如,具有data:read范围的令牌可以读取Forge生态系统内的数据,并可用于需要该范围的那些端点。没有这个范围的令牌将被拒绝访问这些端点。(单个端点参考页列出了所需的范围。)
范围有两个主要功能:
隐私和控制:在三足鼎立的情况下,它们充当一种机制来请求和确保以特定方式代表最终用户行事的权限。
安全性:无论是双腿还是三腿,他们都可以确保如果您失去对令牌的控制权,就不会误用它来访问不属于它的资源。
学到更多
公共和内部令牌
本教程将使用两种类型的访问令牌:public和internal。公共用于Viewer,它运行并需要客户端上的访问令牌。这种情况有一个特殊的范围:可见:读。
现在在服务器端,我们需要启用写入,所以内部将使用bucket:create,bucket:read,data:read,data:create和data:write。
不知道要遵循哪个教程?
回答这个问题:你想访问和查看的文件在哪里?
如果在您的电脑或其他地方,然后查看您的模型。如果模型在任何BIM 360(团队,设计或文档)或Fusion Team上,则查看BIM 360和Fusion模型。
查看您的模型
本教程将指导您使用以下用户界面创建Web应用程序:在左侧列出您的存储桶和对象,在右侧使用3D查看器查看它们。
要查看您的模型,您需要执行以下步骤:
创建一个服务器<<首次开发者? 你应该从这里开始眨眼
认证
上传到OSS
翻译文件
在查看器中显示
创建一个服务器
您的客户ID和密码应受到保护并保密,因为您的所有文件都将被绑定到您的帐户。 对于Web应用程序,请将其保存在服务器上。本节演示如何准备创建本地开发服务器。
创建一个新项目(NodeJS)
在你的机器上创建一个文件夹,不要使用空格并避免使用特殊字符。对于本教程,我们使用forgesample。
打开可视代码,然后进入菜单文件并选择打开(MacOS)或打开文件夹(Windows)并选择新创建的文件夹。
现在我们需要终端,进入菜单视图>>集成终端。 窗口应该出现在底部。 键入以下命令并按照步骤进行操作。 为了与其他Forge示例保持一致,在提示输入点时:使用start.js。
npm init
这将创建package.json文件,该文件定义了我们项目将使用的包。 学到更多。
安装软件包
默认情况下,NodeJS项目为空,所以我们需要使用npm install来安装一些软件包。让我们从一个基本的express服务器,用于JSON处理的body-parser,用于文件上传的Muller,当然还有Autodesk Forge开始。
Run one npminstall at a time. 一次运行一个npm安装。
npm install express --save
npm install forge-apis --save
npm install multer --save
npm install cookie-session --save
npm install body-parser –save
The --save parameterindicates that it should be saved on the package.json file. --save参数表明它应该保存在package.json文件中。
最后打开package.json,并在“脚本”中添加“start”:“node start.js”行。 现在你的文件夹应该有一个node_modules文件夹,你的package.json应该是这样的:
{
"name": "forgesample",
"version": "1.0.0",
"description": "",
"main": "start.js",
"scripts": {
"start": "node start.js",
"test": "echo \"Error: no test specified\"&& exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.2",
"cookie-session": "^2.0.0-beta.3",
"express": "^4.16.2",
"forge-apis": "^0.4.1",
"multer": "^1.3.0"
}
}
The version number (e.g.forge-apis 0.4.1) may vary, this was the latest version when tutorial wascreated. 版本号(例如forge-apis 0.4.1)可能会有所不同,这是创建教程时的最新版本。
文件和文件夹
要创建新文件夹或文件,请右键单击左侧的“资源管理器”区域,然后选择新建文件夹或新建文件。
为了与其他Forge示例保持一致,请为所有服务器端文件创建一个/ server /文件夹,为所有客户端文件创建一个/ www /。
在这一点上,你的项目应该是这样的:
file:///C:/TEMP/msohtmlclip1/01/clip_image002.jpg
launch.json
这个文件向VisualCode指出我们应该如何运行我们的项目。 转到菜单Debug >> AddConfiguration ...,然后在顶部出现的Select Environment小窗口上选择NodeJS,并在创建的/.vscode/launch.json文件中输入以下内容:
Note you need to enter your ForgeClient ID & Secret at theindicated space. 请注意,您需要在指定的位置输入您的Forge客户ID和密码。
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Program", "program": "${workspaceFolder}/start.js", "env": { "FORGE_CLIENT_ID": "your id here", "FORGE_CLIENT_SECRET": "your secret here", "FORGE_CALLBACK_URL": "http://localhost:3000/api/forge/callback/oauth" } } ]}
It's important to define ID & Secret as environment variables so our project can, later, bedeployed online. More on this later, on Deployment. 将ID和Secret定义为环境变量非常重要,这样我们的项目可以稍后在线部署。 稍后将在部署上详细介绍。
start.js
在根文件夹中,使用以下命令创建/start.js文件:
File names are case-sensitive for somedeployments, like Heroku. For this tutorial, let's use lower-case. 文件名对于某些部署区分大小写,如Heroku。 对于本教程,我们使用小写。
'use strict'; var app = require('./server/server'); // start servervar server = app.listen(app.get('port'), function () { if (process.env.FORGE_CLIENT_ID == null || process.env.FORGE_CLIENT_SECRET == null) console.log('*****************\nWARNING: Forge Client ID & Client Secret not defined as environment variables.\n*****************'); console.log('Starting at ' + (new Date()).toString()); console.log('Server listening on port ' + server.address().port);});
这个文件的目的是确保我们运行的服务器是我们所期望的。 稍后再说。
server.js
现在,在/ server /文件夹下,创建一个名为server.js的文件:
'use strict';
var express =require('express');
var app = express();
// prepare server routing
app.use('/', express.static(__dirname + '/../www')); // redirect static calls
app.set('port', process.env.PORT || 3000); // main port
// cookie-based session
var cookieSession =require('cookie-session')
app.use(cookieSession({
name:'forgesession',
keys:['forgesecurekey'],
secure
process.env.NODE_ENV == 'production'),
maxAge:14 * 24 * 60 * 60 * 1000 // 14 days, same as refresh token
}))
// prepare our API endpoint routing
loadRoute('./oauthtoken');
// viewmodels sample
loadRoute('./oss');
loadRoute('./modelderivative');
// view hub models sample
loadRoute('./datamanagement');
loadRoute('./user');
function loadRoute(path) {
try {
require.resolve(path);
var m = require(path);
app.use('/', m);
} catch (e) { }
}
module.exports = app;
此文件启动快速服务器并提供静态文件(例如html)并路由API请求。
config.js
在/ server /下创建一个名为config.js的文件,其中包含以下内容:
'use strict';
// Autodesk Forge configuration
module.exports = {
// set environment variables or hard-code here
credentials: {
client_id: process.env.FORGE_CLIENT_ID,
client_secret: process.env.FORGE_CLIENT_SECRET,
callback_url: process.env.FORGE_CALLBACK_URL
},
// Required scopes for your application on server-side
scopeInternal: ['bucket:create', 'bucket:read', 'data:read','data:create', 'data:write'],
// Required scope of the token sent to the client
scopePublic: ['viewables:read']
};
我们在这里定义ENV变量,在运行我们的Express服务器时,这些变量的值将用于连接我们需要的不同Autodesk Forge服务。
最后我们看到有两个关于范围的定义。 内部范围为我们的访问令牌提供了使用ForgeWeb服务(服务器端)的不同服务的正确权限。 本教程致力于使用查看器,我们只需要公开的“可查看:读取”范围。
项目已准备就绪! 此时你的项目应该有:
file:///C:/TEMP/msohtmlclip1/01/clip_image003.png
package-lock.json是由Visual Code创建的,不用担心。
OAuth 2腿
在正式的OAuth术语中,要在Forge平台上完成双重身份验证,需要使用“客户端证书”授予类型。
这意味着您的应用程序直接与Forge平台进行通信以进行身份验证和访问资源。如果它是一个Web应用程序,最终用户不会直接意识到这些服务器到服务器之间的通信,因为它们都没有通过Web浏览器传递。 学到更多。
访问Forge上的任何资源都需要身份验证。 双腿令牌授予访问您的应用程序信息的权限。
验证(NodeJS)
对于基本的OAuth实现,我们需要2个文件。
oauthtoken.js
创建一个/server/oauthtoken.js文件。 该文件负责创建快速路由器以公开端点。
'use strict';
// web framework
var express =require('express');
var router =express.Router();
// Forge NPM
var forgeSDK =require('forge-apis');
// actually perform the token operation
var oauth = require('./oauth');
// Endpoint to return a 2-legged access token
router.get('/api/forge/oauth/token', function (req, res) {
oauth.getTokenPublic().then(function (credentials) {
res.json({ access_token: credentials.access_token, expires_in:credentials.expires_in });
}).catch(function (error) {
console.log('Error at OAuth Token:');
console.log(error);
res.status(500).json(error);
});
});
module.exports = router;
oauth.js
现在创建一个/server/oauth.js文件,它实际上会向Forge请求访问令牌。 这将在本教程的其他部分重复使用。
'use strict';
// Forge NPM
var forgeSDK =require('forge-apis');
// Forge config information, such as client IDand secret
var config =require('./config');
// Cache of the access tokens
var _cached = [];
module.exports = {
getTokenPublic:function () {
return this.OAuthRequest(config.scopePublic, 'public');
},
getTokenInternal: function () {
return this.OAuthRequest(config.scopeInternal, 'internal');
},
OAuthRequest: function (scopes, cache) {
var client_id = config.credentials.client_id;
var client_secret =config.credentials.client_secret;
var forgeOAuth = this.OAuthClient(scopes);
return new Promise(function (resolve, reject) {
if (_cached[cache] != null && _cached[cache].expires_at > (new Date()).getTime()) {
resolve(_cached[cache]);
return;
}
var client_id =config.credentials.client_id;
var client_secret = config.credentials.client_secret;
//new forgeSDK.AuthClientTwoLegged(client_id,client_secret, scopes);
forgeOAuth.authenticate()
.then(function (credentials) {
_cached[cache] =credentials;
var now = new Date();
_cached[cache].expires_at =(now.setSeconds(now.getSeconds() + credentials.expires_in));
resolve(_cached[cache]);
})
.catch(function (error) {
console.log('Error at OAuthAuthenticate:');
console.log(error);
reject(error)
});
})
},
OAuthClient: function(scopes) {
var client_id = config.credentials.client_id;
var client_secret =config.credentials.client_secret;
if (scopes == undefined) scopes =config.scopeInternal;
return new forgeSDK.AuthClientTwoLegged(client_id, client_secret, scopes);
}
}
为了避免为每个最终用户请求获取新的访问令牌,这会增加不必要的延迟,我们将它们缓存在全局变量中。 请注意,我们仍然需要在expires_in秒后刷新它
在用户之间共享访问令牌仅在这种情况下有效,其中所有用户都访问相同的信息(双腿)。如果您的应用使用的是每用户数据(3段),请勿使用此方法。
数据管理(OSS)
在OSS中,文件以桶形式存储为对象。 除了为您的应用程序提供从更广泛的Forge生态系统下载数据的功能外,它还提供了管理应用程序自己的存储桶和对象(包括创建,列出,删除,上传和下载)的功能。
每个存储桶还具有确定对象保留时间的保留策略:
l 瞬态:类似高速缓存的存储只持续24小时,对于短暂物体很理想。 对于本教程,让我们使用这个策略。
l 临时:保存30天的存储。
l 持久性:存储在删除之前一直存在。
在本节中,让我们创建几个端点来创建存储桶,上传文件和列出存储桶和对象。
上传文件到OSS(NodeJS)
在这一部分,我们实际上需要3个特征:
1. 创建桶
2. 列出存储桶和对象(文件)
3. 上传对象(文件)
oss.js
使用以下内容创建/server/oss.js文件:
'use strict'; // web frameworkvar express = require('express');var router = express.Router(); // Forge NPMvar forgeSDK = require('forge-apis'); // handle json requestsvar bodyParser = require('body-parser');var jsonParser = bodyParser.json(); // actually perform the token operationvar oauth = require('./oauth'); // Return list of buckets (id=#) or list of objects (id=bucketKey)router.get('/api/forge/oss/buckets', function (req, res) { var id = req.query.id; if (id === '#') { // root // in this case, let's return all buckets var bucketsApi = new forgeSDK.BucketsApi(); oauth.getTokenInternal().then(function (credentials) { bucketsApi.getBuckets({ limit: 100 }, oauth.OAuthClient(), credentials).then(function (buckets) { var list = []; buckets.body.items.forEach(function (bucket) { list.push({ id: bucket.bucketKey, text: bucket.bucketKey, type: 'bucket', children: true }) }) res.json(list); }); }).catch(function (error) { console.log('Error at Get Buckets:'); console.log(error); res.status(500).json(error); }); } else { // as we have the id (bucketKey), let's return all objects var objectsApi = new forgeSDK.ObjectsApi(); oauth.getTokenInternal().then(function (credentials) { objectsApi.getObjects(id, {}, oauth.OAuthClient(), credentials).then(function (objects) { var list = []; objects.body.items.forEach(function (object) { list.push({ id: object.objectId.toBase64(), text: object.objectKey, type: 'object', children: false }) }) res.json(list); }); }).catch(function (error) { console.log('Error at Get Objects:'); console.log(error); res.status(500).json(error); }); }}); // Create a new bucket router.post('/api/forge/oss/buckets', jsonParser, function (req, res) { oauth.getTokenInternal().then(function (credentials) { var bucketsApi = new forgeSDK.BucketsApi(); var postBuckets = new forgeSDK.PostBucketsPayload(); postBuckets.bucketKey = req.body.bucketKey; postBuckets.policyKey = "transient"; // expires in 24h bucketsApi.createBucket(postBuckets, {}, oauth.OAuthClient(), credentials).then(function (buckets) { res.status(200).end(); }).catch(function (error) { if (error.statusCode && error.statusCode == 409) res.status(409).end(); else { console.log('Error at OSS Create Bucket:'); console.log(error); res.status(500).json(error); } }); });}); // handle file uploadvar multer = require('multer')var upload = multer({ dest: './tmp' }) // Receive a file from the client and upload to the bucketrouter.post('/api/forge/oss/objects', upload.single('fileToUpload'), function (req, res) { oauth.getTokenInternal().then(function (credentials) { var bucketKey = req.body.bucketKey; var fs = require('fs'); fs.readFile(req.file.path, function (err, filecontent) { var objects = new forgeSDK.ObjectsApi(); objects.uploadObject(bucketKey, req.file.originalname, filecontent.length, filecontent, {}, oauth.OAuthClient(), credentials) .then(function (object) { res.end(); }).catch(function (error) { console.log('Error at Upload Object:'); console.log(error); res.status(500).end(); }); }) });}); String.prototype.toBase64 = function () { return new Buffer(this).toString('base64');}; module.exports = router;当我们计划支持jsTree时,我们的GEToss / buckets需要返回句柄id querystring参数,并在id =#时返回桶,并且给定bucketKey的对象作为id = bucketKey传递。 上传端点使用Muller包来处理文件上传。它将文件保存在我们的服务器上(例如在/ tmp /文件夹下),以便稍后上传到伪造文件。
注意我们如何重用/server/oauth.js文件在所有函数上调用.getTokenInternal()。
可以将客户端(浏览器)上的文件直接上传到Autodesk Forge,但需要向客户端提供一个写入启用的访问令牌,该令牌不是安全的。
翻译文件
模型衍生API使用户能够以不同的格式表示和共享他们的设计,并提取有价值的元数据。
在这一节中,让我们调用POST Job开始翻译过程。 请注意,此端点是异步的,并启动在后台运行的进程,而不是保持打开的HTTP连接直到完成。
翻译模型(NodeJS)
要翻译一个文件,我们只需要一个端点。
modelderivative.js
使用以下内容创建/server/modelderivative.js文件:
'use strict'; // web frameworkvar express = require('express');var router = express.Router(); // Forge NPMvar forgeSDK = require('forge-apis'); // handle json requestsvar bodyParser = require('body-parser');var jsonParser = bodyParser.json(); // actually perform the token operationvar oauth = require('./oauth'); // Create a new bucket router.post('/api/forge/modelderivative/jobs', jsonParser, function (req, res) { oauth.getTokenInternal().then(function (credentials) { // prepare the translation job payload var postJob = new forgeSDK.JobPayload(); postJob.input = new forgeSDK.JobPayloadInput(); postJob.input.urn = req.body.objectName; postJob.output = new forgeSDK.JobPayloadOutput( [new forgeSDK.JobSvfOutputPayload()] ); postJob.output.formats[0].type = 'svf'; postJob.output.formats[0].views = ['2d', '3d']; // create the derivative API var derivativesApi = new forgeSDK.DerivativesApi(); // post the job derivativesApi.translate(postJob, {}, oauth.OAuthClient(), credentials) .then(function (data) { res.status(200).end(); }).catch(function (e) { console.log('Error at Model Derivative job:'); console.log(e); res.status(500).json({ error: e.error.body }) }); });}); module.exports = router;
作业端点接收bucketKey和objectName并发布翻译作业以提取模型的2D和3D视图。
总结一下,在这一点上你的NodeJS项目应该是这样的:
file:///C:/TEMP/msohtmlclip1/01/clip_image004.png
查看器
Viewer是一个客户端库,因此是纯HTML5和JavaScript。 但是每个服务器端实现都有一些提示:
客户端文件(NodeJS)
我们的NodeJS服务器被配置为从/www /文件夹提供文件。 让我们这样组织吧:
l / www /:.html
l / www / js:.js
l / www / css:.css
下图显示了它(在下一节创建文件之后)
file:///C:/TEMP/msohtmlclip1/01/clip_image005.png
查看器(客户端)
让我们在客户端创建我们需要的4个文件:
index.html
这是您的应用的入口点。 对于此示例,我们将使用jQuery进行DOM操作,使用Bootstrap进行样式设置,并使用jsTree列出存储桶和对象。 所有这些图书馆都来自CDN(内容交付网络)。
当然,还有Autodesk Forge查看器库:viewer3d.min.js,three.min.js和style.min.css。
创建一个index.html文件:
<!DOCTYPE html><html><head> <title>Autodesk Forge Tutorial</title> <meta charset="utf-8" /> <!-- Common packages: jQuery, Bootstrap, jsTree --> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" /> <!-- Autodesk Forge Viewer files --> <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/style.min.css?v=v4.0" type="text/css"> <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/three.min.js"></script> <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/viewer3D.min.js?v=v4.0"></script> <!-- this project files --> <link href="css/main.css" rel="stylesheet" /> <script src="js/ForgeTree.js"></script> <script src="js/ForgeViewer.js"></script></head><body> <!-- Fixed navbar by Bootstrap: https://getbootstrap.com/examples/navbar-fixed-top/ --> <nav class="navbar navbar-default navbar-fixed-top"> <div class="container-fluid"> <ul class="nav navbar-nav left"> <li> <a href="http://developer.autodesk.com" target="_blank"> <img alt="Autodesk Forge" src="//developer.static.autodesk.com/images/logo_forge-2-line.png" height="20"> </a> </li> </ul> </div> </nav> <!-- End of navbar --> <div class="container-fluid fill"> <div class="row fill"> <div class="col-sm-4 fill"> <div class="panel panel-default fill"> <div class="panel-heading" data-toggle="tooltip"> Buckets & Objects <span id="refreshBuckets" class="glyphicon glyphicon-refresh" style="cursor: pointer"></span> <button class="btn btn-xs btn-info" style="float: right" id="showFormCreateBucket" data-toggle="modal" data-target="#createBucketModal"> <span class="glyphicon glyphicon-folder-close"></span> New bucket </button> </div> <div id="appBuckets"> tree here </div> </div> </div> <div class="col-sm-8 fill"> <div id="forgeViewer"></div> </div> </div> </div> <form id="uploadFile" method='post' enctype="multipart/form-data"> <input id="hiddenUploadField" type="file" name="theFile" style="visibility:hidden" /> </form> <!-- Modal Create Bucket --> <div class="modal fade" id="createBucketModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Cancel"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title" id="myModalLabel">Create new bucket</h4> </div> <div class="modal-body"> <input type="text" id="newBucketKey" class="form-control"> For demonstration purposes, objects (files) are NOT automatically translated. After you upload, right click on the object and select "Translate". </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-primary" id="createNewBucket">Go ahead, create the bucket</button> </div> </div> </div> </div></body></html>
main.css
CSS是一种描述HTML文档样式的语言。在W3Schools了解更多信息。 对于本教程,使用以下命令在css文件夹下创建一个main.css:
html, body { min-height: 100%; height: 100%;} .fill { height: calc(100vh - 100px);} body { padding-top: 60px; /* space for the top nav bar */ margin-right: 30px;} #appBuckets { overflow: auto; width: 100%; height: calc(100vh - 150px);} #forgeViewer { width: 100%;}
ForgeTree.js
该文件将处理列出您所有存储桶的树视图。 在js文件夹下,使用以下内容创建一个ForgeTree.js文件:
$(document).ready(function () {
prepareAppBucketTree();
$('#refreshBuckets').click(function () {
$('#appBuckets').jstree(true).refresh();
});
$('#createNewBucket').click(function () {
createNewBucket();
});
$('#createBucketModal').on('shown.bs.modal', function () {
$("#newBucketKey").focus();
})
});
function createNewBucket() {
var bucketKey = $('#newBucketKey').val();
var policyKey = $('#newBucketPolicyKey').val();
jQuery.post({
url:'/api/forge/oss/buckets',
contentType: 'application/json',
data:JSON.stringify({ 'bucketKey': bucketKey, 'policyKey': policyKey }),
success: function(res) {
$('#appBuckets').jstree(true).refresh();
$('#createBucketModal').modal('toggle');
},
error: function (err) {
if (err.status == 409)
alert('Bucket already exists - 409: Duplicated')
console.log(err);
}
});
}
functionprepareAppBucketTree() {
$('#appBuckets').jstree({
'core':{
'themes': { "icons": true },
'data': {
"url": '/api/forge/oss/buckets',
"dataType": "json",
'multiple': false,
"data": function (node) {
return { "id": node.id };
}
}
},
'types': {
'default': {
'icon': 'glyphicon glyphicon-question-sign'
},
'#':{
'icon': 'glyphicon glyphicon-cloud'
},
'bucket': {
'icon': 'glyphicon glyphicon-folder-open'
},
'object': {
'icon': 'glyphicon glyphicon-file'
}
},
"plugins": ["types", "state","sort", "contextmenu"],
contextmenu: { items: autodeskCustomMenu }
}).on('loaded.jstree', function () {
$('#appBuckets').jstree('open_all');
}).bind("activate_node.jstree", function (evt, data) {
if (data != null && data.node != null && data.node.type == 'object') {
$("#forgeViewer").empty();
var urn = data.node.id;
getForgeToken(function (access_token) {
jQuery.ajax({
url: 'https://developer.api.autodesk.com/modelderivative/v2/designdata/'+ urn + '/manifest',
headers: { 'Authorization': 'Bearer ' + access_token },
success: function(res) {
if (res.status ==='success') launchViewer(urn);
else$("#forgeViewer").html('The translation job still running: ' +res.progress + '. Please try again in a moment.');
},
error: function (err) {
var msgButton = 'This fileis not translated yet! ' +
'<button class="btn btn-xsbtn-info"><spanclass="glyphicon glyphicon-eye-open"></span> ' +
'Start translation</button>'
$("#forgeViewer").html(msgButton);
}
});
})
}
});
}
functionautodeskCustomMenu(autodeskNode) {
var items;
switch (autodeskNode.type) {
case "bucket":
items= {
uploadFile: {
label: "Upload file",
action: function() {
var treeNode = $('#appBuckets').jstree(true).get_selected(true)[0];
uploadFile(treeNode);
},
icon: 'glyphicon glyphicon-cloud-upload'
}
};
break;
case "object":
items= {
translateFile: {
label: "Translate",
action: function() {
var treeNode =$('#appBuckets').jstree(true).get_selected(true)[0];
translateObject(treeNode);
},
icon: 'glyphicon glyphicon-eye-open'
}
};
break;
}
return items;
}
function uploadFile(node) {
$('#hiddenUploadField').click();
$('#hiddenUploadField').change(function () {
if (this.files.length == 0) return;
var file = this.files[0];
switch (node.type) {
case 'bucket':
var formData = new FormData();
formData.append('fileToUpload', file);
formData.append('bucketKey', node.id);
$.ajax({
url: '/api/forge/oss/objects',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function(data) {
$('#appBuckets').jstree(true).refresh_node(node);
}
});
break;
}
});
}
functiontranslateObject(node) {
$("#forgeViewer").empty();
if (node == null) node = $('#appBuckets').jstree(true).get_selected(true)[0];
var bucketKey = node.parents[0];
var objectKey = node.id;
jQuery.post({
url:'/api/forge/modelderivative/jobs',
contentType: 'application/json',
data:JSON.stringify({ 'bucketKey': bucketKey, 'objectName': objectKey }),
success: function(res) {
$("#forgeViewer").html('Translation started! Please try againin a moment.');
},
});
}
ForgeViewer.js
现在这个文件将处理Viewer初始化。 以下代码基于Autodesk Forge Viewer基本应用程序。 在js文件夹下,使用以下命令创建一个ForgeViewer.js文件:
var viewerApp; function launchViewer(urn) { var options = { env: 'AutodeskProduction', getAccessToken: getForgeToken }; var documentId = 'urn:' + urn; Autodesk.Viewing.Initializer(options, function onInitialized() { viewerApp = new Autodesk.Viewing.ViewingApplication('forgeViewer'); viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D); viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure); });} function onDocumentLoadSuccess(doc) { // We could still make use of Document.getSubItemsWithProperties() // However, when using a ViewingApplication, we have access to the **bubble** attribute, // which references the root node of a graph that wraps each object from the Manifest JSON. var viewables = viewerApp.bubble.search({ 'type': 'geometry' }); if (viewables.length === 0) { console.error('Document contains no viewables.'); return; } // Choose any of the available viewables viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail);} function onDocumentLoadFailure(viewerErrorCode) { console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);} function onItemLoadSuccess(viewer, item) { // item loaded, any custom action?} function onItemLoadFail(errorCode) { console.error('onItemLoadFail() - errorCode:' + errorCode);} function getForgeToken(callback) { jQuery.ajax({ url: '/api/forge/oauth/token', success: function (res) { callback(res.access_token, res.expires_in) } });}
总结一下:在用户界面你的应用应该有4个文件:
l index.html
l main.css
l ForgeTree.js
l ForgeViewer.js
可以了,好了? 现在是时候运行应用程序了!
本地运行和调试
现在你的应用程序已准备就绪,是时候运行了。 这是我们可以测试并检查可能的错误的地方(通过调试)。 并检查提示和技巧。
使用样本
下一节将向您展示如何运行您的应用程序。 当它在浏览器上打开时,点击New Bucket创建您的存储桶(该名称在所有Forge帐户中应该是唯一的)。 右键单击新创建的存储桶并选择上传文件(这会触发OSS上传过程)。然后展开桶树节点并右键单击该文件,选择Translate(这将触发模型微分作业)。 一会儿你的文件应该准备好了,再次点击该文件在查看器上显示它。
运行和调试(NodeJS)
转到菜单调试并选择开始调试。 “调试控制台”选项卡应显示在底部,如下所示:
file:///C:/TEMP/msohtmlclip1/01/clip_image007.png
打开浏览器并转到http://localhost:3000
查看器扩展
扩展提供了一种机制来编写与查看器交互的自定义代码。 每个扩展应该向扩展管理器注册自己,提供一个唯一的字符串ID,然后用它在运行时加载或卸载扩展。 学到更多。
本教程将指导您为Viewer创建一个扩展。
对于本教程,您需要使用Viewer的应用程序,例如查看您的模型或查看BIM 360和Fusion模型教程。 无论文件托管在何处,查看器都是一样的。
准备开始编码?