locar 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/dist/locar.es.js +284 -155
- package/dist/locar.umd.js +3 -3
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Location-based AR from AR.js.
|
|
|
4
4
|
|
|
5
5
|
## What is this?
|
|
6
6
|
|
|
7
|
-
LocAR.js is an AR.js project to develop a library focused specifically on location-based augmented reality in the browser. Currently it consists of the location-based three.js code from [the main AR.js repository](https://github.com/AR-js-org/AR.js), with some minor changes to make it compatible with latest versions (0.
|
|
7
|
+
LocAR.js is an AR.js project to develop a library focused specifically on location-based augmented reality in the browser. Currently it consists of the location-based three.js code from [the main AR.js repository](https://github.com/AR-js-org/AR.js), with some minor changes to make it compatible with latest versions (0.175.0 at time of writing) of three.js.
|
|
8
8
|
|
|
9
9
|
## Why?
|
|
10
10
|
|
|
@@ -20,8 +20,6 @@ For a while there have been some bugs and issues with location-based AR.js which
|
|
|
20
20
|
|
|
21
21
|
Some of these issues, such as incorrect North on some devices, may well be to do with incorrect or mis-calibrated sensors but the hope is that the standalone library will help to verify this and, if certain devices have North wrong by a consistent bearing, to develop a calibration tool.
|
|
22
22
|
|
|
23
|
-
For this reason, the focus at present will be on developing a **pure three.js version only**. When we believe that the key bugs and issues have been resolved, the plan is to then provide an A-Frame wrapper.
|
|
24
|
-
|
|
25
23
|
## Cross-platform Compatibility
|
|
26
24
|
|
|
27
25
|
Chrome on Android is recommended. It may also work on Chrome in iOS; please file an issue if not. It will not work on Safari on iOS, due to permissions issues - **though pull requests are welcome to fix this**. Firefox unfortunately does not appear to fully implement the Device Orientation API so is unlikely to work
|
|
@@ -42,8 +40,8 @@ import * as LocAR from 'locar';
|
|
|
42
40
|
as long as you include `locar` as a dependency, e.g. in your `package.json`:
|
|
43
41
|
```
|
|
44
42
|
"dependencies": {
|
|
45
|
-
"locar" : "^0.0.
|
|
46
|
-
"three" : "^0.
|
|
43
|
+
"locar" : "^0.0.10",
|
|
44
|
+
"three" : "^0.175.0"
|
|
47
45
|
}
|
|
48
46
|
```
|
|
49
47
|
|
package/dist/locar.es.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
var
|
|
2
|
-
throw TypeError(
|
|
1
|
+
var W = (i) => {
|
|
2
|
+
throw TypeError(i);
|
|
3
3
|
};
|
|
4
|
-
var S = (
|
|
5
|
-
var
|
|
6
|
-
var
|
|
4
|
+
var S = (i, t, e) => t.has(i) || W("Cannot " + e);
|
|
5
|
+
var s = (i, t, e) => (S(i, t, "read from private field"), e ? e.call(i) : t.get(i)), m = (i, t, e) => t.has(i) ? W("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(i) : t.set(i, e), u = (i, t, e, n) => (S(i, t, "write to private field"), n ? n.call(i, e) : t.set(i, e), e), f = (i, t, e) => (S(i, t, "access private method"), e);
|
|
6
|
+
var k = (i, t, e, n) => ({
|
|
7
7
|
set _(r) {
|
|
8
|
-
u(
|
|
8
|
+
u(i, t, r, e);
|
|
9
9
|
},
|
|
10
10
|
get _() {
|
|
11
|
-
return
|
|
11
|
+
return s(i, t, n);
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
|
-
import * as
|
|
15
|
-
import { Vector3 as
|
|
16
|
-
var E,
|
|
17
|
-
class
|
|
14
|
+
import * as L from "three";
|
|
15
|
+
import { Vector3 as Y, Euler as U, Quaternion as _, EventDispatcher as Z, MathUtils as C } from "three";
|
|
16
|
+
var E, N, z, V, X;
|
|
17
|
+
class $ {
|
|
18
18
|
/**
|
|
19
19
|
* Create a SphMercProjection.
|
|
20
20
|
*/
|
|
@@ -29,7 +29,7 @@ class K {
|
|
|
29
29
|
* @return {Array} Two-member array containing easting and northing.
|
|
30
30
|
*/
|
|
31
31
|
project(t, e) {
|
|
32
|
-
return [
|
|
32
|
+
return [f(this, E, N).call(this, t), f(this, E, z).call(this, e)];
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Unproject a Spherical Mercator easting and northing.
|
|
@@ -37,7 +37,7 @@ class K {
|
|
|
37
37
|
* @return {Array} Two-member array containing longitude and latitude
|
|
38
38
|
*/
|
|
39
39
|
unproject(t) {
|
|
40
|
-
return [
|
|
40
|
+
return [f(this, E, V).call(this, t[0]), f(this, E, X).call(this, t[1])];
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Return the projection's ID.
|
|
@@ -47,19 +47,19 @@ class K {
|
|
|
47
47
|
return "epsg:3857";
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
E = new WeakSet(),
|
|
50
|
+
E = new WeakSet(), N = function(t) {
|
|
51
51
|
return t / 180 * this.HALF_EARTH;
|
|
52
|
-
},
|
|
52
|
+
}, z = function(t) {
|
|
53
53
|
var e = Math.log(Math.tan((90 + t) * Math.PI / 360)) / (Math.PI / 180);
|
|
54
54
|
return e * this.HALF_EARTH / 180;
|
|
55
|
-
},
|
|
55
|
+
}, V = function(t) {
|
|
56
56
|
return t / this.HALF_EARTH * 180;
|
|
57
|
-
},
|
|
57
|
+
}, X = function(t) {
|
|
58
58
|
var e = t / this.HALF_EARTH * 180;
|
|
59
59
|
return e = 180 / Math.PI * (2 * Math.atan(Math.exp(e * Math.PI / 180)) - Math.PI / 2), e;
|
|
60
60
|
};
|
|
61
|
-
var
|
|
62
|
-
class
|
|
61
|
+
var D, A, b, H, R, P, M, T, O, w, p, j, Q, F, B;
|
|
62
|
+
class K {
|
|
63
63
|
/**
|
|
64
64
|
* @param {THREE.Scene} scene - The Three.js scene to use.
|
|
65
65
|
* @param {THREE.Camera} camera - The Three.js camera to use. Should usually
|
|
@@ -68,19 +68,19 @@ class st {
|
|
|
68
68
|
* setGpsOptions() below.
|
|
69
69
|
* @param {Object} serverLogger - an object which can optionally log GPS position to a server for debugging. null by default, so no logging will be done. This object should implement a sendData() method to send data (2nd arg) to a given endpoint (1st arg). Please see source code for details. Ensure you comply with privacy laws (GDPR or equivalent) if implementing this.
|
|
70
70
|
*/
|
|
71
|
-
constructor(t, e,
|
|
72
|
-
m(this,
|
|
73
|
-
m(this,
|
|
74
|
-
m(this, O);
|
|
75
|
-
m(this, P);
|
|
76
|
-
m(this, x);
|
|
77
|
-
m(this, L);
|
|
71
|
+
constructor(t, e, n = {}, r = null) {
|
|
72
|
+
m(this, p);
|
|
73
|
+
m(this, D);
|
|
78
74
|
m(this, A);
|
|
79
|
-
m(this, y);
|
|
80
75
|
m(this, b);
|
|
81
|
-
m(this,
|
|
76
|
+
m(this, H);
|
|
77
|
+
m(this, R);
|
|
78
|
+
m(this, P);
|
|
82
79
|
m(this, M);
|
|
83
|
-
|
|
80
|
+
m(this, T);
|
|
81
|
+
m(this, O);
|
|
82
|
+
m(this, w);
|
|
83
|
+
this.scene = t, this.camera = e, u(this, D, new $()), u(this, A, {}), u(this, b, null), u(this, H, 0), u(this, R, 100), u(this, P, null), this.setGpsOptions(n), u(this, M, null), u(this, T, 0), u(this, O, 0), u(this, w, r);
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Set the projection to use.
|
|
@@ -89,7 +89,7 @@ class st {
|
|
|
89
89
|
* containing easting and northing.
|
|
90
90
|
*/
|
|
91
91
|
setProjection(t) {
|
|
92
|
-
u(this,
|
|
92
|
+
u(this, D, t);
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
95
|
* Set the GPS options.
|
|
@@ -99,7 +99,7 @@ class st {
|
|
|
99
99
|
* minimum accuracy, in metres, for a GPS reading to be counted.
|
|
100
100
|
*/
|
|
101
101
|
setGpsOptions(t = {}) {
|
|
102
|
-
t.gpsMinDistance !== void 0 && u(this,
|
|
102
|
+
t.gpsMinDistance !== void 0 && u(this, H, t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && u(this, R, t.gpsMinAccuracy);
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
105
|
* Start the GPS on a real device
|
|
@@ -107,19 +107,19 @@ class st {
|
|
|
107
107
|
* GPS errors can be handled by handling the gpserror event.
|
|
108
108
|
*/
|
|
109
109
|
async startGps() {
|
|
110
|
-
if (
|
|
111
|
-
const e = await (await
|
|
112
|
-
gpsMinDistance:
|
|
113
|
-
gpsMinAccuracy:
|
|
110
|
+
if (s(this, w)) {
|
|
111
|
+
const e = await (await s(this, w).sendData("/gps/start", {
|
|
112
|
+
gpsMinDistance: s(this, H),
|
|
113
|
+
gpsMinAccuracy: s(this, R)
|
|
114
114
|
})).json();
|
|
115
|
-
u(this,
|
|
115
|
+
u(this, O, e.session);
|
|
116
116
|
}
|
|
117
|
-
return
|
|
117
|
+
return s(this, P) === null ? (u(this, P, navigator.geolocation.watchPosition(
|
|
118
118
|
(t) => {
|
|
119
|
-
|
|
119
|
+
f(this, p, F).call(this, t);
|
|
120
120
|
},
|
|
121
121
|
(t) => {
|
|
122
|
-
|
|
122
|
+
s(this, A).gpserror ? s(this, A).gpserror(t.code) : alert(`GPS error: code ${t.code}`);
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
enableHighAccuracy: !0
|
|
@@ -132,7 +132,7 @@ class st {
|
|
|
132
132
|
* stopped (i.e. it was never started).
|
|
133
133
|
*/
|
|
134
134
|
stopGps() {
|
|
135
|
-
return
|
|
135
|
+
return s(this, P) !== null ? (navigator.geolocation.clearWatch(s(this, P)), u(this, P, null), !0) : !1;
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Send a fake GPS signal. Useful for testing on a desktop or laptop.
|
|
@@ -143,8 +143,8 @@ class st {
|
|
|
143
143
|
* @param {number} acc - The accuracy of the GPS reading in metres. May be
|
|
144
144
|
* ignored if lower than the specified minimum accuracy.
|
|
145
145
|
*/
|
|
146
|
-
fakeGps(t, e,
|
|
147
|
-
|
|
146
|
+
fakeGps(t, e, n = null, r = 0) {
|
|
147
|
+
n !== null && this.setElevation(n), f(this, p, F).call(this, {
|
|
148
148
|
coords: {
|
|
149
149
|
longitude: t,
|
|
150
150
|
latitude: e,
|
|
@@ -163,12 +163,12 @@ class st {
|
|
|
163
163
|
* @return {Array} a two member array containing the WebGL x and z coordinates
|
|
164
164
|
*/
|
|
165
165
|
lonLatToWorldCoords(t, e) {
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
168
|
-
|
|
166
|
+
const n = s(this, D).project(t, e);
|
|
167
|
+
if (s(this, M))
|
|
168
|
+
n[0] -= s(this, M)[0], n[1] -= s(this, M)[1];
|
|
169
169
|
else
|
|
170
170
|
throw "No initial position determined";
|
|
171
|
-
return [
|
|
171
|
+
return [n[0], -n[1]];
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
174
|
* Add a new AR object at a given latitude, longitude and elevation.
|
|
@@ -180,13 +180,13 @@ class st {
|
|
|
180
180
|
* @param {Object} properties - properties describing the object (for example,
|
|
181
181
|
* the contents of the GeoJSON properties field).
|
|
182
182
|
*/
|
|
183
|
-
add(t, e,
|
|
183
|
+
add(t, e, n, r, d = {}) {
|
|
184
184
|
var g;
|
|
185
|
-
t.properties = d,
|
|
185
|
+
t.properties = d, f(this, p, j).call(this, t, e, n, r), this.scene.add(t), (g = s(this, w)) == null || g.sendData("/object/new", {
|
|
186
186
|
position: t.position,
|
|
187
187
|
x: t.position.x,
|
|
188
188
|
z: t.position.z,
|
|
189
|
-
session:
|
|
189
|
+
session: s(this, O),
|
|
190
190
|
properties: d
|
|
191
191
|
});
|
|
192
192
|
}
|
|
@@ -211,54 +211,55 @@ class st {
|
|
|
211
211
|
* @listens LocationBased#gpserror
|
|
212
212
|
*/
|
|
213
213
|
on(t, e) {
|
|
214
|
-
|
|
214
|
+
s(this, A)[t] = e;
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
|
-
|
|
218
|
-
const d = this.lonLatToWorldCoords(e,
|
|
217
|
+
D = new WeakMap(), A = new WeakMap(), b = new WeakMap(), H = new WeakMap(), R = new WeakMap(), P = new WeakMap(), M = new WeakMap(), T = new WeakMap(), O = new WeakMap(), w = new WeakMap(), p = new WeakSet(), j = function(t, e, n, r) {
|
|
218
|
+
const d = this.lonLatToWorldCoords(e, n);
|
|
219
219
|
r !== void 0 && (t.position.y = r), [t.position.x, t.position.z] = d;
|
|
220
|
-
},
|
|
221
|
-
u(this,
|
|
222
|
-
},
|
|
223
|
-
var
|
|
220
|
+
}, Q = function(t, e) {
|
|
221
|
+
u(this, M, s(this, D).project(t, e));
|
|
222
|
+
}, F = function(t) {
|
|
223
|
+
var n, r, d;
|
|
224
224
|
let e = Number.MAX_VALUE;
|
|
225
|
-
|
|
226
|
-
gpsCount:
|
|
225
|
+
k(this, T)._++, (n = s(this, w)) == null || n.sendData("/gps/new", {
|
|
226
|
+
gpsCount: s(this, T),
|
|
227
227
|
lat: t.coords.latitude,
|
|
228
228
|
lon: t.coords.longitude,
|
|
229
229
|
acc: t.coords.accuracy,
|
|
230
|
-
session:
|
|
231
|
-
}), t.coords.accuracy <=
|
|
230
|
+
session: s(this, O)
|
|
231
|
+
}), t.coords.accuracy <= s(this, R) && (s(this, b) === null ? u(this, b, {
|
|
232
232
|
latitude: t.coords.latitude,
|
|
233
233
|
longitude: t.coords.longitude
|
|
234
|
-
}) : e =
|
|
235
|
-
gpsCount:
|
|
234
|
+
}) : e = f(this, p, B).call(this, s(this, b), t.coords), e >= s(this, H) && (s(this, b).longitude = t.coords.longitude, s(this, b).latitude = t.coords.latitude, s(this, M) || (f(this, p, Q).call(this, t.coords.longitude, t.coords.latitude), (r = s(this, w)) == null || r.sendData("/worldorigin/new", {
|
|
235
|
+
gpsCount: s(this, T),
|
|
236
236
|
lat: t.coords.latitude,
|
|
237
237
|
lon: t.coords.longitude,
|
|
238
|
-
session:
|
|
239
|
-
initialPosition:
|
|
240
|
-
})),
|
|
241
|
-
gpsCount:
|
|
238
|
+
session: s(this, O),
|
|
239
|
+
initialPosition: s(this, M)
|
|
240
|
+
})), f(this, p, j).call(this, this.camera, t.coords.longitude, t.coords.latitude), (d = s(this, w)) == null || d.sendData("/gps/accepted", {
|
|
241
|
+
gpsCount: s(this, T),
|
|
242
242
|
cameraX: this.camera.position.x,
|
|
243
243
|
cameraZ: this.camera.position.z,
|
|
244
|
-
session:
|
|
244
|
+
session: s(this, O),
|
|
245
245
|
distMoved: e
|
|
246
|
-
}),
|
|
246
|
+
}), s(this, A).gpsupdate && s(this, A).gpsupdate(t, e)));
|
|
247
247
|
}, /**
|
|
248
248
|
* Calculate haversine distance between two lat/lon pairs.
|
|
249
249
|
*
|
|
250
250
|
* Taken from original A-Frame AR.js location-based components
|
|
251
251
|
*/
|
|
252
|
-
|
|
253
|
-
const
|
|
252
|
+
B = function(t, e) {
|
|
253
|
+
const n = L.MathUtils.degToRad(e.longitude - t.longitude), r = L.MathUtils.degToRad(e.latitude - t.latitude), d = Math.sin(r / 2) * Math.sin(r / 2) + Math.cos(L.MathUtils.degToRad(t.latitude)) * Math.cos(L.MathUtils.degToRad(e.latitude)) * (Math.sin(n / 2) * Math.sin(n / 2));
|
|
254
254
|
return 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1 - d)) * 6371e3;
|
|
255
255
|
};
|
|
256
|
-
class
|
|
256
|
+
class J {
|
|
257
257
|
/**
|
|
258
258
|
* Create a Webcam.
|
|
259
|
-
* @options {Object} - options to use for initialising the camera.
|
|
260
|
-
*
|
|
261
|
-
* a *required* callback which runs when the camera has
|
|
259
|
+
* @param options {Object} - options to use for initialising the camera.
|
|
260
|
+
* Currently idealWidth and idealHeight properties are understood as well as
|
|
261
|
+
* onVideoStarted(), a *required* callback which runs when the camera has
|
|
262
|
+
* been initialised.
|
|
262
263
|
* This takes a THREE.VideoTexture as an argument which can be used to set
|
|
263
264
|
* the background of your three.js scene within a callback.
|
|
264
265
|
* @param {string} videoElementSelector - selector to obtain the HTML video
|
|
@@ -266,21 +267,21 @@ class ot {
|
|
|
266
267
|
* undefined), a video element will be created.
|
|
267
268
|
*/
|
|
268
269
|
constructor(t = {}, e) {
|
|
269
|
-
this.sceneWebcam = new
|
|
270
|
-
let
|
|
271
|
-
if (e ?
|
|
270
|
+
this.sceneWebcam = new L.Scene();
|
|
271
|
+
let n;
|
|
272
|
+
if (e ? n = document.querySelector(e) : (n = document.createElement("video"), n.setAttribute("autoplay", !0), n.setAttribute("playsinline", !0), n.style.display = "none", document.body.appendChild(n)), this.texture = new L.VideoTexture(n), navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
272
273
|
const r = {
|
|
273
274
|
video: {
|
|
274
|
-
width: { ideal: t.
|
|
275
|
-
height: { ideal: t.
|
|
275
|
+
width: { ideal: t.idealWidth || 1280 },
|
|
276
|
+
height: { ideal: t.idealHeight || 720 },
|
|
276
277
|
facingMode: "environment"
|
|
277
278
|
}
|
|
278
279
|
};
|
|
279
280
|
navigator.mediaDevices.getUserMedia(r).then((d) => {
|
|
280
|
-
|
|
281
|
+
n.addEventListener("loadedmetadata", () => {
|
|
281
282
|
var g;
|
|
282
|
-
|
|
283
|
-
}),
|
|
283
|
+
n.setAttribute("width", n.videoWidth), n.setAttribute("height", n.videoHeight), n.play(), (g = t.onVideoStarted) == null || g.call(this, this.texture);
|
|
284
|
+
}), n.srcObject = d;
|
|
284
285
|
}).catch((d) => {
|
|
285
286
|
setTimeout(() => {
|
|
286
287
|
alert(
|
|
@@ -303,8 +304,8 @@ Message: ` + d.message
|
|
|
303
304
|
this.texture.dispose();
|
|
304
305
|
}
|
|
305
306
|
}
|
|
306
|
-
const
|
|
307
|
-
class
|
|
307
|
+
const q = navigator.userAgent.match(/iPhone|iPad|iPod/i) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1, tt = new Y(0, 0, 1), G = new U(), et = new _(), it = new _(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)), nt = { type: "change" };
|
|
308
|
+
class st extends Z {
|
|
308
309
|
/**
|
|
309
310
|
* Create an instance of DeviceOrientationControls.
|
|
310
311
|
* @param {Object} object - the object to attach the controls to
|
|
@@ -314,19 +315,19 @@ class at extends B {
|
|
|
314
315
|
super(), window.isSecureContext === !1 && console.error(
|
|
315
316
|
"THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)"
|
|
316
317
|
);
|
|
317
|
-
const e = this,
|
|
318
|
+
const e = this, n = 1e-6, r = new _();
|
|
318
319
|
this.object = t, this.object.rotation.reorder("YXZ"), this.enabled = !0, this.deviceOrientation = null, this.screenOrientation = 0, this.alphaOffset = 0, this.initialOffset = null, this.TWO_PI = 2 * Math.PI, this.HALF_PI = 0.5 * Math.PI, this.orientationChangeEventName = "ondeviceorientationabsolute" in window ? "deviceorientationabsolute" : "deviceorientation", this.smoothingFactor = 1;
|
|
319
320
|
const d = function({
|
|
320
|
-
alpha:
|
|
321
|
+
alpha: o,
|
|
321
322
|
beta: c,
|
|
322
|
-
gamma:
|
|
323
|
-
webkitCompassHeading:
|
|
323
|
+
gamma: l,
|
|
324
|
+
webkitCompassHeading: a
|
|
324
325
|
}) {
|
|
325
|
-
if (
|
|
326
|
-
const
|
|
327
|
-
e.alphaOffset = C.degToRad(
|
|
326
|
+
if (q) {
|
|
327
|
+
const h = 360 - a;
|
|
328
|
+
e.alphaOffset = C.degToRad(h - o), e.deviceOrientation = { alpha: o, beta: c, gamma: l, webkitCompassHeading: a };
|
|
328
329
|
} else
|
|
329
|
-
|
|
330
|
+
o < 0 && (o += 360), e.deviceOrientation = { alpha: o, beta: c, gamma: l };
|
|
330
331
|
window.dispatchEvent(
|
|
331
332
|
new CustomEvent("camera-rotation-change", {
|
|
332
333
|
detail: { cameraRotation: t.rotation }
|
|
@@ -334,22 +335,22 @@ class at extends B {
|
|
|
334
335
|
);
|
|
335
336
|
}, g = function() {
|
|
336
337
|
e.screenOrientation = window.orientation || 0;
|
|
337
|
-
},
|
|
338
|
-
|
|
338
|
+
}, x = function(o, c, l, a, h) {
|
|
339
|
+
G.set(l, c, -a, "YXZ"), o.setFromEuler(G), o.multiply(it), o.multiply(et.setFromAxisAngle(tt, -h));
|
|
339
340
|
};
|
|
340
341
|
this.connect = function() {
|
|
341
|
-
g(), window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((
|
|
342
|
-
|
|
342
|
+
g(), window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((o) => {
|
|
343
|
+
o === "granted" && (window.addEventListener(
|
|
343
344
|
"orientationchange",
|
|
344
345
|
g
|
|
345
346
|
), window.addEventListener(
|
|
346
347
|
e.orientationChangeEventName,
|
|
347
348
|
d
|
|
348
349
|
));
|
|
349
|
-
}).catch(function(
|
|
350
|
+
}).catch(function(o) {
|
|
350
351
|
console.error(
|
|
351
352
|
"THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",
|
|
352
|
-
|
|
353
|
+
o
|
|
353
354
|
);
|
|
354
355
|
}) : (window.addEventListener(
|
|
355
356
|
"orientationchange",
|
|
@@ -366,82 +367,82 @@ class at extends B {
|
|
|
366
367
|
e.orientationChangeEventName,
|
|
367
368
|
d
|
|
368
369
|
), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
|
|
369
|
-
}, this.update = function({ theta:
|
|
370
|
+
}, this.update = function({ theta: o = 0 } = { theta: 0 }) {
|
|
370
371
|
if (e.enabled === !1) return;
|
|
371
372
|
const c = e.deviceOrientation;
|
|
372
373
|
if (c) {
|
|
373
|
-
let
|
|
374
|
-
const
|
|
375
|
-
if (
|
|
374
|
+
let l = c.alpha ? C.degToRad(c.alpha) + e.alphaOffset : 0, a = c.beta ? C.degToRad(c.beta) : 0, h = c.gamma ? C.degToRad(c.gamma) : 0;
|
|
375
|
+
const I = e.screenOrientation ? C.degToRad(e.screenOrientation) : 0;
|
|
376
|
+
if (q) {
|
|
376
377
|
const v = new _();
|
|
377
|
-
|
|
378
|
-
const
|
|
378
|
+
x(v, l, a, h, I);
|
|
379
|
+
const y = new U().setFromQuaternion(
|
|
379
380
|
v,
|
|
380
381
|
"YXZ"
|
|
381
382
|
);
|
|
382
|
-
console.log(
|
|
383
|
+
console.log(y.x, y.y, y.z), y.y = C.degToRad(
|
|
383
384
|
360 - c.webkitCompassHeading
|
|
384
|
-
), v.setFromEuler(
|
|
385
|
+
), v.setFromEuler(y), e.object.quaternion.copy(v);
|
|
385
386
|
} else {
|
|
386
387
|
if (this.smoothingFactor < 1) {
|
|
387
388
|
if (this.lastOrientation) {
|
|
388
389
|
const v = this.smoothingFactor;
|
|
389
|
-
|
|
390
|
-
|
|
390
|
+
l = this._getSmoothedAngle(
|
|
391
|
+
l,
|
|
391
392
|
this.lastOrientation.alpha,
|
|
392
393
|
v
|
|
393
|
-
),
|
|
394
|
-
|
|
394
|
+
), a = this._getSmoothedAngle(
|
|
395
|
+
a + Math.PI,
|
|
395
396
|
this.lastOrientation.beta,
|
|
396
397
|
v
|
|
397
|
-
),
|
|
398
|
-
|
|
398
|
+
), h = this._getSmoothedAngle(
|
|
399
|
+
h + this.HALF_PI,
|
|
399
400
|
this.lastOrientation.gamma,
|
|
400
401
|
v,
|
|
401
402
|
Math.PI
|
|
402
403
|
);
|
|
403
404
|
} else
|
|
404
|
-
|
|
405
|
+
a += Math.PI, h += this.HALF_PI;
|
|
405
406
|
this.lastOrientation = {
|
|
406
|
-
alpha:
|
|
407
|
-
beta:
|
|
408
|
-
gamma:
|
|
407
|
+
alpha: l,
|
|
408
|
+
beta: a,
|
|
409
|
+
gamma: h
|
|
409
410
|
};
|
|
410
411
|
}
|
|
411
|
-
|
|
412
|
+
x(
|
|
412
413
|
e.object.quaternion,
|
|
413
|
-
|
|
414
|
-
this.smoothingFactor < 1 ?
|
|
415
|
-
this.smoothingFactor < 1 ?
|
|
416
|
-
|
|
414
|
+
l + o,
|
|
415
|
+
this.smoothingFactor < 1 ? a - Math.PI : a,
|
|
416
|
+
this.smoothingFactor < 1 ? h - this.HALF_PI : h,
|
|
417
|
+
I
|
|
417
418
|
);
|
|
418
419
|
}
|
|
419
|
-
8 * (1 - r.dot(e.object.quaternion)) >
|
|
420
|
+
8 * (1 - r.dot(e.object.quaternion)) > n && (r.copy(e.object.quaternion), e.dispatchEvent(nt));
|
|
420
421
|
}
|
|
421
|
-
}, this._orderAngle = function(
|
|
422
|
-
return c >
|
|
423
|
-
}, this._getSmoothedAngle = function(
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
let
|
|
427
|
-
return
|
|
422
|
+
}, this._orderAngle = function(o, c, l = this.TWO_PI) {
|
|
423
|
+
return c > o && Math.abs(c - o) < l / 2 || o > c && Math.abs(c - o) > l / 2 ? { left: o, right: c } : { left: c, right: o };
|
|
424
|
+
}, this._getSmoothedAngle = function(o, c, l, a = this.TWO_PI) {
|
|
425
|
+
const h = this._orderAngle(o, c, a), I = h.left, v = h.right;
|
|
426
|
+
h.left = 0, h.right -= I, h.right < 0 && (h.right += a);
|
|
427
|
+
let y = v == c ? (1 - l) * h.right + l * h.left : l * h.right + (1 - l) * h.left;
|
|
428
|
+
return y += I, y >= a && (y -= a), y;
|
|
428
429
|
}, this.updateAlphaOffset = function() {
|
|
429
430
|
e.initialOffset = !1;
|
|
430
431
|
}, this.dispose = function() {
|
|
431
432
|
e.disconnect();
|
|
432
433
|
}, this.getAlpha = function() {
|
|
433
|
-
const { deviceOrientation:
|
|
434
|
-
return
|
|
434
|
+
const { deviceOrientation: o } = e;
|
|
435
|
+
return o && o.alpha ? C.degToRad(o.alpha) + e.alphaOffset : 0;
|
|
435
436
|
}, this.getBeta = function() {
|
|
436
|
-
const { deviceOrientation:
|
|
437
|
-
return
|
|
437
|
+
const { deviceOrientation: o } = e;
|
|
438
|
+
return o && o.beta ? C.degToRad(o.beta) : 0;
|
|
438
439
|
}, window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? this.initPermissionDialog() : this.connect();
|
|
439
440
|
}
|
|
440
441
|
// Provide gesture before initialising device orientation controls
|
|
441
442
|
// From PR #659 on the main AR.js repo
|
|
442
443
|
// Thanks to @ma2yama
|
|
443
444
|
initPermissionDialog() {
|
|
444
|
-
const t = document.createElement("div"), e = document.createElement("div"),
|
|
445
|
+
const t = document.createElement("div"), e = document.createElement("div"), n = document.createElement("div"), r = document.createElement("div");
|
|
445
446
|
document.body.appendChild(t);
|
|
446
447
|
const d = {
|
|
447
448
|
display: "flex",
|
|
@@ -460,32 +461,32 @@ class at extends B {
|
|
|
460
461
|
borderRadius: "3px",
|
|
461
462
|
width: "36rem",
|
|
462
463
|
height: "24rem"
|
|
463
|
-
},
|
|
464
|
+
}, x = {
|
|
464
465
|
width: "100%",
|
|
465
466
|
height: "70%",
|
|
466
467
|
display: "flex",
|
|
467
468
|
justifyContent: "center",
|
|
468
469
|
alignItems: "center"
|
|
469
|
-
},
|
|
470
|
+
}, o = {
|
|
470
471
|
display: "inline-flex",
|
|
471
472
|
width: "100%",
|
|
472
473
|
height: "30%",
|
|
473
474
|
justifyContent: "center",
|
|
474
475
|
alignItems: "center"
|
|
475
476
|
};
|
|
476
|
-
for (let
|
|
477
|
-
t.style[
|
|
478
|
-
for (let
|
|
479
|
-
e.style[
|
|
480
|
-
for (let
|
|
481
|
-
|
|
482
|
-
for (let
|
|
483
|
-
r.style[
|
|
484
|
-
t.appendChild(e), e.appendChild(
|
|
477
|
+
for (let a in d)
|
|
478
|
+
t.style[a] = d[a];
|
|
479
|
+
for (let a in g)
|
|
480
|
+
e.style[a] = g[a];
|
|
481
|
+
for (let a in x)
|
|
482
|
+
n.style[a] = x[a];
|
|
483
|
+
for (let a in o)
|
|
484
|
+
r.style[a] = o[a];
|
|
485
|
+
t.appendChild(e), e.appendChild(n), e.appendChild(r), n.innerHTML = '<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';
|
|
485
486
|
const c = () => {
|
|
486
487
|
this.connect(), t.style.display = "none";
|
|
487
|
-
},
|
|
488
|
-
|
|
488
|
+
}, l = document.createElement("button");
|
|
489
|
+
l.addEventListener("click", c), l.style.width = "50%", l.style.height = "80%", l.style.fontSize = "20pt", l.appendChild(document.createTextNode("OK")), r.appendChild(l), document.body.appendChild(t);
|
|
489
490
|
}
|
|
490
491
|
}
|
|
491
492
|
class rt {
|
|
@@ -495,7 +496,7 @@ class rt {
|
|
|
495
496
|
* events will be handled.
|
|
496
497
|
*/
|
|
497
498
|
constructor(t) {
|
|
498
|
-
this.raycaster = new
|
|
499
|
+
this.raycaster = new L.Raycaster(), this.normalisedMousePosition = new L.Vector2(null, null), t.domElement.addEventListener("click", (e) => {
|
|
499
500
|
this.normalisedMousePosition.set(
|
|
500
501
|
e.clientX / t.domElement.clientWidth * 2 - 1,
|
|
501
502
|
-(e.clientY / t.domElement.clientHeight * 2) + 1
|
|
@@ -513,18 +514,146 @@ class rt {
|
|
|
513
514
|
raycast(t, e) {
|
|
514
515
|
if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
|
|
515
516
|
this.raycaster.setFromCamera(this.normalisedMousePosition, t);
|
|
516
|
-
const
|
|
517
|
-
return this.normalisedMousePosition.set(null, null),
|
|
517
|
+
const n = this.raycaster.intersectObjects(e.children, !1);
|
|
518
|
+
return this.normalisedMousePosition.set(null, null), n;
|
|
518
519
|
}
|
|
519
520
|
return [];
|
|
520
521
|
}
|
|
521
522
|
}
|
|
522
|
-
|
|
523
|
+
AFRAME.registerComponent("locar-webcam", {
|
|
524
|
+
schema: {
|
|
525
|
+
idealWidth: {
|
|
526
|
+
type: "number",
|
|
527
|
+
default: 1024
|
|
528
|
+
},
|
|
529
|
+
idealHeight: {
|
|
530
|
+
type: "number",
|
|
531
|
+
default: 768
|
|
532
|
+
},
|
|
533
|
+
videoElement: {
|
|
534
|
+
type: "string",
|
|
535
|
+
default: ""
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
init: function() {
|
|
539
|
+
new J({
|
|
540
|
+
idealWidth: this.data.idealWidth,
|
|
541
|
+
idealHeight: this.data.idealHeight,
|
|
542
|
+
onVideoStarted: (i) => {
|
|
543
|
+
this.el.object3D.background = i;
|
|
544
|
+
}
|
|
545
|
+
}, this.data.videoElement || null);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
AFRAME.registerComponent("locar-camera", {
|
|
549
|
+
schema: {
|
|
550
|
+
simulateLatitude: {
|
|
551
|
+
type: "number",
|
|
552
|
+
default: 0
|
|
553
|
+
},
|
|
554
|
+
simulateLongitude: {
|
|
555
|
+
type: "number",
|
|
556
|
+
default: 0
|
|
557
|
+
},
|
|
558
|
+
simulateAltitude: {
|
|
559
|
+
type: "number",
|
|
560
|
+
default: -Number.MAX_VALUE
|
|
561
|
+
},
|
|
562
|
+
positionMinAccuracy: {
|
|
563
|
+
type: "number",
|
|
564
|
+
default: 100
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
init: function() {
|
|
568
|
+
this.locar = new K(
|
|
569
|
+
this.el.sceneEl.object3D,
|
|
570
|
+
this.el.object3D
|
|
571
|
+
), this.locar.on("gpsupdate", (i, t) => {
|
|
572
|
+
this.el.emit("gpsupdate", {
|
|
573
|
+
position: i,
|
|
574
|
+
distMoved: t
|
|
575
|
+
});
|
|
576
|
+
}), this.locar.on("gpserror", (i) => {
|
|
577
|
+
const t = [
|
|
578
|
+
"User denied access to GPS.",
|
|
579
|
+
"GPS satellites not available.",
|
|
580
|
+
"Timeout communicating with GPS satellites - try moving to a more open area."
|
|
581
|
+
];
|
|
582
|
+
i >= 1 && i <= 3 ? alert(t[i - 1]) : alert(`Unknown geolocation error code ${i}.`);
|
|
583
|
+
}), this._isMobile() && (this.deviceOrientationControls = new st(this.el.object3D));
|
|
584
|
+
},
|
|
585
|
+
update: function(i) {
|
|
586
|
+
this.locar.setGpsOptions({
|
|
587
|
+
gpsMinAccuracy: this.data.positionMinAccuracy,
|
|
588
|
+
gpsMinDistance: this.data.gpsMinDistance
|
|
589
|
+
}), (this.data.simulateLatitude !== 0 || this.data.simulateLongitude !== 0) && (this.data.simulateLatitude != (i == null ? void 0 : i.simulateLatitude) || this.data.simulateLongitude != (i == null ? void 0 : i.simulateLongitude)) && (this.locar.stopGps(), this.locar.fakeGps(
|
|
590
|
+
this.data.simulateLongitude,
|
|
591
|
+
this.data.simulateLatitude
|
|
592
|
+
), this.data.simulateLongitude = 0, this.data.simulateLatitude = 0), this.data.simulateAltitude > -Number.MAX_VALUE && this.locar.setElevation(this.data.simulateAltitude + 1.6);
|
|
593
|
+
},
|
|
594
|
+
play: function() {
|
|
595
|
+
this.locar.startGps();
|
|
596
|
+
},
|
|
597
|
+
pause: function() {
|
|
598
|
+
this.locar.stopGps();
|
|
599
|
+
},
|
|
600
|
+
/**
|
|
601
|
+
* Convert longitude and latitude to three.js/WebGL world coordinates.
|
|
602
|
+
* Uses the specified projection, and negates the northing (in typical
|
|
603
|
+
* projections, northings increase northwards, but in the WebGL coordinate
|
|
604
|
+
* system, we face negative z if the camera is at the origin with default
|
|
605
|
+
* rotation).
|
|
606
|
+
* @param {number} lon - The longitude.
|
|
607
|
+
* @param {number} lat - The latitude.
|
|
608
|
+
* @return {Array} a two member array containing the WebGL x and z coordinates
|
|
609
|
+
*/
|
|
610
|
+
lonLatToWorldCoords: function(i, t) {
|
|
611
|
+
return this.locar.lonLatToWorldCoords(i, t);
|
|
612
|
+
},
|
|
613
|
+
tick: function() {
|
|
614
|
+
var i;
|
|
615
|
+
(i = this.deviceOrientationControls) == null || i.update();
|
|
616
|
+
},
|
|
617
|
+
_isMobile: function() {
|
|
618
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
619
|
+
navigator.userAgent
|
|
620
|
+
) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1;
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
AFRAME.registerComponent("locar-entity-place", {
|
|
624
|
+
schema: {
|
|
625
|
+
latitude: {
|
|
626
|
+
type: "number",
|
|
627
|
+
default: 0
|
|
628
|
+
},
|
|
629
|
+
longitude: {
|
|
630
|
+
type: "number",
|
|
631
|
+
default: 0
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
init: function() {
|
|
635
|
+
const i = this.el.sceneEl.querySelector("[locar-camera]");
|
|
636
|
+
this.locarCamera = i.components["locar-camera"];
|
|
637
|
+
},
|
|
638
|
+
update: function(i) {
|
|
639
|
+
this.locarCamera || console.error("Cannot update locar-entity-place without a locar-camera component on the scene camera.");
|
|
640
|
+
const t = this.locarCamera.lonLatToWorldCoords(
|
|
641
|
+
this.data.longitude,
|
|
642
|
+
this.data.latitude
|
|
643
|
+
);
|
|
644
|
+
this.el.object3D.position.set(
|
|
645
|
+
t[0],
|
|
646
|
+
this.el.object3D.position.y,
|
|
647
|
+
t[1]
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
const ct = "0.0.10";
|
|
523
652
|
export {
|
|
524
653
|
rt as ClickHandler,
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
654
|
+
st as DeviceOrientationControls,
|
|
655
|
+
K as LocationBased,
|
|
656
|
+
$ as SphMercProjection,
|
|
657
|
+
J as Webcam,
|
|
529
658
|
ct as version
|
|
530
659
|
};
|
package/dist/locar.umd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
Name: `+
|
|
3
|
-
Message: `+
|
|
1
|
+
(function(r,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],n):(r=typeof globalThis<"u"?globalThis:r||self,n(r.locar={},r.THREE))})(this,function(r,n){"use strict";var Q=r=>{throw TypeError(r)};var U=(r,n,p)=>n.has(r)||Q("Cannot "+p);var s=(r,n,p)=>(U(r,n,"read from private field"),p?p.call(r):n.get(r)),y=(r,n,p)=>n.has(r)?Q("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(r):n.set(r,p),m=(r,n,p,v)=>(U(r,n,"write to private field"),v?v.call(r,p):n.set(r,p),p),w=(r,n,p)=>(U(r,n,"access private method"),p);var V=(r,n,p,v)=>({set _(W){m(r,n,W,p)},get _(){return s(r,n,v)}});var b,X,B,Y,Z,_,L,E,j,I,D,A,S,T,O,M,k,$,q,K;function p(a){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const e in a)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(a,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>a[e]})}}return t.default=a,Object.freeze(t)}const v=p(n);class W{constructor(){y(this,b);this.EARTH=4007501668e-2,this.HALF_EARTH=2003750834e-2}project(t,e){return[w(this,b,X).call(this,t),w(this,b,B).call(this,e)]}unproject(t){return[w(this,b,Y).call(this,t[0]),w(this,b,Z).call(this,t[1])]}getID(){return"epsg:3857"}}b=new WeakSet,X=function(t){return t/180*this.HALF_EARTH},B=function(t){var e=Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180);return e*this.HALF_EARTH/180},Y=function(t){return t/this.HALF_EARTH*180},Z=function(t){var e=t/this.HALF_EARTH*180;return e=180/Math.PI*(2*Math.atan(Math.exp(e*Math.PI/180))-Math.PI/2),e};class H{constructor(t,e,i={},h=null){y(this,M);y(this,_);y(this,L);y(this,E);y(this,j);y(this,I);y(this,D);y(this,A);y(this,S);y(this,T);y(this,O);this.scene=t,this.camera=e,m(this,_,new W),m(this,L,{}),m(this,E,null),m(this,j,0),m(this,I,100),m(this,D,null),this.setGpsOptions(i),m(this,A,null),m(this,S,0),m(this,T,0),m(this,O,h)}setProjection(t){m(this,_,t)}setGpsOptions(t={}){t.gpsMinDistance!==void 0&&m(this,j,t.gpsMinDistance),t.gpsMinAccuracy!==void 0&&m(this,I,t.gpsMinAccuracy)}async startGps(){if(s(this,O)){const e=await(await s(this,O).sendData("/gps/start",{gpsMinDistance:s(this,j),gpsMinAccuracy:s(this,I)})).json();m(this,T,e.session)}return s(this,D)===null?(m(this,D,navigator.geolocation.watchPosition(t=>{w(this,M,q).call(this,t)},t=>{s(this,L).gpserror?s(this,L).gpserror(t.code):alert(`GPS error: code ${t.code}`)},{enableHighAccuracy:!0})),!0):!1}stopGps(){return s(this,D)!==null?(navigator.geolocation.clearWatch(s(this,D)),m(this,D,null),!0):!1}fakeGps(t,e,i=null,h=0){i!==null&&this.setElevation(i),w(this,M,q).call(this,{coords:{longitude:t,latitude:e,accuracy:h}})}lonLatToWorldCoords(t,e){const i=s(this,_).project(t,e);if(s(this,A))i[0]-=s(this,A)[0],i[1]-=s(this,A)[1];else throw"No initial position determined";return[i[0],-i[1]]}add(t,e,i,h,u={}){var f;t.properties=u,w(this,M,k).call(this,t,e,i,h),this.scene.add(t),(f=s(this,O))==null||f.sendData("/object/new",{position:t.position,x:t.position.x,z:t.position.z,session:s(this,T),properties:u})}setElevation(t){this.camera.position.y=t}on(t,e){s(this,L)[t]=e}}_=new WeakMap,L=new WeakMap,E=new WeakMap,j=new WeakMap,I=new WeakMap,D=new WeakMap,A=new WeakMap,S=new WeakMap,T=new WeakMap,O=new WeakMap,M=new WeakSet,k=function(t,e,i,h){const u=this.lonLatToWorldCoords(e,i);h!==void 0&&(t.position.y=h),[t.position.x,t.position.z]=u},$=function(t,e){m(this,A,s(this,_).project(t,e))},q=function(t){var i,h,u;let e=Number.MAX_VALUE;V(this,S)._++,(i=s(this,O))==null||i.sendData("/gps/new",{gpsCount:s(this,S),lat:t.coords.latitude,lon:t.coords.longitude,acc:t.coords.accuracy,session:s(this,T)}),t.coords.accuracy<=s(this,I)&&(s(this,E)===null?m(this,E,{latitude:t.coords.latitude,longitude:t.coords.longitude}):e=w(this,M,K).call(this,s(this,E),t.coords),e>=s(this,j)&&(s(this,E).longitude=t.coords.longitude,s(this,E).latitude=t.coords.latitude,s(this,A)||(w(this,M,$).call(this,t.coords.longitude,t.coords.latitude),(h=s(this,O))==null||h.sendData("/worldorigin/new",{gpsCount:s(this,S),lat:t.coords.latitude,lon:t.coords.longitude,session:s(this,T),initialPosition:s(this,A)})),w(this,M,k).call(this,this.camera,t.coords.longitude,t.coords.latitude),(u=s(this,O))==null||u.sendData("/gps/accepted",{gpsCount:s(this,S),cameraX:this.camera.position.x,cameraZ:this.camera.position.z,session:s(this,T),distMoved:e}),s(this,L).gpsupdate&&s(this,L).gpsupdate(t,e)))},K=function(t,e){const i=v.MathUtils.degToRad(e.longitude-t.longitude),h=v.MathUtils.degToRad(e.latitude-t.latitude),u=Math.sin(h/2)*Math.sin(h/2)+Math.cos(v.MathUtils.degToRad(t.latitude))*Math.cos(v.MathUtils.degToRad(e.latitude))*(Math.sin(i/2)*Math.sin(i/2));return 2*Math.atan2(Math.sqrt(u),Math.sqrt(1-u))*6371e3};class G{constructor(t={},e){this.sceneWebcam=new v.Scene;let i;if(e?i=document.querySelector(e):(i=document.createElement("video"),i.setAttribute("autoplay",!0),i.setAttribute("playsinline",!0),i.style.display="none",document.body.appendChild(i)),this.texture=new v.VideoTexture(i),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const h={video:{width:{ideal:t.idealWidth||1280},height:{ideal:t.idealHeight||720},facingMode:"environment"}};navigator.mediaDevices.getUserMedia(h).then(u=>{i.addEventListener("loadedmetadata",()=>{var f;i.setAttribute("width",i.videoWidth),i.setAttribute("height",i.videoHeight),i.play(),(f=t.onVideoStarted)==null||f.call(this,this.texture)}),i.srcObject=u}).catch(u=>{setTimeout(()=>{alert(`Webcam Error
|
|
2
|
+
Name: `+u.name+`
|
|
3
|
+
Message: `+u.message)},1e3)})}else setTimeout(()=>{alert("sorry - media devices API not supported")},1e3)}dispose(){this.texture.dispose()}}const R=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,J=new n.Vector3(0,0,1),N=new n.Euler,tt=new n.Quaternion,et=new n.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),it={type:"change"};class z extends n.EventDispatcher{constructor(t){super(),window.isSecureContext===!1&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const e=this,i=1e-6,h=new n.Quaternion;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation=null,this.screenOrientation=0,this.alphaOffset=0,this.initialOffset=null,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=1;const u=function({alpha:o,beta:l,gamma:d,webkitCompassHeading:c}){if(R){const g=360-c;e.alphaOffset=n.MathUtils.degToRad(g-o),e.deviceOrientation={alpha:o,beta:l,gamma:d,webkitCompassHeading:c}}else o<0&&(o+=360),e.deviceOrientation={alpha:o,beta:l,gamma:d};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:t.rotation}}))},f=function(){e.screenOrientation=window.orientation||0},x=function(o,l,d,c,g){N.set(d,l,-c,"YXZ"),o.setFromEuler(N),o.multiply(et),o.multiply(tt.setFromAxisAngle(J,-g))};this.connect=function(){f(),window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(o=>{o==="granted"&&(window.addEventListener("orientationchange",f),window.addEventListener(e.orientationChangeEventName,u))}).catch(function(o){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",o)}):(window.addEventListener("orientationchange",f),window.addEventListener(e.orientationChangeEventName,u)),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",f),window.removeEventListener(e.orientationChangeEventName,u),e.enabled=!1,e.initialOffset=!1,e.deviceOrientation=null},this.update=function({theta:o=0}={theta:0}){if(e.enabled===!1)return;const l=e.deviceOrientation;if(l){let d=l.alpha?n.MathUtils.degToRad(l.alpha)+e.alphaOffset:0,c=l.beta?n.MathUtils.degToRad(l.beta):0,g=l.gamma?n.MathUtils.degToRad(l.gamma):0;const F=e.screenOrientation?n.MathUtils.degToRad(e.screenOrientation):0;if(R){const P=new n.Quaternion;x(P,d,c,g,F);const C=new n.Euler().setFromQuaternion(P,"YXZ");console.log(C.x,C.y,C.z),C.y=n.MathUtils.degToRad(360-l.webkitCompassHeading),P.setFromEuler(C),e.object.quaternion.copy(P)}else{if(this.smoothingFactor<1){if(this.lastOrientation){const P=this.smoothingFactor;d=this._getSmoothedAngle(d,this.lastOrientation.alpha,P),c=this._getSmoothedAngle(c+Math.PI,this.lastOrientation.beta,P),g=this._getSmoothedAngle(g+this.HALF_PI,this.lastOrientation.gamma,P,Math.PI)}else c+=Math.PI,g+=this.HALF_PI;this.lastOrientation={alpha:d,beta:c,gamma:g}}x(e.object.quaternion,d+o,this.smoothingFactor<1?c-Math.PI:c,this.smoothingFactor<1?g-this.HALF_PI:g,F)}8*(1-h.dot(e.object.quaternion))>i&&(h.copy(e.object.quaternion),e.dispatchEvent(it))}},this._orderAngle=function(o,l,d=this.TWO_PI){return l>o&&Math.abs(l-o)<d/2||o>l&&Math.abs(l-o)>d/2?{left:o,right:l}:{left:l,right:o}},this._getSmoothedAngle=function(o,l,d,c=this.TWO_PI){const g=this._orderAngle(o,l,c),F=g.left,P=g.right;g.left=0,g.right-=F,g.right<0&&(g.right+=c);let C=P==l?(1-d)*g.right+d*g.left:d*g.right+(1-d)*g.left;return C+=F,C>=c&&(C-=c),C},this.updateAlphaOffset=function(){e.initialOffset=!1},this.dispose=function(){e.disconnect()},this.getAlpha=function(){const{deviceOrientation:o}=e;return o&&o.alpha?n.MathUtils.degToRad(o.alpha)+e.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:o}=e;return o&&o.beta?n.MathUtils.degToRad(o.beta):0},window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?this.initPermissionDialog():this.connect()}initPermissionDialog(){const t=document.createElement("div"),e=document.createElement("div"),i=document.createElement("div"),h=document.createElement("div");document.body.appendChild(t);const u={display:"flex",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:1,backgroundColor:"rgba(0,0,0,0.6)",justifyContent:"center",alignItems:"center"},f={backgroundColor:"white",padding:"6px",borderRadius:"3px",width:"36rem",height:"24rem"},x={width:"100%",height:"70%",display:"flex",justifyContent:"center",alignItems:"center"},o={display:"inline-flex",width:"100%",height:"30%",justifyContent:"center",alignItems:"center"};for(let c in u)t.style[c]=u[c];for(let c in f)e.style[c]=f[c];for(let c in x)i.style[c]=x[c];for(let c in o)h.style[c]=o[c];t.appendChild(e),e.appendChild(i),e.appendChild(h),i.innerHTML='<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';const l=()=>{this.connect(),t.style.display="none"},d=document.createElement("button");d.addEventListener("click",l),d.style.width="50%",d.style.height="80%",d.style.fontSize="20pt",d.appendChild(document.createTextNode("OK")),h.appendChild(d),document.body.appendChild(t)}}class nt{constructor(t){this.raycaster=new v.Raycaster,this.normalisedMousePosition=new v.Vector2(null,null),t.domElement.addEventListener("click",e=>{this.normalisedMousePosition.set(e.clientX/t.domElement.clientWidth*2-1,-(e.clientY/t.domElement.clientHeight*2)+1)})}raycast(t,e){if(this.normalisedMousePosition.x!==null&&this.normalisedMousePosition.y!==null){this.raycaster.setFromCamera(this.normalisedMousePosition,t);const i=this.raycaster.intersectObjects(e.children,!1);return this.normalisedMousePosition.set(null,null),i}return[]}}AFRAME.registerComponent("locar-webcam",{schema:{idealWidth:{type:"number",default:1024},idealHeight:{type:"number",default:768},videoElement:{type:"string",default:""}},init:function(){new G({idealWidth:this.data.idealWidth,idealHeight:this.data.idealHeight,onVideoStarted:a=>{this.el.object3D.background=a}},this.data.videoElement||null)}}),AFRAME.registerComponent("locar-camera",{schema:{simulateLatitude:{type:"number",default:0},simulateLongitude:{type:"number",default:0},simulateAltitude:{type:"number",default:-Number.MAX_VALUE},positionMinAccuracy:{type:"number",default:100}},init:function(){this.locar=new H(this.el.sceneEl.object3D,this.el.object3D),this.locar.on("gpsupdate",(a,t)=>{this.el.emit("gpsupdate",{position:a,distMoved:t})}),this.locar.on("gpserror",a=>{const t=["User denied access to GPS.","GPS satellites not available.","Timeout communicating with GPS satellites - try moving to a more open area."];a>=1&&a<=3?alert(t[a-1]):alert(`Unknown geolocation error code ${a}.`)}),this._isMobile()&&(this.deviceOrientationControls=new z(this.el.object3D))},update:function(a){this.locar.setGpsOptions({gpsMinAccuracy:this.data.positionMinAccuracy,gpsMinDistance:this.data.gpsMinDistance}),(this.data.simulateLatitude!==0||this.data.simulateLongitude!==0)&&(this.data.simulateLatitude!=(a==null?void 0:a.simulateLatitude)||this.data.simulateLongitude!=(a==null?void 0:a.simulateLongitude))&&(this.locar.stopGps(),this.locar.fakeGps(this.data.simulateLongitude,this.data.simulateLatitude),this.data.simulateLongitude=0,this.data.simulateLatitude=0),this.data.simulateAltitude>-Number.MAX_VALUE&&this.locar.setElevation(this.data.simulateAltitude+1.6)},play:function(){this.locar.startGps()},pause:function(){this.locar.stopGps()},lonLatToWorldCoords:function(a,t){return this.locar.lonLatToWorldCoords(a,t)},tick:function(){var a;(a=this.deviceOrientationControls)==null||a.update()},_isMobile:function(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1}}),AFRAME.registerComponent("locar-entity-place",{schema:{latitude:{type:"number",default:0},longitude:{type:"number",default:0}},init:function(){const a=this.el.sceneEl.querySelector("[locar-camera]");this.locarCamera=a.components["locar-camera"]},update:function(a){this.locarCamera||console.error("Cannot update locar-entity-place without a locar-camera component on the scene camera.");const t=this.locarCamera.lonLatToWorldCoords(this.data.longitude,this.data.latitude);this.el.object3D.position.set(t[0],this.el.object3D.position.y,t[1])}});const st="0.0.10";r.ClickHandler=nt,r.DeviceOrientationControls=z,r.LocationBased=H,r.SphMercProjection=W,r.Webcam=G,r.version=st,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "locar",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "Location-based AR from AR.js.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -20,5 +20,8 @@
|
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"jsdoc": "^4.0.4",
|
|
22
22
|
"vite": "^5.4.8"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"three": "^0.175.0"
|
|
23
26
|
}
|
|
24
27
|
}
|