]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Doughnut/Pie Chart refactor
authorTanner Linsley <tannerlinsley@gmail.com>
Sat, 16 May 2015 04:34:08 +0000 (22:34 -0600)
committerTanner Linsley <tannerlinsley@gmail.com>
Sat, 16 May 2015 04:34:08 +0000 (22:34 -0600)
samples/doughnut.html
src/Chart.Core.js
src/Chart.Doughnut.js

index 125beaf4653c8c4486aa53d54a478fdd069cf18d..145ff450a1a1f931e347c9a7842a7a3ebe1d9970 100644 (file)
         return Math.round(Math.random() * 255)
     };
 
-    var doughnutData = [{
-            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"
-        }
+    var doughnutData = {
+        data: [{
+                value: randomScalingFactor(),
+                backgroundColor: "#F7464A",
+                hoverBackgroundColor: "#FF5A5E",
+                label: "Red"
+            }, {
+                value: randomScalingFactor(),
+                backgroundColor: "#46BFBD",
+                hoverBackgroundColor: "#5AD3D1",
+                label: "Green"
+            }, {
+                value: randomScalingFactor(),
+                backgroundColor: "#FDB45C",
+                hoverBackgroundColor: "#FFC870",
+                label: "Yellow"
+            }, {
+                value: randomScalingFactor(),
+                backgroundColor: "#949FB1",
+                hoverBackgroundColor: "#A8B3C5",
+                label: "Grey"
+            }, {
+                value: randomScalingFactor(),
+                backgroundColor: "#4D5360",
+                hoverBackgroundColor: "#616774",
+                label: "Dark Grey"
+            }
 
-    ];
+        ]
+    };
 
     window.onload = function() {
         var ctx = document.getElementById("chart-area").getContext("2d");
@@ -67,9 +69,9 @@
     };
 
     $('#randomizeData').click(function() {
-        $.each(doughnutData, function(i, piece) {
-            doughnutData[i].value = randomScalingFactor();
-            doughnutData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
+        $.each(doughnutData.data, function(i, datapoint) {
+            datapoint.value = randomScalingFactor();
+            datapoint.backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
         });
         window.myDoughnut.update();
     });
index 1d6651ab7065086469768ed867f443373f90e55b..fbb6f5397583811b6b42e0a001b42f3f0b53013e 100755 (executable)
                 y: this.y + (Math.sin(centreAngle) * rangeFromCentre)
             };
         },
-        draw: function(animationPercent) {
-
-            var easingDecimal = animationPercent || 1;
+        draw: function() {
 
-            var ctx = this.ctx;
+            var ctx = this._chart.ctx;
+            var vm = this._vm;
 
             ctx.beginPath();
 
-            ctx.arc(this.x, this.y, this.outerRadius, this.startAngle, this.endAngle);
+            ctx.arc(vm.x, vm.y, vm.outerRadius, vm.startAngle, vm.endAngle);
 
-            ctx.arc(this.x, this.y, this.innerRadius, this.endAngle, this.startAngle, true);
+            ctx.arc(vm.x, vm.y, vm.innerRadius, vm.endAngle, vm.startAngle, true);
 
             ctx.closePath();
-            ctx.strokeStyle = this.borderColor;
-            ctx.lineWidth = this.borderWidth;
+            ctx.strokeStyle = vm.borderColor;
+            ctx.lineWidth = vm.borderWidth;
 
-            ctx.fillStyle = this.backgroundColor;
+            ctx.fillStyle = vm.backgroundColor;
 
             ctx.fill();
             ctx.lineJoin = 'bevel';
 
-            if (this.showBorder) {
+            if (vm.borderWidth) {
                 ctx.stroke();
             }
         }
index b9633aac21aee31a0a4a2660f411491726b0e1bd..64e3634ab0a8bbfc6cb93268da10999a32d1d551 100644 (file)
         segmentStrokeColor: "#fff",
 
         //Number - The width of each segment stroke
-        segmentStrokeWidth: 2,
+        borderWidth: 2,
 
         //The percentage of the chart that we cut out of the middle.
-        percentageInnerCutout: 50,
+        cutoutPercentage: 50,
 
-        //Number - Amount of animation steps
-        animationSteps: 100,
+        // The duration of animations triggered by hover events
+        hoverAnimationDuration: 400,
 
         //String - Animation easing effect
-        animationEasing: "easeOutBounce",
+        animationEasing: "easeOutQuart",
 
         //Boolean - Whether we animate the rotation of the Doughnut
         animateRotate: true,
             if (this.options.showTooltips) {
                 helpers.bindEvents(this, this.options.tooltipEvents, this.onHover);
             }
-            this.calculateTotal(data);
 
             // Create new slice for each piece of data
-            helpers.each(this.data.datasets, function(dataset, datasetIndex) {
-                dataset.metaData = [];
-                helpers.each(dataset.data, function(slice, index) {
-                    var metaSlice = new this.Slice();
-                    if (typeof slice == 'number') {
-                        helpers.extend(metaSlice, {
-                            value: slice
-                        });
-                    } else {
-                        helpers.extend(metaSlice, slice);
-                    }
-                    if (!metaSlice.color) {
-                        slice.color = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
-                    }
-                    metaSlice.save();
-                    dataset.metaData.push(metaSlice);
-                }, this);
+            this.data.metaData = [];
+            helpers.each(this.data.data, function(slice, index) {
+                var metaSlice = new this.Slice();
+                if (typeof slice == 'number') {
+                    helpers.extend(metaSlice, {
+                        value: slice
+                    });
+                } else {
+                    helpers.extend(metaSlice, slice);
+                }
+                helpers.extend(metaSlice, {
+                    startAngle: Math.PI * 1.5,
+                    circumference: (this.options.animateRotate) ? 0 : this.calculateCircumference(metaSlice.value),
+                    outerRadius: (this.options.animateScale) ? 0 : this.outerRadius,
+                    innerRadius: (this.options.animateScale) ? 0 : (this.outerRadius / 100) * this.options.percentageInnerCutout,
+                });
+                if (!metaSlice.backgroundColor) {
+                    slice.backgroundColor = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
+                }
+                metaSlice.save();
+                this.data.metaData.push(metaSlice);
             }, this);
 
             // Create tooltip instance exclusively for this chart with some defaults.
@@ -90,7 +93,7 @@
 
             this.update();
         },
-        onHover: function(evt) {
+        onHover: function(e) {
 
             // If exiting chart
             if (e.type == 'mouseout') {
             this.lastActive = this.lastActive || [];
 
             // Find Active Elements
-            this.active = function() {
-                switch (this.options.hoverMode) {
-                    case 'single':
-                        return this.getElementAtEvent(e);
-                    case 'label':
-                        return this.getElementsAtEvent(e);
-                    case 'dataset':
-                        return this.getDatasetAtEvent(e);
-                    default:
-                        return e;
-                }
-            }.call(this);
+            this.active = this.getSliceAtEvent(e);
 
             // On Hover hook
             if (this.options.onHover) {
 
             // Remove styling for last active (even if it may still be active)
             if (this.lastActive.length) {
-                switch (this.options.hoverMode) {
-                    case 'single':
-                        this.lastActive[0].backgroundColor = this.data.datasets[0].backgroundColor;
-                        break;
-                    case 'label':
-                        for (var i = 0; i < this.lastActive.length; i++) {
-                            this.lastActive[i].backgroundColor = this.data.datasets[this.lastActive[i]._datasetIndex].backgroundColor;
-                        }
-                        break;
-                    case 'dataset':
-                        break;
-                    default:
-                        // Don't change anything
-                }
+                this.lastActive[0].backgroundColor = this.data.data[this.lastActive[0]._index].backgroundColor;
             }
 
             // Built in hover styling
             if (this.active.length && this.options.hoverMode) {
-                switch (this.options.hoverMode) {
-                    case 'single':
-                        this.active[0].backgroundColor = this.data.datasets[this.active[0]._datasetIndex].hoverBackgroundColor || helpers.color(this.active[0].backgroundColor).saturate(0.5).darken(0.35).rgbString();
-                        break;
-                    case 'label':
-                        for (var i = 0; i < this.active.length; i++) {
-                            this.active[i].backgroundColor = this.data.datasets[this.active[i]._datasetIndex].hoverBackgroundColor || helpers.color(this.active[i].backgroundColor).saturate(0.5).darken(0.35).rgbString();
-                        }
-                        break;
-                    case 'dataset':
-                        break;
-                    default:
-                        // Don't change anything
-                }
+                this.active[0].backgroundColor = this.data.data[this.active[0]._index].hoverBackgroundColor || helpers.color(this.active[0].backgroundColor).saturate(0.5).darken(0.35).rgbString();
             }
 
-
             // Built in Tooltips
             if (this.options.showTooltips) {
 
             return this;
 
         },
-        getSegmentsAtEvent: function(e) {
-            var segmentsArray = [];
+        getSliceAtEvent: function(e) {
+            var elements = [];
 
             var location = helpers.getRelativePosition(e);
 
-            helpers.each(this.segments, function(segment) {
-                if (segment.inRange(location.x, location.y)) segmentsArray.push(segment);
+            helpers.each(this.data.metaData, function(slice, index) {
+                if (slice.inRange(location.x, location.y)) elements.push(slice);
             }, this);
-            return segmentsArray;
+            return elements;
         },
         calculateCircumference: function(value) {
             if (this.total > 0) {
                 return 0;
             }
         },
-        calculateTotal: function(data) {
-            this.total = 0;
-            helpers.each(data, function(segment) {
-                this.total += Math.abs(segment.value);
-            }, this);
-        },
         update: function() {
 
-            this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.segmentStrokeWidth / 2) / 2;
+            // Calc Total
+            this.total = 0;
+            helpers.each(this.data.data, function(slice) {
+                this.total += Math.abs(slice.value);
+            }, this);
 
+            this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.borderWidth / 2) / 2;
 
             // Map new data to data points
-            helpers.each(this.data, function(segment, i) {
-                helpers.extend(this.segments[i], {
+            helpers.each(this.data.metaData, function(slice, index) {
+
+                var datapoint = this.data.data[index];
+
+                helpers.extend(slice, {
+                    _index: index,
                     x: this.chart.width / 2,
                     y: this.chart.height / 2,
-                    value: segment.value,
-                    backgroundColor: segment.color,
-                    hoverBackgroundColor: segment.highlight || segment.color,
-                    borderWidth: this.options.segmentStrokeWidth,
+                    value: datapoint.value,
+                    label: datapoint.label,
+                    circumference: this.calculateCircumference(datapoint.value),
+                    outerRadius: this.outerRadius,
+                    innerRadius: (this.outerRadius / 100) * this.options.cutoutPercentage,
+
+                    backgroundColor: datapoint.backgroundColor,
+                    hoverBackgroundColor: datapoint.hoverBackgroundColor || datapoint.backgroundColor,
+                    borderWidth: this.options.borderWidth,
                     borderColor: this.options.segmentStrokeColor,
-                    label: segment.label,
-                    startAngle: Math.PI * 1.5,
-                    circumference: (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
-                    innerRadius: (this.options.animateScale) ? 0 : (this.outerRadius / 100) * this.options.percentageInnerCutout,
-                    outerRadius: (this.options.animateScale) ? 0 : this.outerRadius,
                 });
-            }, this);
 
-            this.calculateTotal(this.segments);
+                helpers.extend(slice, {
+                    endAngle: slice.startAngle + slice.circumference,
+                });
 
-            // Reset any highlight colours before updating.
-            helpers.each(this.activeElements, function(activeElement) {
-                activeElement.restore(['backgroundColor']);
-            });
+                if (index === 0) {
+                    slice.startAngle = Math.PI * 1.5;
+                }
 
-            helpers.each(this.segments, function(segment) {
-                segment.save();
-            });
-            this.render();
-        },
+                //Check to see if it's the last slice, if not get the next and update its start angle
+                if (index < this.data.data.length - 1) {
+                    this.data.metaData[index + 1].startAngle = slice.endAngle;
+                }
 
-        removeData: function(atIndex) {
-            var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length - 1;
-            this.segments.splice(indexToDelete, 1);
-            this.reflow();
-            this.update();
-        },
+                slice.pivot();
 
-        reflow: function() {
-            helpers.extend(this.Slice.prototype, {
-                x: this.chart.width / 2,
-                y: this.chart.height / 2
-            });
-            this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.segmentStrokeWidth / 2) / 2;
-            helpers.each(this.segments, function(segment) {
-                segment.update({
-                    outerRadius: this.outerRadius,
-                    innerRadius: (this.outerRadius / 100) * this.options.percentageInnerCutout
-                });
             }, this);
+
+            this.render();
         },
         draw: function(easeDecimal) {
-            var animDecimal = (easeDecimal) ? easeDecimal : 1;
+            easeDecimal = easeDecimal || 1;
             this.clear();
-            helpers.each(this.segments, function(segment, index) {
-                segment.transition({
-                    circumference: this.calculateCircumference(segment.value),
-                    outerRadius: this.outerRadius,
-                    innerRadius: (this.outerRadius / 100) * this.options.percentageInnerCutout
-                }, animDecimal);
-
-                segment.endAngle = segment.startAngle + segment.circumference;
 
-                segment.draw();
-                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;
-                }
+            helpers.each(this.data.metaData, function(slice, index) {
+                slice.transition(easeDecimal).draw();
             }, this);
 
+            this.tooltip.transition(easeDecimal).draw();
         }
     });
 
     Chart.types.Doughnut.extend({
         name: "Pie",
         defaults: helpers.merge(defaultConfig, {
-            percentageInnerCutout: 0
+            cutoutPercentage: 0
         })
     });