diff --git a/common/webapp/src/js/controls/map/MapControls.js b/common/webapp/src/js/controls/map/MapControls.js index 818fd4fb6..e9d3373f0 100644 --- a/common/webapp/src/js/controls/map/MapControls.js +++ b/common/webapp/src/js/controls/map/MapControls.js @@ -96,6 +96,7 @@ export class MapControls { */ start(manager) { this.manager = manager; + this.snapDistance = manager.distance; this.rootElement.addEventListener("contextmenu", this.onContextMenu); this.hammer.on("tap", this.onTap); @@ -172,9 +173,6 @@ export class MapControls { this.manager.distance = softClamp(this.manager.distance, this.minDistance, this.maxDistance, 0.8); - // max angle for current distance - let maxAngleForZoom = MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance); - // rotation this.mouseRotate.update(delta, map); this.keyRotate.update(delta, map); @@ -193,12 +191,11 @@ export class MapControls { this.mouseAngle.update(delta, map); this.keyAngle.update(delta, map); this.touchAngle.update(delta, map); - this.manager.angle = softClamp(this.manager.angle, 0, maxAngleForZoom, 0.8); + this.manager.angle = softClamp(this.manager.angle, 0, HALF_PI, 0.8); } // target height if (this.manager.ortho === 0 || this.manager.angle === 0) { - this.mapHeight.maxAngle = maxAngleForZoom; this.mapHeight.update(delta, map); } } diff --git a/common/webapp/src/js/controls/map/MapHeightControls.js b/common/webapp/src/js/controls/map/MapHeightControls.js index 8ef0b7763..1e56ccae6 100644 --- a/common/webapp/src/js/controls/map/MapHeightControls.js +++ b/common/webapp/src/js/controls/map/MapHeightControls.js @@ -24,6 +24,7 @@ */ import {MathUtils, Vector2} from "three"; +import {MapControls} from "./MapControls"; export class MapHeightControls { @@ -36,7 +37,6 @@ export class MapHeightControls { this.cameraHeightStiffness = cameraHeightStiffness; this.targetHeightStiffness = targetHeightStiffness; - this.maxAngle = Math.PI / 2; this.targetHeight = 0; this.cameraHeight = 0; @@ -78,7 +78,8 @@ export class MapHeightControls { // camera height this.minCameraHeight = 0; - if (this.maxAngle >= 0.1) { + let maxAngle = MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance); + if (maxAngle >= 0.1) { let cameraSmoothing = this.cameraHeightStiffness / (16.666 / delta); cameraSmoothing = MathUtils.clamp(cameraSmoothing, 0, 1); @@ -88,7 +89,7 @@ export class MapHeightControls { this.cameraHeight += cameraDelta * cameraSmoothing; if (Math.abs(cameraDelta) < 0.001) this.cameraHeight = cameraTerrainHeight; - let maxAngleHeight = Math.cos(this.maxAngle) * this.manager.distance; + let maxAngleHeight = Math.cos(maxAngle) * this.manager.distance; this.minCameraHeight = this.cameraHeight - maxAngleHeight + 1; } diff --git a/common/webapp/src/js/controls/map/keyboard/KeyAngleControls.js b/common/webapp/src/js/controls/map/keyboard/KeyAngleControls.js index fcdb25297..77871f1da 100644 --- a/common/webapp/src/js/controls/map/keyboard/KeyAngleControls.js +++ b/common/webapp/src/js/controls/map/keyboard/KeyAngleControls.js @@ -25,6 +25,8 @@ import {MathUtils} from "three"; import {KeyCombination} from "../../KeyCombination"; +import {softMax} from "../../../util/Utils"; +import {MapControls} from "../MapControls"; export class KeyAngleControls { @@ -90,6 +92,7 @@ export class KeyAngleControls { smoothing = MathUtils.clamp(smoothing, 0, 1); this.manager.angle += this.deltaAngle * smoothing * this.speed * delta * 0.06; + this.manager.angle = softMax(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance), 0.8); this.deltaAngle *= 1 - smoothing; if (Math.abs(this.deltaAngle) < 0.0001) { diff --git a/common/webapp/src/js/controls/map/keyboard/KeyZoomControls.js b/common/webapp/src/js/controls/map/keyboard/KeyZoomControls.js index dd9a5b166..2d5d34072 100644 --- a/common/webapp/src/js/controls/map/keyboard/KeyZoomControls.js +++ b/common/webapp/src/js/controls/map/keyboard/KeyZoomControls.js @@ -25,6 +25,7 @@ import {MathUtils} from "three"; import {KeyCombination} from "../../KeyCombination"; +import {MapControls} from "../MapControls"; export class KeyZoomControls { @@ -88,6 +89,7 @@ export class KeyZoomControls { smoothing = MathUtils.clamp(smoothing, 0, 1); this.manager.distance *= Math.pow(1.5, this.deltaZoom * smoothing * this.speed * delta * 0.06); + this.manager.angle = Math.min(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance)); this.deltaZoom *= 1 - smoothing; if (Math.abs(this.deltaZoom) < 0.0001) { diff --git a/common/webapp/src/js/controls/map/mouse/MouseAngleControls.js b/common/webapp/src/js/controls/map/mouse/MouseAngleControls.js index 467ed3ea5..e57ccc149 100644 --- a/common/webapp/src/js/controls/map/mouse/MouseAngleControls.js +++ b/common/webapp/src/js/controls/map/mouse/MouseAngleControls.js @@ -24,6 +24,8 @@ */ import {MathUtils} from "three"; +import {MapControls} from "../MapControls"; +import {softMax, softSet} from "../../../util/Utils"; export class MouseAngleControls { @@ -40,6 +42,9 @@ export class MouseAngleControls { this.lastY = 0; this.deltaAngle = 0; + this.dynamicDistance = false; + this.startDistance = 0; + this.speed = speed; this.stiffness = stiffness; @@ -56,6 +61,7 @@ export class MouseAngleControls { this.target.addEventListener("mousedown", this.onMouseDown); window.addEventListener("mousemove", this.onMouseMove); window.addEventListener("mouseup", this.onMouseUp); + window.addEventListener("wheel", this.onWheel); window.addEventListener("resize", this.updatePixelToSpeedMultiplier); } @@ -64,6 +70,7 @@ export class MouseAngleControls { this.target.removeEventListener("mousedown", this.onMouseDown); window.removeEventListener("mousemove", this.onMouseMove); window.removeEventListener("mouseup", this.onMouseUp); + window.removeEventListener("wheel", this.onWheel); window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); } @@ -80,6 +87,12 @@ export class MouseAngleControls { this.manager.angle += this.deltaAngle * smoothing * this.speed * this.pixelToSpeedMultiplierY; + if (this.dynamicDistance) { + this.manager.distance = softSet(this.manager.distance, Math.min(MapControls.getMaxDistanceForPerspectiveAngle(this.manager.angle), this.startDistance), 0.4); + } else { + this.manager.angle = softMax(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance), 0.8); + } + this.deltaAngle *= 1 - smoothing; if (Math.abs(this.deltaAngle) < 0.0001) { this.deltaAngle = 0; @@ -100,6 +113,9 @@ export class MouseAngleControls { this.moving = true; this.deltaAngle = 0; this.lastY = evt.y; + + this.startDistance = this.manager.distance; + this.dynamicDistance = this.manager.distance < 1000; } } @@ -123,6 +139,10 @@ export class MouseAngleControls { this.moving = false; } + onWheel = evt => { + this.dynamicDistance = false; + } + updatePixelToSpeedMultiplier = () => { this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; } diff --git a/common/webapp/src/js/controls/map/mouse/MouseZoomControls.js b/common/webapp/src/js/controls/map/mouse/MouseZoomControls.js index 79aa14de0..d081d5fee 100644 --- a/common/webapp/src/js/controls/map/mouse/MouseZoomControls.js +++ b/common/webapp/src/js/controls/map/mouse/MouseZoomControls.js @@ -24,6 +24,7 @@ */ import {MathUtils} from "three"; +import {MapControls} from "../MapControls"; export class MouseZoomControls { @@ -66,6 +67,7 @@ export class MouseZoomControls { smoothing = MathUtils.clamp(smoothing, 0, 1); this.manager.distance *= Math.pow(1.5, this.deltaZoom * smoothing * this.speed); + this.manager.angle = Math.min(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance)); this.deltaZoom *= 1 - smoothing; if (Math.abs(this.deltaZoom) < 0.0001) { diff --git a/common/webapp/src/js/controls/map/touch/TouchAngleControls.js b/common/webapp/src/js/controls/map/touch/TouchAngleControls.js index 8d3760691..3beed9faa 100644 --- a/common/webapp/src/js/controls/map/touch/TouchAngleControls.js +++ b/common/webapp/src/js/controls/map/touch/TouchAngleControls.js @@ -24,6 +24,8 @@ */ import {MathUtils} from "three"; +import {softMax} from "../../../util/Utils"; +import {MapControls} from "../MapControls"; export class TouchAngleControls { @@ -83,6 +85,7 @@ export class TouchAngleControls { smoothing = MathUtils.clamp(smoothing, 0, 1); this.manager.angle += this.deltaAngle * smoothing * this.speed * this.pixelToSpeedMultiplierY; + this.manager.angle = softMax(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance), 0.8); this.deltaAngle *= 1 - smoothing; if (Math.abs(this.deltaAngle) < 0.0001) { diff --git a/common/webapp/src/js/controls/map/touch/TouchZoomControls.js b/common/webapp/src/js/controls/map/touch/TouchZoomControls.js index e959637d2..62204b93f 100644 --- a/common/webapp/src/js/controls/map/touch/TouchZoomControls.js +++ b/common/webapp/src/js/controls/map/touch/TouchZoomControls.js @@ -23,6 +23,8 @@ * THE SOFTWARE. */ +import {MapControls} from "../MapControls"; + export class TouchZoomControls { /** @@ -87,6 +89,7 @@ export class TouchZoomControls { onTouchMove = evt => { if(this.moving){ this.deltaZoom *= evt.scale / this.lastZoom; + this.manager.angle = Math.min(this.manager.angle, MapControls.getMaxPerspectiveAngleForDistance(this.manager.distance)); } this.lastZoom = evt.scale; diff --git a/common/webapp/src/js/util/Utils.js b/common/webapp/src/js/util/Utils.js index dde61d2da..287518cd4 100644 --- a/common/webapp/src/js/util/Utils.js +++ b/common/webapp/src/js/util/Utils.js @@ -377,6 +377,17 @@ export const softClamp = (value, min, max, stiffness) => { return softMax(softMin(value, min, stiffness), max, stiffness); } +/** + * Softly sets a value + * @param value {number} + * @param target {number} + * @param stiffness {number} + * @returns {number} + */ +export const softSet = (value, target, stiffness) => { + return softClamp(value, target, target, stiffness); +} + export const vecArrToObj = (val, useZ = false) => { if (val && val.length >= 2) { if (useZ) return {x: val[0], z: val[1]};