modern/js/controls.js
2021-01-17 17:17:19 +01:00

474 lines
13 KiB
JavaScript
Executable File

import {
Vector3,
Raycaster,
Object3D,
Mesh,
BackSide,
MeshBasicMaterial,
ShaderMaterial,
AdditiveBlending,
JSONLoader,
AxesHelper,
BoxGeometry
} from "./three_modules";
const overlayInfo = (function () {
"use strict";
let d = document.getElementById("overlay-info");
return {
animIn: function (heading, text) {
d.innerHTML = "<h3>" + heading.charAt(0).toUpperCase() + heading.slice(1) + "</h3><h5>" + text + "</h5>";
d.classList.add("overlayIN");
},
animOut: function () {
d.classList.remove("overlayIN");
}
}
})();
const helpers = {
//Clamp a number to two decimals
twoDecimals: function (value) {
"use strict";
return Math.round((value * 100)) / 100;
},
//Linear Interpolate between two numbers
lerp: function (a, b, f) {
"use strict";
return a + f * (b - a);
},
//Clamp a number to the min and max
clip: function (number, min, max) {
"use strict";
return Math.max(min, Math.min(number, max));
},
//Easing Type
easeInOutCubic: function (t) {
"use strict";
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
};
function initMobileEventListeners(scope) {
import("./controls/initMobileEventListeners").then(mod => {
mod.default(scope);
});
}
function initDesktopEventListeners(scope) {
import("./controls/initDesktopEventListeners").then(mod => {
mod.default(scope);
});
}
var w = window.innerWidth;
var h = window.innerHeight;
window.addEventListener("resize", function () {
"use strict";
w = window.innerWidth;
h = window.innerHeight;
});
class archVizControls {
constructor(scene, camera, renderer) {
"use strict";
this.scene = scene;
this.camera = camera;
this.domElement = (renderer.domElement !== undefined) ? renderer.domElement : document;
this.debug = false;
this.saveCamTransform = true;
//General Stuff
this.type = "fp",
this.lookSpeed = 0.5,
this.camera,
this.target,
this.dddcursor = new Mesh(new BoxGeometry(2, 2, 2), new MeshBasicMaterial());
//Limiting Angles
this.maxAzimuthAngle = -1337,
this.minAzimuthAngle = 1337,
this.maxPolarAngle = -1,
this.minPolarAngle = 1;
//Auto Rotation Stuff
this.autoRotate = (localStorage.autoRotate === "true") || true,
this.autoRotateMaxSpeed = 0.001,
//Drag Stuff
this.drag = (localStorage.drag === "true") || true,
this.dragStrength = 0.05,
this.dragMultiplier = 2,
this.dragVector = {
x: 0,
y: 0
};
//Mouse events
this.mVector = {
x: 0,
y: 0
},
this.mouseMove = {
x: 0,
y: 0
},
this.m1 = {
x: 0,
y: 0
};
this.nm = [0, 0];
this.mouseArray = [...new Array(10)].fill([0, 0]);
//MOBILE STUFF
this.mobile = false;
this.deviceorientation = (localStorage.deviceorientation === "true") || false;
this.deviceorientationSpeed = 0.03;
this.alpha = 0;
this.beta = 0;
this.gamma = 0;
//Raycaster stuff
this.activeObject = {
name: "",
uuid: "",
text: ""
},
this.outlineObject = new Object3D();
this.outlineObject.name = "outlineObject";
this.outlineMaterial = new ShaderMaterial({
uniforms: {},
vertexShader: `
void main()
{
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 displacement = vec4( normalize( normalMatrix * normal ) * 0.02, 0.0 ) + mvPosition;
gl_Position = projectionMatrix * displacement;
}`,
fragmentShader: `
void main()
{
gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );
}`,
blending: AdditiveBlending,
side: BackSide
});
this.anim = (function () {
let anim, time = 0,
percent;
return function (from, to, type) {
let finished = function () {
this.type = type;
time = 0;
}.bind(this);
if (this.type !== "anim") {
this.type = "anim";
anim = function () {
time++;
if (time <= 70) {
window.requestAnimationFrame(anim);
percent = helpers.easeInOutCubic(time / 70);
this.target.position.x = helpers.lerp(from[0], to[0], percent);
this.target.position.y = helpers.lerp(from[1], to[1], percent);
this.target.position.z = helpers.lerp(from[2], to[2], percent);
this.camera.position.x = helpers.lerp(from[3], to[3], percent);
this.camera.position.y = helpers.lerp(from[4], to[4], percent);
this.camera.position.z = helpers.lerp(from[5], to[5], percent);
this.target.rotation.y = helpers.lerp(from[6], to[6], percent);
} else {
this.minPolarAngle = to[7];
this.maxPolarAngle = to[8];
this.minAzimuthAngle = to[9];
this.maxAzimuthAngle = to[10];
finished();
}
}.bind(this)
anim();
};
}
}.bind(this))();
this.update = (function () {
let applyDeviceOrientation = function () {
this.mVector.x += this.alpha * this.deviceorientationSpeed * 0.1;
this.mVector.y += this.beta * this.deviceorientationSpeed * 0.1;
}.bind(this);
let mouseOver = (function () {
let obj, INTERSECTED, raycaster = new Raycaster();
raycaster.far = 50;
return function () {
//GET THE OBJECT UNDER THE CURSOR
raycaster.setFromCamera(this.m1, this.camera);
this.intersects = raycaster.intersectObjects(scene.children)[0];
if (this.intersects !== undefined) {
//ALIAS IT FOR FASTER REFERENCING
obj = this.intersects.object;
//IF THE OBJECT UNDER THE CURSOR IS THE FLOOR -- Most likely
if (obj.name === "floor" || obj.name === "dddcursor") {
this.outlineObject.visible = false;
this.dddcursor.visible = true;
this.dddcursor.position.set(this.intersects.point.x, this.intersects.point.y, this.intersects.point.z);
//IF THE OBJECT UNDER THE CURSOR WAS ALREADY HIGHLIGHTED
} else if (INTERSECTED === obj.uuid) {
this.dddcursor.visible = false;
} else if (obj.userData.clickable === true && this.activeObject.uuid !== obj.uuid) {
INTERSECTED = obj.uuid;
document.body.style.cursor = "pointer";
scene.remove(this.outlineObject);
this.outlineObject = obj.clone();
this.outlineObject.material = this.outlineMaterial;
scene.add(this.outlineObject);
} else {
this.outlineObject.visible = false;
this.dddcursor.visible = false;
document.body.style.cursor = "default";
INTERSECTED = null;
}
}
}.bind(this);
}).bind(this)();
let mouseMove = function () {
if (this.anim !== true) {
this.mouseArray.push([this.nm[0], this.nm[1]]);
this.mouseArray.splice(0, 1);
this.m1.x = this.nm[0];
this.m1.y = this.nm[1];
if (this.pressed === true) {
this.mVector.y += (this.mouseArray[0][0] - this.nm[0]) * -0.75 * this.lookSpeed;
this.mVector.x += (this.mouseArray[0][1] - this.nm[1]) * 0.6 * this.lookSpeed;
} else {
this.mVector.x = 0;
this.mVector.y = 0;
}
}
}.bind(this);
let drag = function () {
if (this.pressed === false && this.dragMultiplier > 0 && this.drag === true) {
this.dragMultiplier -= 0.035;
if (this.type === "fp") {
this.mVector.y += this.dragVector.y * helpers.easeInOutCubic(this.dragMultiplier);
this.mVector.x += this.dragVector.x * helpers.easeInOutCubic(this.dragMultiplier);
} else if (this.type === "orbit") {
this.mVector.y -= this.dragVector.y * helpers.easeInOutCubic(this.dragMultiplier);
this.mVector.x -= this.dragVector.x * helpers.easeInOutCubic(this.dragMultiplier);
}
} else {
this.dragMultiplier = 0;
}
}.bind(this);
let autoRotate = (function () {
let autoRotateTimer;
return function () {
if (autoRotateTimer <= 10) {
//Last Stage
this.target.rotation.y = helpers.clip((this.target.rotation.y - this.autoRotateMaxSpeed), this.minAzimuthAngle, this.maxAzimuthAngle);
//MAKE IT BOUNCE!
//INVERT THE ROTATION IF IT REACHES MIN OR MAX ROTATION
if (this.target.rotation.y === this.minAzimuthAngle) {
this.autoRotateMaxSpeed = -this.autoRotateMaxSpeed;
}
if (this.target.rotation.y === this.maxAzimuthAngle) {
this.autoRotateMaxSpeed = -this.autoRotateMaxSpeed;
}
} else if (autoRotateTimer <= 70) {
autoRotateTimer -= 1;
this.target.rotation.y = helpers.clip((this.target.rotation.y - this.autoRotateMaxSpeed * (10 / autoRotateTimer)), this.minAzimuthAngle, this.maxAzimuthAngle);
} else {
autoRotateTimer -= 1;
}
}.bind(this)
}).bind(this)();
return function () {
if (this.type !== "anim") {
applyDeviceOrientation();
mouseOver();
mouseMove();
drag();
autoRotate();
}
this.rotate();
};
}).bind(this)();
this.initialize();
}
rotate() {
this.target.rotation.y = helpers.clip(this.target.rotation.y + this.mVector.y, this.maxAzimuthAngle, this.minAzimuthAngle)
this.target.rotation.x = helpers.clip(this.target.rotation.x + this.mVector.x, this.maxPolarAngle, this.minPolarAngle);
this.mVector.x = 0;
this.mVector.y = 0;
};
}
archVizControls.prototype.setOrbit = function (target) {
if (this.type === "fp") {
this.savePosition = this.target.position.clone();
}
this.outlineObject.visible = false;
this.activeObject.uuid = this.intersects.object.uuid;
this.activeObject.name = this.intersects.object.name;
this.activeObject.text = this.intersects.object.userData.text;
overlayInfo.animIn(this.activeObject.name, this.activeObject.text);
this.dragMultiplier = 0;
if (this.lookSpeed > 0) {
this.lookSpeed = -this.lookSpeed;
}
if (this.type !== "anim") {
this.target.rotation.y = this.target.rotation.y % (Math.PI * 2);
if (this.target.rotation.y > 0 && ((target.userData.camAngle[2] + target.userData.camAngle[3]) / 2) < 0) {
this.target.rotation.y -= Math.PI * 2;
}
if (this.target.rotation.y < 0 && ((target.userData.camAngle[2] + target.userData.camAngle[3]) / 2) > 0) {
this.target.rotation.y += Math.PI * 2;
}
this.anim(
[
this.target.position.x, this.target.position.y, this.target.position.z,
this.camera.position.x, this.camera.position.y, this.camera.position.z,
this.target.rotation.y
], [
target.position.x, target.position.y + target.userData.fpos[1], target.position.z,
0, 0, target.userData.fpos[0],
(target.userData.camAngle[2] + target.userData.camAngle[3]) / 2,
target.userData.camAngle[1], target.userData.camAngle[0], target.userData.camAngle[3], target.userData.camAngle[2]
],
"orbit"
);
}
};
archVizControls.prototype.setFP = function (target) {
overlayInfo.animOut();
if (this.lookSpeed < 0) {
this.lookSpeed = -this.lookSpeed;
}
this.dragMultiplier = 0;
this.anim(
[
this.target.position.x, this.target.position.y, this.target.position.z,
this.camera.position.x, this.camera.position.y, this.camera.position.z,
this.target.rotation.y
], [
target.point.x, target.point.y + 1.6, target.point.z,
0, 0, 0,
this.target.rotation.y, 0.5, -0.5, 1337, -1337
],
"fp"
);
};
archVizControls.prototype.reset = function () {
let empty = new Object3D();
empty.point = new Vector3(0, 0, 0);
this.setFP(empty);
};
archVizControls.prototype.initialize = function () {
this.camera.position.z = 0.2;
this.target = new AxesHelper();
this.target.name = "ControlsTarget";
this.target.position.set(0, 1.3, 0);
this.target.rotation.order = "YXZ";
if (this.saveCamTransform) {
if (localStorage.camTransform) {
let _trans = localStorage.camTransform.split(",");
this.target.position.x = parseFloat(_trans[0]);
this.target.position.y = parseFloat(_trans[1]);
this.target.position.z = parseFloat(_trans[2]);
this.target.rotation.x = parseFloat(_trans[3]);
this.target.rotation.y = parseFloat(_trans[4]);
this.target.rotation.z = 0;
}
}
this.target.add(this.camera);
this.scene.add(this.target);
this.target.visible = false;
this.scene.add(this.outlineObject);
//ADD EVENTLISTENERS ACCORDING TO PLATTFORM
if (window.isMobile) {
initMobileEventListeners(this);
} else {
initDesktopEventListeners(this);
}
//LOAD THE CURSOR MODEL
new JSONLoader().load("./data/cursor.json", function (geometry) {
this.dddcursor = new Mesh(geometry, new MeshBasicMaterial());
this.scene.add(this.dddcursor);
}.bind(this));
};
export default archVizControls;