├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .prettierrc
├── .travis.yml
├── README.md
├── example
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── shaver
│ │ ├── 0.svf
│ │ ├── geometry0.pack
│ │ ├── geometry1.pack
│ │ ├── geometry2.pack
│ │ ├── geometry3.pack
│ │ ├── image0.png
│ │ ├── objects_attrs.json.gz
│ │ ├── objects_avs.json.gz
│ │ ├── objects_ids.json.gz
│ │ ├── objects_offs.json.gz
│ │ └── objects_vals.json.gz
├── src
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── ExampleExtension.ts
│ ├── ExampleTool.ts
│ ├── index.css
│ ├── index.tsx
│ ├── react-app-env.d.ts
│ └── setupTests.ts
├── tsconfig.json
└── yarn.lock
├── package-lock.json
├── package.json
├── src
├── .eslintrc
├── defaults.ts
├── extension.ts
├── helpers.ts
├── hooks.ts
├── index.test.tsx
├── index.tsx
├── react-app-env.d.ts
├── tool-interface.ts
└── typings.d.ts
├── tsconfig.json
├── tsconfig.test.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | node_modules/
4 | .snapshots/
5 | *.min.js
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "extends": [
4 | "standard",
5 | "standard-react",
6 | "plugin:prettier/recommended",
7 | "prettier/standard",
8 | "prettier/react",
9 | "plugin:@typescript-eslint/eslint-recommended"
10 | ],
11 | "env": {
12 | "node": true
13 | },
14 | "parserOptions": {
15 | "ecmaVersion": 2020,
16 | "ecmaFeatures": {
17 | "legacyDecorators": true,
18 | "jsx": true
19 | }
20 | },
21 | "settings": {
22 | "react": {
23 | "version": "16"
24 | }
25 | },
26 | "rules": {
27 | "space-before-function-paren": 0,
28 | "react/prop-types": 0,
29 | "react/jsx-handler-names": 0,
30 | "react/jsx-fragments": 0,
31 | "react/no-unused-prop-types": 0,
32 | "import/export": 0,
33 | "semi": [2, "always"]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/ignore-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | node_modules
6 |
7 | # builds
8 | build
9 | dist
10 | .rpt2_cache
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "jsxSingleQuote": true,
4 | "semi": true,
5 | "tabWidth": 2,
6 | "bracketSpacing": true,
7 | "jsxBracketSameLine": false,
8 | "arrowParens": "always",
9 | "trailingComma": "none"
10 | }
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 12
4 | - 10
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-adsk-forge-viewer-ts
2 |
3 |
4 |
5 | React Typescript Autodesk Forge Viewer.
6 |
7 |
8 |
9 | [](https://www.npmjs.com/package/@contecht/react-adsk-forge-viewer) [](https://standardjs.com)
10 |
11 |
12 |
13 | ## Install
14 |
15 |
16 |
17 | ```bash
18 |
19 | npm install @contecht/react-adsk-forge-viewer
20 |
21 | ```
22 |
23 |
24 |
25 | ## Basic Usage
26 |
27 |
28 |
29 | ```tsx
30 |
31 | import React from 'react';
32 |
33 | import { ForgeViewer } from '@contecht/react-adsk-forge-viewer';
34 |
35 |
36 |
37 | const token = "dXtgfg433432e4445..."; // Forge token 2 or 3 legged
38 |
39 | const urn = "dJggddssvc_ggddd..."; // base64 encoded model urn
40 |
41 |
42 |
43 |
44 | const Container = () => {
45 |
46 | return
47 |
48 | }
49 |
50 | ```
51 |
52 | ## Props
53 |
54 | - local (optional) {boolean} - specifies environment, by default `derivativeV2`, when `true` turns to `Local` and allows to load a model from SVF file, default `false`
55 | - token (local:false) {string} - 2 or 3 legged access_token retrieved from Forge Authentication API endpoints
56 | - urn (local:false) {string} - base64 encoded item urn
57 | - path (local:true) {string} - path to SVF file
58 | - version (optional) {string} - Forge Viewer script version, default: `7.*`
59 | - headless (optional) {boolean} - if true mounts a headless viewer without toolbars and other widgets, default: `true`
60 | - initializerOptions (optional) {Autodesk.Viewing.InitializerOptions} - viewer initializer options, see: [docs](https://forge.autodesk.com/en/docs/viewer/v7/reference/Viewing/#initializer-options-callback), default: `{env: 'AutodeskProduction', api: 'derivativeV2'}`
61 | - viewerOptions (optional) {object} -3D viewer options, see: [docs](https://forge.autodesk.com/en/docs/viewer/v7/reference/Viewing/Viewer3D/#new-viewer3d-container-config), default: `{}`
62 | - onDocumentLoadSuccess (optional) {(d: Autodesk.Viewing.Document) => Autodesk.Viewing.BubbleNode} - callback triggered on successful document load, pass a new one to select different viewables, must return a viewable to display, default: `(viewerDocument) => viewerDocument.getRoot().getDefaultGeometry();`
63 | - onDocumentLoadError (optional) {(code?: number, msg?: string, msgs?: any[]) => void} - error handling callback, default: `(args) => console.error(args)`
64 | - viewableOptions - (optional) {object} - viewable options see: [docs](https://forge.autodesk.com/en/docs/viewer/v7/reference/Viewing/Viewer3D/#loaddocumentnode-avdocument-manifestnode-options), default: `{}`
65 | - onInit (optional) {(o: any) => void} - function to trigger after successful viewer initialization, default: `undefined`
66 | - extensions (optional) {ForgeExtension[]} - array of extensions to load on viewer start, more about extensions in the section below, default: `undefined`
67 | - activeTool (optional) {ToolInterface} - Tool interface implementing viewer interactions. Constructor recives additionally viewerOptions as extOptions, default: `undefined`
68 | - style (optional) {object} - React inline style to be applied to viewer container div
69 | - disableLoader (optional) {boolean} - remove Forge spinner while initializing the viewer, default: `false`
70 |
71 | ## Local files
72 |
73 | Forge Viewer can display models without calling the API, using SVF files downloaded from Model Derivatives API. This method doesn't require any access token. File must be loaded via http.
74 |
75 | ```tsx
76 | import React from 'react';
77 |
78 | import { ForgeViewer } from '@contecht/react-adsk-forge-viewer';
79 |
80 | const svf = '../assets/model/file.svf';
81 |
82 | const Container = () => {
83 |
84 | return
88 |
89 | }
90 | ```
91 |
92 | ## Extensions
93 |
94 | Viewer Extensions contain functionality extending viewer capabilities, can be loaded using property `extensions`, example:
95 |
96 | ```tsx
97 | import { ForgeExtension } from '@contecht/react-adsk-forge-viewer';
98 |
99 | declare var THREE: any;
100 |
101 | declare var Autodesk: any;
102 |
103 | export default class ExampleExtension extends ForgeExtension {
104 |
105 | extensionName = 'ExampleExtension';
106 |
107 | load(): boolean {
108 |
109 | // change selection color to red
110 |
111 | const red = new THREE.Color(1,0,0);
112 |
113 | this.viewer.setSelectionColor(red, Autodesk.Viewing.SelectionType.MIXED);
114 |
115 | return true;
116 | }
117 |
118 | unload(): boolean {
119 |
120 | return true;
121 | }
122 |
123 | activate() {}
124 |
125 | deactivate() {}
126 |
127 | }
128 | ```
129 |
130 | ## Tool Interface
131 |
132 | ToolInterface is a base class for viewer interactions. It supports the following event handlers:
133 | - handleSingleClick
134 | - handleDoubleClick
135 | - handleSingleTap
136 | - handleDoubleTap
137 | - handleKeyDown
138 | - handleKeyUp
139 | - handleWheelInput
140 | - handleButtonDown
141 | - handleButtonUp
142 | - handleMouseMove
143 | - handleGesture
144 | - handleBlur
145 | - handleResize
146 |
147 | Can be registered and activated using property `activeTool`. In case of more complex workflow it's recommended to handle (de)registering and (de)activating inside an extension to have full controll over the tool lifecycle.
148 |
149 | Example:
150 | ```
151 | import { ToolInterface } from 'react-adsk-forge-viewer-ts';
152 |
153 | export default class ExampleTool extends ToolInterface {
154 | public toolName = 'ExampleTool';
155 |
156 | activate() {}
157 | deactivate() {}
158 | register() {}
159 | deregister() {}
160 | handleSingleClick(event: any) {
161 | // method executed on every mouse button click
162 | // do something with the event here
163 | const hitTest = this.viewer.clientToWorld(event.canvasX, event.canvasY, true);
164 | console.info(hitTest);
165 | return true;
166 | }
167 | }
168 | ```
169 |
170 | ## Advanced Usage
171 |
172 | ```tsx
173 |
174 | import React from 'react';
175 | import { ForgeViewer } from '@contecht/react-adsk-forge-viewer';
176 | import ExampleExtension from './extensions/example-extension';
177 | import ExampleTool from './tools/example-tool';
178 | const token = "dXtgfg433432e4445..."; // Forge token 2 or 3 legged
179 | const urn = "dJggddssvc_ggddd..."; // base64 encoded model urn
180 |
181 | const initializerOptions = {
182 | language: 'de'
183 | }
184 | const viewerOptions = {
185 | theme: 'light'
186 | }
187 | const onDocumentLoadSuccess = (viewerDocument) => {
188 | const viewables = viewerDocument.getRoot().search({'type':'geometry'});
189 | return viewables.find(v => v.is2D());
190 | }
191 | const viewableOptions = {
192 | globalOffset: {x:0,y:0,z:25}
193 | }
194 |
195 | const ViewerContainer = () => {
196 |
197 | return(
198 |
210 | )
211 |
212 | }
213 | ```
214 |
215 | ## Author
216 | ```
217 | Damian Harasymczuk
218 | ```
219 |
220 | ## License
221 |
222 |
223 |
224 | MIT ©
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | It is linked to the react-adsk-forge-viewer-ts package in the parent directory for development purposes.
4 |
5 | You can run `yarn install` and then `yarn start` to test your package.
6 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-adsk-forge-viewer-ts-example",
3 | "homepage": ".",
4 | "version": "0.0.0",
5 | "private": true,
6 | "scripts": {
7 | "start": "node ../node_modules/react-scripts/bin/react-scripts.js start",
8 | "build": "node ../node_modules/react-scripts/bin/react-scripts.js build",
9 | "test": "node ../node_modules/react-scripts/bin/react-scripts.js test",
10 | "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject"
11 | },
12 | "dependencies": {
13 | "@testing-library/jest-dom": "link:../node_modules/@testing-library/jest-dom",
14 | "@testing-library/react": "link:../node_modules/@testing-library/react",
15 | "@testing-library/user-event": "link:../node_modules/@testing-library/user-event",
16 | "@types/jest": "link:../node_modules/@types/jest",
17 | "@types/node": "link:../node_modules/@types/node",
18 | "@types/react": "link:../node_modules/@types/react",
19 | "@types/react-dom": "link:../node_modules/@types/react-dom",
20 | "react": "link:../node_modules/react",
21 | "react-dom": "link:../node_modules/react-dom",
22 | "react-scripts": "link:../node_modules/react-scripts",
23 | "typescript": "link:../node_modules/typescript",
24 | "react-adsk-forge-viewer-ts": "link:.."
25 | },
26 | "devDependencies": {
27 | "@babel/plugin-syntax-object-rest-spread": "^7.8.3"
28 | },
29 | "eslintConfig": {
30 | "extends": "react-app"
31 | },
32 | "browserslist": {
33 | "production": [
34 | ">0.2%",
35 | "not dead",
36 | "not op_mini all"
37 | ],
38 | "development": [
39 | "last 1 chrome version",
40 | "last 1 firefox version",
41 | "last 1 safari version"
42 | ]
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
16 |
17 |
18 |
27 | react-adsk-forge-viewer-ts
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/example/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "react-adsk-forge-viewer-ts",
3 | "name": "react-adsk-forge-viewer-ts",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/example/public/shaver/0.svf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/0.svf
--------------------------------------------------------------------------------
/example/public/shaver/geometry0.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/geometry0.pack
--------------------------------------------------------------------------------
/example/public/shaver/geometry1.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/geometry1.pack
--------------------------------------------------------------------------------
/example/public/shaver/geometry2.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/geometry2.pack
--------------------------------------------------------------------------------
/example/public/shaver/geometry3.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/geometry3.pack
--------------------------------------------------------------------------------
/example/public/shaver/image0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/image0.png
--------------------------------------------------------------------------------
/example/public/shaver/objects_attrs.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/objects_attrs.json.gz
--------------------------------------------------------------------------------
/example/public/shaver/objects_avs.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/objects_avs.json.gz
--------------------------------------------------------------------------------
/example/public/shaver/objects_ids.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/objects_ids.json.gz
--------------------------------------------------------------------------------
/example/public/shaver/objects_offs.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/objects_offs.json.gz
--------------------------------------------------------------------------------
/example/public/shaver/objects_vals.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmh126/react-adsk-forge-viewer-ts/297709a8b0a11f10fcb407974e11dac8418b61a5/example/public/shaver/objects_vals.json.gz
--------------------------------------------------------------------------------
/example/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div')
7 | ReactDOM.render(, div)
8 | ReactDOM.unmountComponentAtNode(div)
9 | })
10 |
--------------------------------------------------------------------------------
/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ForgeViewer } from 'react-adsk-forge-viewer-ts';
3 | import ExampleExtension from './ExampleExtension';
4 | import ExampleTool from './ExampleTool';
5 | //const token = 'eyJhbGciOi...'
6 | //const urn = 'dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLm5aUnFBSVZsUmtLWFdIeXYyZlpIR3c_dmVyc2lvbj0x'
7 | const extensions = [ExampleExtension]
8 |
9 | const App = () => {
10 | return
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/example/src/ExampleExtension.ts:
--------------------------------------------------------------------------------
1 | import { ForgeExtension } from 'react-adsk-forge-viewer-ts';
2 |
3 | declare var THREE: any;
4 | declare var Autodesk: any;
5 |
6 | export default class ExampleExtension extends ForgeExtension {
7 | public static extensionName = 'ChangedName';
8 |
9 | load(): boolean {
10 | // change selection color to red
11 | const red = new THREE.Color(1,0,0);
12 | this.viewer.setSelectionColor(red, Autodesk.Viewing.SelectionType.MIXED);
13 | return true;
14 | }
15 |
16 | unload(): boolean {
17 | return true;
18 | }
19 |
20 | activate() {}
21 | deactivate() {}
22 |
23 | }
--------------------------------------------------------------------------------
/example/src/ExampleTool.ts:
--------------------------------------------------------------------------------
1 | import { ToolInterface } from 'react-adsk-forge-viewer-ts';
2 |
3 | export default class ExampleTool extends ToolInterface {
4 | public toolName = 'ExampleTool';
5 |
6 | activate() {}
7 | deactivate() {}
8 | register() {}
9 | deregister() {}
10 | handleSingleClick(event: any) {
11 | const hitTest = this.viewer.clientToWorld(event.canvasX, event.canvasY, true);
12 | console.info(hitTest);
13 | return true;
14 | }
15 | }
--------------------------------------------------------------------------------
/example/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/example/src/index.tsx:
--------------------------------------------------------------------------------
1 | import './index.css'
2 |
3 | import React from 'react'
4 | import ReactDOM from 'react-dom'
5 | import App from './App'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
--------------------------------------------------------------------------------
/example/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/example/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "dist",
4 | "module": "esnext",
5 | "lib": [
6 | "dom",
7 | "esnext"
8 | ],
9 | "moduleResolution": "node",
10 | "jsx": "react",
11 | "sourceMap": true,
12 | "declaration": true,
13 | "esModuleInterop": true,
14 | "noImplicitReturns": true,
15 | "noImplicitThis": true,
16 | "noImplicitAny": true,
17 | "strictNullChecks": true,
18 | "suppressImplicitAnyIndexErrors": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "allowSyntheticDefaultImports": true,
22 | "target": "es5",
23 | "allowJs": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "forceConsistentCasingInFileNames": true,
27 | "resolveJsonModule": true,
28 | "isolatedModules": true,
29 | "noEmit": true
30 | },
31 | "include": [
32 | "src"
33 | ],
34 | "exclude": [
35 | "node_modules",
36 | "build"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@contecht/react-adsk-forge-viewer",
3 | "version": "1.1.7",
4 | "description": "React Typescript Autodesk Forge Viewer",
5 | "author": "Damian Harasymczuk",
6 | "license": "MIT",
7 | "main": "dist/index.js",
8 | "module": "dist/index.modern.js",
9 | "source": "src/index.tsx",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/dmh126/react-adsk-forge-viewer-ts.git"
13 | },
14 | "engines": {
15 | "node": ">=10"
16 | },
17 | "scripts": {
18 | "build": "microbundle-crl --no-compress --format modern,cjs",
19 | "start": "microbundle-crl watch --no-compress --format modern,cjs",
20 | "prepare": "run-s build",
21 | "test": "run-s test:unit test:lint test:build",
22 | "test:build": "run-s build",
23 | "test:lint": "eslint",
24 | "test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
25 | "test:watch": "react-scripts test --env=jsdom",
26 | "predeploy": "cd example && yarn install && yarn run build",
27 | "deploy": "gh-pages -d example/build"
28 | },
29 | "peerDependencies": {
30 | "react": "^18.0.0"
31 | },
32 | "devDependencies": {
33 | "@testing-library/jest-dom": "^4.2.4",
34 | "@testing-library/react": "^9.5.0",
35 | "@testing-library/user-event": "^7.2.1",
36 | "@types/jest": "^25.1.4",
37 | "@types/node": "^12.12.38",
38 | "@types/react": "^16.9.27",
39 | "@types/react-dom": "^16.9.7",
40 | "@typescript-eslint/eslint-plugin": "^2.26.0",
41 | "@typescript-eslint/parser": "^2.26.0",
42 | "microbundle-crl": "^0.13.10",
43 | "babel-eslint": "^10.0.3",
44 | "cross-env": "^7.0.2",
45 | "eslint": "^6.8.0",
46 | "eslint-config-prettier": "^6.7.0",
47 | "eslint-config-standard": "^14.1.0",
48 | "eslint-config-standard-react": "^9.2.0",
49 | "eslint-plugin-import": "^2.18.2",
50 | "eslint-plugin-node": "^11.0.0",
51 | "eslint-plugin-prettier": "^3.1.1",
52 | "eslint-plugin-promise": "^4.2.1",
53 | "eslint-plugin-react": "^7.17.0",
54 | "eslint-plugin-standard": "^4.0.1",
55 | "gh-pages": "^2.2.0",
56 | "npm-run-all": "^4.1.5",
57 | "prettier": "^2.0.4",
58 | "react": "^16.13.1",
59 | "react-dom": "^16.13.1",
60 | "react-scripts": "^5.0.1",
61 | "typescript": "^3.7.5"
62 | },
63 | "files": [
64 | "dist",
65 | "README.md"
66 | ],
67 | "dependencies": {
68 | "@types/forge-viewer": "^7.32.2"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "jest": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/defaults.ts:
--------------------------------------------------------------------------------
1 | export const DEFAULT_VERSION: string = '7.*';
2 | export const DEFAULT_INITIALIZER_OPTIONS: object = {
3 | env: 'AutodeskProduction',
4 | api: 'derivativeV2'
5 | };
6 | export const DEFAULT_VIEWER_OPTIONS: object = {};
7 | export const DEFAULT_VIEWABLE_OPTIONS: object = {};
8 | export const DEFAULT_DOCUMENT_LOAD_SUCCESS = (
9 | viewerDocument: Autodesk.Viewing.Document
10 | ): Autodesk.Viewing.BubbleNode => viewerDocument.getRoot().getDefaultGeometry();
11 | export const DEFAULT_DOCUMENT_LOAD_ERROR = (
12 | errorCode?: Autodesk.Viewing.ErrorCodes,
13 | errorMsg?: string,
14 | messages?: any[]
15 | ): void => {
16 | console.error(errorCode, errorMsg, messages);
17 | };
18 | export const DEFAULT_ON_INIT = (): void => {};
19 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export abstract class Extension {
4 | public static extensionName: string = '';
5 | protected viewer: Autodesk.Viewing.Viewer3D;
6 | protected extOptions: Autodesk.Viewing.ExtensionOptions;
7 |
8 | constructor(
9 | viewer: Autodesk.Viewing.Viewer3D,
10 | options?: Autodesk.Viewing.ExtensionOptions
11 | ) {
12 | this.viewer = viewer;
13 | this.extOptions = options || ({} as Autodesk.Viewing.ExtensionOptions);
14 | }
15 |
16 | public abstract load(): void;
17 | public abstract unload(): void;
18 | public abstract activate(): void;
19 | public abstract deactivate(): void;
20 | }
21 |
--------------------------------------------------------------------------------
/src/helpers.ts:
--------------------------------------------------------------------------------
1 | export const loadScripts = (version: string): Promise =>
2 | new Promise((resolve, reject) => {
3 | let ready: boolean = false;
4 | const script: HTMLScriptElement = document.createElement('script');
5 | script.src = `https://developer.api.autodesk.com/modelderivative/v2/viewers/${version}/viewer3D.min.js`;
6 | script.async = true;
7 | document.body.appendChild(script);
8 | const style: HTMLLinkElement = document.createElement('link');
9 | style.rel = 'stylesheet';
10 | style.type = 'text/css';
11 | style.href = `https://developer.api.autodesk.com/modelderivative/v2/viewers/${version}/style.min.css`;
12 | document.body.appendChild(style);
13 |
14 | script.onload = (): void => {
15 | if (!ready) {
16 | ready = true;
17 | resolve(script);
18 | }
19 | };
20 | script.onerror = (msg: any): void => {
21 | console.error(msg);
22 | reject(new Error('Error loading Forge script.'));
23 | };
24 | script.onabort = (msg: UIEvent): void => {
25 | console.error(msg);
26 | reject(new Error('Forge script loading aborted.'));
27 | };
28 | });
29 |
--------------------------------------------------------------------------------
/src/hooks.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { loadScripts } from './helpers';
3 | import {
4 | DEFAULT_DOCUMENT_LOAD_ERROR,
5 | DEFAULT_DOCUMENT_LOAD_SUCCESS,
6 | DEFAULT_INITIALIZER_OPTIONS,
7 | DEFAULT_VIEWER_OPTIONS,
8 | DEFAULT_VIEWABLE_OPTIONS,
9 | DEFAULT_VERSION,
10 | DEFAULT_ON_INIT
11 | } from './defaults';
12 |
13 | type State = {
14 | scriptsLoaded: boolean;
15 | scriptElement: HTMLScriptElement | null;
16 | styleElement: HTMLScriptElement | null;
17 | };
18 | type Refs = {
19 | viewer: any;
20 | };
21 | type Setters = {
22 | setScriptsLoaded: React.Dispatch>;
23 | };
24 |
25 | type Hooks = {
26 | refs: Refs;
27 | state?: State;
28 | setters?: Setters;
29 | style: React.CSSProperties;
30 | };
31 |
32 | export function useHooks({
33 | local = false,
34 | version = DEFAULT_VERSION,
35 | path,
36 | token,
37 | urn,
38 | initializerOptions,
39 | viewerOptions,
40 | headless = false,
41 | onDocumentLoadSuccess = DEFAULT_DOCUMENT_LOAD_SUCCESS,
42 | onDocumentLoadError = DEFAULT_DOCUMENT_LOAD_ERROR,
43 | viewableOptions = DEFAULT_VIEWABLE_OPTIONS,
44 | onInit = DEFAULT_ON_INIT,
45 | extensions,
46 | style = {},
47 | disableLoader = false,
48 | activeTool
49 | }: any): Hooks {
50 | // declare state
51 | const [scriptsLoaded, setScriptsLoaded] = React.useState(false);
52 | const [
53 | scriptElement,
54 | setScriptElement
55 | ] = React.useState(null);
56 | const [
57 | styleElement,
58 | setStyleElement
59 | ] = React.useState(null);
60 | // viewer container ref
61 | const viewerRef = React.useRef(null);
62 | // viewer object
63 | let viewer: Autodesk.Viewing.Viewer3D;
64 | // forge initializer options, default settings for Derivatives API
65 | // if passed 'local' as true it changes that to Local and allows to load SVF
66 | // see: https://forge.autodesk.com/en/docs/viewer/v7/reference/Viewing/#initializer-options-callback
67 | const initializerOpts: Autodesk.Viewing.InitializerOptions = Object.assign(
68 | DEFAULT_INITIALIZER_OPTIONS,
69 | initializerOptions
70 | );
71 | if (local) {
72 | initializerOpts.env = 'Local';
73 | } else {
74 | initializerOpts.getAccessToken = (done: (t: string, n: number) => void) =>
75 | done(token, 3600);
76 | }
77 | // viewer options
78 | // see: https://forge.autodesk.com/en/docs/viewer/v7/reference/Viewing/Viewer3D/#new-viewer3d-container-config
79 | const viewerOpts: Autodesk.Viewing.Viewer3DConfig = Object.assign(
80 | DEFAULT_VIEWER_OPTIONS,
81 | viewerOptions
82 | );
83 | // initialize the viewer, depending on some parameters can instantiate a headless viewer,
84 | // can load SVF files, can load all the provided extensions
85 | const initialize = (): void => {
86 | Autodesk.Viewing.Initializer(initializerOpts, () => {
87 | if (headless) {
88 | viewer = new Autodesk.Viewing.Viewer3D(viewerRef.current, viewerOpts);
89 | } else {
90 | viewer = new Autodesk.Viewing.GuiViewer3D(
91 | viewerRef.current,
92 | viewerOpts
93 | );
94 | }
95 | viewer.addEventListener(Autodesk.Viewing.VIEWER_INITIALIZED, (e) => {
96 | if (disableLoader) {
97 | const spinnerContainer = (viewer as any)._loadingSpinner.domElement;
98 | while (spinnerContainer.hasChildNodes()) {
99 | spinnerContainer.removeChild(spinnerContainer.lastChild);
100 | }
101 | }
102 | onInit(e);
103 | });
104 | const startedCode = viewer.start(path);
105 | if (startedCode > 0) {
106 | console.error('Failed to create a Viewer: WebGL not supported.');
107 | return;
108 | }
109 | if (extensions) {
110 | extensions.forEach((extension: any) => {
111 | Autodesk.Viewing.theExtensionManager.registerExtension(
112 | extension.extensionName,
113 | extension
114 | );
115 | viewer.loadExtension(extension.extensionName, viewerOptions);
116 | });
117 | }
118 | if (activeTool) {
119 | const ToolConstructor = activeTool;
120 | // eslint-disable-next-line dot-notation
121 | const toolController = viewer['toolController'];
122 | const tool = new ToolConstructor(viewer, viewerOptions);
123 | toolController.registerTool(tool);
124 | toolController.activateTool(tool.toolName);
125 | }
126 | });
127 | };
128 | // onDocumentLoadSuccess wrapper
129 | const handleDocumentLoad = (
130 | viewerDocument: Autodesk.Viewing.Document
131 | ): void => {
132 | const viewable = onDocumentLoadSuccess(viewerDocument);
133 | viewer.loadDocumentNode(viewerDocument, viewable, viewableOptions);
134 | };
135 | // load model using Derivatives API
136 | const loadModel = (): void => {
137 | Autodesk.Viewing.Document.load(
138 | `urn:${urn}`,
139 | handleDocumentLoad,
140 | onDocumentLoadError
141 | );
142 | };
143 | // triggered on forge scripts loaded
144 | React.useEffect(() => {
145 | if (!window.Autodesk) {
146 | loadScripts(version)
147 | .then(({ script, style }) => {
148 | setScriptElement(script);
149 | setStyleElement(style);
150 | setScriptsLoaded(true);
151 | })
152 | .catch((error) => {
153 | console.error(error);
154 | });
155 | } else {
156 | setScriptsLoaded(true);
157 | }
158 | if (scriptsLoaded) {
159 | initialize();
160 | if (!local) loadModel();
161 | }
162 | return () => {
163 | if (scriptElement && styleElement) {
164 | document.body.removeChild(scriptElement);
165 | document.body.removeChild(styleElement);
166 | }
167 | };
168 | }, [scriptsLoaded]);
169 |
170 | return {
171 | refs: {
172 | viewer: viewerRef
173 | },
174 | style
175 | };
176 | }
177 |
--------------------------------------------------------------------------------
/src/index.test.tsx:
--------------------------------------------------------------------------------
1 | import { ForgeViewer } from '.';
2 |
3 | describe('ForgeViewer', () => {
4 | it('is truthy', () => {
5 | expect(ForgeViewer).toBeTruthy();
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useHooks } from './hooks';
3 |
4 | interface LocalProps {
5 | local?: true;
6 | path: string;
7 | }
8 |
9 | interface ApiProps {
10 | local?: false;
11 | token: string;
12 | urn: string;
13 | onDocumentLoadSuccess?: (
14 | d: Autodesk.Viewing.Document
15 | ) => Autodesk.Viewing.BubbleNode;
16 | onDocumentLoadError?: (
17 | errorCode?: Autodesk.Viewing.ErrorCodes,
18 | errorMsg?: string,
19 | messages?: any[]
20 | ) => void;
21 | }
22 |
23 | interface DefaultProps {
24 | version?: string;
25 | initializerOptions?: Autodesk.Viewing.InitializerOptions;
26 | viewerOptions?: Autodesk.Viewing.Viewer3DConfig;
27 | headless?: boolean;
28 | viewableOptions?: Autodesk.Viewing.LoadModelOptions;
29 | onInit?: (v?: any) => void;
30 | extensions?: any[];
31 | style?: any;
32 | disableLoader?: boolean;
33 | activeTool?: any;
34 | }
35 |
36 | type Props = (ApiProps | LocalProps) & DefaultProps;
37 |
38 | export const ForgeViewer = (props: Props): React.ReactElement => {
39 | const { refs, style } = useHooks(props);
40 | return ;
41 | };
42 |
43 | export { Extension as ForgeExtension } from './extension';
44 | export { ToolInterface } from './tool-interface';
45 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/tool-interface.ts:
--------------------------------------------------------------------------------
1 | ///
2 | export interface ToolInterface {
3 | handleSingleClick?(event: any, button: number): boolean;
4 | handleDoubleClick?(event: any, button: number): boolean;
5 | handleSingleTap?(event: any): boolean;
6 | handleDoubleTap?(event: any): boolean;
7 | handleKeyDown?(event: any, keyCode: number): boolean;
8 | handleKeyUp?(event: any, keyCode: number): boolean;
9 | handleWheelInput?(delta: number): boolean;
10 | handleButtonDown?(event: any, button: number): boolean;
11 | handleButtonUp?(event: any, button: number): boolean;
12 | handleMouseMove?(event: any): boolean;
13 | handleGesture?(event: any): boolean;
14 | handleBlur?(event: any): boolean;
15 | handleResize?(): void;
16 | }
17 |
18 | export abstract class ToolInterface {
19 | public abstract toolName: string;
20 | protected viewer: Autodesk.Viewing.Viewer3D;
21 | protected extOptions: any;
22 |
23 | constructor(viewer: Autodesk.Viewing.Viewer3D, options?: any) {
24 | this.viewer = viewer;
25 | this.extOptions = options || {};
26 | }
27 |
28 | public abstract register(): void;
29 | public abstract deregister(): void;
30 | public abstract activate(): void;
31 | public abstract deactivate(): void;
32 |
33 | getName(): string {
34 | return this.toolName;
35 | }
36 |
37 | getNames(): string[] {
38 | return [this.toolName];
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'forge-viewer';
2 |
3 | declare module 'react-adsk-forge-viewer-ts' {
4 | export const ForgeViewer: (props: Props) => React.ReactElement;
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "dist",
4 | "module": "esnext",
5 | "lib": [
6 | "dom",
7 | "esnext"
8 | ],
9 | "moduleResolution": "node",
10 | "jsx": "react",
11 | "sourceMap": true,
12 | "declaration": true,
13 | "esModuleInterop": true,
14 | "noImplicitReturns": true,
15 | "noImplicitThis": true,
16 | "noImplicitAny": true,
17 | "strictNullChecks": true,
18 | "suppressImplicitAnyIndexErrors": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "allowSyntheticDefaultImports": true,
22 | "target": "es5",
23 | "allowJs": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "forceConsistentCasingInFileNames": true,
27 | "resolveJsonModule": true,
28 | "isolatedModules": true,
29 | "noEmit": true
30 | },
31 | "include": [
32 | "src"
33 | ],
34 | "exclude": [
35 | "node_modules",
36 | "dist",
37 | "example"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs"
5 | }
6 | }
--------------------------------------------------------------------------------