UNPKG

qwc2

Version:
395 lines (393 loc) 20.1 kB
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 _construct(t, e, r) { if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments); var o = [null]; o.push.apply(o, e); var p = new (t.bind.apply(t, o))(); return r && _setPrototypeOf(p, r.prototype), p; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } 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); } /** * Copyright 2024 Sourcepole AG * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ import React from 'react'; import ReactDOM from 'react-dom'; import { connect } from 'react-redux'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import { MOUSE, Vector3 } from 'three'; import ConfigUtils from '../../utils/ConfigUtils'; import { UrlParams } from '../../utils/PermaLinkUtils'; import Icon from '../Icon'; import { MapButtonPortalContext } from '../PluginsContainer'; import FirstPersonControls3D from './utils/FirstPersonControls3D'; import OrbitControls3D from './utils/OrbitControls3D'; import './style/MapControls3D.css'; // FIXME: camera.fov is 30, but in reality seems to be 50 (as would be the threejs default) var CAMERA_FOV = 50; var MapControls3D = /*#__PURE__*/function (_React$Component) { function MapControls3D(props) { var _buttonMap$_this$prop, _buttonMap$_this$prop2, _buttonMap$_this$prop3; var _this; _classCallCheck(this, MapControls3D); _this = _callSuper(this, MapControls3D, [props]); _defineProperty(_this, "state", { pickingFirstPerson: false, firstPerson: false }); _defineProperty(_this, "unload", function (el) { // componentWillUnmount is called too early, so do cleanup when the element is actually removed if (!el) { _this.controls.removeEventListener('change', _this.updateControlsTarget); _this.fpcontrols.removeEventListener('change', _this.updateFpUrlParams); if (_this.state.firstPerson) { _this.fpcontrols.disconnect(); } else { _this.controls.disconnect(); } _this.props.sceneContext.scene.domElement.removeEventListener('dblclick', _this.switchToFirstPersonView); } }); _defineProperty(_this, "switchToFirstPersonView", function (ev) { // Don't do anything if a task is set, may interfere if (!_this.props.currentTask && !_this.state.firstPerson) { _this.setupFirstPerson(ev); } }); _defineProperty(_this, "toggleFirstPersonControls", function () { if (_this.state.firstPerson) { _this.leaveFirstPerson(); } else if (_this.state.pickingFirstPerson) { _this.props.sceneContext.scene.domElement.removeEventListener('click', _this.setupFirstPerson); _this.props.sceneContext.scene.domElement.style.cursor = ''; _this.setState({ pickingFirstPerson: false }); } else { _this.props.sceneContext.scene.domElement.addEventListener('click', _this.setupFirstPerson, { once: true }); var cursor = ConfigUtils.getAssetsPath() + "/img/person.svg"; _this.props.sceneContext.scene.domElement.style.cursor = "url(".concat(cursor, "), pointer"); _this.setState({ pickingFirstPerson: true }); } }); _defineProperty(_this, "setupFirstPerson", function (ev) { _this.props.sceneContext.scene.domElement.style.cursor = ''; var rect = ev.target.getBoundingClientRect(); var mouseX = (ev.clientX - rect.left) / rect.width * 2 - 1; var mouseY = -((ev.clientY - rect.top) / rect.height) * 2 + 1; var intersection = _this.props.sceneContext.getSceneIntersection(mouseX, mouseY, false); if (!intersection) { return; } var pos = intersection.point; _this.props.sceneContext.getTerrainHeightFromDTM([pos.x, pos.y]).then(function (z) { var camerapos = new Vector3(pos.x, pos.y, z + _this.fpcontrols.personHeight); var targetpos = new Vector3(pos.x, pos.y + 300, z + _this.fpcontrols.personHeight); _this.controls.animateTo(camerapos, targetpos, 0, function () { _this.controls.disconnect(); _this.fpcontrols.connect(_this.props.sceneContext); _this.fpcontrols.setView(camerapos, new Vector3(0, 1, 0)); _this.setState({ firstPerson: true, pickingFirstPerson: false }); }); }); }); _defineProperty(_this, "leaveFirstPerson", function () { if (_this.state.firstPerson) { _this.setState({ firstPerson: false }, function () { // Need to ensure this.state.firstPerson is false to avoid endless loop var camerapos = _this.props.sceneContext.scene.view.camera.position; _this.fpcontrols.disconnect(); _this.controls.connect(_this.props.sceneContext); _this.controls.setView(camerapos, new Vector3().addVectors(camerapos, _this.fpcontrols.lookAt)); var bounds = [camerapos.x - 750, camerapos.y - 750, camerapos.x + 750, camerapos.y + 750]; _this.setViewToExtent(bounds); }); } }); _defineProperty(_this, "home", function () { var extent = _this.props.sceneContext.map.extent; var bounds = [extent.west, extent.south, extent.east, extent.north]; _this.setViewToExtent(bounds); }); _defineProperty(_this, "setViewToExtent", function (bounds) { var angle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; _this.leaveFirstPerson(); var fov = CAMERA_FOV / 180 * Math.PI; var cameraHeight = (bounds[2] - bounds[0]) / (2 * Math.tan(fov / 2)); var center = { x: 0.5 * (bounds[0] + bounds[2]), y: 0.5 * (bounds[1] + bounds[3]) }; var camerapos = new Vector3(center.x, center.y, cameraHeight); var target = new Vector3(center.x, center.y, 0); var h = _this.props.sceneContext.getTerrainHeightFromMap([center.x, center.y]); // Fall back to getTerrainHeightFromDTM if map is not yet loaded if (h === undefined) { _this.props.sceneContext.getTerrainHeightFromDTM([center.x, center.y]).then(function (h2) { camerapos.z += h2; target.z += h2; _this.controls.animateTo(camerapos, target, angle); }); } else { camerapos.z += h; target.z += h; _this.controls.animateTo(camerapos, target, angle); } }); _defineProperty(_this, "pan", function (ev, dx, dy) { var panInterval = setInterval(function () { _this.props.sceneContext.scene.view.controls.panView(dx, dy); }, 50); ev.view.addEventListener('pointerup', function () { clearInterval(panInterval); }, { once: true }); }); _defineProperty(_this, "tilt", function (ev, azimuth, polar) { var tiltInterval = setInterval(function () { _this.props.sceneContext.scene.view.controls.tiltView(azimuth, polar); }, 50); ev.view.addEventListener('pointerup', function () { clearInterval(tiltInterval); }, { once: true }); }); _defineProperty(_this, "resetTilt", function () { var camerapos = _this.props.sceneContext.scene.view.camera.position; if (_this.state.firstPerson) { var newLookAt = _this.fpcontrols.lookAt.clone(); newLookAt.z = 0; _this.fpcontrols.setView(camerapos, newLookAt.normalize()); } else { var target = _this.controls.target; var newcamerapos = new Vector3(target.x, target.y, target.distanceTo(camerapos)); _this.controls.animateTo(newcamerapos, target, 0); } }); _defineProperty(_this, "zoom", function (ev, delta) { var zoomInterval = setInterval(function () { var camerapos = _this.props.sceneContext.scene.view.camera.position; var target = _this.controls.target; var k = Math.min(150, Math.sqrt(target.distanceTo(camerapos))); _this.props.sceneContext.scene.view.controls.zoomView(delta * k); }, 50); ev.view.addEventListener('pointerup', function () { clearInterval(zoomInterval); }, { once: true }); }); _defineProperty(_this, "updateUrlParams", function () { var cpos = _this.props.sceneContext.scene.view.camera.position; var tpos = _this.controls.target; UrlParams.updateParams({ v3d: [cpos.x, cpos.y, cpos.z, tpos.x, tpos.y, tpos.z, 0].map(function (v) { return v.toFixed(1); }).join(",") }); _this.props.onCameraChanged([tpos.x, tpos.y, tpos.z], [cpos.x, cpos.y, cpos.z], CAMERA_FOV); }); _defineProperty(_this, "updateFpUrlParams", function () { var cpos = _this.fpcontrols.target; var lkat = _this.fpcontrols.lookAt; var h = _this.fpcontrols.personHeight; UrlParams.updateParams({ v3d: [cpos.x, cpos.y, cpos.z, lkat.x, lkat.y, lkat.z, h].map(function (v) { return v.toFixed(1); }).join(",") }); _this.props.onCameraChanged([cpos.x, cpos.y, cpos.z], null); }); _defineProperty(_this, "restoreView", function (viewState) { if (viewState.camera && viewState.target) { var camera = _construct(Vector3, _toConsumableArray(viewState.camera)); var target = _construct(Vector3, _toConsumableArray(viewState.target)); if (viewState.personHeight > 0) { _this.controls.disconnect(); _this.fpcontrols.connect(_this.props.sceneContext); _this.fpcontrols.setView(camera, target, viewState.personHeight); _this.setState({ firstPerson: true }); } else { _this.controls.setView(camera, target); } } }); var sceneElement = props.sceneContext.scene.domElement; sceneElement.tabIndex = 0; var buttonMap = { pan: MOUSE.PAN, rotate: MOUSE.ROTATE, zoom: MOUSE.DOLLY }; var mouseButtons = { LEFT: (_buttonMap$_this$prop = buttonMap[_this.props.mouseButtons.left]) !== null && _buttonMap$_this$prop !== void 0 ? _buttonMap$_this$prop : null, MIDDLE: (_buttonMap$_this$prop2 = buttonMap[_this.props.mouseButtons.middle]) !== null && _buttonMap$_this$prop2 !== void 0 ? _buttonMap$_this$prop2 : null, RIGHT: (_buttonMap$_this$prop3 = buttonMap[_this.props.mouseButtons.right]) !== null && _buttonMap$_this$prop3 !== void 0 ? _buttonMap$_this$prop3 : null }; _this.controls = new OrbitControls3D(props.sceneContext.scene.view.camera, mouseButtons); _this.fpcontrols = new FirstPersonControls3D(props.sceneContext.scene.view.camera, mouseButtons); _this.controls.connect(props.sceneContext); var targetPos = props.sceneContext.scene.view.camera.position.clone(); targetPos.z = 0; _this.controls.target = targetPos; _this.controls.addEventListener('change', _this.updateUrlParams); _this.fpcontrols.addEventListener('change', _this.updateFpUrlParams); sceneElement.addEventListener('dblclick', _this.switchToFirstPersonView); props.onControlsSet(_this); _this.updateUrlParams(); return _this; } _inherits(MapControls3D, _React$Component); return _createClass(MapControls3D, [{ key: "render", value: function render() { var _this2 = this; var firstPersonButtonClasses = classNames({ "map3d-firstperson-button": true, "map3d-firstperson-button-active": this.state.firstPerson }); return [this.props.children, /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", { className: "map3d-nav-pan", "data-slot": 0, key: "MapControlsPan", style: { order: 1000 } }, /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "chevron-up", onPointerDown: function onPointerDown(ev) { return _this2.pan(ev, 0, 1); } }), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "chevron-left", onPointerDown: function onPointerDown(ev) { return _this2.pan(ev, -1, 0); } }), /*#__PURE__*/React.createElement(Icon, { icon: "home", onClick: function onClick() { return _this2.home(); } }), /*#__PURE__*/React.createElement(Icon, { icon: "chevron-right", onPointerDown: function onPointerDown(ev) { return _this2.pan(ev, 1, 0); } }), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "chevron-down", onPointerDown: function onPointerDown(ev) { return _this2.pan(ev, 0, -1); } }), /*#__PURE__*/React.createElement("span", null)), this.context), /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", { className: "map3d-nav-rotate", "data-slot": 0, key: "MapControlsRotate", style: { order: 999 } }, /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "tilt-up", onPointerDown: function onPointerDown(ev) { return _this2.tilt(ev, 0, 0.1); } }), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "tilt-left", onPointerDown: function onPointerDown(ev) { return _this2.tilt(ev, 0.1, 0); } }), /*#__PURE__*/React.createElement(Icon, { icon: "point", onClick: function onClick() { return _this2.resetTilt(); } }), /*#__PURE__*/React.createElement(Icon, { icon: "tilt-right", onPointerDown: function onPointerDown(ev) { return _this2.tilt(ev, -0.1, 0); } }), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(Icon, { icon: "tilt-down", onPointerDown: function onPointerDown(ev) { return _this2.tilt(ev, 0, -0.1); } }), /*#__PURE__*/React.createElement("span", null)), this.context), /*#__PURE__*/ReactDOM.createPortal(!this.state.firstPerson ? /*#__PURE__*/React.createElement("div", { className: "map3d-nav-zoom", "data-slot": 0, key: "MapControlsSpacerZoom", style: { order: 998 } }, /*#__PURE__*/React.createElement(Icon, { icon: "plus", onPointerDown: function onPointerDown(ev) { return _this2.zoom(ev, +1); } }), /*#__PURE__*/React.createElement(Icon, { icon: "minus", onPointerDown: function onPointerDown(ev) { return _this2.zoom(ev, -1); } })) : null, this.context), /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", { className: firstPersonButtonClasses, "data-slot": 0, key: "MapControlsFirstPerson", style: { order: 997 } }, /*#__PURE__*/React.createElement(Icon, { icon: "person", onClick: this.toggleFirstPersonControls })), this.context), this.props.controlsPosition !== 'bottom' ? /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", { className: "map3d-nav-spacer", key: "MapControlsSpacer", style: { order: 996 } }), this.context) : null]; } }]); }(React.Component); _defineProperty(MapControls3D, "contextType", MapButtonPortalContext); _defineProperty(MapControls3D, "propTypes", { children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), controlsPosition: PropTypes.string, currentTask: PropTypes.string, mouseButtons: PropTypes.object, onCameraChanged: PropTypes.func, onControlsSet: PropTypes.func, sceneContext: PropTypes.object }); export default connect(function (state) { return { currentTask: state.task.id }; }, {})(MapControls3D);