Skip to content

Instantly share code, notes, and snippets.

@reportbase
Created December 30, 2014 19:47
Show Gist options
  • Save reportbase/019435fe36374eb0f068 to your computer and use it in GitHub Desktop.
Save reportbase/019435fe36374eb0f068 to your computer and use it in GitHub Desktop.
Circular canvas loader

Circular canvas loader

A canvas showing loading progress in a circle. Here it's faked and animated on requestAnimationFrame. But you get the idea.

A Pen by pimskie on CodePen.

License.

<h1>Circular canvas loader</h1>
<div class="loader-holder" id="loader-holder">
<div class="percent"></div>
<canvas id="loader"></canvas>
</div>
<button id="btn-reload">Do it!</button>
;(function () {
// request animation frame
window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)}}()
var Loader = function (options) {
this.options = options;
this.options.completeCallback = this.options.completeCallback || function () {};
this.options.progressCallback = this.options.progressCallback || function () {};
this.options.borderColor = options.borderColor || '#0000000';
this.canvas = document.querySelector(options.canvas);
this.ctx = this.canvas.getContext('2d');
this.loaded = 0;
var parent = this.canvas.parentNode;
this.canvas.width = parent.offsetWidth;
this.canvas.height = parent.offsetHeight;
this.canvasR = parent.offsetWidth >> 1;
this.draw();
}
Loader.prototype.init = function() {
this.loaded = 0;
this.load();
}
Loader.prototype.load = function() {
var me = this;
me.draw();
me.options.progressCallback(me.loaded);
if (me.loaded < 100) {
requestAnimFrame(function () {
me.load();
});
} else {
me.loadingComplete();
}
me.loaded += .5;
}
Loader.prototype.loadingComplete = function() {
this.options.completeCallback();
}
Loader.prototype.draw = function () {
var fillRadian = 360 / 100 * this.loaded * Math.PI / 180,
midX = this.canvas.width * .5,
midY = this.canvas.height * .5;
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// draw arc
this.ctx.beginPath();
this.ctx.arc(midX, midY, this.canvasR, 0, fillRadian, false);
this.ctx.lineWidth = this.options.arcWidth,
this.ctx.strokeStyle = this.options.arcColor,
this.ctx.stroke();
// draw border
if (this.options.borderWidth !== 'undefined') {
this.ctx.beginPath();
this.ctx.arc(midX, midY, this.canvasR, 0, Math.PI * 2, false);
this.ctx.arc(midX, midY, this.canvasR - this.options.borderWidth, 0, Math.PI * 2, true);
this.ctx.fillStyle = this.options.borderColor,
this.ctx.fill();
}
}
var holder = document.getElementById('loader-holder');
var loadingProgress = function (percent) {
var percentHolder = document.querySelector('.percent');
percentHolder.innerHTML = Math.round(percent) + '%';
}
var loadingDone = function () {
holder.classList.add('loading-done');
}
var loader = new Loader({
canvas: '#loader',
arcWidth: 100,
arcColor: 'rgb(0, 165, 255)',
borderWidth: 20,
borderColor: 'rgb(53, 138, 185)',
progressCallback: loadingProgress,
completeCallback: loadingDone
});
var button = document.getElementById('btn-reload');
button.addEventListener('mousedown', function() {
holder.classList.remove('loading-done');
loader.init();
}, false);
})();
@import "bourbon";
@import url(http://fonts.googleapis.com/css?family=Roboto:700,300);
$radius: 200px;
* {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
font-weight: 300;
padding: 2em;
text-align: center;
}
h1 {
font-size: 1.5em;
}
button {
$bg: rgb(0, 165, 255);
background: $bg;
border: none;
color: #fff;
padding: 10px 15px;
border-radius: 10px;
cursor: pointer;
@include transition(background .1s ease-in);
&:hover {
background: darken($bg, 20%);
}
}
.loader-holder {
width: $radius;
height: $radius;
position: relative;
margin: 30px auto;
&.loading-done {
@include animation(loading-done .5s cubic-bezier(.99, .27, .99, 1.01) forwards);
.percent {
opacity: 0;
}
}
.percent {
position: absolute;
z-index: 10;
text-align: center;
width: 100%;
top: 50%;
font-weight: 700;
font-size: 1.5em;
line-height: 0;
color: rgb(38, 38, 38);
opacity: 1;
@include transition(opacity .2s ease-out);
.loading-done & {
// update sass
}
}
& > canvas {
width: 100%;
height: 100%;
border-radius: 100%;
}
}
@include keyframes(loading-done) {
0% {
@include transform(scale(1));
}
20% {
@include transform(scale(1.2));
}
100% {
@include transform(scale(0));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment