forked from WyriHaximus/reactphp.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmanjindex.html
More file actions
272 lines (241 loc) · 8.59 KB
/
manjindex.html
File metadata and controls
272 lines (241 loc) · 8.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>DeviceMotion Rate Tester</title>
<style>
:root{
--bg:#0b1220; --card:#0f1724; --muted:#9aa4b2; --accent:#60a5fa; --text:#e6eef6;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:Inter,system-ui,-apple-system,"Segoe UI",Roboto,Arial;
background:linear-gradient(180deg,#071022 0%, #0b1220 100%);
color:var(--text);
display:flex;
align-items:center;
justify-content:center;
min-height:100vh;
padding:20px;
}
.card{
width:min(760px,96%);
background:linear-gradient(180deg, rgba(255,255,255,0.02), var(--card));
padding:20px;
border-radius:12px;
box-shadow:0 10px 30px rgba(0,0,0,0.6);
}
h1{margin:0 0 10px;font-size:1.2rem}
p {color:var(--muted);margin:0 0 12px}
.controls{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
button{
background:transparent;border:1px solid rgba(255,255,255,0.06);
color:var(--text);padding:10px 12px;border-radius:8px;cursor:pointer;
}
button.primary{border-color:var(--accent);box-shadow:0 6px 18px rgba(96,165,250,0.08)}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:14px}
.stat{
background:rgba(255,255,255,0.02);padding:12px;border-radius:8px;text-align:center;
}
.stat .label{color:var(--muted);font-size:0.85rem}
.stat .value{font-weight:700;font-size:1.3rem;margin-top:6px}
canvas{width:100%;height:80px;border-radius:8px;background:linear-gradient(180deg,#06101a, #08121a);display:block}
.note{font-size:0.85rem;color:var(--muted);margin-top:12px}
a {color:var(--accent)}
</style>
</head>
<body>
<div class="card">
<h1>DeviceMotion Rate Tester</h1>
<p>Shows how fast your browser is sending <code>devicemotion</code> events (events per second, intervals, and a small live graph).</p>
<div class="controls">
<button id="btn-perm" class="primary">Request Motion Permission</button>
<button id="btn-start">Start Listening</button>
<button id="btn-stop">Stop</button>
<button id="btn-reset">Reset</button>
</div>
<div class="stats">
<div class="stat">
<div class="label">Events / sec (instant)</div>
<div id="eps" class="value">—</div>
</div>
<div class="stat">
<div class="label">Average interval (ms)</div>
<div id="avg-interval" class="value">—</div>
</div>
<div class="stat">
<div class="label">Last interval (ms)</div>
<div id="last-interval" class="value">—</div>
</div>
<div class="stat">
<div class="label">Total events</div>
<div id="total" class="value">0</div>
</div>
</div>
<canvas id="chart" width="800" height="120" aria-label="event rate chart"></canvas>
<p class="note">
Notes: Most desktop browsers do not emit device motion events. On iOS 13+ you must explicitly grant permission; press <strong>Request Motion Permission</strong> first. Try moving or rotating the device to see events.
</p>
<p class="note">Repo: <a href="https://chaicode.com/" target="_blank" rel="noopener">ChaiCode example</a></p>
</div>
<script>
(() => {
// DOM
const btnPerm = document.getElementById('btn-perm');
const btnStart = document.getElementById('btn-start');
const btnStop = document.getElementById('btn-stop');
const btnReset = document.getElementById('btn-reset');
const epsEl = document.getElementById('eps');
const avgEl = document.getElementById('avg-interval');
const lastEl = document.getElementById('last-interval');
const totalEl = document.getElementById('total');
const canvas = document.getElementById('chart');
const ctx = canvas.getContext('2d');
// State
let listening = false;
let eventCount = 0;
let lastTs = null;
let intervals = []; // ms
const MAX_SAMPLES = 120;
let timestamps = []; // recent timestamps for instantaneous EPS
// Helpers
function msToFixed(n){ return (Math.round(n*10)/10).toFixed(1); }
// Permission flow for iOS Safari
async function requestPermission() {
if (typeof DeviceMotionEvent !== 'undefined' && typeof DeviceMotionEvent.requestPermission === 'function') {
try {
const resp = await DeviceMotionEvent.requestPermission();
if (resp === 'granted') {
alert('Motion permission granted. Now press "Start Listening".');
} else {
alert('Motion permission denied.');
}
} catch (err) {
console.error(err);
alert('Permission request failed: ' + err);
}
} else {
alert('No permission prompt required (or not supported). Try "Start Listening".');
}
}
function onDeviceMotion(e) {
const t = performance.now(); // high-res timestamp
eventCount++;
totalEl.textContent = eventCount;
if (lastTs !== null) {
const interval = t - lastTs;
intervals.push(interval);
if (intervals.length > MAX_SAMPLES) intervals.shift();
lastEl.textContent = msToFixed(interval);
}
lastTs = t;
// keep recent timestamps for instant EPS (1s window)
timestamps.push(t);
// drop timestamps older than 1s
const cutoff = t - 1000;
while (timestamps.length && timestamps[0] < cutoff) timestamps.shift();
const eps = timestamps.length;
epsEl.textContent = eps;
// average interval over stored intervals
if (intervals.length) {
const sum = intervals.reduce((a,b)=>a+b,0);
const avg = sum / intervals.length;
avgEl.textContent = msToFixed(avg);
} else {
avgEl.textContent = '—';
}
drawChart();
}
function startListening() {
if (listening) return;
// Some browsers require the handler to be passive: false if you want preventDefault (not needed here)
window.addEventListener('devicemotion', onDeviceMotion);
listening = true;
btnStart.disabled = true;
btnStop.disabled = false;
}
function stopListening() {
if (!listening) return;
window.removeEventListener('devicemotion', onDeviceMotion);
listening = false;
btnStart.disabled = false;
btnStop.disabled = true;
}
function reset() {
stopListening();
eventCount = 0;
lastTs = null;
intervals = [];
timestamps = [];
epsEl.textContent = '—';
avgEl.textContent = '—';
lastEl.textContent = '—';
totalEl.textContent = '0';
clearChart();
}
// Chart drawing (simple sparkline for events per frame calculated from intervals)
function drawChart(){
// compute samples: convert intervals[] to EPS-like values (1000 / interval)
const samples = intervals.map(i => 1000 / i);
// pad to length
const len = MAX_SAMPLES;
const padded = Array(Math.max(0, len - samples.length)).fill(0).concat(samples);
const w = canvas.width;
const h = canvas.height;
ctx.clearRect(0,0,w,h);
// background gradient
const g = ctx.createLinearGradient(0,0,0,h);
g.addColorStop(0,'rgba(96,165,250,0.08)');
g.addColorStop(1,'rgba(6,8,12,0.02)');
ctx.fillStyle = g;
ctx.fillRect(0,0,w,h);
// find max for scaling (or use fallback)
const max = Math.max(5, ...padded);
// draw line
ctx.beginPath();
padded.forEach((v,i) => {
const x = (i / (padded.length-1)) * w;
const y = h - ((v / max) * (h - 8) + 4);
if (i === 0) ctx.moveTo(x,y);
else ctx.lineTo(x,y);
});
ctx.strokeStyle = 'rgba(96,165,250,0.95)';
ctx.lineWidth = 2.0;
ctx.stroke();
// fill under curve
ctx.lineTo(w, h);
ctx.lineTo(0, h);
ctx.closePath();
ctx.fillStyle = 'rgba(96,165,250,0.08)';
ctx.fill();
// draw current EPS text small
ctx.fillStyle = 'rgba(230,238,246,0.9)';
ctx.font = '12px Inter, Arial';
const current = padded[padded.length-1] ? padded[padded.length-1].toFixed(1) : '0.0';
ctx.fillText('EPS (recent): ' + current, 8, 14);
}
function clearChart(){
ctx.clearRect(0,0,canvas.width,canvas.height);
}
// Attach events
btnPerm.addEventListener('click', requestPermission);
btnStart.addEventListener('click', startListening);
btnStop.addEventListener('click', stopListening);
btnReset.addEventListener('click', reset);
// initial state
btnStop.disabled = true;
clearChart();
// Helpful UX: if devicemotion events were active in the past, offer auto-start on load (commented out)
// startListening();
// Minor: handle page visibility to pause chart updates if needed (not strictly necessary)
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// optionally pause chart updates or logging
}
});
})();
</script>
</body>
</html>