how to create a visual library of images in html5 canvas david cathue

Upload: aditya-kiran

Post on 04-Apr-2018

223 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    1/29

    How to Create a Visual Library of Images in HTML5 Canvas

    by David Catuhe

    As a user interface fan, I could not miss the opportunity to develop with HTML5 Canvas. It unlocks

    a whole new set of ways to visualize images and data on the web. In this tutorial, Ill walk you

    through how to create one for your site.

    Application overview

    Tools

    The HTML5 page

    Data gathering

    Cards loading & cache handling

    Cards display

    Mouse management

    State storage

    Animations

    Handling multi-devicesConclusion

    To go further

    Application overview

    We will produce an application that will let us display a Magic the Gathering (courtesy of

    www.wizards.com/Magic) cards collection. Users will be able to scroll and zoom using the mouse

    (like Bing Maps, for example).

    Note: Image and data visualization is hardware intensive. Learn aboutHTML5 hardware

    acceleration and why its important here.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    2/29

    You can see the final result here: http://bolaslenses.catuhe.com

    The project source files can be downloaded here: http://www.catuhe.com/msdn/bolaslenses.zip

    Cards are stored on Window s Azure Stor age and use the Azure Content Distribution Network(CDN : a service that deploys data near the final users) in order to achieve maximum performances.

    An ASP.NET service is used to return cards list (using JSON format).

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    3/29

    Tools

    To write our application, we will use Visual Studio 2010 SP1 with Web Standards Update. This

    extension adds IntelliSense support in HTML5 page (which is a really important thing ).

    So, our solution will contain an HTML5 page side by side with .js files (these files will contain

    JavaScript scripts). About debug, it is possible to set a breakpoint directly in the .js files under Visual

    Studio. Try using the F12 Developer tools in Internet Explorer 9.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    4/29

    Debug with Visual Studio 2010

    Debug with Internet Explorer 9 (F12/Developer bar)

    So, we have a modern developer environment with IntelliSense and debug support. Therefore,

    we are ready to start and first of all, we will write the HTML5 page.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    5/29

    The HTML5 page

    Our page will be built around an HTML5 canvas which will be used to draw the cards:

    1.2.3.4.5.Bolas Lenses6.7.

    8.

    9.

    10. 11. 12. 13. 14. Cards scanned by MWSHQ

    Team

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    6/29

    15. Magic the Gathering official site :

    16. http://www.wizards.com/Magic17. 18. 19. 20. 21.

    22. 23. Bolas Lenses24. 25. 26. 27. 28. 30. 31. Your browser does not support HTML5 canvas.32. 33. 34. 35. 36. Loading data...37. 38. 39. 40.

    41.

    42.

    43.

    44. 45.

    If we dissect this page, we can note that it is divided into two parts:

    The header part with the title, the logo and the special mentions The main part (section) holds the canvas and the tooltips that will display the status of the

    application. There is also a hidden image (backImage) used as source for not yet loaded

    cards.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    7/29

    To build the layout of the page, a style sheet (full.css) is applied. Style sheets are a mechanism used

    to change the tags styles (in HTML, a style defines the entire display options for a tag):

    1. html, body2. {3. height: 100%;4. }5.6. body7. {8. background-color: #888888;9. font-size: .85em;10. font-family: "Segoe UI, Trebuchet MS",Verdana,Helvetica,Sans-

    Serif;

    11. margin: 0;12. padding: 0;13. color: #696969;14. }15.16. a:link17. {18. color: #034af3;19. text-decoration: underline;20. }21.22. a:visited23. {24. color: #505abc;25. }26.27. a:hover28. {29. color: #1d60ff;30. text-decoration: none;31. }32.33. a:active34. {35. color: #12eb87;36.

    }

    37.38. header, footer, nav, section39. {40. display: block;41. }42.43. table

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    8/29

    44. {45. width: 100%;46. }47.48. header, #header49. {50. position: relative;51. margin-bottom: 0px;52. color: #000;53. padding: 0;54. }55.56. #title57. {58. font-weight: bold;59. color: #fff;60. border: none;61. font-size: 60px!important;62. vertical-align: middle;63. margin-left: 70px64. }65.66. #legal67. {68. text-align: right;69. color: white;70. font-size: 14px;71. width: 50%;72. position: absolute;73. top: 15px;74. right: 10px75. }76.77. #leftHeader78. {79. width: 50%;80. vertical-align: middle;81. }82.83. section84. {85. margin: 20px20px20px20px;86. }87.88. #mainCanvas{89. border: 4pxsolid#000000;90. }91.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    9/29

    92. #cardsCount93. {94. font-weight: bolder;95. font-size: 1.1em;96. }97.98. .tooltip99. {100. position: absolute;101. bottom: 5px;102. color: black;103. background-color: white;104. margin-right: auto;105. margin-left: auto;106. left: 35%;107. right: 35%;108. padding: 5px;109. width: 30%;110. text-align: center;111. border-radius: 10px;112. -webkit-border-radius: 10px;113. -moz-border-radius: 10px;114. box-shadow: 2px2px2px#333333;115. }116.117. #bolasLogo118. {119. width: 64px;120. height: 64px;121. }122.123. #pictureCell124. {125. float: left;126. width: 64px;127. margin: 5px5px5px5px;128. vertical-align: middle;129. }

    Thus, this sheet is responsible for setting up the following display:

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    10/29

    Style sheets are powerful tools that allow an infinite number of displays. However, they are

    sometimes complicated to setup (for example if a tag is affected by a class, an identifier and its

    container). To simplify this setup, the development bar of Internet Explorer 9 is particularly useful

    because we can use it to see styles hierarchy that is applied to a tag.

    For example lets take a look at the waitTexttooltip with the development bar. To do this, you must

    press F12 in Internet Explorer 9 and use the selector to choose the tooltip:

    Once the selection is done, we can see the styles hierarchy:

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    11/29

    Thus, we can see that our divreceived its styles from the bodytag and the .tooltipentry of the style

    sheet.

    With this tool, it becomes possible to see the effect of each style (which can be disabled). It is also

    possible to add new style on the fly.

    Another important point of this window is the ability to change the rendering mode of Internet

    Explorer 9. Indeed, we can test how, for example, Internet Explorer 8 will handle the same page. To

    do this, go to the [Browser mode] menu and select the engine of Internet Explorer 8. This change

    will especially impact our tooltip as it uses border-radius (rounded edge) and box-shadow that are

    features of CSS 3:

    Internet Explorer 9 Internet Explorer 8

    Our page provides a graceful degradationas it still works (with no annoying visual difference) when

    the browser does not support all the required technologies.

    Now that our interface is ready, we will take a look at the data source to retrieve the cards to

    display.

    Data gathering

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    12/29

    The server provides the cards list using JSON format on this URL:

    http://bolaslenses.catuhe.com/Home/ListOfCards/?colorString=0

    It takes one parameter (colorString) to select a specific color (0 = all).

    When developing with JavaScript, there is a good reflex to have (reflex also good in other languages

    too, but really important in JavaScript): one must ask whether what we want to develop has not

    been already done in an existing framework.

    Indeed, there is a multitude of open source projects around JavaScript. One of them isjQuery

    which provides a plethora of convenient services.

    Thus, in our case to connect to the URL of our server and get the cards list, we could go through a

    XmlHttpRequestand have fun to parse the returned JSON. Or we can use jQuery .

    So we will use the getJSONfunction which will take care of everything for us:

    1. function getListOfCards() {2. var url =

    "http://bolaslenses.catuhe.com/Home/ListOfCards/?jsoncallback=?";

    3. $.getJSON(url, { colorString: "0" }, function (data) {4. listOfCards = data;5. $("#cardsCount").text(listOfCards.length + " cards displayed");6. $("#waitText").slideToggle("fast");7. });8. }

    As we can see, our function stores the cards list in the listOfCardsvariable and calls two jQuery

    functions:

    textthat change the text of a tag slideTogglethat hides (or shows) a tag by animating its height

    The listOfCardslist contains objects whose format is:

    ID: unique identifier of the card Path: relative path of the card (without the extension)

    It should be noted that the URL of the server is called with the ?jsoncallback=? suffix. Indeed,

    Ajax calls are constrained in terms of security to connect only to the same address as the calling

    script. However, there is a solution called JSONP that will allow us to make a concerted call to the

    server (which of course must be aware of the operation). And fortunately, jQuery can handle it all

    alone by just adding the right suffix.

    Once we have our cards list, we can set up the pictures loading and caching.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    13/29

    Cards loading & cache handling

    The main trick of our application is to draw only the cards effectively visible on the screen. The

    display window is defined by a zoom level and an offset (x, y) in the overall system.

    1. var visuControl = { zoom : 0.25, offsetX : 0, offsetY : 0 };

    The overall system is defined by 14819 cards that are spread over 200 columns and 75 rows.

    Also, we must be aware that each card is available in three versions:

    High definition: 480x680 without compression (.jpg suffix) Medium definition: 240x340 with standard compression (.50.jpg suffix) Low definition: 120x170 with strong compression (.25.jpg suffix)

    Thus, depending on the zoom level, we will load the correct version to optimize networks transfer.

    To do this we will develop a function that will give an image for a given card. This function will be

    configured to download a certain level of quality. In addition it will be linked with lower quality level

    to return it if the card for the current level is not yet uploaded:

    1.function imageCache(substr, replacementCache) {2.var extension = substr;3.var backImage = document.getElementById("backImage");4.5.6.this.load = function (card) {

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    14/29

    7.var localCache = this;8.9.if (this[card.ID] != undefined)10. return;11.12. var img = new Image();13. localCache[card.ID] = { image: img, isLoaded: false };14. currentDownloads++;15.16. img.onload = function () {17. localCache[card.ID].isLoaded = true;18. currentDownloads--;19. };20.21. img.onerror = function() {22. currentDownloads--;23. };24.25. img.src = "http://az30809.vo.msecnd.net/" + card.Path + extension;26. };27.28. this.getReplacementFromLowerCache = function (card) {29. if (replacementCache == undefined)30. return backImage;31.32. return replacementCache.getImageForCard(card);33. };34.35. this.getImageForCard = function(card) {36. var img;37. if (this[card.ID] == undefined) {38. this.load(card);39.40. img = this.getReplacementFromLowerCache(card);41. }42. else {43. if (this[card.ID].isLoaded)44. img = this[card.ID].image;45. else46. img = this.getReplacementFromLowerCache(card);47. }48.49. return img;50. };51. }

    An ImageCacheis built by giving the associated suffix and the underlying cache.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    15/29

    Here you can see two important functions:

    load: this function will load the right picture and will store it in a cache (the msecnd.neturl isthe Azure CDN address of the cards)

    getImageForCard: this function returns the card picture from the cache if already loaded.Otherwise it requests the underlying cache to return its version (and so on)

    So to handle our 3 levels of caches, we have to declare three variables:

    1. var imagesCache25 = new imageCache(".25.jpg");2. var imagesCache50 = new imageCache(".50.jpg", imagesCache25);3. var imagesCacheFull = new imageCache(".jpg", imagesCache50);

    Selecting the right cover is only depending on zoom:

    1.function getCorrectImageCache() {2.if (visuControl.zoom

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    16/29

    Again we note the use of jQuery to simplify animations.

    We will now discuss the display of cards.

    Cards display

    To draw our cards, we need to actually fill the canvas using its 2D context (which exists only if the

    browser supports HTML5 canvas):

    1. var mainCanvas = document.getElementById("mainCanvas");2. var drawingContext = mainCanvas.getContext('2d');

    The drawing will be made byprocessListOfCardsfunction (called 60 times per second):

    1.function processListOfCards() {2.3.if (listOfCards == undefined) {4.drawWaitMessage();5.return;6.}7.8.mainCanvas.width = document.getElementById("center").clientWidth;9.mainCanvas.height = document.getElementById("center").clientHeight;10. totalCards = listOfCards.length;11.12. var localCardWidth = cardWidth * visuControl.zoom;13. var localCardHeight = cardHeight * visuControl.zoom;14.15. var effectiveTotalCardsInWidth = colsCount * localCardWidth;16.17. var rowsCount = Math.ceil(totalCards / colsCount);18. var effectiveTotalCardsInHeight = rowsCount * localCardHeight;19.20. initialX = (mainCanvas.width - effectiveTotalCardsInWidth) / 2.0

    - localCardWidth / 2.0;

    21. initialY = (mainCanvas.height - effectiveTotalCardsInHeight) /2.0 - localCardHeight / 2.0;

    22.23. // Clear24. clearCanvas();25.26. // Computing of the viewing area27. var initialOffsetX = initialX + visuControl.offsetX *

    visuControl.zoom;

    28. var initialOffsetY = initialY + visuControl.offsetY *visuControl.zoom;

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    17/29

    29.30. var startX = Math.max(Math.floor(-initialOffsetX / localCardWidth)

    - 1, 0);

    31. var startY = Math.max(Math.floor(-initialOffsetY /localCardHeight) - 1, 0);

    32.33. var endX = Math.min(startX + Math.floor((mainCanvas.width -

    initialOffsetX - startX * localCardWidth) / localCardWidth) + 1,

    colsCount);

    34. var endY = Math.min(startY + Math.floor((mainCanvas.height -initialOffsetY - startY * localCardHeight) / localCardHeight) + 1,

    rowsCount);

    35.36. // Getting current cache37. var imageCache = getCorrectImageCache();38.39. // Render40. for (var y = startY; y < endY; y++) {41. for (var x = startX; x < endX; x++) {42. var localX = x * localCardWidth + initialOffsetX;43. var localY = y * localCardHeight + initialOffsetY;44.45. // Clip46. if (localX > mainCanvas.width)47. continue;48.49. if (localY > mainCanvas.height)50. continue;51.52. if (localX + localCardWidth < 0)53. continue;54.55. if (localY + localCardHeight < 0)56. continue;57.58. var card = listOfCards[x + y * colsCount];59.60. if (card == undefined)61. continue;62.63. // Get from cache64. var img = imageCache.getImageForCard(card);65.66. // Render67. try {68.69. if (img != undefined)

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    18/29

    70. drawingContext.drawImage(img, localX, localY, localCardWidth,localCardHeight);

    71. } catch (e) {72. $.grep(listOfCards, function (item) {73. return item.image != img;74. });75.76. }77. }78. };79.80. // Scroll bars81. drawScrollBars(effectiveTotalCardsInWidth,

    effectiveTotalCardsInHeight, initialOffsetX, initialOffsetY);

    82.83. // FPS84. computeFPS();85. }

    This function is built around many key points:

    If the cards list is not yet loaded, we display a tooltip indicating that download is in progress::1.var pointCount = 0;2.3.function drawWaitMessage() {4.pointCount++;5.6.if (pointCount > 200)7.pointCount = 0;8.9.var points = "";10.11. for (var index = 0; index < pointCount / 10; index++)12. points += ".";13.14. $("#waitText").html("Loading...Please wait
    " + points);15. } Subsequently, we define the position of the display window (in terms of cards andcoordinates), then we proceed to clean the canvas:

    1. function clearCanvas() {2. mainCanvas.width = document.body.clientWidth - 50;3. mainCanvas.height = document.body.clientHeight - 140;4.5. drawingContext.fillStyle = "rgb(0, 0, 0)";

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    19/29

    6. drawingContext.fillRect(0, 0, mainCanvas.width, mainCanvas.height);7. }

    Then we browse the cards list and call the drawImagefunction of the canvas context. Thecurrent image is provided by the active cache (depending on the zoom):

    1.// Get from cache2.var img = imageCache.getImageForCard(card);3.4.// Render5.try {6.7.if (img != undefined)8.drawingContext.drawImage(img, localX, localY, localCardWidth,

    localCardHeight);

    9.} catch (e) {10. $.grep(listOfCards, function (item) {11. return item.image != img;12. }); We also have to draw the scroll bar with the RoundedRectangle function that uses quadratic

    curves:

    1.function roundedRectangle(x, y, width, height, radius) {2.drawingContext.beginPath();3.drawingContext.moveTo(x + radius, y);4.drawingContext.lineTo(x + width - radius, y);5.drawingContext.quadraticCurveTo(x + width, y, x + width, y + radius);6.drawingContext.lineTo(x + width, y + height - radius);7.drawingContext.quadraticCurveTo(x + width, y + height, x + width -

    radius, y + height);

    8.drawingContext.lineTo(x + radius, y + height);9.drawingContext.quadraticCurveTo(x, y + height, x, y + height - radius);10. drawingContext.lineTo(x, y + radius);11. drawingContext.quadraticCurveTo(x, y, x + radius, y);12. drawingContext.closePath();13. drawingContext.stroke();14. drawingContext.fill();15. }1.function drawScrollBars(effectiveTotalCardsInWidth,

    effectiveTotalCardsInHeight, initialOffsetX, initialOffsetY) {

    2.drawingContext.fillStyle = "rgba(255, 255, 255, 0.6)";3.drawingContext.lineWidth = 2;4.5.// Vertical6.var totalScrollHeight = effectiveTotalCardsInHeight + mainCanvas.height;

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    20/29

    7.var scaleHeight = mainCanvas.height - 20;8.var scrollHeight = mainCanvas.height / totalScrollHeight;9.var scrollStartY = (-initialOffsetY + mainCanvas.height * 0.5) /

    totalScrollHeight;

    10. roundedRectangle(mainCanvas.width - 8, scrollStartY * scaleHeight+ 10, 5, scrollHeight * scaleHeight, 4);

    11.12. // Horizontal13. var totalScrollWidth = effectiveTotalCardsInWidth +

    mainCanvas.width;

    14. var scaleWidth = mainCanvas.width - 20;15. var scrollWidth = mainCanvas.width / totalScrollWidth;16. var scrollStartX = (-initialOffsetX + mainCanvas.width * 0.5) /

    totalScrollWidth;

    17. roundedRectangle(scrollStartX * scaleWidth + 10,mainCanvas.height - 8, scrollWidth * scaleWidth, 5, 4);

    18. }And finally, we need to compute the number of frames per second:1.function computeFPS() {2.if (previous.length > 60) {3.previous.splice(0, 1);4.}5.var start = (new Date).getTime();6.previous.push(start);7.var sum = 0;8.9.for (var id = 0; id < previous.length - 1; id++) {10. sum += previous[id + 1] - previous[id];11. }12.13. var diff = 1000.0 / (sum / previous.length);14.15. $("#cardsCount").text(diff.toFixed() + " fps. " +

    listOfCards.length + " cards displayed");

    16. }Drawing cards relies heavily on the browser's ability to speed up canvas rendering. For the record,

    here are the performances on my machine with the minimum zoom level (0.05):

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    21/29

    Browser FPS

    Internet Explorer 9 30

    Firefox 5 30

    Chrome 12 17

    iPad (with a zoom level of 0.8) 7

    Windows Phone Mango (with a zoom level of 0.8) 20 (!!)

    The site even works on mobile phones and tablets as long as they support HTML5.

    Here we can see the inner power of HTML5 browsers that can handle a full screen of cards more

    than 30 times per second! This is possible through hardware acceleration.

    Mouse management

    To browse our cards collection, we have to manage the mouse (including its wheel).

    For the scrolling, we'll just handle the onmouvemove, onmouseupand onmousedownevents.

    Onmouseupand onmousedownevents will be used to detect if the mouse is clicked or not:

    1.var mouseDown = 0;2.document.body.onmousedown = function (e) {3.mouseDown = 1;

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    22/29

    4.getMousePosition(e);5.6.previousX = posx;7.previousY = posy;8.};9.10. document.body.onmouseup = function () {11. mouseDown = 0;12. };

    The onmousemoveevent is connected to the canvas and used to move the view:

    1.var previousX = 0;2.var previousY = 0;3.var posx = 0;4.var posy = 0;5.6.function getMousePosition(eventArgs) {7.var e;8.9.if (!eventArgs)10. e = window.event;11. else {12. e = eventArgs;13. }14.15. if (e.offsetX || e.offsetY) {16. posx = e.offsetX;17. posy = e.offsetY;18. }19. elseif (e.clientX || e.clientY) {20. posx = e.clientX;21. posy = e.clientY;22. }23. }24.25. function onMouseMove(e) {26. if (!mouseDown)27. return;28.

    getMousePosition(e);

    29.30. mouseMoveFunc(posx, posy, previousX, previousY);31.32. previousX = posx;33. previousY = posy;34. }

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    23/29

    This function (onMouseMove) calculates the current position and provides also the previous value in

    order to move the offset of the display window:

    1. function Move(posx, posy, previousX, previousY) {2. currentAddX = (posx - previousX) / visuControl.zoom;3. currentAddY = (posy - previousY) / visuControl.zoom;4. }5. MouseHelper.registerMouseMove(mainCanvas, Move);

    Note that jQuery also provides tools to manage mouse events.

    For the management of the wheel, we will have to adapt to different browsers that do not behave

    the same way on this point:

    1.function wheel(event) {2.var delta = 0;3.if (event.wheelDelta) {4.delta = event.wheelDelta / 120;5.if (window.opera)6.delta = -delta;7.} elseif (event.detail) { /** Mozilla case. */8.delta = -event.detail / 3;9.}10. if (delta) {11. wheelFunc(delta);12. }13.14. if (event.preventDefault)15. event.preventDefault();16. event.returnValue = false;17. }

    We can see that everyone does what he wants .

    The function to register with this event is:

    1. MouseHelper.registerWheel = function (func) {2. wheelFunc = func;3.4. if (window.addEventListener)5. window.addEventListener('DOMMouseScroll', wheel, false);6.7. window.onmousewheel = document.onmousewheel = wheel;8. };

    And we will use this function to change the zoom with the wheel:

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    24/29

    1. // Mouse2. MouseHelper.registerWheel(function (delta) {3. currentAddZoom += delta / 500.0;4. });

    Finally we will add a bit of inertia when moving the mouse (and the zoom) to give some kind ofsmoothness:

    1.// Inertia2.var inertia = 0.92;3.var currentAddX = 0;4.var currentAddY = 0;5.var currentAddZoom = 0;6.7.function doInertia() {8.visuControl.offsetX += currentAddX;9.visuControl.offsetY += currentAddY;10. visuControl.zoom += currentAddZoom;11.12. var effectiveTotalCardsInWidth = colsCount * cardWidth;13.14. var rowsCount = Math.ceil(totalCards / colsCount);15. var effectiveTotalCardsInHeight = rowsCount * cardHeight16.17. var maxOffsetX = effectiveTotalCardsInWidth / 2.0;18. var maxOffsetY = effectiveTotalCardsInHeight / 2.0;19.20. if (visuControl.offsetX < -maxOffsetX + cardWidth)21. visuControl.offsetX = -maxOffsetX + cardWidth;22. elseif (visuControl.offsetX > maxOffsetX)23. visuControl.offsetX = maxOffsetX;24.25. if (visuControl.offsetY < -maxOffsetY + cardHeight)26. visuControl.offsetY = -maxOffsetY + cardHeight;27. elseif (visuControl.offsetY > maxOffsetY)28. visuControl.offsetY = maxOffsetY;29.30. if (visuControl.zoom < 0.05)31. visuControl.zoom = 0.05;32.

    elseif (visuControl.zoom > 1)

    33. visuControl.zoom = 1;34.35. processListOfCards();36.37. currentAddX *= inertia;38. currentAddY *= inertia;39. currentAddZoom *= inertia;

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    25/29

    40.41. // Epsilon42. if (Math.abs(currentAddX) < 0.001)43. currentAddX = 0;44. if (Math.abs(currentAddY) < 0.001)45. currentAddY = 0;46. }

    This kind of small function does not cost a lot to implement, but adds a lot to the quality of user

    experience.

    State storage

    Also to provide a better user experience, we will save the display windows position and zoom. To do

    this, we will use the service oflocalStorage (which saves pairs of keys / values for the long term

    (the data is retained after the browser is closed) and only accessible by the current window object):

    1.function saveConfig() {2.if (window.localStorage == undefined)3.return;4.5.// Zoom6.window.localStorage["zoom"] = visuControl.zoom;7.8.// Offsets9.window.localStorage["offsetX"] = visuControl.offsetX;10. window.localStorage["offsetY"] = visuControl.offsetY;11. }12.13. // Restore data14. if (window.localStorage != undefined) {15. var storedZoom = window.localStorage["zoom"];16. if (storedZoom != undefined)17. visuControl.zoom = parseFloat(storedZoom);18.19. var storedoffsetX = window.localStorage["offsetX"];20. if (storedoffsetX != undefined)21. visuControl.offsetX = parseFloat(storedoffsetX);22.23. var storedoffsetY = window.localStorage["offsetY"];24. if (storedoffsetY != undefined)25. visuControl.offsetY = parseFloat(storedoffsetY);26. }

    Animations

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    26/29

    To add even more dynamism to our application we will allow our users to double-click on a card to

    zoom and focus on it.

    Our system should animate three values: the two offsets (X, Y) and the zoom. To do this, we will

    use a function that will be responsible of animating a variable from a source value to a destination

    value with a given duration:

    1.var AnimationHelper = function (root, name) {2.var paramName = name;3.this.animate = function (current, to, duration) {4.var offset = (to - current);5.var ticks = Math.floor(duration / 16);6.var offsetPart = offset / ticks;7.var ticksCount = 0;8.9.var intervalID = setInterval(function () {10. current += offsetPart;11. root[paramName] = current;12. ticksCount++;13.14. if (ticksCount == ticks) {15. clearInterval(intervalID);16. root[paramName] = to;17. }18. }, 16);19. };20. };

    The use of this function is:

    1. // Prepare animations parameters2. var zoomAnimationHelper = new AnimationHelper(visuControl, "zoom");3. var offsetXAnimationHelper = new AnimationHelper(visuControl, "offsetX");4. var offsetYAnimationHelper = new AnimationHelper(visuControl, "offsetY");5. var speed = 1.1 - visuControl.zoom;6. zoomAnimationHelper.animate(visuControl.zoom, 1.0, 1000 * speed);7. offsetXAnimationHelper.animate(visuControl.offsetX, targetOffsetX, 1000

    * speed);

    8. offsetYAnimationHelper.animate(visuControl.offsetY, targetOffsetY, 1000* speed);

    The advantage of theAnimationHelperfunction is that it is able to animate as many parameters as

    you wish (and that only with the setTimerfunction!)

    Handling multi-devices

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    27/29

    Finally we will ensure that our page can also be seen on tablets PC and even on phones.

    To do this, we will use a feature of CSS 3: The media-queries. With this technology, we can apply

    style sheets according to some queries such as a specific display size:

    1. 2.

    3.

    Here we see that if the screen width is less than 480 pixels, the following style sheet will be added:

    1.#legal2.{3.font-size: 8px;4.}5.6.#title7.{8.font-size: 30px!important;9.}10.11. #waitText12. {13. font-size: 12px;14. }15.16. #bolasLogo17. {18. width: 48px;19. height: 48px;20. }21.22. #pictureCell23. {24. width: 48px;25. }

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    28/29

    This sheet will reduce the size of the header to keep the site viewable even when the browser width

    is less than 480 pixels (for example, on a Windows Phone):

    ConclusionHTML5 / CSS 3 / JavaScrip t and Visual Studio 2010 allow to develop portable and efficient

    solutions (within the limits of browsers that support HTML5 of course) with some great features

    such as hardware accelerated rendering.

    This kind of development is also simplified by the use of frameworks like jQuery.

  • 7/29/2019 How to Create a Visual Library of Images in HTML5 Canvas David Cathue

    29/29

    Also, I am especially fan of JavaScript that turns out to be a very powerful dynamic language. Of

    course, C# or VB.NET developers have to change theirs reflexes but for the development of web

    pages it's worth.

    In conclusion, I think that the best to be convinced is to try!

    To go further

    Learn about Hardware Acceleration F12 Developer Tools in Internet Explorer 9 and 10 Internet Explorer 10 Platform Previews Internet Explorer 9 Developer Guide W3C site for HTML5

    AbouttheAuthor

    David Catuhe is a developer evangelist for Microsoft France in charge of user experience developmenttools (from XAML to DirectX/XNA and HTML5). He defines himself as a geek and likes coding all that refer

    to graphics. Before working for Microsoft, he founded a company that developed a realtime 3D engine

    written with DirectX (www.vertice.fr)."