I'm making a canvas webpage for animation. Strange thing is that every time I launch the webpage from double clicking the html file the canvas will almost always size incorrectly. I have post a similar question before: Canvas sizing incorrectly on loading but have no desired answer.
After extensive debugging I find out that it's the window.innerWidth that's giving me such trouble. The window.innerWidth returns 0 every time the page is launched from double clicking the html file and results in a incorrect canvas size (interestingly the canvas size is not exactly 0, but a very small one that has object to be rendered stack on top of one another), but after reloading the page (Ctrl+R) the problem no longer happens. I'm using jQuery to load the page, here is my code:
html:
<body>
<canvas id="main_canvas"></canvas>
</body>
js:
$(document).ready(function() {
var SCREEN_WIDTH = window.innerWidth-10,
SCREEN_HEIGHT = window.innerHeight-10;
if (window.innerWidth === 0) { alert("wtf? width = 0?");}
var canvas = $('canvas')[0],
context;
init(); // use $(window).load(init) does not fix the problem
function init() {
if (canvas.getContext) {
context = canvas.getContext('2d');
animate(); // draw stuff
}
else {
alert('Your browser does not support html5 canvas');
}
}
});
As you can see here, I'm already using $(docuemnt).ready(function()) to make sure things gets loaded, however from a link http://4loc.wordpress.com/2009/04/28/documentready-vs-windowload/ the author suggest that the document ready event executes already when the HTML-Document is loaded and the DOM is ready, even if all the graphics haven’t loaded yet.
On the other hand the $(window).load(function()) executes a bit later when the complete page is fully loaded, including all frames, objects and images. Therefore functions which concern images or other page contents should be placed in the load event for the window or the content tag itself. But even I use this the problem is not solved.
Maybe the js file is asking for window's width before it's loaded, but I can't find a viable solution. Can anyone help with this?
Use an event listener that triggers on a window resize. That way you don't have to do any nonsense with trying to find when the window fully initializes. It will also make you less dependent on state which is a nice bonus.
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
windowX = window.innerWidth;
windowY = window.innerHeight;
}
I had a similar problem with window.outerWidth which is returning 0 on some browsers when called from the ready() method, and I solved it by using screen.width instead.
I didn't test it but I think that screen.availWidth would solve your issue.
Related
I have a function responsive that changes behaviour of certain elements on my website, including hiding popups etc. I call it in 2 cases:
$(document).ready(responsive);
$(window).resize(responsive);
The problem occurs on android chrome, as the virtual keyboard actually changes the height of the screen, and triggers responsive function, which closes my popups (some of them have text fields, making it impossible to type).
How can I prevent this from happening? I read somewhere a good point that android virtual keyboard only changes height of the screen, not a width, so I assume it would be a good idea to compare width before and after resize. So I created this function to compare the widths before and after and run resize() if width is different, but it doesn't work as expected, and console logs show different document widths even though I only changed the height of the screen (using chrome developer tools).
Any idea what went wrong or how can I prevent function responsive being launched on height change?
function resizeWidth() {
var existingWidth = $(document).width();
$(window).resize(function() {
var newWidth = $(document).width();
if (existingWidth != newWidth) {
$(window).resize(responsive);
console.log(existingWidth);
console.log(newWidth);
};
});
};
$(window).resize(resizeWidth);
Firstly you are attaching a handler to the resize event multiple times. One on load, then another every time the resize happens and resizeWidth is called. You should remove the handler within that function. Also, I guess you just want to call the responsive() function, not attach yet another resize handler when the width changes.
The main issue you have is that the scope of existingWidth is not low enough for it to be seen over multiple events. You could make it global, although that is generally considered bad practice. Instead you could use a data attribute, like this:
function resizeWidth() {
var existingWidth = $(document).data('resize-width');
var newWidth = $(document).width();
if (existingWidth != newWidth) {
responsive();
$(document).data('resize-width', newWidth);
};
};
$(window).resize(resizeWidth);
hope you can help
My current project requires me to recall a set of functions on window resize so that I can keep the responsive nature correct. However the code I am using is rather twitchy as it calls the functions even if the window is resized by 1px.
I am relatively new to jQuery but learning more and more every day, but this is something I'm struggling to find a way to do.
In an ideal world I would like to call the functions when the window has been resized over a breaking point at anytime, for example:
say the breaking point is 500px, the initial load size is 400px the user resizes to 600px, so over the threshold so call the functions again.
It would also need to work in reverse... so window (or load) size 600px, breaking point 500px, resize to 400px call functions.
Here's the code I'm currently:
var windowWidth = $(window).width();
var resizing = !1;
$(window).resize(function(a) {
!1 !== resizing && clearTimeout(resizing);
resizing = setTimeout(doResize, 200);
});
function doResize() {
call_these_functions();
}
Cheers for the help guys
Thanks for the reply Zze
I am using something similar to what you've put, but I have it based within the start of my functions to filter what each thing does based on the window size. My problem is that these are getting called far too often and causing issues / twitchy behaviour.
For example I'm having issues on a tablet I'm testing on, when you scroll down, the scrollbar that appears on the right seems to trigger the window resize... causing functions to be called again that automatically accordion up or .hide() elements to their initial loaded state.
So my thinking is if I can test it's actually broken a set threshold rather than just what size the window is then it will be far more reliable.
There are some really handy jQuery functions available and it looks like you are very close to cracking this yourself. Hope this helps though.
$(window).resize(ResizeCode); // called on window resize
$(document).ready(function(e) { ResizeCode(); }); // called once document is ready to resize content immediatly
function ResizeCode()
{
if ($(window).width() < 500){
//insertCode
}
else if($(window).width() >= 500){
//insertCode
}
}
Update
If we are looking to 'restrict' the call time of this function, then you could add an interval which updates a bool every time it ticks, and then check this bool in the previous code:
var ready = true;
setInterval(function(){ready = true;}, 3000);
function ResizeCode()
{
if (ready)
{
// run code
ready = false;
}
}
But i would suggest storing the width and height of the window in a var and then comparing the current window with the var when the window is resized, that way you can tell if the window has actually been resized over 'x' amount or if it is that weird bug you've found.
Looks like i've found a solution that's going to do what i need with a little work (fingers crossed as i'm currently working on it), from http://xoxco.com/projects/code/breakpoints/
Thanks for the help Zze
In my web app, I have some thumbnails that open a lightbox when clicked. On mobile, the thumbnails are small and the user typically zooms in. The problem is that when they click to play it, the lightbox is outside of the viewable area (they have to scroll to the lightbox to see the video). Is it possible to force a mobile browser to zoom out so they can see the whole page?
Making the page more responsive is not an option right now; it is a fairly large web application and it would take a huge amount of time to refactor.
Dug through a lot of other questions trying to get something to zoom out to fit the entire page. This question was the most relevant to my needs, but had no answers. I found this similar question which had a solution, although implemented differently, and not what I needed.
I came up with this, which seems to work in Android at least.
initial-scale=0.1: Zooms out really far. Should reveal your whole website (and then some)
width=1200: Overwrites initial-scale, sets the device width to 1200.
You'll want to change 1200 to be the width of your site. If your site is responsive then you can probably just use initial-scale=1. But if your site is responsive, you probably don't need this in the first place.
function zoomOutMobile() {
var viewport = document.querySelector('meta[name="viewport"]');
if ( viewport ) {
viewport.content = "initial-scale=0.1";
viewport.content = "width=1200";
}
}
zoomOutMobile();
Similar to Radley Sustaire's solution I managed to force unzoom whenever the device is turned in React with
zoomOutMobile = () => {
const viewport = document.querySelector('meta[name="viewport"]');
if ( viewport ) {
viewport.content = 'initial-scale=1';
viewport.content = 'width=device-width';
}
}
and inside my render
this.zoomOutMobile();
1 edge case I found was this did not work on the Firefox mobile browser
I ran in a similar problem, rather the opposite, I guess, but the solution is most certainly the same. In my case, I have a thumbnail that people click, that opens a "popup" where users are likely to zoom in to see better and once done I want to return to the normal page with a scale of 1.0.
To do that I looked around quite a bit until I understood what happens and could then write the correct code.
The viewport definition in the meta data is a live value. When changed, the system takes the new value in consideration and fixes the rendering accordingly. However, the "when changed" is detected by the GUI and while the JavaScript code is running, the GUI thread is mostly blocked...
With that in mind, it meant that doing something like this would fail:
viewport = jQuery("meta[name='viewport']");
original = viewport.attr("content");
force_scale = original + ", maximum-scale=1";
viewport.attr("content", force_scale); // IGNORED!
viewport.attr("content", original);
So, since the only way I found to fix the scale is to force it by making a change that I do not want to keep, I have to reset back to the original. But the intermediary changes are not viewed and act upon (great optimization!) so how do we resolve that issue? I used the setTimeout() function:
viewport = jQuery("meta[name='viewport']");
original = viewport.attr("content");
force_scale = original + ", maximum-scale=1";
viewport.attr("content", force_scale);
setTimeout(function()
{
viewport.attr("content", original);
}, 100);
Here I sleep 100ms before resetting the viewport back to what I consider normal. That way the viewport takes the maximum-scale=1 parameter in account, then it times out and removes that parameter. The scale was changed back to 1 in the process and restoring my original (which does not have a maximum-scale parameter) works as expected (i.e. I can scale the interface again.)
WARNING 1: If you have a maximum-scale parameter in your original, you probably want to replace it instead of just appending another value at the end like in my sample code. (i.e. force_scale = original.replace(/maximum-scale=[^,]+/, "maximum-scale=1") would do the replace--but that works only if there is already a maximum-scale, so you may first need to check to allow for either case.)
WARNING 2: I tried with 0ms instead of 100ms and it fails. This may differ from browser to browser, but the Mozilla family runs the immediately timed out timer code back to back, meaning that the GUI process would never get a chance to reset the scale back to 1 before executing the function to reset the viewport. Also I do know of a way to know that the current viewport values were worked on by the GUI... (i.e. this is a hack, unfortunately.)
This one works for me
let sw = window.innerWidth;
let bw = $('body').width();
let ratio = sw / bw - 0.01;
$('html').css('zoom', ratio);
$('html').css('overflow-x', 'hidden');
Its fits html to screen and prevents from scrolling. But this is not a good idea and work not everywhere.
var zoomreset = function() {
var viewport = document.querySelector("meta[name='viewport']");
viewport.content = "width=650, maximum-scale=0.635";
setTimeout(function() {
viewport.content = "width=650, maximum-scale=1";
}, 350);
}
setTimeout(zoomreset, 150);
replace 650 with the width of your page
I am a newb to JavaScript, but am trying to learn. For that reason I would like to try and accomplish this without resorting to jQuery.
I am trying to load a page where the content is dynamically re-sized based on the height and width of the browser. I presently have two iterations of the code, one with an image in the content div and another, much simpler, without.
Firstly, addressing the one without the image. Calling winSizefrom an onload event in the body tag or inside the script tag at the bottom of the HTML seems to be able to determine the scrollHeight/Width prior to setting the style, but fills the entire window with the black of the content div rather than setting its width to 704px as the script has determined it should be. Using the document.body.onload in the script header to call winSize resulted in a null scrollWidth/Height and only displays the grey background.
The code for that is as as follows:
<style>
body {
padding:0px;
background-color: #808080;
}
div {
position:absolute;
}
</style>
<script type="text/javascript">
bArat=3/2;
bH1=0;
bW1=0;
bX1=0;
bY1=0;
function winSize(){
winW=document.body.scrollWidth;
winH=document.body.scrollHeight;
_style();
}
function _style(){
bH1=winH;
bW1=bH1/bArat;
bX1=(winW/2)-(bW1/2);
document.getElementById("gutters").style.left=bX1;
document.getElementById("gutters").style.top=bY1;
document.getElementById("gutters").style.height=bH1;
document.getElementById("gutters").style.width=bW1;
document.getElementById("gutters").style.backgroundColor="black";
document.body.style.backgroundColor="black";
}
//document.body.onload=winSize();
</script>
</head>
<body>
<div id="gutters">
</div>
<script>
//winSize();
</script>
</body>
</html>
Secondly, in the more complicated version of this script that includes a div within "gutters" that houses an img (soon to be multiple, as soon as this problem is solved), almost everything works fine except for when it loads, it does not load the styles (in Chrome). It does, however, load the styles on a refresh or if I set a 50ms delay on the onload trigger. I presume this is because Chrome (and Safari?) triggers the onload event after the html has loaded but before the image itself has been rendered, therefore the function cannot determine the height and width of the body that has not truly finished loading.
In this second script the function above:
function winSize(){
winW=document.body.scrollWidth;
winH=document.body.scrollHeight;
_style();
}
does not work at all. winH or winW are not defined.
but the function snagged from http://www.javascripter.net/faq/browserw.htm
function winSize(){
if (document.body && document.body.offsetWidth) {
winW = document.body.offsetWidth;
winH = document.body.offsetHeight;
}
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
winW = document.documentElement.offsetWidth;
winH = document.documentElement.offsetHeight;
}
if (window.innerWidth && window.innerHeight) {
winW = window.innerWidth;
winH = window.innerHeight;
}
}
works as described above: "...when it loads it does not load the styles (in Chrome). It does, however, load the styles on a refresh." If I run this second winSize function in the first script it returns the error "Cannot read property 'style' of null".
I prefer the first function for its brevity and (according to W3schools.com) better cross browser compatibility with object.scrollWidth over window.innerWidth, but clearly, one or both are broken in some context.
My questions are, in order of importance:
In the second script, how can I get the 'winSize' function to run after the images have fully loaded? (if that is the issue)
Why are the two scripts having such drastically different reactions to the two functions when implemented in the same way.
What would fix the first script that I presented--where the first content div, "gutters", is filling the entire screen rather than making a rectangle.
Why putting an onload event in the body tag works, but putting document.body.onload in the script of the head doesn't.
Sorry for such a long question--and so many questions in one, but I couldn't figure a way to untangle them. I would appreciate any help and forever praise those who can help me wrap my head around this.
why not just specify dimensions in % and let the browser do it.
May be you have some very specific requirement?
Please write the scenario, (in short)
I created a canvas element and I'm using javascript to make it as big as possible in the viewport, while maintaining the aspect ratio.
When you rotate the iPad, the device first rotates the page and only after that launches the resize event.
The problem is, if you come from landscape (about 800px wide) to portrait (about 400px), a part of the body is not being displayed, because the resize didn't happen yet at that moment. After this, the resize event resizes the canvas to the correct size, but then a part of the canvas (& document) is still outside the viewport.
So basically the problem exists because the resize event only launches after the iPad already cut off a part of the body on both sides because the body is too wide.
I could fix this by setting a margin to the canvas to compensate, but it's a dirty solution... does anyone have a better suggestion?
This could also be considered a dirty solution, but in the past I have used a setTimeout to deal with this issue, and it seems to always be reliable.
window.onorientationchange = function() {
canvasResize();
}
function canvasResize() {
window.setTimeout(function () {
//Your code here based on new size
}, 100);
}
Or if you are looking for a slightly less dirty solution, you should be able to just keep track of the viewport width yourself, and then wait until that changes to do your updates. Add to your script somewhere:
var viewportWidth = window.innerWidth;
And change canvasResize:
function canvasResize() {
if(window.innerWidth != viewportWidth) {//Dimensions have changed for sure
viewportWidth = window.innerWidth; //Update viewportWidth for future use
//Your code here based on new size
}
else {
//Delay and try again
window.setTimeout(function () {
canvasResize();
}, 100);
}
}
Both of are pretty quick and dirty, and I'd be interested if there's a more elegant solution, but I haven't found one yet.