{"id":4329,"date":"2012-01-16T22:03:30","date_gmt":"2012-01-17T02:03:30","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=4329"},"modified":"2012-01-16T22:04:52","modified_gmt":"2012-01-17T02:04:52","slug":"caching-images-with-javascript-and-html5-progress-bars","status":"publish","type":"post","link":"https:\/\/www.useragentman.com\/blog\/2012\/01\/16\/caching-images-with-javascript-and-html5-progress-bars\/","title":{"rendered":"Caching Images With JavaScript and HTML5 <code>progress<\/code> Bars"},"content":{"rendered":"<p><div id=\"attachment_4354\" style=\"width: 260px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/www.useragentman.com\/examples\/progress\/dnfmomd.html\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-4354\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2012\/01\/loading.jpg\" alt=\"\" title=\"loading\" width=\"250\" height=\"180\" class=\"size-full wp-image-4354\" \/><\/a><p id=\"caption-attachment-4354\" class=\"wp-caption-text\">Progress Bars can be used to show users how long it will be until a high-traffic page, like a photo gallery, fully loads.  Click on the image to see one in action. (Photos courtesy of Do Not Forsake Me Oh My Darling)<\/p><\/div> <strong>In my last article<\/strong>, <em><a href=\"https:\/\/www.useragentman.com\/blog\/2012\/01\/03\/cross-browser-html5-progress-bars-in-depth\/\" rel=\"prev\">Cross Browser HTML5 Progress Bars In Depth<\/a><\/em>, <strong>I discussed how to create progress bars<\/strong> and how to do fancy-pants CSS styling on them in all browsers.  Sure, it&#8217;s cool eye candy, <strong>but where would you use one?<\/strong>  I&#8217;m sure you have seen <strong>Flash sites that have a progress bars<\/strong> before (or what some of my designer friends call a &#8220;loader&#8221;), but just in case, <strong>take a look at the <a href=\"http:\/\/www.startrekmovie.com\/\">Star Trek Movie site<\/a> to see an example of one in the wild.<\/strong>  This loader tells the user how long it will take for the page to load and display. If this page takes a long time to load, <strong>a loader will prevent users from thinking the page is not loading properly<\/strong> and go someplace else. In most cases, these loaders show the percentage of assets have been loaded, and when it reaches 100%, the content is displayed.  This prevents images from appearing half loaded when the content is first shown.  While I wouldn&#8217;t want loaders for most HTML-based web sites, there are definitely times you would to want to do this, like when creating a full-screen slideshow. This article will show you how to make one easily.<\/p>\n\r\n<br \/><a href=\"https:\/\/www.useragentman.com\/examples\/progress\/dnfmomd.html\" class=\"exampleLink\">A Really Cool Photo Gallery Example of Image Caching With HTML5 <code>&lt;progress&gt;<\/code><\/a>\r\n<h2>Caching Images.<\/h2>\n<p><strong>Before we do anything, we need to know how to cache images.<\/strong>  Developers have been using the DOM Level 0 <code>Image()<\/code> object to cache images since almost the beginning of JavaScript&#8217;s history.  Basically it involves creating a new <code>Image()<\/code> object, and then setting the src to be URL of the image.<\/p>\n<blockquote class=\"code\">\n<pre>\r\nvar im = new Image();\r\nim.src = \"https:\/\/www.useragentman.com\/images\/zoltFront.jpg\";\r\n<\/pre>\n<\/blockquote>\n<p>Back in the 1990&#8217;s, this technique was used a lot to cache images involved in animation of hover states.  A good example of this is on the <a href=\"http:\/\/web.archive.org\/web\/19970715114207\/http:\/\/www.netcom.ca\/netcom\/about.html\">old Netcom Canada website circa 1997<\/a> (available today thanks to the magic of <a href=\"http:\/\/wayback.archive.org\/web\/\">The Way Back Machine<\/a>).  If you mouseover any of the navigation links in the header, you&#8217;ll see the image button change in appearance.  In order for this animation to happen as soon as the user hovers over the links, the page must cache all the hover-state images, so that the user doesn&#8217;t see any flicker on-hover as the image is loading.  Modern developers would use <a href=\"http:\/\/www.alistapart.com\/articles\/sprites\">CSS sprites<\/a> to do this, but back in the day, this was the only way to go.<\/p>\n<p>But how can one use this technique to update a progress bar?  The <code>Image()<\/code> object has a <code>load<\/code> event, so we can use that to increment a progress bar.  To simplify this process, I have created a very simple JavaScript library, <a href=\"https:\/\/github.com\/zoltan-dulac\/imageCache\">imageCache.js<\/a>, that will cache an array of image URLs and fire off two events: one when each image is loaded, and one where the whole array is loaded.  Image caching is as simple as this:<\/p>\n<blockquote class=\"code\">\n<pre>\r\nvar s=[\"images\/1.jpg\", \"images\/2.jpg\", \"images\/3.jpg\"];\r\n<span class=\"hilite\">imageCache.pushArray(s, <em>loadImageEvent<\/em>, <em>loadAllEvent<\/em>);<\/span>\r\n<\/pre>\n<\/blockquote>\n<p><code>loadImageEvent<\/code> is a callback that is called every time an image is loaded, and <code>loadAllEvent<\/code> is called when all of the images are loaded.<\/p>\n<p><a href=\"https:\/\/github.com\/zoltan-dulac\/imageCache\" class=\"exampleLink\">Download <code>imageCache.js<\/code> from GitHub.<\/a><\/p>\n<h2>Using <code>&lt;progress&gt;<\/code> to Show When Each Image Has Loaded<\/h2>\n<p>In the image gallery example at the beginning of this article, we have 28 images that we want to load into cache before showing the content of the page.  We also want a progress bar to show these images loading.  In order to do this, we need to make two containers: one that holds the progress bar and one that holds the content:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;-- The Progress Bar Container --&gt;\r\n&lt;div id=\"progressContainer\"&gt;\r\n    Loading: &lt;br \/&gt;\r\n    &lt;progress id=\"loader\" max=\"28\" value=\"0\"&gt;\r\n       &lt;strong&gt;Loaded &lt;span id=\"value\"&gt;0&lt;\/span&gt;\/28&lt;\/strong&gt;\r\n    &lt;\/progress&gt;\r\n&lt;\/div&gt;\r\n\r\n&lt;-- The Content Container --&gt;\r\n&lt;div id=\"content\"&gt;\r\n   &lt;!-- this should contain the content for the rest of the site --&gt;  \r\n&lt;\/div&gt;\r\n\r\n<\/pre>\n<\/blockquote>\n<p>You would then create a JavaScript snippit that would pre-cache all the images.  What follows is an example that uses jQuery to do this, but since <strong>the imageCache.js library itself doesn&#8217;t need jQuery<\/strong>, feel free to use any framework you like (or lack of framework if you are &#8220;<a href=\"http:\/\/www.penny-arcade.com\/comic\/2008\/03\/12\">Teh Hardcorez<\/a>&#8220;):<\/p>\n<blockquote class=\"code\">\n<pre>\r\nvar dnfmomd = new function () {\r\n   var me = this;\r\n   \r\n   var $loader,\r\n       currentImage = 0;\r\n   \r\n   \r\n   me.init = function () {\r\n      \r\n      var s = [];\r\n      \r\n      for (var i=1; i&lt;=28; i++) {\r\n         s.push('images\/dnfmomd\/' + i + '.jpg');\r\n      }\r\n      $loader = $('#loader');\r\n      \r\n      $loader.max = s.length;\r\n      imageCache.pushArray(s, <span class=\"hilite\">loadImageEvent<\/span>, <span class=\"hilite2\">loadAllEvent<\/span>);\r\n      \r\n   }\r\n\r\n<span class=\"hilite\">   function loadImageEvent() {\r\n      val = parseInt($loader.attr('value'));\r\n      val++;\r\n      $loader.attr('value', val);\r\n   }<\/span>\r\n   \r\n<span class=\"hilite2\">   function loadAllEvent() {\r\n      $('body').addClass('loaded');\r\n      showImage(1, true);\r\n   }<\/span>\r\n\r\n   ....\r\n\r\n}\r\n\r\n\/*\r\n *  Use $(window).load() instead of $(document).ready() because we wan't to start caching images\r\n *  as soon as the progress bar images are loaded.\r\n *\/\r\n\r\n$(window).load(dnfmomd.init)\r\n<\/pre>\n<\/blockquote>\n<p>Note that progress bar&#8217;s value is increased every time an image is loaded, and when all the images are loaded, we add the <code>loaded<\/code> class to the body.  This will result in the progress bar disappearing and the content becoming visible, due to this CSS in the page:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n  #content {\r\n     display: none;\r\n  }\r\n\r\n  body.loaded #content {\r\n     display: block;\r\n  }\r\n\r\n  body.loaded #progressContainer {\r\n     display: none !important;\r\n  }\r\n<\/pre>\n<\/blockquote>\n<h2>Can We Show Other Things Loading in the Progress Bar Besides Images?<\/h2>\n<p>It is possible to show CSS and JavaScript in the progress bar using <a href=\"http:\/\/yepnopejs.com\/\">yepnope.js<\/a>.  It is a little bit more involved, but very doable (I have done it before), and I leave it as an exercise to the reader to do it.  Post it below, and I&#8217;ll give you full geek-cred.  If no one does it, I will probably take some time and publish an example in a few weeks, but I thought it would be neat to offer up a little challenge. :-)<\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/01\/loading.jpg\" \/>HTML5 Progress Bars are cool, <strong>but where would you use one?<\/strong>  If you are have a page with a lot of images that are being animated, you may not want to the content to be visible until is all loaded into memory, so why not use a progress bar to show the load progression? This article will show how to <strong>make a simple slideshow with a progress bar<\/strong> that updates as images are loaded.  Proof that HTML5 progress bars are useful and not just a bunch of eye-candy with a fancy name.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4329","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/4329","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=4329"}],"version-history":[{"count":85,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/4329\/revisions"}],"predecessor-version":[{"id":4415,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/4329\/revisions\/4415"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=4329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=4329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=4329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}