{"id":1144,"date":"2018-04-28T13:00:31","date_gmt":"2018-04-28T12:00:31","guid":{"rendered":"http:\/\/chewett.co.uk\/blog\/?p=1144"},"modified":"2018-04-30T01:01:25","modified_gmt":"2018-04-30T00:01:25","slug":"creating-a-loading-progress-bar-animation-with-html5-canvas","status":"publish","type":"post","link":"https:\/\/chewett.co.uk\/blog\/1144\/creating-a-loading-progress-bar-animation-with-html5-canvas\/","title":{"rendered":"Creating a loading progress bar animation with HTML5 Canvas"},"content":{"rendered":"<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1149\" data-permalink=\"https:\/\/chewett.co.uk\/blog\/1144\/creating-a-loading-progress-bar-animation-with-html5-canvas\/animated_canvas_html5\/\" data-orig-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?fit=800%2C300&amp;ssl=1\" data-orig-size=\"800,300\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"animated_canvas_html5\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?fit=300%2C113&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?fit=678%2C254&amp;ssl=1\" class=\"aligncenter size-full wp-image-1149\" src=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?resize=678%2C254\" alt=\"\" width=\"678\" height=\"254\" srcset=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?w=800&amp;ssl=1 800w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?resize=300%2C113&amp;ssl=1 300w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?resize=768%2C288&amp;ssl=1 768w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/animated_canvas_html5.jpg?resize=50%2C19&amp;ssl=1 50w\" sizes=\"auto, (max-width: 678px) 100vw, 678px\" \/><\/p>\n<p>In this HTML5 canvas example I create a simple loading progress bar demonstrating how you can use animation in a canvas.<\/p>\n<p><!--more--><\/p>\n<h2>Creating an animation function<\/h2>\n<p>Like all animation, the HTML5 canvas can create moving images by rapidly changing the image you are viewing. This is done by having a function that will be called between 30 to 60 times a second. I will be using this to quickly draw a picture to make it look like its a continuously changing picture.<\/p>\n<p>In most browsers there is a useful function which takes a callback called <code>window.requestAnimationFrame<\/code>. This function tells the browser that you want to call a specific function before the next repaint. This is typically capped at 60 frames a second but might be lower if your code is executing in the background.<\/p>\n<p>The animation function I will be using to draw my\u00a0progress bar is as follows<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">window.requestForAnimation = (function(callback) {\r\n    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||\r\n        function(callback) {\r\n            window.setTimeout(callback, 1000 \/ 60);\r\n        };\r\n})();<\/pre>\n<p>Since this might not be supported by all browsers we also use the above code to attempt to find this method\u00a0or methods like it. If all fails and no browser-specific methods are available we fall back to a simple callback that runs after 1\/60th of a second. This means that if the browser doesn&#8217;t support <code>requestAnimationFrame<\/code>\u00a0then we just call the animation using the basic <code>setTimeout<\/code> function. Depending on the level of browser support you want to target you could probably fall back to calling <code>requestAnimationFrame<\/code>\u00a0directly but it is entirely up to your implementation.<\/p>\n<h2>Creating my draw function for the Progress bar<\/h2>\n<p>Now I have my animation function I am going to create a draw function. This will take the percentage to draw as a parameter and draw that percentage on the canvas.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">var canvas = document.getElementById(&quot;mainCanvas&quot;);\r\nvar context = canvas.getContext(&quot;2d&quot;);\r\ncontext.fillStyle = &quot;black&quot;;\r\ncontext.font = &quot;20px Arial&quot;;\r\ncontext.lineWidth = 10;<\/pre>\n<p>First I have to set up the canvas as above. Here I get the context and set up the fillStyle and lineWidth (used for the arc), and the font of the progress text. This won&#8217;t\u00a0change throughout the example so I don&#8217;t\u00a0need to set this in the function.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">function drawPercentage(percentage) {\r\n    \/\/Clear the screen\r\n    context.clearRect(0, 0, canvas.width, canvas.height);\r\n\r\n    \/\/Draw some text\r\n    context.fillText(percentage + &quot;%&quot;, 40, 65);\r\n\r\n    \/\/Draw a circle\r\n    context.beginPath();\r\n\r\n    \/\/arcs start middle right of the circle so we tell it to start at Math.PI *0.5 which is the middle bottom\r\n    var arcPercent = 0.5 + (2 * ( percentage \/ 100));\r\n    context.arc(60, 60, 50, 0.5 * Math.PI, arcPercent*Math.PI);\r\n    context.stroke();\r\n}<\/pre>\n<p>The first thing I do in my draw function is clear the canvas. This is because\u00a0each time you draw it does not remove the old images on the canvas. Once cleared I draw the percentage on the screen with <code>fillText<\/code>, specifying the text and the x and y position on the screen.<\/p>\n<p>Here I am hardcoding the location of the text but in a later tutorial, I will improve how I place the text.<\/p>\n<p>To draw the circle I start a new path with <code>beginPath<\/code>. Once this has been done I can start to work out how far the arc needs to be drawn.<\/p>\n<p>All arcs start from the middle right hand side of a circle, the east side, this represents 0 on the arc. Since I want to start from the bottom southern side I need to start my arc using\u00a0<code>0.5 * Math.PI<\/code>. This is using radians to specify the angle to start at.<\/p>\n<p>I calculate the finish at using the formulae <code>0.5 + (2 * ( percentage \/ 100))<\/code>. This calculates a value from 0.5 to 2.5 depending on the percentage which I then use this calculated value multiplied by <code>Math.PI<\/code>\u00a0as the final angle.<\/p>\n<p>Once I have created the arc I finish off the drawing by calling <code>stroke<\/code> to create the line.<\/p>\n<h2>Animating the progress bar<\/h2>\n<p>Now I have a function to draw the progress bar I can start animating it. The animation function will use two variables to keep track of how long the animation has been running and what the current percentage shown is.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">var animationStart = Date.now();\r\nvar currentPercentage = -1;<\/pre>\n<p>The time that the animation started will be used in the function to work out what percentage the animation should be at when the animate function is called. This is important because the animation function will be called when the browser is able to perform an animation call. Most of the time this will be roughly the same period of time but it is open to the browser.<\/p>\n<p>So instead of assuming each time it is called a similar amount of time has passed we keep track of when the animation started to work out what the canvas should show.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">function animateNextFrame() {\r\n    var thisPercentage = Math.floor(((Date.now() - animationStart) \/ 50));\r\n    if(thisPercentage &gt; 100) {\r\n        thisPercentage = 100;\r\n    }\r\n\r\n    if(thisPercentage !== currentPercentage) {\r\n        drawPercentage(thisPercentage);\r\n        currentPercentage = thisPercentage;\r\n    }\r\n\r\n    \/\/Only request more animation until we have reached 100%\r\n    if(thisPercentage &lt; 100) {\r\n        requestForAnimation(animateNextFrame);\r\n    }\r\n}<\/pre>\n<p>The first thing that the animation function does is use the animation start time to work out what percentage should be shown. Here I use the current time minus the start time of the animation divided by 50 (20 percentage\u00a0points increase every second).<\/p>\n<p>The next check is important and sets the percentage to 100 if it is above 100. This handles that the event that the animation call was delayed and the new percentage is larger than 100.<\/p>\n<p>Then if the current percentage is different from the currently animated percentage we draw the new percentage and update what we have currently drawn.<\/p>\n<p>Now this has been drawn (or not drawn if it hasn&#8217;t reached a new percentage) we request a new animation frame if we haven&#8217;t drawn the last percentage (100). If we have drawn the 100th percentage image then we no longer need to call the animation frame. This means that as soon as the final frame has been animated we have no further overhead.<\/p>\n<p>Now we have our animated progress bar.<\/p>\n<h2>Conclusions on animating a progress bar<\/h2>\n<p>One important piece of information to note is that you have to consider that the animation function may not be called at even time intervals. Since it depends on the browser having time to execute the callback it is likely to be different time periods each call. Therefore we must handle drawing the animation based on how long has passed from the start which may involve skipping frames.<\/p>\n<p>The example including the source code is\u00a0<a href=\"http:\/\/chewett.co.uk\/html5_canvas\/loading_progress_animation\/\">available on my website<\/a>.<\/p>\n<p>If you have any questions or wish to learn more leave a comment below and I will endeavour to answer any questions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this HTML5 canvas example I create a simple loading progress bar demonstrating how you can use animation in a canvas.<\/p>\n","protected":false},"author":1,"featured_media":1151,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Today I wrote about creating a loading progress bar animation with #HTML5 #Canvas","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[98],"tags":[154,155,72,256],"class_list":["post-1144","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software","tag-html5","tag-html5-canvas","tag-javascript","tag-tutorial"],"wppr_data":{"cwp_meta_box_check":"No"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/loading_progress_bar_animation_html5.jpg?fit=800%2C800&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p2toWX-is","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1166,"url":"https:\/\/chewett.co.uk\/blog\/1166\/better-positioning-of-text-using-measuretext-with-html5-canvas\/","url_meta":{"origin":1144,"position":0},"title":"Better positioning of text using measureText with HTML5 Canvas","author":"Chewett","date":"May 5, 2018","format":false,"excerpt":"In this tutorial I am extending the previous animation example by better positioning the text using measureText with the HTML5 canvas. The problem with positioning text When positioning\u00a0text you will sometimes want to know the width and height so that you can centre it on the canvas. However this isn't\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/measure_text_html5_canvas.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/measure_text_html5_canvas.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/measure_text_html5_canvas.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/measure_text_html5_canvas.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":667,"url":"https:\/\/chewett.co.uk\/blog\/667\/html5-canvas-drawing-tutorial-basic-shapes\/","url_meta":{"origin":1144,"position":1},"title":"HTML5 Canvas Drawing Tutorial &#8211; Basic Shapes","author":"Chewett","date":"September 27, 2017","format":false,"excerpt":"This post is the first in a series of blog posts where I explore the HTML5 canvas. This first tutorial looks at creating the basic elements required to draw on a canvas and drawing some basic shapes. Creating and styling the canvas The first step to creating an HTML5 canvas\u2026","rel":"","context":"In &quot;Informational&quot;","block_context":{"text":"Informational","link":"https:\/\/chewett.co.uk\/blog\/category\/informational\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2017\/09\/html5_canvas_basic_shapes.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2017\/09\/html5_canvas_basic_shapes.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2017\/09\/html5_canvas_basic_shapes.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2017\/09\/html5_canvas_basic_shapes.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1130,"url":"https:\/\/chewett.co.uk\/blog\/1130\/new-html5-canvas-experiments-and-tutorials-section-of-my-website\/","url_meta":{"origin":1144,"position":2},"title":"New HTML5 Canvas Experiments and tutorials section of my website","author":"Chewett","date":"April 21, 2018","format":false,"excerpt":"This post talks about the new HTML5 Canvas part of my website and what I plan to do with it. The new page on my website! I have added a link on the\u00a0homepage of my website\u00a0to the\u00a0new HTML5 canvas experiments and tutorials section. Here you will be able to view\u2026","rel":"","context":"In &quot;Informational&quot;","block_context":{"text":"Informational","link":"https:\/\/chewett.co.uk\/blog\/category\/informational\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/new_html5_canvas_part_of_website.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/new_html5_canvas_part_of_website.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/new_html5_canvas_part_of_website.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/04\/new_html5_canvas_part_of_website.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1186,"url":"https:\/\/chewett.co.uk\/blog\/1186\/exploring-the-many-method-parameters-of-drawimage-with-html5-canvas\/","url_meta":{"origin":1144,"position":3},"title":"Exploring the many method parameters of drawImage with HTML5 Canvas","author":"Chewett","date":"May 30, 2018","format":false,"excerpt":"In this post I look at the different method parameters that can be used with drawImage and what they are useful for. Whats the use for different parameters of drawImage The context drawImage function allows for creating more complex canvas scenes by allowing you to draw different images at various\u2026","rel":"","context":"In &quot;Informational&quot;","block_context":{"text":"Informational","link":"https:\/\/chewett.co.uk\/blog\/category\/informational\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/06\/drawImage_methods.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/06\/drawImage_methods.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/06\/drawImage_methods.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/06\/drawImage_methods.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1177,"url":"https:\/\/chewett.co.uk\/blog\/1177\/scaling-sprites-for-pixel-art-with-html5-canvas\/","url_meta":{"origin":1144,"position":4},"title":"Scaling Sprites for Pixel Art with HTML5 Canvas","author":"Chewett","date":"May 12, 2018","format":false,"excerpt":"In this blog post, I am showing a simple way of scaling sprites for Pixel Art\u00a0using the HTML5 canvas. Why we scale up sprites rather than rendering them higher quality When displaying pixel art it\u00a0is originally drawn pixel by pixel at a\u00a0very low resolution and then scaled up from original\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/scaling_sprites-for_pixel_art.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/scaling_sprites-for_pixel_art.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/scaling_sprites-for_pixel_art.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/05\/scaling_sprites-for_pixel_art.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":2335,"url":"https:\/\/chewett.co.uk\/blog\/2335\/d3-js-version-5-lazily-loading-dom-elements\/","url_meta":{"origin":1144,"position":5},"title":"D3.js version 5 Lazily loading DOM elements","author":"Chewett","date":"August 24, 2019","format":false,"excerpt":"In this example I demonstrate how you can lazily load DOM elements as you scroll through a page using D3.js. The full code for this is available on my website. Why you might want to lazily load DOM elements As page size increases the browser will slow down rendering it.\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom_elements.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom_elements.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom_elements.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom_elements.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1144","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=1144"}],"version-history":[{"count":7,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1144\/revisions"}],"predecessor-version":[{"id":1154,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1144\/revisions\/1154"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/media\/1151"}],"wp:attachment":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=1144"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=1144"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=1144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}