diff options
author | bobzel <zzzman@gmail.com> | 2023-12-15 11:20:43 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-12-15 11:20:43 -0500 |
commit | 0f2a9cce8286ca069ce7a7bf20fd05abc50acf22 (patch) | |
tree | 01938235d5a461be9a0157d50ce617669aeeee10 /src/client/views/nodes/MapBox/AnimationUtility.ts | |
parent | adf56d455ab0e429b7eac3430890ba7677cce8d9 (diff) | |
parent | ceb9ff8f2495bfeddb7bc0ab73fd5ddc3a6924fa (diff) |
Merge remote-tracking branch 'origin/zaul-new-branch' into moreUpgrading
Diffstat (limited to 'src/client/views/nodes/MapBox/AnimationUtility.ts')
-rw-r--r-- | src/client/views/nodes/MapBox/AnimationUtility.ts | 141 |
1 files changed, 108 insertions, 33 deletions
diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 13ce5b7e2..a5cff4668 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -7,7 +7,7 @@ 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 { action, computed, observable, runInAction } from 'mobx'; export enum AnimationStatus { START = 'start', @@ -24,18 +24,29 @@ export enum AnimationSpeed { 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,36 +62,99 @@ 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 @@ -94,11 +168,21 @@ export class AnimationUtility { this.isStreetViewAnimation = isStreetViewAnimation; } - constructor(firstLngLat: { lng: number; lat: number }, routeCoordinates: Position[], isStreetViewAnimation: boolean, animationSpeed: AnimationSpeed) { + @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, 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( { @@ -111,13 +195,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 ({ @@ -140,8 +218,6 @@ export class AnimationUtility { updateFrameId: (newFrameId: number) => void; }) => { 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) => { @@ -157,7 +233,7 @@ export class AnimationUtility { } // calculate the distance along the path based on the animationPhase - const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry.coordinates; + const alongPath = turf.along(this.PATH, this.PATH_DISTANCE * animationPhase).geometry.coordinates; const lngLat = { lng: alongPath[0], @@ -166,11 +242,7 @@ export class AnimationUtility { let bearing: number; if (this.isStreetViewAnimation) { - bearing = this.lerp( - this.currentStreetViewBearing, - this.calculateBearing(this.previousLngLat, lngLat), - 0.028 // Adjust the transition speed as needed - ); + bearing = this.lerp(this.currentStreetViewBearing, this.calculateBearing(this.previousLngLat, lngLat), 0.032); this.currentStreetViewBearing = bearing; // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing } else { @@ -179,32 +251,35 @@ 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); + camera.position = MercatorCoordinate.fromLngLat(correctedPosition, 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); updateFrameId(innerFrameId); |