Skip to content

Commit 81e85b3

Browse files
committed
feat: add cesium-walk
1 parent 0df3973 commit 81e85b3

6 files changed

Lines changed: 266 additions & 0 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ A collection of helpers and web component for working with [CesiumJS](https://ce
88
* [cesium-first-person-mode](packages/FirstPersonCameraMode): a first person navigation mode that uses the Pointer Lock API
99
* [cesium-sphere-camera](packages/cesium-sphere-camera): a camera mode that allows the user to rotate the camera around a position
1010
* [cesium-binoculars](packages/cesium-binoculars): a camera mode that allows the user to use binoculars with the mouse wheel
11+
* [cesium-walk](packages/cesium-walk): a camera mode that allows the user to walk around the scene
1112

1213
## Online demos
1314

@@ -22,6 +23,7 @@ npx parcel serve demos/cesium-view-cube.html --open
2223
npx parcel serve demos/cesium-first-person-mode.html --open
2324
npx parcel serve demos/cesium-sphere-camera.html --open
2425
npx parcel serve demos/cesium-binoculars.html --open
26+
npx parcel serve demos/cesium-walk.html --open
2527
```
2628

2729
## Guide

demos/cesium-walk.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<script src="https://cesium.com/downloads/cesiumjs/releases/1.137/Build/Cesium/Cesium.js"></script>
7+
<link href="https://cesium.com/downloads/cesiumjs/releases/1.137/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
8+
<style>
9+
html, body, #cesiumContainer {
10+
height: 100%;
11+
margin: 0;
12+
}
13+
#activate {
14+
position: absolute;
15+
right: 30px;
16+
top: 30px;
17+
font-family: monospace;
18+
font-weight: bold;
19+
font-size: 1.6em;
20+
}
21+
</style>
22+
</head>
23+
24+
<body>
25+
<div id="cesiumContainer"></div>
26+
<button id="activate" type="button">Activate !</button>
27+
<script type="module">
28+
import {createViewer} from './setup.js';
29+
import CesiumWalk from '../packages/cesium-walk/cesium-walk.js';
30+
31+
createViewer('cesiumContainer').then(viewer => {
32+
const mode = new CesiumWalk(viewer);
33+
document.querySelector('#activate').addEventListener('click', () => mode.active = !mode.active);
34+
});
35+
</script>
36+
</body>
37+
38+
</html>

packages/cesium-walk/LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2024-present, camptocamp SA
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
3. Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/cesium-walk/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# walk mode for CesiumJS
2+
3+
Control the camera in CesiumJS as if you were walking around.
4+
Use `w`, `a`, `s` and `d` keys to move.
5+
6+
## Demo
7+
8+
[Demo](https://geoblocks.github.io/cesium-helpers/cesium-walk.html)
9+
10+
## Installation
11+
12+
```bash
13+
npm i --save @geoblocks/cesium-walk
14+
```
15+
16+
### Usage
17+
18+
```js
19+
import {Viewer} from 'cesium';
20+
import WalkCameraMode from '@geoblocks/cesium-walk';
21+
22+
const viewer = new Viewer(...);
23+
const mode = new WalkCameraMode(viewer.scene);
24+
25+
// ...
26+
mode.active = true;
27+
```
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// FIXME: make key bindings configurable, add arrow keys
2+
3+
export default class CesiumWalk {
4+
/**
5+
* @param {import('cesium').Viewer} viewer
6+
* @param {number} [speed=1.6] Walk speed in meters per second.
7+
* @param {number} [height=2.0] Height of the camera above the terrain.
8+
*/
9+
constructor(viewer, speed = 1.6, height = 2.0) {
10+
/**
11+
* @type {import('cesium').Viewer}
12+
*/
13+
this.viewer = viewer;
14+
15+
/**
16+
* @type {number}
17+
*/
18+
this.speed = speed;
19+
20+
/**
21+
* @type {number}
22+
*/
23+
this.height = height;
24+
25+
/**
26+
* @type {boolean}
27+
*/
28+
this.active_ = false;
29+
30+
/**
31+
* @type {number}
32+
*/
33+
this.lastTick;
34+
35+
/**
36+
* @type {{forward: boolean, left: boolean, backward: boolean, right: boolean}}
37+
*/
38+
this.buttons = {
39+
forward: false,
40+
left: false,
41+
backward: false,
42+
right: false,
43+
};
44+
45+
/**
46+
* @type {function(KeyboardEvent): void}
47+
*/
48+
this.handleKeyUpDownFunction = this.handleKeyUpDown.bind(this);
49+
50+
/**
51+
* @type {function(): void}
52+
*/
53+
this.handleTickFunction = this.handleTick.bind(this);
54+
}
55+
56+
get active() {
57+
return this.active_;
58+
}
59+
60+
set active(active) {
61+
this.active_ = active;
62+
if (this.active_) {
63+
document.addEventListener("keydown", this.handleKeyUpDownFunction);
64+
document.addEventListener("keyup", this.handleKeyUpDownFunction);
65+
this.viewer.clock.onTick.addEventListener(this.handleTickFunction);
66+
this.clampCameraToTerrain();
67+
} else {
68+
document.removeEventListener("keydown", this.handleKeyUpDownFunction);
69+
document.removeEventListener("keyup", this.handleKeyUpDownFunction);
70+
this.viewer.clock.onTick.removeEventListener(this.handleTickFunction);
71+
}
72+
this.enableNavigation(!this.active_);
73+
}
74+
75+
/**
76+
* @param {KeyboardEvent} event
77+
*/
78+
handleKeyUpDown(event) {
79+
const pressed = event.type === "keydown";
80+
switch (event.key) {
81+
case "w":
82+
this.buttons.forward = pressed;
83+
break;
84+
case "a":
85+
this.buttons.left = pressed;
86+
break;
87+
case "s":
88+
this.buttons.backward = pressed;
89+
break;
90+
case "d":
91+
this.buttons.right = pressed;
92+
break;
93+
}
94+
}
95+
96+
handleTick() {
97+
const timestamp = performance.now();
98+
if (this.needsTick()) {
99+
const camera = this.viewer.camera;
100+
const deltaTime = timestamp - this.lastTick;
101+
102+
const distance = (this.speed * deltaTime) / 1000;
103+
104+
if (this.buttons.forward) {
105+
camera.moveForward(distance);
106+
}
107+
if (this.buttons.left) {
108+
camera.moveLeft(distance);
109+
}
110+
if (this.buttons.backward) {
111+
camera.moveBackward(distance);
112+
}
113+
if (this.buttons.right) {
114+
camera.moveRight(distance);
115+
}
116+
this.clampCameraToTerrain();
117+
}
118+
119+
this.lastTick = timestamp;
120+
}
121+
122+
clampCameraToTerrain() {
123+
const camera = this.viewer.camera;
124+
const terrainHeight = this.viewer.scene.globe.getHeight(
125+
camera.positionCartographic
126+
);
127+
const cameraHeight = camera.positionCartographic.height;
128+
129+
camera.moveDown(cameraHeight - terrainHeight - this.height);
130+
}
131+
132+
/**
133+
* @return {boolean}
134+
*/
135+
needsTick() {
136+
return (
137+
this.buttons.forward ||
138+
this.buttons.left ||
139+
this.buttons.backward ||
140+
this.buttons.right
141+
);
142+
}
143+
144+
/**
145+
* Enable or disable cesium navigation interactions.
146+
* @param {boolean} enable
147+
*/
148+
enableNavigation(enable) {
149+
const controller = this.viewer.scene.screenSpaceCameraController;
150+
controller.enableTranslate = enable;
151+
controller.enableZoom = enable;
152+
controller.enableRotate = enable;
153+
controller.enableTilt = enable;
154+
}
155+
}

packages/cesium-walk/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@geoblocks/cesium-walk",
3+
"version": "0.0.0",
4+
"license": "BSD-3-Clause",
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/geoblocks/cesium-helpers/",
8+
"directory": "packages/cesium-walk"
9+
},
10+
"main": "cesium-walk.js",
11+
"module": "cesium-walk.js",
12+
"publishConfig": {
13+
"access": "public"
14+
}
15+
}

0 commit comments

Comments
 (0)