1'use strict'; 2 3/** 4 * Isemantics. Michel Peters 5 * 6 * Redistributions of files must retain the above copyright notice. 7 * If you did not receive a copy of the license and are unable to obtain it through 8 * the web, please send a note to [email protected] so we can mail you a 9 * copy immediately. 10 * 11 * @category Javascript 12 * @package App 13 * @author Michel Peters <[email protected]> 14 * @copyright 2015-2018 Isemantics 15 * @license Proprietary licence 16 * @version GIT: $Id$ 17 * @link https://www.isemantics.nl 18 * @since 1.0.0 19 */ 20 21 /** 22 * Main configurator class/handler 23 */ 24function Configurator(domElementId) { 25 if (domElementId == null || domElementId == "") { 26 console.error('Creating configurator failed because no DOM element ID was given.'); 27 return false; 28 } 29 // Self-reference 30 let self = this; 31 32 // HTML elements for configurator and preview 33 self.element = $(domElementId); 34 35 // GLTF exporter 36 self.exporter = new ConfiguratorExporter(); 37 38 // Create UI component 39 self.ui = new ConfiguratorUI(self, { element: self.element }); 40 41 // Main renderer for everything 3D/view 42 self.renderer = new ConfiguratorRenderer(self, 'configuratorRenderer'); 43 44 // Create asset loader 45 self.assetLoader = new ConfiguratorLoader(self, CONFIGURATOR_PATHS); 46 47 // Scene manager 48 self.scene = new ConfiguratorScene(self); 49 50 // Data processor/manager 51 self.data = new ConfiguratorData(self); 52 53 /** 54 * Bootstrap 55 */ 56 self.start = function () { 57 logger.debug('core::start'); 58 // First of all: Check browser support 59 if (browser_detector.detect() === false) { 60 self.ui.showNoBrowserSupportMessage(); 61 return false; 62 } 63 // Set state/UI to loading 64 self.ui.setLoading(true); 65 // Create asset loader and add all known assets 66 self.assetLoader.setLoadingCompletedCallback(self.eventAssetLoadingFinished); 67 self.assetLoader.start(); 68 } 69 70 self.eventAssetLoadingFinished = function () 71 { 72 logger.debug('core::eventAssetLoadingFinished: done preloading all assets for configurator, starting render'); 73 // Trigger initialize for further loading 74 self.initialize(); 75 }; 76 77 /** 78 * Initialize 79 */ 80 self.initialize = function() { 81 logger.debug('core::initialize'); 82 // Initialize renderer 83 self.renderer.initialize(); 84 // Let UI update to current state 85 self.ui.initialize(); 86 // Done loading everything 87 self.ui.setLoading(false); 88 // Create intial scene 89 self.scene.initialize(); 90 // Start actually rendering 91 self.renderer.start(); 92 93 self.eventModelChanged(); 94 } 95 96 self.setConnectorPosition = function (pos) { 97 if (self.getModel() == null) return false; 98 // Update model 99 self.getModel().setConnectorPosition(pos); 100 // Refresh 101 self.refresh(); 102 self.ui.refresh(); 103 } 104 105 self.setDisplayCase = function (id, label) { 106 // Update model 107 self.getModel().setDisplayCase(id, label); 108 // Refresh 109 self.refresh(); 110 self.ui.refresh(); 111 } 112 113 self.setDisplayCaseHeight = function (height) { 114 // Update model 115 self.getModel().setDisplayCaseHeight(height); 116 // Refresh 117 self.refresh(); 118 self.ui.refresh(); 119 } 120 121 self.setProductId = function (productId) { 122 // Update model 123 self.getModel().setProductId(productId); 124 // Refresh 125 self.refresh(); 126 self.ui.refresh(); 127 } 128 129 self.resetCamera = function () { 130 if (self.renderer === null) return; 131 self.renderer.resetCamera(); 132 } 133 134 /** 135 * Export configurator 3D data to GLTF. Will hide the environment and texts, 136 * among other things. This because we will get a cleaner image of only the model 137 */ 138 self.doExport = function (successCallback, errorCallback) { 139 // Hide all non-model meshes/elements
140 self.scene.removeBackgroundScene(); 141 // Get/do export 142 // @note: no return value, will call the success/error callback 143 self.exporter.getExport(self.scene.getScene(), successCallback, errorCallback); 144 // Show all non-model meshes/elements again for normal rendering 145 //self.scene.addBackgroundScene(); 146 } 147 148 self.getState = function () { 149 if (self.getModel() == null) return false; 150 return self.getModel().getState(); 151 } 152 153 /** 154 * This will remove the entire current model state and initialize/set 155 * the given new state. 156 */ 157 self.setState = function (newState) { 158 logger.debug('core::getState: removing old model and initializing new state'); 159 // Clear current scene 160 //self.scene.clear();s 161 // Set new state 162 self.scene.createModel(newState); 163 } 164 165 self.getScene = function () { 166 return self.scene; 167 } 168 169 self.getModel = function () { 170 logger.debug('core::getModel'); 171 return self.getModel(); 172 } 173 174 self.refresh = function () { 175 logger.debug('core::refresh'); 176 // Update model state 177 let state = self.getState(); 178 // Refresh scene with model state 179 self.scene.refresh(state); 180 } 181 182 self.resetMaterialsTab = function (tab) { 183 let type = tab.data('type'); 184 $("#product-size-type").val(type); 185 }; 186 187 self.isCustomTopProductId = function (topProductId) { 188 return self.getData().isCustomTopProductId(topProductId); 189 } 190 191 self.isCustomProductId = function (productId) { 192 return self.getData().isCustomProductId(productId); 193 } 194 195 self.convertToCustomProductId = function (productId) { 196 let idPart = productId.substring(0, productId.length - 7); 197 return idPart + "0000000"; 198 } 199 200 self.setPlint = function (uiState) { 201 // Update model 202 self.getModel().setPlint(uiState); 203 // Refresh 204 self.refresh(); 205 self.ui.refresh(); 206 } 207 208 self.setLighting = function (lightingType, lightingId, lightingLabel) { 209 // Update model 210 self.getModel().setLighting(lightingType, lightingId, lightingLabel); 211 // Refresh 212 self.refresh(); 213 self.ui.refresh(); 214 } 215 216 self.setLightingCount = function (count) { 217 // Update model 218 self.getModel().setLightingCount(count); 219 // Refresh 220 self.refresh(); 221 self.ui.refresh(); 222 } 223 224 self.setLightingPattern = function (pattern) { 225 // Update model 226 self.getModel().setLightingPattern(pattern); 227 // Refresh 228 self.refresh(); 229 self.ui.refresh(); 230 } 231 232 self.setTurnTable = function (turnTable) { 233 // Get current turn table from list of possibilities 234 // This, so that we can get the name translated for this turn table ( if any ) 235 // TODO: check model_id and category_id exist/not empty 236 let turnTableLabel = null; 237 if (turnTable !== null) { 238 let s = this.getState(); 239 let turnTables = self.getData().getTurnTables(s.model_id, s.category_id); 240 if (turnTables[turnTable] != undefined 241 && turnTables[turnTable].name != undefined) { 242 turnTableLabel = turnTables[turnTable].name; 243 } 244 } 245 // Update model state 246 self.getModel().setTurnTable(turnTable, turnTableLabel); 247 // Refresh 248 self.refresh(); 249 self.ui.refresh(); 250 } 251 252 self.setTop = function (topProductId) { 253 // Update model 254 self.getModel().setTop(topProductId); 255 // Refresh 256 self.refresh(); 257 self.ui.refresh(); 258 } 259 260 self.setDoorPosition = function (newPosition) { 261 // Update model 262 self.getModel().setDoorPosition(newPosition); 263 // Refresh 264 self.refresh(); 265 self.ui.refresh(); 266 } 267 268 self.setDoorOpening = function (newPosition) { 269 // Update model 270 self.getModel().setDoorOpening(newPosition); 271 // Refresh 272 self.refresh(); 273 self.ui.refresh(); 274 } 275 276 self.setMaterialId = function (materialId, categoryId) { 277 const currentMaterialId = self.getModel() ? self.getModel().getState().material_id : null; 278 const currentCategoryId = self.getModel() ? self.getModel().getState().category_id : null; 279 280 if (materialId != currentMaterialId || currentCategoryId != categoryId) { 281 logger.debug('core::setMaterialId: Material (material ID or category ID) has changed'); 282 self.eventMaterialChanged(materialId, categoryId); 283 return true; 284 } 285 return false;
286 } 287 288 self.eventMaterialChanged = function (materialId, categoryId) { 289 logger.debug('core::eventMaterialChanged('+materialId+', '+categoryId+'): updating model material'); 290 // Update model 291 self.getModel().setMaterialId(materialId, categoryId); 292 // Refresh model 293 self.refresh(); 294 self.ui.refresh(); 295 } 296 297 self.setMaterialColor = function (materialColorId) { 298 logger.debug('core::eventMaterialChanged(' + materialColorId + ')'); 299 const currentModelId = self.getModel() ? self.getModel().getState().model_id : null; 300 // Update model 301 self.getModel().setMaterialColor(materialColorId); 302 // Refresh model 303 self.refresh(); 304 self.ui.refresh(); 305 } 306 307 self.setModelId = function (newModelId) { 308 logger.debug('core::setModelId(' + newModelId + ')'); 309 const currentModelId = self.getModel() ? self.getModel().getState().model_id : null; 310 311 // Only trigger on different model 312 if (newModelId == currentModelId) { 313 logger.debug('NOTICE: Model change cancelled, because it is the currently selected model'); 314 return false; 315 } 316 317 // Create new model 318 self.scene.createModel({ 319 model_id: newModelId 320 }); 321 322 self.eventModelChanged(); 323 324 } 325 326 self.eventModelChanged = function () { 327 logger.debug('core::eventModelChanged'); 328 // ### Update data shown in UI based on current state 329 let state = self.getState(); 330 let modelId = parseInt(state.model_id); 331 let categoryId = parseInt(state.category_id); 332 logger.debug('core::eventModelChanged: model ID = ' + modelId); 333 logger.debug('core::eventModelChanged: category ID = ' + categoryId); 334 335 // Update axes helper 336 self.scene.updateGrid(); 337 338 // Let UI refresh to reflect current model state (for example: tabs and selected items) 339 self.ui.refresh(); 340 } 341 342 self.getModel = function () { 343 return self.scene.getModel(); 344 } 345 346 self.getAsset = function (key) { 347 return self.assetLoader.getAsset(key); 348 } 349 350 self.setDimensions = function (width, height, depth) { 351 if (self.getModel() == null) return false; 352 353 // Note: removed parseInt and used parseFloat because it could have "31.5" 354 width = parseFloat(width); 355 height = parseFloat(height); 356 depth = parseFloat(depth); 357 358 // Set dimensions on model 359 self.getModel().setDimensions(width, height, depth); 360 361 // Refresh 362 self.refresh(); 363 self.ui.refresh(); 364 365 return true; 366 } 367 368 /** 369 * Set wire color for current model 370 */ 371 self.setWireColor = function(value) { 372 // Update model 373 self.getModel().setWireColor(value); 374 // Refresh 375 self.ui.refresh(); 376 } 377 378 /** 379 * Resize event handler 380 */ 381 self.resize = function () { 382 logger.debug('core::resize'); 383 // Update renderer based on new width/height and ratio 384 self.renderer.resize(); 385 } 386 387 /** 388 * Returns a reference to the renderer object 389 */ 390 self.getRenderer = function () { 391 return self.renderer; 392 } 393 394 /** 395 * Get a frame from the renderer as base64 (for screenshot or saving) 396 */ 397 self.getCanvasImageAsBase64 = function () { 398 logger.debug('core::getCanvasImageAsBase64'); 399 // Get frame from renderer as base64 400 return self.renderer.getCanvasImageAsBase64(); 401 } 402 403 /** 404 * Get reference to main camera 405 */ 406 self.getCamera = function() 407 { 408 if (self.renderer != null) return; 409 return self.renderer.getCamera(); 410 } 411 412 /** 413 * Pan up 414 */ 415 self.panCamera = function (direction) 416 { 417 if (self.renderer == null) return; 418 self.renderer.panCamera(direction); 419 } 420 421 /** 422 * Zoom in 423 */ 424 self.zoomCamera = function (direction) 425 { 426 if (self.renderer == null) return; 427 self.renderer.zoomCamera(direction); 428 } 429 430 self.getData = function () 431 { 432 return self.data; 433 } 434 435 self.getDPR = function () 436 { 437 if (self.renderer == null) return; 438 return self.renderer.getDPR(); 439 } 440 441 // Return public class method mapping 442 return { 443 // Core methods 444 start: self.start, 445 refresh: self.refresh, 446 getState: self.getState, 447 setState: self.setState, 448 getModel: self.getModel, 449 getDPR: self.getDPR, 450 getCanvasImageAsBase64: self.getCanvasImageAsBase64, 451 getLoadingState: self.getLoadingState, 452 getAsset: self.getAsset, 453 doExport: self.doExport, 454 getScene: self.getScene, 455 getRenderer: self.getRenderer, 456 resize: self.resize, 457 getData: self.getData, 458 isCustomProductId: self.isCustomProductId, 459 // Camera 460 zoomCamera: self.zoomCamera, 461 panCamera: self.panCamera, 462 getCamera: self.getCamera, 463 // Model setters 464 setPlint: self.setPlint, 465 setProductId: self.setProductId, 466 setModelId: self.setModelId, 467 setMaterialId: self.setMaterialId, 468 setDimensions: self.setDimensions, 469 setDisplayCase: self.setDisplayCase, 470 setDisplayCaseHeight: self.setDisplayCaseHeight, 471 setWireColor: self.setWireColor, 472 setLighting: self.setLighting, 473 setLightingCount: self.setLightingCount, 474 setLightingPattern: self.setLightingPattern, 475 setConnectorPosition: self.setConnectorPosition, 476 setMaterialColor: self.setMaterialColor, 477 setTurnTable: self.setTurnTable, 478 setDoorPosition: self.setDoorPosition, 479 } 480}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.