Skip to content

Instantly share code, notes, and snippets.

@ourmaninamsterdam
Created September 17, 2013 21:06
Show Gist options
  • Save ourmaninamsterdam/6600637 to your computer and use it in GitHub Desktop.
Save ourmaninamsterdam/6600637 to your computer and use it in GitHub Desktop.
A Pen by Justin Perry.

Canvas Chart

JavaScript class for creating simple charts in Canvas. Uses requestAnimationFrame for smooth animations and includes options for variable speed and multiple linear gradient stops. Includes HiDPI resize.

A Pen by Justin Perry on CodePen.

License.

Canvas Circles

JavaScript class for creating circles on Canvas. Uses requestAnimationFrame for smooth animations and includes options for variable speed and multiple linear gradient stops. Includes HiDPI resize.

A Pen by Justin Perry on CodePen.

License.

<body>
<canvas id="canvas" width="200" height="200"></canvas>
<div class="js-controls">
<label>
Value
<input type="number" min="0" max="360" name="" placeholder="Degrees" id="pie-value" value="80" />
</label>
</div>
</body>
(function(){
'use strict';
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
canvasHeight = canvas.height,
canvasWidth = canvas.width,
canvasXCentre = canvasWidth / 2,
canvasYCentre = canvasHeight / 2,
inputPieValue = document.querySelector('#pie-value'),
updateHandler,
circle1,
circle2,
innerCircle1,
innerCircle2,
fps = 60,
timer,
draw,
resizeToRetina;
function Circle( options ){
this.options = options;
this.context = options.context;
this.radius = options.radius;
this.direction = options.direction || 'clockwise';
this.x = options.x;
this.y = options.y;
this.startAngle = options.startAngle;
this.endAngle = options.endAngle;
this.fillStyle = options.fillStyle;
this.lineWidth = options.lineWidth;
this.strokeStyle = options.strokeStyle;
this.animate = options.animate || false;
this.animate.counter = 0;
this.startAngle = this._degreesToRadians( this.startAngle );
}
Circle.prototype._draw = function(){
var endAngle;
if( this.animate ){
if( ( this.animate.counter + 1 * this.animate.speed ) < this.endAngle ){
this.animate.counter += 1 * this.animate.speed;
}
else if( this.endAngle < ( this.animate.counter - 1 * this.animate.speed ) ) {
this.animate.counter -= 1 * this.animate.speed;
}
else{
this.animate.counter = this.endAngle;
}
endAngle = this.startAngle - this._degreesToRadians( this.animate.counter );
}
else{
endAngle = this._degreesToRadians( this.endAngle );
}
if( typeof this.strokeStyle.gradient === 'object' ) {
if( typeof this.strokeStyle.gradient.cache !== 'object' ) {
this.strokeStyle.gradient.cache = this._createGradient( this.strokeStyle.gradient.x0, this.strokeStyle.gradient.y0, this.strokeStyle.gradient.x1, this.strokeStyle.gradient.y1);
}
this.context.strokeStyle = this.strokeStyle.gradient.cache;
}
else{
this.context.strokeStyle = this.strokeStyle;
}
this.context.beginPath();
this.context.arc( this.x, this.y, this.radius, this.startAngle, endAngle, (this.direction === 'clockwise' ));
this.context.lineWidth = this.lineWidth;
this.context.stroke();
this.context.fillStyle = this.fillStyle;
this.context.fill();
};
Circle.prototype._createGradient = function( x0, y0, x1, y1 ){
var gradient = this.context.createLinearGradient( x0, y0, x1, y1 ),
stops = this.strokeStyle.gradient.stops,
len = stops.length,
i;
for( i = 0; i < len; i++){
gradient.addColorStop( stops[i].start, stops[i].color );
}
return gradient;
};
Circle.prototype._degreesToRadians = function( degrees ){
return degrees * Math.PI / 180;
};
Circle.prototype.changeDirection = function(){
this.direction = ( this.direction === 'clockwise' )? 'anticlockwise' : 'clockwise';
};
Circle.prototype.getStartAngle = function(){
return this.startAngle;
};
Circle.prototype.getEndAngle = function(){
return this.endAngle;
};
Circle.prototype.updateStartAngle = function( angle ){
this.startAngle = parseInt( angle || this.startAngle, 10 );
};
Circle.prototype.updateEndAngle = function( angle ){
this.endAngle = parseInt( angle || this.endAngle, 10 );
};
// Gradient Circle
circle1 = new Circle({
context: context,
radius: 75,
x: canvasXCentre,
y: canvasYCentre,
lineWidth: 15,
fillStyle: 'none',
strokeStyle: {
gradient: {
x0: canvasXCentre - 80,
y0: 0,
x1: 0,
y1: canvasXCentre + 80,
stops : [
{
color: '#ebd157',
start: 0.25
},
{
color: '#eb7a32',
start: .5
},
{
color: '#ff3131',
start: .75
}
]
},
},
startAngle : 0,
endAngle : 360
});
// Outer grey circle
circle2 = new Circle({
context: context,
direction: 'anticlockwise',
radius: 75,
x: canvasXCentre,
y: canvasYCentre,
lineWidth: 15.9,
fillStyle: 'none',
strokeStyle: '#5d6e7f',
clip : true,
startAngle : -90,
endAngle : 360 - 280,
animate: {
speed: 3
}
});
// White inner circle
innerCircle1 = new Circle({
context: context,
radius: 63,
x: canvasXCentre,
y: canvasYCentre,
lineWidth : 10,
fillStyle: 'white',
strokeStyle : 'white',
startAngle : 0,
endAngle : 360
});
// Grey small inner circle
innerCircle2 = new Circle({
context: context,
radius: 69,
x: canvasXCentre,
y: canvasYCentre,
lineWidth : 10,
fillStyle: 'none',
strokeStyle : '#e9ecf0',
startAngle : 0,
endAngle : 360
});
draw = function(){
setTimeout(function(){
requestAnimationFrame(draw);
context.clearRect( 0, 0, canvas.width, canvas.height);
circle1._draw();
innerCircle2._draw();
circle2._draw();
innerCircle1._draw();
}, 1000 / fps );
}
inputPieValue.addEventListener('keyup', function(e){
updateHandler.call(this);
});
inputPieValue.addEventListener('change', function(e){
updateHandler.call(this);
});
updateHandler = function(){
clearTimeout(timer);
timer = setTimeout(function(){
circle2.updateEndAngle( this.value );
}.bind(this), 250);
};
// https://github.com/component/autoscale-canvas
resizeToRetina = function( canvas ){
var context = canvas.getContext('2d'),
ratio = window.devicePixelRatio || 1;
if ( 1 !== ratio ) {
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width *= ratio;
canvas.height *= ratio;
context.scale(ratio, ratio);
}
return canvas;
};
resizeToRetina( canvas );
draw();
// Paul Irish polyfill
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
})();
body{
background-color: #272729;
color: #f7f7f7;
font-family: Helvetica, serif;
margin: 10px;
padding: 0;
}
#canvas{
display: block;
left: 50%;
margin: -150px auto 0 -100px;
position: absolute;
top: 50%;
}
.js-controls{
display: block;
position: fixed;
bottom: 30px;
text-align: center;
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment