├── .gitignore ├── LICENSE ├── README.md ├── app.json ├── build ├── asset-manifest.json ├── images │ ├── adsk.24x24.png │ ├── forge-icon.png │ ├── forge-logo-footer.png │ ├── forge-logo.png │ ├── fusion-engine.png │ ├── fusion-rcar.png │ ├── revit-factory.png │ ├── revit-house.png │ ├── rhino-legocar.png │ ├── tie-fighter.png │ ├── urban-house.png │ └── viewer-rocks-preview.png ├── index.html ├── service-worker.js └── static │ ├── css │ ├── main.d17c5ebf.css │ └── main.d17c5ebf.css.map │ ├── js │ ├── main.77805bae.js │ └── main.77805bae.js.map │ └── media │ ├── fontawesome-webfont.674f50d2.eot │ ├── fontawesome-webfont.912ec66d.svg │ ├── fontawesome-webfont.af7ae505.woff2 │ ├── fontawesome-webfont.b06871f2.ttf │ ├── fontawesome-webfont.fee66e71.woff │ ├── glyphicons-halflings-regular.448c34a5.woff2 │ ├── glyphicons-halflings-regular.89889688.svg │ ├── glyphicons-halflings-regular.e18bbf61.ttf │ ├── glyphicons-halflings-regular.f4769f9b.eot │ └── glyphicons-halflings-regular.fa277232.woff ├── package-lock.json ├── package.json ├── public ├── images │ ├── adsk.24x24.png │ ├── forge-icon.png │ ├── forge-logo-footer.png │ ├── forge-logo.png │ ├── fusion-engine.png │ ├── fusion-rcar.png │ ├── revit-factory.png │ ├── revit-house.png │ ├── rhino-legocar.png │ ├── tie-fighter.png │ ├── urban-house.png │ └── viewer-rocks-preview.png └── index.html ├── routes └── auth.js ├── server ├── aps.js ├── config.js └── server.js ├── src ├── actions │ ├── index.js │ ├── viewerActions.js │ └── viewerTypes.js ├── components │ ├── App.css │ ├── App.js │ ├── Client.js │ ├── Footer │ │ ├── Footer.js │ │ ├── footer.css │ │ └── index.js │ ├── Gallery │ │ ├── Gallery.js │ │ ├── gallery.css │ │ └── index.js │ ├── Jumbotron │ │ ├── Jumbotron.js │ │ ├── index.js │ │ └── jumbotron.css │ ├── Properties │ │ ├── Properties.js │ │ ├── index.js │ │ └── properties.css │ └── Viewer │ │ ├── Viewer-helpers.js │ │ └── Viewer.js ├── index.js ├── reducers │ ├── index.js │ └── viewerReducer.js └── store.js └── thumbnail.png /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | # build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log 16 | 17 | 18 | cra-server-ex.graffle 19 | server/credentials.js 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Autodesk, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Viewer - React - Express - Headless 2 | 3 | [![Node.js](https://img.shields.io/badge/Node.js-6.7.0-blue.svg)](https://nodejs.org/) 4 | [![npm](https://img.shields.io/badge/npm-3.10.7-green.svg)](https://www.npmjs.com/) 5 | ![Platforms](https://img.shields.io/badge/platform-windows%20%7C%20osx%20%7C%20linux-lightgray.svg) 6 | [![License](http://img.shields.io/:license-mit-blue.svg)](http://opensource.org/licenses/MIT) 7 | 8 | [![oAuth2](https://img.shields.io/badge/oAuth2-v1-green.svg)](http://developer.autodesk.com/) 9 | [![Viewer](https://img.shields.io/badge/Viewer-v3.3-green.svg)](http://developer.autodesk.com/) 10 | 11 | ## Description 12 | 13 | Using Forge Viewer, you have the option of a Headless one, the option to add your own logo and get rid of extension that interact with the viewer is possible. 14 | I created a demonstration of this scenario using React on the Front End, Redux to handle states for Properties metadata access and NodeJS (Express) together with React-Scripts to handle the authentication and access to the use of the Forge services. 15 | 16 | The available Extensions once in Full Screen mode are. 17 | - Properties (Categories are display with the option to expand to see all metadata available from the model) 18 | - Explode Slider 19 | - Explode Animation 20 | - Rotate Animation 21 | - Restate of the model to original form 22 | 23 | This sample show a simple integration of the [Viewer](https://developer.autodesk.com/en/docs/viewer/v2/overview/) in a headless way with custom made extensions. The front-end will look like: 24 | 25 | ### Thumbnail 26 | 27 | ![thumbnail](/thumbnail.png) 28 | 29 | ## Setup 30 | 31 | The 6 models will need to translated and hosted on your own bucket. This will change the URN values that will need to be subtitued here. 32 | [URN Gallery JSON](https://github.com/Autodesk-Forge/viewer-react-express-headless/blob/master/src/components/Gallery/Gallery.js#L29) 33 | 34 | Feel free to use your own models in the Gallery. 35 | 36 | ### Note Restore State 37 | 38 | The Restore State functionality is hardcoded for the specific models. You will need to get the State for each of your models and pass the new JSON value at this location 39 | [Restore State JSON](https://github.com/Autodesk-Forge/viewer-react-express-headless/blob/master/src/components/Viewer/Viewer-helpers.js#L156) 40 | 41 | ### Development mode 42 | 43 | Follow these instructions to get the app running locally: 44 | 45 | 1. run `git clone` this repository 46 | 1. `cd` into the project's directory 47 | 1. create a file called `server/credentials.js` with your credentials, [follow this template](https://github.com/Autodesk-Forge/viewer-react-express-headless/blob/master/server/credentials_.js) 48 | 1. run `npm install` 49 | 1. run `npm run watch` 50 | 51 | This will get a server running locally, open `http://localhost:3000` on your browser to see the app running. 52 | 53 | ### Production mode 54 | 55 | To run this app in production mode, run `npm run build` and then `npm start` in a production environment. 56 | 57 | If you try to deploy this on Heroku, we set a `postinstall` script that will run the `build` script, so there is no need to run it again, simply let Heroku run `npm start` (which it does automatically) and you'll be good to go. 58 | 59 | ## Heroku Deployment 60 | 61 | To deploy this project to Heroku, be sure to set your environment variables in the dashboard: 62 | 63 | - `FORGE_CLIENT_ID` 64 | - `FORGE_CLIENT_SECRET` 65 | 66 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 67 | 68 | -------- 69 | 70 | ## License 71 | 72 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). 73 | Please see the [LICENSE](LICENSE) file for full details. 74 | 75 | 76 | ## Written by 77 | 78 | Jaime Rosales D.
79 | [![Twitter Follow](https://img.shields.io/twitter/follow/afrojme.svg?style=social&label=Follow)](https://twitter.com/AfroJme)
Forge Partner Development
80 | Forge Developer Portal
81 | 82 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "viewer-react-express-headless", 3 | "description": "A React and Node JS (express) sample demonstrating the use of Forge Headless Viewer and custom made extensions.", 4 | "repository": "https://github.com/Autodesk-Forge/viewer-react-express-headless.git", 5 | "logo": "https://github.com/Autodesk-Forge/viewer-react-express-headless/raw/master/public/images/adsk.24x24.png", 6 | "keywords": [ "node", "forge", "autodesk", "react" ], 7 | "website": "https://developer.autodesk.com/", 8 | "env": { 9 | "FORGE_CLIENT_ID": { 10 | "description": "Replace with your FORGE CLIENT ID KEY", 11 | "value": "public" 12 | }, 13 | "FORGE_CLIENT_SECRET": { 14 | "description": "Replace with your FORGE CLIENT SECRET KEY", 15 | "value": "secret" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.d17c5ebf.css", 3 | "main.css.map": "static/css/main.d17c5ebf.css.map", 4 | "main.js": "static/js/main.77805bae.js", 5 | "main.js.map": "static/js/main.77805bae.js.map", 6 | "static/media/fontawesome-webfont.eot": "static/media/fontawesome-webfont.674f50d2.eot", 7 | "static/media/fontawesome-webfont.svg?v=4.7.0": "static/media/fontawesome-webfont.912ec66d.svg", 8 | "static/media/fontawesome-webfont.ttf?v=4.7.0": "static/media/fontawesome-webfont.b06871f2.ttf", 9 | "static/media/fontawesome-webfont.woff2?v=4.7.0": "static/media/fontawesome-webfont.af7ae505.woff2", 10 | "static/media/fontawesome-webfont.woff?v=4.7.0": "static/media/fontawesome-webfont.fee66e71.woff", 11 | "static/media/glyphicons-halflings-regular.eot": "static/media/glyphicons-halflings-regular.f4769f9b.eot", 12 | "static/media/glyphicons-halflings-regular.svg": "static/media/glyphicons-halflings-regular.89889688.svg", 13 | "static/media/glyphicons-halflings-regular.ttf": "static/media/glyphicons-halflings-regular.e18bbf61.ttf", 14 | "static/media/glyphicons-halflings-regular.woff": "static/media/glyphicons-halflings-regular.fa277232.woff", 15 | "static/media/glyphicons-halflings-regular.woff2": "static/media/glyphicons-halflings-regular.448c34a5.woff2" 16 | } -------------------------------------------------------------------------------- /build/images/adsk.24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/adsk.24x24.png -------------------------------------------------------------------------------- /build/images/forge-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/forge-icon.png -------------------------------------------------------------------------------- /build/images/forge-logo-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/forge-logo-footer.png -------------------------------------------------------------------------------- /build/images/forge-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/forge-logo.png -------------------------------------------------------------------------------- /build/images/fusion-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/fusion-engine.png -------------------------------------------------------------------------------- /build/images/fusion-rcar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/fusion-rcar.png -------------------------------------------------------------------------------- /build/images/revit-factory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/revit-factory.png -------------------------------------------------------------------------------- /build/images/revit-house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/revit-house.png -------------------------------------------------------------------------------- /build/images/rhino-legocar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/rhino-legocar.png -------------------------------------------------------------------------------- /build/images/tie-fighter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/tie-fighter.png -------------------------------------------------------------------------------- /build/images/urban-house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/urban-house.png -------------------------------------------------------------------------------- /build/images/viewer-rocks-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/images/viewer-rocks-preview.png -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | Autodesk Viewer
-------------------------------------------------------------------------------- /build/service-worker.js: -------------------------------------------------------------------------------- 1 | "use strict";var precacheConfig=[["/index.html","537864ad045928b0cb5a7c5596e64bec"],["/static/css/main.d17c5ebf.css","e1d99bf736ca259dc278009f177d6dd6"],["/static/js/main.77805bae.js","6382eae1dd57f67aa3afa5fd7ad34860"],["/static/media/fontawesome-webfont.674f50d2.eot","674f50d287a8c48dc19ba404d20fe713"],["/static/media/fontawesome-webfont.912ec66d.svg","912ec66d7572ff821749319396470bde"],["/static/media/fontawesome-webfont.af7ae505.woff2","af7ae505a9eed503f8b8e6982036873e"],["/static/media/fontawesome-webfont.b06871f2.ttf","b06871f281fee6b241d60582ae9369b9"],["/static/media/fontawesome-webfont.fee66e71.woff","fee66e712a8a08eef5805a46892932ad"],["/static/media/glyphicons-halflings-regular.448c34a5.woff2","448c34a56d699c29117adc64c43affeb"],["/static/media/glyphicons-halflings-regular.89889688.svg","89889688147bd7575d6327160d64e760"],["/static/media/glyphicons-halflings-regular.e18bbf61.ttf","e18bbf611f2a2e43afc071aa2f4e1512"],["/static/media/glyphicons-halflings-regular.f4769f9b.eot","f4769f9bdb7466be65088239c12046d1"],["/static/media/glyphicons-halflings-regular.fa277232.woff","fa2772327f55d8198301fdb8bcfc8158"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(t){return t.redirected?("body"in t?Promise.resolve(t.body):t.blob()).then(function(e){return new Response(e,{headers:t.headers,status:t.status,statusText:t.statusText})}):Promise.resolve(t)},createCacheKey=function(e,t,n,a){var r=new URL(e);return a&&r.pathname.match(a)||(r.search+=(r.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),r.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(t){return n.every(function(e){return!e.test(t[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],a=new URL(t,self.location),r=createCacheKey(a,hashParamName,n,/\.\w{8}\./);return[a.toString(),r]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(a){return setOfCachedUrls(a).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var e=new Request(t,{credentials:"same-origin"});return fetch(e).then(function(e){if(!e.ok)throw new Error("Request for "+t+" returned a response with status "+e.status);return cleanResponse(e).then(function(e){return a.put(t,e)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(t){return t.keys().then(function(e){return Promise.all(e.map(function(e){if(!n.has(e.url))return t.delete(e)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(t){if("GET"===t.request.method){var e,n=stripIgnoredUrlParameters(t.request.url,ignoreUrlParametersMatching),a="index.html";(e=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,a),e=urlsToCacheKeys.has(n));var r="/index.html";!e&&"navigate"===t.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],t.request.url)&&(n=new URL(r,self.location).toString(),e=urlsToCacheKeys.has(n)),e&&t.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(e){return console.warn('Couldn\'t serve response for "%s" from cache: %O',t.request.url,e),fetch(t.request)}))}}); -------------------------------------------------------------------------------- /build/static/media/fontawesome-webfont.674f50d2.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/fontawesome-webfont.674f50d2.eot -------------------------------------------------------------------------------- /build/static/media/fontawesome-webfont.af7ae505.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/fontawesome-webfont.af7ae505.woff2 -------------------------------------------------------------------------------- /build/static/media/fontawesome-webfont.b06871f2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/fontawesome-webfont.b06871f2.ttf -------------------------------------------------------------------------------- /build/static/media/fontawesome-webfont.fee66e71.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/fontawesome-webfont.fee66e71.woff -------------------------------------------------------------------------------- /build/static/media/glyphicons-halflings-regular.448c34a5.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/glyphicons-halflings-regular.448c34a5.woff2 -------------------------------------------------------------------------------- /build/static/media/glyphicons-halflings-regular.89889688.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /build/static/media/glyphicons-halflings-regular.e18bbf61.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/glyphicons-halflings-regular.e18bbf61.ttf -------------------------------------------------------------------------------- /build/static/media/glyphicons-halflings-regular.f4769f9b.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/glyphicons-halflings-regular.f4769f9b.eot -------------------------------------------------------------------------------- /build/static/media/glyphicons-halflings-regular.fa277232.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/build/static/media/glyphicons-halflings-regular.fa277232.woff -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "viewer-server", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "npm run start:server", 7 | "watch": "npm-run-all --parallel start:*", 8 | "start:server": "node server/server.js", 9 | "start:client": "react-scripts start", 10 | "build": "react-scripts build", 11 | "test": "react-scripts test --env=jsdom", 12 | "eject": "react-scripts eject", 13 | "postinstall": "npm run build" 14 | }, 15 | "author": "Jaime Rosales", 16 | "license": "MIT", 17 | "proxy": "http://localhost:3001/", 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Autodesk-Forge/viewer-react-express-headless.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/Autodesk-Forge/viewer-react-express-headless/issues" 24 | }, 25 | "dependencies": { 26 | "@aps_sdk/authentication": "^0.1.0-beta.1", 27 | "@aps_sdk/autodesk-sdkmanager": "^0.0.7-beta.1", 28 | "axios": "^0.15.2", 29 | "babel-cli": "^6.26.0", 30 | "babel-core": "^6.26.3", 31 | "babel-preset-es2015": "6.3.13", 32 | "babel-preset-stage-0": "6.5.0", 33 | "bootstrap": "^3.3.7", 34 | "classnames": "^2.2.6", 35 | "dotenv": "^16.4.5", 36 | "express": "^4.16.3", 37 | "font-awesome": "^4.7.0", 38 | "lodash": "^4.17.10", 39 | "npm-run-all": "^3.1.1", 40 | "react": "^15.3.2", 41 | "react-dom": "^15.3.2", 42 | "react-redux": "^5.0.7", 43 | "react-scripts": "^1.1.4", 44 | "redux": "^3.6.0", 45 | "scroll-to": "0.0.2" 46 | }, 47 | "babel": { 48 | "presets": [ 49 | "es2015", 50 | "stage-0" 51 | ] 52 | }, 53 | "engines": { 54 | "node": "6.7.x", 55 | "npm": "3.10.x" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/images/adsk.24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/adsk.24x24.png -------------------------------------------------------------------------------- /public/images/forge-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/forge-icon.png -------------------------------------------------------------------------------- /public/images/forge-logo-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/forge-logo-footer.png -------------------------------------------------------------------------------- /public/images/forge-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/forge-logo.png -------------------------------------------------------------------------------- /public/images/fusion-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/fusion-engine.png -------------------------------------------------------------------------------- /public/images/fusion-rcar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/fusion-rcar.png -------------------------------------------------------------------------------- /public/images/revit-factory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/revit-factory.png -------------------------------------------------------------------------------- /public/images/revit-house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/revit-house.png -------------------------------------------------------------------------------- /public/images/rhino-legocar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/rhino-legocar.png -------------------------------------------------------------------------------- /public/images/tie-fighter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/tie-fighter.png -------------------------------------------------------------------------------- /public/images/urban-house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/urban-house.png -------------------------------------------------------------------------------- /public/images/viewer-rocks-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/public/images/viewer-rocks-preview.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 23 | Autodesk Viewer 24 | 25 | 26 | 27 | 28 |
29 | 30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { getPublicToken } = require('../server/aps'); 3 | 4 | let router = express.Router(); 5 | 6 | router.get('/token', async function (req, res, next) { 7 | try { 8 | res.json(await getPublicToken()); 9 | } catch (err) { 10 | next(err); 11 | } 12 | }); 13 | 14 | module.exports = router; -------------------------------------------------------------------------------- /server/aps.js: -------------------------------------------------------------------------------- 1 | const { SdkManagerBuilder } = require('@aps_sdk/autodesk-sdkmanager'); 2 | const { AuthenticationClient, Scopes } = require('@aps_sdk/authentication'); 3 | const { APS_CLIENT_ID, APS_CLIENT_SECRET } = require('./config.js'); 4 | 5 | 6 | const sdk = SdkManagerBuilder.create().build(); 7 | const authenticationClient = new AuthenticationClient(sdk); 8 | 9 | const service = module.exports = {}; 10 | 11 | 12 | service.getPublicToken = async () => { 13 | const credentials = await authenticationClient.getTwoLeggedToken(APS_CLIENT_ID, APS_CLIENT_SECRET, [ 14 | Scopes.DataRead 15 | ]); 16 | return credentials; 17 | }; -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | let { APS_CLIENT_ID, APS_CLIENT_SECRET, PORT } = process.env; 4 | if (!APS_CLIENT_ID || !APS_CLIENT_SECRET) { 5 | console.warn('Missing some of the environment variables.'); 6 | process.exit(1); 7 | } 8 | 9 | PORT = PORT || 3001; 10 | 11 | module.exports = { 12 | APS_CLIENT_ID, 13 | APS_CLIENT_SECRET, 14 | PORT 15 | }; -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | const path = require('path'); 20 | const express = require('express'); 21 | const app = express(); 22 | const request = require('request'); 23 | const { PORT } = require('./config.js'); 24 | 25 | 26 | 27 | app.use(express.static("../build")); 28 | app.use(require('../routes/auth.js')); 29 | 30 | 31 | app.listen(PORT, function () { console.log(`Server listening on port ${PORT}...`); }); -------------------------------------------------------------------------------- /src/actions/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from './viewerActions'; 2 | import * as types from './viewerTypes'; 3 | 4 | export { 5 | types, 6 | actions, 7 | } -------------------------------------------------------------------------------- /src/actions/viewerActions.js: -------------------------------------------------------------------------------- 1 | import * as types from './viewerTypes'; 2 | 3 | export function getViewerProperties(properties = []) { 4 | //console.log('action', properties) 5 | return { 6 | type: types.GET_AGGREGATE_PROPERTIES, 7 | properties, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/actions/viewerTypes.js: -------------------------------------------------------------------------------- 1 | export const GET_AGGREGATE_PROPERTIES = 'GET_AGGREGATE_PROPERTIES'; -------------------------------------------------------------------------------- /src/components/App.css: -------------------------------------------------------------------------------- 1 | body.fullscreen { 2 | max-height: 100vh; 3 | overflow: hidden; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React, { Component } from 'react'; 20 | import Jumbotron from './Jumbotron'; 21 | import Footer from './Footer'; 22 | import Gallery from './Gallery'; 23 | import 'bootstrap/dist/css/bootstrap.css'; 24 | import './App.css'; 25 | import 'font-awesome/css/font-awesome.css'; 26 | 27 | class App extends Component { 28 | render() { 29 | return ( 30 |
31 | 32 | 33 | 34 | 35 |
37 | ); 38 | } 39 | } 40 | 41 | export default App; 42 | -------------------------------------------------------------------------------- /src/components/Client.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import axios from 'axios'; 20 | 21 | function getaccesstoken() { 22 | return axios.get('/token') 23 | .then(function (response) { 24 | return response.data; 25 | }) 26 | .catch(function (error) { 27 | console.log(error); 28 | }); 29 | } 30 | 31 | const Client = { getaccesstoken }; 32 | export default Client; -------------------------------------------------------------------------------- /src/components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React, { Component } from 'react'; 20 | import './footer.css'; 21 | 22 | class Footer extends Component { 23 | render() { 24 | return ( 25 |
26 |
27 |
28 |
29 | View on GitHub 30 |
31 |
32 | © 2024 Copyright Autodesk. All rights reserved. 33 |
34 |
35 |
36 |
37 | ); 38 | } 39 | } 40 | 41 | export default Footer; 42 | -------------------------------------------------------------------------------- /src/components/Footer/footer.css: -------------------------------------------------------------------------------- 1 | .forge-footer { 2 | color: #999; 3 | padding: 1em 0; 4 | } 5 | 6 | .forge-footer .footer-logo { 7 | width: 150px; 8 | } 9 | 10 | .forge-footer .footer-copyright { 11 | text-align: right; 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Footer/index.js: -------------------------------------------------------------------------------- 1 | import Footer from './Footer'; 2 | 3 | export default Footer; 4 | -------------------------------------------------------------------------------- /src/components/Gallery/Gallery.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | // Models 20 | 21 | //Steampunk : dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1NwTTNXNy5mM2Q 22 | 23 | import React, { Component } from 'react'; 24 | import scrollTo from 'scroll-to'; 25 | import Helpers from '../Viewer/Viewer-helpers'; 26 | import './gallery.css'; 27 | 28 | 29 | const tilesData = [ 30 | { 31 | img: 'images/tie-fighter.png', 32 | title: 'Fusion Tie Fighter', 33 | key: '0001', 34 | urn:'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1RpZV9GaWd0aGVyX1RveS5mM2Q' 35 | }, 36 | { 37 | img: 'images/fusion-rcar.png', 38 | title: 'Fusion Race Car', 39 | key: '0002', 40 | urn: 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1JDJTIwQ2FyLmYzZA' 41 | }, 42 | { 43 | img: 'images/fusion-engine.png', 44 | title: 'Fusion Engine', 45 | key: '0003', 46 | urn: 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1RWUi00LUN5Y2wtZW5naW5lLmYzZA' 47 | }, 48 | 49 | { 50 | img: 'images/revit-house.png', 51 | title: 'Revit House', 52 | key: '0004', 53 | urn: 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L0hvdXNlLmR3Zng' 54 | 55 | }, 56 | { 57 | img: 'images/urban-house.png', 58 | title: 'Revit Urban House', 59 | key: '0005', 60 | urn: 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1VyYmFuJTIwSG91c2UlMjAtJTIwMjAxNS5ydnQ' 61 | }, 62 | { 63 | img: 'images/revit-factory.png', 64 | title: 'Revit Factory', 65 | key: '0006', 66 | urn: 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0LzNkRmFjdG9yeS5kd2Y' 67 | }, 68 | ]; 69 | 70 | 71 | class Gallery extends Component { 72 | 73 | onTileSelect(tile, e) { 74 | e.preventDefault(); 75 | 76 | // Scroll to top 77 | scrollTo(0, 0, { 78 | ease: 'inQuad', 79 | duration: 300 80 | }); 81 | 82 | // Starts loading once it scrolls 83 | setTimeout( 84 | () => Helpers.launchViewer("viewerDiv", tile.urn, tile.key), 85 | 300 86 | ); 87 | } 88 | 89 | render() { 90 | return ( 91 |
92 |
93 |
94 | {tilesData.map((tile, index) => 95 | ( 96 |
97 | 98 | {tile.title} 99 | 100 |
{tile.title}
101 |
102 | ) 103 | )} 104 |
105 |
106 |
107 | ) 108 | } 109 | } 110 | 111 | export default Gallery; 112 | -------------------------------------------------------------------------------- /src/components/Gallery/gallery.css: -------------------------------------------------------------------------------- 1 | .forge-gallery { 2 | background-color: #7b7b7b; 3 | padding-top: 3.5em; 4 | } 5 | 6 | .forge-gallery .tile { 7 | border-radius: 5px; 8 | margin-bottom: 1.8em; 9 | position: relative; 10 | } 11 | 12 | .forge-gallery .tile .tile-avatar { 13 | border-radius: 5px; 14 | box-shadow: 1px 1px 5px 1px rgb(73, 77, 84); 15 | height: auto; 16 | max-width: 100%; 17 | } 18 | 19 | .forge-gallery .tile .tile-title { 20 | bottom: 0; 21 | width: calc(100% - 30px); 22 | background-color: rgba(80, 80, 80, .5); 23 | border-bottom-left-radius: 5px; 24 | border-bottom-right-radius: 5px; 25 | bottom: 0; 26 | color: white; 27 | font-size: 1em; 28 | padding: .6em .8em; 29 | position: absolute; 30 | text-shadow: 1px 1px 1px black; 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Gallery/index.js: -------------------------------------------------------------------------------- 1 | import Gallery from './Gallery'; 2 | 3 | export default Gallery; 4 | -------------------------------------------------------------------------------- /src/components/Jumbotron/Jumbotron.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React, { Component } from 'react'; 20 | import './jumbotron.css'; 21 | import Viewer from '../Viewer/Viewer'; 22 | import classnames from 'classnames'; 23 | import scrollTo from 'scroll-to'; 24 | import Properties from '../Properties' 25 | import { 26 | viewerResize, 27 | viewerExplode, 28 | toggleExplosion, 29 | toggleRotation, 30 | stopMotion, 31 | modelRestoreState, 32 | } from '../Viewer/Viewer-helpers'; 33 | 34 | class Jumbotron extends Component { 35 | 36 | constructor() { 37 | super(); 38 | 39 | this.state = { 40 | fullscreen: false, 41 | explode: false, 42 | expMotion: false, 43 | rotMotion: false, 44 | resetState: false, 45 | properties: false, 46 | value: 0 47 | } 48 | 49 | this.onFullscreen = this.onFullscreen.bind(this); 50 | this.onExplode = this.onExplode.bind(this); 51 | this.onExplodeAnimation = this.onExplodeAnimation.bind(this); 52 | this.onRotateAnimation = this.onRotateAnimation.bind(this); 53 | this.onResetState = this.onResetState.bind(this); 54 | this.onOrientationChange = this.onOrientationChange.bind(this); 55 | this.onPropertiesDisplay = this.onPropertiesDisplay.bind(this); 56 | this.handleValueChange = this.handleValueChange.bind(this); 57 | this.onSelectionChange = this.onSelectionChange.bind(this); 58 | } 59 | 60 | componentDidMount() { 61 | window.addEventListener('orientationchange', this.onOrientationChange); 62 | } 63 | 64 | componentWillUnmount() { 65 | window.removeEventListener('orientationchange', this.onOrientationChange); 66 | } 67 | 68 | handleValueChange(event) { 69 | this.setState({ 70 | value: event.target.value 71 | }); 72 | viewerExplode(this.state.value/100); 73 | 74 | } 75 | 76 | onFullscreen() { 77 | this.setState({ fullscreen: !this.state.fullscreen }, () => { 78 | 79 | if (this.state.fullscreen) { 80 | scrollTo(0, 0, { 81 | ease: 'inQuad', 82 | duration: 300 83 | }); 84 | document.body.classList.add('fullscreen') 85 | } else { 86 | document.body.classList.remove('fullscreen'); 87 | this.onResetState(); 88 | if (this.state.explode){ 89 | document.body.classList.remove('explode'); 90 | } 91 | 92 | this.setState({ 93 | fullscreen: false, 94 | explode: false, 95 | expMotion: false, 96 | rotMotion: false, 97 | resetState: false, 98 | properties: false, 99 | value: 0 100 | }) 101 | } 102 | 103 | // resize viewer after css animation 104 | setTimeout(() => viewerResize(), 300); 105 | }); 106 | } 107 | 108 | onPropertiesDisplay(){ 109 | this.setState({ properties: !this.state.properties }, () => { 110 | if (this.state.properties) { 111 | document.body.classList.add('properties-show'); 112 | } else { 113 | document.body.classList.remove('properties-show'); 114 | } 115 | }); 116 | } 117 | 118 | onExplode(){ 119 | this.setState({ explode: !this.state.explode }, () => { 120 | if (this.state.explode) { 121 | document.body.classList.add('explode') 122 | } else { 123 | document.body.classList.remove('explode'); 124 | } 125 | }); 126 | } 127 | 128 | onOrientationChange() { 129 | setTimeout(() => viewerResize(), 300); 130 | } 131 | 132 | onExplodeAnimation() { 133 | this.setState({ expMotion: !this.state.expMotion}, () => { 134 | if (this.state.expMotion) { 135 | document.body.classList.add('explode-motion') 136 | toggleExplosion(); 137 | } else { 138 | document.body.classList.remove('explode-motion'); 139 | toggleExplosion(); 140 | } 141 | }); 142 | } 143 | 144 | onRotateAnimation() { 145 | this.setState({ rotMotion: !this.state.rotMotion }, () => { 146 | if (this.state.rotMotion) { 147 | document.body.classList.add('rotate-motion') 148 | toggleRotation(); 149 | } else { 150 | document.body.classList.remove('rotate-motion'); 151 | toggleRotation(); 152 | } 153 | }); 154 | } 155 | 156 | onResetState() { 157 | document.body.classList.remove('explode', 'explode-motion', 'rotate-motion'); 158 | this.setState({explode: false, expMotion: false, rotMotion: false}); 159 | stopMotion(); 160 | modelRestoreState(); 161 | } 162 | 163 | onSelectionChange() { 164 | if (!this.state.properties) { 165 | return; 166 | } 167 | 168 | // this.setState({ 169 | // 170 | // }) 171 | } 172 | 173 | handlePropertiesClose = () => { 174 | this.setState({ properties: false }) 175 | } 176 | 177 | render() { 178 | 179 | const buttonClass = classnames({ 180 | 'fa': true, 181 | 'fa-expand': !this.state.fullscreen, 182 | 'fa-compress': this.state.fullscreen, 183 | }); 184 | 185 | const propertiesClass = classnames({ 186 | 'fa': true, 187 | 'fa-list': this.state.fullscreen, 188 | }); 189 | 190 | const explodeClass = classnames({ 191 | 'fa': true, 192 | 'fa-cubes': this.state.fullscreen, 193 | }); 194 | 195 | const explodeMotionClass = classnames({ 196 | 'fa': true, 197 | 'fa-bomb': this.state.fullscreen, 198 | }); 199 | 200 | const rotateMotionClass = classnames({ 201 | 'fa': true, 202 | 'fa-repeat': this.state.fullscreen, 203 | }); 204 | 205 | const resetClass = classnames({ 206 | 'fa': true, 207 | 'fa-refresh': this.state.fullscreen, 208 | }); 209 | 210 | const propertiesBtnClass = classnames({ 211 | 'properties-btn': true, 212 | 'btn--active': this.state.properties, 213 | 'btn--deactive': !this.state.properties 214 | }) 215 | 216 | const explodeBtnClass = classnames({ 217 | 'explode-btn': true, 218 | 'btn--active': this.state.explode, 219 | 'btn--deactive': !this.state.explode 220 | }) 221 | 222 | const explodeMotionBtnClass = classnames({ 223 | 'explode-motion-btn': true, 224 | 'expbtn--active': this.state.expMotion, 225 | 'expbtn--deactive': !this.state.expMotion 226 | }) 227 | 228 | const rotateMotionBtnClass = classnames({ 229 | 'rotate-motion-btn': true, 230 | 'rotbtn--active': this.state.rotMotion, 231 | 'rotbtn--deactive': !this.state.rotMotion 232 | }) 233 | 234 | const resetBtnClass = classnames({ 235 | 'reset-btn': true, 236 | 'resetbtn--deactive': !this.state.rotMotion 237 | }) 238 | 239 | return ( 240 |
241 | 242 |
243 | Autodesk Platform Services 244 |
245 |
246 | 249 | 252 | 255 | 258 | 261 | 264 | 265 | { 266 | this.state.properties 267 | ? 268 | : null 269 | } 270 | 271 | 278 |
279 |
280 | ); 281 | } 282 | } 283 | 284 | export default Jumbotron; 285 | -------------------------------------------------------------------------------- /src/components/Jumbotron/index.js: -------------------------------------------------------------------------------- 1 | import Jumbotron from './Jumbotron'; 2 | 3 | export default Jumbotron; 4 | -------------------------------------------------------------------------------- /src/components/Jumbotron/jumbotron.css: -------------------------------------------------------------------------------- 1 | @media only screen 2 | and (min-device-width : 768px) 3 | and (max-device-width : 1024px) { /* STYLES GO HERE */ 4 | .fullscreen .forge-jumbotron .container{ 5 | top: -50px; 6 | } 7 | } 8 | 9 | @media screen and (max-width: 768px) { 10 | .forge-jumbotron .container { 11 | margin-left: 20px; 12 | margin-right: 20px; 13 | min-height: 250px; 14 | } 15 | } 16 | 17 | @media (max-width: 768px) { 18 | .fullscreen .forge-jumbotron .container { 19 | height: 100vh; 20 | width: 90vw; 21 | } 22 | } 23 | 24 | @media (max-width: 768px) { 25 | .explode .forge-jumbotron .range-style { 26 | width: 50%; 27 | } 28 | } 29 | 30 | @media (max-width: 768px) { 31 | .forge-jumbotron .forge-logo img { 32 | width: 200px !important; 33 | } 34 | } 35 | 36 | /*Iphone 5 & 5s*/ 37 | @media (min-device-width : 320px) 38 | and (max-device-width : 568px) { /* STYLES GO HERE */ 39 | .forge-jumbotron .forge-logo img { 40 | width: 200px !important; 41 | } 42 | /* 43 | .forge-jumbotron .forge-btn, .explode-btn, .explode-motion-btn, .rotate-motion-btn, .reset-btn, .properties-btn{ 44 | font-size: 1.2em !important; 45 | height: 35px !important; 46 | width: 35px !important; 47 | } 48 | 49 | .properties-btn{ 50 | right: 40px !important; 51 | } 52 | 53 | .explode-btn { 54 | right: 80px !important; 55 | } 56 | 57 | .explode-motion-btn { 58 | right: 120px !important; 59 | } 60 | 61 | .rotate-motion-btn { 62 | right: 160px !important; 63 | } 64 | 65 | .reset-btn{ 66 | right: 200px !important; 67 | }*/ 68 | 69 | } 70 | 71 | /*Iphone 6 plus*/ 72 | /*@media (min-width : 414px) 73 | and (max-width : 736px)*/ 74 | 75 | @media screen and (max-width: 736px) { /* STYLES GO HERE */ 76 | .forge-jumbotron .forge-logo img { 77 | width: 200px !important; 78 | } 79 | 80 | .fullscreen .forge-jumbotron { 81 | height: 100vh; 82 | } 83 | 84 | .fullscreen .forge-jumbotron .container{ 85 | bottom: 5px; 86 | } 87 | 88 | /* Suppose to handle Safari browser 89 | ::i-block-chrome, .forge-jumbotron .container{ 90 | top: -50px; 91 | }*/ 92 | 93 | .forge-jumbotron .forge-logo { 94 | top: 30px !important; 95 | } 96 | } 97 | 98 | /* CSS for non mobile devices */ 99 | 100 | .forge-jumbotron { 101 | background: #EDEDED; 102 | margin: 0; 103 | padding: 20px 10px; 104 | position: relative; 105 | } 106 | 107 | .forge-jumbotron .container { 108 | height: 60vh; 109 | min-height: 200px; 110 | position: relative; 111 | transition: all 300ms ease; 112 | } 113 | 114 | .fullscreen .forge-jumbotron .container { 115 | height: 100vh; 116 | width: 90vw; 117 | } 118 | 119 | 120 | .forge-jumbotron .forge-logo { 121 | position: absolute; 122 | top: 20px; 123 | left: 30px; 124 | z-index: 2; 125 | } 126 | 127 | /* .forge-jumbotron .forge-logo img { 128 | width: 300px; 129 | } */ 130 | 131 | 132 | .forge-jumbotron .forge-viewer { 133 | bottom: 0; 134 | left: 0; 135 | right: 0; 136 | top: 0; 137 | position: absolute; 138 | } 139 | 140 | .forge-jumbotron .forge-btn { 141 | background-color: #EE8822; 142 | border-radius: 50%; 143 | border: none; 144 | bottom: -48px; 145 | color: white; 146 | font-size: 2em; 147 | height: 55px; 148 | line-height: 1.8; 149 | padding: 0; 150 | position: absolute; 151 | right: 0; 152 | text-align: center; 153 | transition: all 300ms ease; 154 | width: 55px; 155 | z-index: 2; 156 | } 157 | 158 | .forge-jumbotron .forge-btn:focus { 159 | outline: none; 160 | } 161 | 162 | .forge-jumbotron .forge-btn:active { 163 | background-color: #b4610e; 164 | } 165 | 166 | .fullscreen .forge-jumbotron .forge-btn { 167 | bottom: 40px; 168 | } 169 | 170 | .forge-jumbotron .explode-btn, .explode-motion-btn, .rotate-motion-btn, .reset-btn, .properties-btn { 171 | background-color: rgba(135,135,135, 0.6); 172 | border-radius: 50%; 173 | border: none; 174 | bottom: -48px; 175 | color: white; 176 | font-size: 2em; 177 | height: 55px; 178 | line-height: 1.8; 179 | padding: 0; 180 | position: absolute; 181 | text-align: center; 182 | width: 55px; 183 | z-index: 2; 184 | visibility: hidden; 185 | outline: none; 186 | } 187 | 188 | .forge-jumbotron .properties-table { 189 | visibility: hidden; 190 | } 191 | 192 | .fullscreen .forge-jumbotron .properties-table { 193 | visibility: visible; 194 | } 195 | 196 | .properties-btn{ 197 | right: 60px; 198 | } 199 | 200 | .explode-btn { 201 | right: 120px; 202 | } 203 | 204 | .explode-motion-btn { 205 | right: 180px; 206 | } 207 | 208 | .rotate-motion-btn { 209 | right: 240px; 210 | } 211 | 212 | .reset-btn{ 213 | right: 300px; 214 | } 215 | 216 | .fullscreen .forge-jumbotron .properties-btn { 217 | bottom: 40px; 218 | visibility: visible; 219 | } 220 | 221 | .fullscreen .forge-jumbotron .explode-btn { 222 | bottom: 40px; 223 | visibility: visible; 224 | } 225 | 226 | .fullscreen .forge-jumbotron .explode-motion-btn { 227 | bottom: 40px; 228 | visibility: visible; 229 | } 230 | 231 | .fullscreen .forge-jumbotron .rotate-motion-btn { 232 | bottom: 40px; 233 | visibility: visible; 234 | } 235 | 236 | .fullscreen .forge-jumbotron .reset-btn { 237 | bottom: 40px; 238 | visibility: visible; 239 | } 240 | 241 | .forge-jumbotron .btn--active, .expbtn--active, .rotbtn--active { 242 | background-color: rgba(53,102,204, 0.9); 243 | } 244 | 245 | .forge-jumbotron .btn--deactive, .expbtn--deactive, .rotbtn--deactive { 246 | background-color: rgba(135,135,135, 0.6); 247 | } 248 | 249 | .forge-jumbotron .range-style { 250 | background-color: rgba(135,135,135, 0.8); 251 | bottom: -48px; 252 | color: white; 253 | font-size: 2em; 254 | height: 55px; 255 | line-height: 1.8; 256 | padding: 0; 257 | position: absolute; 258 | text-align: center; 259 | transition: all 300ms ease; 260 | width: 55px; 261 | right: 0; 262 | z-index: 2; 263 | visibility: hidden; 264 | transition: visibility 0s linear 300ms, opacity 300ms; 265 | } 266 | 267 | .explode .forge-jumbotron .range-style { 268 | bottom: 100px; 269 | width: 24%; 270 | visibility: visible; 271 | transition: visibility 0s linear 0s, opacity 300ms; 272 | } -------------------------------------------------------------------------------- /src/components/Properties/Properties.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React, { Component } from 'react'; 20 | import { connect } from 'react-redux'; 21 | import './properties.css'; 22 | 23 | class Properties extends Component { 24 | constructor(props) { 25 | super(props); 26 | 27 | this.state = { 28 | collapsed: new Map() 29 | } 30 | 31 | } 32 | 33 | toggleProperty(propertyIndex, evt) { 34 | evt.preventDefault(); 35 | const { collapsed } = this.state; 36 | const isCollapsed = collapsed.get(propertyIndex); 37 | 38 | this.setPropertyByIndex(propertyIndex, !isCollapsed); 39 | } 40 | 41 | setPropertyByIndex(index, isCollapsed) { 42 | const { collapsed } = this.state; 43 | collapsed.set(index, true); 44 | this.setState({ collapsed }); 45 | } 46 | 47 | componentDidMount() { 48 | if (this.props.properties.length === 1) { 49 | this.setPropertyByIndex(0, true); 50 | } 51 | } 52 | 53 | componentDidUpdate(prevProps) { 54 | const { properties } = this.props 55 | 56 | 57 | if (prevProps.properties === properties) { 58 | return 59 | } 60 | 61 | if (properties.length === 1) { 62 | this.setPropertyByIndex(0, true); 63 | } 64 | } 65 | 66 | 67 | render() { 68 | const {collapsed} = this.state; 69 | 70 | return( 71 |
72 |
73 | 74 |

Properties

75 | 76 | {!this.props.properties.length 77 | ?

Select a part to get started

78 | : null 79 | } 80 |
81 |
82 | {this.props.properties.map((property, i) => ( 83 |
    84 |
    85 |

    86 | {property.category} 87 |

    88 |
    89 | { 90 | collapsed.get(i) 91 | ? ( 92 |
    93 |
      94 | {property.data.map((item, itemIndex) => ( 95 |
    • 96 | {item.displayName}: {item.displayValue} 97 |
    • 98 | ))} 99 |
    100 |
    101 | ) 102 | : null 103 | } 104 |
105 | ))} 106 | 107 |
108 |
109 |
110 |
111 | ) 112 | } 113 | } 114 | 115 | 116 | const PropertiesComponent = connect( 117 | state => ({ properties: state.properties }) 118 | )(Properties); 119 | 120 | export default PropertiesComponent; 121 | -------------------------------------------------------------------------------- /src/components/Properties/index.js: -------------------------------------------------------------------------------- 1 | import Properties from './Properties'; 2 | 3 | export default Properties; 4 | -------------------------------------------------------------------------------- /src/components/Properties/properties.css: -------------------------------------------------------------------------------- 1 | .model-properties { 2 | background-color: transparent; 3 | padding: .5em 1em; 4 | position: absolute; 5 | right: 20px; 6 | width: 20%; 7 | z-index: 2; 8 | max-height: 60%; 9 | min-width: 15%; 10 | min-height: 25%; 11 | overflow-y: auto; 12 | } 13 | 14 | .model-properties .close-btn { 15 | visibility: hidden; 16 | } 17 | 18 | @media (max-width: 768px) { 19 | .model-properties { 20 | font-size: 1em; 21 | width: auto; 22 | top: 0; 23 | right: 0; 24 | left: 0; 25 | bottom: 0; 26 | background: rgba(0, 0, 0, .8); 27 | position: fixed; 28 | height: auto; 29 | max-height: 100vh; 30 | padding: 2em; 31 | } 32 | 33 | .model-properties > div { 34 | background: rgba(255, 255, 255, .8); 35 | padding: 2em; 36 | color: black; 37 | } 38 | 39 | .model-properties .close-btn { 40 | border-radius: 50%; 41 | border: none; 42 | color: white; 43 | font-size: 2em; 44 | height: 55px; 45 | line-height: 1.8; 46 | outline: none; 47 | padding: 0; 48 | position: absolute; 49 | right: 10px; 50 | text-align: center; 51 | top: 10px; 52 | width: 55px; 53 | z-index: 2; 54 | visibility: visible; 55 | background-color: rgba(135,135,135, 0.8); 56 | } 57 | } 58 | 59 | .model-properties h3 { 60 | margin: .2em 0; 61 | } 62 | 63 | .model-properties ul { 64 | margin: 0 0 0 1em; 65 | padding: 0; 66 | } 67 | 68 | .model-properties ul li { 69 | margin: 0 0 0 .3em; 70 | padding: 0; 71 | } 72 | 73 | .tg { 74 | border-collapse:collapse; 75 | border-spacing:0; 76 | border-color:#ccc; 77 | margin:0px auto; 78 | } 79 | 80 | .tg td{ 81 | font-family:Arial, sans-serif; 82 | font-size:14px; 83 | padding:10px 5px; 84 | border-style:solid; 85 | border-width:0px; 86 | overflow:hidden; 87 | word-break:normal; 88 | 89 | color:#333; 90 | 91 | border-top-width:1px; 92 | border-bottom-width:1px; 93 | position: relative; 94 | } 95 | 96 | .tg th{ 97 | font-family:Arial, sans-serif; 98 | font-size:14px; 99 | font-weight:normal; 100 | padding:10px 5px; 101 | border-style:solid; 102 | border-width:0px; 103 | overflow:hidden; 104 | word-break:normal; 105 | 106 | color:#333; 107 | 108 | border-top-width:1px; 109 | border-bottom-width:1px; 110 | position: relative; 111 | } 112 | 113 | .tg .tg-yw4l{ 114 | z-index: 2; 115 | } 116 | 117 | @media screen and (max-width: 767px) { 118 | .tg { 119 | width: auto !important; 120 | } 121 | .tg col { 122 | width: auto !important; 123 | } 124 | .tg-wrap { 125 | overflow-x: auto; 126 | -webkit-overflow-scrolling: touch; 127 | margin: auto 0px; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/components/Viewer/Viewer-helpers.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | 20 | /* global Autodesk, THREE */ 21 | import { debounce, uniq } from 'lodash'; 22 | import { actions } from '../../actions'; 23 | import { store } from '../../store'; 24 | 25 | //import Client from '../Client'; 26 | var viewer; 27 | var explodeScale = 0; 28 | var startExplosion = null; 29 | var explosionReq; 30 | var isExploding = false; 31 | var outwardExplosion = true; 32 | var startRotation = null; 33 | var rotationReq; 34 | var isRotating = false; 35 | var tileId = ''; 36 | export var properties = {}; 37 | 38 | 39 | 40 | //The Access Token Logic 41 | 42 | async function getAccessToken(callback) { 43 | try { 44 | const resp = await fetch('/token'); 45 | if (!resp.ok) { 46 | throw new Error(await resp.text()); 47 | } 48 | const { access_token, expires_in } = await resp.json(); 49 | callback(access_token, expires_in); 50 | } catch (err) { 51 | alert('Could not obtain access token. See the console for more details.'); 52 | console.error(err); 53 | } 54 | } 55 | 56 | function launchViewer(div, urn, id) { 57 | tileId = id; 58 | var options = { 59 | 'document': urn, 60 | env: 'AutodeskProduction2', 61 | api: 'streamingV2', // for models uploaded to EMEA change this option to 'streamingV2_EU' 62 | getAccessToken: getAccessToken 63 | }; 64 | 65 | var viewerElement = document.getElementById(div); 66 | viewer = new Autodesk.Viewing.Viewer3D(viewerElement, {}); 67 | 68 | Autodesk.Viewing.Initializer( 69 | options, 70 | function () { 71 | viewer.initialize(); 72 | loadDocument(options.document); 73 | } 74 | ); 75 | 76 | } 77 | 78 | 79 | //The load models function 80 | function loadDocument(documentId){ 81 | Autodesk.Viewing.Document.load( 82 | documentId, 83 | function (doc) { // onLoadCallback 84 | var geometryItems = doc.getRoot().search({ type: 'geometry' }); 85 | if (geometryItems.length > 0) { 86 | geometryItems.forEach(function (item, index) { 87 | }); 88 | viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, onGeometryLoaded); 89 | viewer.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, debounce(() => { 90 | console.log('selection change') 91 | getModelProperties() 92 | .then((modelProperties) => 93 | store.dispatch(actions.getViewerProperties(modelProperties)) 94 | ) 95 | .catch(() => 96 | store.dispatch(actions.getViewerProperties([])) 97 | ) 98 | }), 200); 99 | 100 | //viewer.prefs.tag('ignore-producer'); 101 | // viewer.setLightPreset('Rim Highlights'); 102 | viewer.loadModel (doc.getViewablePath(geometryItems[0])); // show 1st view on this document... 103 | } 104 | }, 105 | function (errorMsg) { // onErrorCallback 106 | console.log(errorMsg); 107 | } 108 | ) 109 | } 110 | 111 | 112 | 113 | ////////////////////////////////////////////////////////////////////////// 114 | // Model Geometry loaded callback 115 | // 116 | ////////////////////////////////////////////////////////////////////////// 117 | function onGeometryLoaded(event) { 118 | var viewer = event.target; 119 | viewer.removeEventListener( 120 | Autodesk.Viewing.GEOMETRY_LOADED_EVENT, 121 | onGeometryLoaded); 122 | viewer.fitToView(); 123 | viewer.setLightPreset('Rim Highlights'); 124 | viewer.setQualityLevel(false,false); // Getting rid of Ambientshadows to false to avoid blackscreen problem in Viewer. 125 | } 126 | 127 | 128 | function getModelProperties() { 129 | return new Promise((resolve, reject) => { 130 | const dbId = viewer.getSelection()[0]; 131 | 132 | if (viewer.getSelectionCount() !== 1) { 133 | return reject('Invalid selection count'); 134 | } 135 | 136 | return new Promise((resolve) => { 137 | viewer.model.getProperties(dbId, (item) => { 138 | const items = item.properties.filter((property) => !property.hidden); 139 | resolve(items); 140 | }); 141 | }) 142 | .then((list) => { 143 | 144 | // Normalize displayCategory property in case it's falsy 145 | list = list.map(item => ({ 146 | ...item, 147 | displayCategory: item.displayCategory || 'Miscellaneous' 148 | })); 149 | 150 | // Unique list of categories 151 | const categories = uniq(list.map(item => item.displayCategory)); 152 | 153 | // Model data to be consumed 154 | // Ex: [ {category: 'Miscellaneous', data: []} ] 155 | const properties = categories.map(category => ( 156 | { 157 | category, 158 | data: list.filter(item => item.displayCategory === category) 159 | } 160 | )); 161 | 162 | resolve(properties); 163 | }); 164 | }); 165 | } 166 | 167 | export function viewerResize() { 168 | viewer.resize(); 169 | } 170 | 171 | export function viewerExplode(num){ 172 | viewer.explode(num); 173 | } 174 | 175 | export function modelRestoreState(){ 176 | var originalState = ""; 177 | 178 | switch (tileId){ 179 | case "0001": 180 | originalState = JSON.parse('{"guid":"f075a989156eb711398","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1RpZV9GaWd0aGVyX1RveS5mM2Q","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[145.8184640788883,93.51676504768685,-124.19785909734301],"target":[0,0,0.0000019073486328125],"up":[-0.3340034881841154,0.8986169812472194,0.28448056329910826],"worldUpVector":[0,1,0],"pivotPoint":[0,0,0.0000019073486328125],"distanceToOrbit":213.15139804714164,"aspectRatio":1.9929737351528332,"projection":"perspective","isOrthographic":false,"fieldOfView":61.92751520437556},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":10,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 181 | console.log("Restoring State for Tile:", tileId); 182 | break; 183 | case "0002": 184 | originalState = JSON.parse('{"guid":"f075a989156eb711397","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1JDJTIwQ2FyLmYzZA","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[268.15901156738664,268.1590007567955,268.15899179720685],"target":[0,-0.0000019073486328125,-0.00000762939453125],"up":[0,1,0],"worldUpVector":[0,1,0],"pivotPoint":[0,-0.0000019073486328125,-0.00000762939453125],"distanceToOrbit":464.4650203923889,"aspectRatio":1.9409698157397892,"projection":"orthographic","isOrthographic":true,"orthographicHeight":464.46502039238896},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":10,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 185 | console.log("Restoring State for Tile:", tileId); 186 | break; 187 | case "0003": 188 | originalState = JSON.parse('{"guid":"f075a989156eb711399","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1RWUi00LUN5Y2wtZW5naW5lLmYzZA","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[947.8717757705549,-947.8718237856292,947.8718169263327],"target":[0,0,0],"up":[0,1,0],"worldUpVector":[0,1,0],"pivotPoint":[0,0,0],"distanceToOrbit":1641.7621261779516,"aspectRatio":2.47171569916115,"projection":"orthographic","isOrthographic":true,"orthographicHeight":1641.7621261779514},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":10,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 189 | console.log("Restoring State for Tile:", tileId); 190 | break; 191 | case "0004": 192 | originalState = JSON.parse('{"guid":"f075a989156eb711400","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L0hvdXNlLmR3Zng","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[-163.8662266489145,0,101.51004011675508],"target":[0,0,0],"up":[0,1,0],"worldUpVector":[0,1,0],"pivotPoint":[0,0,0],"distanceToOrbit":192.76002822332916,"aspectRatio":2.0663910331477187,"projection":"perspective","isOrthographic":false,"fieldOfView":46.48761986856245},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":7.3109139716724485,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 193 | console.log("Restoring State for Tile:", tileId); 194 | break; 195 | case "0005": 196 | originalState = JSON.parse('{"guid":"f075a989156eb711401","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1VyYmFuJTIwSG91c2UlMjAtJTIwMjAxNS5ydnQ","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[71.29038959242611,-71.98501662992042,67.07221817123673],"target":[0,0,-0.0000019073486328125],"up":[0,0,1],"worldUpVector":[0,0,1],"pivotPoint":[0,0,-0.0000019073486328125],"distanceToOrbit":121.50244842685274,"aspectRatio":0.4481514231771144,"projection":"orthographic","isOrthographic":true,"orthographicHeight":121.50244842685272},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":5.211787184833593,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 197 | console.log("Restoring State for Tile:", tileId); 198 | break; 199 | case "0006": 200 | originalState = JSON.parse('{"guid":"f075a989156eb711402","seedURN":"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0LzNkRmFjdG9yeS5kd2Y","overrides":{"transformations":[]},"objectSet":[{"id":[],"isolated":[],"hidden":[],"explodeScale":0,"idType":"lmv"}],"viewport":{"name":"","eye":[74.02664223103163,-62.794491882241786,57.115458464302066],"target":[0,-9.5367431640625e-7,-2.384185791015625e-7],"up":[0,0,1],"worldUpVector":[0,0,1],"pivotPoint":[0,-9.5367431640625e-7,-2.384185791015625e-7],"distanceToOrbit":112.62889271319895,"aspectRatio":1.8124895442487394,"projection":"perspective","isOrthographic":false,"fieldOfView":28.656461643949527},"renderOptions":{"environment":"Rim Highlights","ambientOcclusion":{"enabled":false,"radius":2.7574370487702686,"intensity":0.4},"toneMap":{"method":1,"exposure":-9,"lightMultiplier":-1e-20},"appearance":{"ghostHidden":true,"ambientShadow":false,"antiAliasing":true,"progressiveDisplay":true,"displayLines":true}},"cutplanes":[]}'); 201 | console.log("Restoring State for Tile:", tileId); 202 | break; 203 | default: 204 | console.log("Sorry, no model selected"); 205 | } 206 | 207 | 208 | viewer.restoreState(originalState, false, false); 209 | } 210 | 211 | /** 212 | * toggle explosion motion 213 | * @param boolean cancelMotion - true if cancel motion is requested 214 | */ 215 | export function toggleExplosion(cancelMotion) { 216 | if (cancelMotion || isExploding) { 217 | cancelAnimationFrame(explosionReq); 218 | isExploding = false; 219 | if (cancelMotion) { 220 | explodeScale = 0; 221 | viewer.explode(explodeScale); 222 | } 223 | } else { 224 | explodeMotion(); 225 | isExploding = true; 226 | } 227 | } 228 | 229 | /** 230 | * Recursive function for calling requestAnimationFrame for explode motion 231 | */ 232 | 233 | export function explodeMotion(timestamp) { 234 | if (!startExplosion) { 235 | startExplosion = timestamp; 236 | } 237 | var progress = timestamp - startExplosion; 238 | startExplosion = timestamp; 239 | var explodeStep = 0.0002 * (progress || 0); 240 | // explode outward and inward 241 | if (outwardExplosion) { 242 | explodeScale += explodeStep; 243 | } else { 244 | explodeScale -= explodeStep; 245 | } 246 | if (explodeScale > 1) { 247 | outwardExplosion = false; 248 | explodeScale = 1; // this solves when user go to another browser tab 249 | } else if (explodeScale < 0) { 250 | outwardExplosion = true; 251 | explodeScale = 0; // this solves when user go to another browser tab 252 | } 253 | viewer.explode(explodeScale); 254 | explosionReq = window.requestAnimationFrame(explodeMotion); 255 | }; 256 | 257 | /** 258 | * recursive function for rotation motion each time page refreshes 259 | */ 260 | export function rotateMotion(timestamp) { 261 | if (!startRotation) { 262 | startRotation = timestamp; 263 | } 264 | var progress = timestamp - startRotation; 265 | startRotation = timestamp; 266 | var rotateStep = 0.0005 * (progress || 0); 267 | // get the up axis 268 | var worldUp = viewer.navigation.getWorldUpVector(); 269 | // get the current position 270 | var pos = viewer.navigation.getPosition(); 271 | // copy that position 272 | var position = new THREE.Vector3(pos.x, pos.y, pos.z); 273 | // set the rotate axis 274 | var rAxis = new THREE.Vector3(worldUp.x, worldUp.y, worldUp.z); 275 | var matrix = new THREE.Matrix4().makeRotationAxis(rAxis, rotateStep); 276 | //apply the new position 277 | position.applyMatrix4(matrix); 278 | viewer.navigation.setPosition(position); 279 | rotationReq = window.requestAnimationFrame(rotateMotion); 280 | } 281 | 282 | 283 | /** 284 | * Toggle the rotation movement 285 | * @param boolean cancelMotion true if motion is to be cancelled 286 | */ 287 | export function toggleRotation(cancelMotion) { 288 | if (cancelMotion || isRotating) { 289 | cancelAnimationFrame(rotationReq); 290 | isRotating = false; 291 | } else { 292 | rotateMotion(); 293 | isRotating = true; 294 | } 295 | } 296 | 297 | export function stopMotion() { 298 | toggleExplosion(true); 299 | toggleRotation(true); 300 | } 301 | 302 | 303 | const Helpers = { 304 | launchViewer, 305 | loadDocument 306 | }; 307 | 308 | export default Helpers; 309 | -------------------------------------------------------------------------------- /src/components/Viewer/Viewer.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React, { Component } from 'react'; 20 | import Helpers from './Viewer-helpers'; 21 | 22 | class Viewer extends Component { 23 | 24 | componentDidMount() { 25 | // RC Car Model 26 | var documentId = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dmlld2VyLXJvY2tzLXJlYWN0L1RWUi00LUN5Y2wtZW5naW5lLmYzZA'; 27 | Helpers.launchViewer('viewerDiv', documentId , '0003'); 28 | 29 | } 30 | 31 | render() { 32 | return ( 33 |
34 | ); 35 | } 36 | } 37 | 38 | export default Viewer; 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Jaime Rosales 2016 - Forge Developer Partner Services 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReactDOM from 'react-dom'; 21 | import App from './components/App'; 22 | import { Provider } from 'react-redux'; 23 | import store from './store'; 24 | 25 | ReactDOM.render( 26 | ( 27 | 28 | 29 | 30 | ), 31 | document.getElementById('root') 32 | ); 33 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import viewerReducer from './viewerReducer'; 2 | export default viewerReducer; 3 | -------------------------------------------------------------------------------- /src/reducers/viewerReducer.js: -------------------------------------------------------------------------------- 1 | import { types } from '../actions'; 2 | 3 | const initialState = { 4 | properties: [] 5 | }; 6 | 7 | export default function viewer(state = initialState, action) { 8 | switch(action.type) { 9 | case types.GET_AGGREGATE_PROPERTIES: 10 | const { properties } = action; 11 | return { 12 | ...state, 13 | properties, 14 | } 15 | default: 16 | return state; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'redux'; 2 | import reducers from './reducers'; 3 | 4 | export const store = createStore(reducers); 5 | export default store; -------------------------------------------------------------------------------- /thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/viewer-react-express-headless/03292f6321ccae0e8ac5b8dcf6b921ea280977e9/thumbnail.png --------------------------------------------------------------------------------