locar 0.0.12 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,9 @@ Some of these issues, such as incorrect North on some devices, may well be to do
22
22
 
23
23
  ## Cross-platform Compatibility
24
24
 
25
- Chrome on Android is recommended. It may also work on Chrome in iOS; please file an issue if not. It will not work on Safari on iOS, due to permissions issues - **though pull requests are welcome to fix this**. Firefox unfortunately does not appear to fully implement the Device Orientation API so is unlikely to work
25
+ It should now work on Chrome (and possibly Safari) on iOS as well as Android, due to a number of recent iOS fixes by project contributors.
26
+
27
+ Firefox unfortunately does not appear to fully implement the Device Orientation API so is unlikely to work.
26
28
 
27
29
  ## Using the library
28
30
 
@@ -40,7 +42,7 @@ import * as LocAR from 'locar';
40
42
  as long as you include `locar` as a dependency, e.g. in your `package.json`:
41
43
  ```
42
44
  "dependencies": {
43
- "locar" : "^0.0.11",
45
+ "locar" : "^0.1.0",
44
46
  "three" : "^0.175.0"
45
47
  }
46
48
  ```
@@ -55,6 +57,10 @@ Please see [here](https://ar-js-org.github.io/locar.js/api) for full API documen
55
57
 
56
58
  Please see [here](https://github.com/AR-js-org/locar.js/blob/master/docs/tutorial/index.md) for a tutorial introducing LocAR.js.
57
59
 
60
+ ## Contributors
61
+
62
+ Many thanks to all contributors to the project, in particular [Darian Elias Weiß](https://github.com/darianwwu) and [Kazuhiro Matsuyama](https://github.com/ma2yama) for providing extremely valuable iOS fixes and enhancements.
63
+
58
64
  ## Disclaimer
59
65
 
60
66
  This is an open-source project licensed under the [MIT License](LICENSE) and thus comes with no warranty. Also it is a volunteer-led project; work on the project by AR.js maintainers or any other contributor will be undertaken *time-permitting* only. For this reason we welcome contributors! The more people working on the project, the more likely it is that it will become full-featured and issues will be resolved.
package/dist/locar.es.js CHANGED
@@ -1,25 +1,10 @@
1
- var q = (r) => {
2
- throw TypeError(r);
3
- };
4
- var S = (r, t, i) => t.has(r) || q("Cannot " + i);
5
- var n = (r, t, i) => (S(r, t, "read from private field"), i ? i.call(r) : t.get(r)), m = (r, t, i) => t.has(r) ? q("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(r) : t.set(r, i), l = (r, t, i, e) => (S(r, t, "write to private field"), e ? e.call(r, i) : t.set(r, i), i), p = (r, t, i) => (S(r, t, "access private method"), i);
6
- var k = (r, t, i, e) => ({
7
- set _(c) {
8
- l(r, t, c, i);
9
- },
10
- get _() {
11
- return n(r, t, e);
12
- }
13
- });
14
- import * as b from "three";
15
- import { Vector3 as B, Euler as U, Quaternion as F, EventDispatcher as K, MathUtils as C } from "three";
16
- var E, G, X, Q, V;
17
- class $ {
1
+ import * as f from "three";
2
+ import { Vector3 as I, Euler as A, Quaternion as w, EventDispatcher as C, MathUtils as m } from "three";
3
+ class T {
18
4
  /**
19
5
  * Create a SphMercProjection.
20
6
  */
21
7
  constructor() {
22
- m(this, E);
23
8
  this.EARTH = 4007501668e-2, this.HALF_EARTH = 2003750834e-2;
24
9
  }
25
10
  /**
@@ -28,16 +13,30 @@ class $ {
28
13
  * @param {number} lat - the latitude.
29
14
  * @return {Array} Two-member array containing easting and northing.
30
15
  */
31
- project(t, i) {
32
- return [p(this, E, G).call(this, t), p(this, E, X).call(this, i)];
16
+ project(e, i) {
17
+ return [this.#t(e), this.#h(i)];
33
18
  }
34
19
  /**
35
20
  * Unproject a Spherical Mercator easting and northing.
36
21
  * @param {Array} projected - Two-member array containing easting and northing
37
22
  * @return {Array} Two-member array containing longitude and latitude
38
23
  */
39
- unproject(t) {
40
- return [p(this, E, Q).call(this, t[0]), p(this, E, V).call(this, t[1])];
24
+ unproject(e) {
25
+ return [this.#e(e[0]), this.#s(e[1])];
26
+ }
27
+ #t(e) {
28
+ return e / 180 * this.HALF_EARTH;
29
+ }
30
+ #h(e) {
31
+ var i = Math.log(Math.tan((90 + e) * Math.PI / 360)) / (Math.PI / 180);
32
+ return i * this.HALF_EARTH / 180;
33
+ }
34
+ #e(e) {
35
+ return e / this.HALF_EARTH * 180;
36
+ }
37
+ #s(e) {
38
+ var i = e / this.HALF_EARTH * 180;
39
+ return i = 180 / Math.PI * (2 * Math.atan(Math.exp(i * Math.PI / 180)) - Math.PI / 2), i;
41
40
  }
42
41
  /**
43
42
  * Return the projection's ID.
@@ -47,19 +46,38 @@ class $ {
47
46
  return "epsg:3857";
48
47
  }
49
48
  }
50
- E = new WeakSet(), G = function(t) {
51
- return t / 180 * this.HALF_EARTH;
52
- }, X = function(t) {
53
- var i = Math.log(Math.tan((90 + t) * Math.PI / 360)) / (Math.PI / 180);
54
- return i * this.HALF_EARTH / 180;
55
- }, Q = function(t) {
56
- return t / this.HALF_EARTH * 180;
57
- }, V = function(t) {
58
- var i = t / this.HALF_EARTH * 180;
59
- return i = 180 / Math.PI * (2 * Math.atan(Math.exp(i * Math.PI / 180)) - Math.PI / 2), i;
60
- };
61
- var x, O, P, H, L, A, y, D, T, M, f, j, Y, W, Z;
62
- class ot {
49
+ class P {
50
+ constructor() {
51
+ this.eventHandlers = {};
52
+ }
53
+ /**
54
+ * Add an event handler.
55
+ * @param {string} eventName - the event to handle.
56
+ * @param {Function} eventHandler - the event handler function.
57
+ */
58
+ on(e, i) {
59
+ this.eventHandlers[e] = i;
60
+ }
61
+ /**
62
+ * Emit an event.
63
+ * @param {string} eventName - the event to emit.
64
+ * @param ...params - parameters to pass to the event handler.
65
+ */
66
+ emit(e, ...i) {
67
+ this.eventHandlers[e]?.call(this, ...i);
68
+ }
69
+ }
70
+ class L extends P {
71
+ #t;
72
+ #h;
73
+ #e;
74
+ #s;
75
+ #c;
76
+ #o;
77
+ #i;
78
+ #r;
79
+ #a;
80
+ #n;
63
81
  /**
64
82
  * @param {THREE.Scene} scene - The Three.js scene to use.
65
83
  * @param {THREE.Camera} camera - The Three.js camera to use. Should usually
@@ -68,19 +86,8 @@ class ot {
68
86
  * setGpsOptions() below.
69
87
  * @param {Object} serverLogger - an object which can optionally log GPS position to a server for debugging. null by default, so no logging will be done. This object should implement a sendData() method to send data (2nd arg) to a given endpoint (1st arg). Please see source code for details. Ensure you comply with privacy laws (GDPR or equivalent) if implementing this.
70
88
  */
71
- constructor(t, i, e = {}, c = null) {
72
- m(this, f);
73
- m(this, x);
74
- m(this, O);
75
- m(this, P);
76
- m(this, H);
77
- m(this, L);
78
- m(this, A);
79
- m(this, y);
80
- m(this, D);
81
- m(this, T);
82
- m(this, M);
83
- this.scene = t, this.camera = i, l(this, x, new $()), l(this, O, {}), l(this, P, null), l(this, H, 0), l(this, L, 100), l(this, A, null), this.setGpsOptions(e), l(this, y, null), l(this, D, 0), l(this, T, 0), l(this, M, c);
89
+ constructor(e, i, t = {}, c = null) {
90
+ 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;
84
91
  }
85
92
  /**
86
93
  * Set the projection to use.
@@ -88,8 +95,8 @@ class ot {
88
95
  * taking longitude and latitude as arguments and returning an array
89
96
  * containing easting and northing.
90
97
  */
91
- setProjection(t) {
92
- l(this, x, t);
98
+ setProjection(e) {
99
+ this.#t = e;
93
100
  }
94
101
  /**
95
102
  * Set the GPS options.
@@ -98,8 +105,8 @@ class ot {
98
105
  * must move to process a new GPS reading, and the latter specifies the
99
106
  * minimum accuracy, in metres, for a GPS reading to be counted.
100
107
  */
101
- setGpsOptions(t = {}) {
102
- t.gpsMinDistance !== void 0 && l(this, H, t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && l(this, L, t.gpsMinAccuracy);
108
+ setGpsOptions(e = {}) {
109
+ e.gpsMinDistance !== void 0 && (this.#s = e.gpsMinDistance), e.gpsMinAccuracy !== void 0 && (this.#c = e.gpsMinAccuracy);
103
110
  }
104
111
  /**
105
112
  * Start the GPS on a real device
@@ -107,24 +114,24 @@ class ot {
107
114
  * GPS errors can be handled by handling the gpserror event.
108
115
  */
109
116
  async startGps() {
110
- if (n(this, M)) {
111
- const i = await (await n(this, M).sendData("/gps/start", {
112
- gpsMinDistance: n(this, H),
113
- gpsMinAccuracy: n(this, L)
117
+ if (this.#n) {
118
+ const i = await (await this.#n.sendData("/gps/start", {
119
+ gpsMinDistance: this.#s,
120
+ gpsMinAccuracy: this.#c
114
121
  })).json();
115
- l(this, T, i.session);
122
+ this.#a = i.session;
116
123
  }
117
- return n(this, A) === null ? (l(this, A, navigator.geolocation.watchPosition(
118
- (t) => {
119
- p(this, f, W).call(this, t);
124
+ return this.#o === null ? (this.#o = navigator.geolocation.watchPosition(
125
+ (e) => {
126
+ this.#l(e);
120
127
  },
121
- (t) => {
122
- n(this, O).gpserror ? n(this, O).gpserror(t.code) : alert(`GPS error: code ${t.code}`);
128
+ (e) => {
129
+ this.emit("gpserror", e);
123
130
  },
124
131
  {
125
132
  enableHighAccuracy: !0
126
133
  }
127
- )), !0) : !1;
134
+ ), !0) : !1;
128
135
  }
129
136
  /**
130
137
  * Stop the GPS on a real device
@@ -132,7 +139,7 @@ class ot {
132
139
  * stopped (i.e. it was never started).
133
140
  */
134
141
  stopGps() {
135
- return n(this, A) !== null ? (navigator.geolocation.clearWatch(n(this, A)), l(this, A, null), !0) : !1;
142
+ return this.#o !== null ? (navigator.geolocation.clearWatch(this.#o), this.#o = null, !0) : !1;
136
143
  }
137
144
  /**
138
145
  * Send a fake GPS signal. Useful for testing on a desktop or laptop.
@@ -143,10 +150,10 @@ class ot {
143
150
  * @param {number} acc - The accuracy of the GPS reading in metres. May be
144
151
  * ignored if lower than the specified minimum accuracy.
145
152
  */
146
- fakeGps(t, i, e = null, c = 0) {
147
- e !== null && this.setElevation(e), p(this, f, W).call(this, {
153
+ fakeGps(e, i, t = null, c = 0) {
154
+ t !== null && this.setElevation(t), this.#l({
148
155
  coords: {
149
- longitude: t,
156
+ longitude: e,
150
157
  latitude: i,
151
158
  accuracy: c
152
159
  }
@@ -158,17 +165,18 @@ class ot {
158
165
  * projections, northings increase northwards, but in the WebGL coordinate
159
166
  * system, we face negative z if the camera is at the origin with default
160
167
  * rotation).
168
+ * Must not be called until an initial position is determined.
161
169
  * @param {number} lon - The longitude.
162
170
  * @param {number} lat - The latitude.
163
171
  * @return {Array} a two member array containing the WebGL x and z coordinates
164
172
  */
165
- lonLatToWorldCoords(t, i) {
166
- const e = n(this, x).project(t, i);
167
- if (n(this, y))
168
- e[0] -= n(this, y)[0], e[1] -= n(this, y)[1];
173
+ lonLatToWorldCoords(e, i) {
174
+ const t = this.#t.project(e, i);
175
+ if (this.#i)
176
+ t[0] -= this.#i[0], t[1] -= this.#i[1];
169
177
  else
170
178
  throw "No initial position determined";
171
- return [e[0], -e[1]];
179
+ return [t[0], -t[1]];
172
180
  }
173
181
  /**
174
182
  * Add a new AR object at a given latitude, longitude and elevation.
@@ -180,121 +188,95 @@ class ot {
180
188
  * @param {Object} properties - properties describing the object (for example,
181
189
  * the contents of the GeoJSON properties field).
182
190
  */
183
- add(t, i, e, c, d = {}) {
184
- var g;
185
- t.properties = d, p(this, f, j).call(this, t, i, e, c), this.scene.add(t), (g = n(this, M)) == null || g.sendData("/object/new", {
186
- position: t.position,
187
- x: t.position.x,
188
- z: t.position.z,
189
- session: n(this, T),
191
+ add(e, i, t, c, d = {}) {
192
+ e.properties = d, this.#d(e, i, t, c), this.scene.add(e), this.#n?.sendData("/object/new", {
193
+ position: e.position,
194
+ x: e.position.x,
195
+ z: e.position.z,
196
+ session: this.#a,
190
197
  properties: d
191
198
  });
192
199
  }
200
+ #d(e, i, t, c) {
201
+ const d = this.lonLatToWorldCoords(i, t);
202
+ c !== void 0 && (e.position.y = c), [e.position.x, e.position.z] = d;
203
+ }
193
204
  /**
194
205
  * Set the elevation (y coordinate) of the camera.
195
206
  * @param {number} elev - the elevation in metres.
196
207
  */
197
- setElevation(t) {
198
- this.camera.position.y = t;
208
+ setElevation(e) {
209
+ this.camera.position.y = e;
210
+ }
211
+ #u(e, i) {
212
+ this.#i = this.#t.project(e, i);
213
+ }
214
+ #l(e) {
215
+ let i = Number.MAX_VALUE;
216
+ this.#r++, this.#n?.sendData("/gps/new", {
217
+ gpsCount: this.#r,
218
+ lat: e.coords.latitude,
219
+ lon: e.coords.longitude,
220
+ acc: e.coords.accuracy,
221
+ session: this.#a
222
+ }), e.coords.accuracy <= this.#c && (this.#e === null ? this.#e = {
223
+ latitude: e.coords.latitude,
224
+ longitude: e.coords.longitude
225
+ } : 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(
226
+ e.coords.longitude,
227
+ e.coords.latitude
228
+ ), this.#n?.sendData("/worldorigin/new", {
229
+ gpsCount: this.#r,
230
+ lat: e.coords.latitude,
231
+ lon: e.coords.longitude,
232
+ session: this.#a,
233
+ initialPosition: this.#i
234
+ })), this.#d(
235
+ this.camera,
236
+ e.coords.longitude,
237
+ e.coords.latitude
238
+ ), this.#n?.sendData("/gps/accepted", {
239
+ gpsCount: this.#r,
240
+ cameraX: this.camera.position.x,
241
+ cameraZ: this.camera.position.z,
242
+ session: this.#a,
243
+ distMoved: i
244
+ }), this.emit("gpsupdate", { position: e, distMoved: i })));
199
245
  }
200
246
  /**
201
- * Add an event handler.
202
- * Currently-understood events: "gpsupdate" and "gpserror".
203
- * The former fires when a GPS update is received, and is passed the
204
- * standard Geolocation API position object, along with the distance moved
205
- * since the last GPS update in metres.
206
- * The latter fires when a GPS error is generated, and is passed the
207
- * standard Geolocation API numerical error code.
208
- * @param {string} eventName - the event to handle.
209
- * @param {Function} eventHandler - the event handler function.
210
- * @listens LocationBased#gpsupdate
211
- * @listens LocationBased#gpserror
247
+ * Calculate haversine distance between two lat/lon pairs.
248
+ *
249
+ * Taken from original A-Frame AR.js location-based components
212
250
  */
213
- on(t, i) {
214
- n(this, O)[t] = i;
251
+ #m(e, i) {
252
+ const t = f.MathUtils.degToRad(i.longitude - e.longitude), c = f.MathUtils.degToRad(i.latitude - e.latitude), d = Math.sin(c / 2) * Math.sin(c / 2) + Math.cos(f.MathUtils.degToRad(e.latitude)) * Math.cos(f.MathUtils.degToRad(i.latitude)) * (Math.sin(t / 2) * Math.sin(t / 2));
253
+ return 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1 - d)) * 6371e3;
215
254
  }
216
255
  }
217
- x = new WeakMap(), O = new WeakMap(), P = new WeakMap(), H = new WeakMap(), L = new WeakMap(), A = new WeakMap(), y = new WeakMap(), D = new WeakMap(), T = new WeakMap(), M = new WeakMap(), f = new WeakSet(), j = function(t, i, e, c) {
218
- const d = this.lonLatToWorldCoords(i, e);
219
- c !== void 0 && (t.position.y = c), [t.position.x, t.position.z] = d;
220
- }, Y = function(t, i) {
221
- l(this, y, n(this, x).project(t, i));
222
- }, W = function(t) {
223
- var e, c, d;
224
- let i = Number.MAX_VALUE;
225
- k(this, D)._++, (e = n(this, M)) == null || e.sendData("/gps/new", {
226
- gpsCount: n(this, D),
227
- lat: t.coords.latitude,
228
- lon: t.coords.longitude,
229
- acc: t.coords.accuracy,
230
- session: n(this, T)
231
- }), t.coords.accuracy <= n(this, L) && (n(this, P) === null ? l(this, P, {
232
- latitude: t.coords.latitude,
233
- longitude: t.coords.longitude
234
- }) : i = p(this, f, Z).call(this, n(this, P), t.coords), i >= n(this, H) && (n(this, P).longitude = t.coords.longitude, n(this, P).latitude = t.coords.latitude, n(this, y) || (p(this, f, Y).call(this, t.coords.longitude, t.coords.latitude), (c = n(this, M)) == null || c.sendData("/worldorigin/new", {
235
- gpsCount: n(this, D),
236
- lat: t.coords.latitude,
237
- lon: t.coords.longitude,
238
- session: n(this, T),
239
- initialPosition: n(this, y)
240
- })), p(this, f, j).call(this, this.camera, t.coords.longitude, t.coords.latitude), (d = n(this, M)) == null || d.sendData("/gps/accepted", {
241
- gpsCount: n(this, D),
242
- cameraX: this.camera.position.x,
243
- cameraZ: this.camera.position.z,
244
- session: n(this, T),
245
- distMoved: i
246
- }), n(this, O).gpsupdate && n(this, O).gpsupdate(t, i)));
247
- }, /**
248
- * Calculate haversine distance between two lat/lon pairs.
249
- *
250
- * Taken from original A-Frame AR.js location-based components
251
- */
252
- Z = function(t, i) {
253
- const e = b.MathUtils.degToRad(i.longitude - t.longitude), c = b.MathUtils.degToRad(i.latitude - t.latitude), d = Math.sin(c / 2) * Math.sin(c / 2) + Math.cos(b.MathUtils.degToRad(t.latitude)) * Math.cos(b.MathUtils.degToRad(i.latitude)) * (Math.sin(e / 2) * Math.sin(e / 2));
254
- return 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1 - d)) * 6371e3;
255
- };
256
- class at {
256
+ class H extends P {
257
+ #t;
257
258
  /**
258
259
  * Create a Webcam.
259
- * @param options {Object} - options to use for initialising the camera.
260
- * Currently idealWidth and idealHeight properties are understood as well as
261
- * onVideoStarted(), a *required* callback which runs when the camera has
262
- * been initialised.
263
- * This takes a THREE.VideoTexture as an argument which can be used to set
264
- * the background of your three.js scene within a callback.
260
+ * @param constraints {Object} - options to use for initialising the camera.
261
+ * The same constraints object as used by standard MediaDevices API.
265
262
  * @param {string} videoElementSelector - selector to obtain the HTML video
266
263
  * element to render the webcam feed. If a falsy value (e.g. null or
267
264
  * undefined), a video element will be created.
268
265
  */
269
- constructor(t = {}, i) {
270
- this.sceneWebcam = new b.Scene();
271
- let e;
272
- if (i ? e = document.querySelector(i) : (e = document.createElement("video"), e.setAttribute("autoplay", !0), e.setAttribute("playsinline", !0), e.style.display = "none", document.body.appendChild(e)), this.texture = new b.VideoTexture(e), navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
273
- const c = {
274
- video: {
275
- width: { ideal: t.idealWidth || 1280 },
276
- height: { ideal: t.idealHeight || 720 },
277
- facingMode: "environment"
278
- }
279
- };
280
- navigator.mediaDevices.getUserMedia(c).then((d) => {
281
- e.addEventListener("loadedmetadata", () => {
282
- var g;
283
- e.setAttribute("width", e.videoWidth), e.setAttribute("height", e.videoHeight), e.play(), (g = t.onVideoStarted) == null || g.call(this, this.texture);
284
- }), e.srcObject = d;
285
- }).catch((d) => {
286
- setTimeout(() => {
287
- alert(
288
- `Webcam Error
289
- Name: ` + d.name + `
290
- Message: ` + d.message
291
- );
292
- }, 1e3);
266
+ constructor(e = { video: { facingMode: "environment" } }, i) {
267
+ super(), this.sceneWebcam = new f.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 f.VideoTexture(this.#t), navigator.mediaDevices && navigator.mediaDevices.getUserMedia ? navigator.mediaDevices.getUserMedia(e).then((t) => {
268
+ this.#t.addEventListener("loadedmetadata", () => {
269
+ this.#t.setAttribute("width", this.#t.videoWidth), this.#t.setAttribute("height", this.#t.videoHeight), this.#t.play(), this.emit("webcamstarted", { texture: this.texture });
270
+ }), this.#t.srcObject = t;
271
+ }).catch((t) => {
272
+ this.emit("webcamerror", {
273
+ code: t.name,
274
+ message: t.message
293
275
  });
294
- } else
295
- setTimeout(() => {
296
- alert("sorry - media devices API not supported");
297
- }, 1e3);
276
+ }) : this.emit("webcamerror", {
277
+ code: "LOCAR_NO_MEDIA_DEVICES_API",
278
+ message: "Media devices API not supported"
279
+ });
298
280
  }
299
281
  /**
300
282
  * Free up the memory associated with the webcam.
@@ -304,203 +286,224 @@ Message: ` + d.message
304
286
  this.texture.dispose();
305
287
  }
306
288
  }
307
- const z = navigator.userAgent.match(/iPhone|iPad|iPod/i) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1, J = new B(0, 0, 1), N = new U(), tt = new F(), et = new F(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)), it = { type: "change" };
308
- class rt extends K {
289
+ const E = navigator.userAgent.match(/iPhone|iPad|iPod/i) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1, _ = new I(0, 0, 1), y = new A(), R = new w(), D = new w(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
290
+ class x extends C {
309
291
  /**
310
- * Create an instance of DeviceOrientationControls.
311
- * @param {Object} object - the object to attach the controls to
312
- * (usually your Three.js camera)
313
- * @param {Object} options - options for DeviceOrientationControls: currently accepts smoothingFactor
314
- */
315
- constructor(t, i = {}) {
316
- super(), window.isSecureContext === !1 && console.error(
317
- "THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)"
318
- );
319
- const e = this, c = 1e-6, d = new F();
320
- this.object = t, this.object.rotation.reorder("YXZ"), this.enabled = !0, this.deviceOrientation = null, this.screenOrientation = 0, this.alphaOffset = 0, this.initialOffset = null, this.TWO_PI = 2 * Math.PI, this.HALF_PI = 0.5 * Math.PI, this.orientationChangeEventName = "ondeviceorientationabsolute" in window ? "deviceorientationabsolute" : "deviceorientation", this.smoothingFactor = i.smoothingFactor || 1;
321
- const g = function({
322
- alpha: s,
323
- beta: o,
292
+ * Create an instance of DeviceOrientationControls.
293
+ * @param {Object} object - the object to attach the controls to
294
+ * (usually your Three.js camera)
295
+ * @param {Object} options - options for DeviceOrientationControls: currently accepts smoothingFactor, enablePermissionDialog
296
+ */
297
+ constructor(e, i = {}) {
298
+ super(), this.eventEmitter = new P();
299
+ const t = this;
300
+ 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", console.log("Device Orientation Event Name:", this.orientationChangeEventName), this.smoothingFactor = i.smoothingFactor || 1, this.enablePermissionDialog = i.enablePermissionDialog ?? !0;
301
+ const c = function({
302
+ alpha: n,
303
+ beta: s,
324
304
  gamma: a,
325
- webkitCompassHeading: u
305
+ webkitCompassHeading: r
326
306
  }) {
327
- if (z) {
328
- const h = 360 - u;
329
- e.alphaOffset = C.degToRad(h - s), e.deviceOrientation = { alpha: s, beta: o, gamma: a, webkitCompassHeading: u };
307
+ if (E) {
308
+ const o = 360 - r;
309
+ t.alphaOffset = m.degToRad(o - n), t.deviceOrientation = { alpha: n, beta: s, gamma: a, webkitCompassHeading: r };
330
310
  } else
331
- s < 0 && (s += 360), e.deviceOrientation = { alpha: s, beta: o, gamma: a };
311
+ n < 0 && (n += 360), t.deviceOrientation = { alpha: n, beta: s, gamma: a };
332
312
  window.dispatchEvent(
333
313
  new CustomEvent("camera-rotation-change", {
334
- detail: { cameraRotation: t.rotation }
314
+ detail: { cameraRotation: e.rotation }
335
315
  })
336
316
  );
337
- }, I = function() {
338
- e.screenOrientation = window.orientation || 0;
339
- }, R = function(s, o, a, u, h) {
340
- N.set(a, o, -u, "YXZ"), s.setFromEuler(N), s.multiply(et), s.multiply(tt.setFromAxisAngle(J, -h));
317
+ }, d = function() {
318
+ t.screenOrientation = window.orientation || 0, E && (t.screenOrientation === 90 ? t.orientationOffset = -t.HALF_PI : t.screenOrientation === -90 ? t.orientationOffset = t.HALF_PI : t.orientationOffset = 0);
319
+ }, M = function(n, s, a, r, o) {
320
+ y.set(a, s, -r, "YXZ"), n.setFromEuler(y), n.multiply(D), n.multiply(R.setFromAxisAngle(_, -o));
341
321
  };
342
322
  this.connect = function() {
343
- I(), window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((s) => {
344
- s === "granted" && (window.addEventListener(
345
- "orientationchange",
346
- I
347
- ), window.addEventListener(
348
- e.orientationChangeEventName,
349
- g
350
- ));
351
- }).catch(function(s) {
352
- console.error(
353
- "THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",
354
- s
355
- );
356
- }) : (window.addEventListener(
323
+ d(), window.addEventListener(
357
324
  "orientationchange",
358
- I
325
+ d
359
326
  ), window.addEventListener(
360
- e.orientationChangeEventName,
361
- g
362
- )), e.enabled = !0;
327
+ t.orientationChangeEventName,
328
+ c
329
+ ), t.enabled = !0;
363
330
  }, this.disconnect = function() {
364
331
  window.removeEventListener(
365
332
  "orientationchange",
366
- I
333
+ d
367
334
  ), window.removeEventListener(
368
- e.orientationChangeEventName,
369
- g
370
- ), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
371
- }, this.update = function({ theta: s = 0 } = { theta: 0 }) {
372
- if (e.enabled === !1) return;
373
- const o = e.deviceOrientation;
374
- if (o) {
375
- let a = o.alpha ? C.degToRad(o.alpha) + e.alphaOffset : 0, u = o.beta ? C.degToRad(o.beta) : 0, h = o.gamma ? C.degToRad(o.gamma) : 0;
376
- const _ = e.screenOrientation ? C.degToRad(e.screenOrientation) : 0;
377
- if (z) {
378
- const v = new F();
379
- R(v, a, u, h, _);
380
- const w = new U().setFromQuaternion(
381
- v,
335
+ t.orientationChangeEventName,
336
+ c
337
+ ), t.enabled = !1, t.initialOffset = !1, t.deviceOrientation = null;
338
+ }, this.requestOrientationPermissions = function() {
339
+ window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((n) => {
340
+ n === "granted" ? this.eventEmitter.emit("deviceorientationgranted", {
341
+ target: this
342
+ }) : this.eventEmitter.emit("deviceorientationerror", {
343
+ code: "LOCAR_DEVICE_ORIENTATION_PERMISSION_DENIED",
344
+ message: "Permission for device orientation denied - AR will not work correctly"
345
+ });
346
+ }).catch(function(n) {
347
+ this.eventEmitter.emit("deviceorientationerror", {
348
+ code: "LOCAR_DEVICE_ORIENTATION_PERMISSION_FAILED",
349
+ message: "Permission request for device orientation failed - AR will not work correctly"
350
+ });
351
+ }) : this.eventEmitter.emit("deviceorientationerror", {
352
+ code: "LOCAR_DEVICE_ORIENTATION_INTERNAL_ERROR",
353
+ message: "Internal error: no requestPermission() found although requestOrientationPermissions() was called - please raise an issue on GitHub"
354
+ });
355
+ }, this.update = function({ theta: n = 0 } = { theta: 0 }) {
356
+ if (t.enabled === !1) return;
357
+ const s = t.deviceOrientation;
358
+ if (s) {
359
+ 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;
360
+ const g = t.screenOrientation ? m.degToRad(t.screenOrientation) : 0;
361
+ if (t.smoothingFactor < 1) {
362
+ if (t.lastOrientation) {
363
+ const h = t.smoothingFactor;
364
+ a = t._getSmoothedAngle(
365
+ a,
366
+ t.lastOrientation.alpha,
367
+ h
368
+ ), r = t._getSmoothedAngle(
369
+ r + Math.PI,
370
+ t.lastOrientation.beta,
371
+ h
372
+ ), o = t._getSmoothedAngle(
373
+ o + t.HALF_PI,
374
+ t.lastOrientation.gamma,
375
+ h,
376
+ Math.PI
377
+ );
378
+ } else
379
+ r += Math.PI, o += t.HALF_PI;
380
+ t.lastOrientation = {
381
+ alpha: a,
382
+ beta: r,
383
+ gamma: o
384
+ };
385
+ }
386
+ if (E) {
387
+ const h = new w();
388
+ M(
389
+ h,
390
+ a,
391
+ t.smoothingFactor < 1 ? r - Math.PI : r,
392
+ t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
393
+ g
394
+ );
395
+ const u = new A().setFromQuaternion(
396
+ h,
382
397
  "YXZ"
383
398
  );
384
- console.log(w.x, w.y, w.z), w.y = C.degToRad(
385
- 360 - o.webkitCompassHeading
386
- ), v.setFromEuler(w), e.object.quaternion.copy(v);
387
- } else {
388
- if (this.smoothingFactor < 1) {
389
- if (this.lastOrientation) {
390
- const v = this.smoothingFactor;
391
- a = this._getSmoothedAngle(
392
- a,
393
- this.lastOrientation.alpha,
394
- v
395
- ), u = this._getSmoothedAngle(
396
- u + Math.PI,
397
- this.lastOrientation.beta,
398
- v
399
- ), h = this._getSmoothedAngle(
400
- h + this.HALF_PI,
401
- this.lastOrientation.gamma,
402
- v,
403
- Math.PI
404
- );
405
- } else
406
- u += Math.PI, h += this.HALF_PI;
407
- this.lastOrientation = {
408
- alpha: a,
409
- beta: u,
410
- gamma: h
411
- };
412
- }
413
- R(
414
- e.object.quaternion,
415
- a + s,
416
- this.smoothingFactor < 1 ? u - Math.PI : u,
417
- this.smoothingFactor < 1 ? h - this.HALF_PI : h,
418
- _
399
+ let v = m.degToRad(360 - s.webkitCompassHeading);
400
+ t.smoothingFactor < 1 && t.lastCompassY !== void 0 && (v = t._getSmoothedAngle(v, t.lastCompassY, t.smoothingFactor)), t.lastCompassY = v, u.y = v + (t.orientationOffset || 0), h.setFromEuler(u), t.object.quaternion.copy(h);
401
+ } else
402
+ M(
403
+ t.object.quaternion,
404
+ E ? a + t.alphaOffset : a,
405
+ t.smoothingFactor < 1 ? r - Math.PI : r,
406
+ t.smoothingFactor < 1 ? o - Math.PI / 2 : o,
407
+ g
419
408
  );
420
- }
421
- 8 * (1 - d.dot(e.object.quaternion)) > c && (d.copy(e.object.quaternion), e.dispatchEvent(it));
422
409
  }
423
- }, this._orderAngle = function(s, o, a = this.TWO_PI) {
424
- return o > s && Math.abs(o - s) < a / 2 || s > o && Math.abs(o - s) > a / 2 ? { left: s, right: o } : { left: o, right: s };
425
- }, this._getSmoothedAngle = function(s, o, a, u = this.TWO_PI) {
426
- const h = this._orderAngle(s, o, u), _ = h.left, v = h.right;
427
- h.left = 0, h.right -= _, h.right < 0 && (h.right += u);
428
- let w = v == o ? (1 - a) * h.right + a * h.left : a * h.right + (1 - a) * h.left;
429
- return w += _, w >= u && (w -= u), w;
410
+ }, this.getCorrectedHeading = function() {
411
+ const { deviceOrientation: n } = t;
412
+ if (!n) return 0;
413
+ let s = 0;
414
+ return E ? (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;
415
+ }, this._orderAngle = function(n, s, a = t.TWO_PI) {
416
+ 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 };
417
+ }, this._getSmoothedAngle = function(n, s, a, r = t.TWO_PI) {
418
+ const o = t._orderAngle(n, s, r), g = o.left, h = o.right;
419
+ o.left = 0, o.right -= g, o.right < 0 && (o.right += r);
420
+ let u = h == s ? (1 - a) * o.right + a * o.left : a * o.right + (1 - a) * o.left;
421
+ return u += g, u >= r && (u -= r), u;
430
422
  }, this.updateAlphaOffset = function() {
431
- e.initialOffset = !1;
423
+ t.initialOffset = !1;
432
424
  }, this.dispose = function() {
433
- e.disconnect();
425
+ t.disconnect();
434
426
  }, this.getAlpha = function() {
435
- const { deviceOrientation: s } = e;
436
- return s && s.alpha ? C.degToRad(s.alpha) + e.alphaOffset : 0;
427
+ const { deviceOrientation: n } = t;
428
+ return n && n.alpha ? m.degToRad(n.alpha) + t.alphaOffset : 0;
437
429
  }, this.getBeta = function() {
438
- const { deviceOrientation: s } = e;
439
- return s && s.beta ? C.degToRad(s.beta) : 0;
440
- }, window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? this.initPermissionDialog() : this.connect();
441
- }
442
- // Provide gesture before initialising device orientation controls
443
- // From PR #659 on the main AR.js repo
444
- // Thanks to @ma2yama
445
- initPermissionDialog() {
446
- const t = document.createElement("div"), i = document.createElement("div"), e = document.createElement("div"), c = document.createElement("div");
447
- document.body.appendChild(t);
448
- const d = {
449
- display: "flex",
450
- position: "fixed",
451
- top: 0,
452
- left: 0,
453
- width: "100%",
454
- height: "100%",
455
- zIndex: 1,
456
- backgroundColor: "rgba(0,0,0,0.6)",
457
- justifyContent: "center",
458
- alignItems: "center"
459
- }, g = {
460
- backgroundColor: "white",
461
- padding: "6px",
462
- borderRadius: "3px",
463
- width: "36rem",
464
- height: "24rem"
465
- }, I = {
466
- width: "100%",
467
- height: "70%",
468
- display: "flex",
469
- justifyContent: "center",
470
- alignItems: "center"
471
- }, R = {
472
- display: "inline-flex",
473
- width: "100%",
474
- height: "30%",
475
- justifyContent: "center",
476
- alignItems: "center"
430
+ const { deviceOrientation: n } = t;
431
+ return n && n.beta ? m.degToRad(n.beta) : 0;
432
+ }, this.getGamma = function() {
433
+ const { deviceOrientation: n } = t;
434
+ return n && n.gamma ? m.degToRad(n.gamma) : 0;
435
+ }, this.obtainPermissionGesture = function() {
436
+ const n = document.createElement("div"), s = document.createElement("div"), a = document.createElement("div"), r = document.createElement("div");
437
+ document.body.appendChild(n);
438
+ const o = {
439
+ display: "flex",
440
+ position: "fixed",
441
+ top: 0,
442
+ left: 0,
443
+ width: "100%",
444
+ height: "100%",
445
+ zIndex: 1,
446
+ backgroundColor: "rgba(0,0,0,0.6)",
447
+ justifyContent: "center",
448
+ alignItems: "center"
449
+ }, g = {
450
+ backgroundColor: "white",
451
+ padding: "6px",
452
+ borderRadius: "3px",
453
+ width: "36rem",
454
+ height: "24rem"
455
+ }, h = {
456
+ width: "100%",
457
+ height: "70%",
458
+ display: "flex",
459
+ justifyContent: "center",
460
+ alignItems: "center"
461
+ }, u = {
462
+ display: "inline-flex",
463
+ width: "100%",
464
+ height: "30%",
465
+ justifyContent: "center",
466
+ alignItems: "center"
467
+ };
468
+ for (let l in o)
469
+ n.style[l] = o[l];
470
+ for (let l in g)
471
+ s.style[l] = g[l];
472
+ for (let l in h)
473
+ a.style[l] = h[l];
474
+ for (let l in u)
475
+ r.style[l] = u[l];
476
+ n.appendChild(s), s.appendChild(a), s.appendChild(r), a.innerHTML = '<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';
477
+ const v = () => {
478
+ this.requestOrientationPermissions(), n.style.display = "none";
479
+ }, p = document.createElement("button");
480
+ p.addEventListener("click", v), p.style.width = "50%", p.style.height = "80%", p.style.fontSize = "20pt", p.appendChild(document.createTextNode("OK")), r.appendChild(p), document.body.appendChild(n);
477
481
  };
478
- for (let a in d)
479
- t.style[a] = d[a];
480
- for (let a in g)
481
- i.style[a] = g[a];
482
- for (let a in I)
483
- e.style[a] = I[a];
484
- for (let a in R)
485
- c.style[a] = R[a];
486
- t.appendChild(i), i.appendChild(e), i.appendChild(c), e.innerHTML = '<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';
487
- const s = () => {
488
- this.connect(), t.style.display = "none";
489
- }, o = document.createElement("button");
490
- o.addEventListener("click", s), o.style.width = "50%", o.style.height = "80%", o.style.fontSize = "20pt", o.appendChild(document.createTextNode("OK")), c.appendChild(o), document.body.appendChild(t);
482
+ }
483
+ on(e, i) {
484
+ this.eventEmitter.on(e, i);
485
+ }
486
+ init() {
487
+ window.DeviceOrientationEvent === void 0 ? this.eventEmitter.emit("deviceorientationerror", {
488
+ code: "LOCAR_DEVICE_ORIENTATION_NOT_SUPPORTED",
489
+ message: "Device orientation API not supported"
490
+ }) : window.isSecureContext === !1 ? this.eventEmitter.emit("deviceorientationerror", {
491
+ code: "LOCAR_DEVICE_ORIENTATION_NO_HTTPS",
492
+ message: "DeviceOrientationEvent is only available in secure contexts (https)"
493
+ }) : typeof window.DeviceOrientationEvent.requestPermission == "function" && this.enablePermissionDialog ? this.obtainPermissionGesture() : this.eventEmitter.emit("deviceorientationgranted", { target: this });
491
494
  }
492
495
  }
493
- class ct {
496
+ class N {
494
497
  /**
495
498
  * Create a ClickHandler.
496
499
  * @param {THREE.WebGLRenderer} - The Three.js renderer on which the click
497
500
  * events will be handled.
498
501
  */
499
- constructor(t) {
500
- this.raycaster = new b.Raycaster(), this.normalisedMousePosition = new b.Vector2(null, null), t.domElement.addEventListener("click", (i) => {
502
+ constructor(e) {
503
+ this.raycaster = new f.Raycaster(), this.normalisedMousePosition = new f.Vector2(null, null), e.domElement.addEventListener("click", (i) => {
501
504
  this.normalisedMousePosition.set(
502
- i.clientX / t.domElement.clientWidth * 2 - 1,
503
- -(i.clientY / t.domElement.clientHeight * 2) + 1
505
+ i.clientX / e.domElement.clientWidth * 2 - 1,
506
+ -(i.clientY / e.domElement.clientHeight * 2) + 1
504
507
  );
505
508
  });
506
509
  }
@@ -512,21 +515,22 @@ class ct {
512
515
  * cast into.
513
516
  * @return {Array} - array of all intersected objects.
514
517
  */
515
- raycast(t, i) {
518
+ raycast(e, i) {
516
519
  if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
517
- this.raycaster.setFromCamera(this.normalisedMousePosition, t);
518
- const e = this.raycaster.intersectObjects(i.children, !1);
519
- return this.normalisedMousePosition.set(null, null), e;
520
+ this.raycaster.setFromCamera(this.normalisedMousePosition, e);
521
+ const t = this.raycaster.intersectObjects(i.children, !1);
522
+ return this.normalisedMousePosition.set(null, null), t;
520
523
  }
521
524
  return [];
522
525
  }
523
526
  }
524
- const ht = "0.0.10-noaframe-1";
527
+ const S = "0.1.0";
525
528
  export {
526
- ct as ClickHandler,
527
- rt as DeviceOrientationControls,
528
- ot as LocationBased,
529
- $ as SphMercProjection,
530
- at as Webcam,
531
- ht as version
529
+ N as ClickHandler,
530
+ x as DeviceOrientationControls,
531
+ P as EventEmitter,
532
+ L as LocationBased,
533
+ T as SphMercProjection,
534
+ H as Webcam,
535
+ S as version
532
536
  };
package/dist/locar.umd.js CHANGED
@@ -1,3 +1 @@
1
- (function(a,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],n):(a=typeof globalThis<"u"?globalThis:a||self,n(a.locar={},a.THREE))})(this,function(a,n){"use strict";var N=a=>{throw TypeError(a)};var q=(a,n,f)=>n.has(a)||N("Cannot "+f);var s=(a,n,f)=>(q(a,n,"read from private field"),f?f.call(a):n.get(a)),v=(a,n,f)=>n.has(a)?N("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(a):n.set(a,f),u=(a,n,f,m)=>(q(a,n,"write to private field"),m?m.call(a,f):n.set(a,f),f),y=(a,n,f)=>(q(a,n,"access private method"),f);var Q=(a,n,f,m)=>({set _(W){u(a,n,W,f)},get _(){return s(a,n,m)}});var w,G,X,V,Y,E,D,I,S,j,L,O,_,T,P,M,H,Z,k,B;function f(b){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(b){for(const i in b)if(i!=="default"){const e=Object.getOwnPropertyDescriptor(b,i);Object.defineProperty(t,i,e.get?e:{enumerable:!0,get:()=>b[i]})}}return t.default=b,Object.freeze(t)}const m=f(n);class W{constructor(){v(this,w);this.EARTH=4007501668e-2,this.HALF_EARTH=2003750834e-2}project(t,i){return[y(this,w,G).call(this,t),y(this,w,X).call(this,i)]}unproject(t){return[y(this,w,V).call(this,t[0]),y(this,w,Y).call(this,t[1])]}getID(){return"epsg:3857"}}w=new WeakSet,G=function(t){return t/180*this.HALF_EARTH},X=function(t){var i=Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180);return i*this.HALF_EARTH/180},V=function(t){return t/this.HALF_EARTH*180},Y=function(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};class K{constructor(t,i,e={},l=null){v(this,M);v(this,E);v(this,D);v(this,I);v(this,S);v(this,j);v(this,L);v(this,O);v(this,_);v(this,T);v(this,P);this.scene=t,this.camera=i,u(this,E,new W),u(this,D,{}),u(this,I,null),u(this,S,0),u(this,j,100),u(this,L,null),this.setGpsOptions(e),u(this,O,null),u(this,_,0),u(this,T,0),u(this,P,l)}setProjection(t){u(this,E,t)}setGpsOptions(t={}){t.gpsMinDistance!==void 0&&u(this,S,t.gpsMinDistance),t.gpsMinAccuracy!==void 0&&u(this,j,t.gpsMinAccuracy)}async startGps(){if(s(this,P)){const i=await(await s(this,P).sendData("/gps/start",{gpsMinDistance:s(this,S),gpsMinAccuracy:s(this,j)})).json();u(this,T,i.session)}return s(this,L)===null?(u(this,L,navigator.geolocation.watchPosition(t=>{y(this,M,k).call(this,t)},t=>{s(this,D).gpserror?s(this,D).gpserror(t.code):alert(`GPS error: code ${t.code}`)},{enableHighAccuracy:!0})),!0):!1}stopGps(){return s(this,L)!==null?(navigator.geolocation.clearWatch(s(this,L)),u(this,L,null),!0):!1}fakeGps(t,i,e=null,l=0){e!==null&&this.setElevation(e),y(this,M,k).call(this,{coords:{longitude:t,latitude:i,accuracy:l}})}lonLatToWorldCoords(t,i){const e=s(this,E).project(t,i);if(s(this,O))e[0]-=s(this,O)[0],e[1]-=s(this,O)[1];else throw"No initial position determined";return[e[0],-e[1]]}add(t,i,e,l,h={}){var p;t.properties=h,y(this,M,H).call(this,t,i,e,l),this.scene.add(t),(p=s(this,P))==null||p.sendData("/object/new",{position:t.position,x:t.position.x,z:t.position.z,session:s(this,T),properties:h})}setElevation(t){this.camera.position.y=t}on(t,i){s(this,D)[t]=i}}E=new WeakMap,D=new WeakMap,I=new WeakMap,S=new WeakMap,j=new WeakMap,L=new WeakMap,O=new WeakMap,_=new WeakMap,T=new WeakMap,P=new WeakMap,M=new WeakSet,H=function(t,i,e,l){const h=this.lonLatToWorldCoords(i,e);l!==void 0&&(t.position.y=l),[t.position.x,t.position.z]=h},Z=function(t,i){u(this,O,s(this,E).project(t,i))},k=function(t){var e,l,h;let i=Number.MAX_VALUE;Q(this,_)._++,(e=s(this,P))==null||e.sendData("/gps/new",{gpsCount:s(this,_),lat:t.coords.latitude,lon:t.coords.longitude,acc:t.coords.accuracy,session:s(this,T)}),t.coords.accuracy<=s(this,j)&&(s(this,I)===null?u(this,I,{latitude:t.coords.latitude,longitude:t.coords.longitude}):i=y(this,M,B).call(this,s(this,I),t.coords),i>=s(this,S)&&(s(this,I).longitude=t.coords.longitude,s(this,I).latitude=t.coords.latitude,s(this,O)||(y(this,M,Z).call(this,t.coords.longitude,t.coords.latitude),(l=s(this,P))==null||l.sendData("/worldorigin/new",{gpsCount:s(this,_),lat:t.coords.latitude,lon:t.coords.longitude,session:s(this,T),initialPosition:s(this,O)})),y(this,M,H).call(this,this.camera,t.coords.longitude,t.coords.latitude),(h=s(this,P))==null||h.sendData("/gps/accepted",{gpsCount:s(this,_),cameraX:this.camera.position.x,cameraZ:this.camera.position.z,session:s(this,T),distMoved:i}),s(this,D).gpsupdate&&s(this,D).gpsupdate(t,i)))},B=function(t,i){const e=m.MathUtils.degToRad(i.longitude-t.longitude),l=m.MathUtils.degToRad(i.latitude-t.latitude),h=Math.sin(l/2)*Math.sin(l/2)+Math.cos(m.MathUtils.degToRad(t.latitude))*Math.cos(m.MathUtils.degToRad(i.latitude))*(Math.sin(e/2)*Math.sin(e/2));return 2*Math.atan2(Math.sqrt(h),Math.sqrt(1-h))*6371e3};class ${constructor(t={},i){this.sceneWebcam=new m.Scene;let e;if(i?e=document.querySelector(i):(e=document.createElement("video"),e.setAttribute("autoplay",!0),e.setAttribute("playsinline",!0),e.style.display="none",document.body.appendChild(e)),this.texture=new m.VideoTexture(e),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const l={video:{width:{ideal:t.idealWidth||1280},height:{ideal:t.idealHeight||720},facingMode:"environment"}};navigator.mediaDevices.getUserMedia(l).then(h=>{e.addEventListener("loadedmetadata",()=>{var p;e.setAttribute("width",e.videoWidth),e.setAttribute("height",e.videoHeight),e.play(),(p=t.onVideoStarted)==null||p.call(this,this.texture)}),e.srcObject=h}).catch(h=>{setTimeout(()=>{alert(`Webcam Error
2
- Name: `+h.name+`
3
- Message: `+h.message)},1e3)})}else setTimeout(()=>{alert("sorry - media devices API not supported")},1e3)}dispose(){this.texture.dispose()}}const R=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,J=new n.Vector3(0,0,1),z=new n.Euler,tt=new n.Quaternion,et=new n.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),it={type:"change"};class nt extends n.EventDispatcher{constructor(t,i={}){super(),window.isSecureContext===!1&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const e=this,l=1e-6,h=new n.Quaternion;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation=null,this.screenOrientation=0,this.alphaOffset=0,this.initialOffset=null,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=i.smoothingFactor||1;const p=function({alpha:o,beta:r,gamma:c,webkitCompassHeading:g}){if(R){const d=360-g;e.alphaOffset=n.MathUtils.degToRad(d-o),e.deviceOrientation={alpha:o,beta:r,gamma:c,webkitCompassHeading:g}}else o<0&&(o+=360),e.deviceOrientation={alpha:o,beta:r,gamma:c};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:t.rotation}}))},x=function(){e.screenOrientation=window.orientation||0},F=function(o,r,c,g,d){z.set(c,r,-g,"YXZ"),o.setFromEuler(z),o.multiply(et),o.multiply(tt.setFromAxisAngle(J,-d))};this.connect=function(){x(),window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(o=>{o==="granted"&&(window.addEventListener("orientationchange",x),window.addEventListener(e.orientationChangeEventName,p))}).catch(function(o){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",o)}):(window.addEventListener("orientationchange",x),window.addEventListener(e.orientationChangeEventName,p)),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",x),window.removeEventListener(e.orientationChangeEventName,p),e.enabled=!1,e.initialOffset=!1,e.deviceOrientation=null},this.update=function({theta:o=0}={theta:0}){if(e.enabled===!1)return;const r=e.deviceOrientation;if(r){let c=r.alpha?n.MathUtils.degToRad(r.alpha)+e.alphaOffset:0,g=r.beta?n.MathUtils.degToRad(r.beta):0,d=r.gamma?n.MathUtils.degToRad(r.gamma):0;const U=e.screenOrientation?n.MathUtils.degToRad(e.screenOrientation):0;if(R){const A=new n.Quaternion;F(A,c,g,d,U);const C=new n.Euler().setFromQuaternion(A,"YXZ");console.log(C.x,C.y,C.z),C.y=n.MathUtils.degToRad(360-r.webkitCompassHeading),A.setFromEuler(C),e.object.quaternion.copy(A)}else{if(this.smoothingFactor<1){if(this.lastOrientation){const A=this.smoothingFactor;c=this._getSmoothedAngle(c,this.lastOrientation.alpha,A),g=this._getSmoothedAngle(g+Math.PI,this.lastOrientation.beta,A),d=this._getSmoothedAngle(d+this.HALF_PI,this.lastOrientation.gamma,A,Math.PI)}else g+=Math.PI,d+=this.HALF_PI;this.lastOrientation={alpha:c,beta:g,gamma:d}}F(e.object.quaternion,c+o,this.smoothingFactor<1?g-Math.PI:g,this.smoothingFactor<1?d-this.HALF_PI:d,U)}8*(1-h.dot(e.object.quaternion))>l&&(h.copy(e.object.quaternion),e.dispatchEvent(it))}},this._orderAngle=function(o,r,c=this.TWO_PI){return r>o&&Math.abs(r-o)<c/2||o>r&&Math.abs(r-o)>c/2?{left:o,right:r}:{left:r,right:o}},this._getSmoothedAngle=function(o,r,c,g=this.TWO_PI){const d=this._orderAngle(o,r,g),U=d.left,A=d.right;d.left=0,d.right-=U,d.right<0&&(d.right+=g);let C=A==r?(1-c)*d.right+c*d.left:c*d.right+(1-c)*d.left;return C+=U,C>=g&&(C-=g),C},this.updateAlphaOffset=function(){e.initialOffset=!1},this.dispose=function(){e.disconnect()},this.getAlpha=function(){const{deviceOrientation:o}=e;return o&&o.alpha?n.MathUtils.degToRad(o.alpha)+e.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:o}=e;return o&&o.beta?n.MathUtils.degToRad(o.beta):0},window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?this.initPermissionDialog():this.connect()}initPermissionDialog(){const t=document.createElement("div"),i=document.createElement("div"),e=document.createElement("div"),l=document.createElement("div");document.body.appendChild(t);const h={display:"flex",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:1,backgroundColor:"rgba(0,0,0,0.6)",justifyContent:"center",alignItems:"center"},p={backgroundColor:"white",padding:"6px",borderRadius:"3px",width:"36rem",height:"24rem"},x={width:"100%",height:"70%",display:"flex",justifyContent:"center",alignItems:"center"},F={display:"inline-flex",width:"100%",height:"30%",justifyContent:"center",alignItems:"center"};for(let c in h)t.style[c]=h[c];for(let c in p)i.style[c]=p[c];for(let c in x)e.style[c]=x[c];for(let c in F)l.style[c]=F[c];t.appendChild(i),i.appendChild(e),i.appendChild(l),e.innerHTML='<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';const o=()=>{this.connect(),t.style.display="none"},r=document.createElement("button");r.addEventListener("click",o),r.style.width="50%",r.style.height="80%",r.style.fontSize="20pt",r.appendChild(document.createTextNode("OK")),l.appendChild(r),document.body.appendChild(t)}}class st{constructor(t){this.raycaster=new m.Raycaster,this.normalisedMousePosition=new m.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 ot="0.0.10-noaframe-1";a.ClickHandler=st,a.DeviceOrientationControls=nt,a.LocationBased=K,a.SphMercProjection=W,a.Webcam=$,a.version=ot,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d.locar={},d.THREE))})(this,(function(d,c){"use strict";function E(u){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(u){for(const i in u)if(i!=="default"){const e=Object.getOwnPropertyDescriptor(u,i);Object.defineProperty(t,i,e.get?e:{enumerable:!0,get:()=>u[i]})}}return t.default=u,Object.freeze(t)}const v=E(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 y{constructor(){this.eventHandlers={}}on(t,i){this.eventHandlers[t]=i}emit(t,...i){this.eventHandlers[t]?.call(this,...i)}}class C extends y{#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.#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=v.MathUtils.degToRad(i.longitude-t.longitude),l=v.MathUtils.degToRad(i.latitude-t.latitude),m=Math.sin(l/2)*Math.sin(l/2)+Math.cos(v.MathUtils.degToRad(t.latitude))*Math.cos(v.MathUtils.degToRad(i.latitude))*(Math.sin(e/2)*Math.sin(e/2));return 2*Math.atan2(Math.sqrt(m),Math.sqrt(1-m))*6371e3}}class _ extends y{#t;constructor(t={video:{facingMode:"environment"}},i){super(),this.sceneWebcam=new v.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 v.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 w=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,b=new c.Vector3(0,0,1),I=new c.Euler,D=new c.Quaternion,T=new c.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5));class L extends c.EventDispatcher{constructor(t,i={}){super(),this.eventEmitter=new y;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",console.log("Device Orientation Event Name:",this.orientationChangeEventName),this.smoothingFactor=i.smoothingFactor||1,this.enablePermissionDialog=i.enablePermissionDialog??!0;const l=function({alpha:n,beta:s,gamma:a,webkitCompassHeading:r}){if(w){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,w&&(e.screenOrientation===90?e.orientationOffset=-e.HALF_PI:e.screenOrientation===-90?e.orientationOffset=e.HALF_PI:e.orientationOffset=0)},P=function(n,s,a,r,o){I.set(a,s,-r,"YXZ"),n.setFromEuler(I),n.multiply(T),n.multiply(D.setFromAxisAngle(b,-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"})}):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 p=e.screenOrientation?c.MathUtils.degToRad(e.screenOrientation):0;if(e.smoothingFactor<1){if(e.lastOrientation){const h=e.smoothingFactor;a=e._getSmoothedAngle(a,e.lastOrientation.alpha,h),r=e._getSmoothedAngle(r+Math.PI,e.lastOrientation.beta,h),o=e._getSmoothedAngle(o+e.HALF_PI,e.lastOrientation.gamma,h,Math.PI)}else r+=Math.PI,o+=e.HALF_PI;e.lastOrientation={alpha:a,beta:r,gamma:o}}if(w){const h=new c.Quaternion;P(h,a,e.smoothingFactor<1?r-Math.PI:r,e.smoothingFactor<1?o-Math.PI/2:o,p);const f=new c.Euler().setFromQuaternion(h,"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),h.setFromEuler(f),e.object.quaternion.copy(h)}else P(e.object.quaternion,w?a+e.alphaOffset:a,e.smoothingFactor<1?r-Math.PI:r,e.smoothingFactor<1?o-Math.PI/2:o,p)}},this.getCorrectedHeading=function(){const{deviceOrientation:n}=e;if(!n)return 0;let s=0;return w?(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),p=o.left,h=o.right;o.left=0,o.right-=p,o.right<0&&(o.right+=r);let f=h==s?(1-a)*o.right+a*o.left:a*o.right+(1-a)*o.left;return f+=p,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.obtainPermissionGesture=function(){const n=document.createElement("div"),s=document.createElement("div"),a=document.createElement("div"),r=document.createElement("div");document.body.appendChild(n);const o={display:"flex",position:"fixed",top:0,left:0,width:"100%",height:"100%",zIndex:1,backgroundColor:"rgba(0,0,0,0.6)",justifyContent:"center",alignItems:"center"},p={backgroundColor:"white",padding:"6px",borderRadius:"3px",width:"36rem",height:"24rem"},h={width:"100%",height:"70%",display:"flex",justifyContent:"center",alignItems:"center"},f={display:"inline-flex",width:"100%",height:"30%",justifyContent:"center",alignItems:"center"};for(let g in o)n.style[g]=o[g];for(let g in p)s.style[g]=p[g];for(let g in h)a.style[g]=h[g];for(let g in f)r.style[g]=f[g];n.appendChild(s),s.appendChild(a),s.appendChild(r),a.innerHTML='<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';const O=()=>{this.requestOrientationPermissions(),n.style.display="none"},M=document.createElement("button");M.addEventListener("click",O),M.style.width="50%",M.style.height="80%",M.style.fontSize="20pt",M.appendChild(document.createTextNode("OK")),r.appendChild(M),document.body.appendChild(n)}}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 R{constructor(t){this.raycaster=new v.Raycaster,this.normalisedMousePosition=new v.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 S="0.1.0";d.ClickHandler=R,d.DeviceOrientationControls=L,d.EventEmitter=y,d.LocationBased=C,d.SphMercProjection=A,d.Webcam=_,d.version=S,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locar",
3
- "version": "0.0.12",
3
+ "version": "0.1.0",
4
4
  "description": "Location-based AR from AR.js.",
5
5
  "files": [
6
6
  "dist"
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "jsdoc": "^4.0.4",
22
- "vite": "^5.4.8"
22
+ "vite": "^7.1.3"
23
23
  },
24
24
  "dependencies": {
25
25
  "three": "^0.175.0"