Jquery Site Setup (Positioning) 2 of 4

Posted on Friday, May 2, 2014


This tutorial is going to be split into 4 sections.  The goal of this tutorial is to create a simple web site that has a top bar with a static Height, a left tool bar with a static width, and a variable "display area" which will take up the rest of the space.

This tutorial will start where the last tutorial finished were the problem
Of resizing on a window resize was not yet solved.




Output to console


Edit the JavaScript to write to the console.


> vi js/main.js


And update it the following



(function (window, undefined) {
  $(window).load(function () {
    setSizes()
  })

  $(window).resize(function () {
    console.log("(" + $(window).width() + ", "
           + $(window).height() + ")")
  })

  function setSizes() {
    $("#nav-display-area").height(
       $(window).height() - $("#nav-top").height() - 10)
       .width(
   $(window).width() - $("#nav-left-outer").width() - 10)
  }
})(this)



Open the console.

From google chrome you can use the hot key

Ctrl+shift+j


Or you can click on the menu and select Tools -> JavaScript Console





Now resize the screen a bit and you will see the console update its data





Here you can see the information scrolling by as you resize the window.

The resize event kicks off rather quickly.

In fact it kicks off too much.  The resize of the element sizes does not need to occur every millisecond but rather every 250 or 500 milliseconds is more than fast enough and reduces CPU usage.


Resize Elements to fit window size


To accomplish this you can use the JavaScript setTimeout function see http://www.w3schools.com/jsref/met_win_settimeout.asp [1] for more details.



Edit the JavaScript


> vi js/main.js


And update it the following



(function (window, undefined) {
  $(window).load(function () {
    setSizes()
  })

  var resizeTimer
  $(window).resize(function () {
    console.log("(" + $(window).width() + ", "
               + $(window).height() + ")")
    clearTimeout(resizeTimer)
    resizeTimer = setTimeout(function () {
        setSizes()
        console.log("Finish Resizing")
    }, 250)
  })

  function setSizes() {
    $("#nav-display-area").height(
       $(window).height() - $("#nav-top").height() - 10)
       .width($(window).width() -
        $("#nav-left-outer").width() - 10)
  }
})(this)


This will run the setSizes function 250 milliseconds after the last resize event occurs.


Reload the page and resize it




You will see that the display area resizes with the browser (almost perfectly)




Sometimes the bottom has this little gap, which is from the scrollbars







In the case of IE you see the gap on both sides.




To better see what is going on up the timeout to 5000 (5 seconds) and change the size of the window. 

When you shrink the window you will see the scroll bars appear.  These effectively reduce the $(window).height() and $(window).width().  As a result the setSizes function makes the div  fit within the scroll bars, which makes the scroll bars unnecessary and then they are removed leaving your div a little too small.








So…. What is a good way to fix this problem?


One way is to run setSizes twice if the browser window has been reduced (either its width or height).


Edit the JavaScript


> vi js/main.js


And update it the following


(function (window, undefined) {
  $(window).load(function () {
    setSizes()
  })

  var resizeTimer
  $(window).resize(function () {
    console.log("(" + $(window).width() + ", "
           + $(window).height() + ")")
    clearTimeout(resizeTimer)
    resizeTimer = setTimeout(function () {
        setSizes()
        console.log("Finish Resizing")
    }, 250)
  })

  function setSizes() {
    priorHeight = $("#nav-display-area").height()
    priorWidth = $("#nav-display-area").width()

    $("#nav-display-area").height(
       $(window).height() - $("#nav-top").height() - 10)
       .width($(window).width() -
   $("#nav-left-outer").width() - 10)

    if (priorHeight > $("#nav-display-area").height()
      || priorWidth > $("#nav-display-area").width()) {
        //Call setSizes again
        setSizes()
    }
  }
})(this)






That worked!





A better way is just to remove the scroll bars temporarily while you resize.


Edit the JavaScript


> vi js/main.js


And update it the following


(function (window, undefined) {
  $(window).load(function () {
    setSizes()
  })

  var resizeTimer
  $(window).resize(function () {
    console.log("(" + $(window).width() + ", "
           + $(window).height() + ")")
    clearTimeout(resizeTimer)
    resizeTimer = setTimeout(function () {
        setSizes()
        console.log("Finish Resizing")
    }, 250)
  })

  function setSizes() {
     $('body').css('overflow', 'hidden')
          //Temporarily remove the scroll bars

    $("#nav-display-area").height(
       $(window).height() - $("#nav-top").height() - 10)
       .width($(window).width() -
   $("#nav-left-outer").width() - 10)


    $('body').css('overflow', 'visible')
     //Make them visible again if need be

  }
})(this)







That worked!

And in a much simpler way



Another way, using CSS calc function


There is another way to do this using the CSS function calc http://www.w3.org/TR/css3-values/#calc [3]

If I turn off my javascript and edit my nav.css as follows



html, body {
margin: 0;
background-color:yellow;
}

#nav{
position:relative
background-color:red;
height:100%;
}

#nav-top{
position:absolute;
top:0px;
right:0px;
height:200px;
width:100%;
background-color:#f58a22;
z-index:2;
}

#nav-left-outer{
position:absolute;
top:0px;
left:0px;
width:200px;
height:100%;
background-color:#000000;
z-index:1;
}

#nav-left{
position:absolute;
top:200px;
left:0px;
background-color:#000000;
color:#FFFFFF;
}

#nav-display-area-outer{
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
background-color:#80dd77;
}

#nav-display-area{
position:absolute;
top:200px;
left:200px;
background-color:#80dd77;
border:solid 5px red;
width:calc(100% - 200px - 10px);
height:calc(100% - 200px - 10px);
}



Now reload the page and resize it.

You can see that this works just fine, however before you choose to use the calc CSS tool you should see how cross-browser friendly it is.





Firefox and chrome has supported it for some time, but IE only fully supported it in IE 10 and even safari in version 6.0



Using Underscore debounce function


Finally, I would like to go over a little clean up the setTimeout function clearTimeout seems a little long winded in this day and age.  The Underscore.js library http://underscorejs.org/ [1] provides a shorter way of doing this with the debounce functions


Download underscore.js


> cd js
> wget http://underscorejs.org/underscore.js
> cd ..


Now add it to the index.html


> vi index.html



<html>
<head>
<link rel="stylesheet" href="css/main.css" type="text/css"/>
</head>
<body>

<div id="nav">
  <div id="nav-top">
    <h1>This is the Top Area</h1>
  </div>
  <div id="nav-left-outer">
     <div id="nav-left">
        <h1>Side Area<br/><br/>Static Width</h1>
     </div>
  </div>
  <div id="nav-display-area-outer">
    <div id="nav-display-area">
        <h1>Resizeable Display Area</h1>
    </div>
  </div>
</div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="js/underscore.js"></script>
<script src="js/main.js"></script>

</body>
</html>






Edit main.js JavaScript to use it


> vi js/main.js


And edit it to the following



(function (window, undefined) {
  $(window).load(function () {
    setSizes()
  })

  $(window).resize(_.debounce(function () {
    setSizes()
  }, 250))

  function setSizes() {
    priorHeight = $("#nav-display-area").height()
    priorWidth = $("#nav-display-area").width()

    $("#nav-display-area").height(
       $(window).height() - $("#nav-top").height() - 10)
       .width($(window).width() -
              $("#nav-left-outer").width() - 10)

    console.log("(" + $(window).width() + ", "
              +  $(window).height() + ")")

    if (priorHeight > $("#nav-display-area").height()
      || priorWidth > $("#nav-display-area").width()) {
        //Call setSizes again
        setSizes()
    }
  }
})(this)




The debounce function makes code look a lot cleaner.


The resizable area is done and working, the next tutorial will go over using JQuery load function to add clickable buttons that will upload information to a div asynchronously.


The next tutorial can be found at
http://www.whiteboardcoder.com/2014/05/jquery-site-setup-positioning-3-of-4.html


References
[1]        W3C School setTimeout function
                Accessed 03/2014
[2]        Cross-browser window resize event - JavaScript / jQuery
                Accessed 03/2014
[3]        Cross-browser window resize event - JavaScript / jQuery
                Accessed 03/2014
[4]        Can I use calc() as CSS unit value?
            http://caniuse.com/calc  
                Accessed 03/2014


No comments:

Post a Comment