-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
159 lines (142 loc) · 7.22 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>osm4vr demo - Fly through the world in VR with OSM map data</title>
<meta name="description" content="osm4vr: Fly through the world in Virtual Reality, with map and buildings from OpenStreetmap">
<script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/aframe-extras.controls.min.js"></script>
<script src="https://unpkg.com/[email protected]/osmtogeojson.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/utils/BufferGeometryUtils.min.js"></script>
<script src="osm-geojson.js"></script>
<script src="osm-tiles.js"></script>
<!-- <script src="log2hud.js"></script> -->
<script src="birdman.js"></script>
<script src="wing.js"></script>
<style>
body { font: 0.9em "Verdana", sans-serif; }
.ontop { z-index: 10; position: relative; }
#info { padding: 4px; position: relative; max-width: 100%; max-height: 95%; overflow: auto; }
#legal { font-size: 0.75em; }
#location input, #location button { font-size: inherit; }
@media (width <= 800px) {
body { font-size: 0.8em; }
h1 { font-size: 1.2em; }
#legal { font-size: 0.8em; }
}
</style>
</head>
<body>
<div id="info" class="ontop">
<div id="description">
<h1>osm4vr</h1>
<p>
Fly through the world in Virtual Reality, in your browser.
The map, buildings and potentially other features come from OpenStreetMap.
</p>
<p>
In VR, you can use hand controllers to fly around by extending your arms and flapping.
The experience also works in non-VR mode, where you can use arrow or W/A/S/D keys to move, and touch on mobile.
</p>
<p>Search for a place or enter the latitude / longitude directly and press Go, or simply press Menu to start at the default position.</p>
</div>
<div id="location">
<input id="searchInput" type="search" placeholder="Berlin" />
<button id="searchButton" onclick="searchLocation(); return false;">Search</button>
<br />
<input type="number" id="latitude" placeholder="latitude" value="52.52" size="8" step="0.00001" min="-90" max="90" />
<input type="number" id="longitude" placeholder="longitude" value="13.41" size="8" step="0.00001" min="-180" max="180" />
<button id="goButton" onclick="loadLocation(); return false;">Go</button>
</div>
<div id="legal">
<p>
Source code (MIT license): <a href="https://github.com/ctrlw/osm4vr">github.com/ctrlw/osm4vr</a>
<br />
Map data and tiles ©
<a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>
contributors, under <a href="https://www.openstreetmap.org/copyright"
target="_blank">ODbL</a> license.
</p>
</div>
</div>
<!-- HTML button to control flying in non-VR mode -->
<button id="flapButton" class="ontop">Flap</button>
<button id="menuButton" class="ontop" onclick="toggleMenu(); return false;">Menu</button>
<a-scene>
<a-assets>
</a-assets>
<!-- The rig contains the camera and can move around -->
<a-entity id="rig" position="0 0 0" rotation="0 0 0" movement-controls="speed: 1; fly: true; camera: #head;">
<!-- Camera position and rotation in the rig get overwritten by the actual VR head-set, starting at default height 1.6m -->
<a-entity id="head" camera look-controls wasd-controls="fly: true" birdman log2hud="target: chud" position="0 1.6 0">
<!-- "Head up displays" to show live data for camera and left/right hand controller -->
<a-entity id="lhud" position="0.5 0 -2" scale="2 2 1"></a-entity>
<a-entity id="chud" position="1 0.5 -2" scale="2 2 1"></a-entity>
<a-entity id="rhud" position="1.5 0 -2" scale="2 2 1"></a-entity>
</a-entity>
<!-- The actual left and right hand controllers -->
<a-entity id="leftHand" laser-controls="hand: left" wing log2hud="target: lhud" raycaster="objects: .collidable;"></a-entity>
<a-entity id="rightHand" laser-controls="hand: right" wing log2hud="target: rhud" raycaster="objects: .collidable;"></a-entity>
</a-entity>
<a-entity osm-tiles="lat: 52.52; lon: 13.41; trackId: head" rotation="-90 0 0" shadow="receive: true"></a-entity>
<a-entity osm-geojson="lat: 52.52; lon: 13.41; radius_m: 500; trackId: head"></a-entity>
</a-scene>
<!-- Some javascript to interact with the scene and its contents -->
<script>
const rig = document.getElementById('rig');
const head = document.getElementById('head');
const VAXIS = new THREE.Vector3(0, 1, 0);
document.getElementById("flapButton").addEventListener('click', e => {
rig.object3D.position.y += 5;
head.components.birdman.dir.z = -0.1;
head.components.birdman.dir.applyAxisAngle(VAXIS, head.object3D.rotation.y);
});
// adapted from https://stackoverflow.com/a/53009978/2437664
// let's the user take off and glide into the view direction
window.addEventListener('wheel', event => {
const delta = event.deltaY;
rig.object3D.position.y += 1;
head.components.birdman.dir.z = Math.sign(delta);
head.components.birdman.dir.applyAxisAngle(VAXIS, head.object3D.rotation.y);
});
// if url contains lat,lon parameters, load that position, e.g. https://ctrlw.github.io/osm4vr/?lat=52.5163&lon=13.3783
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('lat') && urlParams.has('lon')) {
document.getElementById('latitude').value = urlParams.get('lat');
document.getElementById('longitude').value = urlParams.get('lon');
loadLocation();
}
function toggleMenu() {
let style = document.getElementById('info').style;
style.display = style.display == 'none' ? 'block' : 'none';
}
// switch to the location in the coordinate input fields, hide the forms
function loadLocation() {
const lat = document.getElementById('latitude').value;
const lon = document.getElementById('longitude').value;
console.log('loadLocation', lat, lon);
// set user position to origin
document.getElementById('rig').object3D.position.set(0, 0, 0);
document.getElementById('head').object3D.position.set(0, 0, 0);
let tiles = document.querySelector('a-entity[osm-tiles]');
tiles.setAttribute('osm-tiles', `lat: ${lat}; lon: ${lon}`);
let buildings = document.querySelector('a-entity[osm-geojson]');
buildings.setAttribute('osm-geojson', `lat: ${lat}; lon: ${lon}`);
// hide the info element
document.getElementById('info').style.display = 'none';
}
// query OSM's nominatim API with the search query input and update the coordinate input fields
function searchLocation() {
const search = document.getElementById('searchInput').value;
fetch(`https://nominatim.openstreetmap.org/search?q=${search}&format=json`)
.then(response => response.json())
.then(data => {
if (data.length > 0) {
document.getElementById('latitude').value = parseFloat(data[0].lat).toFixed(5);
document.getElementById('longitude').value = parseFloat(data[0].lon).toFixed(5);
}
});
}
</script>
</body>
</html>