Skip to content

Commit 867be54

Browse files
authored
Merge pull request #406 from AR-js-org/new-aframe-location-based
New A-Frame location based
2 parents 3fdc52a + 25a4b40 commit 867be54

File tree

15 files changed

+359
-4
lines changed

15 files changed

+359
-4
lines changed

aframe/build/aframe-ar-new-location-only.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aframe/build/aframe-ar-nft.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aframe/build/aframe-ar.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>AR.js A-Frame</title>
5+
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
6+
<!-- Assumes AR.js build is in the 'AR.js' directory -->
7+
<script type='text/javascript' src='../../../three.js/build/ar-threex-location-only.js'></script>
8+
<script type='text/javascript' src='../../build/aframe-ar.js'></script>
9+
<script src='index.js'></script>
10+
</head>
11+
<body>
12+
<a-scene vr-mode-ui='enabled: false' arjs='sourceType: webcam; videoTexture: true; debugUIEnabled: false' renderer='antialias: true; alpha: true'>
13+
<!--
14+
<a-camera gps-new-camera='gpsMinDistance: 5' look-controls-enabled='false' arjs-device-orientation-controls></a-camera>
15+
-->
16+
<a-camera gps-new-camera='gpsMinDistance: 5'></a-camera>
17+
</a-scene>
18+
<div id='setloc' style='position:absolute; left: 10px; bottom: 2%; z-index:999; background-color: blue; color: white; padding: 10px'>
19+
Lat:<input id="lat" value="51.049" />
20+
Lon: <input id="lon" value="-0.723"/>
21+
Min Acc: <input id='minacc' value='1000' /> <input type='button' id='go' value='go' />
22+
</div>
23+
</body>
24+
</html>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
window.onload = () => {
2+
let testEntitiesAdded = false;
3+
alert('If testing the lat/lon manual input on a mobile device, please turn off your GPS to avoid the real location being detected.');
4+
const el = document.querySelector("[gps-new-camera]");
5+
el.addEventListener("gps-camera-update-position", e => {
6+
if(!testEntitiesAdded) {
7+
alert(`Got first GPS position: lon ${e.detail.position.longitude} lat ${e.detail.position.latitude}`);
8+
// Add four boxes to the north (red), south (yellow), west (blue)
9+
// and east (red) of the initial GPS position
10+
const properties = [{
11+
color: 'red',
12+
latDis: 0.001,
13+
lonDis: 0
14+
},{
15+
color: 'yellow',
16+
latDis: -0.001,
17+
lonDis: 0
18+
},{
19+
color: 'blue',
20+
latDis: 0,
21+
lonDis: -0.001
22+
},{
23+
color: 'green',
24+
latDis: 0,
25+
lonDis: 0.001
26+
}
27+
];
28+
for(const prop of properties) {
29+
const entity = document.createElement("a-box");
30+
entity.setAttribute("scale", {
31+
x: 20,
32+
y: 20,
33+
z: 20
34+
});
35+
entity.setAttribute('material', { color: prop.color } );
36+
entity.setAttribute('gps-new-entity-place', {
37+
latitude: e.detail.position.latitude + prop.latDis,
38+
longitude: e.detail.position.longitude + prop.lonDis
39+
});
40+
41+
document.querySelector("a-scene").appendChild(entity);
42+
}
43+
testEntitiesAdded = true;
44+
}
45+
});
46+
47+
document.getElementById("go").addEventListener("click", e=> {
48+
const lat = document.getElementById('lat').value;
49+
const lon = document.getElementById('lon').value;
50+
const minacc = document.getElementById('minacc').value;
51+
52+
el.setAttribute('gps-new-camera', { simulateLatitude: lat, simulateLongitude: lon, positionMinAccuracy: minacc } );
53+
});
54+
};

aframe/src/index-nft.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import "./location-based/gps-camera";
1010
import "./location-based/gps-entity-place";
1111
import "./location-based/gps-projected-camera";
1212
import "./location-based/gps-projected-entity-place";
13+
import "./new-location-based/gps-new-camera";
14+
import "./new-location-based/gps-new-entity-place";
15+
import "./new-location-based/arjs-device-orientation-controls";
1316

1417
// System
1518
import "./system-arjs-nft";

aframe/src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import "./location-based/gps-camera";
1010
import "./location-based/gps-entity-place";
1111
import "./location-based/gps-projected-camera";
1212
import "./location-based/gps-projected-entity-place";
13+
import "./new-location-based/gps-new-camera";
14+
import "./new-location-based/gps-new-entity-place";
15+
import "./new-location-based/arjs-device-orientation-controls";
1316

1417
// System
1518
import "./system-arjs";
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* arjs-device-orientation-controls
3+
*
4+
* Replaces the standard look-controls component to provide mobile device
5+
* orientation controls.
6+
*
7+
* A lightweight A-Frame wrapper round the modified three.js
8+
* DeviceOrientationControls used in the three.js location-based API.
9+
*
10+
* Creates the THREE object using using the three.js camera, and allows update
11+
* of the smoothing factor.
12+
*/
13+
14+
import * as AFRAME from "aframe";
15+
AFRAME.registerComponent("arjs-device-orientation-controls", {
16+
schema: {
17+
smoothingFactor: {
18+
type: "number",
19+
default: 1,
20+
},
21+
},
22+
23+
init: function () {
24+
this._orientationControls = new THREEx.DeviceOrientationControls(
25+
this.el.object3D
26+
);
27+
},
28+
29+
update: function () {
30+
this._orientationControls.smoothingFactor = this.data.smoothingFactor;
31+
},
32+
33+
tick: function () {
34+
this._orientationControls.update();
35+
},
36+
});
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import * as AFRAME from "aframe";
2+
3+
AFRAME.registerComponent("gps-new-camera", {
4+
schema: {
5+
simulateLatitude: {
6+
type: "number",
7+
default: 0,
8+
},
9+
simulateLongitude: {
10+
type: "number",
11+
default: 0,
12+
},
13+
simulateAltitude: {
14+
type: "number",
15+
default: -Number.MAX_VALUE,
16+
},
17+
gpsMinDistance: {
18+
type: "number",
19+
default: 0,
20+
},
21+
positionMinAccuracy: {
22+
type: "number",
23+
default: 1000,
24+
},
25+
},
26+
27+
init: function () {
28+
this._testForOrientationControls();
29+
30+
this.threeLoc = new THREEx.LocationBased(
31+
this.el.sceneEl.object3D,
32+
this.el.object3D
33+
);
34+
35+
this.threeLoc.on("gpsupdate", (gpspos) => {
36+
this._sendGpsUpdateEvent(gpspos.coords.longitude, gpspos.coords.latitude);
37+
});
38+
39+
this.threeLoc.on("gpserror", (code) => {
40+
const msg = [
41+
"User denied access to GPS.",
42+
"GPS satellites not available.",
43+
"Timeout communicating with GPS satellites - try moving to a more open area.",
44+
];
45+
if (code >= 1 && code <= 3) {
46+
this._displayError(msg[code - 1]);
47+
} else {
48+
this._displayError(`Unknown geolocation error code ${code}.`);
49+
}
50+
});
51+
52+
// Use arjs-device-orientation-controls on mobile only, with standard
53+
// look-controls disabled (this interferes with the readings from the
54+
// sensors). On desktop, use standard look-controls instead.
55+
56+
const mobile = this._isMobile();
57+
this.el.setAttribute("look-controls-enabled", !mobile);
58+
if (mobile) {
59+
this.el.setAttribute("arjs-device-orientation-controls", true);
60+
}
61+
62+
// from original gps-camera component
63+
// if Safari
64+
if (!!navigator.userAgent.match(/Version\/[\d.]+.*Safari/)) {
65+
this._setupSafariOrientationPermissions();
66+
}
67+
},
68+
69+
update: function (oldData) {
70+
this.threeLoc.setGpsOptions({
71+
gpsMinAccuracy: this.data.positionMinAccuracy,
72+
gpsMinDistance: this.data.gpsMinDistance,
73+
});
74+
if (
75+
(this.data.simulateLatitude !== 0 || this.data.simulateLongitude !== 0) &&
76+
(this.data.simulateLatitude != oldData.simulateLatitude ||
77+
this.data.simulateLongitude != oldData.simulateLongitude)
78+
) {
79+
this.threeLoc.fakeGps(
80+
this.data.simulateLongitude,
81+
this.data.simulateLatitude
82+
);
83+
this.data.simulateLatitude = 0;
84+
this.data.simulateLongitude = 0;
85+
}
86+
if (this.data.simulateAltitude > -Number.MAX_VALUE) {
87+
this.threeLoc.setElevation(this.data.simulateAltitude + 1.6);
88+
}
89+
},
90+
91+
play: function () {
92+
if (this.data.simulateLatitude === 0 && this.data.simulateLongitude === 0) {
93+
this.threeLoc.startGps();
94+
}
95+
},
96+
97+
pause: function () {
98+
this.threeLoc.stopGps();
99+
},
100+
101+
_sendGpsUpdateEvent: function (lon, lat) {
102+
this.el.emit("gps-camera-update-position", {
103+
position: {
104+
longitude: lon,
105+
latitude: lat,
106+
},
107+
});
108+
},
109+
110+
_testForOrientationControls: function () {
111+
const msg =
112+
"WARNING - No orientation controls component, app will not respond to device rotation.";
113+
if (
114+
!this.el.components["arjs-device-orientation-controls"] &&
115+
!this.el.components["look-controls"]
116+
) {
117+
this._displayError(msg);
118+
}
119+
},
120+
121+
_displayError: function (error) {
122+
const arjs = this.el.sceneEl.systems["arjs"];
123+
if (arjs) {
124+
arjs._displayErrorPopup(msg);
125+
} else {
126+
alert(msg);
127+
}
128+
},
129+
130+
// from original gps-camera component
131+
_setupSafariOrientationPermissions: function () {
132+
// iOS 13+
133+
if (typeof DeviceOrientationEvent.requestPermission === "function") {
134+
var handler = function () {
135+
console.log("Requesting device orientation permissions...");
136+
DeviceOrientationEvent.requestPermission();
137+
document.removeEventListener("touchend", handler);
138+
};
139+
140+
document.addEventListener(
141+
"touchend",
142+
function () {
143+
handler();
144+
},
145+
false
146+
);
147+
148+
this.el.sceneEl.systems["arjs"]._displayErrorPopup(
149+
"After camera permission prompt, please tap the screen to activate geolocation."
150+
);
151+
} else {
152+
var timeout = setTimeout(function () {
153+
this.el.sceneEl.systems["arjs"]._displayErrorPopup(
154+
"Please enable device orientation in Settings > Safari > Motion & Orientation Access."
155+
);
156+
}, 750);
157+
window.addEventListener(eventName, function () {
158+
clearTimeout(timeout);
159+
});
160+
}
161+
},
162+
163+
_isMobile: function () {
164+
if (
165+
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
166+
navigator.userAgent
167+
)
168+
) {
169+
// true for mobile device
170+
return true;
171+
}
172+
return false;
173+
},
174+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as AFRAME from "aframe";
2+
3+
AFRAME.registerComponent("gps-new-entity-place", {
4+
schema: {
5+
longitude: {
6+
type: "number",
7+
default: 0,
8+
},
9+
latitude: {
10+
type: "number",
11+
default: 0,
12+
},
13+
},
14+
15+
init: function () {
16+
const camera = document.querySelector("[gps-new-camera]");
17+
if (!camera.components["gps-new-camera"]) {
18+
console.error("gps-new-camera not initialised");
19+
return;
20+
}
21+
this._cameraGps = camera.components["gps-new-camera"];
22+
},
23+
24+
update: function () {
25+
const projCoords = this._cameraGps.threeLoc.lonLatToWorldCoords(
26+
this.data.longitude,
27+
this.data.latitude
28+
);
29+
this.el.object3D.position.set(
30+
projCoords[0],
31+
this.el.object3D.position.y,
32+
projCoords[1]
33+
);
34+
},
35+
});

0 commit comments

Comments
 (0)