Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RD-327: add terrain animation events #119

Merged
merged 4 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

## NEXT
### New Features

- The `Map` class instances now have a `.setTerrainAnimationDuration(d: number)` method
- The `Map` class instances now have events related to terrain animation `"terrainAnimationStart"` and `"terrainAnimationStop"`
- expose the function `getWebGLSupportError()` to detect WebGL compatibility


## 2.3.0
### Bug Fixes
- Updating from MapLibre v4.4.1 to v4.7.0. See Maplibre changelogs for [v4.5.0](https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#450), [v4.5.1](https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#451), [v4.5.2](https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#452), and [v4.6.0](https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#460)
Expand Down
49 changes: 49 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,55 @@ map.disableTerrain()

> 📣 *__Note 2:__* please be aware that due to the volume and elevation of the map floor in 3D space, the navigation with the terrain enabled is slightly different than without.

By default, enabling, disabling or even just updating the terrain exaggeration will result in a 1-second animation. This is possible to modify with the following `Map` method:

```ts
// Duration in milliseconds
map.setTerrainAnimationDuration(500);
```

## Terrain events
- `"terrain"` event

As an extension of Maplibre GL JS, MapTiler SDK is also exposing the terrain event `"terrain"`. This event is triggered when a terrain source is added or removed:

```ts
map.on("terrain", (e) => {
// your logic here
})
```

Since MapTiler SDK adds animation and the terrain data is necessary all along, the `"terrain"` event will be called at the very begining of the terrain animation when enabling and at the very end when disabling.

- `"terrainAnimationStart"` and `"terrainAnimationStop"` events

With the animation of the terrain, it can sometimes be convenient to know when the animation starts and ends. These two events are made just for that, here are how they work:

```ts
map.on("terrainAnimationStart", (event) => {
console.log("Terrain animation is starting...");
});

map.on("terrainAnimationStop", (event) => {
console.log("Terrain animation is finished");
});
```

The `event` argument is an object that contains (amond other things) a `terrain` attribute. In the case of `"terrainAnimationStop"`, this terrain attribute is `null` if the animation was about disabling the terrain, otherwise, this is just a propagation of `map.terrain`.

In the following example, we decide to associate the terrain animation with a change of camera, e.g. from clicking on the terrain control:
- when the terrain is enabled, it pops up with an animation and only **then** the camera is animated to take a lower point of view
- when the terrain is disabled, it is flattened with an animation and only **then** the camera is animated to a top view

```ts
map.on("terrainAnimationStop", (e) => {
map.easeTo({
pitch: e.terrain ? 60 : 0,
duration: 500,
});
});
```


# Easy language switching
The language generally depends on the style but we made it possible to easily set and update from a built-in list of languages.
Expand Down
32 changes: 24 additions & 8 deletions src/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export class Map extends maplibregl.Map {
private forceLanguageUpdate: boolean;
private languageAlwaysBeenStyle: boolean;
private isReady = false;
private terrainAnimationDuration = 1000;

constructor(options: MapOptions) {
displayNoWebGlWarning(options.container);
Expand Down Expand Up @@ -557,6 +558,14 @@ export class Map extends maplibregl.Map {
}
}

/**
* Set the duration (millisec) of the terrain animation for growing or flattening.
* Must be positive. (Built-in default: `1000` milliseconds)
*/
setTerrainAnimationDuration(d: number) {
this.terrainAnimationDuration = Math.max(d, 0);
}

/**
* Awaits for _this_ Map instance to be "loaded" and returns a Promise to the Map.
* If _this_ Map instance is already loaded, the Promise is resolved directly,
Expand Down Expand Up @@ -1012,7 +1021,7 @@ export class Map extends maplibregl.Map {
return this.isTerrainEnabled;
}

private growTerrain(exaggeration: number, durationMs = 1000) {
private growTerrain(exaggeration: number) {
// This method assumes the terrain is already built
if (!this.terrain) {
return;
Expand All @@ -1037,7 +1046,7 @@ export class Map extends maplibregl.Map {
}

// normalized value in interval [0, 1] of where we are currently in the animation loop
const positionInLoop = (performance.now() - startTime) / durationMs;
const positionInLoop = (performance.now() - startTime) / this.terrainAnimationDuration;

// The animation goes on until we reached 99% of the growing sequence duration
if (positionInLoop < 0.99) {
Expand All @@ -1049,13 +1058,18 @@ export class Map extends maplibregl.Map {
this.terrainGrowing = false;
this.terrainFlattening = false;
this.terrain.exaggeration = exaggeration;
this.fire("terrainAnimationStop", { terrain: this.terrain });
}

// When growing the terrain, this is only necessary before rendering
this._elevationFreeze = false;
this.triggerRepaint();
};

if (!this.terrainGrowing && !this.terrainFlattening) {
this.fire("terrainAnimationStart", { terrain: this.terrain });
}

this.terrainGrowing = true;
this.terrainFlattening = false;
requestAnimationFrame(updateExaggeration);
Expand Down Expand Up @@ -1157,10 +1171,7 @@ export class Map extends maplibregl.Map {
}

this.isTerrainEnabled = false;
// this.stopFlattening = false;

// Duration of the animation in millisec
const animationLoopDuration = 1 * 1000;
const startTime = performance.now();
// This is supposedly 0, but it could be something else (e.g. already in the middle of growing, or user defined other)
const currentExaggeration = this.terrain.exaggeration;
Expand All @@ -1172,14 +1183,14 @@ export class Map extends maplibregl.Map {
return;
}

// If the growing animation is triggered while flattening,
// then we exist the flatening
// If the growing animation is triggered while flattening is in progress.
// We exit the flatening
if (this.terrainGrowing) {
return;
}

// normalized value in interval [0, 1] of where we are currently in the animation loop
const positionInLoop = (performance.now() - startTime) / animationLoopDuration;
const positionInLoop = (performance.now() - startTime) / this.terrainAnimationDuration;

// At disabling, this should be togled fo both the setTerrain() (at the end of the animation)
// and also just before triggerRepain(), this is why we moved it this high
Expand All @@ -1201,11 +1212,16 @@ export class Map extends maplibregl.Map {
if (this.getSource(defaults.terrainSourceId)) {
this.removeSource(defaults.terrainSourceId);
}
this.fire("terrainAnimationStop", { terrain: null });
}

this.triggerRepaint();
};

if (!this.terrainGrowing && !this.terrainFlattening) {
this.fire("terrainAnimationStart", { terrain: this.terrain });
}

this.terrainGrowing = false;
this.terrainFlattening = true;
requestAnimationFrame(updateExaggeration);
Expand Down
Loading