aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/MapBox/AnimationUtility.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/MapBox/AnimationUtility.ts')
-rw-r--r--src/client/views/nodes/MapBox/AnimationUtility.ts147
1 files changed, 114 insertions, 33 deletions
diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts
index 256acbf13..11b335a96 100644
--- a/src/client/views/nodes/MapBox/AnimationUtility.ts
+++ b/src/client/views/nodes/MapBox/AnimationUtility.ts
@@ -5,9 +5,8 @@ import * as React from 'react';
import * as d3 from "d3";
import * as turf from '@turf/turf';
import { Position } from "@turf/turf";
-import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson";
-import { observer } from "mobx-react";
-import { action, computed, observable } from "mobx";
+import { Feature, GeoJsonProperties, Geometry } from "geojson";
+import { action, computed, observable, runInAction } from "mobx";
export enum AnimationStatus {
START = 'start',
@@ -21,23 +20,32 @@ export enum AnimationSpeed {
FAST = '3x',
}
-@observer
export class AnimationUtility {
private SMOOTH_FACTOR = 0.95
private ROUTE_COORDINATES: Position[] = [];
+
+ @observable
private PATH: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>;
+
+ private PATH_DISTANCE: number;
private FLY_IN_START_PITCH = 40;
private FIRST_LNG_LAT: {lng: number, lat: number};
private START_ALTITUDE = 3_000_000;
+ private MAP_REF: MapRef | null;
@observable private isStreetViewAnimation: boolean;
@observable private animationSpeed: AnimationSpeed;
-
+ @observable
private previousLngLat: {lng: number, lat: number};
+ private previousAltitude: number | null = null;
+ private previousPitch: number | null = null;
+
private currentStreetViewBearing: number = 0;
+ private terrainDisplayed: boolean;
+
@computed get flyInEndBearing() {
return this.isStreetViewAnimation ?
this.calculateBearing(
@@ -51,38 +59,103 @@ export class AnimationUtility {
}
)
: -20;
+ }
+
+ @computed get currentAnimationAltitude(): number {
+ if (!this.isStreetViewAnimation) return 20_000;
+ if (!this.terrainDisplayed) return 50;
+ const coords: mapboxgl.LngLatLike = [this.previousLngLat.lng, this.previousLngLat.lat];
+ // console.log('MAP REF: ', this.MAP_REF)
+ // console.log("current elevation: ", this.MAP_REF?.queryTerrainElevation(coords));
+ let altitude = (this.MAP_REF ? (this.MAP_REF.queryTerrainElevation(coords) ?? 0) : 0);
+ if (altitude === 0){
+ altitude+=50;
}
+ if (this.previousAltitude){
+ return this.lerp(altitude, this.previousAltitude, 0.02);
+ }
+ return altitude;
+
+ }
@computed get flyInStartBearing() {
return Math.max(0, Math.min(this.flyInEndBearing + 20, 360)); // between 0 and 360
}
@computed get flyInEndAltitude() {
- return this.isStreetViewAnimation ? 70 : 10000;
+ // return this.isStreetViewAnimation ? (this.currentAnimationAltitude + 70 ): 10_000;
+ return this.currentAnimationAltitude;
+ }
+
+ @computed get currentPitch(): number {
+ if (!this.isStreetViewAnimation) return 50;
+ if (!this.terrainDisplayed) return 80;
+ else {
+ // const groundElevation = 0;
+ const heightAboveGround = this.currentAnimationAltitude;
+ const horizontalDistance = 500;
+
+ let pitch;
+ if (heightAboveGround >= 0){
+ pitch = (90- Math.atan(heightAboveGround/horizontalDistance) * (180/Math.PI));
+ }
+ else {
+ pitch = 80;
+ }
+
+ console.log(Math.max(50, Math.min(pitch, 85)));
+
+ if (this.previousPitch){
+ return this.lerp(Math.max(50, Math.min(pitch, 85)), this.previousPitch, 0.02);
+ }
+ return Math.max(50, Math.min(pitch, 85));
+ }
}
@computed get flyInEndPitch() {
- return this.isStreetViewAnimation ? 80 : 50;
+ return this.currentPitch;
}
@computed get flyToDuration() {
switch (this.animationSpeed) {
case AnimationSpeed.SLOW:
- return 4000;
+ return 4_000;
case AnimationSpeed.MEDIUM:
- return 2500;
+ return 2_500;
case AnimationSpeed.FAST:
- return 1250;
+ return 1_250;
default:
- return 2500;
+ return 2_500;
}
}
@computed get animationDuration(): number {
- return 20_000;
- // compute path distance for a standard speed
- // get animation speed
- // get isStreetViewAnimation (should be slower if so)
+ let scalingFactor: number;
+ const MIN_DISTANCE = 0;
+ const MAX_DISTANCE = 3_000; // anything greater than 3000 is just set to 1 when normalized
+ const MAX_DURATION = this.isStreetViewAnimation ? 120_000 : 60_000;
+
+ const normalizedDistance = Math.min(1, (this.PATH_DISTANCE - MIN_DISTANCE) / (MAX_DISTANCE - MIN_DISTANCE));
+ const easedDistance = d3.easeExpOut(Math.min(normalizedDistance, 1));
+
+ switch (this.animationSpeed){
+ case AnimationSpeed.SLOW:
+ scalingFactor = 250;
+ break;
+ case AnimationSpeed.MEDIUM:
+ scalingFactor = 150;
+ break;
+ case AnimationSpeed.FAST:
+ scalingFactor = 85;
+ break;
+ default:
+ scalingFactor = 150;
+ break;
+ }
+
+ const duration = Math.min(MAX_DURATION, (easedDistance * MAX_DISTANCE) * (this.isStreetViewAnimation ? scalingFactor*1.12 : scalingFactor));
+
+ return duration;
}
@action
@@ -96,17 +169,29 @@ export class AnimationUtility {
this.isStreetViewAnimation = isStreetViewAnimation;
}
+ @action
+ public setPath = (path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>) => {
+ this.PATH = path;
+ }
+
constructor(
firstLngLat: {lng: number, lat: number},
routeCoordinates: Position[],
isStreetViewAnimation: boolean,
- animationSpeed: AnimationSpeed
+ animationSpeed: AnimationSpeed,
+ terrainDisplayed: boolean,
+ mapRef: MapRef | null
) {
this.FIRST_LNG_LAT = firstLngLat;
this.previousLngLat = firstLngLat;
+ this.isStreetViewAnimation = isStreetViewAnimation;
+ this.MAP_REF = mapRef;
+
this.ROUTE_COORDINATES = routeCoordinates;
this.PATH = turf.lineString(routeCoordinates);
+ this.PATH_DISTANCE = turf.lineDistance(this.PATH);
+ this.terrainDisplayed = terrainDisplayed;
const bearing = this.calculateBearing(
{
@@ -119,13 +204,7 @@ export class AnimationUtility {
}
);
this.currentStreetViewBearing = bearing;
- // if (isStreetViewAnimation){
- // this.flyInEndBearing = bearing;
- // }
- this.isStreetViewAnimation = isStreetViewAnimation;
this.animationSpeed = animationSpeed;
- // calculate animation duration based on speed
- // this.animationDuration = animationDuration;
}
public animatePath = async ({
@@ -151,8 +230,6 @@ export class AnimationUtility {
}) => {
return new Promise<void>(async (resolve) => {
- const pathDistance = turf.lineDistance(this.PATH);
- console.log("PATH DISTANCE: ", pathDistance);
let startTime: number | null = null;
const frame = async (currentTime: number) => {
@@ -169,7 +246,7 @@ export class AnimationUtility {
// calculate the distance along the path based on the animationPhase
- const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry
+ const alongPath = turf.along(this.PATH, this.PATH_DISTANCE * animationPhase).geometry
.coordinates;
const lngLat = {
@@ -182,7 +259,7 @@ export class AnimationUtility {
bearing = this.lerp(
this.currentStreetViewBearing,
this.calculateBearing(this.previousLngLat, lngLat),
- 0.028 // Adjust the transition speed as needed
+ 0.032
);
this.currentStreetViewBearing = bearing;
// bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing
@@ -192,35 +269,39 @@ export class AnimationUtility {
// bearing = startBearing - animationPhase * 200.0;
}
- this.previousLngLat = lngLat;
+ runInAction(() => {
+ this.previousLngLat = lngLat;
+ })
updateAnimationPhase(animationPhase);
// compute corrected camera ground position, so that he leading edge of the path is in view
var correctedPosition = this.computeCameraPosition(
this.isStreetViewAnimation,
- this.flyInEndPitch,
+ this.currentPitch,
bearing,
lngLat,
- this.flyInEndAltitude,
+ this.currentAnimationAltitude,
true // smooth
);
// set the pitch and bearing of the camera
const camera = map.getFreeCameraOptions();
- camera.setPitchBearing(this.flyInEndPitch, bearing);
+ camera.setPitchBearing(this.currentPitch, bearing);
- console.log("Corrected pos: ", correctedPosition);
- console.log("Start altitude: ", this.flyInEndAltitude);
+
// set the position and altitude of the camera
camera.position = MercatorCoordinate.fromLngLat(
correctedPosition,
- this.flyInEndAltitude
+ this.currentAnimationAltitude
);
// apply the new camera options
map.setFreeCameraOptions(camera);
+
+ this.previousAltitude = this.currentAnimationAltitude;
+ this.previousPitch = this.previousPitch;
// repeat!
const innerFrameId = await window.requestAnimationFrame(frame);