locar 0.1.5 → 0.1.6
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/dist/locar.es.js +154 -152
- package/dist/locar.umd.js +1 -1
- package/package.json +1 -1
package/dist/locar.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as m from "three";
|
|
2
|
-
import { Vector3 as
|
|
3
|
-
class
|
|
2
|
+
import { Vector3 as y, Euler as C, Quaternion as I, EventDispatcher as w, MathUtils as g } from "three";
|
|
3
|
+
class R {
|
|
4
4
|
/**
|
|
5
5
|
* Create a SphMercProjection.
|
|
6
6
|
*/
|
|
@@ -13,29 +13,29 @@ class T {
|
|
|
13
13
|
* @param {number} lat - the latitude.
|
|
14
14
|
* @return {Array} Two-member array containing easting and northing.
|
|
15
15
|
*/
|
|
16
|
-
project(
|
|
17
|
-
return [this.#t(
|
|
16
|
+
project(e, i) {
|
|
17
|
+
return [this.#t(e), this.#l(i)];
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Unproject a Spherical Mercator easting and northing.
|
|
21
21
|
* @param {Array} projected - Two-member array containing easting and northing
|
|
22
22
|
* @return {Array} Two-member array containing longitude and latitude
|
|
23
23
|
*/
|
|
24
|
-
unproject(
|
|
25
|
-
return [this.#e(
|
|
24
|
+
unproject(e) {
|
|
25
|
+
return [this.#e(e[0]), this.#s(e[1])];
|
|
26
26
|
}
|
|
27
|
-
#t(
|
|
28
|
-
return
|
|
27
|
+
#t(e) {
|
|
28
|
+
return e / 180 * this.HALF_EARTH;
|
|
29
29
|
}
|
|
30
|
-
#l(
|
|
31
|
-
var i = Math.log(Math.tan((90 +
|
|
30
|
+
#l(e) {
|
|
31
|
+
var i = Math.log(Math.tan((90 + e) * Math.PI / 360)) / (Math.PI / 180);
|
|
32
32
|
return i * this.HALF_EARTH / 180;
|
|
33
33
|
}
|
|
34
|
-
#e(
|
|
35
|
-
return
|
|
34
|
+
#e(e) {
|
|
35
|
+
return e / this.HALF_EARTH * 180;
|
|
36
36
|
}
|
|
37
|
-
#s(
|
|
38
|
-
var i =
|
|
37
|
+
#s(e) {
|
|
38
|
+
var i = e / this.HALF_EARTH * 180;
|
|
39
39
|
return i = 180 / Math.PI * (2 * Math.atan(Math.exp(i * Math.PI / 180)) - Math.PI / 2), i;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -55,17 +55,17 @@ class A {
|
|
|
55
55
|
* @param {string} eventName - the event to handle.
|
|
56
56
|
* @param {Function} eventHandler - the event handler function.
|
|
57
57
|
*/
|
|
58
|
-
on(
|
|
59
|
-
this.eventHandlers[
|
|
58
|
+
on(e, i) {
|
|
59
|
+
this.eventHandlers[e] === void 0 && (this.eventHandlers[e] = []), this.eventHandlers[e].push(i);
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Emit an event.
|
|
63
63
|
* @param {string} eventName - the event to emit.
|
|
64
64
|
* @param ...params - parameters to pass to the event handlers.
|
|
65
65
|
*/
|
|
66
|
-
emit(
|
|
67
|
-
this.eventHandlers[
|
|
68
|
-
|
|
66
|
+
emit(e, ...i) {
|
|
67
|
+
this.eventHandlers[e]?.forEach((t) => {
|
|
68
|
+
t(...i);
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
@@ -73,14 +73,14 @@ class A {
|
|
|
73
73
|
* @param {string} eventName - the event to remove a handler from.
|
|
74
74
|
* @param {Function} eventHandler - the event handler function to remove.
|
|
75
75
|
*/
|
|
76
|
-
off(
|
|
77
|
-
if (this.eventHandlers[
|
|
78
|
-
const
|
|
79
|
-
|
|
76
|
+
off(e, i) {
|
|
77
|
+
if (this.eventHandlers[e]) {
|
|
78
|
+
const t = this.eventHandlers[e].indexOf(i);
|
|
79
|
+
t > -1 && this.eventHandlers[e].splice(t, 1);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
class
|
|
83
|
+
class q extends A {
|
|
84
84
|
#t;
|
|
85
85
|
// eslint-disable-next-line no-unused-private-class-members
|
|
86
86
|
#l;
|
|
@@ -100,8 +100,8 @@ class k extends A {
|
|
|
100
100
|
* setGpsOptions() below.
|
|
101
101
|
* @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.
|
|
102
102
|
*/
|
|
103
|
-
constructor(
|
|
104
|
-
super(), this.scene =
|
|
103
|
+
constructor(e, i, t = {}, c = null) {
|
|
104
|
+
super(), this.scene = e, this.camera = i, this.#t = new R(), this.#e = null, this.#s = 0, this.#c = 100, this.#o = null, this.setGpsOptions(t), this.#i = null, this.#r = 0, this.#a = 0, this.#n = c;
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
107
|
* Set the projection to use.
|
|
@@ -109,8 +109,8 @@ class k extends A {
|
|
|
109
109
|
* taking longitude and latitude as arguments and returning an array
|
|
110
110
|
* containing easting and northing.
|
|
111
111
|
*/
|
|
112
|
-
setProjection(
|
|
113
|
-
this.#t =
|
|
112
|
+
setProjection(e) {
|
|
113
|
+
this.#t = e;
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Set the GPS options.
|
|
@@ -119,8 +119,8 @@ class k extends A {
|
|
|
119
119
|
* must move to process a new GPS reading, and the latter specifies the
|
|
120
120
|
* minimum accuracy, in metres, for a GPS reading to be counted.
|
|
121
121
|
*/
|
|
122
|
-
setGpsOptions(
|
|
123
|
-
|
|
122
|
+
setGpsOptions(e = {}) {
|
|
123
|
+
e.gpsMinDistance !== void 0 && (this.#s = e.gpsMinDistance), e.gpsMinAccuracy !== void 0 && (this.#c = e.gpsMinAccuracy);
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Start the GPS on a real device
|
|
@@ -136,11 +136,11 @@ class k extends A {
|
|
|
136
136
|
this.#a = i.session;
|
|
137
137
|
}
|
|
138
138
|
return this.#o === null ? (this.#o = navigator.geolocation.watchPosition(
|
|
139
|
-
(
|
|
140
|
-
this.#h(
|
|
139
|
+
(e) => {
|
|
140
|
+
this.#h(e);
|
|
141
141
|
},
|
|
142
|
-
(
|
|
143
|
-
this.emit("gpserror",
|
|
142
|
+
(e) => {
|
|
143
|
+
this.emit("gpserror", e);
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
enableHighAccuracy: !0
|
|
@@ -164,10 +164,10 @@ class k extends A {
|
|
|
164
164
|
* @param {number} acc - The accuracy of the GPS reading in metres. May be
|
|
165
165
|
* ignored if lower than the specified minimum accuracy.
|
|
166
166
|
*/
|
|
167
|
-
fakeGps(
|
|
168
|
-
|
|
167
|
+
fakeGps(e, i, t = null, c = 0) {
|
|
168
|
+
t !== null && this.setElevation(t), this.#h({
|
|
169
169
|
coords: {
|
|
170
|
-
longitude:
|
|
170
|
+
longitude: e,
|
|
171
171
|
latitude: i,
|
|
172
172
|
accuracy: c
|
|
173
173
|
}
|
|
@@ -184,13 +184,13 @@ class k extends A {
|
|
|
184
184
|
* @param {number} lat - The latitude.
|
|
185
185
|
* @return {Array} a two member array containing the WebGL x and z coordinates
|
|
186
186
|
*/
|
|
187
|
-
lonLatToWorldCoords(
|
|
188
|
-
const
|
|
187
|
+
lonLatToWorldCoords(e, i) {
|
|
188
|
+
const t = this.#t.project(e, i);
|
|
189
189
|
if (this.#i)
|
|
190
|
-
|
|
190
|
+
t[0] -= this.#i[0], t[1] -= this.#i[1];
|
|
191
191
|
else
|
|
192
192
|
throw "No initial position determined";
|
|
193
|
-
return [
|
|
193
|
+
return [t[0], -t[1]];
|
|
194
194
|
}
|
|
195
195
|
/**
|
|
196
196
|
* Add a new AR object at a given latitude, longitude and elevation.
|
|
@@ -202,68 +202,68 @@ class k extends A {
|
|
|
202
202
|
* @param {Object} properties - properties describing the object (for example,
|
|
203
203
|
* the contents of the GeoJSON properties field).
|
|
204
204
|
*/
|
|
205
|
-
add(
|
|
206
|
-
|
|
207
|
-
position:
|
|
208
|
-
x:
|
|
209
|
-
z:
|
|
205
|
+
add(e, i, t, c, h = {}) {
|
|
206
|
+
e.properties = h, this.#d(e, i, t, c), this.scene.add(e), this.#n?.sendData("/object/new", {
|
|
207
|
+
position: e.position,
|
|
208
|
+
x: e.position.x,
|
|
209
|
+
z: e.position.z,
|
|
210
210
|
session: this.#a,
|
|
211
211
|
properties: h
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
|
-
#d(
|
|
215
|
-
const h = this.lonLatToWorldCoords(i,
|
|
216
|
-
c !== void 0 && (
|
|
214
|
+
#d(e, i, t, c) {
|
|
215
|
+
const h = this.lonLatToWorldCoords(i, t);
|
|
216
|
+
c !== void 0 && (e.position.y = c), [e.position.x, e.position.z] = h;
|
|
217
217
|
}
|
|
218
218
|
/**
|
|
219
219
|
* Set the elevation (y coordinate) of the camera.
|
|
220
220
|
* @param {number} elev - the elevation in metres.
|
|
221
221
|
*/
|
|
222
|
-
setElevation(
|
|
223
|
-
this.camera.position.y =
|
|
222
|
+
setElevation(e) {
|
|
223
|
+
this.camera.position.y = e;
|
|
224
224
|
}
|
|
225
|
-
#u(
|
|
226
|
-
this.#i = this.#t.project(
|
|
225
|
+
#u(e, i) {
|
|
226
|
+
this.#i = this.#t.project(e, i);
|
|
227
227
|
}
|
|
228
|
-
#h(
|
|
228
|
+
#h(e) {
|
|
229
229
|
let i = Number.MAX_VALUE;
|
|
230
230
|
this.#r++, this.#n?.sendData("/gps/new", {
|
|
231
231
|
gpsCount: this.#r,
|
|
232
|
-
lat:
|
|
233
|
-
lon:
|
|
234
|
-
acc:
|
|
232
|
+
lat: e.coords.latitude,
|
|
233
|
+
lon: e.coords.longitude,
|
|
234
|
+
acc: e.coords.accuracy,
|
|
235
235
|
session: this.#a
|
|
236
|
-
}),
|
|
237
|
-
latitude:
|
|
238
|
-
longitude:
|
|
239
|
-
} : i = this.#g(this.#e,
|
|
240
|
-
|
|
241
|
-
|
|
236
|
+
}), e.coords.accuracy <= this.#c && (this.#e === null ? this.#e = {
|
|
237
|
+
latitude: e.coords.latitude,
|
|
238
|
+
longitude: e.coords.longitude
|
|
239
|
+
} : i = this.#g(this.#e, e.coords), i >= this.#s && (this.#e.longitude = e.coords.longitude, this.#e.latitude = e.coords.latitude, this.#i || (this.#u(
|
|
240
|
+
e.coords.longitude,
|
|
241
|
+
e.coords.latitude
|
|
242
242
|
), this.#n?.sendData("/worldorigin/new", {
|
|
243
243
|
gpsCount: this.#r,
|
|
244
|
-
lat:
|
|
245
|
-
lon:
|
|
244
|
+
lat: e.coords.latitude,
|
|
245
|
+
lon: e.coords.longitude,
|
|
246
246
|
session: this.#a,
|
|
247
247
|
initialPosition: this.#i
|
|
248
248
|
})), this.#d(
|
|
249
249
|
this.camera,
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
e.coords.longitude,
|
|
251
|
+
e.coords.latitude
|
|
252
252
|
), this.#n?.sendData("/gps/accepted", {
|
|
253
253
|
gpsCount: this.#r,
|
|
254
254
|
cameraX: this.camera.position.x,
|
|
255
255
|
cameraZ: this.camera.position.z,
|
|
256
256
|
session: this.#a,
|
|
257
257
|
distMoved: i
|
|
258
|
-
}), this.emit("gpsupdate", { position:
|
|
258
|
+
}), this.emit("gpsupdate", { position: e, distMoved: i })));
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Calculate haversine distance between two lat/lon pairs.
|
|
262
262
|
*
|
|
263
263
|
* Taken from original A-Frame AR.js location-based components
|
|
264
264
|
*/
|
|
265
|
-
#g(
|
|
266
|
-
const
|
|
265
|
+
#g(e, i) {
|
|
266
|
+
const t = m.MathUtils.degToRad(i.longitude - e.longitude), c = m.MathUtils.degToRad(i.latitude - e.latitude), h = Math.sin(c / 2) * Math.sin(c / 2) + Math.cos(m.MathUtils.degToRad(e.latitude)) * Math.cos(m.MathUtils.degToRad(i.latitude)) * (Math.sin(t / 2) * Math.sin(t / 2));
|
|
267
267
|
return 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)) * 6371e3;
|
|
268
268
|
}
|
|
269
269
|
/**
|
|
@@ -275,7 +275,7 @@ class k extends A {
|
|
|
275
275
|
return this.#e;
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
class
|
|
278
|
+
class k extends A {
|
|
279
279
|
#t;
|
|
280
280
|
/**
|
|
281
281
|
* Create a Webcam.
|
|
@@ -285,15 +285,15 @@ class W extends A {
|
|
|
285
285
|
* element to render the webcam feed. If a falsy value (e.g. null or
|
|
286
286
|
* undefined), a video element will be created.
|
|
287
287
|
*/
|
|
288
|
-
constructor(
|
|
289
|
-
super(), this.sceneWebcam = new m.Scene(), i ? this.#t = document.querySelector(i) : (this.#t = document.createElement("video"), this.#t.setAttribute("autoplay", !0), this.#t.setAttribute("playsinline", !0), this.#t.style.display = "none", document.body.appendChild(this.#t)), this.texture = new m.VideoTexture(this.#t), navigator.mediaDevices && navigator.mediaDevices.getUserMedia ? navigator.mediaDevices.getUserMedia(
|
|
288
|
+
constructor(e = { video: { facingMode: "environment" } }, i) {
|
|
289
|
+
super(), this.sceneWebcam = new m.Scene(), i ? this.#t = document.querySelector(i) : (this.#t = document.createElement("video"), this.#t.setAttribute("autoplay", !0), this.#t.setAttribute("playsinline", !0), this.#t.style.display = "none", document.body.appendChild(this.#t)), this.texture = new m.VideoTexture(this.#t), navigator.mediaDevices && navigator.mediaDevices.getUserMedia ? navigator.mediaDevices.getUserMedia(e).then((t) => {
|
|
290
290
|
this.#t.addEventListener("loadedmetadata", () => {
|
|
291
291
|
this.#t.setAttribute("width", this.#t.videoWidth), this.#t.setAttribute("height", this.#t.videoHeight), this.#t.play(), this.emit("webcamstarted", { texture: this.texture });
|
|
292
|
-
}), this.#t.srcObject =
|
|
293
|
-
}).catch((
|
|
292
|
+
}), this.#t.srcObject = t;
|
|
293
|
+
}).catch((t) => {
|
|
294
294
|
this.emit("webcamerror", {
|
|
295
|
-
code:
|
|
296
|
-
message:
|
|
295
|
+
code: t.name,
|
|
296
|
+
message: t.message
|
|
297
297
|
});
|
|
298
298
|
}) : this.emit("webcamerror", {
|
|
299
299
|
code: "LOCAR_NO_MEDIA_DEVICES_API",
|
|
@@ -308,18 +308,19 @@ class W extends A {
|
|
|
308
308
|
this.texture.dispose();
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
const b = "locar-device-orientation-permission-modal", D = "locar-device-orientation-permission-button", S = "locar-device-orientation-permission-message", N = "locar-device-orientation-permission-inner", L = "locar-device-orientation-permission-button-inner",
|
|
312
|
-
class V extends
|
|
311
|
+
const b = "locar-device-orientation-permission-modal", D = "locar-device-orientation-permission-button", S = "locar-device-orientation-permission-message", N = "locar-device-orientation-permission-inner", L = "locar-device-orientation-permission-button-inner", T = "This immersive website requires access to your device motion sensors.", O = navigator.userAgent.match(/iPhone|iPad|iPod/i) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1, x = new y(0, 0, 1), P = new C(), H = new I(), F = new I(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
|
|
312
|
+
class V extends w {
|
|
313
313
|
/**
|
|
314
314
|
* Create an instance of DeviceOrientationControls.
|
|
315
315
|
* @param {Object} object - the object to attach the controls to
|
|
316
316
|
* (usually your Three.js camera)
|
|
317
|
-
* @param {Object} options - options for DeviceOrientationControls:
|
|
317
|
+
* @param {Object} options - options for DeviceOrientationControls:
|
|
318
|
+
* currently accepts smoothingFactor (< 1), enablePermissionDialog, orientationChangeThreshold (radians)
|
|
318
319
|
*/
|
|
319
|
-
constructor(
|
|
320
|
+
constructor(e, i = {}) {
|
|
320
321
|
super(), this.eventEmitter = new A();
|
|
321
|
-
const
|
|
322
|
-
this.object =
|
|
322
|
+
const t = this;
|
|
323
|
+
this.object = e, this.object.rotation.reorder("YXZ"), this.enabled = !0, this.deviceOrientation = null, this.screenOrientation = 0, this.alphaOffset = 0, this.orientationOffset = 0, this.initialOffset = null, this.lastCompassY = void 0, this.lastOrientation = null, this.TWO_PI = 2 * Math.PI, this.HALF_PI = 0.5 * Math.PI, this.orientationChangeEventName = "ondeviceorientationabsolute" in window ? "deviceorientationabsolute" : "deviceorientation", this.smoothingFactor = i.smoothingFactor || 1, this.enablePermissionDialog = i.enablePermissionDialog ?? !0, this.enableInlineStyling = i.enableStyling ?? !0, this.preferConfirmDialog = i.preferConfirmDialog ?? !1, this.orientationChangeThreshold = i.orientationChangeThreshold ?? 0;
|
|
323
324
|
const c = function({
|
|
324
325
|
alpha: n,
|
|
325
326
|
beta: s,
|
|
@@ -328,35 +329,35 @@ class V extends R {
|
|
|
328
329
|
}) {
|
|
329
330
|
if (O) {
|
|
330
331
|
const o = 360 - r;
|
|
331
|
-
|
|
332
|
+
t.alphaOffset = g.degToRad(o - n), t.deviceOrientation = { alpha: n, beta: s, gamma: a, webkitCompassHeading: r };
|
|
332
333
|
} else
|
|
333
|
-
n < 0 && (n += 360),
|
|
334
|
+
n < 0 && (n += 360), t.deviceOrientation = { alpha: n, beta: s, gamma: a };
|
|
334
335
|
window.dispatchEvent(
|
|
335
336
|
new CustomEvent("camera-rotation-change", {
|
|
336
|
-
detail: { cameraRotation:
|
|
337
|
+
detail: { cameraRotation: e.rotation }
|
|
337
338
|
})
|
|
338
339
|
);
|
|
339
340
|
}, h = function() {
|
|
340
|
-
|
|
341
|
+
t.screenOrientation = window.orientation || 0, O && (t.screenOrientation === 90 ? t.orientationOffset = -t.HALF_PI : t.screenOrientation === -90 ? t.orientationOffset = t.HALF_PI : t.orientationOffset = 0);
|
|
341
342
|
}, E = function(n, s, a, r, o) {
|
|
342
|
-
|
|
343
|
+
P.set(a, s, -r, "YXZ"), n.setFromEuler(P), n.multiply(F), n.multiply(H.setFromAxisAngle(x, -o));
|
|
343
344
|
};
|
|
344
345
|
this.connect = function() {
|
|
345
346
|
h(), window.addEventListener(
|
|
346
347
|
"orientationchange",
|
|
347
348
|
h
|
|
348
349
|
), window.addEventListener(
|
|
349
|
-
|
|
350
|
+
t.orientationChangeEventName,
|
|
350
351
|
c
|
|
351
|
-
),
|
|
352
|
+
), t.enabled = !0;
|
|
352
353
|
}, this.disconnect = function() {
|
|
353
354
|
window.removeEventListener(
|
|
354
355
|
"orientationchange",
|
|
355
356
|
h
|
|
356
357
|
), window.removeEventListener(
|
|
357
|
-
|
|
358
|
+
t.orientationChangeEventName,
|
|
358
359
|
c
|
|
359
|
-
),
|
|
360
|
+
), t.enabled = !1, t.initialOffset = !1, t.deviceOrientation = null;
|
|
360
361
|
}, this.requestOrientationPermissions = function() {
|
|
361
362
|
window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((n) => {
|
|
362
363
|
n === "granted" ? this.eventEmitter.emit("deviceorientationgranted", {
|
|
@@ -376,88 +377,89 @@ class V extends R {
|
|
|
376
377
|
message: "Internal error: no requestPermission() found although requestOrientationPermissions() was called - please raise an issue on GitHub"
|
|
377
378
|
});
|
|
378
379
|
}, this.update = function({ theta: n = 0 } = { theta: 0 }) {
|
|
379
|
-
if (
|
|
380
|
-
const s =
|
|
380
|
+
if (t.enabled === !1) return;
|
|
381
|
+
const s = t.deviceOrientation;
|
|
381
382
|
if (s) {
|
|
382
|
-
let a = s.alpha ? g.degToRad(s.alpha) +
|
|
383
|
-
const f =
|
|
384
|
-
if (
|
|
385
|
-
if (
|
|
386
|
-
const d =
|
|
387
|
-
a =
|
|
383
|
+
let a = s.alpha ? g.degToRad(s.alpha) + t.alphaOffset : 0, r = s.beta ? g.degToRad(s.beta) : 0, o = s.gamma ? g.degToRad(s.gamma) : 0;
|
|
384
|
+
const f = t.screenOrientation ? g.degToRad(t.screenOrientation) : 0;
|
|
385
|
+
if (t.smoothingFactor < 1)
|
|
386
|
+
if (t.lastOrientation) {
|
|
387
|
+
const d = t.smoothingFactor;
|
|
388
|
+
a = t._getSmoothedAngle(
|
|
388
389
|
a,
|
|
389
|
-
|
|
390
|
+
t.lastOrientation.alpha,
|
|
390
391
|
d
|
|
391
|
-
), r =
|
|
392
|
+
), r = t._getSmoothedAngle(
|
|
392
393
|
r + Math.PI,
|
|
393
|
-
|
|
394
|
+
t.lastOrientation.beta,
|
|
394
395
|
d
|
|
395
|
-
), o =
|
|
396
|
-
o +
|
|
397
|
-
|
|
396
|
+
), o = t._getSmoothedAngle(
|
|
397
|
+
o + t.HALF_PI,
|
|
398
|
+
t.lastOrientation.gamma,
|
|
398
399
|
d,
|
|
399
400
|
Math.PI
|
|
400
401
|
);
|
|
401
402
|
} else
|
|
402
|
-
r += Math.PI, o +=
|
|
403
|
-
|
|
404
|
-
alpha: a,
|
|
405
|
-
beta: r,
|
|
406
|
-
gamma: o
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
if (O) {
|
|
403
|
+
r += Math.PI, o += t.HALF_PI;
|
|
404
|
+
if (t.lastOrientation && (a = t._calcAngleWithThreshold(a, t.lastOrientation.alpha), r = t._calcAngleWithThreshold(r, t.lastOrientation.beta), o = t._calcAngleWithThreshold(o, t.lastOrientation.gamma)), O) {
|
|
410
405
|
const d = new I();
|
|
411
406
|
E(
|
|
412
407
|
d,
|
|
413
408
|
a,
|
|
414
|
-
|
|
415
|
-
|
|
409
|
+
t.smoothingFactor < 1 ? r - Math.PI : r,
|
|
410
|
+
t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
|
|
416
411
|
f
|
|
417
412
|
);
|
|
418
|
-
const u = new
|
|
413
|
+
const u = new C().setFromQuaternion(
|
|
419
414
|
d,
|
|
420
415
|
"YXZ"
|
|
421
416
|
);
|
|
422
417
|
let p = g.degToRad(360 - s.webkitCompassHeading);
|
|
423
|
-
|
|
418
|
+
t.smoothingFactor < 1 && t.lastCompassY !== void 0 && (p = t._getSmoothedAngle(
|
|
424
419
|
p,
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
)),
|
|
420
|
+
t.lastCompassY,
|
|
421
|
+
t.smoothingFactor
|
|
422
|
+
)), t.lastCompassY = p, u.y = p + (t.orientationOffset || 0), d.setFromEuler(u), t.object.quaternion.copy(d);
|
|
428
423
|
} else
|
|
429
424
|
E(
|
|
430
|
-
|
|
431
|
-
O ? a +
|
|
432
|
-
|
|
433
|
-
|
|
425
|
+
t.object.quaternion,
|
|
426
|
+
O ? a + t.alphaOffset : a,
|
|
427
|
+
t.smoothingFactor < 1 ? r - Math.PI : r,
|
|
428
|
+
t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
|
|
434
429
|
f
|
|
435
430
|
);
|
|
431
|
+
t.lastOrientation = {
|
|
432
|
+
alpha: a,
|
|
433
|
+
beta: r,
|
|
434
|
+
gamma: o
|
|
435
|
+
};
|
|
436
436
|
}
|
|
437
437
|
}, this.getCorrectedHeading = function() {
|
|
438
|
-
const { deviceOrientation: n } =
|
|
438
|
+
const { deviceOrientation: n } = t;
|
|
439
439
|
if (!n) return 0;
|
|
440
440
|
let s = 0;
|
|
441
|
-
return O ? (s = 360 - n.webkitCompassHeading,
|
|
442
|
-
}, this.
|
|
441
|
+
return O ? (s = 360 - n.webkitCompassHeading, t.orientationOffset && (s += t.orientationOffset * (180 / Math.PI), s = (s + 360) % 360)) : (n.absolute === !0 || t.orientationChangeEventName, s = n.alpha ? n.alpha : 0, s = (360 - s) % 360, s < 0 && (s += 360)), s;
|
|
442
|
+
}, this._calcAngleWithThreshold = function(n, s) {
|
|
443
|
+
return Math.abs(n - s) < t.orientationChangeThreshold ? s : n;
|
|
444
|
+
}, this._orderAngle = function(n, s, a = t.TWO_PI) {
|
|
443
445
|
return s > n && Math.abs(s - n) < a / 2 || n > s && Math.abs(s - n) > a / 2 ? { left: n, right: s } : { left: s, right: n };
|
|
444
|
-
}, this._getSmoothedAngle = function(n, s, a, r =
|
|
445
|
-
const o =
|
|
446
|
+
}, this._getSmoothedAngle = function(n, s, a, r = t.TWO_PI) {
|
|
447
|
+
const o = t._orderAngle(n, s, r), f = o.left, d = o.right;
|
|
446
448
|
o.left = 0, o.right -= f, o.right < 0 && (o.right += r);
|
|
447
449
|
let u = d == s ? (1 - a) * o.right + a * o.left : a * o.right + (1 - a) * o.left;
|
|
448
450
|
return u += f, u >= r && (u -= r), u;
|
|
449
451
|
}, this.updateAlphaOffset = function() {
|
|
450
|
-
|
|
452
|
+
t.initialOffset = !1;
|
|
451
453
|
}, this.dispose = function() {
|
|
452
|
-
|
|
454
|
+
t.disconnect();
|
|
453
455
|
}, this.getAlpha = function() {
|
|
454
|
-
const { deviceOrientation: n } =
|
|
455
|
-
return n && n.alpha ? g.degToRad(n.alpha) +
|
|
456
|
+
const { deviceOrientation: n } = t;
|
|
457
|
+
return n && n.alpha ? g.degToRad(n.alpha) + t.alphaOffset : 0;
|
|
456
458
|
}, this.getBeta = function() {
|
|
457
|
-
const { deviceOrientation: n } =
|
|
459
|
+
const { deviceOrientation: n } = t;
|
|
458
460
|
return n && n.beta ? g.degToRad(n.beta) : 0;
|
|
459
461
|
}, this.getGamma = function() {
|
|
460
|
-
const { deviceOrientation: n } =
|
|
462
|
+
const { deviceOrientation: n } = t;
|
|
461
463
|
return n && n.gamma ? g.degToRad(n.gamma) : 0;
|
|
462
464
|
}, this.createObtainPermissionGestureDialog = function() {
|
|
463
465
|
const n = document.createElement("div");
|
|
@@ -525,18 +527,18 @@ class V extends R {
|
|
|
525
527
|
o.style[l] = _[l];
|
|
526
528
|
}
|
|
527
529
|
n.appendChild(s), s.appendChild(a), s.appendChild(r), a.appendChild(
|
|
528
|
-
document.createTextNode(
|
|
530
|
+
document.createTextNode(T)
|
|
529
531
|
);
|
|
530
532
|
const f = () => {
|
|
531
533
|
this.requestOrientationPermissions(), n.style.display = "none";
|
|
532
534
|
};
|
|
533
535
|
o.addEventListener("click", f), o.appendChild(document.createTextNode("OK")), r.appendChild(o), document.body.appendChild(n);
|
|
534
536
|
}, this.obtainPermissionGesture = function() {
|
|
535
|
-
this.preferConfirmDialog === !0 ? window.confirm(
|
|
537
|
+
this.preferConfirmDialog === !0 ? window.confirm(T) && this.requestOrientationPermissions() : this.createObtainPermissionGestureDialog();
|
|
536
538
|
};
|
|
537
539
|
}
|
|
538
|
-
on(
|
|
539
|
-
this.eventEmitter.on(
|
|
540
|
+
on(e, i) {
|
|
541
|
+
this.eventEmitter.on(e, i);
|
|
540
542
|
}
|
|
541
543
|
/**
|
|
542
544
|
* Initialise device orientation controls.
|
|
@@ -560,11 +562,11 @@ class j {
|
|
|
560
562
|
* @param {THREE.WebGLRenderer} - The Three.js renderer on which the click
|
|
561
563
|
* events will be handled.
|
|
562
564
|
*/
|
|
563
|
-
constructor(
|
|
564
|
-
this.raycaster = new m.Raycaster(), this.normalisedMousePosition = new m.Vector2(null, null),
|
|
565
|
+
constructor(e) {
|
|
566
|
+
this.raycaster = new m.Raycaster(), this.normalisedMousePosition = new m.Vector2(null, null), e.domElement.addEventListener("click", (i) => {
|
|
565
567
|
this.normalisedMousePosition.set(
|
|
566
|
-
i.clientX /
|
|
567
|
-
-(i.clientY /
|
|
568
|
+
i.clientX / e.domElement.clientWidth * 2 - 1,
|
|
569
|
+
-(i.clientY / e.domElement.clientHeight * 2) + 1
|
|
568
570
|
);
|
|
569
571
|
});
|
|
570
572
|
}
|
|
@@ -576,22 +578,22 @@ class j {
|
|
|
576
578
|
* cast into.
|
|
577
579
|
* @return {Array} - array of all intersected objects.
|
|
578
580
|
*/
|
|
579
|
-
raycast(
|
|
581
|
+
raycast(e, i) {
|
|
580
582
|
if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
|
|
581
|
-
this.raycaster.setFromCamera(this.normalisedMousePosition,
|
|
582
|
-
const
|
|
583
|
-
return this.normalisedMousePosition.set(null, null),
|
|
583
|
+
this.raycaster.setFromCamera(this.normalisedMousePosition, e);
|
|
584
|
+
const t = this.raycaster.intersectObjects(i.children, !1);
|
|
585
|
+
return this.normalisedMousePosition.set(null, null), t;
|
|
584
586
|
}
|
|
585
587
|
return [];
|
|
586
588
|
}
|
|
587
589
|
}
|
|
588
|
-
const U = "0.1.
|
|
590
|
+
const U = "0.1.6";
|
|
589
591
|
export {
|
|
590
592
|
j as ClickHandler,
|
|
591
593
|
V as DeviceOrientationControls,
|
|
592
594
|
A as EventEmitter,
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
595
|
+
q as LocationBased,
|
|
596
|
+
R as SphMercProjection,
|
|
597
|
+
k as Webcam,
|
|
596
598
|
U as version
|
|
597
599
|
};
|
package/dist/locar.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],c):(h=typeof globalThis<"u"?globalThis:h||self,c(h.locar={},h.THREE))})(this,(function(h,c){"use strict";function w(g){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(g){for(const i in g)if(i!=="default"){const e=Object.getOwnPropertyDescriptor(g,i);Object.defineProperty(t,i,e.get?e:{enumerable:!0,get:()=>g[i]})}}return t.default=g,Object.freeze(t)}const p=w(c);class A{constructor(){this.EARTH=4007501668e-2,this.HALF_EARTH=2003750834e-2}project(t,i){return[this.#t(t),this.#l(i)]}unproject(t){return[this.#e(t[0]),this.#s(t[1])]}#t(t){return t/180*this.HALF_EARTH}#l(t){var i=Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180);return i*this.HALF_EARTH/180}#e(t){return t/this.HALF_EARTH*180}#s(t){var i=t/this.HALF_EARTH*180;return i=180/Math.PI*(2*Math.atan(Math.exp(i*Math.PI/180))-Math.PI/2),i}getID(){return"epsg:3857"}}class M{constructor(){this.eventHandlers={}}on(t,i){this.eventHandlers[t]===void 0&&(this.eventHandlers[t]=[]),this.eventHandlers[t].push(i)}emit(t,...i){this.eventHandlers[t]?.forEach(e=>{e(...i)})}off(t,i){if(this.eventHandlers[t]){const e=this.eventHandlers[t].indexOf(i);e>-1&&this.eventHandlers[t].splice(e,1)}}}class b extends M{#t;#l;#e;#s;#c;#o;#i;#r;#a;#n;constructor(t,i,e={},l=null){super(),this.scene=t,this.camera=i,this.#t=new A,this.#e=null,this.#s=0,this.#c=100,this.#o=null,this.setGpsOptions(e),this.#i=null,this.#r=0,this.#a=0,this.#n=l}setProjection(t){this.#t=t}setGpsOptions(t={}){t.gpsMinDistance!==void 0&&(this.#s=t.gpsMinDistance),t.gpsMinAccuracy!==void 0&&(this.#c=t.gpsMinAccuracy)}async startGps(){if(this.#n){const i=await(await this.#n.sendData("/gps/start",{gpsMinDistance:this.#s,gpsMinAccuracy:this.#c})).json();this.#a=i.session}return this.#o===null?(this.#o=navigator.geolocation.watchPosition(t=>{this.#h(t)},t=>{this.emit("gpserror",t)},{enableHighAccuracy:!0}),!0):!1}stopGps(){return this.#o!==null?(navigator.geolocation.clearWatch(this.#o),this.#o=null,!0):!1}fakeGps(t,i,e=null,l=0){e!==null&&this.setElevation(e),this.#h({coords:{longitude:t,latitude:i,accuracy:l}})}lonLatToWorldCoords(t,i){const e=this.#t.project(t,i);if(this.#i)e[0]-=this.#i[0],e[1]-=this.#i[1];else throw"No initial position determined";return[e[0],-e[1]]}add(t,i,e,l,m={}){t.properties=m,this.#d(t,i,e,l),this.scene.add(t),this.#n?.sendData("/object/new",{position:t.position,x:t.position.x,z:t.position.z,session:this.#a,properties:m})}#d(t,i,e,l){const m=this.lonLatToWorldCoords(i,e);l!==void 0&&(t.position.y=l),[t.position.x,t.position.z]=m}setElevation(t){this.camera.position.y=t}#u(t,i){this.#i=this.#t.project(t,i)}#h(t){let i=Number.MAX_VALUE;this.#r++,this.#n?.sendData("/gps/new",{gpsCount:this.#r,lat:t.coords.latitude,lon:t.coords.longitude,acc:t.coords.accuracy,session:this.#a}),t.coords.accuracy<=this.#c&&(this.#e===null?this.#e={latitude:t.coords.latitude,longitude:t.coords.longitude}:i=this.#g(this.#e,t.coords),i>=this.#s&&(this.#e.longitude=t.coords.longitude,this.#e.latitude=t.coords.latitude,this.#i||(this.#u(t.coords.longitude,t.coords.latitude),this.#n?.sendData("/worldorigin/new",{gpsCount:this.#r,lat:t.coords.latitude,lon:t.coords.longitude,session:this.#a,initialPosition:this.#i})),this.#d(this.camera,t.coords.longitude,t.coords.latitude),this.#n?.sendData("/gps/accepted",{gpsCount:this.#r,cameraX:this.camera.position.x,cameraZ:this.camera.position.z,session:this.#a,distMoved:i}),this.emit("gpsupdate",{position:t,distMoved:i})))}#g(t,i){const e=p.MathUtils.degToRad(i.longitude-t.longitude),l=p.MathUtils.degToRad(i.latitude-t.latitude),m=Math.sin(l/2)*Math.sin(l/2)+Math.cos(p.MathUtils.degToRad(t.latitude))*Math.cos(p.MathUtils.degToRad(i.latitude))*(Math.sin(e/2)*Math.sin(e/2));return 2*Math.atan2(Math.sqrt(m),Math.sqrt(1-m))*6371e3}getLastKnownLocation(){return this.#e}}class D extends M{#t;constructor(t={video:{facingMode:"environment"}},i){super(),this.sceneWebcam=new p.Scene,i?this.#t=document.querySelector(i):(this.#t=document.createElement("video"),this.#t.setAttribute("autoplay",!0),this.#t.setAttribute("playsinline",!0),this.#t.style.display="none",document.body.appendChild(this.#t)),this.texture=new p.VideoTexture(this.#t),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia?navigator.mediaDevices.getUserMedia(t).then(e=>{this.#t.addEventListener("loadedmetadata",()=>{this.#t.setAttribute("width",this.#t.videoWidth),this.#t.setAttribute("height",this.#t.videoHeight),this.#t.play(),this.emit("webcamstarted",{texture:this.texture})}),this.#t.srcObject=e}).catch(e=>{this.emit("webcamerror",{code:e.name,message:e.message})}):this.emit("webcamerror",{code:"LOCAR_NO_MEDIA_DEVICES_API",message:"Media devices API not supported"})}dispose(){this.texture.dispose()}}const S="locar-device-orientation-permission-modal",T="locar-device-orientation-permission-button",R="locar-device-orientation-permission-message",N="locar-device-orientation-permission-inner",L="locar-device-orientation-permission-button-inner",P="This immersive website requires access to your device motion sensors.",I=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,x=new c.Vector3(0,0,1),_=new c.Euler,F=new c.Quaternion,H=new c.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5));class U extends c.EventDispatcher{constructor(t,i={}){super(),this.eventEmitter=new M;const e=this;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation=null,this.screenOrientation=0,this.alphaOffset=0,this.orientationOffset=0,this.initialOffset=null,this.lastCompassY=void 0,this.lastOrientation=null,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=i.smoothingFactor||1,this.enablePermissionDialog=i.enablePermissionDialog??!0,this.enableInlineStyling=i.enableStyling??!0,this.preferConfirmDialog=i.preferConfirmDialog??!1;const l=function({alpha:n,beta:s,gamma:a,webkitCompassHeading:r}){if(I){const o=360-r;e.alphaOffset=c.MathUtils.degToRad(o-n),e.deviceOrientation={alpha:n,beta:s,gamma:a,webkitCompassHeading:r}}else n<0&&(n+=360),e.deviceOrientation={alpha:n,beta:s,gamma:a};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:t.rotation}}))},m=function(){e.screenOrientation=window.orientation||0,I&&(e.screenOrientation===90?e.orientationOffset=-e.HALF_PI:e.screenOrientation===-90?e.orientationOffset=e.HALF_PI:e.orientationOffset=0)},E=function(n,s,a,r,o){_.set(a,s,-r,"YXZ"),n.setFromEuler(_),n.multiply(H),n.multiply(F.setFromAxisAngle(x,-o))};this.connect=function(){m(),window.addEventListener("orientationchange",m),window.addEventListener(e.orientationChangeEventName,l),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",m),window.removeEventListener(e.orientationChangeEventName,l),e.enabled=!1,e.initialOffset=!1,e.deviceOrientation=null},this.requestOrientationPermissions=function(){window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(n=>{n==="granted"?this.eventEmitter.emit("deviceorientationgranted",{target:this}):this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_PERMISSION_DENIED",message:"Permission for device orientation denied - AR will not work correctly"})}).catch(function(n){this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_PERMISSION_FAILED",message:"Permission request for device orientation failed - AR will not work correctly",error:JSON.stringify(n,null,2)})}):this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_INTERNAL_ERROR",message:"Internal error: no requestPermission() found although requestOrientationPermissions() was called - please raise an issue on GitHub"})},this.update=function({theta:n=0}={theta:0}){if(e.enabled===!1)return;const s=e.deviceOrientation;if(s){let a=s.alpha?c.MathUtils.degToRad(s.alpha)+e.alphaOffset:0,r=s.beta?c.MathUtils.degToRad(s.beta):0,o=s.gamma?c.MathUtils.degToRad(s.gamma):0;const v=e.screenOrientation?c.MathUtils.degToRad(e.screenOrientation):0;if(e.smoothingFactor<1){if(e.lastOrientation){const u=e.smoothingFactor;a=e._getSmoothedAngle(a,e.lastOrientation.alpha,u),r=e._getSmoothedAngle(r+Math.PI,e.lastOrientation.beta,u),o=e._getSmoothedAngle(o+e.HALF_PI,e.lastOrientation.gamma,u,Math.PI)}else r+=Math.PI,o+=e.HALF_PI;e.lastOrientation={alpha:a,beta:r,gamma:o}}if(I){const u=new c.Quaternion;E(u,a,e.smoothingFactor<1?r-Math.PI:r,e.smoothingFactor<1?o-Math.PI/2:o,v);const f=new c.Euler().setFromQuaternion(u,"YXZ");let O=c.MathUtils.degToRad(360-s.webkitCompassHeading);e.smoothingFactor<1&&e.lastCompassY!==void 0&&(O=e._getSmoothedAngle(O,e.lastCompassY,e.smoothingFactor)),e.lastCompassY=O,f.y=O+(e.orientationOffset||0),u.setFromEuler(f),e.object.quaternion.copy(u)}else E(e.object.quaternion,I?a+e.alphaOffset:a,e.smoothingFactor<1?r-Math.PI:r,e.smoothingFactor<1?o-Math.PI/2:o,v)}},this.getCorrectedHeading=function(){const{deviceOrientation:n}=e;if(!n)return 0;let s=0;return I?(s=360-n.webkitCompassHeading,e.orientationOffset&&(s+=e.orientationOffset*(180/Math.PI),s=(s+360)%360)):(n.absolute===!0||e.orientationChangeEventName,s=n.alpha?n.alpha:0,s=(360-s)%360,s<0&&(s+=360)),s},this._orderAngle=function(n,s,a=e.TWO_PI){return s>n&&Math.abs(s-n)<a/2||n>s&&Math.abs(s-n)>a/2?{left:n,right:s}:{left:s,right:n}},this._getSmoothedAngle=function(n,s,a,r=e.TWO_PI){const o=e._orderAngle(n,s,r),v=o.left,u=o.right;o.left=0,o.right-=v,o.right<0&&(o.right+=r);let f=u==s?(1-a)*o.right+a*o.left:a*o.right+(1-a)*o.left;return f+=v,f>=r&&(f-=r),f},this.updateAlphaOffset=function(){e.initialOffset=!1},this.dispose=function(){e.disconnect()},this.getAlpha=function(){const{deviceOrientation:n}=e;return n&&n.alpha?c.MathUtils.degToRad(n.alpha)+e.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:n}=e;return n&&n.beta?c.MathUtils.degToRad(n.beta):0},this.getGamma=function(){const{deviceOrientation:n}=e;return n&&n.gamma?c.MathUtils.degToRad(n.gamma):0},this.createObtainPermissionGestureDialog=function(){const n=document.createElement("div");n.classList.add(S);const s=document.createElement("div");s.classList.add(N);const a=document.createElement("div");a.classList.add(R);const r=document.createElement("div");r.classList.add(L);const o=document.createElement("button");if(o.classList.add(T),document.body.appendChild(n),this.enableInlineStyling===!0){const u={fontFamily:"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",display:"flex",position:"fixed",zIndex:1e5,justifyContent:"center",alignItems:"center",backgroundColor:"rgba(0,0,0,0.2)",inset:0,padding:"20px"},f={backgroundColor:"rgba(220, 220, 220, 0.85)",padding:"6px 0",borderRadius:"10px",width:"100%",maxWidth:"400px"},O={padding:"10px 12px",textAlign:"center",fontWeight:400,fontSize:"13px",display:"flex",justifyContent:"center",alignItems:"center"},y={display:"block",textAlign:"center",textDecoration:"none",borderTop:"rgb(180,180,180) solid 1px"},C={display:"block",width:"100%",textAlign:"center",appearance:"none",background:"none",border:"none",outline:"none",padding:"10px",fontWeight:400,fontSize:"16px",color:"#2e7cf1",cursor:"pointer"};for(let d in u)n.style[d]=u[d];for(let d in f)s.style[d]=f[d];for(let d in O)a.style[d]=O[d];for(let d in y)r.style[d]=y[d];for(let d in C)o.style[d]=C[d]}n.appendChild(s),s.appendChild(a),s.appendChild(r),a.appendChild(document.createTextNode(P));const v=()=>{this.requestOrientationPermissions(),n.style.display="none"};o.addEventListener("click",v),o.appendChild(document.createTextNode("OK")),r.appendChild(o),document.body.appendChild(n)},this.obtainPermissionGesture=function(){this.preferConfirmDialog===!0?window.confirm(P)&&this.requestOrientationPermissions():this.createObtainPermissionGestureDialog()}}on(t,i){this.eventEmitter.on(t,i)}init(){window.DeviceOrientationEvent===void 0?this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_NOT_SUPPORTED",message:"Device orientation API not supported"}):window.isSecureContext===!1?this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_NO_HTTPS",message:"DeviceOrientationEvent is only available in secure contexts (https)"}):typeof window.DeviceOrientationEvent.requestPermission=="function"&&this.enablePermissionDialog?this.obtainPermissionGesture():this.eventEmitter.emit("deviceorientationgranted",{target:this})}}class j{constructor(t){this.raycaster=new p.Raycaster,this.normalisedMousePosition=new p.Vector2(null,null),t.domElement.addEventListener("click",i=>{this.normalisedMousePosition.set(i.clientX/t.domElement.clientWidth*2-1,-(i.clientY/t.domElement.clientHeight*2)+1)})}raycast(t,i){if(this.normalisedMousePosition.x!==null&&this.normalisedMousePosition.y!==null){this.raycaster.setFromCamera(this.normalisedMousePosition,t);const e=this.raycaster.intersectObjects(i.children,!1);return this.normalisedMousePosition.set(null,null),e}return[]}}const q="0.1.5";h.ClickHandler=j,h.DeviceOrientationControls=U,h.EventEmitter=M,h.LocationBased=b,h.SphMercProjection=A,h.Webcam=D,h.version=q,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(h,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],c):(h=typeof globalThis<"u"?globalThis:h||self,c(h.locar={},h.THREE))})(this,(function(h,c){"use strict";function b(g){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(g){for(const i in g)if(i!=="default"){const t=Object.getOwnPropertyDescriptor(g,i);Object.defineProperty(e,i,t.get?t:{enumerable:!0,get:()=>g[i]})}}return e.default=g,Object.freeze(e)}const p=b(c);class A{constructor(){this.EARTH=4007501668e-2,this.HALF_EARTH=2003750834e-2}project(e,i){return[this.#t(e),this.#l(i)]}unproject(e){return[this.#e(e[0]),this.#s(e[1])]}#t(e){return e/180*this.HALF_EARTH}#l(e){var i=Math.log(Math.tan((90+e)*Math.PI/360))/(Math.PI/180);return i*this.HALF_EARTH/180}#e(e){return e/this.HALF_EARTH*180}#s(e){var i=e/this.HALF_EARTH*180;return i=180/Math.PI*(2*Math.atan(Math.exp(i*Math.PI/180))-Math.PI/2),i}getID(){return"epsg:3857"}}class M{constructor(){this.eventHandlers={}}on(e,i){this.eventHandlers[e]===void 0&&(this.eventHandlers[e]=[]),this.eventHandlers[e].push(i)}emit(e,...i){this.eventHandlers[e]?.forEach(t=>{t(...i)})}off(e,i){if(this.eventHandlers[e]){const t=this.eventHandlers[e].indexOf(i);t>-1&&this.eventHandlers[e].splice(t,1)}}}class w extends M{#t;#l;#e;#s;#c;#o;#i;#r;#a;#n;constructor(e,i,t={},l=null){super(),this.scene=e,this.camera=i,this.#t=new A,this.#e=null,this.#s=0,this.#c=100,this.#o=null,this.setGpsOptions(t),this.#i=null,this.#r=0,this.#a=0,this.#n=l}setProjection(e){this.#t=e}setGpsOptions(e={}){e.gpsMinDistance!==void 0&&(this.#s=e.gpsMinDistance),e.gpsMinAccuracy!==void 0&&(this.#c=e.gpsMinAccuracy)}async startGps(){if(this.#n){const i=await(await this.#n.sendData("/gps/start",{gpsMinDistance:this.#s,gpsMinAccuracy:this.#c})).json();this.#a=i.session}return this.#o===null?(this.#o=navigator.geolocation.watchPosition(e=>{this.#h(e)},e=>{this.emit("gpserror",e)},{enableHighAccuracy:!0}),!0):!1}stopGps(){return this.#o!==null?(navigator.geolocation.clearWatch(this.#o),this.#o=null,!0):!1}fakeGps(e,i,t=null,l=0){t!==null&&this.setElevation(t),this.#h({coords:{longitude:e,latitude:i,accuracy:l}})}lonLatToWorldCoords(e,i){const t=this.#t.project(e,i);if(this.#i)t[0]-=this.#i[0],t[1]-=this.#i[1];else throw"No initial position determined";return[t[0],-t[1]]}add(e,i,t,l,m={}){e.properties=m,this.#d(e,i,t,l),this.scene.add(e),this.#n?.sendData("/object/new",{position:e.position,x:e.position.x,z:e.position.z,session:this.#a,properties:m})}#d(e,i,t,l){const m=this.lonLatToWorldCoords(i,t);l!==void 0&&(e.position.y=l),[e.position.x,e.position.z]=m}setElevation(e){this.camera.position.y=e}#u(e,i){this.#i=this.#t.project(e,i)}#h(e){let i=Number.MAX_VALUE;this.#r++,this.#n?.sendData("/gps/new",{gpsCount:this.#r,lat:e.coords.latitude,lon:e.coords.longitude,acc:e.coords.accuracy,session:this.#a}),e.coords.accuracy<=this.#c&&(this.#e===null?this.#e={latitude:e.coords.latitude,longitude:e.coords.longitude}:i=this.#g(this.#e,e.coords),i>=this.#s&&(this.#e.longitude=e.coords.longitude,this.#e.latitude=e.coords.latitude,this.#i||(this.#u(e.coords.longitude,e.coords.latitude),this.#n?.sendData("/worldorigin/new",{gpsCount:this.#r,lat:e.coords.latitude,lon:e.coords.longitude,session:this.#a,initialPosition:this.#i})),this.#d(this.camera,e.coords.longitude,e.coords.latitude),this.#n?.sendData("/gps/accepted",{gpsCount:this.#r,cameraX:this.camera.position.x,cameraZ:this.camera.position.z,session:this.#a,distMoved:i}),this.emit("gpsupdate",{position:e,distMoved:i})))}#g(e,i){const t=p.MathUtils.degToRad(i.longitude-e.longitude),l=p.MathUtils.degToRad(i.latitude-e.latitude),m=Math.sin(l/2)*Math.sin(l/2)+Math.cos(p.MathUtils.degToRad(e.latitude))*Math.cos(p.MathUtils.degToRad(i.latitude))*(Math.sin(t/2)*Math.sin(t/2));return 2*Math.atan2(Math.sqrt(m),Math.sqrt(1-m))*6371e3}getLastKnownLocation(){return this.#e}}class T extends M{#t;constructor(e={video:{facingMode:"environment"}},i){super(),this.sceneWebcam=new p.Scene,i?this.#t=document.querySelector(i):(this.#t=document.createElement("video"),this.#t.setAttribute("autoplay",!0),this.#t.setAttribute("playsinline",!0),this.#t.style.display="none",document.body.appendChild(this.#t)),this.texture=new p.VideoTexture(this.#t),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia?navigator.mediaDevices.getUserMedia(e).then(t=>{this.#t.addEventListener("loadedmetadata",()=>{this.#t.setAttribute("width",this.#t.videoWidth),this.#t.setAttribute("height",this.#t.videoHeight),this.#t.play(),this.emit("webcamstarted",{texture:this.texture})}),this.#t.srcObject=t}).catch(t=>{this.emit("webcamerror",{code:t.name,message:t.message})}):this.emit("webcamerror",{code:"LOCAR_NO_MEDIA_DEVICES_API",message:"Media devices API not supported"})}dispose(){this.texture.dispose()}}const D="locar-device-orientation-permission-modal",S="locar-device-orientation-permission-button",R="locar-device-orientation-permission-message",N="locar-device-orientation-permission-inner",L="locar-device-orientation-permission-button-inner",_="This immersive website requires access to your device motion sensors.",I=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,x=new c.Vector3(0,0,1),P=new c.Euler,F=new c.Quaternion,H=new c.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5));class U extends c.EventDispatcher{constructor(e,i={}){super(),this.eventEmitter=new M;const t=this;this.object=e,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation=null,this.screenOrientation=0,this.alphaOffset=0,this.orientationOffset=0,this.initialOffset=null,this.lastCompassY=void 0,this.lastOrientation=null,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=i.smoothingFactor||1,this.enablePermissionDialog=i.enablePermissionDialog??!0,this.enableInlineStyling=i.enableStyling??!0,this.preferConfirmDialog=i.preferConfirmDialog??!1,this.orientationChangeThreshold=i.orientationChangeThreshold??0;const l=function({alpha:n,beta:s,gamma:a,webkitCompassHeading:r}){if(I){const o=360-r;t.alphaOffset=c.MathUtils.degToRad(o-n),t.deviceOrientation={alpha:n,beta:s,gamma:a,webkitCompassHeading:r}}else n<0&&(n+=360),t.deviceOrientation={alpha:n,beta:s,gamma:a};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:e.rotation}}))},m=function(){t.screenOrientation=window.orientation||0,I&&(t.screenOrientation===90?t.orientationOffset=-t.HALF_PI:t.screenOrientation===-90?t.orientationOffset=t.HALF_PI:t.orientationOffset=0)},E=function(n,s,a,r,o){P.set(a,s,-r,"YXZ"),n.setFromEuler(P),n.multiply(H),n.multiply(F.setFromAxisAngle(x,-o))};this.connect=function(){m(),window.addEventListener("orientationchange",m),window.addEventListener(t.orientationChangeEventName,l),t.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",m),window.removeEventListener(t.orientationChangeEventName,l),t.enabled=!1,t.initialOffset=!1,t.deviceOrientation=null},this.requestOrientationPermissions=function(){window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(n=>{n==="granted"?this.eventEmitter.emit("deviceorientationgranted",{target:this}):this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_PERMISSION_DENIED",message:"Permission for device orientation denied - AR will not work correctly"})}).catch(function(n){this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_PERMISSION_FAILED",message:"Permission request for device orientation failed - AR will not work correctly",error:JSON.stringify(n,null,2)})}):this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_INTERNAL_ERROR",message:"Internal error: no requestPermission() found although requestOrientationPermissions() was called - please raise an issue on GitHub"})},this.update=function({theta:n=0}={theta:0}){if(t.enabled===!1)return;const s=t.deviceOrientation;if(s){let a=s.alpha?c.MathUtils.degToRad(s.alpha)+t.alphaOffset:0,r=s.beta?c.MathUtils.degToRad(s.beta):0,o=s.gamma?c.MathUtils.degToRad(s.gamma):0;const O=t.screenOrientation?c.MathUtils.degToRad(t.screenOrientation):0;if(t.smoothingFactor<1)if(t.lastOrientation){const u=t.smoothingFactor;a=t._getSmoothedAngle(a,t.lastOrientation.alpha,u),r=t._getSmoothedAngle(r+Math.PI,t.lastOrientation.beta,u),o=t._getSmoothedAngle(o+t.HALF_PI,t.lastOrientation.gamma,u,Math.PI)}else r+=Math.PI,o+=t.HALF_PI;if(t.lastOrientation&&(a=t._calcAngleWithThreshold(a,t.lastOrientation.alpha),r=t._calcAngleWithThreshold(r,t.lastOrientation.beta),o=t._calcAngleWithThreshold(o,t.lastOrientation.gamma)),I){const u=new c.Quaternion;E(u,a,t.smoothingFactor<1?r-Math.PI:r,t.smoothingFactor<1?o-Math.PI/2:o,O);const f=new c.Euler().setFromQuaternion(u,"YXZ");let v=c.MathUtils.degToRad(360-s.webkitCompassHeading);t.smoothingFactor<1&&t.lastCompassY!==void 0&&(v=t._getSmoothedAngle(v,t.lastCompassY,t.smoothingFactor)),t.lastCompassY=v,f.y=v+(t.orientationOffset||0),u.setFromEuler(f),t.object.quaternion.copy(u)}else E(t.object.quaternion,I?a+t.alphaOffset:a,t.smoothingFactor<1?r-Math.PI:r,t.smoothingFactor<1?o-Math.PI/2:o,O);t.lastOrientation={alpha:a,beta:r,gamma:o}}},this.getCorrectedHeading=function(){const{deviceOrientation:n}=t;if(!n)return 0;let s=0;return I?(s=360-n.webkitCompassHeading,t.orientationOffset&&(s+=t.orientationOffset*(180/Math.PI),s=(s+360)%360)):(n.absolute===!0||t.orientationChangeEventName,s=n.alpha?n.alpha:0,s=(360-s)%360,s<0&&(s+=360)),s},this._calcAngleWithThreshold=function(n,s){return Math.abs(n-s)<t.orientationChangeThreshold?s:n},this._orderAngle=function(n,s,a=t.TWO_PI){return s>n&&Math.abs(s-n)<a/2||n>s&&Math.abs(s-n)>a/2?{left:n,right:s}:{left:s,right:n}},this._getSmoothedAngle=function(n,s,a,r=t.TWO_PI){const o=t._orderAngle(n,s,r),O=o.left,u=o.right;o.left=0,o.right-=O,o.right<0&&(o.right+=r);let f=u==s?(1-a)*o.right+a*o.left:a*o.right+(1-a)*o.left;return f+=O,f>=r&&(f-=r),f},this.updateAlphaOffset=function(){t.initialOffset=!1},this.dispose=function(){t.disconnect()},this.getAlpha=function(){const{deviceOrientation:n}=t;return n&&n.alpha?c.MathUtils.degToRad(n.alpha)+t.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:n}=t;return n&&n.beta?c.MathUtils.degToRad(n.beta):0},this.getGamma=function(){const{deviceOrientation:n}=t;return n&&n.gamma?c.MathUtils.degToRad(n.gamma):0},this.createObtainPermissionGestureDialog=function(){const n=document.createElement("div");n.classList.add(D);const s=document.createElement("div");s.classList.add(N);const a=document.createElement("div");a.classList.add(R);const r=document.createElement("div");r.classList.add(L);const o=document.createElement("button");if(o.classList.add(S),document.body.appendChild(n),this.enableInlineStyling===!0){const u={fontFamily:"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",display:"flex",position:"fixed",zIndex:1e5,justifyContent:"center",alignItems:"center",backgroundColor:"rgba(0,0,0,0.2)",inset:0,padding:"20px"},f={backgroundColor:"rgba(220, 220, 220, 0.85)",padding:"6px 0",borderRadius:"10px",width:"100%",maxWidth:"400px"},v={padding:"10px 12px",textAlign:"center",fontWeight:400,fontSize:"13px",display:"flex",justifyContent:"center",alignItems:"center"},y={display:"block",textAlign:"center",textDecoration:"none",borderTop:"rgb(180,180,180) solid 1px"},C={display:"block",width:"100%",textAlign:"center",appearance:"none",background:"none",border:"none",outline:"none",padding:"10px",fontWeight:400,fontSize:"16px",color:"#2e7cf1",cursor:"pointer"};for(let d in u)n.style[d]=u[d];for(let d in f)s.style[d]=f[d];for(let d in v)a.style[d]=v[d];for(let d in y)r.style[d]=y[d];for(let d in C)o.style[d]=C[d]}n.appendChild(s),s.appendChild(a),s.appendChild(r),a.appendChild(document.createTextNode(_));const O=()=>{this.requestOrientationPermissions(),n.style.display="none"};o.addEventListener("click",O),o.appendChild(document.createTextNode("OK")),r.appendChild(o),document.body.appendChild(n)},this.obtainPermissionGesture=function(){this.preferConfirmDialog===!0?window.confirm(_)&&this.requestOrientationPermissions():this.createObtainPermissionGestureDialog()}}on(e,i){this.eventEmitter.on(e,i)}init(){window.DeviceOrientationEvent===void 0?this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_NOT_SUPPORTED",message:"Device orientation API not supported"}):window.isSecureContext===!1?this.eventEmitter.emit("deviceorientationerror",{code:"LOCAR_DEVICE_ORIENTATION_NO_HTTPS",message:"DeviceOrientationEvent is only available in secure contexts (https)"}):typeof window.DeviceOrientationEvent.requestPermission=="function"&&this.enablePermissionDialog?this.obtainPermissionGesture():this.eventEmitter.emit("deviceorientationgranted",{target:this})}}class W{constructor(e){this.raycaster=new p.Raycaster,this.normalisedMousePosition=new p.Vector2(null,null),e.domElement.addEventListener("click",i=>{this.normalisedMousePosition.set(i.clientX/e.domElement.clientWidth*2-1,-(i.clientY/e.domElement.clientHeight*2)+1)})}raycast(e,i){if(this.normalisedMousePosition.x!==null&&this.normalisedMousePosition.y!==null){this.raycaster.setFromCamera(this.normalisedMousePosition,e);const t=this.raycaster.intersectObjects(i.children,!1);return this.normalisedMousePosition.set(null,null),t}return[]}}const j="0.1.6";h.ClickHandler=W,h.DeviceOrientationControls=U,h.EventEmitter=M,h.LocationBased=w,h.SphMercProjection=A,h.Webcam=T,h.version=j,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
|