viewer.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { TemplateManager } from './../templateManager';
  2. import configurationLoader from './../configuration/loader';
  3. import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight } from 'babylonjs';
  4. import { ViewerConfiguration } from '../configuration/configuration';
  5. export abstract class AbstractViewer {
  6. public templateManager: TemplateManager;
  7. public engine: Engine;
  8. public scene: Scene;
  9. public baseId: string;
  10. protected configuration: ViewerConfiguration;
  11. constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { defaultViewer: true }) {
  12. // if exists, use the container id. otherwise, generate a random string.
  13. if (containerElement.id) {
  14. this.baseId = containerElement.id;
  15. } else {
  16. this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
  17. }
  18. this.templateManager = new TemplateManager(containerElement);
  19. this.prepareContainerElement();
  20. // extend the configuration
  21. configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
  22. this.configuration = configuration;
  23. // initialize the templates
  24. let templateConfiguration = this.configuration.template || {};
  25. this.templateManager.initTemplate(templateConfiguration);
  26. // when done, execute onTemplatesLoaded()
  27. this.templateManager.onAllLoaded.add(() => {
  28. this.onTemplatesLoaded();
  29. })
  30. });
  31. }
  32. public getBaseId(): string {
  33. return this.baseId;
  34. }
  35. protected abstract prepareContainerElement();
  36. /**
  37. * This function will execute when the HTML templates finished initializing.
  38. * It should initialize the engine and continue execution.
  39. *
  40. * @protected
  41. * @returns {Promise<AbstractViewer>} The viewer object will be returned after the object was loaded.
  42. * @memberof AbstractViewer
  43. */
  44. protected onTemplatesLoaded(): Promise<AbstractViewer> {
  45. return this.initEngine().then(() => {
  46. return this.loadModel();
  47. }).then(() => {
  48. return this;
  49. });
  50. }
  51. /**
  52. * Initialize the engine. Retruns a promise in case async calls are needed.
  53. *
  54. * @protected
  55. * @returns {Promise<Engine>}
  56. * @memberof Viewer
  57. */
  58. protected initEngine(): Promise<Engine> {
  59. let canvasElement = this.templateManager.getCanvas();
  60. if (!canvasElement) {
  61. return Promise.reject('Canvas element not found!');
  62. }
  63. let config = this.configuration.engine || {};
  64. // TDO enable further configuration
  65. this.engine = new Engine(canvasElement, !!config.antialiasing);
  66. window.addEventListener('resize', () => {
  67. this.engine.resize();
  68. });
  69. this.engine.runRenderLoop(() => {
  70. this.scene && this.scene.render();
  71. });
  72. var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
  73. this.engine.setHardwareScalingLevel(scale);
  74. return Promise.resolve(this.engine);
  75. }
  76. protected initScene(): Promise<Scene> {
  77. // if the scen exists, dispose it.
  78. if (this.scene) {
  79. this.scene.dispose();
  80. }
  81. // create a new scene
  82. this.scene = new Scene(this.engine);
  83. // make sure there is a default camera and light.
  84. this.scene.createDefaultCameraOrLight(true, true, true);
  85. return Promise.resolve(this.scene);
  86. }
  87. public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
  88. let modelUrl = (typeof model === 'string') ? model : model.url;
  89. let parts = modelUrl.split('/');
  90. let filename = parts.pop();
  91. let base = parts.join('/') + '/';
  92. return Promise.resolve().then(() => {
  93. if (!this.scene || clearScene) return this.initScene();
  94. else return this.scene;
  95. }).then(() => {
  96. return new Promise<Array<AbstractMesh>>((resolve, reject) => {
  97. SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
  98. resolve(meshes);
  99. }, undefined, (e, m, exception) => {
  100. console.log(m, exception);
  101. reject(m);
  102. });
  103. });
  104. }).then((meshes: Array<AbstractMesh>) => {
  105. return this.onModelLoaded(meshes);
  106. });
  107. }
  108. protected onModelLoaded(meshes: Array<AbstractMesh>): Promise<Scene> {
  109. console.log("model loaded");
  110. return Promise.resolve(this.scene);
  111. }
  112. public abstract initEnvironment(): Promise<Scene>;
  113. }