Actualización

This commit is contained in:
Xes
2025-04-10 11:37:29 +02:00
parent 4bfeadb360
commit 8969cc929d
39112 changed files with 975884 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
{
"name": "jquery.easy-pie-chart",
"version": "2.1.6",
"main": [
"dist/jquery.easypiechart.js"
],
"ignore": [
"demo",
".editorconfig"
],
"dependencies": {
"jquery": ">=1.9.0",
"requirejs": "~2.1.10"
},
"devDependencies": {
"angular": "~1.2.9",
"angular-mocks": "~1.2.9"
},
"homepage": "https://github.com/rendro/easy-pie-chart",
"_release": "2.1.6",
"_resolution": {
"type": "version",
"tag": "2.1.6",
"commit": "29636bc1cc0ecbd8de9490525724a12dbf723888"
},
"_source": "https://github.com/rendro/easy-pie-chart.git",
"_target": "^2.1.6",
"_originalSource": "jquery.easy-pie-chart"
}

View File

@@ -0,0 +1,4 @@
node_modules
bower_components
.grunt
_SpecRunner.html

View File

@@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.10"
before_install:
- npm install -g karma bower grunt-cli
- bower install
- npm install

View File

@@ -0,0 +1,188 @@
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
cfg: {
filename: 'easypiechart',
vanillaExportName: 'EasyPieChart'
},
dirs: {
tmp: 'tmp',
src: 'src',
dest: 'dist',
docs: 'docs',
test: 'test',
demo: 'demo'
},
clean: {
all: ['<%= dirs.dest %>/', '<%= dirs.tmp %>/'],
tmp: ['<%= dirs.tmp %>/']
},
concat: {
vanilla: {
src: [
'<%= dirs.src %>/renderer/canvas.js',
'<%= dirs.src %>/<%= cfg.filename %>.js'
],
dest: '<%= dirs.tmp %>/<%= cfg.filename %>.js'
},
jquery: {
src: [
'<%= dirs.src %>/renderer/canvas.js',
'<%= dirs.src %>/<%= cfg.filename %>.js',
'<%= dirs.src %>/jquery.plugin.js'
],
dest: '<%= dirs.tmp %>/jquery.<%= cfg.filename %>.js'
},
angular: {
src: [
'<%= dirs.src %>/angular.directive.js',
'<%= dirs.src %>/renderer/canvas.js',
'<%= dirs.src %>/<%= cfg.filename %>.js'
],
dest: '<%= dirs.tmp %>/angular.<%= cfg.filename %>.js'
}
},
usebanner: {
options: {
position: 'top',
banner: '/**!\n' +
' * <%= pkg.name %>\n' +
' * <%= pkg.description %>\n' +
' *\n' +
' * @license <%= pkg.license %>\n'+
' * @author <%= pkg.author.name %> <<%= pkg.author.email %>> (<%= pkg.author.url %>)\n' +
' * @version <%= pkg.version %>\n' +
' **/\n'
},
files: {
src: [
'<%= dirs.dest %>/<%= cfg.filename %>.js',
'<%= dirs.dest %>/jquery.<%= cfg.filename %>.js',
'<%= dirs.dest %>/angular.<%= cfg.filename %>.js'
]
}
},
uglify: {
dist: {
options: {
report: 'gzip',
preserveComments: 'some'
},
files: {
'dist/<%= cfg.filename %>.min.js': ['dist/<%= cfg.filename %>.js'],
'dist/jquery.<%= cfg.filename %>.min.js': ['dist/jquery.<%= cfg.filename %>.js'],
'dist/angular.<%= cfg.filename %>.min.js': ['dist/angular.<%= cfg.filename %>.js']
}
}
},
watch: {
gruntfile: {
files: ['Gruntfile.js']
},
scripts: {
files: '<%= dirs.src %>/**/*.js',
tasks: ['default'],
options: {
debounceDelay: 250
}
},
less: {
files: '<%= dirs.demo %>/*.less',
tasks: ['less'],
options: {
debounceDelay: 250
}
},
readme: {
files: '<%= dirs.docs %>/**/*.md',
tasks: ['readme'],
options: {
debounceDelay: 250
}
}
},
jshint: {
files: [
'<%= dirs.src %>/**/*.js',
'<%= dirs.test %>/**/*.js'
],
options: {}
},
karma: {
unit: {
configFile: 'karma.conf.coffee'
},
ci: {
configFile: 'karma.conf.coffee',
singleRun: true,
browsers: ['PhantomJS']
}
},
less: {
demo: {
files: {
'<%= dirs.demo %>/style.css': ['<%= dirs.demo %>/style.less']
}
}
},
umd: {
vanilla: {
src: '<%= dirs.tmp %>/<%= cfg.filename %>.js',
dest: '<%= dirs.dest %>/<%= cfg.filename %>.js',
objectToExport: '<%= cfg.vanillaExportName %>',
globalAlias: '<%= cfg.vanillaExportName %>'
},
jquery: {
src: '<%= dirs.tmp %>/jquery.<%= cfg.filename %>.js',
dest: '<%= dirs.dest %>/jquery.<%= cfg.filename %>.js',
deps: {
'default': ['$'],
amd: ['jquery'],
cjs: ['jquery'],
global: ['jQuery']
}
},
angular: {
src: '<%= dirs.tmp %>/angular.<%= cfg.filename %>.js',
dest: '<%= dirs.dest %>/angular.<%= cfg.filename %>.js',
deps: {
'default': ['angular'],
amd: ['angular'],
cjs: ['angular'],
global: ['angular']
}
}
}
});
// load all installed grunt tasks
require('load-grunt-tasks')(grunt);
// task defiinitions
grunt.registerTask('default', [
'clean:all',
'jshint',
'concat',
'umd',
'usebanner',
'uglify',
'clean:tmp',
'readme'
]);
grunt.registerTask('test', ['karma:unit']);
grunt.registerTask('all', ['default', 'less']);
};

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Robert Fleischmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,268 @@
# easyPieChart
> Lightweight plugin to render simple, animated and retina optimized pie charts
![Version](http://img.shields.io/version/2.1.6.png?color=green)
[![Build Status](https://travis-ci.org/rendro/easy-pie-chart.png)](https://travis-ci.org/rendro/easy-pie-chart)
[![Dependencies Status](https://david-dm.org/rendro/easy-pie-chart/dev-status.png)](https://david-dm.org/rendro/easy-pie-chart)
[![Analytics](https://ga-beacon.appspot.com/UA-46840672-1/easy-pie-chart/readme)](https://github.com/igrigorik/ga-beacon)
## Features
[![](https://github.com/rendro/easy-pie-chart/raw/master/demo/img/easy-pie-chart.png)](http://drbl.in/ezuc)
* highly customizable
* very easy to implement
* resolution independent (retina optimized)
* uses `requestAnimationFrame` for smooth animations on modern devices and
* works in all modern browsers, even in IE7+ with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions)
#### framework support
* Vanilla JS *(no dependencies)* (~872 bytes)
* jQuery plugin (~921 bytes)
* Angular Module (~983 bytes)
## Get started
#### Installation
You can also use [bower](http://bower.io) to install the component:
```
$ bower install jquery.easy-pie-chart
```
#### jQuery
To use the easy pie chart plugin you need to load the current version of jQuery (> 1.6.4) and the source of the plugin.
```html
<div class="chart" data-percent="73" data-scale-color="#ffb400">73%</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="/path/to/jquery.easy-pie-chart.js"></script>
<script>
$(function() {
$('.chart').easyPieChart({
//your options goes here
});
});
</script>
```
#### Vanilla JS
If you don't want to use jQuery, implement the Vanilla JS version without any dependencies.
```html
<div class="chart" data-percent="73">73%</div>
<script src="/path/to/easy-pie-chart.js"></script>
<script>
var element = document.querySelector('.chart');
new EasyPieChart(element, {
// your options goes here
});
</script>
```
#### AngularJS
```html
<div ng-controller="chartCtrl">
<div easypiechart options="options" percent="percent"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="../dist/angular.easypiechart.min.js"></script>
<script>
var app = angular.module('app', ['easypiechart']);
app.controller('chartCtrl', ['$scope', function ($scope) {
$scope.percent = 65;
$scope.options = {
animate:{
duration:0,
enabled:false
},
barColor:'#2C3E50',
scaleColor:false,
lineWidth:20,
lineCap:'circle'
};
}]);
</script>
```
## Options
You can pass these options to the initialize function to set a custom look and feel for the plugin.
<table>
<tr>
<th>Property (Type)</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td><strong>barColor</strong></td>
<td>#ef1e25</td>
<td>The color of the curcular bar. You can either pass a valid css color string, or a function that takes the current percentage as a value and returns a valid css color string.</td>
</tr>
<tr>
<td><strong>trackColor</strong></td>
<td>#f2f2f2</td>
<td>The color of the track, or false to disable rendering.</td>
</tr>
<tr>
<td><strong>scaleColor</strong></td>
<td>#dfe0e0</td>
<td>The color of the scale lines, false to disable rendering.</td>
</tr>
<tr>
<td><strong>scaleLength</strong></td>
<td>5</td>
<td>Length of the scale lines (reduces the radius of the chart).</td>
</tr>
<tr>
<td><strong>lineCap</strong></td>
<td>round</td>
<td>Defines how the ending of the bar line looks like. Possible values are: <code>butt</code>, <code>round</code> and <code>square</code>.</td>
</tr>
<tr>
<td><strong>lineWidth</strong></td>
<td>3</td>
<td>Width of the chart line in px.</td>
</tr>
<tr>
<td><strong>size</strong></td>
<td>110</td>
<td>Size of the pie chart in px. It will always be a square.</td>
</tr>
<tr>
<td><strong>rotate</strong></td>
<td>0</td>
<td>Rotation of the complete chart in degrees.</td>
</tr>
<tr>
<td><strong>animate</strong></td>
<td>object</td>
<td>Object with time in milliseconds and boolean for an animation of the bar growing (<code>{ duration: 1000, enabled: true }</code>), or false to deactivate animations.</td>
</tr>
<tr>
<td><strong>easing</strong></td>
<td>defaultEasing</td>
<td>Easing function or string with the name of a <a href="http://gsgd.co.uk/sandbox/jquery/easing/" target="_blank">jQuery easing function</a></td>
</tr>
</table>
## Callbacks
All callbacks will only be called if `animate` is not `false`.
<table>
<tr>
<th>Callback(params, ...)</th>
<th>Description</th>
</tr>
<tr>
<td><strong>onStart(from, to)</strong></td>
<td>Is called at the start of any animation.</td>
</tr>
<tr>
<td><strong>onStep(from, to, currentValue)</strong></td>
<td>Is called during animations providing the current value (the method is scoped to the context of th eplugin, so you can access the DOM element via <code>this.el</code>).</td>
</tr>
<tr>
<td><strong>onStop(from, to)</strong></td>
<td>Is called at the end of any animation.</td>
</tr>
</table>
## Plugin api
#### jQuery
```javascript
$(function() {
// instantiate the plugin
...
// update
$('.chart').data('easyPieChart').update(40);
...
// disable animation
$('.chart').data('easyPieChart').disableAnimation();
...
// enable animation
$('.chart').data('easyPieChart').enableAnimation();
});
```
#### Vanilla JS
```javascript
// instantiate the plugin
var chart = new EasyPieChart(element, options);
// update
chart.update(40);
// disable animation
chart.disableAnimation();
// enable animation
chart.enableAnimation();
```
###### Using a gradient
```javascript
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop(0, "#ffe57e");
gradient.addColorStop(1, "#de5900");
return gradient;
}
});
```
#### AngularJS
For a value binding you need to add the `percent` attribute and bind it to your controller.
#### RequireJS
When using [RequireJS](http://requirejs.org) you can define your own name. Examples can be found in the `demo/requirejs.html`.
## Browser Support
Native support
* Chrome
* Safari
* FireFox
* Opera
* Internet Explorer 9+
Support for Internet Explorer 7 and 8 with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions) polyfill.
## Test
To run the test just use the karma adapter of grunt: `grunt test`
## Credits
Thanks to [Rafal Bromirski](http://www.paranoida.com/) for designing [this dribble shot](http://drbl.in/ezuc) which inspired me building this plugin.
## Copyright
Copyright (c) 2014 Robert Fleischmann, contributors. Released under the MIT, GPL licenses

View File

@@ -0,0 +1,19 @@
{
"name": "jquery.easy-pie-chart",
"version": "2.1.6",
"main": [
"dist/jquery.easypiechart.js"
],
"ignore": [
"demo",
".editorconfig"
],
"dependencies": {
"jquery": ">=1.9.0",
"requirejs": "~2.1.10"
},
"devDependencies": {
"angular": "~1.2.9",
"angular-mocks": "~1.2.9"
}
}

View File

@@ -0,0 +1,80 @@
# Changlog
## Version 2.1.5 - Feb 28, 2014
* Fixed build error for minified vanilla version
## Version 2.1.4 - Feb 1, 2014
* Various updates and pull requests
## Version 2.1.3 - Dec 1, 2013
* Allow negative percent values with a reversed pie chart
## Version 2.1.2 - Dec 1, 2013
* Allow override of default options with data attributes in JQuery plugin
## Version 2.1.1 - Nov 19, 2013
* Fixed AMD support for jQuery version
## Version 2.1.0 - Oct 28, 2013
* Added UMD (Universal Module Definition) wrapper for AMD and requireJS support
* Angular module: Move options into single attribute and provide it as JSON
* Allow decimal numbers for percent values
## Version 2.0.5 Oct 12, 2013
* (Angular) Fixed timer bug
## Version 2.0.4 - Oct 10, 2013
* Use the internal timing function of angular
* Added the ability to create two instances of the chart on one main scope
* Removed unnecessary stuff from the angular example to provide the minimal setup
* Added more conventional way to create controller in angular
## Version 2.0.3 - Sep 29, 2013
* Fixed render bug on retina displays
* Auto detect and load renderer (in preparation of a svg renderer)
## Version 2.0.2 - Sep 26, 2013
* Improved render performance by approx. 300%
## Version 2.0.1 - Sep 22, 2013
* Support for Internet Explorer 7 and 8 with excanvas
## Version 2.0.0 - Sep 22, 2013
* Added vanilla JS version
* Added angular directive
* Dropped coffeescript version
* Dropped support for delayed animations
* Moved canvas render methods in own module
## Version 1.2.5 - Aug 05, 2013
* Added default option value for delay
## Version 1.2.4 - Aug 05, 2013
* bug fix for incomplete animations
* support for delayed animations
## Version 1.2.3 - Jul 17, 2013
* Date.now fix for IE < IE9
## Version 1.2.2 - Jul 15, 2013
* Add `currentValue` and `to` to the onStop callback
## Version 1.2.1 - Jun 19, 2013
* Allow overriding of options with HTML data attributes where provided
## Version 1.2.0 - Jun 19, 2013
* Added `rotate` option to rotate the complete chart
## Version 1.1.0 - Jun 10, 2013
* Added missing `onStop` method
* cast `percent` to float to avoid breaking chart if a string is passed to the update method
## Version 1.0.2 - Jun 07, 2013
* Use requestAnimationFrame for smooth animations
* Added `onStep` option to get the current value during animations
## Version 1.0.1 - Feb 07, 2013
* Added retina support
## Version 1.0.0 - Aug 02, 2012
* Initial version

View File

@@ -0,0 +1,397 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
(function(root, factory) {
if(typeof exports === 'object') {
module.exports = factory(require('angular'));
}
else if(typeof define === 'function' && define.amd) {
define(['angular'], factory);
}
else {
factory(root.angular);
}
}(this, function(angular) {
(function (angular) {
'use strict';
return angular.module('easypiechart', [])
.directive('easypiechart', [function() {
return {
restrict: 'A',
require: '?ngModel',
scope: {
percent: '=',
options: '='
},
link: function (scope, element, attrs) {
scope.percent = scope.percent || 0;
/**
* default easy pie chart options
* @type {Object}
*/
var options = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
}
};
scope.options = angular.extend(options, scope.options);
var pieChart = new EasyPieChart(element[0], options);
scope.$watch('percent', function(newVal, oldVal) {
pieChart.update(newVal);
});
}
};
}]);
})(angular);
/**
* Renderer to render the chart on a canvas object
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
* @param {object} options options object of the plugin
*/
var CanvasRenderer = function(el, options) {
var cachedBackground;
var canvas = document.createElement('canvas');
el.appendChild(canvas);
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
// canvas on retina devices
var scaleBy = 1;
if (window.devicePixelRatio > 1) {
scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
canvas.width = canvas.height = options.size * scaleBy;
ctx.scale(scaleBy, scaleBy);
}
// move 0,0 coordinates to the center
ctx.translate(options.size / 2, options.size / 2);
// rotate canvas -90deg
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
var radius = (options.size - options.lineWidth) / 2;
if (options.scaleColor && options.scaleLength) {
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
}
// IE polyfill for Date
Date.now = Date.now || function() {
return +(new Date());
};
/**
* Draw a circle around the center of the canvas
* @param {strong} color Valid CSS color string
* @param {number} lineWidth Width of the line in px
* @param {number} percent Percentage to draw (float between -1 and 1)
*/
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(-1, percent || 0), 1);
var isNegative = percent <= 0 ? true : false;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.stroke();
};
/**
* Draw the scale of the chart
*/
var drawScale = function() {
var offset;
var length;
ctx.lineWidth = 1;
ctx.fillStyle = options.scaleColor;
ctx.save();
for (var i = 24; i > 0; --i) {
if (i % 6 === 0) {
length = options.scaleLength;
offset = 0;
} else {
length = options.scaleLength * 0.6;
offset = options.scaleLength - length;
}
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
ctx.rotate(Math.PI / 12);
}
ctx.restore();
};
/**
* Request animation frame wrapper with polyfill
* @return {function} Request animation frame method or timeout fallback
*/
var reqAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
/**
* Draw the background of the plugin including the scale and the track
*/
var drawBackground = function() {
if(options.scaleColor) drawScale();
if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
};
/**
* Canvas accessor
*/
this.getCanvas = function() {
return canvas;
};
/**
* Canvas 2D context 'ctx' accessor
*/
this.getCtx = function() {
return ctx;
};
/**
* Clear the complete canvas
*/
this.clear = function() {
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
};
/**
* Draw the complete chart
* @param {number} percent Percent shown by the chart between -100 and 100
*/
this.draw = function(percent) {
// do we need to render a background
if (!!options.scaleColor || !!options.trackColor) {
// getImageData and putImageData are supported
if (ctx.getImageData && ctx.putImageData) {
if (!cachedBackground) {
drawBackground();
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
} else {
ctx.putImageData(cachedBackground, 0, 0);
}
} else {
this.clear();
drawBackground();
}
} else {
this.clear();
}
ctx.lineCap = options.lineCap;
// if barcolor is a function execute it and pass the percent as a value
var color;
if (typeof(options.barColor) === 'function') {
color = options.barColor(percent);
} else {
color = options.barColor;
}
// draw bar
drawCircle(color, options.lineWidth, percent / 100);
}.bind(this);
/**
* Animate from some percent to some other percentage
* @param {number} from Starting percentage
* @param {number} to Final percentage
*/
this.animate = function(from, to) {
var startTime = Date.now();
options.onStart(from, to);
var animation = function() {
var process = Math.min(Date.now() - startTime, options.animate.duration);
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
this.draw(currentValue);
options.onStep(from, to, currentValue);
if (process >= options.animate.duration) {
options.onStop(from, to);
} else {
reqAnimationFrame(animation);
}
}.bind(this);
reqAnimationFrame(animation);
}.bind(this);
};
var EasyPieChart = function(el, opts) {
var defaultOptions = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
trackWidth: undefined,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
},
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
t = t / (d/2);
if (t < 1) {
return c / 2 * t * t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
onStart: function(from, to) {
return;
},
onStep: function(from, to, currentValue) {
return;
},
onStop: function(from, to) {
return;
}
};
// detect present renderer
if (typeof(CanvasRenderer) !== 'undefined') {
defaultOptions.renderer = CanvasRenderer;
} else if (typeof(SVGRenderer) !== 'undefined') {
defaultOptions.renderer = SVGRenderer;
} else {
throw new Error('Please load either the SVG- or the CanvasRenderer');
}
var options = {};
var currentValue = 0;
/**
* Initialize the plugin by creating the options object and initialize rendering
*/
var init = function() {
this.el = el;
this.options = options;
// merge user options into default options
for (var i in defaultOptions) {
if (defaultOptions.hasOwnProperty(i)) {
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
if (typeof(options[i]) === 'function') {
options[i] = options[i].bind(this);
}
}
}
// check for jQuery easing
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
options.easing = jQuery.easing[options.easing];
} else {
options.easing = defaultOptions.easing;
}
// process earlier animate option to avoid bc breaks
if (typeof(options.animate) === 'number') {
options.animate = {
duration: options.animate,
enabled: true
};
}
if (typeof(options.animate) === 'boolean' && !options.animate) {
options.animate = {
duration: 1000,
enabled: options.animate
};
}
// create renderer
this.renderer = new options.renderer(el, options);
// initial draw
this.renderer.draw(currentValue);
// initial update
if (el.dataset && el.dataset.percent) {
this.update(parseFloat(el.dataset.percent));
} else if (el.getAttribute && el.getAttribute('data-percent')) {
this.update(parseFloat(el.getAttribute('data-percent')));
}
}.bind(this);
/**
* Update the value of the chart
* @param {number} newValue Number between 0 and 100
* @return {object} Instance of the plugin for method chaining
*/
this.update = function(newValue) {
newValue = parseFloat(newValue);
if (options.animate.enabled) {
this.renderer.animate(currentValue, newValue);
} else {
this.renderer.draw(newValue);
}
currentValue = newValue;
return this;
}.bind(this);
/**
* Disable animation
* @return {object} Instance of the plugin for method chaining
*/
this.disableAnimation = function() {
options.animate.enabled = false;
return this;
};
/**
* Enable animation
* @return {object} Instance of the plugin for method chaining
*/
this.enableAnimation = function() {
options.animate.enabled = true;
return this;
};
init();
};
}));

View File

@@ -0,0 +1,9 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
!function(a,b){"object"==typeof exports?module.exports=b(require("angular")):"function"==typeof define&&define.amd?define(["angular"],b):b(a.angular)}(this,function(a){!function(a){"use strict";return a.module("easypiechart",[]).directive("easypiechart",[function(){return{restrict:"A",require:"?ngModel",scope:{percent:"=",options:"="},link:function(b,d){b.percent=b.percent||0;var e={barColor:"#ef1e25",trackColor:"#f9f9f9",scaleColor:"#dfe0e0",scaleLength:5,lineCap:"round",lineWidth:3,size:110,rotate:0,animate:{duration:1e3,enabled:!0}};b.options=a.extend(e,b.options);var f=new c(d[0],e);b.$watch("percent",function(a){f.update(a)})}}}])}(a);var b=function(a,b){var c,d=document.createElement("canvas");a.appendChild(d),"undefined"!=typeof G_vmlCanvasManager&&G_vmlCanvasManager.initElement(d);var e=d.getContext("2d");d.width=d.height=b.size;var f=1;window.devicePixelRatio>1&&(f=window.devicePixelRatio,d.style.width=d.style.height=[b.size,"px"].join(""),d.width=d.height=b.size*f,e.scale(f,f)),e.translate(b.size/2,b.size/2),e.rotate((-0.5+b.rotate/180)*Math.PI);var g=(b.size-b.lineWidth)/2;b.scaleColor&&b.scaleLength&&(g-=b.scaleLength+2),Date.now=Date.now||function(){return+new Date};var h=function(a,b,c){c=Math.min(Math.max(-1,c||0),1);var d=0>=c?!0:!1;e.beginPath(),e.arc(0,0,g,0,2*Math.PI*c,d),e.strokeStyle=a,e.lineWidth=b,e.stroke()},i=function(){var a,c;e.lineWidth=1,e.fillStyle=b.scaleColor,e.save();for(var d=24;d>0;--d)d%6===0?(c=b.scaleLength,a=0):(c=.6*b.scaleLength,a=b.scaleLength-c),e.fillRect(-b.size/2+a,0,c,1),e.rotate(Math.PI/12);e.restore()},j=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),k=function(){b.scaleColor&&i(),b.trackColor&&h(b.trackColor,b.trackWidth||b.lineWidth,1)};this.getCanvas=function(){return d},this.getCtx=function(){return e},this.clear=function(){e.clearRect(b.size/-2,b.size/-2,b.size,b.size)},this.draw=function(a){b.scaleColor||b.trackColor?e.getImageData&&e.putImageData?c?e.putImageData(c,0,0):(k(),c=e.getImageData(0,0,b.size*f,b.size*f)):(this.clear(),k()):this.clear(),e.lineCap=b.lineCap;var d;d="function"==typeof b.barColor?b.barColor(a):b.barColor,h(d,b.lineWidth,a/100)}.bind(this),this.animate=function(a,c){var d=Date.now();b.onStart(a,c);var e=function(){var f=Math.min(Date.now()-d,b.animate.duration),g=b.easing(this,f,a,c-a,b.animate.duration);this.draw(g),b.onStep(a,c,g),f>=b.animate.duration?b.onStop(a,c):j(e)}.bind(this);j(e)}.bind(this)},c=function(a,c){var d={barColor:"#ef1e25",trackColor:"#f9f9f9",scaleColor:"#dfe0e0",scaleLength:5,lineCap:"round",lineWidth:3,trackWidth:void 0,size:110,rotate:0,animate:{duration:1e3,enabled:!0},easing:function(a,b,c,d,e){return b/=e/2,1>b?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},onStart:function(){},onStep:function(){},onStop:function(){}};if("undefined"!=typeof b)d.renderer=b;else{if("undefined"==typeof SVGRenderer)throw new Error("Please load either the SVG- or the CanvasRenderer");d.renderer=SVGRenderer}var e={},f=0,g=function(){this.el=a,this.options=e;for(var b in d)d.hasOwnProperty(b)&&(e[b]=c&&"undefined"!=typeof c[b]?c[b]:d[b],"function"==typeof e[b]&&(e[b]=e[b].bind(this)));e.easing="string"==typeof e.easing&&"undefined"!=typeof jQuery&&jQuery.isFunction(jQuery.easing[e.easing])?jQuery.easing[e.easing]:d.easing,"number"==typeof e.animate&&(e.animate={duration:e.animate,enabled:!0}),"boolean"!=typeof e.animate||e.animate||(e.animate={duration:1e3,enabled:e.animate}),this.renderer=new e.renderer(a,e),this.renderer.draw(f),a.dataset&&a.dataset.percent?this.update(parseFloat(a.dataset.percent)):a.getAttribute&&a.getAttribute("data-percent")&&this.update(parseFloat(a.getAttribute("data-percent")))}.bind(this);this.update=function(a){return a=parseFloat(a),e.animate.enabled?this.renderer.animate(f,a):this.renderer.draw(a),f=a,this}.bind(this),this.disableAnimation=function(){return e.animate.enabled=!1,this},this.enableAnimation=function(){return e.animate.enabled=!0,this},g()}});

View File

@@ -0,0 +1,351 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
(function(root, factory) {
if(typeof exports === 'object') {
module.exports = factory();
}
else if(typeof define === 'function' && define.amd) {
define([], factory);
}
else {
root['EasyPieChart'] = factory();
}
}(this, function() {
/**
* Renderer to render the chart on a canvas object
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
* @param {object} options options object of the plugin
*/
var CanvasRenderer = function(el, options) {
var cachedBackground;
var canvas = document.createElement('canvas');
el.appendChild(canvas);
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
// canvas on retina devices
var scaleBy = 1;
if (window.devicePixelRatio > 1) {
scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
canvas.width = canvas.height = options.size * scaleBy;
ctx.scale(scaleBy, scaleBy);
}
// move 0,0 coordinates to the center
ctx.translate(options.size / 2, options.size / 2);
// rotate canvas -90deg
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
var radius = (options.size - options.lineWidth) / 2;
if (options.scaleColor && options.scaleLength) {
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
}
// IE polyfill for Date
Date.now = Date.now || function() {
return +(new Date());
};
/**
* Draw a circle around the center of the canvas
* @param {strong} color Valid CSS color string
* @param {number} lineWidth Width of the line in px
* @param {number} percent Percentage to draw (float between -1 and 1)
*/
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(-1, percent || 0), 1);
var isNegative = percent <= 0 ? true : false;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.stroke();
};
/**
* Draw the scale of the chart
*/
var drawScale = function() {
var offset;
var length;
ctx.lineWidth = 1;
ctx.fillStyle = options.scaleColor;
ctx.save();
for (var i = 24; i > 0; --i) {
if (i % 6 === 0) {
length = options.scaleLength;
offset = 0;
} else {
length = options.scaleLength * 0.6;
offset = options.scaleLength - length;
}
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
ctx.rotate(Math.PI / 12);
}
ctx.restore();
};
/**
* Request animation frame wrapper with polyfill
* @return {function} Request animation frame method or timeout fallback
*/
var reqAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
/**
* Draw the background of the plugin including the scale and the track
*/
var drawBackground = function() {
if(options.scaleColor) drawScale();
if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
};
/**
* Canvas accessor
*/
this.getCanvas = function() {
return canvas;
};
/**
* Canvas 2D context 'ctx' accessor
*/
this.getCtx = function() {
return ctx;
};
/**
* Clear the complete canvas
*/
this.clear = function() {
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
};
/**
* Draw the complete chart
* @param {number} percent Percent shown by the chart between -100 and 100
*/
this.draw = function(percent) {
// do we need to render a background
if (!!options.scaleColor || !!options.trackColor) {
// getImageData and putImageData are supported
if (ctx.getImageData && ctx.putImageData) {
if (!cachedBackground) {
drawBackground();
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
} else {
ctx.putImageData(cachedBackground, 0, 0);
}
} else {
this.clear();
drawBackground();
}
} else {
this.clear();
}
ctx.lineCap = options.lineCap;
// if barcolor is a function execute it and pass the percent as a value
var color;
if (typeof(options.barColor) === 'function') {
color = options.barColor(percent);
} else {
color = options.barColor;
}
// draw bar
drawCircle(color, options.lineWidth, percent / 100);
}.bind(this);
/**
* Animate from some percent to some other percentage
* @param {number} from Starting percentage
* @param {number} to Final percentage
*/
this.animate = function(from, to) {
var startTime = Date.now();
options.onStart(from, to);
var animation = function() {
var process = Math.min(Date.now() - startTime, options.animate.duration);
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
this.draw(currentValue);
options.onStep(from, to, currentValue);
if (process >= options.animate.duration) {
options.onStop(from, to);
} else {
reqAnimationFrame(animation);
}
}.bind(this);
reqAnimationFrame(animation);
}.bind(this);
};
var EasyPieChart = function(el, opts) {
var defaultOptions = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
trackWidth: undefined,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
},
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
t = t / (d/2);
if (t < 1) {
return c / 2 * t * t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
onStart: function(from, to) {
return;
},
onStep: function(from, to, currentValue) {
return;
},
onStop: function(from, to) {
return;
}
};
// detect present renderer
if (typeof(CanvasRenderer) !== 'undefined') {
defaultOptions.renderer = CanvasRenderer;
} else if (typeof(SVGRenderer) !== 'undefined') {
defaultOptions.renderer = SVGRenderer;
} else {
throw new Error('Please load either the SVG- or the CanvasRenderer');
}
var options = {};
var currentValue = 0;
/**
* Initialize the plugin by creating the options object and initialize rendering
*/
var init = function() {
this.el = el;
this.options = options;
// merge user options into default options
for (var i in defaultOptions) {
if (defaultOptions.hasOwnProperty(i)) {
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
if (typeof(options[i]) === 'function') {
options[i] = options[i].bind(this);
}
}
}
// check for jQuery easing
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
options.easing = jQuery.easing[options.easing];
} else {
options.easing = defaultOptions.easing;
}
// process earlier animate option to avoid bc breaks
if (typeof(options.animate) === 'number') {
options.animate = {
duration: options.animate,
enabled: true
};
}
if (typeof(options.animate) === 'boolean' && !options.animate) {
options.animate = {
duration: 1000,
enabled: options.animate
};
}
// create renderer
this.renderer = new options.renderer(el, options);
// initial draw
this.renderer.draw(currentValue);
// initial update
if (el.dataset && el.dataset.percent) {
this.update(parseFloat(el.dataset.percent));
} else if (el.getAttribute && el.getAttribute('data-percent')) {
this.update(parseFloat(el.getAttribute('data-percent')));
}
}.bind(this);
/**
* Update the value of the chart
* @param {number} newValue Number between 0 and 100
* @return {object} Instance of the plugin for method chaining
*/
this.update = function(newValue) {
newValue = parseFloat(newValue);
if (options.animate.enabled) {
this.renderer.animate(currentValue, newValue);
} else {
this.renderer.draw(newValue);
}
currentValue = newValue;
return this;
}.bind(this);
/**
* Disable animation
* @return {object} Instance of the plugin for method chaining
*/
this.disableAnimation = function() {
options.animate.enabled = false;
return this;
};
/**
* Enable animation
* @return {object} Instance of the plugin for method chaining
*/
this.enableAnimation = function() {
options.animate.enabled = true;
return this;
};
init();
};
return EasyPieChart;
}));

View File

@@ -0,0 +1,9 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.EasyPieChart=b()}(this,function(){var a=function(a,b){var c,d=document.createElement("canvas");a.appendChild(d),"undefined"!=typeof G_vmlCanvasManager&&G_vmlCanvasManager.initElement(d);var e=d.getContext("2d");d.width=d.height=b.size;var f=1;window.devicePixelRatio>1&&(f=window.devicePixelRatio,d.style.width=d.style.height=[b.size,"px"].join(""),d.width=d.height=b.size*f,e.scale(f,f)),e.translate(b.size/2,b.size/2),e.rotate((-0.5+b.rotate/180)*Math.PI);var g=(b.size-b.lineWidth)/2;b.scaleColor&&b.scaleLength&&(g-=b.scaleLength+2),Date.now=Date.now||function(){return+new Date};var h=function(a,b,c){c=Math.min(Math.max(-1,c||0),1);var d=0>=c?!0:!1;e.beginPath(),e.arc(0,0,g,0,2*Math.PI*c,d),e.strokeStyle=a,e.lineWidth=b,e.stroke()},i=function(){var a,c;e.lineWidth=1,e.fillStyle=b.scaleColor,e.save();for(var d=24;d>0;--d)d%6===0?(c=b.scaleLength,a=0):(c=.6*b.scaleLength,a=b.scaleLength-c),e.fillRect(-b.size/2+a,0,c,1),e.rotate(Math.PI/12);e.restore()},j=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),k=function(){b.scaleColor&&i(),b.trackColor&&h(b.trackColor,b.trackWidth||b.lineWidth,1)};this.getCanvas=function(){return d},this.getCtx=function(){return e},this.clear=function(){e.clearRect(b.size/-2,b.size/-2,b.size,b.size)},this.draw=function(a){b.scaleColor||b.trackColor?e.getImageData&&e.putImageData?c?e.putImageData(c,0,0):(k(),c=e.getImageData(0,0,b.size*f,b.size*f)):(this.clear(),k()):this.clear(),e.lineCap=b.lineCap;var d;d="function"==typeof b.barColor?b.barColor(a):b.barColor,h(d,b.lineWidth,a/100)}.bind(this),this.animate=function(a,c){var d=Date.now();b.onStart(a,c);var e=function(){var f=Math.min(Date.now()-d,b.animate.duration),g=b.easing(this,f,a,c-a,b.animate.duration);this.draw(g),b.onStep(a,c,g),f>=b.animate.duration?b.onStop(a,c):j(e)}.bind(this);j(e)}.bind(this)},b=function(b,c){var d={barColor:"#ef1e25",trackColor:"#f9f9f9",scaleColor:"#dfe0e0",scaleLength:5,lineCap:"round",lineWidth:3,trackWidth:void 0,size:110,rotate:0,animate:{duration:1e3,enabled:!0},easing:function(a,b,c,d,e){return b/=e/2,1>b?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},onStart:function(){},onStep:function(){},onStop:function(){}};if("undefined"!=typeof a)d.renderer=a;else{if("undefined"==typeof SVGRenderer)throw new Error("Please load either the SVG- or the CanvasRenderer");d.renderer=SVGRenderer}var e={},f=0,g=function(){this.el=b,this.options=e;for(var a in d)d.hasOwnProperty(a)&&(e[a]=c&&"undefined"!=typeof c[a]?c[a]:d[a],"function"==typeof e[a]&&(e[a]=e[a].bind(this)));e.easing="string"==typeof e.easing&&"undefined"!=typeof jQuery&&jQuery.isFunction(jQuery.easing[e.easing])?jQuery.easing[e.easing]:d.easing,"number"==typeof e.animate&&(e.animate={duration:e.animate,enabled:!0}),"boolean"!=typeof e.animate||e.animate||(e.animate={duration:1e3,enabled:e.animate}),this.renderer=new e.renderer(b,e),this.renderer.draw(f),b.dataset&&b.dataset.percent?this.update(parseFloat(b.dataset.percent)):b.getAttribute&&b.getAttribute("data-percent")&&this.update(parseFloat(b.getAttribute("data-percent")))}.bind(this);this.update=function(a){return a=parseFloat(a),e.animate.enabled?this.renderer.animate(f,a):this.renderer.draw(a),f=a,this}.bind(this),this.disableAnimation=function(){return e.animate.enabled=!1,this},this.enableAnimation=function(){return e.animate.enabled=!0,this},g()};return b});

View File

@@ -0,0 +1,360 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
(function(root, factory) {
if(typeof exports === 'object') {
module.exports = factory(require('jquery'));
}
else if(typeof define === 'function' && define.amd) {
define(['jquery'], factory);
}
else {
factory(root.jQuery);
}
}(this, function($) {
/**
* Renderer to render the chart on a canvas object
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
* @param {object} options options object of the plugin
*/
var CanvasRenderer = function(el, options) {
var cachedBackground;
var canvas = document.createElement('canvas');
el.appendChild(canvas);
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
// canvas on retina devices
var scaleBy = 1;
if (window.devicePixelRatio > 1) {
scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
canvas.width = canvas.height = options.size * scaleBy;
ctx.scale(scaleBy, scaleBy);
}
// move 0,0 coordinates to the center
ctx.translate(options.size / 2, options.size / 2);
// rotate canvas -90deg
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
var radius = (options.size - options.lineWidth) / 2;
if (options.scaleColor && options.scaleLength) {
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
}
// IE polyfill for Date
Date.now = Date.now || function() {
return +(new Date());
};
/**
* Draw a circle around the center of the canvas
* @param {strong} color Valid CSS color string
* @param {number} lineWidth Width of the line in px
* @param {number} percent Percentage to draw (float between -1 and 1)
*/
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(-1, percent || 0), 1);
var isNegative = percent <= 0 ? true : false;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.stroke();
};
/**
* Draw the scale of the chart
*/
var drawScale = function() {
var offset;
var length;
ctx.lineWidth = 1;
ctx.fillStyle = options.scaleColor;
ctx.save();
for (var i = 24; i > 0; --i) {
if (i % 6 === 0) {
length = options.scaleLength;
offset = 0;
} else {
length = options.scaleLength * 0.6;
offset = options.scaleLength - length;
}
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
ctx.rotate(Math.PI / 12);
}
ctx.restore();
};
/**
* Request animation frame wrapper with polyfill
* @return {function} Request animation frame method or timeout fallback
*/
var reqAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
/**
* Draw the background of the plugin including the scale and the track
*/
var drawBackground = function() {
if(options.scaleColor) drawScale();
if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
};
/**
* Canvas accessor
*/
this.getCanvas = function() {
return canvas;
};
/**
* Canvas 2D context 'ctx' accessor
*/
this.getCtx = function() {
return ctx;
};
/**
* Clear the complete canvas
*/
this.clear = function() {
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
};
/**
* Draw the complete chart
* @param {number} percent Percent shown by the chart between -100 and 100
*/
this.draw = function(percent) {
// do we need to render a background
if (!!options.scaleColor || !!options.trackColor) {
// getImageData and putImageData are supported
if (ctx.getImageData && ctx.putImageData) {
if (!cachedBackground) {
drawBackground();
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
} else {
ctx.putImageData(cachedBackground, 0, 0);
}
} else {
this.clear();
drawBackground();
}
} else {
this.clear();
}
ctx.lineCap = options.lineCap;
// if barcolor is a function execute it and pass the percent as a value
var color;
if (typeof(options.barColor) === 'function') {
color = options.barColor(percent);
} else {
color = options.barColor;
}
// draw bar
drawCircle(color, options.lineWidth, percent / 100);
}.bind(this);
/**
* Animate from some percent to some other percentage
* @param {number} from Starting percentage
* @param {number} to Final percentage
*/
this.animate = function(from, to) {
var startTime = Date.now();
options.onStart(from, to);
var animation = function() {
var process = Math.min(Date.now() - startTime, options.animate.duration);
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
this.draw(currentValue);
options.onStep(from, to, currentValue);
if (process >= options.animate.duration) {
options.onStop(from, to);
} else {
reqAnimationFrame(animation);
}
}.bind(this);
reqAnimationFrame(animation);
}.bind(this);
};
var EasyPieChart = function(el, opts) {
var defaultOptions = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
trackWidth: undefined,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
},
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
t = t / (d/2);
if (t < 1) {
return c / 2 * t * t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
onStart: function(from, to) {
return;
},
onStep: function(from, to, currentValue) {
return;
},
onStop: function(from, to) {
return;
}
};
// detect present renderer
if (typeof(CanvasRenderer) !== 'undefined') {
defaultOptions.renderer = CanvasRenderer;
} else if (typeof(SVGRenderer) !== 'undefined') {
defaultOptions.renderer = SVGRenderer;
} else {
throw new Error('Please load either the SVG- or the CanvasRenderer');
}
var options = {};
var currentValue = 0;
/**
* Initialize the plugin by creating the options object and initialize rendering
*/
var init = function() {
this.el = el;
this.options = options;
// merge user options into default options
for (var i in defaultOptions) {
if (defaultOptions.hasOwnProperty(i)) {
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
if (typeof(options[i]) === 'function') {
options[i] = options[i].bind(this);
}
}
}
// check for jQuery easing
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
options.easing = jQuery.easing[options.easing];
} else {
options.easing = defaultOptions.easing;
}
// process earlier animate option to avoid bc breaks
if (typeof(options.animate) === 'number') {
options.animate = {
duration: options.animate,
enabled: true
};
}
if (typeof(options.animate) === 'boolean' && !options.animate) {
options.animate = {
duration: 1000,
enabled: options.animate
};
}
// create renderer
this.renderer = new options.renderer(el, options);
// initial draw
this.renderer.draw(currentValue);
// initial update
if (el.dataset && el.dataset.percent) {
this.update(parseFloat(el.dataset.percent));
} else if (el.getAttribute && el.getAttribute('data-percent')) {
this.update(parseFloat(el.getAttribute('data-percent')));
}
}.bind(this);
/**
* Update the value of the chart
* @param {number} newValue Number between 0 and 100
* @return {object} Instance of the plugin for method chaining
*/
this.update = function(newValue) {
newValue = parseFloat(newValue);
if (options.animate.enabled) {
this.renderer.animate(currentValue, newValue);
} else {
this.renderer.draw(newValue);
}
currentValue = newValue;
return this;
}.bind(this);
/**
* Disable animation
* @return {object} Instance of the plugin for method chaining
*/
this.disableAnimation = function() {
options.animate.enabled = false;
return this;
};
/**
* Enable animation
* @return {object} Instance of the plugin for method chaining
*/
this.enableAnimation = function() {
options.animate.enabled = true;
return this;
};
init();
};
$.fn.easyPieChart = function(options) {
return this.each(function() {
var instanceOptions;
if (!$.data(this, 'easyPieChart')) {
instanceOptions = $.extend({}, options, $(this).data());
$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
}
});
};
}));

View File

@@ -0,0 +1,9 @@
/**!
* easyPieChart
* Lightweight plugin to render simple, animated and retina optimized pie charts
*
* @license
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
* @version 2.1.6
**/
!function(a,b){"object"==typeof exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],b):b(a.jQuery)}(this,function(a){var b=function(a,b){var c,d=document.createElement("canvas");a.appendChild(d),"undefined"!=typeof G_vmlCanvasManager&&G_vmlCanvasManager.initElement(d);var e=d.getContext("2d");d.width=d.height=b.size;var f=1;window.devicePixelRatio>1&&(f=window.devicePixelRatio,d.style.width=d.style.height=[b.size,"px"].join(""),d.width=d.height=b.size*f,e.scale(f,f)),e.translate(b.size/2,b.size/2),e.rotate((-0.5+b.rotate/180)*Math.PI);var g=(b.size-b.lineWidth)/2;b.scaleColor&&b.scaleLength&&(g-=b.scaleLength+2),Date.now=Date.now||function(){return+new Date};var h=function(a,b,c){c=Math.min(Math.max(-1,c||0),1);var d=0>=c?!0:!1;e.beginPath(),e.arc(0,0,g,0,2*Math.PI*c,d),e.strokeStyle=a,e.lineWidth=b,e.stroke()},i=function(){var a,c;e.lineWidth=1,e.fillStyle=b.scaleColor,e.save();for(var d=24;d>0;--d)d%6===0?(c=b.scaleLength,a=0):(c=.6*b.scaleLength,a=b.scaleLength-c),e.fillRect(-b.size/2+a,0,c,1),e.rotate(Math.PI/12);e.restore()},j=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),k=function(){b.scaleColor&&i(),b.trackColor&&h(b.trackColor,b.trackWidth||b.lineWidth,1)};this.getCanvas=function(){return d},this.getCtx=function(){return e},this.clear=function(){e.clearRect(b.size/-2,b.size/-2,b.size,b.size)},this.draw=function(a){b.scaleColor||b.trackColor?e.getImageData&&e.putImageData?c?e.putImageData(c,0,0):(k(),c=e.getImageData(0,0,b.size*f,b.size*f)):(this.clear(),k()):this.clear(),e.lineCap=b.lineCap;var d;d="function"==typeof b.barColor?b.barColor(a):b.barColor,h(d,b.lineWidth,a/100)}.bind(this),this.animate=function(a,c){var d=Date.now();b.onStart(a,c);var e=function(){var f=Math.min(Date.now()-d,b.animate.duration),g=b.easing(this,f,a,c-a,b.animate.duration);this.draw(g),b.onStep(a,c,g),f>=b.animate.duration?b.onStop(a,c):j(e)}.bind(this);j(e)}.bind(this)},c=function(a,c){var d={barColor:"#ef1e25",trackColor:"#f9f9f9",scaleColor:"#dfe0e0",scaleLength:5,lineCap:"round",lineWidth:3,trackWidth:void 0,size:110,rotate:0,animate:{duration:1e3,enabled:!0},easing:function(a,b,c,d,e){return b/=e/2,1>b?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},onStart:function(){},onStep:function(){},onStop:function(){}};if("undefined"!=typeof b)d.renderer=b;else{if("undefined"==typeof SVGRenderer)throw new Error("Please load either the SVG- or the CanvasRenderer");d.renderer=SVGRenderer}var e={},f=0,g=function(){this.el=a,this.options=e;for(var b in d)d.hasOwnProperty(b)&&(e[b]=c&&"undefined"!=typeof c[b]?c[b]:d[b],"function"==typeof e[b]&&(e[b]=e[b].bind(this)));e.easing="string"==typeof e.easing&&"undefined"!=typeof jQuery&&jQuery.isFunction(jQuery.easing[e.easing])?jQuery.easing[e.easing]:d.easing,"number"==typeof e.animate&&(e.animate={duration:e.animate,enabled:!0}),"boolean"!=typeof e.animate||e.animate||(e.animate={duration:1e3,enabled:e.animate}),this.renderer=new e.renderer(a,e),this.renderer.draw(f),a.dataset&&a.dataset.percent?this.update(parseFloat(a.dataset.percent)):a.getAttribute&&a.getAttribute("data-percent")&&this.update(parseFloat(a.getAttribute("data-percent")))}.bind(this);this.update=function(a){return a=parseFloat(a),e.animate.enabled?this.renderer.animate(f,a):this.renderer.draw(a),f=a,this}.bind(this),this.disableAnimation=function(){return e.animate.enabled=!1,this},this.enableAnimation=function(){return e.animate.enabled=!0,this},g()};a.fn.easyPieChart=function(b){return this.each(function(){var d;a.data(this,"easyPieChart")||(d=a.extend({},b,a(this).data()),a.data(this,"easyPieChart",new c(this,d)))})}});

View File

@@ -0,0 +1,32 @@
# {%= name %}
> {%= description %}
{%= _.doc('bagdes.md') %}
## Features
{%= _.doc("features.md") %}
## Get started
{%= _.doc("get-started.md") %}
## Options
{%= _.doc("options.md") %}
## Callbacks
{%= _.doc("callbacks.md") %}
## Plugin api
{%= _.doc("plugin-api.md") %}
## Browser Support
{%= _.doc("browser-support.md") %}
## Test
{%= _.doc("test.md") %}
## Credits
{%= _.doc("credits.md") %}
## Copyright
{%= copyright %} {%= license %}

View File

@@ -0,0 +1,4 @@
![Version](http://img.shields.io/version/{%= version %}.png?color=green)
[![Build Status](https://travis-ci.org/rendro/easy-pie-chart.png)](https://travis-ci.org/rendro/easy-pie-chart)
[![Dependencies Status](https://david-dm.org/rendro/easy-pie-chart/dev-status.png)](https://david-dm.org/rendro/easy-pie-chart)
[![Analytics](https://ga-beacon.appspot.com/UA-46840672-1/easy-pie-chart/readme)](https://github.com/igrigorik/ga-beacon)

View File

@@ -0,0 +1,9 @@
Native support
* Chrome
* Safari
* FireFox
* Opera
* Internet Explorer 9+
Support for Internet Explorer 7 and 8 with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions) polyfill.

View File

@@ -0,0 +1,20 @@
All callbacks will only be called if `animate` is not `false`.
<table>
<tr>
<th>Callback(params, ...)</th>
<th>Description</th>
</tr>
<tr>
<td><strong>onStart(from, to)</strong></td>
<td>Is called at the start of any animation.</td>
</tr>
<tr>
<td><strong>onStep(from, to, currentValue)</strong></td>
<td>Is called during animations providing the current value (the method is scoped to the context of th eplugin, so you can access the DOM element via <code>this.el</code>).</td>
</tr>
<tr>
<td><strong>onStop(from, to)</strong></td>
<td>Is called at the end of any animation.</td>
</tr>
</table>

View File

@@ -0,0 +1 @@
Thanks to [Rafal Bromirski](http://www.paranoida.com/) for designing [this dribble shot](http://drbl.in/ezuc) which inspired me building this plugin.

View File

@@ -0,0 +1,13 @@
[![](https://github.com/rendro/easy-pie-chart/raw/master/demo/img/easy-pie-chart.png)](http://drbl.in/ezuc)
* highly customizable
* very easy to implement
* resolution independent (retina optimized)
* uses `requestAnimationFrame` for smooth animations on modern devices and
* works in all modern browsers, even in IE7+ with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions)
### framework support
* Vanilla JS *(no dependencies)* (~872 bytes)
* jQuery plugin (~921 bytes)
* Angular Module (~983 bytes)

View File

@@ -0,0 +1,68 @@
### Installation
You can also use [bower](http://bower.io) to install the component:
```
$ bower install jquery.easy-pie-chart
```
### jQuery
To use the easy pie chart plugin you need to load the current version of jQuery (> 1.6.4) and the source of the plugin.
```html
<div class="chart" data-percent="73" data-scale-color="#ffb400">73%</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="/path/to/jquery.easy-pie-chart.js"></script>
<script>
$(function() {
$('.chart').easyPieChart({
//your options goes here
});
});
</script>
```
### Vanilla JS
If you don't want to use jQuery, implement the Vanilla JS version without any dependencies.
```html
<div class="chart" data-percent="73">73%</div>
<script src="/path/to/easy-pie-chart.js"></script>
<script>
var element = document.querySelector('.chart');
new EasyPieChart(element, {
// your options goes here
});
</script>
```
### AngularJS
```html
<div ng-controller="chartCtrl">
<div easypiechart options="options" percent="percent"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="../dist/angular.easypiechart.min.js"></script>
<script>
var app = angular.module('app', ['easypiechart']);
app.controller('chartCtrl', ['$scope', function ($scope) {
$scope.percent = 65;
$scope.options = {
animate:{
duration:0,
enabled:false
},
barColor:'#2C3E50',
scaleColor:false,
lineWidth:20,
lineCap:'circle'
};
}]);
</script>
```

View File

@@ -0,0 +1,59 @@
You can pass these options to the initialize function to set a custom look and feel for the plugin.
<table>
<tr>
<th>Property (Type)</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td><strong>barColor</strong></td>
<td>#ef1e25</td>
<td>The color of the curcular bar. You can either pass a valid css color string, or a function that takes the current percentage as a value and returns a valid css color string.</td>
</tr>
<tr>
<td><strong>trackColor</strong></td>
<td>#f2f2f2</td>
<td>The color of the track, or false to disable rendering.</td>
</tr>
<tr>
<td><strong>scaleColor</strong></td>
<td>#dfe0e0</td>
<td>The color of the scale lines, false to disable rendering.</td>
</tr>
<tr>
<td><strong>scaleLength</strong></td>
<td>5</td>
<td>Length of the scale lines (reduces the radius of the chart).</td>
</tr>
<tr>
<td><strong>lineCap</strong></td>
<td>round</td>
<td>Defines how the ending of the bar line looks like. Possible values are: <code>butt</code>, <code>round</code> and <code>square</code>.</td>
</tr>
<tr>
<td><strong>lineWidth</strong></td>
<td>3</td>
<td>Width of the chart line in px.</td>
</tr>
<tr>
<td><strong>size</strong></td>
<td>110</td>
<td>Size of the pie chart in px. It will always be a square.</td>
</tr>
<tr>
<td><strong>rotate</strong></td>
<td>0</td>
<td>Rotation of the complete chart in degrees.</td>
</tr>
<tr>
<td><strong>animate</strong></td>
<td>object</td>
<td>Object with time in milliseconds and boolean for an animation of the bar growing (<code>{ duration: 1000, enabled: true }</code>), or false to deactivate animations.</td>
</tr>
<tr>
<td><strong>easing</strong></td>
<td>defaultEasing</td>
<td>Easing function or string with the name of a <a href="http://gsgd.co.uk/sandbox/jquery/easing/" target="_blank">jQuery easing function</a></td>
</tr>
</table>

View File

@@ -0,0 +1,52 @@
### jQuery
```javascript
$(function() {
// instantiate the plugin
...
// update
$('.chart').data('easyPieChart').update(40);
...
// disable animation
$('.chart').data('easyPieChart').disableAnimation();
...
// enable animation
$('.chart').data('easyPieChart').enableAnimation();
});
```
### Vanilla JS
```javascript
// instantiate the plugin
var chart = new EasyPieChart(element, options);
// update
chart.update(40);
// disable animation
chart.disableAnimation();
// enable animation
chart.enableAnimation();
```
##### Using a gradient
```javascript
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop(0, "#ffe57e");
gradient.addColorStop(1, "#de5900");
return gradient;
}
});
```
### AngularJS
For a value binding you need to add the `percent` attribute and bind it to your controller.
### RequireJS
When using [RequireJS](http://requirejs.org) you can define your own name. Examples can be found in the `demo/requirejs.html`.

View File

@@ -0,0 +1 @@
To run the test just use the karma adapter of grunt: `grunt test`

View File

@@ -0,0 +1,53 @@
# Karma configuration
# http://karma-runner.github.io/0.10/config/configuration-file.html
module.exports = (config) ->
config.set
# base path, that will be used to resolve files and exclude
basePath: ''
# testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine']
# list of files / patterns to load in the browser
files: [
'test/polyfills/bind.js'
'bower_components/jquery/dist/jquery.js'
'bower_components/angular/angular.js'
'bower_components/angular-mocks/angular-mocks.js'
'src/renderer/canvas.js'
'src/easypiechart.js'
'src/jquery.plugin.js'
'src/angular.directive.js'
'test/**/*.js'
]
# list of files / patterns to exclude
exclude: []
# web server port
port: 8080
# level of logging
# possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO
# enable / disable watching file and executing tests whenever any file changes
autoWatch: true
# reporters
reporters: ['progress', 'dots']
# Start these browsers, currently available:
# - Chrome
# - ChromeCanary
# - Firefox
# - Opera
# - Safari (only Mac)
# - PhantomJS
# - IE (only Windows)
browsers: ['Chrome']
# Continuous Integration mode
# if true, it capture browsers, run tests and exit
singleRun: false

View File

@@ -0,0 +1,51 @@
{
"name": "easyPieChart",
"description": "Lightweight plugin to render simple, animated and retina optimized pie charts",
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
},
{
"type": "GPL",
"url": "http://www.opensource.org/licenses/gpl-license.php"
}
],
"version": "2.1.6",
"author": {
"name": "Robert Fleischmann",
"email": "rendro87@gmail.com",
"url": "http://robert-fleischmann.de"
},
"scripts": {
"test": "grunt karma:ci"
},
"repository": {
"type": "git",
"url": "https://github.com/rendro/easy-pie-chart.git"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "~0.4.0",
"grunt-banner": "~0.2.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-less": "~0.11.0",
"grunt-contrib-jshint": "~0.10.0",
"karma-script-launcher": "~0.1.0",
"karma-firefox-launcher": "~0.1.0",
"karma-chrome-launcher": "~0.1.0",
"karma-html2js-preprocessor": "~0.1.0",
"karma-jasmine": "~0.1.3",
"karma-requirejs": "~0.2.1",
"karma-coffee-preprocessor": "~0.2.1",
"karma-phantomjs-launcher": "~0.1.0",
"karma": "~0.12.14",
"grunt-karma": "~0.8.3",
"grunt-umd": "~1.7.3",
"requirejs": "~2.1.10",
"grunt-readme": "~0.4.5",
"load-grunt-tasks": "~0.4.0"
}
}

View File

@@ -0,0 +1,48 @@
(function (angular) {
'use strict';
return angular.module('easypiechart', [])
.directive('easypiechart', [function() {
return {
restrict: 'A',
require: '?ngModel',
scope: {
percent: '=',
options: '='
},
link: function (scope, element, attrs) {
scope.percent = scope.percent || 0;
/**
* default easy pie chart options
* @type {Object}
*/
var options = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
}
};
scope.options = angular.extend(options, scope.options);
var pieChart = new EasyPieChart(element[0], options);
scope.$watch('percent', function(newVal, oldVal) {
pieChart.update(newVal);
});
}
};
}]);
})(angular);

View File

@@ -0,0 +1,134 @@
var EasyPieChart = function(el, opts) {
var defaultOptions = {
barColor: '#ef1e25',
trackColor: '#f9f9f9',
scaleColor: '#dfe0e0',
scaleLength: 5,
lineCap: 'round',
lineWidth: 3,
trackWidth: undefined,
size: 110,
rotate: 0,
animate: {
duration: 1000,
enabled: true
},
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
t = t / (d/2);
if (t < 1) {
return c / 2 * t * t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
onStart: function(from, to) {
return;
},
onStep: function(from, to, currentValue) {
return;
},
onStop: function(from, to) {
return;
}
};
// detect present renderer
if (typeof(CanvasRenderer) !== 'undefined') {
defaultOptions.renderer = CanvasRenderer;
} else if (typeof(SVGRenderer) !== 'undefined') {
defaultOptions.renderer = SVGRenderer;
} else {
throw new Error('Please load either the SVG- or the CanvasRenderer');
}
var options = {};
var currentValue = 0;
/**
* Initialize the plugin by creating the options object and initialize rendering
*/
var init = function() {
this.el = el;
this.options = options;
// merge user options into default options
for (var i in defaultOptions) {
if (defaultOptions.hasOwnProperty(i)) {
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
if (typeof(options[i]) === 'function') {
options[i] = options[i].bind(this);
}
}
}
// check for jQuery easing
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
options.easing = jQuery.easing[options.easing];
} else {
options.easing = defaultOptions.easing;
}
// process earlier animate option to avoid bc breaks
if (typeof(options.animate) === 'number') {
options.animate = {
duration: options.animate,
enabled: true
};
}
if (typeof(options.animate) === 'boolean' && !options.animate) {
options.animate = {
duration: 1000,
enabled: options.animate
};
}
// create renderer
this.renderer = new options.renderer(el, options);
// initial draw
this.renderer.draw(currentValue);
// initial update
if (el.dataset && el.dataset.percent) {
this.update(parseFloat(el.dataset.percent));
} else if (el.getAttribute && el.getAttribute('data-percent')) {
this.update(parseFloat(el.getAttribute('data-percent')));
}
}.bind(this);
/**
* Update the value of the chart
* @param {number} newValue Number between 0 and 100
* @return {object} Instance of the plugin for method chaining
*/
this.update = function(newValue) {
newValue = parseFloat(newValue);
if (options.animate.enabled) {
this.renderer.animate(currentValue, newValue);
} else {
this.renderer.draw(newValue);
}
currentValue = newValue;
return this;
}.bind(this);
/**
* Disable animation
* @return {object} Instance of the plugin for method chaining
*/
this.disableAnimation = function() {
options.animate.enabled = false;
return this;
};
/**
* Enable animation
* @return {object} Instance of the plugin for method chaining
*/
this.enableAnimation = function() {
options.animate.enabled = true;
return this;
};
init();
};

View File

@@ -0,0 +1,10 @@
$.fn.easyPieChart = function(options) {
return this.each(function() {
var instanceOptions;
if (!$.data(this, 'easyPieChart')) {
instanceOptions = $.extend({}, options, $(this).data());
$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
}
});
};

View File

@@ -0,0 +1,190 @@
/**
* Renderer to render the chart on a canvas object
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
* @param {object} options options object of the plugin
*/
var CanvasRenderer = function(el, options) {
var cachedBackground;
var canvas = document.createElement('canvas');
el.appendChild(canvas);
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
// canvas on retina devices
var scaleBy = 1;
if (window.devicePixelRatio > 1) {
scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
canvas.width = canvas.height = options.size * scaleBy;
ctx.scale(scaleBy, scaleBy);
}
// move 0,0 coordinates to the center
ctx.translate(options.size / 2, options.size / 2);
// rotate canvas -90deg
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
var radius = (options.size - options.lineWidth) / 2;
if (options.scaleColor && options.scaleLength) {
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
}
// IE polyfill for Date
Date.now = Date.now || function() {
return +(new Date());
};
/**
* Draw a circle around the center of the canvas
* @param {strong} color Valid CSS color string
* @param {number} lineWidth Width of the line in px
* @param {number} percent Percentage to draw (float between -1 and 1)
*/
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(-1, percent || 0), 1);
var isNegative = percent <= 0 ? true : false;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.stroke();
};
/**
* Draw the scale of the chart
*/
var drawScale = function() {
var offset;
var length;
ctx.lineWidth = 1;
ctx.fillStyle = options.scaleColor;
ctx.save();
for (var i = 24; i > 0; --i) {
if (i % 6 === 0) {
length = options.scaleLength;
offset = 0;
} else {
length = options.scaleLength * 0.6;
offset = options.scaleLength - length;
}
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
ctx.rotate(Math.PI / 12);
}
ctx.restore();
};
/**
* Request animation frame wrapper with polyfill
* @return {function} Request animation frame method or timeout fallback
*/
var reqAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
/**
* Draw the background of the plugin including the scale and the track
*/
var drawBackground = function() {
if(options.scaleColor) drawScale();
if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
};
/**
* Canvas accessor
*/
this.getCanvas = function() {
return canvas;
};
/**
* Canvas 2D context 'ctx' accessor
*/
this.getCtx = function() {
return ctx;
};
/**
* Clear the complete canvas
*/
this.clear = function() {
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
};
/**
* Draw the complete chart
* @param {number} percent Percent shown by the chart between -100 and 100
*/
this.draw = function(percent) {
// do we need to render a background
if (!!options.scaleColor || !!options.trackColor) {
// getImageData and putImageData are supported
if (ctx.getImageData && ctx.putImageData) {
if (!cachedBackground) {
drawBackground();
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
} else {
ctx.putImageData(cachedBackground, 0, 0);
}
} else {
this.clear();
drawBackground();
}
} else {
this.clear();
}
ctx.lineCap = options.lineCap;
// if barcolor is a function execute it and pass the percent as a value
var color;
if (typeof(options.barColor) === 'function') {
color = options.barColor(percent);
} else {
color = options.barColor;
}
// draw bar
drawCircle(color, options.lineWidth, percent / 100);
}.bind(this);
/**
* Animate from some percent to some other percentage
* @param {number} from Starting percentage
* @param {number} to Final percentage
*/
this.animate = function(from, to) {
var startTime = Date.now();
options.onStart(from, to);
var animation = function() {
var process = Math.min(Date.now() - startTime, options.animate.duration);
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
this.draw(currentValue);
options.onStep(from, to, currentValue);
if (process >= options.animate.duration) {
options.onStop(from, to);
} else {
reqAnimationFrame(animation);
}
}.bind(this);
reqAnimationFrame(animation);
}.bind(this);
};