locar 0.0.3 → 0.0.7
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 +9 -1
- package/dist/locar.es.js +455 -129
- package/dist/locar.umd.js +3 -3
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ Some of these issues, such as incorrect North on some devices, may well be to do
|
|
|
22
22
|
|
|
23
23
|
For this reason, the focus at present will be on developing a **pure three.js version only**. When we believe that the key bugs and issues have been resolved, the plan is to then provide an A-Frame wrapper.
|
|
24
24
|
|
|
25
|
+
## Cross-platform Compatibility
|
|
26
|
+
|
|
27
|
+
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
|
|
28
|
+
|
|
25
29
|
## Using the library
|
|
26
30
|
|
|
27
31
|
The library has been published to `npm` so you can install with:
|
|
@@ -38,13 +42,17 @@ import * as LocAR from 'locar';
|
|
|
38
42
|
as long as you include `locar` as a dependency, e.g. in your `package.json`:
|
|
39
43
|
```
|
|
40
44
|
"dependencies": {
|
|
41
|
-
"locar" : "^0.0.
|
|
45
|
+
"locar" : "^0.0.7",
|
|
42
46
|
"three" : "^0.169.0"
|
|
43
47
|
}
|
|
44
48
|
```
|
|
45
49
|
|
|
46
50
|
Including the library bundle directly as an import has issues with duplicate three.js imports which we have not resolved, so we recommend the approach above.
|
|
47
51
|
|
|
52
|
+
## API documentation
|
|
53
|
+
|
|
54
|
+
Please see [here](https://ar-js-org.github.io/locar.js/api) for full API documentation.
|
|
55
|
+
|
|
48
56
|
## Tutorial
|
|
49
57
|
|
|
50
58
|
Please see [here](https://github.com/AR-js-org/locar.js/blob/master/docs/tutorial/index.md) for a tutorial introducing LocAR.js.
|
package/dist/locar.es.js
CHANGED
|
@@ -1,122 +1,274 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var j = (r) => {
|
|
2
|
+
throw TypeError(r);
|
|
3
|
+
};
|
|
4
|
+
var F = (r, t, e) => t.has(r) || j("Cannot " + e);
|
|
5
|
+
var n = (r, t, e) => (F(r, t, "read from private field"), e ? e.call(r) : t.get(r)), m = (r, t, e) => t.has(r) ? j("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(r) : t.set(r, e), d = (r, t, e, i) => (F(r, t, "write to private field"), i ? i.call(r, e) : t.set(r, e), e), v = (r, t, e) => (F(r, t, "access private method"), e);
|
|
6
|
+
var q = (r, t, e, i) => ({
|
|
7
|
+
set _(o) {
|
|
8
|
+
d(r, t, o, e);
|
|
9
|
+
},
|
|
10
|
+
get _() {
|
|
11
|
+
return n(r, t, i);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
import * as f from "three";
|
|
15
|
+
import { Vector3 as Z, Euler as N, Quaternion as _, EventDispatcher as B, MathUtils as D } from "three";
|
|
16
|
+
var P, U, G, X, Q;
|
|
17
|
+
class K {
|
|
18
|
+
/**
|
|
19
|
+
* Create a SphMercProjection.
|
|
20
|
+
*/
|
|
3
21
|
constructor() {
|
|
22
|
+
m(this, P);
|
|
4
23
|
this.EARTH = 4007501668e-2, this.HALF_EARTH = 2003750834e-2;
|
|
5
24
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
latToSphMerc(e) {
|
|
16
|
-
var t = Math.log(Math.tan((90 + e) * Math.PI / 360)) / (Math.PI / 180);
|
|
17
|
-
return t * this.HALF_EARTH / 180;
|
|
18
|
-
}
|
|
19
|
-
sphMercToLon(e) {
|
|
20
|
-
return e / this.HALF_EARTH * 180;
|
|
25
|
+
/**
|
|
26
|
+
* Project a longitude and latitude into Spherical Mercator.
|
|
27
|
+
* @param {number} lon - the longitude.
|
|
28
|
+
* @param {number} lat - the latitude.
|
|
29
|
+
* @return {Array} Two-member array containing easting and northing.
|
|
30
|
+
*/
|
|
31
|
+
project(t, e) {
|
|
32
|
+
return [v(this, P, U).call(this, t), v(this, P, G).call(this, e)];
|
|
21
33
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Unproject a Spherical Mercator easting and northing.
|
|
36
|
+
* @param {Array} projected - Two-member array containing easting and northing
|
|
37
|
+
* @return {Array} Two-member array containing longitude and latitude
|
|
38
|
+
*/
|
|
39
|
+
unproject(t) {
|
|
40
|
+
return [v(this, P, X).call(this, t[0]), v(this, P, Q).call(this, t[1])];
|
|
25
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Return the projection's ID.
|
|
44
|
+
* @return {string} The value "epsg:3857".
|
|
45
|
+
*/
|
|
26
46
|
getID() {
|
|
27
47
|
return "epsg:3857";
|
|
28
48
|
}
|
|
29
49
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
P = 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 R, A, C, L, x, b, E, I, T, O, p, S, V, W, Y;
|
|
62
|
+
class st {
|
|
63
|
+
/**
|
|
64
|
+
* @param {THREE.Scene} scene - The Three.js scene to use.
|
|
65
|
+
* @param {THREE.Camera} camera - The Three.js camera to use. Should usually
|
|
66
|
+
* be a THREE.PerspectiveCamera.
|
|
67
|
+
* @param {Object} options - Initialisation options for the GPS; see
|
|
68
|
+
* setGpsOptions() below.
|
|
69
|
+
* @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
|
+
*/
|
|
71
|
+
constructor(t, e, i = {}, o = null) {
|
|
72
|
+
m(this, p);
|
|
73
|
+
m(this, R);
|
|
74
|
+
m(this, A);
|
|
75
|
+
m(this, C);
|
|
76
|
+
m(this, L);
|
|
77
|
+
m(this, x);
|
|
78
|
+
m(this, b);
|
|
79
|
+
m(this, E);
|
|
80
|
+
m(this, I);
|
|
81
|
+
m(this, T);
|
|
82
|
+
m(this, O);
|
|
83
|
+
this.scene = t, this.camera = e, d(this, R, new K()), d(this, A, {}), d(this, C, null), d(this, L, 0), d(this, x, 100), d(this, b, null), this.setGpsOptions(i), d(this, E, null), d(this, I, 0), d(this, T, 0), d(this, O, o);
|
|
33
84
|
}
|
|
34
|
-
|
|
35
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Set the projection to use.
|
|
87
|
+
* @param {Object} any object which includes a project() method
|
|
88
|
+
* taking longitude and latitude as arguments and returning an array
|
|
89
|
+
* containing easting and northing.
|
|
90
|
+
*/
|
|
91
|
+
setProjection(t) {
|
|
92
|
+
d(this, R, t);
|
|
36
93
|
}
|
|
37
|
-
|
|
38
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Set the GPS options.
|
|
96
|
+
* @param {Object} object containing gpsMinDistance and/or gpsMinAccuracy
|
|
97
|
+
* properties. The former specifies the number of metres which the device
|
|
98
|
+
* must move to process a new GPS reading, and the latter specifies the
|
|
99
|
+
* minimum accuracy, in metres, for a GPS reading to be counted.
|
|
100
|
+
*/
|
|
101
|
+
setGpsOptions(t = {}) {
|
|
102
|
+
t.gpsMinDistance !== void 0 && d(this, L, t.gpsMinDistance), t.gpsMinAccuracy !== void 0 && d(this, x, t.gpsMinAccuracy);
|
|
39
103
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Start the GPS on a real device
|
|
106
|
+
* @return {boolean} code indicating whether the GPS was started successfully.
|
|
107
|
+
* GPS errors can be handled by handling the gpserror event.
|
|
108
|
+
*/
|
|
109
|
+
async startGps() {
|
|
110
|
+
if (n(this, O)) {
|
|
111
|
+
const e = await (await n(this, O).sendData("/gps/start", {
|
|
112
|
+
gpsMinDistance: n(this, L),
|
|
113
|
+
gpsMinAccuracy: n(this, x)
|
|
114
|
+
})).json();
|
|
115
|
+
d(this, T, e.session);
|
|
116
|
+
}
|
|
117
|
+
return n(this, b) === null ? (d(this, b, navigator.geolocation.watchPosition(
|
|
118
|
+
(t) => {
|
|
119
|
+
v(this, p, W).call(this, t);
|
|
44
120
|
},
|
|
45
|
-
(
|
|
46
|
-
this.
|
|
121
|
+
(t) => {
|
|
122
|
+
n(this, A).gpserror ? n(this, A).gpserror(t.code) : alert(`GPS error: code ${t.code}`);
|
|
47
123
|
},
|
|
48
124
|
{
|
|
49
125
|
enableHighAccuracy: !0
|
|
50
126
|
}
|
|
51
|
-
), !0) : !1;
|
|
127
|
+
)), !0) : !1;
|
|
52
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Stop the GPS on a real device
|
|
131
|
+
* @return {boolean} true if the GPS was stopped, false if it could not be
|
|
132
|
+
* stopped (i.e. it was never started).
|
|
133
|
+
*/
|
|
53
134
|
stopGps() {
|
|
54
|
-
return this
|
|
135
|
+
return n(this, b) !== null ? (navigator.geolocation.clearWatch(n(this, b)), d(this, b, null), !0) : !1;
|
|
55
136
|
}
|
|
56
|
-
|
|
57
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Send a fake GPS signal. Useful for testing on a desktop or laptop.
|
|
139
|
+
* @param {number} lon - The longitude.
|
|
140
|
+
* @param {number} lat - The latitude.
|
|
141
|
+
* @param {number} elev - The elevation in metres. (optional, set to null
|
|
142
|
+
* for no elevation).
|
|
143
|
+
* @param {number} acc - The accuracy of the GPS reading in metres. May be
|
|
144
|
+
* ignored if lower than the specified minimum accuracy.
|
|
145
|
+
*/
|
|
146
|
+
fakeGps(t, e, i = null, o = 0) {
|
|
147
|
+
i !== null && this.setElevation(i), v(this, p, W).call(this, {
|
|
58
148
|
coords: {
|
|
59
|
-
longitude:
|
|
60
|
-
latitude:
|
|
61
|
-
accuracy:
|
|
149
|
+
longitude: t,
|
|
150
|
+
latitude: e,
|
|
151
|
+
accuracy: o
|
|
62
152
|
}
|
|
63
153
|
});
|
|
64
154
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Convert longitude and latitude to three.js/WebGL world coordinates.
|
|
157
|
+
* Uses the specified projection, and negates the northing (in typical
|
|
158
|
+
* projections, northings increase northwards, but in the WebGL coordinate
|
|
159
|
+
* system, we face negative z if the camera is at the origin with default
|
|
160
|
+
* rotation).
|
|
161
|
+
* @param {number} lon - The longitude.
|
|
162
|
+
* @param {number} lat - The latitude.
|
|
163
|
+
* @return {Array} a two member array containing the WebGL x and z coordinates
|
|
164
|
+
*/
|
|
165
|
+
lonLatToWorldCoords(t, e) {
|
|
166
|
+
const i = n(this, R).project(t, e);
|
|
167
|
+
if (n(this, E))
|
|
168
|
+
i[0] -= n(this, E)[0], i[1] -= n(this, E)[1];
|
|
69
169
|
else
|
|
70
170
|
throw "No initial position determined";
|
|
71
171
|
return [i[0], -i[1]];
|
|
72
172
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Add a new AR object at a given latitude, longitude and elevation.
|
|
175
|
+
* @param {THREE.Mesh} object the object
|
|
176
|
+
* @param {number} lon - the longitude.
|
|
177
|
+
* @param {number} lat - the latitude.
|
|
178
|
+
* @param {number} elev - the elevation in metres
|
|
179
|
+
* (if not specified, 0 is assigned)
|
|
180
|
+
* @param {Object} properties - properties describing the object (for example,
|
|
181
|
+
* the contents of the GeoJSON properties field).
|
|
182
|
+
*/
|
|
183
|
+
add(t, e, i, o, u = {}) {
|
|
184
|
+
var g;
|
|
185
|
+
t.properties = u, v(this, p, S).call(this, t, e, i, o), this.scene.add(t), (g = n(this, O)) == 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: u
|
|
191
|
+
});
|
|
88
192
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
e.coords.longitude,
|
|
96
|
-
e.coords.latitude
|
|
97
|
-
), this.setWorldPosition(
|
|
98
|
-
this._camera,
|
|
99
|
-
e.coords.longitude,
|
|
100
|
-
e.coords.latitude
|
|
101
|
-
), this._eventHandlers.gpsupdate && this._eventHandlers.gpsupdate(e, t)));
|
|
193
|
+
/**
|
|
194
|
+
* Set the elevation (y coordinate) of the camera.
|
|
195
|
+
* @param {number} elev - the elevation in metres.
|
|
196
|
+
*/
|
|
197
|
+
setElevation(t) {
|
|
198
|
+
this.camera.position.y = t;
|
|
102
199
|
}
|
|
103
200
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
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
|
|
107
212
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) * 6371e3;
|
|
213
|
+
on(t, e) {
|
|
214
|
+
n(this, A)[t] = e;
|
|
111
215
|
}
|
|
112
216
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
217
|
+
R = new WeakMap(), A = new WeakMap(), C = new WeakMap(), L = new WeakMap(), x = new WeakMap(), b = new WeakMap(), E = new WeakMap(), I = new WeakMap(), T = new WeakMap(), O = new WeakMap(), p = new WeakSet(), S = function(t, e, i, o) {
|
|
218
|
+
const u = this.lonLatToWorldCoords(e, i);
|
|
219
|
+
o !== void 0 && (t.position.y = o), [t.position.x, t.position.z] = u;
|
|
220
|
+
}, V = function(t, e) {
|
|
221
|
+
d(this, E, n(this, R).project(t, e));
|
|
222
|
+
}, W = function(t) {
|
|
223
|
+
var i, o, u;
|
|
224
|
+
let e = Number.MAX_VALUE;
|
|
225
|
+
q(this, I)._++, (i = n(this, O)) == null || i.sendData("/gps/new", {
|
|
226
|
+
gpsCount: n(this, I),
|
|
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, x) && (n(this, C) === null ? d(this, C, {
|
|
232
|
+
latitude: t.coords.latitude,
|
|
233
|
+
longitude: t.coords.longitude
|
|
234
|
+
}) : e = v(this, p, Y).call(this, n(this, C), t.coords), e >= n(this, L) && (n(this, C).longitude = t.coords.longitude, n(this, C).latitude = t.coords.latitude, n(this, E) || (v(this, p, V).call(this, t.coords.longitude, t.coords.latitude), (o = n(this, O)) == null || o.sendData("/worldorigin/new", {
|
|
235
|
+
gpsCount: n(this, I),
|
|
236
|
+
lat: t.coords.latitude,
|
|
237
|
+
lon: t.coords.longitude,
|
|
238
|
+
session: n(this, T),
|
|
239
|
+
initialPosition: n(this, E)
|
|
240
|
+
})), v(this, p, S).call(this, this.camera, t.coords.longitude, t.coords.latitude), (u = n(this, O)) == null || u.sendData("/gps/accepted", {
|
|
241
|
+
gpsCount: n(this, I),
|
|
242
|
+
cameraX: this.camera.position.x,
|
|
243
|
+
cameraZ: this.camera.position.z,
|
|
244
|
+
session: n(this, T),
|
|
245
|
+
distMoved: e
|
|
246
|
+
}), n(this, A).gpsupdate && n(this, A).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 = f.MathUtils.degToRad(e.longitude - t.longitude), o = f.MathUtils.degToRad(e.latitude - t.latitude), u = Math.sin(o / 2) * Math.sin(o / 2) + Math.cos(f.MathUtils.degToRad(t.latitude)) * Math.cos(f.MathUtils.degToRad(e.latitude)) * (Math.sin(i / 2) * Math.sin(i / 2));
|
|
254
|
+
return 2 * Math.atan2(Math.sqrt(u), Math.sqrt(1 - u)) * 6371e3;
|
|
255
|
+
};
|
|
256
|
+
class ot {
|
|
257
|
+
/**
|
|
258
|
+
* Create a WebcamRenderer.
|
|
259
|
+
* @param {THREE.WebGLRenderer} renderer - the Three.js renderer.
|
|
260
|
+
* @param {string} videoElementSelector - selector to obtain the HTML video
|
|
261
|
+
* element to render the webcam feed. If a falsy value (e.g. null or
|
|
262
|
+
* undefined), a video element will be created.
|
|
263
|
+
* @options {Object} - options to use for initialising the camera. Currently
|
|
264
|
+
* width and height properties are understood.
|
|
265
|
+
*/
|
|
266
|
+
constructor(t, e, i) {
|
|
267
|
+
this.renderer = t, this.renderer.autoClear = !1, this.sceneWebcam = new f.Scene();
|
|
268
|
+
let o;
|
|
269
|
+
e ? o = document.querySelector(e) : (o = document.createElement("video"), o.setAttribute("autoplay", !0), o.setAttribute("playsinline", !0), o.style.display = "none", document.body.appendChild(o)), this.geom = new f.PlaneGeometry(), this.texture = new f.VideoTexture(o), this.material = new f.MeshBasicMaterial({ map: this.texture });
|
|
270
|
+
const u = new f.Mesh(this.geom, this.material);
|
|
271
|
+
if (this.sceneWebcam.add(u), this.cameraWebcam = new f.OrthographicCamera(
|
|
120
272
|
-0.5,
|
|
121
273
|
0.5,
|
|
122
274
|
0.5,
|
|
@@ -124,21 +276,21 @@ class E {
|
|
|
124
276
|
0,
|
|
125
277
|
10
|
|
126
278
|
), navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
127
|
-
const
|
|
279
|
+
const g = {
|
|
128
280
|
video: {
|
|
129
281
|
width: (i == null ? void 0 : i.width) || 1280,
|
|
130
282
|
height: (i == null ? void 0 : i.height) || 720,
|
|
131
283
|
facingMode: "environment"
|
|
132
284
|
}
|
|
133
285
|
};
|
|
134
|
-
navigator.mediaDevices.getUserMedia(
|
|
135
|
-
console.log("using the webcam successfully..."),
|
|
136
|
-
}).catch((
|
|
286
|
+
navigator.mediaDevices.getUserMedia(g).then((w) => {
|
|
287
|
+
console.log("using the webcam successfully..."), o.srcObject = w, o.play();
|
|
288
|
+
}).catch((w) => {
|
|
137
289
|
setTimeout(() => {
|
|
138
290
|
alert(
|
|
139
291
|
`Webcam Error
|
|
140
|
-
Name: ` +
|
|
141
|
-
Message: ` +
|
|
292
|
+
Name: ` + w.name + `
|
|
293
|
+
Message: ` + w.message
|
|
142
294
|
);
|
|
143
295
|
}, 1e3);
|
|
144
296
|
});
|
|
@@ -147,67 +299,241 @@ Message: ` + c.message
|
|
|
147
299
|
alert("sorry - media devices API not supported");
|
|
148
300
|
}, 1e3);
|
|
149
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Update the webcam.
|
|
304
|
+
* Should be called from your Three.js rendering (animation) function.
|
|
305
|
+
*/
|
|
150
306
|
update() {
|
|
151
307
|
this.renderer.clear(), this.renderer.render(this.sceneWebcam, this.cameraWebcam), this.renderer.clearDepth();
|
|
152
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Free up the memory associated with the webcam.
|
|
311
|
+
* Should be called when your application closes.
|
|
312
|
+
*/
|
|
153
313
|
dispose() {
|
|
154
314
|
this.material.dispose(), this.texture.dispose(), this.geom.dispose();
|
|
155
315
|
}
|
|
156
316
|
}
|
|
157
|
-
const
|
|
158
|
-
class
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
317
|
+
const k = navigator.userAgent.match(/iPhone|iPad|iPod/i), $ = 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" };
|
|
318
|
+
class at extends B {
|
|
319
|
+
/**
|
|
320
|
+
* Create an instance of DeviceOrientationControls.
|
|
321
|
+
* @param {Object} object - the object to attach the controls to
|
|
322
|
+
* (usually your Three.js camera)
|
|
323
|
+
*/
|
|
324
|
+
constructor(t) {
|
|
325
|
+
super(), window.isSecureContext === !1 && console.error(
|
|
326
|
+
"THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)"
|
|
327
|
+
);
|
|
328
|
+
const e = this, i = 1e-6, o = new _();
|
|
329
|
+
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;
|
|
330
|
+
const u = function({
|
|
331
|
+
alpha: s,
|
|
332
|
+
beta: c,
|
|
333
|
+
gamma: h,
|
|
334
|
+
webkitCompassHeading: a
|
|
335
|
+
}) {
|
|
336
|
+
if (k) {
|
|
337
|
+
const l = 360 - a;
|
|
338
|
+
e.alphaOffset = D.degToRad(l - s), e.deviceOrientation = { alpha: s, beta: c, gamma: h, webkitCompassHeading: a };
|
|
339
|
+
} else
|
|
340
|
+
s < 0 && (s += 360), e.deviceOrientation = { alpha: s, beta: c, gamma: h };
|
|
341
|
+
window.dispatchEvent(
|
|
342
|
+
new CustomEvent("camera-rotation-change", {
|
|
343
|
+
detail: { cameraRotation: t.rotation }
|
|
344
|
+
})
|
|
345
|
+
);
|
|
346
|
+
}, g = function() {
|
|
347
|
+
e.screenOrientation = window.orientation || 0;
|
|
348
|
+
}, w = function(s, c, h, a, l) {
|
|
349
|
+
z.set(h, c, -a, "YXZ"), s.setFromEuler(z), s.multiply(tt), s.multiply(J.setFromAxisAngle($, -l));
|
|
169
350
|
};
|
|
170
351
|
this.connect = function() {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
352
|
+
g(), window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? window.DeviceOrientationEvent.requestPermission().then((s) => {
|
|
353
|
+
s === "granted" && (window.addEventListener(
|
|
354
|
+
"orientationchange",
|
|
355
|
+
g
|
|
356
|
+
), window.addEventListener(
|
|
357
|
+
e.orientationChangeEventName,
|
|
358
|
+
u
|
|
359
|
+
));
|
|
360
|
+
}).catch(function(s) {
|
|
361
|
+
console.error(
|
|
362
|
+
"THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",
|
|
363
|
+
s
|
|
364
|
+
);
|
|
365
|
+
}) : (window.addEventListener(
|
|
366
|
+
"orientationchange",
|
|
367
|
+
g
|
|
368
|
+
), window.addEventListener(
|
|
369
|
+
e.orientationChangeEventName,
|
|
370
|
+
u
|
|
371
|
+
)), e.enabled = !0;
|
|
176
372
|
}, this.disconnect = function() {
|
|
177
|
-
window.removeEventListener(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
373
|
+
window.removeEventListener(
|
|
374
|
+
"orientationchange",
|
|
375
|
+
g
|
|
376
|
+
), window.removeEventListener(
|
|
377
|
+
e.orientationChangeEventName,
|
|
378
|
+
u
|
|
379
|
+
), e.enabled = !1, e.initialOffset = !1, e.deviceOrientation = null;
|
|
380
|
+
}, this.update = function({ theta: s = 0 } = { theta: 0 }) {
|
|
381
|
+
if (e.enabled === !1) return;
|
|
382
|
+
const c = e.deviceOrientation;
|
|
383
|
+
if (c) {
|
|
384
|
+
let h = c.alpha ? D.degToRad(c.alpha) + e.alphaOffset : 0, a = c.beta ? D.degToRad(c.beta) : 0, l = c.gamma ? D.degToRad(c.gamma) : 0;
|
|
385
|
+
const H = e.screenOrientation ? D.degToRad(e.screenOrientation) : 0;
|
|
386
|
+
if (k) {
|
|
387
|
+
const y = new _();
|
|
388
|
+
w(y, h, a, l, H);
|
|
389
|
+
const M = new N().setFromQuaternion(
|
|
390
|
+
y,
|
|
391
|
+
"YXZ"
|
|
392
|
+
);
|
|
393
|
+
console.log(M.x, M.y, M.z), M.y = D.degToRad(
|
|
394
|
+
360 - c.webkitCompassHeading
|
|
395
|
+
), y.setFromEuler(M), e.object.quaternion.copy(y);
|
|
396
|
+
} else {
|
|
397
|
+
if (this.smoothingFactor < 1) {
|
|
398
|
+
if (this.lastOrientation) {
|
|
399
|
+
const y = this.smoothingFactor;
|
|
400
|
+
h = this._getSmoothedAngle(
|
|
401
|
+
h,
|
|
402
|
+
this.lastOrientation.alpha,
|
|
403
|
+
y
|
|
404
|
+
), a = this._getSmoothedAngle(
|
|
405
|
+
a + Math.PI,
|
|
406
|
+
this.lastOrientation.beta,
|
|
407
|
+
y
|
|
408
|
+
), l = this._getSmoothedAngle(
|
|
409
|
+
l + this.HALF_PI,
|
|
410
|
+
this.lastOrientation.gamma,
|
|
411
|
+
y,
|
|
412
|
+
Math.PI
|
|
413
|
+
);
|
|
414
|
+
} else
|
|
415
|
+
a += Math.PI, l += this.HALF_PI;
|
|
416
|
+
this.lastOrientation = {
|
|
417
|
+
alpha: h,
|
|
418
|
+
beta: a,
|
|
419
|
+
gamma: l
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
w(
|
|
423
|
+
e.object.quaternion,
|
|
424
|
+
h + s,
|
|
425
|
+
this.smoothingFactor < 1 ? a - Math.PI : a,
|
|
426
|
+
this.smoothingFactor < 1 ? l - this.HALF_PI : l,
|
|
427
|
+
H
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
8 * (1 - o.dot(e.object.quaternion)) > i && (o.copy(e.object.quaternion), e.dispatchEvent(et));
|
|
184
431
|
}
|
|
432
|
+
}, this._orderAngle = function(s, c, h = this.TWO_PI) {
|
|
433
|
+
return c > s && Math.abs(c - s) < h / 2 || s > c && Math.abs(c - s) > h / 2 ? { left: s, right: c } : { left: c, right: s };
|
|
434
|
+
}, this._getSmoothedAngle = function(s, c, h, a = this.TWO_PI) {
|
|
435
|
+
const l = this._orderAngle(s, c, a), H = l.left, y = l.right;
|
|
436
|
+
l.left = 0, l.right -= H, l.right < 0 && (l.right += a);
|
|
437
|
+
let M = y == c ? (1 - h) * l.right + h * l.left : h * l.right + (1 - h) * l.left;
|
|
438
|
+
return M += H, M >= a && (M -= a), M;
|
|
439
|
+
}, this.updateAlphaOffset = function() {
|
|
440
|
+
e.initialOffset = !1;
|
|
185
441
|
}, this.dispose = function() {
|
|
186
|
-
|
|
187
|
-
}, this.
|
|
442
|
+
e.disconnect();
|
|
443
|
+
}, this.getAlpha = function() {
|
|
444
|
+
const { deviceOrientation: s } = e;
|
|
445
|
+
return s && s.alpha ? D.degToRad(s.alpha) + e.alphaOffset : 0;
|
|
446
|
+
}, this.getBeta = function() {
|
|
447
|
+
const { deviceOrientation: s } = e;
|
|
448
|
+
return s && s.beta ? D.degToRad(s.beta) : 0;
|
|
449
|
+
}, window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission == "function" ? this.initPermissionDialog() : this.connect();
|
|
450
|
+
}
|
|
451
|
+
// Provide gesture before initialising device orientation controls
|
|
452
|
+
// From PR #659 on the main AR.js repo
|
|
453
|
+
// Thanks to @ma2yama
|
|
454
|
+
initPermissionDialog() {
|
|
455
|
+
const t = document.createElement("div"), e = document.createElement("div"), i = document.createElement("div"), o = document.createElement("div");
|
|
456
|
+
document.body.appendChild(t);
|
|
457
|
+
const u = {
|
|
458
|
+
display: "flex",
|
|
459
|
+
position: "fixed",
|
|
460
|
+
top: 0,
|
|
461
|
+
left: 0,
|
|
462
|
+
width: "100%",
|
|
463
|
+
height: "100%",
|
|
464
|
+
zIndex: 1,
|
|
465
|
+
backgroundColor: "rgba(0,0,0,0.6)",
|
|
466
|
+
justifyContent: "center",
|
|
467
|
+
alignItems: "center"
|
|
468
|
+
}, g = {
|
|
469
|
+
backgroundColor: "white",
|
|
470
|
+
padding: "6px",
|
|
471
|
+
borderRadius: "3px",
|
|
472
|
+
width: "36rem",
|
|
473
|
+
height: "24rem"
|
|
474
|
+
}, w = {
|
|
475
|
+
width: "100%",
|
|
476
|
+
height: "70%",
|
|
477
|
+
display: "flex",
|
|
478
|
+
justifyContent: "center",
|
|
479
|
+
alignItems: "center"
|
|
480
|
+
}, s = {
|
|
481
|
+
display: "inline-flex",
|
|
482
|
+
width: "100%",
|
|
483
|
+
height: "30%",
|
|
484
|
+
justifyContent: "center",
|
|
485
|
+
alignItems: "center"
|
|
486
|
+
};
|
|
487
|
+
for (let a in u)
|
|
488
|
+
t.style[a] = u[a];
|
|
489
|
+
for (let a in g)
|
|
490
|
+
e.style[a] = g[a];
|
|
491
|
+
for (let a in w)
|
|
492
|
+
i.style[a] = w[a];
|
|
493
|
+
for (let a in s)
|
|
494
|
+
o.style[a] = s[a];
|
|
495
|
+
t.appendChild(e), e.appendChild(i), e.appendChild(o), i.innerHTML = '<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';
|
|
496
|
+
const c = () => {
|
|
497
|
+
this.connect(), t.style.display = "none";
|
|
498
|
+
}, h = document.createElement("button");
|
|
499
|
+
h.addEventListener("click", c), h.style.width = "50%", h.style.height = "80%", h.style.fontSize = "20pt", h.appendChild(document.createTextNode("OK")), o.appendChild(h), document.body.appendChild(t);
|
|
188
500
|
}
|
|
189
501
|
}
|
|
190
|
-
class
|
|
191
|
-
|
|
192
|
-
|
|
502
|
+
class rt {
|
|
503
|
+
/**
|
|
504
|
+
* Create a ClickHandler.
|
|
505
|
+
* @param {THREE.WebGLRenderer} - The Three.js renderer on which the click
|
|
506
|
+
* events will be handled.
|
|
507
|
+
*/
|
|
508
|
+
constructor(t) {
|
|
509
|
+
this.raycaster = new f.Raycaster(), this.normalisedMousePosition = new f.Vector2(null, null), t.domElement.addEventListener("click", (e) => {
|
|
193
510
|
this.normalisedMousePosition.set(
|
|
194
|
-
|
|
195
|
-
-(
|
|
511
|
+
e.clientX / t.domElement.clientWidth * 2 - 1,
|
|
512
|
+
-(e.clientY / t.domElement.clientHeight * 2) + 1
|
|
196
513
|
);
|
|
197
514
|
});
|
|
198
515
|
}
|
|
199
|
-
|
|
516
|
+
/**
|
|
517
|
+
* Cast a ray into the scene to detect objects.
|
|
518
|
+
* @param {THREE.Camera} - The active Three.js camera, from which the ray
|
|
519
|
+
* will be cast.
|
|
520
|
+
* @param {THREE.Scene} - The active Three.js scene, which the ray will be
|
|
521
|
+
* cast into.
|
|
522
|
+
* @return {Array} - array of all intersected objects.
|
|
523
|
+
*/
|
|
524
|
+
raycast(t, e) {
|
|
200
525
|
if (this.normalisedMousePosition.x !== null && this.normalisedMousePosition.y !== null) {
|
|
201
|
-
this.raycaster.setFromCamera(this.normalisedMousePosition,
|
|
202
|
-
const i = this.raycaster.intersectObjects(
|
|
526
|
+
this.raycaster.setFromCamera(this.normalisedMousePosition, t);
|
|
527
|
+
const i = this.raycaster.intersectObjects(e.children, !1);
|
|
203
528
|
return this.normalisedMousePosition.set(null, null), i;
|
|
204
529
|
}
|
|
205
530
|
return [];
|
|
206
531
|
}
|
|
207
532
|
}
|
|
208
533
|
export {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
534
|
+
rt as ClickHandler,
|
|
535
|
+
at as DeviceOrientationControls,
|
|
536
|
+
st as LocationBased,
|
|
537
|
+
K as SphMercProjection,
|
|
538
|
+
ot as WebcamRenderer
|
|
213
539
|
};
|
package/dist/locar.umd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
Name: `+
|
|
3
|
-
Message: `+
|
|
1
|
+
(function(a,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],i):(a=typeof globalThis<"u"?globalThis:a||self,i(a.locar={},a.THREE))})(this,function(a,i){"use strict";var H=a=>{throw TypeError(a)};var U=(a,i,f)=>i.has(a)||H("Cannot "+f);var n=(a,i,f)=>(U(a,i,"read from private field"),f?f.call(a):i.get(a)),v=(a,i,f)=>i.has(a)?H("Cannot add the same private member more than once"):i instanceof WeakSet?i.add(a):i.set(a,f),u=(a,i,f,m)=>(U(a,i,"write to private field"),m?m.call(a,f):i.set(a,f),f),y=(a,i,f)=>(U(a,i,"access private method"),f);var N=(a,i,f,m)=>({set _(W){u(a,i,W,f)},get _(){return n(a,i,m)}});var w,Q,G,X,B,S,I,_,j,x,L,O,T,E,P,M,q,V,R,Y;function f(b){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(b){for(const e in b)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(b,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>b[e]})}}return t.default=b,Object.freeze(t)}const m=f(i);class W{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,B).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},B=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 Z{constructor(t,e,s={},r=null){v(this,M);v(this,S);v(this,I);v(this,_);v(this,j);v(this,x);v(this,L);v(this,O);v(this,T);v(this,E);v(this,P);this.scene=t,this.camera=e,u(this,S,new W),u(this,I,{}),u(this,_,null),u(this,j,0),u(this,x,100),u(this,L,null),this.setGpsOptions(s),u(this,O,null),u(this,T,0),u(this,E,0),u(this,P,r)}setProjection(t){u(this,S,t)}setGpsOptions(t={}){t.gpsMinDistance!==void 0&&u(this,j,t.gpsMinDistance),t.gpsMinAccuracy!==void 0&&u(this,x,t.gpsMinAccuracy)}async startGps(){if(n(this,P)){const e=await(await n(this,P).sendData("/gps/start",{gpsMinDistance:n(this,j),gpsMinAccuracy:n(this,x)})).json();u(this,E,e.session)}return n(this,L)===null?(u(this,L,navigator.geolocation.watchPosition(t=>{y(this,M,R).call(this,t)},t=>{n(this,I).gpserror?n(this,I).gpserror(t.code):alert(`GPS error: code ${t.code}`)},{enableHighAccuracy:!0})),!0):!1}stopGps(){return n(this,L)!==null?(navigator.geolocation.clearWatch(n(this,L)),u(this,L,null),!0):!1}fakeGps(t,e,s=null,r=0){s!==null&&this.setElevation(s),y(this,M,R).call(this,{coords:{longitude:t,latitude:e,accuracy:r}})}lonLatToWorldCoords(t,e){const s=n(this,S).project(t,e);if(n(this,O))s[0]-=n(this,O)[0],s[1]-=n(this,O)[1];else throw"No initial position determined";return[s[0],-s[1]]}add(t,e,s,r,g={}){var p;t.properties=g,y(this,M,q).call(this,t,e,s,r),this.scene.add(t),(p=n(this,P))==null||p.sendData("/object/new",{position:t.position,x:t.position.x,z:t.position.z,session:n(this,E),properties:g})}setElevation(t){this.camera.position.y=t}on(t,e){n(this,I)[t]=e}}S=new WeakMap,I=new WeakMap,_=new WeakMap,j=new WeakMap,x=new WeakMap,L=new WeakMap,O=new WeakMap,T=new WeakMap,E=new WeakMap,P=new WeakMap,M=new WeakSet,q=function(t,e,s,r){const g=this.lonLatToWorldCoords(e,s);r!==void 0&&(t.position.y=r),[t.position.x,t.position.z]=g},V=function(t,e){u(this,O,n(this,S).project(t,e))},R=function(t){var s,r,g;let e=Number.MAX_VALUE;N(this,T)._++,(s=n(this,P))==null||s.sendData("/gps/new",{gpsCount:n(this,T),lat:t.coords.latitude,lon:t.coords.longitude,acc:t.coords.accuracy,session:n(this,E)}),t.coords.accuracy<=n(this,x)&&(n(this,_)===null?u(this,_,{latitude:t.coords.latitude,longitude:t.coords.longitude}):e=y(this,M,Y).call(this,n(this,_),t.coords),e>=n(this,j)&&(n(this,_).longitude=t.coords.longitude,n(this,_).latitude=t.coords.latitude,n(this,O)||(y(this,M,V).call(this,t.coords.longitude,t.coords.latitude),(r=n(this,P))==null||r.sendData("/worldorigin/new",{gpsCount:n(this,T),lat:t.coords.latitude,lon:t.coords.longitude,session:n(this,E),initialPosition:n(this,O)})),y(this,M,q).call(this,this.camera,t.coords.longitude,t.coords.latitude),(g=n(this,P))==null||g.sendData("/gps/accepted",{gpsCount:n(this,T),cameraX:this.camera.position.x,cameraZ:this.camera.position.z,session:n(this,E),distMoved:e}),n(this,I).gpsupdate&&n(this,I).gpsupdate(t,e)))},Y=function(t,e){const s=m.MathUtils.degToRad(e.longitude-t.longitude),r=m.MathUtils.degToRad(e.latitude-t.latitude),g=Math.sin(r/2)*Math.sin(r/2)+Math.cos(m.MathUtils.degToRad(t.latitude))*Math.cos(m.MathUtils.degToRad(e.latitude))*(Math.sin(s/2)*Math.sin(s/2));return 2*Math.atan2(Math.sqrt(g),Math.sqrt(1-g))*6371e3};class K{constructor(t,e,s){this.renderer=t,this.renderer.autoClear=!1,this.sceneWebcam=new m.Scene;let r;e?r=document.querySelector(e):(r=document.createElement("video"),r.setAttribute("autoplay",!0),r.setAttribute("playsinline",!0),r.style.display="none",document.body.appendChild(r)),this.geom=new m.PlaneGeometry,this.texture=new m.VideoTexture(r),this.material=new m.MeshBasicMaterial({map:this.texture});const g=new m.Mesh(this.geom,this.material);if(this.sceneWebcam.add(g),this.cameraWebcam=new m.OrthographicCamera(-.5,.5,.5,-.5,0,10),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const p={video:{width:(s==null?void 0:s.width)||1280,height:(s==null?void 0:s.height)||720,facingMode:"environment"}};navigator.mediaDevices.getUserMedia(p).then(C=>{console.log("using the webcam successfully..."),r.srcObject=C,r.play()}).catch(C=>{setTimeout(()=>{alert(`Webcam Error
|
|
2
|
+
Name: `+C.name+`
|
|
3
|
+
Message: `+C.message)},1e3)})}else setTimeout(()=>{alert("sorry - media devices API not supported")},1e3)}update(){this.renderer.clear(),this.renderer.render(this.sceneWebcam,this.cameraWebcam),this.renderer.clearDepth()}dispose(){this.material.dispose(),this.texture.dispose(),this.geom.dispose()}}const k=navigator.userAgent.match(/iPhone|iPad|iPod/i),$=new i.Vector3(0,0,1),z=new i.Euler,J=new i.Quaternion,tt=new i.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),et={type:"change"};class it extends i.EventDispatcher{constructor(t){super(),window.isSecureContext===!1&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const e=this,s=1e-6,r=new i.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 g=function({alpha:o,beta:h,gamma:l,webkitCompassHeading:c}){if(k){const d=360-c;e.alphaOffset=i.MathUtils.degToRad(d-o),e.deviceOrientation={alpha:o,beta:h,gamma:l,webkitCompassHeading:c}}else o<0&&(o+=360),e.deviceOrientation={alpha:o,beta:h,gamma:l};window.dispatchEvent(new CustomEvent("camera-rotation-change",{detail:{cameraRotation:t.rotation}}))},p=function(){e.screenOrientation=window.orientation||0},C=function(o,h,l,c,d){z.set(l,h,-c,"YXZ"),o.setFromEuler(z),o.multiply(tt),o.multiply(J.setFromAxisAngle($,-d))};this.connect=function(){p(),window.DeviceOrientationEvent!==void 0&&typeof window.DeviceOrientationEvent.requestPermission=="function"?window.DeviceOrientationEvent.requestPermission().then(o=>{o==="granted"&&(window.addEventListener("orientationchange",p),window.addEventListener(e.orientationChangeEventName,g))}).catch(function(o){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",o)}):(window.addEventListener("orientationchange",p),window.addEventListener(e.orientationChangeEventName,g)),e.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",p),window.removeEventListener(e.orientationChangeEventName,g),e.enabled=!1,e.initialOffset=!1,e.deviceOrientation=null},this.update=function({theta:o=0}={theta:0}){if(e.enabled===!1)return;const h=e.deviceOrientation;if(h){let l=h.alpha?i.MathUtils.degToRad(h.alpha)+e.alphaOffset:0,c=h.beta?i.MathUtils.degToRad(h.beta):0,d=h.gamma?i.MathUtils.degToRad(h.gamma):0;const F=e.screenOrientation?i.MathUtils.degToRad(e.screenOrientation):0;if(k){const A=new i.Quaternion;C(A,l,c,d,F);const D=new i.Euler().setFromQuaternion(A,"YXZ");console.log(D.x,D.y,D.z),D.y=i.MathUtils.degToRad(360-h.webkitCompassHeading),A.setFromEuler(D),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),c=this._getSmoothedAngle(c+Math.PI,this.lastOrientation.beta,A),d=this._getSmoothedAngle(d+this.HALF_PI,this.lastOrientation.gamma,A,Math.PI)}else c+=Math.PI,d+=this.HALF_PI;this.lastOrientation={alpha:l,beta:c,gamma:d}}C(e.object.quaternion,l+o,this.smoothingFactor<1?c-Math.PI:c,this.smoothingFactor<1?d-this.HALF_PI:d,F)}8*(1-r.dot(e.object.quaternion))>s&&(r.copy(e.object.quaternion),e.dispatchEvent(et))}},this._orderAngle=function(o,h,l=this.TWO_PI){return h>o&&Math.abs(h-o)<l/2||o>h&&Math.abs(h-o)>l/2?{left:o,right:h}:{left:h,right:o}},this._getSmoothedAngle=function(o,h,l,c=this.TWO_PI){const d=this._orderAngle(o,h,c),F=d.left,A=d.right;d.left=0,d.right-=F,d.right<0&&(d.right+=c);let D=A==h?(1-l)*d.right+l*d.left:l*d.right+(1-l)*d.left;return D+=F,D>=c&&(D-=c),D},this.updateAlphaOffset=function(){e.initialOffset=!1},this.dispose=function(){e.disconnect()},this.getAlpha=function(){const{deviceOrientation:o}=e;return o&&o.alpha?i.MathUtils.degToRad(o.alpha)+e.alphaOffset:0},this.getBeta=function(){const{deviceOrientation:o}=e;return o&&o.beta?i.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"),s=document.createElement("div"),r=document.createElement("div");document.body.appendChild(t);const g={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"},C={width:"100%",height:"70%",display:"flex",justifyContent:"center",alignItems:"center"},o={display:"inline-flex",width:"100%",height:"30%",justifyContent:"center",alignItems:"center"};for(let c in g)t.style[c]=g[c];for(let c in p)e.style[c]=p[c];for(let c in C)s.style[c]=C[c];for(let c in o)r.style[c]=o[c];t.appendChild(e),e.appendChild(s),e.appendChild(r),s.innerHTML='<div style="font-size: 24pt; margin: 1rem;">This immersive website requires access to your device motion sensors.</div>';const h=()=>{this.connect(),t.style.display="none"},l=document.createElement("button");l.addEventListener("click",h),l.style.width="50%",l.style.height="80%",l.style.fontSize="20pt",l.appendChild(document.createTextNode("OK")),r.appendChild(l),document.body.appendChild(t)}}class nt{constructor(t){this.raycaster=new m.Raycaster,this.normalisedMousePosition=new m.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 s=this.raycaster.intersectObjects(e.children,!1);return this.normalisedMousePosition.set(null,null),s}return[]}}a.ClickHandler=nt,a.DeviceOrientationControls=it,a.LocationBased=Z,a.SphMercProjection=W,a.WebcamRenderer=K,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "locar",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Location-based AR from AR.js.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "vite build && npm pack"
|
|
17
|
+
"build": "vite build && npm pack",
|
|
18
|
+
"makedocs": "jsdoc -r lib -d docs/api"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
21
|
+
"jsdoc": "^4.0.4",
|
|
20
22
|
"vite": "^5.4.8"
|
|
21
23
|
}
|
|
22
24
|
}
|