├── .gitignore ├── LICENSE.md ├── README.md ├── assets └── images │ └── forgeVuerLogo.png ├── build └── rollup.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── sample └── index.html └── src ├── ForgeVuer.vue ├── extensions ├── myAwesomeExtension.js └── myCustomToolbar.js ├── index.js └── services ├── Utils.js └── ViewerService.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,vuejs 3 | # Edit at https://www.gitignore.io/?templates=node,vuejs 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # Optional npm cache directory 48 | .npm 49 | 50 | # Optional eslint cache 51 | .eslintcache 52 | 53 | # Optional REPL history 54 | .node_repl_history 55 | 56 | # Output of 'npm pack' 57 | *.tgz 58 | 59 | # Yarn Integrity file 60 | .yarn-integrity 61 | 62 | # dotenv environment variables file 63 | .env 64 | .env.test 65 | 66 | # parcel-bundler cache (https://parceljs.org/) 67 | .cache 68 | 69 | # next.js build output 70 | .next 71 | 72 | # nuxt.js build output 73 | .nuxt 74 | 75 | # vuepress build output 76 | .vuepress/dist 77 | 78 | # Serverless directories 79 | .serverless/ 80 | 81 | # FuseBox cache 82 | .fusebox/ 83 | 84 | # DynamoDB Local files 85 | .dynamodb/ 86 | 87 | ### Vuejs ### 88 | node_modules 89 | .DS_Store 90 | docs/_book 91 | test/ 92 | 93 | dist/ 94 | 95 | #VSCode 96 | .vs 97 | .vscode 98 | 99 | # End of https://www.gitignore.io/api/node,vuejs -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Released under MIT License 2 | 3 | Copyright (c) 2019 Alvaro Ortega Pickmans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![ForgeVuer](assets/images/forgeVuerLogo.png) 2 | # ForgeVuer 3 | 4 | A Vue.js component providing an easy to setup, almost *"plug and play"* experience for Autodesk's Forge Viewer on Vue.js 5 | 6 | - [Getting Started](#getting-started) 7 | - [Prerequisites](#prerequisites) 8 | - [Installing](#installing) 9 | - [TL;DR](#tldr) 10 | - [Setup](#setup) 11 | - [Access Token](#access-token) 12 | - [Properties](#properties) 13 | - [Events](#events) 14 | - [Forge Viewer Events](#forge-viewer-events) 15 | - [ForgeVuer Events](#forgevuer-events) 16 | - [Custom Extensions](#custom-extensions) 17 | - [Versioning](#versioning) 18 | - [License](#license) 19 | 20 | ## Getting Started 21 | 22 | These instructions will get you started on how to install, use and customize the **ForgeVuer** component. 23 | 24 | ### Prerequisites 25 | 26 | - A minimal **Vue** app to use the component. 27 | - The latest Autodesk Forge Viewer **version 7** styling and javascript files referenced on the html `head` section. 28 | 29 | ```html 30 | 31 | [...] 32 | 33 | 34 | 35 | [...] 36 | 37 | ``` 38 | 39 | ### Installing 40 | ``` 41 | npm install forge-vuer 42 | ``` 43 | 44 | ## TL;DR 45 | 46 | A minimal working setup on a SPA application: 47 | 48 | ```html 49 | 50 | 58 | 59 | 87 | ``` 88 | 89 | ## Setup 90 | 91 | Nevertheless, it requires some level of setup in order to have a secure and stable experience. 92 | 93 | ### Access Token 94 | 95 | Forge Viewer requires to be associated to a valid Forge Application, and this is achieved by the use of an **access token** retrieved using the application's **CLIENT_SECRET** and **CLIENT_ID** credentials. 96 | 97 | These credentials **MUST NOT** be exposed on the front-end as: 98 | - Entails a security risk for your Forge Application. 99 | - Making calls to Forge API from the front-end will likely return a **Cross Origin** error. 100 | 101 | Instead, a backend service should be implemented so it securely returns a valid token and expiring time. An example of an endpoint for this purpose using **Express.js** and **Axios**: 102 | 103 | ```javascript 104 | // Backend API 105 | let app = new Express(); 106 | 107 | app.use("/api/token", async (req, res, next) => { 108 | return axios.post( 109 | "https://developer.api.autodesk.com/authentication/v1/authenticate", 110 | { 111 | client_id: "YOUR CLIENT_ID", 112 | client_secret: "YOUR CLIENT_SECRET", 113 | grant_type: "client_credentials&", 114 | scopes: "data:read" 115 | }); 116 | }); 117 | ``` 118 | ```html 119 | 120 | 128 | 129 | 150 | ``` 151 | 152 | 153 | ## Properties 154 | The component has some properties to configure and customize it. 155 | 156 | | Prop | Type | Default | Required | Description | 157 | | ---------------- | ---------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 158 | | `id` | `String` | `forge-vuer` | `false` | This defines the `id` attribute of the DOM element that will host the Viewer | 159 | | `getAccessToken` | `Function` | - | `true` | Function that will provide a valid access token to the Viewer by calling the `onSuccess` callback. | 160 | | `urn` | `String` | - | `false` | Urn of the file to load. Make sure the file has already been [translated](https://forge.autodesk.com/en/docs/model-derivative/v2/tutorials/prepare-file-for-viewer/). | 161 | | `options` | `Object` | - | `false` | Options used to [initialize](https://forge.autodesk.com/en/docs/viewer/v6/reference/Viewing/Initializer/#new-initializer-options-callback) the Viewer instance. The only property that will not be used is `getAccessToken`, as it is replace by the corresponding function passed as a component's property. | 162 | | `headless` | `Boolean` | `false` | `false` | This property defines if the viewer is meant to be use in [headless](https://forge.autodesk.com/en/docs/viewer/v6/tutorials/headless/) mode. | 163 | | `extensions` | `Object` | - | `false` | Object containing the custom extensions. See [custom extensions](#custom-extensions) for more detail. | 164 | 165 | 166 | 167 | ## Events 168 | The component exposes two types of events to which can be subscribed: original Forge Viewer Events and Custom Events. 169 | 170 | ### Forge Viewer Events 171 | 172 | As described on Forge Viewer [API documentation](https://autodeskviewer.com/viewers/latest/docs/Autodesk.Viewing.html#events), the viewer provides several events like `SELECTION_CHANGED_EVENT`, `PROGRESS_UPDATE_EVENT`, etc. The component allows to seamlessly subscribe to these event using the familiar vue syntax `v-on:` or `@` by the convention: 173 | - Same name of original event but all lower cased. 174 | - Underscores `_` replaced by hyphens/dashes `-`. 175 | 176 | As an example: 177 | 178 | | Original Event | Subscribed on component | 179 | | ------------------------- | ------------------------- | 180 | | `SELECTION_CHANGED_EVENT` | `@selection-change-event` | 181 | | `PROGRESS_UPDATE_EVENT` | `@progress-update-event` | 182 | 183 | Internally, on creation it will try to map the component's events to the corresponding on the Viewer, providing an easy interface to subscribe to any original event. 184 | Any data associated that an event might return is encapsulated on a single object to allow for an automated mapping. This means that your subscribing function will have a single input argument containing all parameters passed by the event. 185 | 186 | ```html 187 | 188 | 196 | 197 | 212 | ``` 213 | 214 | 215 | ### ForgeVuer Events 216 | Additionally, the component provides some additional events that allows to act when certain actions happen during the component's execution. 217 | 218 | | Name | Arguments | Description | 219 | | ------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 220 | | `error` | `Error` | This event is fired whenever any error that hasn't been handle in any other way (internally by Forge emitting their events or some other of these custom events). When fired, this event will have as input the actual error that has been thrown. | 221 | | `documentLoading` | - | Event fired when a new `urn` has been provided and the process of loading its associated document starts. | 222 | | `documentLoadError` | `Error` | Fired when Forge fails to load a document. If no function is subscribed to this event, the default `Error` event will be thrown. The `Error` passed as argument contains the Forge `errorCode` reference.* | 223 | | `viewerStarted` | `Viewer3D` instance | Event fired when the Viewer3D has been initialized, passing this instance as function argument. | 224 | | `modelLoading` | - | Fired when the model associated with the document starts to load. | 225 | | `modelLoaded` | `model` | Fired when the model is successfully loaded. The argument is a [Model](https://forge.autodesk.com/en/docs/viewer/v6/reference/Viewing/Model/) instance. | 226 | | `modelLoadError` | `Error` | Fired when Forge fails to load a model. If no function is subscribed to this event, the default `Error` event will be thrown. The `Error` passed as argument contains the Forge `errorCode` reference.* | 227 | 228 | > *For a detailed list of Forge ErrorCodes and their meaning, visit [this blog post](https://forge.autodesk.com/cloud_and_mobile/2016/01/error-codes-in-view-and-data-api.html) 229 | 230 | ## Custom Extensions (6.*) 231 | 232 | One of the most powerful features of Autodesk Forge Viewer is the ability to add custom functionality via **Extensions**. Registering custom extensions to the component's Viewer instance can be done just through the `extensions` component property. The only difference with the common [examples](https://forge.autodesk.com/en/docs/viewer/v6/tutorials/extensions/) found is that the extension implementation must be wrapped within a function so the component can register them at runtime. 233 | 234 | This would be a simple example of custom extension: 235 | ```js 236 | // Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/extensions/#step-2-write-the-extension-code 237 | // my-awesome-extension.js 238 | 239 | export default function (AutodeskViewing) { 240 | 241 | function MyAwesomeExtension(viewer, options) { 242 | AutodeskViewing.Extension.call(this, viewer, options); 243 | } 244 | 245 | MyAwesomeExtension.prototype = Object.create(AutodeskViewing.Extension.prototype); 246 | MyAwesomeExtension.prototype.constructor = MyAwesomeExtension; 247 | 248 | MyAwesomeExtension.prototype.load = function () { 249 | alert('MyAwesomeExtension is loaded!'); 250 | return true; 251 | }; 252 | 253 | MyAwesomeExtension.prototype.unload = function () { 254 | alert('MyAwesomeExtension is now unloaded!'); 255 | return true; 256 | }; 257 | 258 | // Is not necessary to implicitly register the extension 259 | // as this is handled by the component. 260 | // Autodesk.Viewing.theExtensionManager.registerExtension('MyAwesomeExtension', MyAwesomeExtension); 261 | 262 | // IMPORTANT to return the extension function itself. 263 | return MyAwesomeExtension; 264 | 265 | } 266 | ``` 267 | 268 | If you are comfortable and able to use ES6 classes, an extension could also be written as: 269 | ```js 270 | // Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/toolbar-button/#step-1-detect-the-toolbar 271 | // my-custom-toolbar.js 272 | 273 | export default function (AutodeskViewing) { 274 | 275 | return class ToolbarExtension extends AutodeskViewing.Extension { 276 | viewer; 277 | options; 278 | subToolbar; 279 | 280 | constructor(viewer, options) { 281 | super(viewer, options); 282 | this.viewer = viewer; 283 | this.options = options; 284 | } 285 | 286 | load = function () { 287 | 288 | if (this.viewer.toolbar) { 289 | // Toolbar is already available, create the UI 290 | this.createUI(); 291 | } else { 292 | // Toolbar hasn't been created yet, wait until we get notification of its creation 293 | this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this); 294 | this.viewer.addEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 295 | } 296 | 297 | return true; 298 | } 299 | 300 | unload = function () { 301 | this.viewer.toolbar.removeControl(this.subToolbar); 302 | return true; 303 | }; 304 | 305 | onToolbarCreated = function() { 306 | this.viewer.removeEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 307 | this.onToolbarCreatedBinded = null; 308 | this.createUI(); 309 | }; 310 | 311 | createUI = function() { 312 | var viewer = this.viewer; 313 | 314 | // Button 1 315 | var button1 = new AutodeskViewing.UI.Button('my-view-front-button'); 316 | button1.onClick = function() { 317 | viewer.setViewCube('front'); 318 | }; 319 | button1.addClass('my-view-front-button'); 320 | button1.setToolTip('View front'); 321 | 322 | // Button 2 323 | var button2 = new AutodeskViewing.UI.Button('my-view-back-button'); 324 | button2.onClick = function() { 325 | viewer.setViewCube('back'); 326 | }; 327 | button2.addClass('my-view-back-button'); 328 | button2.setToolTip('View Back'); 329 | 330 | // SubToolbar 331 | this.subToolbar = new AutodeskViewing.UI.ControlGroup('my-custom-view-toolbar'); 332 | this.subToolbar.addControl(button1); 333 | this.subToolbar.addControl(button2); 334 | 335 | viewer.toolbar.addControl(this.subToolbar); 336 | }; 337 | } 338 | 339 | } 340 | ``` 341 | 342 | Then, on the component implementation we just need to set the `extension` property as an object where `keys` will be the registered `id` of the extensions, and the values the imported functions. 343 | 344 | ```html 345 | 346 | 356 | 357 | 366 | ``` 367 | 368 | ## Custom Extensions (7.*) 369 | 370 | There has been [breaking changes](https://forge.autodesk.com/blog/breaking-change-forge-viewerloadextension) since 6.*. Also, you need [CSS classes](https://forge.autodesk.com/blog/what-icons-are-provided-viewer-stylesheet) to set the icon of the buttons. 371 | 372 | ```js 373 | // Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/toolbar-button/#step-1-detect-the-toolbar 374 | // my-custom-toolbar.js 375 | 376 | export default function (AutodeskViewing) { 377 | 378 | return class ToolbarExtension extends AutodeskViewing.Extension { 379 | viewer; 380 | options; 381 | subToolbar; 382 | 383 | constructor(viewer, options) { 384 | super(viewer, options); 385 | this.viewer = viewer; 386 | this.options = options; 387 | } 388 | 389 | load = function () { 390 | if (this.viewer.toolbar) { 391 | // Toolbar is already available, create the UI 392 | this.createUI(); 393 | } else { 394 | // Toolbar hasn't been created yet, wait until we get notification of its creation 395 | this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this); 396 | this.viewer.addEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 397 | } 398 | 399 | return true; 400 | } 401 | 402 | unload = function () { 403 | this.viewer.toolbar.removeControl(this.subToolbar); 404 | return true; 405 | }; 406 | 407 | onToolbarCreated = function () { 408 | this.viewer.removeEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 409 | this.onToolbarCreatedBinded = null; 410 | this.createUI(); 411 | }; 412 | 413 | createUI = async function () { 414 | let viewer = this.viewer; 415 | const vC = await viewer.loadExtension('Autodesk.ViewCubeUi'); 416 | 417 | // Button 1 418 | let button1 = new AutodeskViewing.UI.Button('my-view-front-button'); 419 | button1.onClick = function () { 420 | vC.setViewCube('front'); 421 | }; 422 | button1.addClass('my-view-front-button'); 423 | button1.setToolTip('View front'); 424 | button1.setIcon('adsk-icon-first'); 425 | 426 | // Button 2 427 | let button2 = new AutodeskViewing.UI.Button('my-view-back-button'); 428 | button2.onClick = function () { 429 | vC.setViewCube('back'); 430 | }; 431 | button2.addClass('my-view-back-button'); 432 | button2.setToolTip('View Back'); 433 | button2.setIcon('adsk-icon-second'); 434 | 435 | // SubToolbar 436 | this.subToolbar = new AutodeskViewing.UI.ControlGroup('my-custom-view-toolbar'); 437 | this.subToolbar.addControl(button1); 438 | this.subToolbar.addControl(button2); 439 | 440 | viewer.toolbar.addControl(this.subToolbar); 441 | }; 442 | } 443 | } 444 | ``` 445 | 446 | Moreover, the function for checking load module has been changed (See `/services/Utils.js`): 447 | ```js 448 | // If extension already registered 449 | if (AutodeskViewing.theExtensionManager.isAvailable(name)) { 450 | registeredExtensions.push(name); 451 | continue; 452 | } 453 | ``` 454 | 455 | ## Detailed implementation note (nuxt.js, 2 legged authtication, OSS bucket approch) 456 | 457 | Note that Hub approch requires 3 legged oauth. If you are not going to implement redirection and user management, you can use OSS bucket approch instead. 458 | Follow session **Access Token** and perform a online 2 legged or 3 legged authentication. 459 | If you are using Hub approch, follow [this guide](https://github.com/Autodesk-Forge/forge-derivatives-explorer) or upload files [here](https://derivatives.autodesk.io/), [a360](https://a360.autodesk.com/drive/app/) or [another viewer](https://viewer.autodesk.com/) 460 | If you are using Bucket approch, follow [this guide](https://forge.autodesk.com/en/docs/data/v2/tutorials/app-managed-bucket/). If you are feeling puzzled, read [this article](https://forge.autodesk.com/blog/oss-manager-migrated-autodeskio-server) and manually upload the files [in their new website](https://oss-manager.autodesk.io/). 461 | 462 | If you are using plain Vue, `/sample/index.html` will be enough for you. Host it on a web host, host domain must match with the app in forge web console. 463 | If you are using SSR framework (e.g. [Nuxt](https://nuxtjs.org/) ), you are recommended to directly copy the source codes in `/src` into `/components`, even with inner folder (i.e. `/components/forge`). `/src/index.js` can be omited, as nuxt will handle it instead. 464 | Then wrap it into a plugin (e.g. `/plugins/forge-vuer.js`): 465 | 466 | ```js 467 | import Vue from 'vue'; 468 | //import ForgeVuer from 'forge-vuer'; 469 | import ForgeVuer from '~/components/forge/ForgeVuer' 470 | 471 | Vue.component('forge-vuer', ForgeVuer); 472 | ``` 473 | 474 | Since you have no direct access in head session, you can use `head()` to tell nuxt to add them. ([Article](https://nuxtjs.org/api/pages-head/)) 475 | Adding them into vue page will minimalize the effect. Extensions can be a k-v map e.g. `/pages/forge.vue`: 476 | ```vue 477 | 491 | 492 | 493 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/ForgeVuer.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 97 | 98 | 109 | -------------------------------------------------------------------------------- /src/extensions/myAwesomeExtension.js: -------------------------------------------------------------------------------- 1 | // Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/extensions/#step-2-write-the-extension-code 2 | // my-awesome-extension.js 3 | 4 | export default function (AutodeskViewing) { 5 | 6 | function MyAwesomeExtension(viewer, options) { 7 | AutodeskViewing.Extension.call(this, viewer, options); 8 | } 9 | 10 | MyAwesomeExtension.prototype = Object.create(AutodeskViewing.Extension.prototype); 11 | MyAwesomeExtension.prototype.constructor = MyAwesomeExtension; 12 | 13 | MyAwesomeExtension.prototype.load = function () { 14 | console.log('MyAwesomeExtension.load()'); 15 | return true; 16 | }; 17 | 18 | MyAwesomeExtension.prototype.unload = function () { 19 | console.log('MyAwesomeExtension.unload()'); 20 | return true; 21 | }; 22 | 23 | // Is not necessary to implicitly register the extension 24 | // as this is handled by the component. 25 | // Autodesk.Viewing.theExtensionManager.registerExtension('MyAwesomeExtension', MyAwesomeExtension); 26 | 27 | // IMPORTANT to return the extension function itself. 28 | return MyAwesomeExtension; 29 | } -------------------------------------------------------------------------------- /src/extensions/myCustomToolbar.js: -------------------------------------------------------------------------------- 1 | // Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/toolbar-button/#step-1-detect-the-toolbar 2 | // my-custom-toolbar.js 3 | 4 | export default function (AutodeskViewing) { 5 | 6 | return class ToolbarExtension extends AutodeskViewing.Extension { 7 | viewer; 8 | options; 9 | subToolbar; 10 | 11 | constructor(viewer, options) { 12 | super(viewer, options); 13 | this.viewer = viewer; 14 | this.options = options; 15 | } 16 | 17 | load = function () { 18 | if (this.viewer.toolbar) { 19 | // Toolbar is already available, create the UI 20 | this.createUI(); 21 | } else { 22 | // Toolbar hasn't been created yet, wait until we get notification of its creation 23 | this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this); 24 | this.viewer.addEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 25 | } 26 | 27 | return true; 28 | } 29 | 30 | unload = function () { 31 | this.viewer.toolbar.removeControl(this.subToolbar); 32 | return true; 33 | }; 34 | 35 | onToolbarCreated = function () { 36 | this.viewer.removeEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); 37 | this.onToolbarCreatedBinded = null; 38 | this.createUI(); 39 | }; 40 | 41 | createUI = async function () { 42 | let viewer = this.viewer; 43 | const vC = await viewer.loadExtension('Autodesk.ViewCubeUi'); 44 | 45 | // Button 1 46 | let button1 = new AutodeskViewing.UI.Button('my-view-front-button'); 47 | button1.onClick = function () { 48 | vC.setViewCube('front'); 49 | }; 50 | button1.addClass('my-view-front-button'); 51 | button1.setToolTip('View front'); 52 | button1.setIcon('adsk-icon-first'); 53 | 54 | // Button 2 55 | let button2 = new AutodeskViewing.UI.Button('my-view-back-button'); 56 | button2.onClick = function () { 57 | vC.setViewCube('back'); 58 | }; 59 | button2.addClass('my-view-back-button'); 60 | button2.setToolTip('View Back'); 61 | button2.setIcon('adsk-icon-second'); 62 | 63 | // SubToolbar 64 | this.subToolbar = new AutodeskViewing.UI.ControlGroup('my-custom-view-toolbar'); 65 | this.subToolbar.addControl(button1); 66 | this.subToolbar.addControl(button2); 67 | 68 | viewer.toolbar.addControl(this.subToolbar); 69 | }; 70 | } 71 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import component from "./ForgeVuer.vue"; 2 | 3 | // Declare install function executed by Vue.use() 4 | export function install(Vue) { 5 | if (install.installed) return; 6 | install.installed = true; 7 | Vue.component('forge-vuer', component); 8 | } 9 | 10 | // Create module definition for Vue.use() 11 | const plugin = { 12 | install, 13 | }; 14 | 15 | // Auto-install when vue is found (eg. in browser via