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);
}
Related
Is there any difference between writing JS touch events for iPad vs. iPhone? I have read a ton of documentation and as far as I can tell it should work the same way for both.
I have a drag-and-drop game, basically you grab a coin from under the dragon and drag it over to your vault. The dragging works on iPad, but not on iPhone. I'm trying to figure out why.
The game, for reference: https://codeeverydamnday.com/projects/dragondrop/dragondrop.html
The JS, abridged to just the relevant code for this question (with comments for clarity):
var dragndrop = (function() {
var myX = "";
var myY = "";
// The coin's starting X and Y coordinate positions
var coin = "";
// The coin you start touching / dragging
function touchStart(e) {
e.preventDefault();
// Prevents default behavior of scrolling when you touch/drag on mobile
var coin = e.target;
var touch = e.touches[0];
var moveOffsetX = coin.offsetLeft - touch.pageX;
var moveOffsetY = coin.offsetTop - touch.pageY;
// Defines offset between left edge of coin and where you place your finger on it
coin.addEventListener('touchmove', function() {
var positionX = touch.pageX+moveOffsetX;
var positionY = touch.pageY+moveOffsetY;
// Defines the X-Y coordinates of wherever you stop dragging
coin.style.left = positionX + 'px';
coin.style.top = positionY + 'px';
// Updates the coin's X-Y coordinates with the new positions
}, false)
}
document.querySelector('body').addEventListener('touchstart', touchStart, false);
})();
If it helps, I am getting this console log error every time I click / tap on the iPad screen in the Chrome Dev Tools emulator:
[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive.
This error doesn't seem to prevent the dragging from working on iPad, but I'm not sure if it has anything to do with the dragging not working on mobile? I tried adding a few things to fix the error based on other Stack Overflow questions I saw (ex. adding touch-action: none; in my CSS, but the error persisted).
Anyone see anything wrong in my code? I would love to get this game playable on mobile, as that's how most people would access it!
The default value of the passive option is set to true for touch-start and touch-move events, and it being true means your function won't call preventDefault to disable scrolling.
Simply set the passive value to false to solve your issue.
var dragndrop = (function() {
var myX;
var myY;
var coin;
function touchStart(e) {
e.preventDefault();
coin = e.target;
const touch = e.touches[0];
const moveOffsetX = whichArt.offsetLeft - touch.pageX;
const moveOffsetY = whichArt.offsetTop - touch.pageY;
coin.addEventListener("touchmove", touchMove, { passive: false });
function touchMove(e) {
const touch = e.touches[0];
const positionX = touch.pageX + moveOffsetX;
const positionY = touch.pageY + moveOffsetY;
coin.style.left = `${positionX}px`;
coin.style.top = `${positionY}px`;
}
}
document.body.addEventListener('touchstart', touchStart, { passive: false });
})();
Edit
I looked at the code from the website you linked, and I realized that one reason the coin wasn't dragged was because of touch we were using and also because of the once option I passed to the touchmove event.
Whenever the touchmove event is used, we have to use the new touch to get the pageX and pageY positions on the screen, I decided to create a function for the touchmove event, because whenever the touchstart function is called, a new touchmove event is registered because of the anonymous function handler.
So creating and naming a function for it will prevent the same function from being added.
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 have problem with resize windows game. I've read various posts on the forum but I could not get the correct resize the view of the game.
If you rotate the device screen size, I would like to display the game has adapted to the width / height of the display device both horizontally and vertically.
When the game started, it is properly scaled up, just turning your exchange device scaling is incorrect. Return to the previous screen orientation device retains its proportions.
In template html I add:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
First script:
function preload() {
...
Global.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
Global.game.scale.pageAlignHorizontally = true;
Global.game.scale.pageAlignVertically = true;
Global.game.scale.forceOrientation(true, false);
Global.game.scale.setMaximum();
Global.game.scale.setScreenSize(true);
...
}
function resize() {
Global.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
Global.game.scale.pageAlignHorizontally = true;
Global.game.scale.pageAlignVertically = true;
Global.game.scale.forceOrientation(true, true);
Global.game.scale.setShowAll();
Global.game.scale.refresh();
}
When I use this code, game scale correct when game started. When in device:
change position with horizontal on vertical, game is bigges and show
scroll
change position with vertical on horizontal, game is flat
Second script:
function preload() {
...
Global.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
Global.game.scale.parentIsWindow = true;
...
}
function resize () {
Global.game.scale.refresh();
}
When I use this code, game scale correct when game started. When in device:
1. change position with horizontal on vertical, game is scaled but on left and right is see white background
2. change position with vertical on horizontal, game is scaled but on bottom I see white background
I use Phaser 2.3
Does anyone know the solution to my problem?
Thank you =)
BEST SOLUTION
Phaser 2.3 have a bug - not change resize site. I download 2.4.3 version.
I've added features that is loaded at the beginning, which guards the resolution change
var attacks.base.x = 110;
var attacks.base.y = 190;
$(document).ready(function () {
handleScreenResize();
});
function handleScreenResize() {
$(window).resize(function () {
clearTimeout(timeoutResize);
timeoutResize = setTimeout(function () {
var xButtonBase;
var yButtonBase;
/* resize game */
game.scale.scaleMode = Phaser.ScaleManager.RESIZE;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.scale.forceLandscape = true;
game.scale.parentIsWindow = true;
game.scale.refresh();
/* get new width and height*/
var gameWidth = game.width < game.world.width ? game.width : game.world.width;
/** If you have static button you have change position use "cameraOffset.x" and "cameraOffset.y" set new position*/
/* change position buttons attack */
if(settings.control_option === 'RIGHTHAND') {
xButtonBase = attacks.base.x;
yButtonBase = game.height - attacks.base.y;
} else {
xButtonBase = gameWidth - attacks.base.x;
yButtonBase = game.height - attacks.base.y;
}
/** set position buttons with attack and assist (down screen)*/
attacks.base.button.cameraOffset.x = xButtonBase;
attacks.base.button.cameraOffset.y = yButtonBase;
}, 1000);
});
}
In preload add this script
function preload() {
...
Global.game.scale.scaleMode = Phaser.ScaleManager.RESIZE;
Global.game.scale.pageAlignHorizontally = true;
Global.game.scale.pageAlignVertically = true;
Global.game.scale.forceLandscape = true;
Global.game.scale.parentIsWindow = true;
Global.game.scale.refresh();
...
}
This sounds like an issue that my friend and I were getting when we were trying to re-size our game to a larger resolution if our window changed size.
See this issue: https://github.com/photonstorm/phaser/issues/1881
It should be fixed in Phaser 2.4 (RC1 is out now).
I have a page which allows you to browse in an image, then draw on it and save both the original and the annotated version. I am leveraging megapix-image.js and exif.js to help in rendering images from multiple mobile devices properly. It works great, except in certain orientations. For example, a vertical photo taken on an iPhone4s is considered orientation 6 by exif and gets flipped accordingly by megapix-image so it's rendered nicely on the canvas. For some reason, when I draw on it afterward, it seems like the drawing is reversed. Mouse and touch both behave the same way. The coordinates look right to me (meaning they match a working horizontal pic and a non-working vertical pic), as does the canvas height and width when megapix-image.js flips it. This leads me to believe it has something to do with the context, but honestly, I am not really sure. I have a JS fiddle of the part of my work that shows the behavior. Just browse in a vertically taken pic from a mobile device or take a pic in vertical format on a mobile device and use it. I think all will show this same behavior.
The final rendering is done like this:
function RenderImage(file2) {
if (typeof file2[0].files[0] != 'undefined') {
EXIF.getData(file2[0].files[0], function () {
orientation = EXIF.getTag(this, "Orientation");
var file = file2[0].files[0];
var mpImg = new MegaPixImage(file);
var resCanvas1 = document.getElementById('annoCanvas');
mpImg.render(resCanvas1, {
maxWidth: 700,
maxHeight: 700,
orientation: orientation
});
});
}
}
But the full jsfiddle is here:
http://jsfiddle.net/awebster28/Tq3qU/6/
Does anyone have any clues for me?
If you look at the lib you are using there is a transformCoordinate function that is used to set the right transform before drawing.
And they don't save/restore the canvas (boooo!!!) so it remains with this transform after-wise.
Solution for you is to do what the lib should do : save the context before the render and restore it after :
function RenderImage(file2) {
// ... same code ...
var mpImg = new MegaPixImage(file);
var eData = EXIF.pretty(this);
// Render resized image into canvas element.
var resCanvas1 = document.getElementById('annoCanvas');
var ctx = resCanvas1.getContext('2d');
ctx.save();
//setting the orientation flips it
mpImg.render(resCanvas1, {
maxWidth: 700,
maxHeight: 700,
orientation: orientation
});
ctx.restore();
//...
}
I ended up fixing this by adding another canvas to my html (named "annoCanvas2"). Then, I updated megapix-image.js to include this function, which draws the contents of the new canvas to a fresh one:
function drawTwin(sourceCanvas)
{
var id = sourceCanvas.id + "2";
var destCanvas = document.getElementById(id);
if (destCanvas !== null) {
var twinCtx = destCanvas.getContext("2d");
destCanvas.width = sourceCanvas.width;
destCanvas.height = sourceCanvas.height;
twinCtx.drawImage(sourceCanvas, 0, 0, sourceCanvas.width, sourceCanvas.height);
}
}
Then, just after the first is rotated and flipped and rendered, I rendered the resulting canvas to my "twin". Then I had a nice canvas, with my updated image that I could then draw on and also save!
var tagName = target.tagName.toLowerCase();
if (tagName === 'img') {
target.src = renderImageToDataURL(this.srcImage, opt, doSquash);
} else if (tagName === 'canvas') {
renderImageToCanvas(this.srcImage, target, opt, doSquash);
//------I added this-----------
drawTwin(target);
}
I was glad to have it fixed so I met my deadline, but I am still not sure why I had to do this. If anyone out there can explain it, I'd love to know why.
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.