|
@@ -0,0 +1,167 @@
|
|
|
+(function () {
|
|
|
+ class CSS2DObject extends THREE.Object3D {
|
|
|
+ constructor(element = document.createElement("div")) {
|
|
|
+ super();
|
|
|
+
|
|
|
+ this.isCSS2DObject = true;
|
|
|
+
|
|
|
+ this.element = element;
|
|
|
+
|
|
|
+ this.element.style.position = "absolute";
|
|
|
+ this.element.style.userSelect = "none";
|
|
|
+
|
|
|
+ this.element.setAttribute("draggable", false);
|
|
|
+
|
|
|
+ this.addEventListener("removed", function () {
|
|
|
+ this.traverse(function (object) {
|
|
|
+ if (object.element instanceof Element && object.element.parentNode !== null) {
|
|
|
+ object.element.parentNode.removeChild(object.element);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ copy(source, recursive) {
|
|
|
+ super.copy(source, recursive);
|
|
|
+
|
|
|
+ this.element = source.element.cloneNode(true);
|
|
|
+
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
+ const _vector = new THREE.Vector3();
|
|
|
+ const _viewMatrix = new THREE.Matrix4();
|
|
|
+ const _viewProjectionMatrix = new THREE.Matrix4();
|
|
|
+ const _a = new THREE.Vector3();
|
|
|
+ const _b = new THREE.Vector3();
|
|
|
+
|
|
|
+ class CSS2DRenderer {
|
|
|
+ constructor(parameters = {}) {
|
|
|
+ const _this = this;
|
|
|
+
|
|
|
+ let _width, _height;
|
|
|
+ let _widthHalf, _heightHalf;
|
|
|
+
|
|
|
+ const cache = {
|
|
|
+ objects: new WeakMap(),
|
|
|
+ };
|
|
|
+
|
|
|
+ const domElement = parameters.element !== undefined ? parameters.element : document.createElement("div");
|
|
|
+
|
|
|
+ domElement.style.overflow = "hidden";
|
|
|
+
|
|
|
+ this.domElement = domElement;
|
|
|
+
|
|
|
+ this.getSize = function () {
|
|
|
+ return {
|
|
|
+ width: _width,
|
|
|
+ height: _height,
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ this.render = function (scene, camera) {
|
|
|
+ if (scene.autoUpdate === true) scene.updateMatrixWorld();
|
|
|
+ if (camera.parent === null) camera.updateMatrixWorld();
|
|
|
+
|
|
|
+ _viewMatrix.copy(camera.matrixWorldInverse);
|
|
|
+ _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix);
|
|
|
+
|
|
|
+ renderObject(scene, scene, camera);
|
|
|
+ zOrder(scene);
|
|
|
+ };
|
|
|
+
|
|
|
+ this.setSize = function (width, height) {
|
|
|
+ _width = width;
|
|
|
+ _height = height;
|
|
|
+
|
|
|
+ _widthHalf = _width / 2;
|
|
|
+ _heightHalf = _height / 2;
|
|
|
+
|
|
|
+ domElement.style.width = width + "px";
|
|
|
+ domElement.style.height = height + "px";
|
|
|
+ };
|
|
|
+
|
|
|
+ function renderObject(object, scene, camera) {
|
|
|
+ if (object.isCSS2DObject) {
|
|
|
+ _vector.setFromMatrixPosition(object.matrixWorld);
|
|
|
+ _vector.applyMatrix4(_viewProjectionMatrix);
|
|
|
+
|
|
|
+ const visible =
|
|
|
+ object.visible === true && _vector.z >= -1 && _vector.z <= 1 && object.layers.test(camera.layers) === true;
|
|
|
+ object.element.style.display = visible === true ? "" : "none";
|
|
|
+
|
|
|
+ if (visible === true) {
|
|
|
+ object.onBeforeRender(_this, scene, camera);
|
|
|
+
|
|
|
+ const element = object.element;
|
|
|
+
|
|
|
+ element.style.transform =
|
|
|
+ "translate(-50%,-50%) translate(" +
|
|
|
+ (_vector.x * _widthHalf + _widthHalf) +
|
|
|
+ "px," +
|
|
|
+ (-_vector.y * _heightHalf + _heightHalf) +
|
|
|
+ "px)";
|
|
|
+
|
|
|
+ if (element.parentNode !== domElement) {
|
|
|
+ domElement.appendChild(element);
|
|
|
+ }
|
|
|
+
|
|
|
+ object.onAfterRender(_this, scene, camera);
|
|
|
+ }
|
|
|
+
|
|
|
+ const objectData = {
|
|
|
+ distanceToCameraSquared: getDistanceToSquared(camera, object),
|
|
|
+ };
|
|
|
+
|
|
|
+ cache.objects.set(object, objectData);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let i = 0, l = object.children.length; i < l; i++) {
|
|
|
+ renderObject(object.children[i], scene, camera);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function getDistanceToSquared(object1, object2) {
|
|
|
+ _a.setFromMatrixPosition(object1.matrixWorld);
|
|
|
+ _b.setFromMatrixPosition(object2.matrixWorld);
|
|
|
+
|
|
|
+ return _a.distanceToSquared(_b);
|
|
|
+ }
|
|
|
+
|
|
|
+ function filterAndFlatten(scene) {
|
|
|
+ const result = [];
|
|
|
+
|
|
|
+ scene.traverse(function (object) {
|
|
|
+ if (object.isCSS2DObject) result.push(object);
|
|
|
+ });
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ function zOrder(scene) {
|
|
|
+ const sorted = filterAndFlatten(scene).sort(function (a, b) {
|
|
|
+ if (a.renderOrder !== b.renderOrder) {
|
|
|
+ return b.renderOrder - a.renderOrder;
|
|
|
+ }
|
|
|
+
|
|
|
+ const distanceA = cache.objects.get(a).distanceToCameraSquared;
|
|
|
+ const distanceB = cache.objects.get(b).distanceToCameraSquared;
|
|
|
+
|
|
|
+ return distanceA - distanceB;
|
|
|
+ });
|
|
|
+
|
|
|
+ const zMax = sorted.length;
|
|
|
+
|
|
|
+ for (let i = 0, l = sorted.length; i < l; i++) {
|
|
|
+ sorted[i].element.style.zIndex = zMax - i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ THREE.CSS2DRenderer = CSS2DRenderer;
|
|
|
+ THREE.CSS2DObject = CSS2DObject;
|
|
|
+})();
|