clientWidth and clientHeight delayed on Android default browser? - javascript

I am using jqtouch.js (with zepto.js) and testing the onorientationchange event:
http://www.ebi.ac.uk/~mp/test_orientation.html
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<!-- Local jqTouch -->
<link rel="stylesheet" href="lib/jqtouch-1.0-b4-rc/themes/css/apple.css" title="jQTouch">
<!-- <style type="text/css" media="screen">#import "lib/jqtouch-1.0-b4-rc/themes/css/jqtouch.css";</style> -->
<script src="lib/jqtouch-1.0-b4-rc/src/lib/zepto.min.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/jqtouch-1.0-b4-rc/src/jqtouch.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var jQT = new $.jQTouch({});
</script>
</head>
<body>
<h1>Hello World</h1>
<script>
window.onorientationchange = function() {
var w = document.documentElement.clientWidth;
var h = document.documentElement.clientHeight;
alert("WIDTH: " + w + " -- HEIGHT: " + h);
}
</script>
</body>
</html>
Opening this page with the default Android browser I get the clientWidth and clientHeight numbers reversed (when changing the orientation to landscape, I get more height than width, and vice-versa).
If I insert a short delay:
http://www.ebi.ac.uk/~mp/test_orientation_delay.html
<script>
window.onorientationchange = function() {
setTimeout(function() {
var w = document.documentElement.clientWidth;
var h = document.documentElement.clientHeight;
alert("WIDTH: " + w + " -- HEIGHT: " + h);
}, 500);
}
</script>
The clientWidth and clientHeight are properly retrieved.
This doesn't happen with Safari (iOS5) or Chrome (they don't need the short delay to display the correct numbers).
Is there an alternative way to safely retrieve these numbers consistently (without having to introduce an arbitrary delay that can be enough or not)?
M;

Possibly too late, but I think this has to do with the fact that when the event fires you're still looking at the BEFORE state. The new state will occur AFTER the event, as the event only tells you "I am ABOUT to change orientation, but didn't do it yet."

Related

How to scale A Unity-WebGL game to browser window

I've built a Unity game for web, setting the default resolution to 1152 x 648 for testing. The output html file had the following code:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | MyGame</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/chaChingWeb.json", {onProgress: UnityProgress});
</script>
</head>
<body>
<div class="webgl-content">
<div id="gameContainer" style="width: 1152px; height: 648px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
<div class="title">MyGame</div>
</div>
</div>
</body>
</html>
I found out that with resolutions below that (such as 1024 x 768), it doesn't scale at all, and the player would need to scroll to see the rest of the content.
So I added the following code:
<script type="text/javascript">
function resizeGame() {
var winSize = {w:1152, h:648};
var fill1Div = document.getElementById('gameContainer');
var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
var height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
var scaleWidth = width / winSize.w;
var scaleHeight = height / winSize.h;
var bgScale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
bgScale = bgScale >= 1 ? 1 : bgScale;
var bgTransformScale = "scale(" + bgScale + ")";
fill1Div.style.transform = bgTransformScale;
fill1Div.style.webkitTransform = bgTransformScale;
fill1Div.style.MozTransform = bgTransformScale;
fill1Div.style.msTransform = bgTransformScale;
fill1Div.style.OTransform = bgTransformScale;
}
window.addEventListener("resize", resizeGame);
window.addEventListener("orientationchange", resizeGame);
resizeGame();
</script>
While this does the job nicely, unfortunately it screws up the game itself: for example, in the picture below, I need to click on the "X" to dismiss a pop-up. But when scaled (as with the lower picture), to dismiss the pop-up, I need to click on where the "X" button would have been if it weren't.
This becomes worse the smaller it is.
It's like the game scales, but the actual colliders do not.
I can't set the initial resolution to be too small, as that would force the players with larger screens to use the Full-screen mode.
Is there anything else I can try? Thanks.

Can't view Google Maps in HTML, Cordova

I'm trying to displayGoogle Maps on a html page in cordova.
The example code I'm trying to replicate is this one: https://developers.google.com/maps/documentation/javascript/examples/map-simple?hl=it
Here is my code:
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<title>Hello World</title>
</head>
<body>
<div class="app">
<div id="map-canvas"></div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src=js/jquery-1.11.1.min.js></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script type="text/javascript" src="js/google_map.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
index.js (I used some alert() and every method was called)
var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
toIndex();
}
};
$(document).ready( function(){
app.initialize();
});
function toIndex(){
google_map.init();
}
google_map.js
the class which take care of the map
var google_map = (function(){
var _map;
var _$map_canvas;
function init(){
_$map_canvas = $('.app').find('#map-canvas');
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644)
};
_map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
function getMap(){
return _map;
}
return {
init:init,
getMap:getMap
}
})();
and the index.css file
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
Instead of displaying the map, I see a white page.
Second question:
code here: http://jsfiddle.net/qbddfdk7/1/
This one doesn't work too, the problem is at line 14:
if I change it from
map = new google.maps.Map(map_canvas, mapOptions);
to
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
It will work, but I can't undesrstand why.
The problem with your second question is a timing issue.
You see, your inline javascript is in the <head>, so at the time var map_canvas = document.getElementById('map-canvas'); runs, the element with the id map-canvas is not loaded yet, so var map_canvas is set to null.
Moving the <script> tag to the bottom of the <body> element solves this issue. I've updated your jsFiddle accordingly.
As for your first issue, try Chrome Remote Debugging if available, or weinre. These will help you find the source of your problem.
I've had no luck using their recommendation to use percentages for the map-canvas. To ensure everything is working fine, hard-code the div tag to a fixed width and height.
Once you have the map displayed, then you'll need to write javascript to adjust the style width and height during the pagecreate or pageinit. You can then change the same properties during the orientationchange event.
There are several articles on the best way to find the screen size. I'm using:
function effectiveDeviceWidth(factor) {
var deviceWidth = window.orientation == 0 ? window.screen.width : window.screen.height;
// iOS returns available pixels, Android returns pixels / pixel ratio
// http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html
if (navigator.userAgent.indexOf('Android') >= 0 && window.devicePixelRatio) {
deviceWidth = deviceWidth / window.devicePixelRatio;
}
return parseInt(deviceWidth) * factor + 'px';
}
function effectiveDeviceHeight(factor) {
var deviceHeight = window.orientation == 0 ? window.screen.height : window.screen.width;
// iOS returns available pixels, Android returns pixels / pixel ratio
// http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html
if (navigator.userAgent.indexOf('Android') >= 0 && window.devicePixelRatio) {
deviceHeight = deviceHeight / window.devicePixelRatio;
}
return parseInt(deviceHeight) * factor + 'px';
}
$('#map-canvas').width(effectiveDeviceWidth(.8));
$('#map-canvas').height(effectiveDeviceHeight(.6));
Hope this helps.
The problem was in the css, in eclipse I corrcted the css to this:
html, body, #map-canvas {
height: 100%;
width: 100%;
position: relative;
z-index: -1;
margin: 0px;
padding: 0px
}
I'm new to web languages and I didn't know that I had to write css even for the hmtl and the body tag, as you can see those tag are missing from the code in the question.

Javascript does not seem to be called

im having a problem with a javascript file possibly failing to load or containing errors
HTML Code:
<head>
<title>TEMPLATE</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="author" content="Adam Bullock">
<link rel="stylesheet" type="text/css" href="stylesheet.css">
<script src="js/main.js"></script>
</head>
Javascript Code:
/*
* NavBar_ArrowSlider moves an arrow depending on the users move selection on
* the navigation bar
*
* The script takes a position an moves the slider image to a set margin
*
* NavElement - number of list item
* MouseEvent - if users moves out of the name bar the icon will move back to
* its default position
* DefaultPosition - number of list item
*/
function navBar_arrowSlider(navElement, mouseEvent, defaultPosition) {
var arrow = document.getElementById(navBarSlider);
var navElementPosition = ["90px","295px","493px","695px"];
// DEBUG
alert("Positon:" + navElement + " Move Event:" + mouseEvent + " default position:" + defaultPositon);
// END OF DEBUG
if (mouseEvent === "mouseOver") {
var position = navElementPosition[navElement];
arrow.style.marginLeft=navElementPosition;
} else {
var position = navElementPosition[defaultPosition];
arrow.style.marginLeft=navElementPosition;
}
}
im at a lost as to why this is not working, because i cant seem to see any errors atm, bare in mind i have been working solid for the past 14 hours :/ life of a programmer
Any help would be appreciated
Thanks
Bull
You cannot have JavaScript code in <script> tags that loads external JavaScript. You need to break them up:
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript">navBar_arrowSlider(0,'moveOver',0)</script>
A <script> element can have either a "src" attribute or JavaScript content, but not both.

Why can't I get the naturalHeight/naturalWidth of an image in javascript/JQuery?

So I'm trying to do some very basic div re-sizing based on the properties of the image contained within it. I know I can do something really basic like set the background an padding around the image and achieve the same effect, but this is sort of a personal challenge.
The problem I am having is that when I try to fetch the naturalHeight or naturalWidth values of the image, I get a value of 0. However, when I try to fetch these values using the console, they return the correct values. Also, my resizeDiv() function is coming up as undefined in console.
Here's the code:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>kitten_resize - WesGilleland.com</title>
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
var kittens = new Array("100x100_kitten.jpeg","150x150_kitten.jpeg","200x150_kitten.jpeg");
$('#kittens').attr('src', kittens[0]); //set the image
function resizeDiv() {
var img = document.getElementById('kittens');
var imgH = img.naturalHeight;
var imgW = img.naturalWidth;
$('div').width(imgW);
$('div').height(imgH);
console.log('Current imgH: '+imgH);
console.log('Current imgW: '+imgW);
};
resizeDiv();
});
</script>
<style>
div {
background-color: black;
padding: 10px;
margin: auto;
}
</style>
</head>
<body>
<div>
<img id="kittens" src='' />
</div>
</body>
</html>
You can also find a working copy here: http://www.wesgilleland.com/projects/kitten_resize/
I feel like it's something very basic that I'm missing; I haven't fiddled with this stuff since my associate's degree a year ago. Thanks to anyone who can help!
That's because your image isn't yet loaded when you read the original dimensions.
You should read the dimensions when the image is loaded :
var img = $('#kittens')[0];
img.onload = resizeDiv;
img.src = kittens[0];

Internet Explorer 8 Messing Up My Bulletgraphs

I've created HTML and JavaScript files to display bulletgraphs, using the 'canvas' HTML5 tag. I've tried it in Chrome and it works nicely and changes width along with the size of the browser. I have to have this working in IE8, too, so I've used Excanvas, which is working in all except one way: when I resize the browser I get remnants of the valueIndicator. This only happens on IE8.
I've tried looking round for information on redrawing the canvas but I don't think this is the issue. Can anyone see where I'm going wrong, please?
EDIT
I'm keeping the complete code at the bottom, however, following advice I've cut my code down somewhat.
In IE8 it looks like this:
In Chrome it looks like this:
When I refresh the IE8 page it looks OK again.
Cut-down Bulletgraph.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bulletgraph</title>
<!--[if IE]><script src="excanvas.js"></script><![endif]-->
</head>
<body>
<canvas id="graph1"></canvas>
<script src="Scripts.js"></script>
<script>
drawGraphs();
window.onresize=function() { drawGraphs() };
function drawGraphs() {
drawBulletGraph(getScreenWidth(),300,1000,350,"graph1");
}
</script>
</body>
</html>
Complete code:
Cut-down Scripts.js:
function drawBulletGraph (cwidth, left, right, loValue, id) {
var canvas=document.getElementById(id);
var cheight=30;
var multiplier=cwidth/(right-left);
canvas.width=cwidth;
canvas.height=cheight;
var valueIndicator=canvas.getContext("2d");
valueIndicator.lineWidth="1";
valueIndicator.moveTo((loValue-left)*multiplier,0);
valueIndicator.lineTo((loValue-left)*multiplier,cheight);
valueIndicator.fill();
valueIndicator.stroke();
}
function getScreenWidth () {
return (window.innerWidth || document.documentElement.clientWidth)/7;
}
Bulletgraph.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bulletgraph</title>
<!--[if IE]><script src="excanvas.js"></script><![endif]-->
</head>
<body>
<canvas id="graph1"></canvas><br>
<canvas id="graph2"></canvas>
<script src="Scripts.js"></script>
<script>
drawGraphs();
window.onresize=function() { drawGraphs() };
function drawGraphs() {
drawBulletGraph(bgWidth(getScreenWidth()),300,400,450,600,700,1000,800,350,850,"graph1");
drawBulletGraph(bgWidth(getScreenWidth()),250,450,500,650,700,1200,600,350,850,"graph2");
}
</script>
</body>
</html>
Scripts.js:
function drawBulletGraph (cwidth, left, loRed, loAmber, hiAmber, hiRed, right, value, loValue, hiValue, id) {
var canvas=document.getElementById(id);
var cheight=16;
var colour="#008000";
if (value <= loRed || value >= hiRed)
{
colour="#FF0000";
}
else if (value <= loAmber || value >= hiAmber)
{
colour="#FFA500";
}
var multiplier=cwidth/(right-left);
canvas.width=cwidth;
canvas.height=cheight;
var red=canvas.getContext("2d");
red.fillStyle="#F4C3C6";
red.fillRect(0,0,cwidth,cheight);
var amber=canvas.getContext("2d");
amber.fillStyle="#F4F6C6";
amber.fillRect((loRed-left)*multiplier,0,(hiRed-loRed)*multiplier,cheight);
var green=canvas.getContext("2d");
green.fillStyle="#CCE5CC";
green.fillRect((loAmber-left)*multiplier,0,(hiAmber-loAmber)*multiplier,cheight);
var valueIndicator=canvas.getContext("2d");
valueIndicator.fillStyle=colour;
valueIndicator.strokeStyle=colour;
valueIndicator.lineWidth="2";
valueIndicator.moveTo((loValue-left)*multiplier,0);
valueIndicator.lineTo((loValue-left)*multiplier,cheight);
valueIndicator.moveTo((loValue-left)*multiplier,cheight/2);
valueIndicator.lineTo((hiValue-left)*multiplier,cheight/2);
valueIndicator.moveTo((hiValue-left)*multiplier,0);
valueIndicator.lineTo((hiValue-left)*multiplier,cheight);
valueIndicator.moveTo(((value-left)*multiplier)-(cheight/2),cheight/2);
valueIndicator.stroke();
valueIndicator.lineWidth="1";
valueIndicator.lineTo((value-left)*multiplier,cheight);
valueIndicator.lineTo(((value-left)*multiplier)+(cheight/2),cheight/2);
valueIndicator.lineTo((value-left)*multiplier,0);
valueIndicator.lineTo(((value-left)*multiplier)-(cheight/2),cheight/2);
valueIndicator.fill();
valueIndicator.stroke();
}
function getScreenWidth () {
return window.innerWidth || document.documentElement.clientWidth;
}
function bgWidth (screenWidth) {
var graphWidth=screenWidth/7;
if (graphWidth<70) {graphWidth=70;}
if (graphWidth>260) {graphWidth=260;}
return graphWidth;
}
I've managed to get a solution. It feels like a bit of a hack but it does the trick. Basically it involves drawing a white line round the canvas and filling it each time it's drawn again. The following code goes between the var valueIndicator=canvas.getContext("2d"); and the valueIndicator.lineWidth="1"; lines:
valueIndicator.fillStyle="#FFFFFF";
valueIndicator.strokeStyle="#FFFFFF";
valueIndicator.moveTo(0,0);
valueIndicator.beginPath();
valueIndicator.lineTo(0,cheight);
valueIndicator.lineTo(cwidth,cheight);
valueIndicator.lineTo(cwidth,0);
valueIndicator.closePath();
valueIndicator.fill();
valueIndicator.stroke();
valueIndicator.strokeStyle="#000000";
I've tried it in the full code and it works. If anyone has a more elegant solution, and I'm sure there must be many, I would still love to see them.

Categories

Resources