locar 0.0.11 → 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 W = (a) => {
2
- throw TypeError(a);
3
- };
4
- var S = (a, t, e) => t.has(a) || W("Cannot " + e);
5
- var n = (a, t, e) => (S(a, t, "read from private field"), e ? e.call(a) : t.get(a)), m = (a, t, e) => t.has(a) ? W("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(a) : t.set(a, e), u = (a, t, e, i) => (S(a, t, "write to private field"), i ? i.call(a, e) : t.set(a, e), e), p = (a, t, e) => (S(a, t, "access private method"), e);
6
- var q = (a, t, e, i) => ({
7
- set _(r) {
8
- u(a, t, r, e);
9
- },
10
- get _() {
11
- return n(a, t, i);
12
- }
13
- });
14
- import * as b from "three";
15
- import { Vector3 as Z, Euler as N, Quaternion as _, EventDispatcher as B, MathUtils as C } from "three";
16
- var E, U, G, X, Q;
17
- class K {
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 K {
28
13
  * @param {number} lat - the latitude.
29
14
  * @return {Array} Two-member array containing easting and northing.
30
15
  */
31
- project(t, e) {
32
- return [p(this, E, U).call(this, t), p(this, E, G).call(this, e)];
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, X).call(this, t[0]), p(this, E, Q).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 K {
47
46
  return "epsg:3857";
48
47
  }
49
48
  }
50
- E = new WeakSet(), U = function(t) {
51
- return t / 180 * this.HALF_EARTH;
52
- }, G = function(t) {
53
- var e = Math.log(Math.tan((90 + t) * Math.PI / 360)) / (Math.PI / 180);
54
- return e * this.HALF_EARTH / 180;
55
- }, X = function(t) {
56
- return t / this.HALF_EARTH * 180;
57
- }, Q = function(t) {
58
- var e = t / this.HALF_EARTH * 180;
59
- return e = 180 / Math.PI * (2 * Math.atan(Math.exp(e * Math.PI / 180)) - Math.PI / 2), e;
60
- };
61
- var I, O, P, x, H, A, y, D, T, M, f, F, V, j, Y;
62
- class st {
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 st {
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, e, i = {}, r = null) {
72
- m(this, f);
73
- m(this, I);
74
- m(this, O);
75
- m(this, P);
76
- m(this, x);
77
- m(this, H);
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 = e, u(this, I, new K()), u(this, O, {}), u(this, P, null), u(this, x, 0), u(this, H, 100), u(this, A, null), this.setGpsOptions(i), u(this, y, null), u(this, D, 0), u(this, T, 0), u(this, M, r);
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 st {
88
95
  * taking longitude and latitude as arguments and returning an array
89
96
  * containing easting and northing.
90
97
  */
91
- setProjection(t) {
92
- u(this, I, t);
98
+ setProjection(e) {
99
+ this.#t = e;
93
100
  }
94
101
  /**
95
102
  * Set the GPS options.
@@ -98,8 +105,8 @@ class st {
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 && u(this, x, t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && u(this, H, 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 st {
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 e = await (await n(this, M).sendData("/gps/start", {
112
- gpsMinDistance: n(this, x),
113
- gpsMinAccuracy: n(this, H)
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
- u(this, T, e.session);
122
+ this.#a = i.session;
116
123
  }
117
- return n(this, A) === null ? (u(this, A, navigator.geolocation.watchPosition(
118
- (t) => {
119
- p(this, f, j).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 st {
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)), u(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,12 +150,12 @@ class st {
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, e, i = null, r = 0) {
147
- i !== null && this.setElevation(i), p(this, f, j).call(this, {
153
+ fakeGps(e, i, t = null, c = 0) {
154
+ t !== null && this.setElevation(t), this.#l({
148
155
  coords: {
149
- longitude: t,
150
- latitude: e,
151
- accuracy: r
156
+ longitude: e,
157
+ latitude: i,
158
+ accuracy: c
152
159
  }
153
160
  });
154
161
  }
@@ -158,17 +165,18 @@ class st {
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, e) {
166
- const i = n(this, I).project(t, e);
167
- if (n(this, y))
168
- i[0] -= n(this, y)[0], i[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 [i[0], -i[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 st {
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, e, i, r, h = {}) {
184
- var g;
185
- t.properties = h, p(this, f, F).call(this, t, e, i, r), 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),
190
- properties: h
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,
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, e) {
214
- n(this, O)[t] = e;
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
- I = new WeakMap(), O = new WeakMap(), P = new WeakMap(), x = new WeakMap(), H = new WeakMap(), A = new WeakMap(), y = new WeakMap(), D = new WeakMap(), T = new WeakMap(), M = new WeakMap(), f = new WeakSet(), F = function(t, e, i, r) {
218
- const h = this.lonLatToWorldCoords(e, i);
219
- r !== void 0 && (t.position.y = r), [t.position.x, t.position.z] = h;
220
- }, V = function(t, e) {
221
- u(this, y, n(this, I).project(t, e));
222
- }, j = function(t) {
223
- var i, r, h;
224
- let e = Number.MAX_VALUE;
225
- q(this, D)._++, (i = n(this, M)) == null || i.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, H) && (n(this, P) === null ? u(this, P, {
232
- latitude: t.coords.latitude,
233
- longitude: t.coords.longitude
234
- }) : e = p(this, f, Y).call(this, n(this, P), t.coords), e >= n(this, x) && (n(this, P).longitude = t.coords.longitude, n(this, P).latitude = t.coords.latitude, n(this, y) || (p(this, f, V).call(this, t.coords.longitude, t.coords.latitude), (r = n(this, M)) == null || r.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, F).call(this, this.camera, t.coords.longitude, t.coords.latitude), (h = n(this, M)) == null || h.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: e
246
- }), n(this, O).gpsupdate && n(this, O).gpsupdate(t, e)));
247
- }, /**
248
- * Calculate haversine distance between two lat/lon pairs.
249
- *
250
- * Taken from original A-Frame AR.js location-based components
251
- */
252
- Y = function(t, e) {
253
- const i = b.MathUtils.degToRad(e.longitude - t.longitude), r = b.MathUtils.degToRad(e.latitude - t.latitude), h = Math.sin(r / 2) * Math.sin(r / 2) + Math.cos(b.MathUtils.degToRad(t.latitude)) * Math.cos(b.MathUtils.degToRad(e.latitude)) * (Math.sin(i / 2) * Math.sin(i / 2));
254
- return 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)) * 6371e3;
255
- };
256
- class ot {
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 = {}, e) {
270
- this.sceneWebcam = new b.Scene();
271
- let i;
272
- if (e ? i = document.querySelector(e) : (i = document.createElement("video"), i.setAttribute("autoplay", !0), i.setAttribute("playsinline", !0), i.style.display = "none", document.body.appendChild(i)), this.texture = new b.VideoTexture(i), navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
273
- const r = {
274
- video: {
275
- width: { ideal: t.idealWidth || 1280 },
276
- height: { ideal: t.idealHeight || 720 },
277
- facingMode: "environment"
278
- }
279
- };
280
- navigator.mediaDevices.getUserMedia(r).then((h) => {
281
- i.addEventListener("loadedmetadata", () => {
282
- var g;
283
- i.setAttribute("width", i.videoWidth), i.setAttribute("height", i.videoHeight), i.play(), (g = t.onVideoStarted) == null || g.call(this, this.texture);
284
- }), i.srcObject = h;
285
- }).catch((h) => {
286
- setTimeout(() => {
287
- alert(
288
- `Webcam Error
289
- Name: ` + h.name + `
290
- Message: ` + h.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,202 +286,224 @@ Message: ` + h.message
304
286
  this.texture.dispose();
305
287
  }
306
288
  }
307
- const k = navigator.userAgent.match(/iPhone|iPad|iPod/i) || /Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints != null && navigator.maxTouchPoints > 1, $ = new Z(0, 0, 1), z = new N(), J = new _(), tt = new _(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)), et = { type: "change" };
308
- class at extends B {
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
- */
314
- constructor(t) {
315
- super(), window.isSecureContext === !1 && console.error(
316
- "THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)"
317
- );
318
- const e = this, i = 1e-6, r = new _();
319
- this.object = t, this.object.rotation.reorder("YXZ"), this.enabled = !0, this.deviceOrientation = null, this.screenOrientation = 0, this.alphaOffset = 0, this.initialOffset = null, this.TWO_PI = 2 * Math.PI, this.HALF_PI = 0.5 * Math.PI, this.orientationChangeEventName = "ondeviceorientationabsolute" in window ? "deviceorientationabsolute" : "deviceorientation", this.smoothingFactor = 1;
320
- const h = function({
321
- alpha: s,
322
- beta: c,
323
- gamma: d,
324
- webkitCompassHeading: 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,
304
+ gamma: a,
305
+ webkitCompassHeading: r
325
306
  }) {
326
- if (k) {
327
- const l = 360 - o;
328
- e.alphaOffset = C.degToRad(l - s), e.deviceOrientation = { alpha: s, beta: c, gamma: d, webkitCompassHeading: o };
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 };
329
310
  } else
330
- s < 0 && (s += 360), e.deviceOrientation = { alpha: s, beta: c, gamma: d };
311
+ n < 0 && (n += 360), t.deviceOrientation = { alpha: n, beta: s, gamma: a };
331
312
  window.dispatchEvent(
332
313
  new CustomEvent("camera-rotation-change", {
333
- detail: { cameraRotation: t.rotation }
314
+ detail: { cameraRotation: e.rotation }
334
315
  })
335
316
  );
336
- }, g = function() {
337
- e.screenOrientation = window.orientation || 0;
338
- }, L = function(s, c, d, o, l) {
339
- z.set(d, c, -o, "YXZ"), s.setFromEuler(z), s.multiply(tt), s.multiply(J.setFromAxisAngle($, -l));
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));
340
321
  };
341
322
  this.connect = function() {
342
- g(), window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((s) => {
343
- s === "granted" && (window.addEventListener(
344
- "orientationchange",
345
- g
346
- ), window.addEventListener(
347
- e.orientationChangeEventName,
348
- h
349
- ));
350
- }).catch(function(s) {
351
- console.error(
352
- "THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",
353
- s
354
- );
355
- }) : (window.addEventListener(
323
+ d(), window.addEventListener(
356
324
  "orientationchange",
357
- g
325
+ d
358
326
  ), window.addEventListener(
359
- e.orientationChangeEventName,
360
- h
361
- )), e.enabled = !0;
327
+ t.orientationChangeEventName,
328
+ c
329
+ ), t.enabled = !0;
362
330
  }, this.disconnect = function() {
363
331
  window.removeEventListener(
364
332
  "orientationchange",
365
- g
333
+ d
366
334
  ), window.removeEventListener(
367
- e.orientationChangeEventName,
368
- h
369
- ), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
370
- }, this.update = function({ theta: s = 0 } = { theta: 0 }) {
371
- if (e.enabled === !1) return;
372
- const c = e.deviceOrientation;
373
- if (c) {
374
- let d = c.alpha ? C.degToRad(c.alpha) + e.alphaOffset : 0, o = c.beta ? C.degToRad(c.beta) : 0, l = c.gamma ? C.degToRad(c.gamma) : 0;
375
- const R = e.screenOrientation ? C.degToRad(e.screenOrientation) : 0;
376
- if (k) {
377
- const v = new _();
378
- L(v, d, o, l, R);
379
- const w = new N().setFromQuaternion(
380
- 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,
381
397
  "YXZ"
382
398
  );
383
- console.log(w.x, w.y, w.z), w.y = C.degToRad(
384
- 360 - c.webkitCompassHeading
385
- ), v.setFromEuler(w), e.object.quaternion.copy(v);
386
- } else {
387
- if (this.smoothingFactor < 1) {
388
- if (this.lastOrientation) {
389
- const v = this.smoothingFactor;
390
- d = this._getSmoothedAngle(
391
- d,
392
- this.lastOrientation.alpha,
393
- v
394
- ), o = this._getSmoothedAngle(
395
- o + Math.PI,
396
- this.lastOrientation.beta,
397
- v
398
- ), l = this._getSmoothedAngle(
399
- l + this.HALF_PI,
400
- this.lastOrientation.gamma,
401
- v,
402
- Math.PI
403
- );
404
- } else
405
- o += Math.PI, l += this.HALF_PI;
406
- this.lastOrientation = {
407
- alpha: d,
408
- beta: o,
409
- gamma: l
410
- };
411
- }
412
- L(
413
- e.object.quaternion,
414
- d + s,
415
- this.smoothingFactor < 1 ? o - Math.PI : o,
416
- this.smoothingFactor < 1 ? l - this.HALF_PI : l,
417
- R
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
418
408
  );
419
- }
420
- 8 * (1 - r.dot(e.object.quaternion)) > i && (r.copy(e.object.quaternion), e.dispatchEvent(et));
421
409
  }
422
- }, this._orderAngle = function(s, c, d = this.TWO_PI) {
423
- return c > s && Math.abs(c - s) < d / 2 || s > c && Math.abs(c - s) > d / 2 ? { left: s, right: c } : { left: c, right: s };
424
- }, this._getSmoothedAngle = function(s, c, d, o = this.TWO_PI) {
425
- const l = this._orderAngle(s, c, o), R = l.left, v = l.right;
426
- l.left = 0, l.right -= R, l.right < 0 && (l.right += o);
427
- let w = v == c ? (1 - d) * l.right + d * l.left : d * l.right + (1 - d) * l.left;
428
- return w += R, w >= o && (w -= o), 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;
429
422
  }, this.updateAlphaOffset = function() {
430
- e.initialOffset = !1;
423
+ t.initialOffset = !1;
431
424
  }, this.dispose = function() {
432
- e.disconnect();
425
+ t.disconnect();
433
426
  }, this.getAlpha = function() {
434
- const { deviceOrientation: s } = e;
435
- 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;
436
429
  }, this.getBeta = function() {
437
- const { deviceOrientation: s } = e;
438
- return s && s.beta ? C.degToRad(s.beta) : 0;
439
- }, window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? this.initPermissionDialog() : this.connect();
440
- }
441
- // Provide gesture before initialising device orientation controls
442
- // From PR #659 on the main AR.js repo
443
- // Thanks to @ma2yama
444
- initPermissionDialog() {
445
- const t = document.createElement("div"), e = document.createElement("div"), i = document.createElement("div"), r = document.createElement("div");
446
- document.body.appendChild(t);
447
- const h = {
448
- display: "flex",
449
- position: "fixed",
450
- top: 0,
451
- left: 0,
452
- width: "100%",
453
- height: "100%",
454
- zIndex: 1,
455
- backgroundColor: "rgba(0,0,0,0.6)",
456
- justifyContent: "center",
457
- alignItems: "center"
458
- }, g = {
459
- backgroundColor: "white",
460
- padding: "6px",
461
- borderRadius: "3px",
462
- width: "36rem",
463
- height: "24rem"
464
- }, L = {
465
- width: "100%",
466
- height: "70%",
467
- display: "flex",
468
- justifyContent: "center",
469
- alignItems: "center"
470
- }, s = {
471
- display: "inline-flex",
472
- width: "100%",
473
- height: "30%",
474
- justifyContent: "center",
475
- 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);
476
481
  };
477
- for (let o in h)
478
- t.style[o] = h[o];
479
- for (let o in g)
480
- e.style[o] = g[o];
481
- for (let o in L)
482
- i.style[o] = L[o];
483
- for (let o in s)
484
- r.style[o] = s[o];
485
- t.appendChild(e), e.appendChild(i), e.appendChild(r), i.innerHTML = '<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';
486
- const c = () => {
487
- this.connect(), t.style.display = "none";
488
- }, d = document.createElement("button");
489
- d.addEventListener("click", c), d.style.width = "50%", d.style.height = "80%", d.style.fontSize = "20pt", d.appendChild(document.createTextNode("OK")), r.appendChild(d), 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 });
490
494
  }
491
495
  }
492
- class rt {
496
+ class N {
493
497
  /**
494
498
  * Create a ClickHandler.
495
499
  * @param {THREE.WebGLRenderer} - The Three.js renderer on which the click
496
500
  * events will be handled.
497
501
  */
498
- constructor(t) {
499
- this.raycaster = new b.Raycaster(), this.normalisedMousePosition = new b.Vector2(null, null), t.domElement.addEventListener("click", (e) => {
502
+ constructor(e) {
503
+ this.raycaster = new f.Raycaster(), this.normalisedMousePosition = new f.Vector2(null, null), e.domElement.addEventListener("click", (i) => {
500
504
  this.normalisedMousePosition.set(
501
- e.clientX / t.domElement.clientWidth * 2 - 1,
502
- -(e.clientY / t.domElement.clientHeight * 2) + 1
505
+ i.clientX / e.domElement.clientWidth * 2 - 1,
506
+ -(i.clientY / e.domElement.clientHeight * 2) + 1
503
507
  );
504
508
  });
505
509
  }
@@ -511,21 +515,22 @@ class rt {
511
515
  * cast into.
512
516
  * @return {Array} - array of all intersected objects.
513
517
  */
514
- raycast(t, e) {
518
+ raycast(e, i) {
515
519
  if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
516
- this.raycaster.setFromCamera(this.normalisedMousePosition, t);
517
- const i = this.raycaster.intersectObjects(e.children, !1);
518
- return this.normalisedMousePosition.set(null, null), i;
520
+ this.raycaster.setFromCamera(this.normalisedMousePosition, e);
521
+ const t = this.raycaster.intersectObjects(i.children, !1);
522
+ return this.normalisedMousePosition.set(null, null), t;
519
523
  }
520
524
  return [];
521
525
  }
522
526
  }
523
- const ct = "0.0.10-noaframe-1";
527
+ const S = "0.1.0";
524
528
  export {
525
- rt as ClickHandler,
526
- at as DeviceOrientationControls,
527
- st as LocationBased,
528
- K as SphMercProjection,
529
- ot as Webcam,
530
- ct 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
531
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 z=a=>{throw TypeError(a)};var W=(a,n,f)=>n.has(a)||z("Cannot "+f);var s=(a,n,f)=>(W(a,n,"read from private field"),f?f.call(a):n.get(a)),v=(a,n,f)=>n.has(a)?z("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(a):n.set(a,f),g=(a,n,f,p)=>(W(a,n,"write to private field"),p?p.call(a,f):n.set(a,f),f),y=(a,n,f)=>(W(a,n,"access private method"),f);var N=(a,n,f,p)=>({set _(U){g(a,n,U,f)},get _(){return s(a,n,p)}});var w,Q,G,X,V,E,D,I,S,j,L,O,_,T,P,M,q,Y,H,Z;function f(b){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(b){for(const e in b)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(b,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>b[e]})}}return t.default=b,Object.freeze(t)}const p=f(n);class U{constructor(){v(this,w);this.EARTH=4007501668e-2,this.HALF_EARTH=2003750834e-2}project(t,e){return[y(this,w,Q).call(this,t),y(this,w,G).call(this,e)]}unproject(t){return[y(this,w,X).call(this,t[0]),y(this,w,V).call(this,t[1])]}getID(){return"epsg:3857"}}w=new WeakSet,Q=function(t){return t/180*this.HALF_EARTH},G=function(t){var e=Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180);return e*this.HALF_EARTH/180},X=function(t){return t/this.HALF_EARTH*180},V=function(t){var e=t/this.HALF_EARTH*180;return e=180/Math.PI*(2*Math.atan(Math.exp(e*Math.PI/180))-Math.PI/2),e};class B{constructor(t,e,i={},d=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=e,g(this,E,new U),g(this,D,{}),g(this,I,null),g(this,S,0),g(this,j,100),g(this,L,null),this.setGpsOptions(i),g(this,O,null),g(this,_,0),g(this,T,0),g(this,P,d)}setProjection(t){g(this,E,t)}setGpsOptions(t={}){t.gpsMinDistance!==void 0&&g(this,S,t.gpsMinDistance),t.gpsMinAccuracy!==void 0&&g(this,j,t.gpsMinAccuracy)}async startGps(){if(s(this,P)){const e=await(await s(this,P).sendData("/gps/start",{gpsMinDistance:s(this,S),gpsMinAccuracy:s(this,j)})).json();g(this,T,e.session)}return s(this,L)===null?(g(this,L,navigator.geolocation.watchPosition(t=>{y(this,M,H).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)),g(this,L,null),!0):!1}fakeGps(t,e,i=null,d=0){i!==null&&this.setElevation(i),y(this,M,H).call(this,{coords:{longitude:t,latitude:e,accuracy:d}})}lonLatToWorldCoords(t,e){const i=s(this,E).project(t,e);if(s(this,O))i[0]-=s(this,O)[0],i[1]-=s(this,O)[1];else throw"No initial position determined";return[i[0],-i[1]]}add(t,e,i,d,h={}){var m;t.properties=h,y(this,M,q).call(this,t,e,i,d),this.scene.add(t),(m=s(this,P))==null||m.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,e){s(this,D)[t]=e}}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,q=function(t,e,i,d){const h=this.lonLatToWorldCoords(e,i);d!==void 0&&(t.position.y=d),[t.position.x,t.position.z]=h},Y=function(t,e){g(this,O,s(this,E).project(t,e))},H=function(t){var i,d,h;let e=Number.MAX_VALUE;N(this,_)._++,(i=s(this,P))==null||i.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?g(this,I,{latitude:t.coords.latitude,longitude:t.coords.longitude}):e=y(this,M,Z).call(this,s(this,I),t.coords),e>=s(this,S)&&(s(this,I).longitude=t.coords.longitude,s(this,I).latitude=t.coords.latitude,s(this,O)||(y(this,M,Y).call(this,t.coords.longitude,t.coords.latitude),(d=s(this,P))==null||d.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,q).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:e}),s(this,D).gpsupdate&&s(this,D).gpsupdate(t,e)))},Z=function(t,e){const i=p.MathUtils.degToRad(e.longitude-t.longitude),d=p.MathUtils.degToRad(e.latitude-t.latitude),h=Math.sin(d/2)*Math.sin(d/2)+Math.cos(p.MathUtils.degToRad(t.latitude))*Math.cos(p.MathUtils.degToRad(e.latitude))*(Math.sin(i/2)*Math.sin(i/2));return 2*Math.atan2(Math.sqrt(h),Math.sqrt(1-h))*6371e3};class K{constructor(t={},e){this.sceneWebcam=new p.Scene;let i;if(e?i=document.querySelector(e):(i=document.createElement("video"),i.setAttribute("autoplay",!0),i.setAttribute("playsinline",!0),i.style.display="none",document.body.appendChild(i)),this.texture=new p.VideoTexture(i),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const d={video:{width:{ideal:t.idealWidth||1280},height:{ideal:t.idealHeight||720},facingMode:"environment"}};navigator.mediaDevices.getUserMedia(d).then(h=>{i.addEventListener("loadedmetadata",()=>{var m;i.setAttribute("width",i.videoWidth),i.setAttribute("height",i.videoHeight),i.play(),(m=t.onVideoStarted)==null||m.call(this,this.texture)}),i.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 k=navigator.userAgent.match(/iPhone|iPad|iPod/i)||/Macintosh/i.test(navigator.userAgent)&&navigator.maxTouchPoints!=null&&navigator.maxTouchPoints>1,$=new n.Vector3(0,0,1),R=new n.Euler,J=new n.Quaternion,tt=new n.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),et={type:"change"};class it extends n.EventDispatcher{constructor(t){super(),window.isSecureContext===!1&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const e=this,i=1e-6,d=new n.Quaternion;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation=null,this.screenOrientation=0,this.alphaOffset=0,this.initialOffset=null,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=1;const h=function({alpha:o,beta:c,gamma:l,webkitCompassHeading:r}){if(k){const u=360-r;e.alphaOffset=n.MathUtils.degToRad(u-o),e.deviceOrientation={alpha:o,beta:c,gamma:l,webkitCompassHeading:r}}else o<0&&(o+=360),e.deviceOrientation={alpha:o,beta:c,gamma:l};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:t.rotation}}))},m=function(){e.screenOrientation=window.orientation||0},x=function(o,c,l,r,u){R.set(l,c,-r,"YXZ"),o.setFromEuler(R),o.multiply(tt),o.multiply(J.setFromAxisAngle($,-u))};this.connect=function(){m(),window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(o=>{o==="granted"&&(window.addEventListener("orientationchange",m),window.addEventListener(e.orientationChangeEventName,h))}).catch(function(o){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",o)}):(window.addEventListener("orientationchange",m),window.addEventListener(e.orientationChangeEventName,h)),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",m),window.removeEventListener(e.orientationChangeEventName,h),e.enabled=!1,e.initialOffset=!1,e.deviceOrientation=null},this.update=function({theta:o=0}={theta:0}){if(e.enabled===!1)return;const c=e.deviceOrientation;if(c){let l=c.alpha?n.MathUtils.degToRad(c.alpha)+e.alphaOffset:0,r=c.beta?n.MathUtils.degToRad(c.beta):0,u=c.gamma?n.MathUtils.degToRad(c.gamma):0;const F=e.screenOrientation?n.MathUtils.degToRad(e.screenOrientation):0;if(k){const A=new n.Quaternion;x(A,l,r,u,F);const C=new n.Euler().setFromQuaternion(A,"YXZ");console.log(C.x,C.y,C.z),C.y=n.MathUtils.degToRad(360-c.webkitCompassHeading),A.setFromEuler(C),e.object.quaternion.copy(A)}else{if(this.smoothingFactor<1){if(this.lastOrientation){const A=this.smoothingFactor;l=this._getSmoothedAngle(l,this.lastOrientation.alpha,A),r=this._getSmoothedAngle(r+Math.PI,this.lastOrientation.beta,A),u=this._getSmoothedAngle(u+this.HALF_PI,this.lastOrientation.gamma,A,Math.PI)}else r+=Math.PI,u+=this.HALF_PI;this.lastOrientation={alpha:l,beta:r,gamma:u}}x(e.object.quaternion,l+o,this.smoothingFactor<1?r-Math.PI:r,this.smoothingFactor<1?u-this.HALF_PI:u,F)}8*(1-d.dot(e.object.quaternion))>i&&(d.copy(e.object.quaternion),e.dispatchEvent(et))}},this._orderAngle=function(o,c,l=this.TWO_PI){return c>o&&Math.abs(c-o)<l/2||o>c&&Math.abs(c-o)>l/2?{left:o,right:c}:{left:c,right:o}},this._getSmoothedAngle=function(o,c,l,r=this.TWO_PI){const u=this._orderAngle(o,c,r),F=u.left,A=u.right;u.left=0,u.right-=F,u.right<0&&(u.right+=r);let C=A==c?(1-l)*u.right+l*u.left:l*u.right+(1-l)*u.left;return C+=F,C>=r&&(C-=r),C},this.updateAlphaOffset=function(){e.initialOffset=!1},this.dispose=function(){e.disconnect()},this.getAlpha=function(){const{deviceOrientation:o}=e;return o&&o.alpha?n.MathUtils.degToRad(o.alpha)+e.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:o}=e;return o&&o.beta?n.MathUtils.degToRad(o.beta):0},window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?this.initPermissionDialog():this.connect()}initPermissionDialog(){const t=document.createElement("div"),e=document.createElement("div"),i=document.createElement("div"),d=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"},m={backgroundColor:"white",padding:"6px",borderRadius:"3px",width:"36rem",height:"24rem"},x={width:"100%",height:"70%",display:"flex",justifyContent:"center",alignItems:"center"},o={display:"inline-flex",width:"100%",height:"30%",justifyContent:"center",alignItems:"center"};for(let r in h)t.style[r]=h[r];for(let r in m)e.style[r]=m[r];for(let r in x)i.style[r]=x[r];for(let r in o)d.style[r]=o[r];t.appendChild(e),e.appendChild(i),e.appendChild(d),i.innerHTML='<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';const c=()=>{this.connect(),t.style.display="none"},l=document.createElement("button");l.addEventListener("click",c),l.style.width="50%",l.style.height="80%",l.style.fontSize="20pt",l.appendChild(document.createTextNode("OK")),d.appendChild(l),document.body.appendChild(t)}}class nt{constructor(t){this.raycaster=new p.Raycaster,this.normalisedMousePosition=new p.Vector2(null,null),t.domElement.addEventListener("click",e=>{this.normalisedMousePosition.set(e.clientX/t.domElement.clientWidth*2-1,-(e.clientY/t.domElement.clientHeight*2)+1)})}raycast(t,e){if(this.normalisedMousePosition.x!==null&&this.normalisedMousePosition.y!==null){this.raycaster.setFromCamera(this.normalisedMousePosition,t);const i=this.raycaster.intersectObjects(e.children,!1);return this.normalisedMousePosition.set(null,null),i}return[]}}const st="0.0.10-noaframe-1";a.ClickHandler=nt,a.DeviceOrientationControls=it,a.LocationBased=B,a.SphMercProjection=U,a.Webcam=K,a.version=st,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.11",
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"