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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as m from "three";
2
- import { Vector3 as C, Euler as w, Quaternion as I, EventDispatcher as R, MathUtils as g } from "three";
3
- class T {
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(t, i) {
17
- return [this.#t(t), this.#l(i)];
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(t) {
25
- return [this.#e(t[0]), this.#s(t[1])];
24
+ unproject(e) {
25
+ return [this.#e(e[0]), this.#s(e[1])];
26
26
  }
27
- #t(t) {
28
- return t / 180 * this.HALF_EARTH;
27
+ #t(e) {
28
+ return e / 180 * this.HALF_EARTH;
29
29
  }
30
- #l(t) {
31
- var i = Math.log(Math.tan((90 + t) * Math.PI / 360)) / (Math.PI / 180);
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(t) {
35
- return t / this.HALF_EARTH * 180;
34
+ #e(e) {
35
+ return e / this.HALF_EARTH * 180;
36
36
  }
37
- #s(t) {
38
- var i = t / this.HALF_EARTH * 180;
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(t, i) {
59
- this.eventHandlers[t] === void 0 && (this.eventHandlers[t] = []), this.eventHandlers[t].push(i);
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(t, ...i) {
67
- this.eventHandlers[t]?.forEach((e) => {
68
- e(...i);
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(t, i) {
77
- if (this.eventHandlers[t]) {
78
- const e = this.eventHandlers[t].indexOf(i);
79
- e > -1 && this.eventHandlers[t].splice(e, 1);
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 k extends A {
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(t, i, e = {}, c = null) {
104
- super(), this.scene = t, this.camera = i, this.#t = new T(), 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 = c;
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(t) {
113
- this.#t = 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(t = {}) {
123
- t.gpsMinDistance !== void 0 && (this.#s = t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && (this.#c = t.gpsMinAccuracy);
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
- (t) => {
140
- this.#h(t);
139
+ (e) => {
140
+ this.#h(e);
141
141
  },
142
- (t) => {
143
- this.emit("gpserror", t);
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(t, i, e = null, c = 0) {
168
- e !== null && this.setElevation(e), this.#h({
167
+ fakeGps(e, i, t = null, c = 0) {
168
+ t !== null && this.setElevation(t), this.#h({
169
169
  coords: {
170
- longitude: t,
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(t, i) {
188
- const e = this.#t.project(t, i);
187
+ lonLatToWorldCoords(e, i) {
188
+ const t = this.#t.project(e, i);
189
189
  if (this.#i)
190
- e[0] -= this.#i[0], e[1] -= this.#i[1];
190
+ t[0] -= this.#i[0], t[1] -= this.#i[1];
191
191
  else
192
192
  throw "No initial position determined";
193
- return [e[0], -e[1]];
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(t, i, e, c, h = {}) {
206
- t.properties = h, this.#d(t, i, e, c), this.scene.add(t), this.#n?.sendData("/object/new", {
207
- position: t.position,
208
- x: t.position.x,
209
- z: t.position.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(t, i, e, c) {
215
- const h = this.lonLatToWorldCoords(i, e);
216
- c !== void 0 && (t.position.y = c), [t.position.x, t.position.z] = h;
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(t) {
223
- this.camera.position.y = t;
222
+ setElevation(e) {
223
+ this.camera.position.y = e;
224
224
  }
225
- #u(t, i) {
226
- this.#i = this.#t.project(t, i);
225
+ #u(e, i) {
226
+ this.#i = this.#t.project(e, i);
227
227
  }
228
- #h(t) {
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: t.coords.latitude,
233
- lon: t.coords.longitude,
234
- acc: t.coords.accuracy,
232
+ lat: e.coords.latitude,
233
+ lon: e.coords.longitude,
234
+ acc: e.coords.accuracy,
235
235
  session: this.#a
236
- }), t.coords.accuracy <= this.#c && (this.#e === null ? this.#e = {
237
- latitude: t.coords.latitude,
238
- longitude: t.coords.longitude
239
- } : 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(
240
- t.coords.longitude,
241
- t.coords.latitude
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: t.coords.latitude,
245
- lon: t.coords.longitude,
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
- t.coords.longitude,
251
- t.coords.latitude
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: t, distMoved: i })));
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(t, i) {
266
- const e = m.MathUtils.degToRad(i.longitude - t.longitude), c = m.MathUtils.degToRad(i.latitude - t.latitude), h = Math.sin(c / 2) * Math.sin(c / 2) + Math.cos(m.MathUtils.degToRad(t.latitude)) * Math.cos(m.MathUtils.degToRad(i.latitude)) * (Math.sin(e / 2) * Math.sin(e / 2));
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 W extends A {
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(t = { 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(t).then((e) => {
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 = e;
293
- }).catch((e) => {
292
+ }), this.#t.srcObject = t;
293
+ }).catch((t) => {
294
294
  this.emit("webcamerror", {
295
- code: e.name,
296
- message: e.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", P = "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 C(0, 0, 1), y = new w(), H = new I(), F = new I(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
312
- class V extends R {
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: currently accepts smoothingFactor, enablePermissionDialog
317
+ * @param {Object} options - options for DeviceOrientationControls:
318
+ * currently accepts smoothingFactor (< 1), enablePermissionDialog, orientationChangeThreshold (radians)
318
319
  */
319
- constructor(t, i = {}) {
320
+ constructor(e, i = {}) {
320
321
  super(), this.eventEmitter = new A();
321
- const e = this;
322
- 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 = 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;
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
- e.alphaOffset = g.degToRad(o - n), e.deviceOrientation = { alpha: n, beta: s, gamma: a, webkitCompassHeading: r };
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), e.deviceOrientation = { alpha: n, beta: s, gamma: a };
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: t.rotation }
337
+ detail: { cameraRotation: e.rotation }
337
338
  })
338
339
  );
339
340
  }, h = function() {
340
- e.screenOrientation = window.orientation || 0, O && (e.screenOrientation === 90 ? e.orientationOffset = -e.HALF_PI : e.screenOrientation === -90 ? e.orientationOffset = e.HALF_PI : e.orientationOffset = 0);
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
- y.set(a, s, -r, "YXZ"), n.setFromEuler(y), n.multiply(F), n.multiply(H.setFromAxisAngle(x, -o));
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
- e.orientationChangeEventName,
350
+ t.orientationChangeEventName,
350
351
  c
351
- ), e.enabled = !0;
352
+ ), t.enabled = !0;
352
353
  }, this.disconnect = function() {
353
354
  window.removeEventListener(
354
355
  "orientationchange",
355
356
  h
356
357
  ), window.removeEventListener(
357
- e.orientationChangeEventName,
358
+ t.orientationChangeEventName,
358
359
  c
359
- ), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
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 (e.enabled === !1) return;
380
- const s = e.deviceOrientation;
380
+ if (t.enabled === !1) return;
381
+ const s = t.deviceOrientation;
381
382
  if (s) {
382
- let a = s.alpha ? g.degToRad(s.alpha) + e.alphaOffset : 0, r = s.beta ? g.degToRad(s.beta) : 0, o = s.gamma ? g.degToRad(s.gamma) : 0;
383
- const f = e.screenOrientation ? g.degToRad(e.screenOrientation) : 0;
384
- if (e.smoothingFactor < 1) {
385
- if (e.lastOrientation) {
386
- const d = e.smoothingFactor;
387
- a = e._getSmoothedAngle(
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
- e.lastOrientation.alpha,
390
+ t.lastOrientation.alpha,
390
391
  d
391
- ), r = e._getSmoothedAngle(
392
+ ), r = t._getSmoothedAngle(
392
393
  r + Math.PI,
393
- e.lastOrientation.beta,
394
+ t.lastOrientation.beta,
394
395
  d
395
- ), o = e._getSmoothedAngle(
396
- o + e.HALF_PI,
397
- e.lastOrientation.gamma,
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 += e.HALF_PI;
403
- e.lastOrientation = {
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
- e.smoothingFactor < 1 ? r - Math.PI : r,
415
- e.smoothingFactor < 1 ? o - Math.PI / 2 : o,
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 w().setFromQuaternion(
413
+ const u = new C().setFromQuaternion(
419
414
  d,
420
415
  "YXZ"
421
416
  );
422
417
  let p = g.degToRad(360 - s.webkitCompassHeading);
423
- e.smoothingFactor < 1 && e.lastCompassY !== void 0 && (p = e._getSmoothedAngle(
418
+ t.smoothingFactor < 1 && t.lastCompassY !== void 0 && (p = t._getSmoothedAngle(
424
419
  p,
425
- e.lastCompassY,
426
- e.smoothingFactor
427
- )), e.lastCompassY = p, u.y = p + (e.orientationOffset || 0), d.setFromEuler(u), e.object.quaternion.copy(d);
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
- e.object.quaternion,
431
- O ? a + e.alphaOffset : a,
432
- e.smoothingFactor < 1 ? r - Math.PI : r,
433
- e.smoothingFactor < 1 ? o - Math.PI / 2 : o,
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 } = e;
438
+ const { deviceOrientation: n } = t;
439
439
  if (!n) return 0;
440
440
  let s = 0;
441
- return O ? (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;
442
- }, this._orderAngle = function(n, s, a = e.TWO_PI) {
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 = e.TWO_PI) {
445
- const o = e._orderAngle(n, s, r), f = o.left, d = o.right;
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
- e.initialOffset = !1;
452
+ t.initialOffset = !1;
451
453
  }, this.dispose = function() {
452
- e.disconnect();
454
+ t.disconnect();
453
455
  }, this.getAlpha = function() {
454
- const { deviceOrientation: n } = e;
455
- return n && n.alpha ? g.degToRad(n.alpha) + e.alphaOffset : 0;
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 } = e;
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 } = e;
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(P)
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(P) && this.requestOrientationPermissions() : this.createObtainPermissionGestureDialog();
537
+ this.preferConfirmDialog === !0 ? window.confirm(T) && this.requestOrientationPermissions() : this.createObtainPermissionGestureDialog();
536
538
  };
537
539
  }
538
- on(t, i) {
539
- this.eventEmitter.on(t, i);
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(t) {
564
- this.raycaster = new m.Raycaster(), this.normalisedMousePosition = new m.Vector2(null, null), t.domElement.addEventListener("click", (i) => {
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 / t.domElement.clientWidth * 2 - 1,
567
- -(i.clientY / t.domElement.clientHeight * 2) + 1
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(t, i) {
581
+ raycast(e, i) {
580
582
  if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
581
- this.raycaster.setFromCamera(this.normalisedMousePosition, t);
582
- const e = this.raycaster.intersectObjects(i.children, !1);
583
- return this.normalisedMousePosition.set(null, null), e;
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.5";
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
- k as LocationBased,
594
- T as SphMercProjection,
595
- W as Webcam,
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"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locar",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Location-based AR from AR.js.",
5
5
  "files": [
6
6
  "dist",