locar 0.1.4 → 0.1.5

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,5 +1,5 @@
1
- import * as g from "three";
2
- import { Vector3 as C, Euler as w, Quaternion as I, EventDispatcher as R, MathUtils as m } from "three";
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
3
  class T {
4
4
  /**
5
5
  * Create a SphMercProjection.
@@ -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(e, i) {
17
- return [this.#t(e), this.#l(i)];
16
+ project(t, i) {
17
+ return [this.#t(t), 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(e) {
25
- return [this.#e(e[0]), this.#s(e[1])];
24
+ unproject(t) {
25
+ return [this.#e(t[0]), this.#s(t[1])];
26
26
  }
27
- #t(e) {
28
- return e / 180 * this.HALF_EARTH;
27
+ #t(t) {
28
+ return t / 180 * this.HALF_EARTH;
29
29
  }
30
- #l(e) {
31
- var i = Math.log(Math.tan((90 + e) * Math.PI / 360)) / (Math.PI / 180);
30
+ #l(t) {
31
+ var i = Math.log(Math.tan((90 + t) * Math.PI / 360)) / (Math.PI / 180);
32
32
  return i * this.HALF_EARTH / 180;
33
33
  }
34
- #e(e) {
35
- return e / this.HALF_EARTH * 180;
34
+ #e(t) {
35
+ return t / this.HALF_EARTH * 180;
36
36
  }
37
- #s(e) {
38
- var i = e / this.HALF_EARTH * 180;
37
+ #s(t) {
38
+ var i = t / 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,16 +55,29 @@ class A {
55
55
  * @param {string} eventName - the event to handle.
56
56
  * @param {Function} eventHandler - the event handler function.
57
57
  */
58
- on(e, i) {
59
- this.eventHandlers[e] = i;
58
+ on(t, i) {
59
+ this.eventHandlers[t] === void 0 && (this.eventHandlers[t] = []), this.eventHandlers[t].push(i);
60
60
  }
61
61
  /**
62
62
  * Emit an event.
63
63
  * @param {string} eventName - the event to emit.
64
- * @param ...params - parameters to pass to the event handler.
64
+ * @param ...params - parameters to pass to the event handlers.
65
65
  */
66
- emit(e, ...i) {
67
- this.eventHandlers[e]?.call(this, ...i);
66
+ emit(t, ...i) {
67
+ this.eventHandlers[t]?.forEach((e) => {
68
+ e(...i);
69
+ });
70
+ }
71
+ /**
72
+ * Remove an event handler.
73
+ * @param {string} eventName - the event to remove a handler from.
74
+ * @param {Function} eventHandler - the event handler function to remove.
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);
80
+ }
68
81
  }
69
82
  }
70
83
  class k extends A {
@@ -87,8 +100,8 @@ class k extends A {
87
100
  * setGpsOptions() below.
88
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.
89
102
  */
90
- constructor(e, i, t = {}, c = null) {
91
- super(), this.scene = e, this.camera = i, this.#t = new T(), 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;
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;
92
105
  }
93
106
  /**
94
107
  * Set the projection to use.
@@ -96,8 +109,8 @@ class k extends A {
96
109
  * taking longitude and latitude as arguments and returning an array
97
110
  * containing easting and northing.
98
111
  */
99
- setProjection(e) {
100
- this.#t = e;
112
+ setProjection(t) {
113
+ this.#t = t;
101
114
  }
102
115
  /**
103
116
  * Set the GPS options.
@@ -106,8 +119,8 @@ class k extends A {
106
119
  * must move to process a new GPS reading, and the latter specifies the
107
120
  * minimum accuracy, in metres, for a GPS reading to be counted.
108
121
  */
109
- setGpsOptions(e = {}) {
110
- e.gpsMinDistance !== void 0 && (this.#s = e.gpsMinDistance), e.gpsMinAccuracy !== void 0 && (this.#c = e.gpsMinAccuracy);
122
+ setGpsOptions(t = {}) {
123
+ t.gpsMinDistance !== void 0 && (this.#s = t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && (this.#c = t.gpsMinAccuracy);
111
124
  }
112
125
  /**
113
126
  * Start the GPS on a real device
@@ -123,11 +136,11 @@ class k extends A {
123
136
  this.#a = i.session;
124
137
  }
125
138
  return this.#o === null ? (this.#o = navigator.geolocation.watchPosition(
126
- (e) => {
127
- this.#h(e);
139
+ (t) => {
140
+ this.#h(t);
128
141
  },
129
- (e) => {
130
- this.emit("gpserror", e);
142
+ (t) => {
143
+ this.emit("gpserror", t);
131
144
  },
132
145
  {
133
146
  enableHighAccuracy: !0
@@ -151,10 +164,10 @@ class k extends A {
151
164
  * @param {number} acc - The accuracy of the GPS reading in metres. May be
152
165
  * ignored if lower than the specified minimum accuracy.
153
166
  */
154
- fakeGps(e, i, t = null, c = 0) {
155
- t !== null && this.setElevation(t), this.#h({
167
+ fakeGps(t, i, e = null, c = 0) {
168
+ e !== null && this.setElevation(e), this.#h({
156
169
  coords: {
157
- longitude: e,
170
+ longitude: t,
158
171
  latitude: i,
159
172
  accuracy: c
160
173
  }
@@ -171,13 +184,13 @@ class k extends A {
171
184
  * @param {number} lat - The latitude.
172
185
  * @return {Array} a two member array containing the WebGL x and z coordinates
173
186
  */
174
- lonLatToWorldCoords(e, i) {
175
- const t = this.#t.project(e, i);
187
+ lonLatToWorldCoords(t, i) {
188
+ const e = this.#t.project(t, i);
176
189
  if (this.#i)
177
- t[0] -= this.#i[0], t[1] -= this.#i[1];
190
+ e[0] -= this.#i[0], e[1] -= this.#i[1];
178
191
  else
179
192
  throw "No initial position determined";
180
- return [t[0], -t[1]];
193
+ return [e[0], -e[1]];
181
194
  }
182
195
  /**
183
196
  * Add a new AR object at a given latitude, longitude and elevation.
@@ -189,68 +202,68 @@ class k extends A {
189
202
  * @param {Object} properties - properties describing the object (for example,
190
203
  * the contents of the GeoJSON properties field).
191
204
  */
192
- add(e, i, t, c, h = {}) {
193
- e.properties = h, this.#d(e, i, t, c), this.scene.add(e), this.#n?.sendData("/object/new", {
194
- position: e.position,
195
- x: e.position.x,
196
- z: e.position.z,
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,
197
210
  session: this.#a,
198
211
  properties: h
199
212
  });
200
213
  }
201
- #d(e, i, t, c) {
202
- const h = this.lonLatToWorldCoords(i, t);
203
- c !== void 0 && (e.position.y = c), [e.position.x, e.position.z] = h;
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;
204
217
  }
205
218
  /**
206
219
  * Set the elevation (y coordinate) of the camera.
207
220
  * @param {number} elev - the elevation in metres.
208
221
  */
209
- setElevation(e) {
210
- this.camera.position.y = e;
222
+ setElevation(t) {
223
+ this.camera.position.y = t;
211
224
  }
212
- #u(e, i) {
213
- this.#i = this.#t.project(e, i);
225
+ #u(t, i) {
226
+ this.#i = this.#t.project(t, i);
214
227
  }
215
- #h(e) {
228
+ #h(t) {
216
229
  let i = Number.MAX_VALUE;
217
230
  this.#r++, this.#n?.sendData("/gps/new", {
218
231
  gpsCount: this.#r,
219
- lat: e.coords.latitude,
220
- lon: e.coords.longitude,
221
- acc: e.coords.accuracy,
232
+ lat: t.coords.latitude,
233
+ lon: t.coords.longitude,
234
+ acc: t.coords.accuracy,
222
235
  session: this.#a
223
- }), e.coords.accuracy <= this.#c && (this.#e === null ? this.#e = {
224
- latitude: e.coords.latitude,
225
- longitude: e.coords.longitude
226
- } : i = this.#m(this.#e, e.coords), i >= this.#s && (this.#e.longitude = e.coords.longitude, this.#e.latitude = e.coords.latitude, this.#i || (this.#u(
227
- e.coords.longitude,
228
- e.coords.latitude
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
229
242
  ), this.#n?.sendData("/worldorigin/new", {
230
243
  gpsCount: this.#r,
231
- lat: e.coords.latitude,
232
- lon: e.coords.longitude,
244
+ lat: t.coords.latitude,
245
+ lon: t.coords.longitude,
233
246
  session: this.#a,
234
247
  initialPosition: this.#i
235
248
  })), this.#d(
236
249
  this.camera,
237
- e.coords.longitude,
238
- e.coords.latitude
250
+ t.coords.longitude,
251
+ t.coords.latitude
239
252
  ), this.#n?.sendData("/gps/accepted", {
240
253
  gpsCount: this.#r,
241
254
  cameraX: this.camera.position.x,
242
255
  cameraZ: this.camera.position.z,
243
256
  session: this.#a,
244
257
  distMoved: i
245
- }), this.emit("gpsupdate", { position: e, distMoved: i })));
258
+ }), this.emit("gpsupdate", { position: t, distMoved: i })));
246
259
  }
247
260
  /**
248
261
  * Calculate haversine distance between two lat/lon pairs.
249
262
  *
250
263
  * Taken from original A-Frame AR.js location-based components
251
264
  */
252
- #m(e, i) {
253
- const t = g.MathUtils.degToRad(i.longitude - e.longitude), c = g.MathUtils.degToRad(i.latitude - e.latitude), h = Math.sin(c / 2) * Math.sin(c / 2) + Math.cos(g.MathUtils.degToRad(e.latitude)) * Math.cos(g.MathUtils.degToRad(i.latitude)) * (Math.sin(t / 2) * Math.sin(t / 2));
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));
254
267
  return 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)) * 6371e3;
255
268
  }
256
269
  /**
@@ -272,15 +285,15 @@ class W extends A {
272
285
  * element to render the webcam feed. If a falsy value (e.g. null or
273
286
  * undefined), a video element will be created.
274
287
  */
275
- constructor(e = { video: { facingMode: "environment" } }, i) {
276
- super(), this.sceneWebcam = new g.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 g.VideoTexture(this.#t), navigator.mediaDevices && navigator.mediaDevices.getUserMedia ? navigator.mediaDevices.getUserMedia(e).then((t) => {
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) => {
277
290
  this.#t.addEventListener("loadedmetadata", () => {
278
291
  this.#t.setAttribute("width", this.#t.videoWidth), this.#t.setAttribute("height", this.#t.videoHeight), this.#t.play(), this.emit("webcamstarted", { texture: this.texture });
279
- }), this.#t.srcObject = t;
280
- }).catch((t) => {
292
+ }), this.#t.srcObject = e;
293
+ }).catch((e) => {
281
294
  this.emit("webcamerror", {
282
- code: t.name,
283
- message: t.message
295
+ code: e.name,
296
+ message: e.message
284
297
  });
285
298
  }) : this.emit("webcamerror", {
286
299
  code: "LOCAR_NO_MEDIA_DEVICES_API",
@@ -303,10 +316,10 @@ class V extends R {
303
316
  * (usually your Three.js camera)
304
317
  * @param {Object} options - options for DeviceOrientationControls: currently accepts smoothingFactor, enablePermissionDialog
305
318
  */
306
- constructor(e, i = {}) {
319
+ constructor(t, i = {}) {
307
320
  super(), this.eventEmitter = new A();
308
- const t = this;
309
- 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;
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;
310
323
  const c = function({
311
324
  alpha: n,
312
325
  beta: s,
@@ -315,16 +328,16 @@ class V extends R {
315
328
  }) {
316
329
  if (O) {
317
330
  const o = 360 - r;
318
- t.alphaOffset = m.degToRad(o - n), t.deviceOrientation = { alpha: n, beta: s, gamma: a, webkitCompassHeading: r };
331
+ e.alphaOffset = g.degToRad(o - n), e.deviceOrientation = { alpha: n, beta: s, gamma: a, webkitCompassHeading: r };
319
332
  } else
320
- n < 0 && (n += 360), t.deviceOrientation = { alpha: n, beta: s, gamma: a };
333
+ n < 0 && (n += 360), e.deviceOrientation = { alpha: n, beta: s, gamma: a };
321
334
  window.dispatchEvent(
322
335
  new CustomEvent("camera-rotation-change", {
323
- detail: { cameraRotation: e.rotation }
336
+ detail: { cameraRotation: t.rotation }
324
337
  })
325
338
  );
326
339
  }, h = function() {
327
- 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);
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);
328
341
  }, E = function(n, s, a, r, o) {
329
342
  y.set(a, s, -r, "YXZ"), n.setFromEuler(y), n.multiply(F), n.multiply(H.setFromAxisAngle(x, -o));
330
343
  };
@@ -333,17 +346,17 @@ class V extends R {
333
346
  "orientationchange",
334
347
  h
335
348
  ), window.addEventListener(
336
- t.orientationChangeEventName,
349
+ e.orientationChangeEventName,
337
350
  c
338
- ), t.enabled = !0;
351
+ ), e.enabled = !0;
339
352
  }, this.disconnect = function() {
340
353
  window.removeEventListener(
341
354
  "orientationchange",
342
355
  h
343
356
  ), window.removeEventListener(
344
- t.orientationChangeEventName,
357
+ e.orientationChangeEventName,
345
358
  c
346
- ), t.enabled = !1, t.initialOffset = !1, t.deviceOrientation = null;
359
+ ), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
347
360
  }, this.requestOrientationPermissions = function() {
348
361
  window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((n) => {
349
362
  n === "granted" ? this.eventEmitter.emit("deviceorientationgranted", {
@@ -363,31 +376,31 @@ class V extends R {
363
376
  message: "Internal error: no requestPermission() found although requestOrientationPermissions() was called - please raise an issue on GitHub"
364
377
  });
365
378
  }, this.update = function({ theta: n = 0 } = { theta: 0 }) {
366
- if (t.enabled === !1) return;
367
- const s = t.deviceOrientation;
379
+ if (e.enabled === !1) return;
380
+ const s = e.deviceOrientation;
368
381
  if (s) {
369
- let a = s.alpha ? m.degToRad(s.alpha) + t.alphaOffset : 0, r = s.beta ? m.degToRad(s.beta) : 0, o = s.gamma ? m.degToRad(s.gamma) : 0;
370
- const f = t.screenOrientation ? m.degToRad(t.screenOrientation) : 0;
371
- if (t.smoothingFactor < 1) {
372
- if (t.lastOrientation) {
373
- const d = t.smoothingFactor;
374
- a = t._getSmoothedAngle(
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(
375
388
  a,
376
- t.lastOrientation.alpha,
389
+ e.lastOrientation.alpha,
377
390
  d
378
- ), r = t._getSmoothedAngle(
391
+ ), r = e._getSmoothedAngle(
379
392
  r + Math.PI,
380
- t.lastOrientation.beta,
393
+ e.lastOrientation.beta,
381
394
  d
382
- ), o = t._getSmoothedAngle(
383
- o + t.HALF_PI,
384
- t.lastOrientation.gamma,
395
+ ), o = e._getSmoothedAngle(
396
+ o + e.HALF_PI,
397
+ e.lastOrientation.gamma,
385
398
  d,
386
399
  Math.PI
387
400
  );
388
401
  } else
389
- r += Math.PI, o += t.HALF_PI;
390
- t.lastOrientation = {
402
+ r += Math.PI, o += e.HALF_PI;
403
+ e.lastOrientation = {
391
404
  alpha: a,
392
405
  beta: r,
393
406
  gamma: o
@@ -398,54 +411,54 @@ class V extends R {
398
411
  E(
399
412
  d,
400
413
  a,
401
- t.smoothingFactor < 1 ? r - Math.PI : r,
402
- t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
414
+ e.smoothingFactor < 1 ? r - Math.PI : r,
415
+ e.smoothingFactor < 1 ? o - Math.PI / 2 : o,
403
416
  f
404
417
  );
405
418
  const u = new w().setFromQuaternion(
406
419
  d,
407
420
  "YXZ"
408
421
  );
409
- let p = m.degToRad(360 - s.webkitCompassHeading);
410
- t.smoothingFactor < 1 && t.lastCompassY !== void 0 && (p = t._getSmoothedAngle(
422
+ let p = g.degToRad(360 - s.webkitCompassHeading);
423
+ e.smoothingFactor < 1 && e.lastCompassY !== void 0 && (p = e._getSmoothedAngle(
411
424
  p,
412
- t.lastCompassY,
413
- t.smoothingFactor
414
- )), t.lastCompassY = p, u.y = p + (t.orientationOffset || 0), d.setFromEuler(u), t.object.quaternion.copy(d);
425
+ e.lastCompassY,
426
+ e.smoothingFactor
427
+ )), e.lastCompassY = p, u.y = p + (e.orientationOffset || 0), d.setFromEuler(u), e.object.quaternion.copy(d);
415
428
  } else
416
429
  E(
417
- t.object.quaternion,
418
- O ? a + t.alphaOffset : a,
419
- t.smoothingFactor < 1 ? r - Math.PI : r,
420
- t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
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,
421
434
  f
422
435
  );
423
436
  }
424
437
  }, this.getCorrectedHeading = function() {
425
- const { deviceOrientation: n } = t;
438
+ const { deviceOrientation: n } = e;
426
439
  if (!n) return 0;
427
440
  let s = 0;
428
- 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;
429
- }, this._orderAngle = function(n, s, a = t.TWO_PI) {
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) {
430
443
  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 };
431
- }, this._getSmoothedAngle = function(n, s, a, r = t.TWO_PI) {
432
- const o = t._orderAngle(n, s, r), f = o.left, d = o.right;
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;
433
446
  o.left = 0, o.right -= f, o.right < 0 && (o.right += r);
434
447
  let u = d == s ? (1 - a) * o.right + a * o.left : a * o.right + (1 - a) * o.left;
435
448
  return u += f, u >= r && (u -= r), u;
436
449
  }, this.updateAlphaOffset = function() {
437
- t.initialOffset = !1;
450
+ e.initialOffset = !1;
438
451
  }, this.dispose = function() {
439
- t.disconnect();
452
+ e.disconnect();
440
453
  }, this.getAlpha = function() {
441
- const { deviceOrientation: n } = t;
442
- return n && n.alpha ? m.degToRad(n.alpha) + t.alphaOffset : 0;
454
+ const { deviceOrientation: n } = e;
455
+ return n && n.alpha ? g.degToRad(n.alpha) + e.alphaOffset : 0;
443
456
  }, this.getBeta = function() {
444
- const { deviceOrientation: n } = t;
445
- return n && n.beta ? m.degToRad(n.beta) : 0;
457
+ const { deviceOrientation: n } = e;
458
+ return n && n.beta ? g.degToRad(n.beta) : 0;
446
459
  }, this.getGamma = function() {
447
- const { deviceOrientation: n } = t;
448
- return n && n.gamma ? m.degToRad(n.gamma) : 0;
460
+ const { deviceOrientation: n } = e;
461
+ return n && n.gamma ? g.degToRad(n.gamma) : 0;
449
462
  }, this.createObtainPermissionGestureDialog = function() {
450
463
  const n = document.createElement("div");
451
464
  n.classList.add(b);
@@ -522,8 +535,8 @@ class V extends R {
522
535
  this.preferConfirmDialog === !0 ? window.confirm(P) && this.requestOrientationPermissions() : this.createObtainPermissionGestureDialog();
523
536
  };
524
537
  }
525
- on(e, i) {
526
- this.eventEmitter.on(e, i);
538
+ on(t, i) {
539
+ this.eventEmitter.on(t, i);
527
540
  }
528
541
  /**
529
542
  * Initialise device orientation controls.
@@ -547,11 +560,11 @@ class j {
547
560
  * @param {THREE.WebGLRenderer} - The Three.js renderer on which the click
548
561
  * events will be handled.
549
562
  */
550
- constructor(e) {
551
- this.raycaster = new g.Raycaster(), this.normalisedMousePosition = new g.Vector2(null, null), e.domElement.addEventListener("click", (i) => {
563
+ constructor(t) {
564
+ this.raycaster = new m.Raycaster(), this.normalisedMousePosition = new m.Vector2(null, null), t.domElement.addEventListener("click", (i) => {
552
565
  this.normalisedMousePosition.set(
553
- i.clientX / e.domElement.clientWidth * 2 - 1,
554
- -(i.clientY / e.domElement.clientHeight * 2) + 1
566
+ i.clientX / t.domElement.clientWidth * 2 - 1,
567
+ -(i.clientY / t.domElement.clientHeight * 2) + 1
555
568
  );
556
569
  });
557
570
  }
@@ -563,16 +576,16 @@ class j {
563
576
  * cast into.
564
577
  * @return {Array} - array of all intersected objects.
565
578
  */
566
- raycast(e, i) {
579
+ raycast(t, i) {
567
580
  if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
568
- this.raycaster.setFromCamera(this.normalisedMousePosition, e);
569
- const t = this.raycaster.intersectObjects(i.children, !1);
570
- return this.normalisedMousePosition.set(null, null), t;
581
+ this.raycaster.setFromCamera(this.normalisedMousePosition, t);
582
+ const e = this.raycaster.intersectObjects(i.children, !1);
583
+ return this.normalisedMousePosition.set(null, null), e;
571
584
  }
572
585
  return [];
573
586
  }
574
587
  }
575
- const U = "0.1.4";
588
+ const U = "0.1.5";
576
589
  export {
577
590
  j as ClickHandler,
578
591
  V as DeviceOrientationControls,
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(m){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(m){for(const i in m)if(i!=="default"){const e=Object.getOwnPropertyDescriptor(m,i);Object.defineProperty(t,i,e.get?e:{enumerable:!0,get:()=>m[i]})}}return t.default=m,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]=i}emit(t,...i){this.eventHandlers[t]?.call(this,...i)}}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,g={}){t.properties=g,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:g})}#d(t,i,e,l){const g=this.lonLatToWorldCoords(i,e);l!==void 0&&(t.position.y=l),[t.position.x,t.position.z]=g}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.#m(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})))}#m(t,i){const e=p.MathUtils.degToRad(i.longitude-t.longitude),l=p.MathUtils.degToRad(i.latitude-t.latitude),g=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(g),Math.sqrt(1-g))*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",N="locar-device-orientation-permission-message",R="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,U=new c.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5));class j 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}}))},g=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(U),n.multiply(F.setFromAxisAngle(x,-o))};this.connect=function(){g(),window.addEventListener("orientationchange",g),window.addEventListener(e.orientationChangeEventName,l),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",g),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(R);const a=document.createElement("div");a.classList.add(N);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 q{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 k="0.1.4";h.ClickHandler=q,h.DeviceOrientationControls=j,h.EventEmitter=M,h.LocationBased=b,h.SphMercProjection=A,h.Webcam=D,h.version=k,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 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"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locar",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Location-based AR from AR.js.",
5
5
  "files": [
6
6
  "dist",