<!doctype html>
<html>
- <head>
- <title>Polar Area Chart</title>
- <script src="../Chart.js"></script>
- <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
- </head>
- <body>
- <div id="canvas-holder" style="width:30%">
- <canvas id="chart-area" width="300" height="300"/>
- </div>
- <button id="randomizeData">Randomize Data</button>
+<head>
+ <title>Polar Area Chart</title>
+ <script src="../Chart.js"></script>
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+</head>
- <script>
+<body>
+ <div id="canvas-holder" style="width:100%">
+ <canvas id="chart-area" width="300" height="300" />
+ </div>
+ <button id="randomizeData">Randomize Data</button>
+ <script>
+ var randomScalingFactor = function() {
+ return Math.round(Math.random() * 100);
+ };
+ var randomColorFactor = function() {
+ return Math.round(Math.random() * 255);
+ };
- var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
- var randomColorFactor = function(){ return Math.round(Math.random()*255)};
+ var config = {
+ data: {
+ data: [{
+ value: randomScalingFactor(),
+ backgroundColor: "#F7464A",
+ label: "Red"
+ }, {
+ value: randomScalingFactor(),
+ backgroundColor: "#46BFBD",
+ label: "Green"
+ }, {
+ value: randomScalingFactor(),
+ backgroundColor: "#FDB45C",
+ label: "Yellow"
+ }, {
+ value: randomScalingFactor(),
+ backgroundColor: "#949FB1",
+ label: "Grey"
+ }, {
+ value: randomScalingFactor(),
+ backgroundColor: "#4D5360",
+ label: "Dark Grey"
+ }]
+ },
+ options: {
+ responsive: true
+ }
+ };
- var polarData = [
- {
- value: randomScalingFactor(),
- color:"#F7464A",
- highlight: "#FF5A5E",
- label: "Red"
- },
- {
- value: randomScalingFactor(),
- color: "#46BFBD",
- highlight: "#5AD3D1",
- label: "Green"
- },
- {
- value: randomScalingFactor(),
- color: "#FDB45C",
- highlight: "#FFC870",
- label: "Yellow"
- },
- {
- value: randomScalingFactor(),
- color: "#949FB1",
- highlight: "#A8B3C5",
- label: "Grey"
- },
- {
- value: randomScalingFactor(),
- color: "#4D5360",
- highlight: "#616774",
- label: "Dark Grey"
- }
+ window.onload = function() {
+ var ctx = document.getElementById("chart-area").getContext("2d");
+ window.myPolarArea = new Chart(ctx).PolarArea(config);
+ };
- ];
+ $('#randomizeData').click(function() {
+ $.each(polarData, function(i, piece) {
+ polarData[i].value = randomScalingFactor();
+ polarData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
+ });
+ window.myPolarArea.update();
+ });
+ </script>
+</body>
- window.onload = function(){
- var ctx = document.getElementById("chart-area").getContext("2d");
- window.myPolarArea = new Chart(ctx).PolarArea({
- data: polarData,
- options: {
- responsive:true
- }
- });
- };
-
- $('#randomizeData').click(function(){
- $.each(polarData, function(i, piece){
- polarData[i].value = randomScalingFactor();
- polarData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
- });
- window.myPolarArea.update();
- });
-
-
-
- </script>
- </body>
</html>
-(function(){
- "use strict";
+(function() {
+ "use strict";
- var root = this,
- Chart = root.Chart,
- //Cache a local reference to Chart.helpers
- helpers = Chart.helpers;
+ var root = this,
+ Chart = root.Chart,
+ //Cache a local reference to Chart.helpers
+ helpers = Chart.helpers;
- var defaultConfig = {
- //Boolean - Stroke a line around each segment in the chart
- segmentShowStroke : true,
+ var defaultConfig = {
- //String - The colour of the stroke on each segment.
- segmentStrokeColor : "#fff",
+ segment: {
+ //String - The colour of the border on each segment.
+ borderColor: "#fff",
- //Number - The width of the stroke value in pixels
- segmentStrokeWidth : 2,
+ //Number - The width of the border value in pixels
+ borderWidth: 2,
+ },
- scale: {
- scaleType: "radialLinear",
- display: true,
-
- //Boolean - Whether to animate scaling the chart from the centre
- animate : false,
+ scale: {
+ scaleType: "radialLinear",
+ display: true,
+
+ //Boolean - Whether to animate scaling the chart from the centre
+ animate: false,
+
+ lineArc: true,
- lineArc: true,
-
// grid line settings
gridLines: {
show: true,
fontColor: "#666",
fontFamily: "Helvetica Neue",
- //Boolean - Show a backdrop to the scale label
- showLabelBackdrop : true,
+ //Boolean - Show a backdrop to the scale label
+ showLabelBackdrop: true,
- //String - The colour of the label backdrop
- backdropColor : "rgba(255,255,255,0.75)",
+ //String - The colour of the label backdrop
+ backdropColor: "rgba(255,255,255,0.75)",
- //Number - The backdrop padding above & below the label in pixels
- backdropPaddingY : 2,
+ //Number - The backdrop padding above & below the label in pixels
+ backdropPaddingY: 2,
- //Number - The backdrop padding to the side of the label in pixels
- backdropPaddingX : 2,
+ //Number - The backdrop padding to the side of the label in pixels
+ backdropPaddingX: 2,
}
- },
-
- //Number - Amount of animation steps
- animationSteps : 100,
-
- //String - Animation easing effect.
- animationEasing : "easeOutBounce",
-
- //Boolean - Whether to animate the rotation of the chart
- animateRotate : true,
-
- //String - A legend template
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
- };
-
-
- Chart.Type.extend({
- //Passing in a name registers this chart in the Chart namespace
- name: "PolarArea",
- //Providing a defaults will also register the deafults in the chart namespace
- defaults : defaultConfig,
- //Initialize is fired when the chart is initialized - Data is passed in as a parameter
- //Config is automatically merged by the core of Chart.js, and is available at this.options
- initialize: function(){
- this.segments = [];
- //Declare segment class as a chart instance specific class, so it can share props for this instance
- this.SegmentArc = Chart.Arc.extend({
- showStroke : this.options.segmentShowStroke,
- strokeWidth : this.options.segmentStrokeWidth,
- strokeColor : this.options.segmentStrokeColor,
- ctx : this.chart.ctx,
- innerRadius : 0,
- x : this.chart.width/2,
- y : this.chart.height/2
- });
-
- var self = this;
- var ScaleClass = Chart.scales.getScaleConstructor(this.options.scale.scaleType);
- this.scale = new ScaleClass({
- options: this.options.scale,
- lineArc: true,
- width: this.chart.width,
- height: this.chart.height,
- xCenter: this.chart.width/2,
- yCenter: this.chart.height/2,
- ctx : this.chart.ctx,
- valuesCount: this.data.length,
- calculateRange: function() {
- this.min = null;
- this.max = null;
-
- helpers.each(self.data, function(data) {
+ },
+
+ //Boolean - Whether to animate the rotation of the chart
+ animateRotate: true,
+
+ //String - A legend template
+ legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
+ };
+
+
+ Chart.Type.extend({
+ //Passing in a name registers this chart in the Chart namespace
+ name: "PolarArea",
+ //Providing a defaults will also register the deafults in the chart namespace
+ defaults: defaultConfig,
+ //Initialize is fired when the chart is initialized - Data is passed in as a parameter
+ //Config is automatically merged by the core of Chart.js, and is available at this.options
+ initialize: function() {
+
+ // Scale setup
+ var self = this;
+ var ScaleClass = Chart.scales.getScaleConstructor(this.options.scale.scaleType);
+ this.scale = new ScaleClass({
+ options: this.options.scale,
+ lineArc: true,
+ width: this.chart.width,
+ height: this.chart.height,
+ xCenter: this.chart.width / 2,
+ yCenter: this.chart.height / 2,
+ ctx: this.chart.ctx,
+ valuesCount: this.data.length,
+ calculateRange: function() {
+ this.min = null;
+ this.max = null;
+
+ helpers.each(self.data.data, function(data) {
if (this.min === null) {
this.min = data.value;
} else if (data.value < this.min) {
this.min = data.value;
}
-
+
if (this.max === null) {
this.max = data.value;
} else if (data.value > this.max) {
this.max = data.value;
}
}, this);
- }
- });
-
- this.updateScaleRange();
- this.scale.calculateRange();
- this.scale.generateTicks();
- this.scale.buildYLabels();
-
- helpers.each(this.data,function(segment,index){
- this.addData(segment,index,true);
- },this);
-
- //Set up tooltip events on the chart
- if (this.options.showTooltips){
- helpers.bindEvents(this, this.options.events, function(evt){
- var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
- helpers.each(this.segments,function(segment){
- segment.restore(["fillColor"]);
- });
-
- helpers.each(activeSegments,function(activeSegment){
- activeSegment.fillColor = activeSegment.highlightColor;
- });
-
- this.showTooltip(activeSegments);
- });
- }
-
- this.render();
- },
- getSegmentsAtEvent : function(e){
- var segmentsArray = [];
- var location = helpers.getRelativePosition(e);
-
- helpers.each(this.segments,function(segment){
- if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
- },this);
-
- return segmentsArray;
- },
- addData : function(segment, atIndex, silent){
- var index = atIndex || this.segments.length;
-
- this.segments.splice(index, 0, new this.SegmentArc({
- fillColor: segment.color,
- highlightColor: segment.highlight || segment.color,
- label: segment.label,
- value: segment.value,
- outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
- circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
- startAngle: Math.PI * 1.5
- }));
- if (!silent){
- this.reflow();
- this.update();
- }
- },
- removeData: function(atIndex){
- var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
- this.segments.splice(indexToDelete, 1);
- this.reflow();
- this.update();
- },
- calculateTotal: function(data){
- this.total = 0;
- helpers.each(data,function(segment){
- this.total += segment.value;
- },this);
- this.scale.valuesCount = this.segments.length;
- },
- updateScaleRange: function(){
- helpers.extend(this.scale, {
- size: helpers.min([this.chart.width, this.chart.height]),
- xCenter: this.chart.width/2,
- yCenter: this.chart.height/2
- });
-
- },
- update : function(){
-
- // Map new data to data points
- if(this.data.length == this.segments.length){
- helpers.each(this.data, function(segment, i){
- helpers.extend(this.segments[i], {
- fillColor: segment.color,
- highlightColor: segment.highlight || segment.color,
- label: segment.label,
- value: segment.value,
- });
- },this);
- } else{
- // Data size changed without properly inserting, just redraw the chart
- this.initialize(this.data);
- }
-
- this.calculateTotal(this.segments);
-
- helpers.each(this.segments,function(segment){
- segment.save();
- });
-
- this.reflow();
- this.render();
- },
- reflow : function(){
- helpers.extend(this.SegmentArc.prototype,{
- x : this.chart.width/2,
- y : this.chart.height/2
- });
-
- this.updateScaleRange();
- this.scale.calculateRange();
- this.scale.generateTicks();
- this.scale.buildYLabels();
-
- helpers.extend(this.scale,{
- xCenter: this.chart.width/2,
- yCenter: this.chart.height/2
- });
-
- helpers.each(this.segments, function(segment){
- //segment.update({
- // outerRadius : this.scale.calculateCenterOffset(segment.value)
- //});
- helpers.extend(segment, {
- outerRadius: this.scale.calculateCenterOffset(segment.value)
- });
- }, this);
-
- },
- draw : function(ease){
- var easingDecimal = ease || 1;
- //Clear & draw the canvas
- this.clear();
- helpers.each(this.segments,function(segment, index){
- segment.transition({
- circumference : this.scale.getCircumference(),
- outerRadius : this.scale.calculateCenterOffset(segment.value)
- },easingDecimal);
-
- segment.endAngle = segment.startAngle + segment.circumference;
-
- // If we've removed the first segment we need to set the first one to
- // start at the top.
- if (index === 0){
- segment.startAngle = Math.PI * 1.5;
- }
-
- //Check to see if it's the last segment, if not get the next and update the start angle
- if (index < this.segments.length - 1){
- this.segments[index+1].startAngle = segment.endAngle;
- }
- segment.draw();
- }, this);
- this.scale.draw();
- }
- });
+ }
+ });
+
+ //Declare segment class as a chart instance specific class, so it can share props for this instance
+ this.Slice = Chart.Arc.extend();
+
+ //Set up tooltip events on the chart
+ if (this.options.showTooltips) {
+ helpers.bindEvents(this, this.options.events, this.onHover);
+ }
+
+ // Create new slice for each piece of data
+ this.data.metaData = [];
+ helpers.each(this.data.data, function(slice, index) {
+ var metaSlice = new this.Slice({
+ _chart: this.chart,
+ innerRadius: 0,
+ startAngle: Math.PI * 1.5,
+ endAngle: Math.PI * 1.5,
+ x: this.chart.width / 2,
+ y: this.chart.height / 2
+ });
+ if (typeof slice == 'number') {
+ helpers.extend(metaSlice, {
+ value: slice
+ });
+ } else {
+ helpers.extend(metaSlice, slice);
+ }
+ if (!metaSlice.backgroundColor) {
+ slice.backgroundColor = 'hsl(' + (360 * index / this.data.data.length) + ', 100%, 50%)';
+ }
+ metaSlice.save();
+ this.data.metaData.push(metaSlice);
+ }, this);
+
+
+ // Create tooltip instance exclusively for this chart with some defaults.
+ this.tooltip = new Chart.Tooltip({
+ _chart: this.chart,
+ _data: this.data,
+ _options: this.options,
+ }, this);
+
+ this.update();
+
+ },
+ updateScaleRange: function() {
+ helpers.extend(this.scale, {
+ size: helpers.min([this.chart.width, this.chart.height]),
+ xCenter: this.chart.width / 2,
+ yCenter: this.chart.height / 2
+ });
+ },
+ update: function() {
+
+ this.updateScaleRange();
+ this.scale.calculateRange();
+ this.scale.generateTicks();
+ this.scale.buildYLabels();
+
+ this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.segment.borderWidth / 2) / 2;
+
+ var circumference = 1 / this.data.data.length * 2;
+
+ // Map new data to data points
+ helpers.each(this.data.metaData, function(slice, index) {
+
+ var datapoint = this.data.data[index];
+
+ var startAngle = Math.PI * 1.5 + (Math.PI * circumference) * index;
+ var endAngle = startAngle + (circumference * Math.PI);
+
+ helpers.extend(slice, {
+ _index: index,
+ x: this.chart.width / 2,
+ y: this.chart.height / 2,
+ value: datapoint.value,
+ label: datapoint.label,
+ innerRadius: 0,
+ outerRadius: this.scale.calculateCenterOffset(slice.value),
+ startAngle: startAngle,
+ endAngle: endAngle,
+
+ backgroundColor: datapoint.backgroundColor,
+ hoverBackgroundColor: datapoint.hoverBackgroundColor || datapoint.backgroundColor,
+ borderWidth: this.options.borderWidth,
+ borderColor: this.options.segmentStrokeColor,
+ });
+ slice.pivot();
+
+ }, this);
+
+ this.render();
+ },
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+
+ this.clear();
+
+ helpers.each(this.data.metaData, function(segment, index) {
+ segment.transition(easingDecimal).draw();
+ }, this);
+
+ this.scale.draw();
+ }
+ });
}).call(this);