Reputation: 529
I need to detect if and how user moves his phone using React.JS
(I'm using Next.JS 14.0.4). For this purpose I began looking for some libraries that can detect it with gyroscope or accelerometer and reached Shake.js, Motion sensors, and default JS event devicemotion
For every library or event I wrote a code by the example provided on corresponding site.
Shake.js:
"use client"
import React, { useEffect, useState } from 'react';
import Shake from 'shake.js';
export default function Home() {
const [shakeDetected, setShakeDetected] = useState(false);
useEffect(() => {
const shakeEvent = new Shake({ threshold: 15, timeout: 1000 });
shakeEvent.start();
window.addEventListener('shake', shakeHandler, false);
return () => {
shakeEvent.stop();
window.removeEventListener('shake', shakeHandler, false);
};
}, []);
const shakeHandler = () => {
setShakeDetected(true);
setTimeout(() => setShakeDetected(false), 5000); // Reset after 5 seconds
};
return (
<div>
<h1>Shake Detection</h1>
{shakeDetected ? <p>Shake detected!</p> : <p>Shake your device...</p>}
</div>
);
}
Motion sensors:
"use client";
import { useEffect, useState } from "react";
import styles from "./page.module.css";
import { Accelerometer } from "motion-sensors-polyfill";
export default function Home() {
const [accelerationCoords, setAccelerationCoords] = useState({
x: 0,
y: 0,
z: 0,
});
useEffect(() => {
const sensor = new Accelerometer();
sensor.addEventListener("reading", () => {
setAccelerationCoords({
x: sensor.x,
y: sensor.y,
z: sensor.z,
});
});
sensor.start();
return () => {
sensor.stop();
};
}, []);
return <main className={styles.main}>
<p>{accelerationCoords.x}</p>
<p>{accelerationCoords.y}</p>
<p>{accelerationCoords.z}</p>
</main>;
}
devicemotion:
import React, { useEffect, useState } from 'react';
export default function Home() {
const [motion, setMotion] = useState({ x: 0, y: 0, z: 0 });
useEffect(() => {
function handleDeviceMotion(event) {
setMotion({
x: event.accelerationIncludingGravity.x,
y: event.accelerationIncludingGravity.y,
z: event.accelerationIncludingGravity.z,
});
}
window.addEventListener('devicemotion', handleDeviceMotion);
return () => {
window.removeEventListener('devicemotion', handleDeviceMotion);
};
}, []);
return (
<div>
<h1>Device Motion</h1>
<p>X: {motion.x}</p>
<p>Y: {motion.y}</p>
<p>Z: {motion.z}</p>
</div>
);
}
Then I started host with "devip": "next dev -H 0.0.0.0 -p 8080"
(I insert my ip instead 0.0.0.0) and then connect to the host both from desktop browser and from phone (tried both Safari and Chrome).
No matter how much I shake my phone completely nothing happens. I tried to change setState in each block manually like:
setShakeDetected(true);
inside each event listener and it does not change this state
Upvotes: 5
Views: 491
Reputation: 81
The answer by @mgarcia is only part of the picture. For Safari on iOS devices, asides from running in a secured (HTTPS) context, you must also request necessary permission through DeviceMotionEvent.requestPermission()
method.
Notice that this won't work if you call it on page loads. As this is already answered in other thread, you can refer to other answers under this SO question for code examples.
Upvotes: 1
Reputation: 6325
Note that Shake.js
has been archived in 2020 so it seems that is not being actively maintained.
That being said, Shake.js
relies on devicemotion
under the hood so this applies both to your Shake.js
and the devicemotion
approaches.
From the devicemotion
MDN documentation:
This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
By default, nextjs runs the project under http
. If that's your case, the event is not being triggered because of that.
To run your project in https
you will have to change your script in package.json
file, so that it includes the --experimental-https
flag:
next dev --experimental-https
After that your code should work as it is.
Note that this solution is handy for development purposes. For production you should generate your own issued certificates.
Upvotes: 6