Przeglądaj źródła

Merge pull request #3133 from RaananW/viewer-0.2

Viewer 0.2
Raanan Weber 7 lat temu
rodzic
commit
557ea0c74b

+ 4 - 1
Viewer/dist/basicExample.html

@@ -11,7 +11,7 @@
                 max-width: 800px;
                 max-height: 500px;
                 width: 100%;
-                height: 100%;
+                height: 600px;
             }
         </style>
     </head>
@@ -21,6 +21,9 @@
             model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
         <script src="viewer.js"></script>
         <script>
+            // The following lines are redundant. 
+            // They are only here to show how you could achive the tag initialization on your own.
+
             // a simple way of disabling auto init 
             BabylonViewer.disableInit = true;
             // Initializing the viewer on specific HTML tags.

+ 67 - 0
Viewer/dist/eventsExample.html

@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                max-width: 800px;
+                max-height: 500px;
+                width: 100%;
+                height: 600px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon id="babylon-viewer" model.title="Amazing Rabbit" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" observers.on-scene-init="globalSceneInitCallback"></babylon>
+        <script src="viewer.js"></script>
+        <script>
+            //get by id ONLY after viewer init
+            var willNotWork = BabylonViewer.viewerManager.getViewerById('babylon-viewer');
+            console.log('viewer not yet initialized');
+
+            // Pomise-based API:
+            BabylonViewer.viewerManager.getViewerPromiseById('babylon-viewer').then(function (viewer) {
+                // this will resolve only after the viewer with this specific ID is initialized
+                console.log('Using promises: ', 'viewer - ' + viewer.getBaseId());
+
+                viewerObservables(viewer);
+            });
+
+            // call back variant:
+            BabylonViewer.viewerManager.onViewerAdded = function (viewer) {
+                console.log('Using viewerManager.onViewerAdded: ', 'viewer - ' + viewer.getBaseId());
+            }
+
+            // using observers:
+            BabylonViewer.viewerManager.onViewerAddedObservable.add(function (viewer) {
+                console.log('Using viewerManager.onViewerAddedObservable: ', 'viewer - ' + viewer.getBaseId());
+            });
+
+            function viewerObservables(viewer) {
+                viewer.onEngineInitObservable.add(function (engine) {
+                    console.log('Engine initialized');
+                });
+
+                viewer.onSceneInitObservable.add(function (scene) {
+                    console.log('Scene initialized');
+                });
+
+                viewer.onModelLoadedObservable.add(function (meshes) {
+                    console.log('Model loaded');
+                });
+            }
+
+            function globalSceneInitCallback(scene) {
+                console.log('scene-init function defined in the configuration');
+            }
+
+        </script>
+    </body>
+
+</html>

Plik diff jest za duży
+ 3452 - 1657
Viewer/dist/viewer.js


+ 8 - 8
Viewer/package.json

@@ -1,6 +1,6 @@
 {
     "name": "babylonjs-viewer",
-    "version": "0.1.0",
+    "version": "0.2.0",
     "description": "A viewer using BabylonJS to display 3D elements natively",
     "scripts": {
         "start:server": "webpack-dev-server",
@@ -23,7 +23,7 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^8.0.47",
+        "@types/node": "^8.0.51",
         "base64-image-loader": "^1.2.0",
         "html-loader": "^0.5.1",
         "json-loader": "^0.5.7",
@@ -34,15 +34,15 @@
         "webpack-dev-server": "^2.9.4"
     },
     "dependencies": {
-        "babylonjs": "^3.1.0-alpha3.7",
-        "babylonjs-loaders": "^3.1.0-alpha3.7",
-        "babylonjs-materials": "^3.1.0-alpha3.7",
-        "babylonjs-post-process": "^3.1.0-alpha3.7",
-        "babylonjs-procedural-textures": "^3.1.0-alpha3.7",
+        "babylonjs": "^3.1.0-beta1.1.1",
+        "babylonjs-loaders": "^3.1.0-beta1.1",
+        "babylonjs-materials": "^3.1.0-beta1.1",
+        "babylonjs-post-process": "^3.1.0-beta1.1",
+        "babylonjs-procedural-textures": "^3.1.0-beta1.1",
         "es6-promise": "^4.1.1",
         "handlebars": "^4.0.11",
         "lodash": "^4.17.4",
         "lodash.merge": "^4.6.0",
         "promise-polyfill": "^6.0.2"
     }
-}
+}

+ 12 - 3
Viewer/src/configuration/configuration.ts

@@ -13,7 +13,8 @@ export interface ViewerConfiguration {
         mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
     };
 
-    // native (!!!) javascript events. Mainly used in the JSON-format.
+    // Deprecated
+    /*// native (!!!) javascript events. Mainly used in the JSON-format.
     // those events will be triggered by the container element (the <babylon> tag);
     events?: {
         load: boolean | string;
@@ -23,8 +24,15 @@ export interface ViewerConfiguration {
         pointerup: boolean | string;
         pointermove: boolean | string;
         // load: 'onViewerLoaded' // will trigger the event prefix-onViewerLoaded instead of prefix-onLoad (and ONLY this event).
-    } | boolean; //events: true - fire all events
-    eventPrefix?: string;
+    } | boolean; //events: true - fire all events*/
+    //eventPrefix?: string;
+
+    // names of functions in the window context.
+    observers?: {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
 
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
 
@@ -46,6 +54,7 @@ export interface ViewerConfiguration {
     };
 
     scene?: {
+        debug?: boolean;
         autoRotate?: boolean;
         rotationSpeed?: number;
         defaultCamera?: boolean;

+ 2 - 2
Viewer/src/configuration/types/default.ts

@@ -2,8 +2,8 @@ import { ViewerConfiguration } from './../configuration';
 
 export let defaultConfiguration: ViewerConfiguration = {
     version: "0.1",
-    eventPrefix: 'babylonviewer-',
-    events: true,
+    //eventPrefix: 'babylonviewer-',
+    //events: true,
     templates: {
         main: {
             html: require("../../../assets/templates/default/defaultTemplate.html")

+ 39 - 0
Viewer/src/util/promiseObservable.ts

@@ -0,0 +1,39 @@
+import { Observable, Nullable, Observer } from "babylonjs";
+
+export class PromiseObservable<T> extends Observable<T> {
+
+    public notifyWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<any> {
+
+        let p = Promise.resolve();
+
+        if (!this._observers.length) {
+            return p;
+        }
+
+        let state = this['_eventState'];
+        state.mask = mask;
+        state.target = target;
+        state.currentTarget = currentTarget;
+        state.skipNextObservers = false;
+
+        this._observers.forEach(obs => {
+            if (state.skipNextObservers) {
+                return;
+            }
+            if (obs.mask & mask) {
+                if (obs.scope) {
+                    // TODO - I can add the variable from the last function here. Requires changing callback sig
+                    p = p.then(() => {
+                        return obs.callback.apply(obs.scope, [eventData, state]);
+                    });
+                } else {
+                    p = p.then(() => {
+                        return obs.callback(eventData, state);
+                    });
+                }
+            }
+        });
+
+        return p;
+    }
+}

+ 7 - 1
Viewer/src/viewer/defaultViewer.ts

@@ -1,3 +1,4 @@
+import { ViewerConfiguration } from './../configuration/configuration';
 import { Template } from './../templateManager';
 import { AbstractViewer } from './viewer';
 import { Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
@@ -11,6 +12,11 @@ export class DefaultViewer extends AbstractViewer {
 
     public camera: ArcRotateCamera;
 
+    constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
+        super(containerElement, initialConfiguration);
+        this.onModelLoadedObservable.add(this.onModelLoaded);
+    }
+
     public initScene(): Promise<Scene> {
         return super.initScene().then(() => {
             this.extendClassWithConfig(this.scene, this.configuration.scene);
@@ -132,7 +138,7 @@ export class DefaultViewer extends AbstractViewer {
         });
     }
 
-    public onModelLoaded(meshes: Array<AbstractMesh>) {
+    private onModelLoaded = (meshes: Array<AbstractMesh>) => {
 
         // here we could set the navbar's model information:
         this.setModelMetaData();

+ 36 - 11
Viewer/src/viewer/viewer.ts

@@ -3,6 +3,7 @@ import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
 import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight } from 'babylonjs';
 import { ViewerConfiguration } from '../configuration/configuration';
+import { PromiseObservable } from '../util/promiseObservable';
 
 export abstract class AbstractViewer {
 
@@ -14,6 +15,11 @@ export abstract class AbstractViewer {
 
     protected configuration: ViewerConfiguration;
 
+    // observables
+    public onSceneInitObservable: PromiseObservable<Scene>;
+    public onEngineInitObservable: PromiseObservable<Engine>;
+    public onModelLoadedObservable: PromiseObservable<AbstractMesh[]>;
+
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
         if (containerElement.id) {
@@ -22,6 +28,10 @@ export abstract class AbstractViewer {
             this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
         }
 
+        this.onSceneInitObservable = new PromiseObservable();
+        this.onEngineInitObservable = new PromiseObservable();
+        this.onModelLoadedObservable = new PromiseObservable();
+
         // add this viewer to the viewer manager
         viewerManager.addViewer(this);
 
@@ -33,6 +43,20 @@ export abstract class AbstractViewer {
         // extend the configuration
         configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
             this.configuration = configuration;
+
+            // adding preconfigured functions
+            if (this.configuration.observers) {
+                if (this.configuration.observers.onEngineInit) {
+                    this.onEngineInitObservable.add(window[this.configuration.observers.onEngineInit]);
+                }
+                if (this.configuration.observers.onSceneInit) {
+                    this.onSceneInitObservable.add(window[this.configuration.observers.onSceneInit]);
+                }
+                if (this.configuration.observers.onModelLoaded) {
+                    this.onModelLoadedObservable.add(window[this.configuration.observers.onModelLoaded]);
+                }
+            }
+
             // initialize the templates
             let templateConfiguration = this.configuration.templates || {};
             this.templateManager.initTemplate(templateConfiguration);
@@ -93,7 +117,9 @@ export abstract class AbstractViewer {
         var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
         this.engine.setHardwareScalingLevel(scale);
 
-        return Promise.resolve(this.engine);
+        return this.onEngineInitObservable.notifyWithPromise(this.engine).then(() => {
+            return this.engine;
+        });
     }
 
     protected initScene(): Promise<Scene> {
@@ -107,7 +133,12 @@ export abstract class AbstractViewer {
         this.scene = new Scene(this.engine);
         // make sure there is a default camera and light.
         this.scene.createDefaultCameraOrLight(true, true, true);
-        return Promise.resolve(this.scene);
+        if (this.configuration.scene && this.configuration.scene.debug) {
+            this.scene.debugLayer.show();
+        }
+        return this.onSceneInitObservable.notifyWithPromise(this.scene).then(() => {
+            return this.scene;
+        });
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
@@ -130,15 +161,9 @@ export abstract class AbstractViewer {
                 }, plugin);
             });
         }).then((meshes: Array<AbstractMesh>) => {
-            return this.onModelLoaded(meshes);
+            return this.onModelLoadedObservable.notifyWithPromise(meshes).then(() => {
+                return this.scene;
+            });
         });
     }
-
-    protected onModelLoaded(meshes: Array<AbstractMesh>): Promise<Scene> {
-        console.log("model loaded");
-        return Promise.resolve(this.scene);
-    }
-
-    public abstract initEnvironment(): Promise<Scene>;
-
 }

+ 23 - 0
Viewer/src/viewer/viewerManager.ts

@@ -1,15 +1,21 @@
+import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 
 class ViewerManager {
 
     private viewers: { [key: string]: AbstractViewer };
 
+    public onViewerAdded: (viewer: AbstractViewer) => void;
+    public onViewerAddedObservable: Observable<AbstractViewer>;
+
     constructor() {
         this.viewers = {};
+        this.onViewerAddedObservable = new Observable();
     }
 
     public addViewer(viewer: AbstractViewer) {
         this.viewers[viewer.getBaseId()] = viewer;
+        this._onViewerAdded(viewer);
     }
 
     public getViewerById(id: string): AbstractViewer {
@@ -23,6 +29,23 @@ class ViewerManager {
             }
         }
     }
+
+    public getViewerPromiseById(id: string): Promise<AbstractViewer> {
+        return new Promise((resolve, reject) => {
+            let viewerFunction = (viewer: AbstractViewer) => {
+                if (viewer.getBaseId() === id) {
+                    resolve(viewer);
+                    this.onViewerAddedObservable.removeCallback(viewerFunction);
+                }
+            }
+            this.onViewerAddedObservable.add(viewerFunction);
+        });
+    }
+
+    private _onViewerAdded(viewer: AbstractViewer) {
+        this.onViewerAdded && this.onViewerAdded(viewer);
+        this.onViewerAddedObservable.notifyObservers(viewer);
+    }
 }
 
 export let viewerManager = new ViewerManager();