vizicities/src/layer/Layer.js

219 wiersze
4.9 KiB
JavaScript
Executable File

import EventEmitter from 'eventemitter3';
import extend from 'lodash.assign';
import shortid from 'shortid';
import THREE from 'three';
import Scene from '../engine/Scene';
import {CSS3DObject} from '../vendor/CSS3DRenderer';
import {CSS2DObject} from '../vendor/CSS2DRenderer';
// TODO: Make sure nothing is left behind in the heap after calling destroy()
// TODO: Need a single move method that handles moving all the various object
// layers so that the DOM layers stay in sync with the 3D layer
// TODO: Double check that objects within the _object3D Object3D parent are frustum
// culled even if the layer position stays at the default (0,0,0) and the child
// objects are positioned much further away
//
// Or does the layer being at (0,0,0) prevent the child objects from being
// culled because the layer parent is effectively always in view even if the
// child is actually out of camera
class Layer extends EventEmitter {
constructor(options) {
super();
var defaults = {
id: shortid.generate(),
output: true,
outputToScene: true
};
this._options = extend({}, defaults, options);
if (this.isOutput()) {
this._object3D = new THREE.Object3D();
this._dom3D = document.createElement('div');
this._domObject3D = new CSS3DObject(this._dom3D);
this._dom2D = document.createElement('div');
this._domObject2D = new CSS2DObject(this._dom2D);
}
}
// Add THREE object directly to layer
add(object) {
this._object3D.add(object);
}
// Remove THREE object from to layer
remove(object) {
this._object3D.remove(object);
}
addDOM3D(object) {
this._domObject3D.add(object);
}
removeDOM3D(object) {
this._domObject3D.remove(object);
}
addDOM2D(object) {
this._domObject2D.add(object);
}
removeDOM2D(object) {
this._domObject2D.remove(object);
}
// Add layer to world instance and store world reference
addTo(world) {
return world.addLayer(this);
}
// Internal method called by World.addLayer to actually add the layer
_addToWorld(world) {
this._world = world;
return new Promise((resolve, reject) => {
this._onAdd(world).then(() => {
this.emit('added');
resolve(this);
}).catch(reject);
});
}
// Must return a promise
_onAdd(world) {
return Promise.resolve(this);
}
getPickingId() {
if (this._world._engine._picking) {
return this._world._engine._picking.getNextId();
}
return false;
}
// TODO: Tidy this up and don't access so many private properties to work
addToPicking(object) {
if (!this._world._engine._picking) {
return;
}
this._world._engine._picking.add(object);
}
removeFromPicking(object) {
if (!this._world._engine._picking) {
return;
}
this._world._engine._picking.remove(object);
}
isOutput() {
return this._options.output;
}
isOutputToScene() {
return this._options.outputToScene;
}
// TODO: Also hide any attached DOM layers
hide() {
this._object3D.visible = false;
if (this._pickingMesh) {
this._pickingMesh.visible = false;
}
}
// TODO: Also show any attached DOM layers
show() {
this._object3D.visible = true;
if (this._pickingMesh) {
this._pickingMesh.visible = true;
}
}
// Destroys the layer and removes it from the scene and memory
destroy() {
if (this._object3D && this._object3D.children) {
// Remove everything else in the layer
var child;
for (var i = this._object3D.children.length - 1; i >= 0; i--) {
child = this._object3D.children[i];
if (!child) {
continue;
}
this.remove(child);
if (child.geometry) {
// Dispose of mesh and materials
child.geometry.dispose();
child.geometry = null;
}
if (child.material) {
if (child.material.map) {
child.material.map.dispose();
child.material.map = null;
}
child.material.dispose();
child.material = null;
}
}
}
if (this._domObject3D && this._domObject3D.children) {
// Remove everything else in the layer
var child;
for (var i = this._domObject3D.children.length - 1; i >= 0; i--) {
child = this._domObject3D.children[i];
if (!child) {
continue;
}
this.removeDOM3D(child);
}
}
if (this._domObject2D && this._domObject2D.children) {
// Remove everything else in the layer
var child;
for (var i = this._domObject2D.children.length - 1; i >= 0; i--) {
child = this._domObject2D.children[i];
if (!child) {
continue;
}
this.removeDOM2D(child);
}
}
this._domObject3D = null;
this._domObject2D = null;
this._world = null;
this._object3D = null;
}
}
export default Layer;
var noNew = function(options) {
return new Layer(options);
};
export {noNew as layer};