qwc2
Version:
QGIS Web Client
423 lines (416 loc) • 18.5 kB
JavaScript
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import { Controls, MOUSE, Raycaster, Vector2, Vector3 } from 'three';
var _twoPI = 2 * Math.PI;
var STATE = {
NONE: -1,
ROTATE: 0,
PAN: 1,
TOUCH_ROTATE: 2,
TOUCH_PAN: 3
};
var FirstPersonControls3D = /*#__PURE__*/function (_Controls) {
function FirstPersonControls3D(object, mouseButtons) {
var _this;
_classCallCheck(this, FirstPersonControls3D);
_this = _callSuper(this, FirstPersonControls3D, [object, null]);
// Keyboard navigate
_defineProperty(_this, "_handleKeyboardNav", function () {
var lr = -_this._keyState.ArrowLeft + _this._keyState.ArrowRight;
var du = -_this._keyState.ArrowDown + _this._keyState.ArrowUp;
var pg = -_this._keyState.PageDown + _this._keyState.PageUp;
var pitch = _this._keyState.Shift ? du * _this.keyRotateStep : 0;
var yaw = _this._keyState.Control ? 0 : -lr * _this.keyRotateStep;
var dx = _this._keyState.Control ? lr * _this.keyPanStep * 0.75 : 0;
var dy = _this._keyState.Shift ? 0 : du * _this.keyPanStep;
_this._rotate(yaw, pitch);
_this._pan(dx, dy);
if (pg) {
var newPersonHeight = Math.max(2, _this.personHeight + _this.personHeight * pg * 0.05);
_this.target.z += newPersonHeight - _this.personHeight;
_this.personHeight = newPersonHeight;
_this._changed = true;
_this.update();
}
});
// Event listeners
_defineProperty(_this, "_onKeyDown", function (event) {
if (event.key in _this._keyState) {
_this._keyState[event.key] = true;
if (!_this._keyboardNavInterval) {
_this._keyboardNavInterval = setInterval(_this._handleKeyboardNav, 50);
}
}
});
_defineProperty(_this, "_onKeyUp", function (event) {
if (event.key in _this._keyState) {
_this._keyState[event.key] = false;
if (Object.values(_this._keyState).every(function (x) {
return !x;
})) {
clearInterval(_this._keyboardNavInterval);
_this._keyboardNavInterval = null;
}
}
});
_defineProperty(_this, "_onBlur", function () {
_this._keyState = {
ArrowLeft: false,
ArrowRight: false,
ArrowUp: false,
ArrowDown: false,
PageUp: false,
PageDown: false,
Control: false,
Shift: false
};
clearInterval(_this._keyboardNavInterval);
_this._keyboardNavInterval = null;
});
_defineProperty(_this, "_onPointerDown", function (event) {
if (!_this.enabled) {
return;
}
if (_this._pointers.length === 0) {
_this.domElement.setPointerCapture(event.pointerId);
_this.domElement.addEventListener('pointermove', _this._onPointerMove);
_this.domElement.addEventListener('pointerup', _this._onPointerUp);
_this.domElement.addEventListener('pointercancel', _this._onPointerUp);
} else if (_this._isTrackingPointer(event)) {
return;
}
_this._addPointer(event);
if (event.pointerType === 'touch') {
_this._onTouchStart(event);
} else {
_this._onMouseDown(event);
}
});
_defineProperty(_this, "_onPointerMove", function (event) {
if (event.pointerType === 'touch') {
_this._onTouchMove(event);
} else {
_this._onMouseMove(event);
}
});
_defineProperty(_this, "_onPointerUp", function (event) {
_this._removePointer(event);
if (_this._pointers.length === 0) {
_this.domElement.releasePointerCapture(event.pointerId);
_this.domElement.removeEventListener('pointermove', _this._onPointerMove);
_this.domElement.removeEventListener('pointerup', _this._onPointerUp);
_this.domElement.removeEventListener('pointercancel', _this._onPointerUp);
_this._interactionState = STATE.NONE;
} else if (_this._pointers.length === 1) {
var pointerId = _this._pointers[0];
var position = _this._pointerPositions[pointerId];
// minimal placeholder event - allows state correction on pointer-up
_this._onTouchStart({
pointerId: pointerId,
pageX: position.x,
pageY: position.y
});
}
});
_defineProperty(_this, "_onMouseDown", function (event) {
var buttonMap = {
0: 'LEFT',
1: 'MIDDLE',
2: 'RIGHT'
};
_this._interactionState = STATE.NONE;
if (_this.mouseButtons[buttonMap[event.button]] === MOUSE.ROTATE) {
_this._interactionState = STATE.ROTATE;
_this._interactionStart.set(event.clientX, event.clientY);
} else if (_this.mouseButtons[buttonMap[event.button]] === MOUSE.PAN) {
_this._interactionState = STATE.PAN;
_this._interactionStart.set(event.clientX, event.clientY);
}
});
_defineProperty(_this, "_onMouseMove", function (event) {
var deltaX = event.clientX - _this._interactionStart.x;
var deltaY = event.clientY - _this._interactionStart.y;
_this._interactionStart.set(event.clientX, event.clientY);
if (_this._interactionState === STATE.PAN) {
_this._pan(-deltaX * _this.mousePanSpeed, deltaY * _this.mousePanSpeed);
} else if (_this._interactionState === STATE.ROTATE) {
_this._rotate(_twoPI * deltaX * _this.mouseRotateSpeed / _this.domElement.clientHeight,
// yes, height
_twoPI * deltaY * _this.mouseRotateSpeed / _this.domElement.clientHeight);
}
});
_defineProperty(_this, "_onTouchStart", function (event) {
_this._interactionState = STATE.NONE;
if (_this._pointers.length === 1) {
_this._interactionState = STATE.TOUCH_PAN;
_this._interactionStart.set(event.pageX, event.pageY);
} else if (_this._pointers.length === 2) {
_this._interactionState = STATE.TOUCH_ROTATE;
var _this$_getTwoPointerP = _this._getTwoPointerPosition(event),
x = _this$_getTwoPointerP.x,
y = _this$_getTwoPointerP.y;
_this._interactionStart.set(x, y);
}
});
_defineProperty(_this, "_onTouchMove", function (event) {
_this._trackPointer(event);
if (_this._interactionState === STATE.TOUCH_PAN) {
var deltaX = event.pageX - _this._interactionStart.x;
var deltaY = event.pageY - _this._interactionStart.y;
_this._interactionStart.set(event.pageX, event.pageY);
_this._pan(-deltaX * _this.mousePanSpeed, deltaY * _this.mousePanSpeed);
} else if (_this._interactionState === STATE.TOUCH_ROTATE) {
var _this$_getTwoPointerP2 = _this._getTwoPointerPosition(event),
x = _this$_getTwoPointerP2.x,
y = _this$_getTwoPointerP2.y;
var _deltaX = x - _this._interactionStart.x;
var _deltaY = y - _this._interactionStart.y;
_this._interactionStart.set(x, y);
_this._rotate(_twoPI * _deltaX * _this.mouseRotateSpeed / _this.domElement.clientHeight,
// yes, height
_twoPI * _deltaY * _this.mouseRotateSpeed / _this.domElement.clientHeight);
}
});
_defineProperty(_this, "_onContextMenu", function (event) {
event.preventDefault();
});
_this.mouseButtons = mouseButtons;
// Step sizes
_this.keyPanStep = 1.5;
_this.keyRotateStep = 4 / 180 * Math.PI;
_this.mousePanSpeed = 0.1;
_this.mouseRotateSpeed = 10 / 180 * Math.PI;
_this.personHeight = 3;
_this.sceneContext = null;
_this.enabled = false;
_this.yaw = 0;
_this.pitch = 0;
_this.lookAt = new Vector3(0, 1, 0);
// Target is the actual collision detection point
_this.target = new Vector3().addVectors(_this.object.position, _this.lookAt.clone().multiplyScalar(3));
_this.isFirstPerson = true;
// Internals
_this._keyState = {
ArrowLeft: false,
ArrowRight: false,
ArrowUp: false,
ArrowDown: false,
PageUp: false,
PageDown: false,
Control: false,
Shift: false
};
_this._keyboardNavInterval = null;
_this._changed = false;
_this._interactionState = STATE.NONE;
_this._interactionStart = new Vector2();
_this._pointers = [];
_this._pointerPositions = {};
return _this;
}
_inherits(FirstPersonControls3D, _Controls);
return _createClass(FirstPersonControls3D, [{
key: "connect",
value: function connect(sceneContext) {
this.domElement = sceneContext.scene.domElement;
this.sceneContext = sceneContext;
this.domElement.addEventListener('pointerdown', this._onPointerDown);
this.domElement.addEventListener('pointercancel', this._onPointerUp);
this.domElement.addEventListener('contextmenu', this._onContextMenu);
this.domElement.addEventListener('keydown', this._onKeyDown);
this.domElement.addEventListener('keyup', this._onKeyUp);
this.domElement.addEventListener('blur', this._onBlur);
this.domElement.style.touchAction = 'none'; // disable touch scroll
this.object.near = 0.1;
this.sceneContext.scene.view.setControls(this);
this.enabled = true;
}
}, {
key: "disconnect",
value: function disconnect() {
this.enabled = false;
this.sceneContext.scene.view.setControls(null);
this.domElement.removeEventListener('pointerdown', this._onPointerDown);
this.domElement.removeEventListener('pointermove', this._onPointerMove);
this.domElement.removeEventListener('pointerup', this._onPointerUp);
this.domElement.removeEventListener('pointercancel', this._onPointerUp);
this.domElement.removeEventListener('contextmenu', this._onContextMenu);
this.domElement.removeEventListener('keydown', this._onKeyDown);
this.domElement.removeEventListener('keyup', this._onKeyUp);
this.domElement.removeEventListener('blur', this._onBlur);
this.domElement.style.touchAction = 'auto';
}
}, {
key: "setView",
value: function setView(targetpos, lookAt) {
var personHeight = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
this.personHeight = personHeight !== null && personHeight !== void 0 ? personHeight : this.personHeight;
this.target.copy(targetpos);
this.lookAt.copy(lookAt);
this.object.position.subVectors(targetpos, lookAt.clone().multiplyScalar(3));
this.pitch = Math.asin(Math.max(-1.0, Math.min(1.0, this.lookAt.z)));
this.yaw = Math.atan2(-this.lookAt.x, this.lookAt.y);
this.object.lookAt(this.target);
this.dispatchEvent({
type: 'change'
});
}
}, {
key: "panView",
value: function panView(dx, dy) {
if (dx || dy) {
this._pan(dx, dy);
}
}
}, {
key: "tiltView",
value: function tiltView(yaw, pitch) {
this.yaw += yaw;
this.pitch += pitch;
if (yaw || pitch) {
this._changed = true;
this.update();
}
}
}, {
key: "dispose",
value: function dispose() {
this.disconnect();
}
}, {
key: "update",
value: function update() {
var deltaTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
if (!this._changed) {
return;
}
this.lookAt.x = -Math.sin(this.yaw) * Math.cos(this.pitch);
this.lookAt.y = Math.cos(this.yaw) * Math.cos(this.pitch);
this.lookAt.z = Math.sin(this.pitch);
this.object.position.subVectors(this.target, this.lookAt.clone().multiplyScalar(3));
this.object.lookAt(this.target);
this.dispatchEvent({
type: 'change'
});
this._changed = false;
}
// Internals
}, {
key: "_rotate",
value: function _rotate(yaw, pitch) {
this.yaw += yaw;
this.pitch = Math.max(-0.5 * Math.PI, Math.min(this.pitch + pitch, 0.5 * Math.PI));
this._changed = true;
this.update();
}
// deltaX and deltaY are in pixels; right and down are positive
}, {
key: "_pan",
value: function _pan(deltaX, deltaY) {
var cosY = Math.cos(this.yaw);
var sinY = Math.sin(this.yaw);
var dx = cosY * deltaX + -sinY * deltaY;
var dy = sinY * deltaX + cosY * deltaY;
var dir = new Vector2(dx, dy);
var step = dir.length();
if (step < 0.001) {
return;
}
dir.divideScalar(step);
// Adjust step to avoid passing within any wall buffer zone
var raycaster = new Raycaster();
raycaster.set(this.target, new Vector3(dir.x, dir.y, 0));
var inter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0];
var wallBuffer = 0.5;
if (inter && inter.distance - wallBuffer < step) {
var overstep = step - (inter.distance - wallBuffer);
step -= overstep;
this.target.x += step * dir.x;
this.target.y += step * dir.y;
// Project overstep onto wall
var tangent = new Vector2(-inter.normal.y, inter.normal.x).normalize();
var slidestep = tangent.dot(dir) * overstep;
if (slidestep < 0) {
tangent.negate();
slidestep *= -1;
}
raycaster.set(this.target, new Vector3(tangent.x, tangent.y, 0));
var slideInter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0];
if (slideInter && slideInter.distance - wallBuffer < slidestep) {
slidestep = slideInter.distance - wallBuffer;
}
this.target.x += slidestep * tangent.x;
this.target.y += slidestep * tangent.y;
} else {
this.target.x += step * dir.x;
this.target.y += step * dir.y;
}
// Stay above terrain // objects on terain
var height = undefined;
raycaster.set(this.target, new Vector3(0, 0, -1));
var vinter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0];
if (vinter) {
height = vinter.point.z;
} else {
height = this.sceneContext.getTerrainHeightFromMap([this.target.x, this.target.y]);
}
if (height !== undefined) {
var newHeight = height + this.personHeight;
this.target.z = 0.75 * this.target.z + 0.25 * newHeight;
}
this._changed = true;
this.update();
}
}, {
key: "_addPointer",
value:
// Touch pointer tracking
function _addPointer(event) {
this._pointers.push(event.pointerId);
this._pointerPositions[event.pointerId] = new Vector2(event.pageX, event.pageY);
}
}, {
key: "_removePointer",
value: function _removePointer(event) {
delete this._pointerPositions[event.pointerId];
this._pointers = this._pointers.filter(function (id) {
return id !== event.pointerId;
});
}
}, {
key: "_isTrackingPointer",
value: function _isTrackingPointer(event) {
return this._pointers.find(function (id) {
return id === event.pointerId;
}) !== undefined;
}
}, {
key: "_trackPointer",
value: function _trackPointer(event) {
this._pointerPositions[event.pointerId].set(event.pageX, event.pageY);
}
}, {
key: "_getTwoPointerPosition",
value: function _getTwoPointerPosition(event) {
var otherPointerId = event.pointerId === this._pointers[0] ? this._pointers[1] : this._pointers[0];
var otherPointerPos = this._pointerPositions[otherPointerId];
return {
x: 0.5 * (event.pageX + otherPointerPos.x),
y: 0.5 * (event.pageY + otherPointerPos.y)
};
}
}]);
}(Controls);
export { FirstPersonControls3D as default };