{"id":9,"date":"2012-04-04T15:22:38","date_gmt":"2012-04-04T15:22:38","guid":{"rendered":"http:\/\/www.vunet.us\/dev2\/?p=9"},"modified":"2012-04-04T15:22:38","modified_gmt":"2012-04-04T15:22:38","slug":"lazy-load-with-plain-javascript","status":"publish","type":"post","link":"https:\/\/dev.vunet.us\/index.php\/javascript\/lazy-load-with-plain-javascript\/","title":{"rendered":"Lazy Load with Plain JavaScript"},"content":{"rendered":"<p>I was looking for a solution to load a large number of images on one page.<br \/>\nThe problem, however, was the loading speed on a client side where 200-300<br \/>\nthumbnails would take forever to load in a browser.<\/p>\n<p>I did some research and found a few techniques such as &#8220;<strong>JavaScript Paging<\/strong>&#8221;\u00a0and &#8220;<strong>Lazy Load<\/strong>&#8221; to handle so many images on one page.<br \/>\nThe idea is not to load all of them at once. However, my favorite technique I chose &#8220;Lazy Load&#8221; required\u00a0some additional components like Prototype or JQuery libraries to be used.\u00a0With those third party frameworks, it is quite easy to implement the solution but more difficult<br \/>\nto customize and control the code. Moreover, the resources used by a client when loading heavy<br \/>\nlibraries, especially Prototype, to use a tiny bit of their code do not seem to be the best idea.<\/p>\n<p>So, I came up with my own &#8220;Lazy Load&#8221; solution which uses a few lines of plain old JavaScript.<br \/>\nThe demo of the <a title=\"Lazy Load with Plain JavaScript\" href=\"http:\/\/vunet.us\/demo\/lazyload\/\">Lazy Load<\/a><br \/>\nis here (<a href=\"http:\/\/vunet.us\/demo\/lazyload\/\">http:\/\/vunet.us\/demo\/lazyload\/<\/a>).<\/p>\n<p><strong>Code explanation<\/strong><\/p>\n<p>Let&#8217;s say we populate the global JavaScript array with image paths like this<br \/>\n<code><br \/>\nvar imgSrcMap = new Array();<br \/>\nimgSrcMap[0] = \"lazyloadimages\/N08422-1-lr-1.jpg\";<br \/>\nimgSrcMap[1] = \"lazyloadimages\/N08422-2-lr-1.jpg\";<br \/>\n<\/code><br \/>\nand so on&#8230; We can do it with any server side page in ASP or PHP looping through<br \/>\nall images in a folder or database.<\/p>\n<p>When the page is loaded, we initialize the function which draws all images but the source<br \/>\nof each image would be a tiny 1\u00d71 pixel image for every image we draw:<\/p>\n<p><code>var imageMap = new Array();<br \/>\nfunction loadImageTables(){<br \/>\nvar table = document.createElement(\"table\");<br \/>\nvar defaultCell = document.createElement(\"TD\");<br \/>\ndefaultCell.className = \"imageContainerCell\";<br \/>\ndefaultImg = document.createElement(\"img\");<br \/>\ndefaultImg.src=\"lazyloadimages\/grey.gif\";<br \/>\ndefaultImg.border = \"0\";<br \/>\ndefaultImg.width = \"80\";<br \/>\ndefaultImg.height = \"80\";<br \/>\ndefaultCell.appendChild(defaultImg);<br \/>\nfor(var i=0; i&lt;imgSrcMap.length;i++){<br \/>\nif(i==0||i%4==0){\/\/4 thumbs per row<br \/>\nvar row = table.insertRow(table.rows.length);<br \/>\n}<br \/>\nvar cell = defaultCell.cloneNode(true);<br \/>\ncell.onmouseover = hoverImgCell;<br \/>\ncell.onmouseout = outImgCell;<br \/>\nrow.appendChild(cell);<br \/>\nimageMap[i] = cell;\/\/store reference to image<br \/>\n}<br \/>\nvar container = document.getElementById(\"imageContainer\");<br \/>\nif(container){ container.appendChild(table); }<br \/>\ncheckImages();\/\/load initial viewport<br \/>\n}<br \/>\n<\/code><\/p>\n<p>In the code above I create a new array imageMap which stores the reference to the cell for quick access to image source swap (but this is later). To make things nicer I added <span style=\"color: maroon;\">onmouseover<\/span> and <span style=\"color: maroon;\">onmouseout<\/span> events to change the background color of the cell we are in. Feel free to ignore this functionality.<\/p>\n<p>The last function <span style=\"color: maroon;\">checkImages()<\/span> is where the soup is being cooked. It is invoked on load as we saw above and on window scrolling and resizing:<\/p>\n<p><code><br \/>\nwindow.onscroll = checkImages;<br \/>\nwindow.onresize = checkImages;<br \/>\n<\/code><\/p>\n<p>Finally, let&#8217;s take a close look at what the function is doing:<\/p>\n<p><code><br \/>\nfunction checkImages() {<br \/>\nvar viewportSize = document.body.scrollTop + document.body.clientHeight;<br \/>\nfor (var i = imageMap.length; i &gt; 0; i\u2013){<br \/>\nvar index = i-1;<br \/>\nvar el = imageMap[index];<br \/>\nif (viewportSize &gt; el.offsetTop){<br \/>\nloadImage(index);<br \/>\nimageMap.splice(index,1);\/\/delete to avoid looping over<br \/>\nimgSrcMap.splice(index,1);\/\/delete to match array above<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n<\/code><\/p>\n<p>First, we find the size of the Viewport (the distance from the very top of the page to the bottom of your browser including scrolled distance). Then we loop through <span style=\"color: maroon;\">imageMap<\/span> array to check if the cell is within the Viewport, i.e. visible on screen. If so, we must show the actual true source of the image which is done in this function:<\/p>\n<p><code><br \/>\nfunction loadImage(i) {<br \/>\nif(imageMap[i].firstChild.src != imgSrcMap[i]){<br \/>\nimageMap[i].firstChild.src = imgSrcMap[i];<br \/>\n}<br \/>\n}<br \/>\n<\/code><br \/>\nWe simply swap the old 1\u00d71 pixel with the real one. The true image is now loaded.<br \/>\nTo avoid looping through the same elements of array of images which are already loaded,<br \/>\nwe remove all loaded images from array as the last step in function <span style=\"color: maroon;\">checkImages()<\/span>.<\/p>\n<p>I hope this is helpful. Please check <a title=\"Lazy Load with Plain JavaScript\" href=\"http:\/\/vunet.us\/demo\/lazyload\/\">Lazy Load with Plain JavaScript demo page<\/a> and feel free to steal the code from there by viewing the page source.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was looking for a solution to load a large number of images on one page. The problem, however, was the loading speed on a client side where 200-300 thumbnails would take<\/p>\n<a class=\"moretag noptoppad\" href=\"https:\/\/dev.vunet.us\/index.php\/javascript\/lazy-load-with-plain-javascript\/\">Read More...<\/a>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-9","post","type-post","status-publish","format-standard","hentry","category-javascript"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/posts\/9","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/comments?post=9"}],"version-history":[{"count":1,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/posts\/9\/revisions"}],"predecessor-version":[{"id":10,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/posts\/9\/revisions\/10"}],"wp:attachment":[{"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/media?parent=9"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/categories?post=9"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.vunet.us\/index.php\/wp-json\/wp\/v2\/tags?post=9"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}