Skip to content

Commit 553854a

Browse files
lesbaaLes MoffatMapTiler Testbot [lesbaa]
authored
RD-1396 migrate AnimatedRouteLayer and MapTilerAnimation to main repo (#279)
* RD-1396 migrate routing and animation helpers * RD-1396 Update and use correct imports * RD-1396 fix exports and failing exports unit test * RD-1396 Add logic to only use a single geojson feature, update tests * RD-1396 Update-readme * RD-1396 Update changelog * RD-1396 Appease linter, fix types, add 3d as devDep * RD-1396 run prettier * RD-1396 Fix failing CI tests * RD-1396 increase timeout on test for CI * RD-1396 add timeout to correct test * RD-1396 Increase timeout in e2e test * [BOT] Update snapshots (Triggered by @lesbaa in PR RD-1396-move-routing-to-main-repo) * RD-1396 Increase timeout to avoid flakeyness * [BOT] Update snapshots (Triggered by @lesbaa in PR RD-1396-move-routing-to-main-repo) * RD-1396 Update readme * RD-1396 Fixes, typos and update readme from PR requests * RD-1396 fix type failure * RD-1396 Fix PR comments * RD-1396 fix MapTilerAnimation example * RD-1396: Fix default options logic for path smoothing * RD-1396 Fix failing e2e tests and inject correct vite defined variables --------- Co-authored-by: Les Moffat <[email protected]> Co-authored-by: MapTiler Testbot [lesbaa] <[email protected]>
1 parent 8dfa6cf commit 553854a

File tree

80 files changed

+9693
-63
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+9693
-63
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
## 3.10.0
44

5+
### ✨ Features and improvements
6+
- Adds the new `MapTilerAnimation` module and associated helpers for creating and managing animations, lerping between values and 'smoothing' arrays.
7+
- Adds the new `AnimatedRouteLayer` module and associated helpers for animating camera movement along GeoJSON features paths.
8+
9+
### 🐛 Bug Fixes
10+
- None
11+
### ⚙️ Others
12+
- None
13+
14+
## 3.10.0
15+
516
### ✨ Features and improvements
617
- MapLibre GL dependency was updated to `5.14`
718
- Types that were removed in a minor version of MapLibre GL, breaking semver, were moved into MapTiler SDK to not break compatibility for MapTiler SDK users

README.md

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,158 @@ When defining a new _ramp_, the colors can be an RGB array (`[number, number, nu
13231323

13241324
Many methods are available on color ramps, such as getting the `<canvas>` element of it, rescaling it, flipping it or [resampling it in a non-linear way](colorramp.md). Read more on [our reference page](https://docs.maptiler.com/sdk-js/api/color-ramp/) and have a look at our [examples](https://docs.maptiler.com/sdk-js/examples/?q=colorramp) to see how they work.
13251325

1326-
### Vector Layer Helpers
1326+
# Camera routes and animations
1327+
1328+
The SDK comes with several classes to help with animations, particularly route animations.
1329+
1330+
See `demos/11-animated-routes.html` for examples.
1331+
See `demos/12-maptiler-animation.html` for examples.
1332+
1333+
#### 🧩 `MaptilerAnimation`
1334+
1335+
MaptilerAnimation is a utility class for smoothly animating between keyframes using custom easing and playback control. It supports event-based hooks for frame updates and completion, and works well within rendering loops or UI transitions.
1336+
1337+
##### 🚀 Usage
1338+
1339+
```ts
1340+
// linearly animated between values
1341+
const animation = new MaptilerAnimation({
1342+
keyframes: [
1343+
// `props` are interpolated across the duration
1344+
{ delta: 0, props: { lon: -7.445, } },
1345+
// `userData` can hold any type of custom data to pass with the keyframe
1346+
{ delta: 0.5, userData: { mydata: "whoa!" } },
1347+
{ delta: 1, props: { lon: -7.473 } }
1348+
],
1349+
duration: 1000, // 1 second
1350+
iterations: Infinity // loop forever
1351+
});
1352+
1353+
const marker = new Marker().setLngLat(
1354+
new LngLat(
1355+
-7.449346225791231,
1356+
39.399728941536836,
1357+
)
1358+
).addTo(map);
1359+
1360+
// TimeUpdate is fired every frame
1361+
animation.addEventListener(AnimationEventTypes.TimeUpdate, (e) => {
1362+
marker.setLngLat(
1363+
new LngLat(
1364+
e.props.lon,
1365+
39.399728941536836,
1366+
)
1367+
)
1368+
})
1369+
// fired when the keyframe changes
1370+
animation.addEventListener(AnimationEventTypes.Keyframe, ({ userData }) => {
1371+
console.log(userData.mydata) // "whoa!"
1372+
});
1373+
1374+
animation.play();
1375+
```
1376+
![](images/animate-linear-trimmed.gif)
1377+
1378+
```ts
1379+
// eased between values
1380+
const animation = new MaptilerAnimation({
1381+
keyframes: [
1382+
// `props` are interpolated across the duration
1383+
{ delta: 0, easing: EasingFunctionName.ElasticInOut, props: { lon: -7.445, } },
1384+
{ delta: 1, props: { lon: -7.455 } }
1385+
],
1386+
duration: 1000, // 1 second
1387+
iterations: Infinity // loop forever
1388+
});
1389+
```
1390+
![](images/animate-elastic-trimmed.gif)
1391+
1392+
####  🗺️ `AnimatedRouteLayer`
1393+
1394+
`AnimatedRouteLayer` is custom layer that animates a path or route on the map based on keyframes or GeoJSON data. It supports animated line styling and camera following, making it ideal for visualizing routes, playback tracks, or timeline-based geographic events.
1395+
1396+
Note: At present, to avoid problems arising from the camera being manipulated by two animations at any one time, there can only ever be one instance of `AnimatedRouteLayer` on the map at any time. This API may change in the future, but at present you must remove each instance of `AnimatedRouteLayer` from the map before adding another.
1397+
1398+
##### ✨ Features
1399+
- Animate a path using keyframes or GeoJSON data
1400+
- Optional animated stroke styles to indicate progress
1401+
- Camera movement smoothing, following along the route
1402+
- Configurable duration, easing, delay, and iterations via geojson properties
1403+
- Event-based lifecycle hooks for adaptability.
1404+
- Optional manual frame advancement (e.g., for scrubbing or syncing with map events, scroll etc etc)
1405+
1406+
##### 🚀 Basic Usage
1407+
```ts
1408+
const myGeoJSONSource = {
1409+
"type": "FeatureCollection",
1410+
"features": [
1411+
{
1412+
"type": "Feature",
1413+
"geometry": {
1414+
"type": "LineString",
1415+
"coordinates": [
1416+
[-74.0060, 40.7128],
1417+
[-73.9352, 40.7306],
1418+
[-73.9851, 40.7580]
1419+
]
1420+
},
1421+
"properties": {
1422+
"@duration": 5000, // animation params are prepended with '@'
1423+
"@iterations": 3,
1424+
"@delay": 1000,
1425+
"@autoplay": true,
1426+
"bearing": [
1427+
40,
1428+
30,
1429+
10,
1430+
10,
1431+
20,
1432+
40,
1433+
]
1434+
}
1435+
}
1436+
]
1437+
}
1438+
1439+
map.addSource("my-geojson-source", {
1440+
type: "geojson",
1441+
data: myGeoJSONSource,
1442+
});
1443+
1444+
const animatedRoute = new AnimatedRouteLayer({
1445+
source: {
1446+
// assumes that the source is already added to the map with the given layer ID
1447+
id: "my-geojson-source", // the name of the source
1448+
layerID: "route-layer", // the name of the layer
1449+
},
1450+
// OR
1451+
keyframes: [], // an array of keyframes
1452+
1453+
duration: 5000,
1454+
pathStrokeAnimation: {
1455+
// will only be applied to LineString GeoJSON types
1456+
activeColor: [0, 128, 0, 1], // color of the line that has already been traversed
1457+
inactiveColor: [128, 128, 128, 0.5],
1458+
},
1459+
cameraAnimation: {
1460+
follow: true, // should the camera follow the route?
1461+
pathSmoothing: {
1462+
resolution: 20, // the resolution of the smoothness
1463+
epsilon: 10, // how much the path is simplified before smoothing
1464+
},
1465+
},
1466+
autoplay: true,
1467+
});
1468+
1469+
// Add to map
1470+
map.addLayer(animatedRoute);
1471+
1472+
// Playback controls
1473+
animatedRoute.play();
1474+
animatedRoute.pause();
1475+
```
1476+
1477+
For a full example of how to use this, look at [the example](./demos/11-animated-routes.html)
13271478

13281479
**Let's make vector layers easy!** Originally, you'd have to add a source and then proceed to the styling of your layer, which can be tricky because there are a lot of `paint` and `layout` options and they vary a lot from one type of layer to another. **But we have helpers for this!** 🖋️
13291480
![](images/screenshots/point-layer.jpg)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Animations and Animated Routes</title>
7+
<style>
8+
html {
9+
height: 100%;
10+
font-family: sans-serif;
11+
font-size: 13px;
12+
}
13+
14+
body {
15+
height: 100%;
16+
margin: 0;
17+
display: grid;
18+
/* grid-template: 1fr 1fr / 1fr 1fr; */
19+
/* gap: 16px; */
20+
box-sizing: border-box;
21+
}
22+
23+
.map {
24+
display: flex;
25+
justify-content: center;
26+
align-items: center;
27+
}
28+
29+
.controls-container {
30+
position: absolute;
31+
top: 16px;
32+
left: 16px;
33+
gap: 8px;
34+
z-index: 1;
35+
}
36+
37+
.controls {
38+
display: flex;
39+
}
40+
41+
.padded, button {
42+
display: inline-flex;
43+
align-items: center;
44+
border-radius: 8px;
45+
background-color: white;
46+
padding: 8px;
47+
border: 1px solid #ccc;
48+
font-size: 16px;
49+
margin-right: 4px;
50+
}
51+
52+
button {
53+
cursor: pointer;
54+
}
55+
</style>
56+
</head>
57+
<body>
58+
<div class="controls-container">
59+
<div class="controls">
60+
<button id="play">
61+
Play
62+
</button>
63+
<button id="pause">
64+
Pause
65+
</button>
66+
<button id="faster">
67+
Faster
68+
</button>
69+
<button id="slower">
70+
Slower
71+
</button>
72+
<div id="playbackRate" class="padded">1.0x</div>
73+
</div>
74+
<div id="keyframeName" class="padded" style="display: none">
75+
</div>
76+
</div>
77+
<script type="module" src="./src/11-animated-routes.ts"></script>
78+
</body>
79+
</html>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>MaptilerAnimation with MapTiler 3D Module</title>
7+
<style>
8+
html {
9+
height: 100%;
10+
font-family: sans-serif;
11+
font-size: 13px;
12+
}
13+
14+
body {
15+
height: 100%;
16+
margin: 0;
17+
display: grid;
18+
/* grid-template: 1fr 1fr / 1fr 1fr; */
19+
/* gap: 16px; */
20+
box-sizing: border-box;
21+
}
22+
23+
.map {
24+
display: flex;
25+
justify-content: center;
26+
align-items: center;
27+
}
28+
29+
.controls-container {
30+
position: absolute;
31+
top: 16px;
32+
left: 16px;
33+
gap: 8px;
34+
z-index: 1;
35+
}
36+
37+
.controls {
38+
display: flex;
39+
}
40+
41+
.padded, button {
42+
display: inline-flex;
43+
align-items: center;
44+
border-radius: 8px;
45+
background-color: white;
46+
padding: 8px;
47+
border: 1px solid #ccc;
48+
font-size: 16px;
49+
margin-right: 4px;
50+
}
51+
52+
button {
53+
cursor: pointer;
54+
}
55+
</style>
56+
<link rel="stylesheet" href="../build/maptiler-sdk.css">
57+
</head>
58+
<body>
59+
<div class="controls-container">
60+
<div class="controls">
61+
<button id="play">
62+
Play
63+
</button>
64+
<button id="pause">
65+
Pause
66+
</button>
67+
<button id="faster">
68+
Faster
69+
</button>
70+
<button id="slower">
71+
Slower
72+
</button>
73+
<button id="frame-advance">
74+
Frame Advance
75+
</button>
76+
<div id="playbackRate" class="padded">1.0x</div>
77+
</div>
78+
<div id="keyframeName" class="padded" style="display: none">
79+
</div>
80+
</div>
81+
<script type="module" src="./src/12-maptiler-animation.ts"></script>
82+
</body>
83+
</html>

demos/public/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
<a href="07-spacebox.html">SpaceBox →</a>
6262
<a href="09-custom-controls-declarative.html">Custom Controls: Declarative →</a>
6363
<a href="10-custom-controls-programmatic.html">Custom Controls: Programmatic →</a>
64+
<a href="11-animated-routes.html">Animated Routes →</a>
65+
<a href="12-maptiler-animation.html">Basic Animations →</a>
6466
</div>
6567
</div>
6668
</body>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Model Information:
2+
* title: Burj Khalifa
3+
* source: https://sketchfab.com/3d-models/burj-khalifa-59e6dd74e5f647158de568b5a7f9cab7
4+
* author: ManySince910 (https://sketchfab.com/noears6)
5+
6+
Model License:
7+
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
8+
* requirements: Author must be credited. Commercial use is allowed.
9+
10+
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
11+
This work is based on "Burj Khalifa" (https://sketchfab.com/3d-models/burj-khalifa-59e6dd74e5f647158de568b5a7f9cab7) by ManySince910 (https://sketchfab.com/noears6) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
935 KB
Binary file not shown.

0 commit comments

Comments
 (0)