I'm playing with deviceorientation in JavaScript and I noticed some differences between my Ipad (iOS 6.1) and my Nexus7 (Android 4.2.2).
This code does not print the same data with the Ipad and the Nexus7.
<html>
<head/>
<body>
<button id="calibrate">Calibrate</button>
<button id="stop">Stop</button>
<button id="play">Play</button>
<div id="log"><p></p></div>
<script>
var log = document.getElementById('log');
var calibrate = false;
var calibrateG = 0, calibrateB = 0, calibrateA = 0;
var deviceorientation = function(e) {
if (calibrate) {
calibrateG = e.gamma;
calibrateB = e.beta;
calibrateA = e.alpha;
calibrate = false;
}
var gamma = parseInt(e.gamma - calibrateG);
var beta = parseInt(e.beta - calibrateB);
var alpha = parseInt(e.alpha - calibrateA);
var p = document.createElement('p');
p.innerHTML = gamma + ' ' + beta + ' ' + alpha;
log.insertBefore(p, log.firstChild);
}
document.getElementById('stop').onclick = function() {
window.removeEventListener('deviceorientation', deviceorientation);
};
document.getElementById('play').onclick = function() {
window.addEventListener('deviceorientation', deviceorientation);
};
document.getElementById('calibrate').onclick = function() {
calibrate = true;
};
window.addEventListener('deviceorientation', deviceorientation);
</script>
</body>
</html>
At start Android print 0 0 270 and iOS 0 0 0.
Then when I move both in the same way, they don't print the same values.
Can someone explain why, and if there are a way to normalize the data.
UPDATE #1
I already try some calibrations and I care about landscape/portrait.
To reproduce, you can take the code above, put ipad and nexus7 in portrait in front of you.
Calibrate the value of both (first button).
Then take the right corner of the tablet and rotate it until the tablet reaches 90 degrees.
The tablet should be on the left side.
On Android the gamma goes from 0 to -80 and then jump to 270.
On IOS the gamma goes from 0 to -180 without any jump.
Full Tilt JS normalizes the data values between Android and iOS deviceorientation implementations. It also ensures deviceorientation data remains consistent whenever the user rotates their screen.
This article provides a summary of some of the techniques used in the Full Tilt JS library.
Disclaimer: I am the author of both the article and library above. Please give it a try and report any issues directly on the Github project.
If you need all three for an application or game you could prompt the user to ~"hold there device up straight" and record the initial values, then get offsets (deltas) of those values. You could even save that initial calibration to localStorage so it doesn't need to be repeated.
If all you need is landscape or portrait just compare window.innerWidth with window.innerHeight or something equally as trivial.
Related
i want to fire device orientation event for mobiles using JavaScript,
my code is worked fine in chrome , but it doesn't work in safari
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', eventData => {
// gamma: Tilting the device from left to right. Tilting the device to the right will result in a positive value.
const tiltLR = eventData.gamma;
// beta: Tilting the device from the front to the back. Tilting the device to the front will result in a positive value.
const tiltFB = eventData.beta;
// alpha: The direction the compass of the device aims to in degrees.
const dir = eventData.alpha;
// Call the function to use the data on the page.
deviceOrientationHandler(tiltLR, tiltFB, dir);
}, false);
}
This might be a shot in the dark but I have no idea what's causing this.
I've developed a game engine with webgl. My main testing browser has been firefox and everything works perfectly. No lag or random stutters, even if I'm doing more intense things like blending with multiple framebuffers.
However, on Chrome it's a whole other story. Chrome struggles to keep a stable fps when even running the most simple tasks. I decided to create an experiment to see if the problem was in my code or in the requestAnimation loop. This is the code I ran:
<!DOCTYPE html>
<html>
<body>
<div id="fpsCounter"></div>
Lowest fps
<div id="minFps"></div>
<br>
Highest fps
<div id="maxFps"></div>
<script>
var minFps = 999;
var maxFps = 0
var fps = 0;
var last = performance.now();
var now;
var fpsUpdateTime = 20;
var fpsUpdate = 0;
var fpsCounter = document.getElementById("fpsCounter");
var minFpsEle = document.getElementById("minFps");
var maxFpsEle = document.getElementById("maxFps");
function timestamp(){
return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
}
var getMaxFps = false;
setTimeout(function(){
getMaxFps = true;
}, 2000);
function gameLoop(){
now = performance.now();
if(fpsUpdate == 0){
fps = 1000 / (now - last);
fpsUpdate = fpsUpdateTime;
}
fpsUpdate--;
fpsCounter.innerHTML = fps;
if(parseInt(fps, 10) < parseInt(minFps, 10)){
minFps = parseInt(fps, 10);
minFpsEle.innerHTML = minFps;
}
if(parseInt(fps, 10) > parseInt(maxFps, 10) && getMaxFps){
maxFps = parseInt(fps, 10);
maxFpsEle.innerHTML = maxFps;
}
last = now;
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>
All the code does is loop the animation frame and put the fps into a div. On Firefox this works just as well as the whole game engine did, it keeps an average of about 58 and never dipps below 52 fps. Chrome struggles to be above 40 fps and frequently dips below 28. Oddly enough, Chrome has some frequent burst of speed, highest fps chrome got was 99 fps but thats kinda pointless since a stable 60 fps is more important.
Details:
Firefox version: 55.0.2 64-bit
Chrome version: 60.0.3112.78 (official version) 64-bit
OS: Ubuntu 16.04 LTS
Ram: 8gb
GPU: gtx 960m
Cpu: intel core i7HQ
This is how performance looks in Chrome:
I made this minimalistic html page for test:
<!DOCTYPE html>
<html>
<head>
<title>requestAnimationFrame</title>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<script>
"use strict"
// (tested in Ubuntu 18.04 and Chrome 79.0)
//
// requestAnimationFrame is not precise
// often SKIPs a frame
//
function loop() {
requestAnimationFrame(loop)
var ctx = document.getElementById("canvas").getContext("2d")
ctx.fillStyle = "red"
ctx.fillRect(100,100,200,100)
}
loop()
</script>
</body>
</html>
summary - dev tools image
There is no memory leak problem.
The scripting execution time is negligible.
fps - dev tools image
The FPS has inconsistent behaviour (running Chrome on Ubuntu).
In this test the problem was hardware acceleration.
The FPS was ok when hardware acceleration was disabled.
EDITED
I have done more tests with a page containing just a single canvas.
My conclusion is that browsers are too much complex (or buggy) and hardly run smoothly 100% of the time.
my architecture for games
var previousTimeStamp = 0
function mainLoop(timeStamp) {
if (! shallSkipLoop(timeStamp)) { gameLoop() }
requestAnimationFrame(mainLoop)
}
function gameLoop() {
// some code here
}
function shallSkipLoop(timeStamp) {
var deltaTime = timeStamp - previousTimeStamp
previousTimeStamp = timeStamp
//
// avoiding bad frame without less than 1000 / 60 ms!!!
// this happens when browser executes a frame too late
// and tries to be on time for the next screen refresh;
// but then may start a long sequence of unsynced frames:
// one very short (like 5ms) the other very long (like 120ms)
// maybe it is a bug in browser
//
return deltaTime < 16
}
requestAnimationFrame(mainLoop)
how can i set the touch1 to be the upper finger on the screen and touch2 to be always the lower finger on the screen? even if the lower touch came first ?
var touch1 = e.originalEvent.touches["0"];
var touch2 = e.originalEvent.touches["1"];
can the two variables be swapped after each
i am asking this because phonegap has some problems in detecting the second touch on the screen when it is converted to android app
this is a demo of what i tried to convert demo
thanks for the help
not sure if this helps... additional event interrogation for more android and ios cross browser compat. If the lower coordinate is triggered first then swap the variable values (or that's the plan).
var touch1 = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
var touch2 = e.originalEvent.touches[1] || e.originalEvent.changedTouches[1];
var touchX_1 = touch1.pageX || touch1.screenX, touchY_1 = touch1.pageY || touch1.screenY;
var touchX_2 = touch2.pageX || touch2.screenX, touchY_2 = touch2.pageY || touch2.screenY;
if (touchY_1 > touchY_2){ // is first touch lower than second touch ?
var shimx = touchX_1, shimy = touchY_1; // create a temporary shim
touchX_1 = touchX_2, touchY_1 = touchY_2; // copy the second touch coordinate to the first
touchX_2 = shimx, touchY_2 = shimy; // put the lower touch coordinate into the upper
}
// now touchXY_2 is the higher touch position
I am trying to generate a group of thumbnails in the browser out of a HTML5 video using canvas with this code:
var fps = video_model.getFps(); //frames per second, comes from another script
var start = shot.getStart(); //start time of capture, comes from another script
var end = shot.getEnd(); //end time of capture, comes from another script
for(var i = start; i <= end; i += 50){ //capture every 50 frames
video.get(0).currentTime = i / fps;
var capture = $(document.createElement("canvas"))
.attr({
id: video.get(0).currentTime + "sec",
width: video.get(0).videoWidth,
height: video.get(0).videoHeight
})
var ctx = capture.get(0).getContext("2d");
ctx.drawImage(video.get(0), 0, 0, video.get(0).videoWidth, video.get(0).videoHeight);
$("body").append(capture, " ");
}
The the amount of captures is correct, but the problem is that in Chrome all the canvases appear black and in Firefox they always show the same image.
Maybe the problem is that the loop is too fast to let the canvases be painted, but I read that .drawImage() is asynchronous, therefore, in theory, it should let the canvases be painted before jumping to the next line.
Any ideas on how to solve this issue?
Thanks.
After hours of fighting with this I finally came up with a solution based on the "seeked" event. For this to work, the video must be completely loaded:
The code goes like this:
var fps = video_model.getFps(); //screenshot data, comes from another script
var start = shot.getStart();
var end = shot.getEnd();
video.get(0).currentTime = start/fps; //make the video jump to the start
video.on("seeked", function(){ //when the time is seeked, capture screenshot
setTimeout( //the trick is in giving the canvas a little time to be created and painted, 500ms should be enough
function(){
if( video.get(0).currentTime <= end/fps ){
var capture = $(document.createElement("canvas")) //create canvas element on the fly
.attr({
id: video.get(0).currentTime + "sec",
width: video.get(0).videoWidth,
height: video.get(0).videoHeight
})
.appendTo("body");
var ctx = capture.get(0).getContext("2d"); //paint canvas
ctx.drawImage(video.get(0), 0, 0, video.get(0).videoWidth, video.get(0).videoHeight);
if(video.get(0).currentTime + 50/fps > end/fps){
video.off("seeked"); //if last screenshot was captured, unbind
}else{
video.get(0).currentTime += 50/fps; //capture every 50 frames
}
}
}
, 500); //timeout of 500ms
});
This has worked for me in Chrome and Firefox, I've read that the seeked event can be buggy in some version of particular browsers.
Hope this can be useful to anybody. If anyone comes up with a cleaner, better solution, it would be nice to see it.
I have problem with display of correct javascript in IE9. Other browsers (Firefox, Opera, Chrome, Safari) work well, but animation in IE is not fluent. For example see this line which can be dragged from left to right (link at the end of the post).
javascript code:
var w = 1250;
var h = 650;
var drawing = Raphael("obrazek",w,h);
var Ax = 50
var Ay = 50
var Ey = 500
var w = 1250;
var h = 650;
var drawing = Raphael("obrazek",w,h);
var Ax = 50
var function onDragMove(dx,dz) {
this.onDragUpdate(dx - (this.deltax || 0), dz - (this.deltaz || 0));
this.deltax = dx;
this.deltaz = dz;
}
function onDragStart() { this.deltax = this.deltaz = 0; }
function onDragStop() { this.onDragStop(); }
// line 1
var Ax
var line = drawing.path([["M",Ax,Ay],["L",Ax,Ey]]).attr({"stroke-width":3})
line.drag(onDragMove,onDragStart)
line.attr({"cursor":"move"})
line.onDragUpdate = function(dx,dz) {
Ax += dx
line.attr({"path":[["M",Ax,Ay],["L",Ax,Ey]]})
}
and corresponding HTML:
<html>
<head>
<script src="raphael.js"></script>
</head>
<body>
<div id="obrazek">
<script src="ietest.js"></script>
</div>
</body>
</html>
or see the problem in IE9 here and compare it with Chrome:
http://mech.fsv.cvut.cz/~stransky/ietest/ietest.html
Thank in advance for any help.
Your page is missing doctype, so it is rendered in quirks mode. IE9 uses VML instead of SVG in quirks mode, which probably results in slower rendering. Just add this on the first line of your html:
<!DOCTYPE html>
However, your code has some other problems:
Missing semicolons. There is a good explanation of how it may be dangerous.
Variable re-declarations and re-definitions.
When handling rapidly repeating events like mousemove or scroll, it is reasonable to use throttling to avoid redrawing/repainting glitches and performance problems. You can read more about it here. Include the plugin from that site and replace your drag binding with the following:
line.drag($.throttle(30, onDragMove), onDragStart);
In fact, even doing this without specifying the doctype can greatly improve the rendering performance, but there's no reason not to specify it altogether.