From c574995dde3ea0a1c57931311857daff3ac03f48 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Tue, 23 Aug 2016 15:17:37 +0800 Subject: [PATCH 1/2] MDL-55665 core: Add support for stacked bar charts --- lib/amd/build/chart_bar.min.js | 2 +- lib/amd/build/chart_output_chartjs.min.js | 2 +- lib/amd/src/chart_bar.js | 28 +++++++++++++++++++++++ lib/amd/src/chart_output_chartjs.js | 23 +++++++++++++++++++ lib/classes/chart_bar.php | 24 +++++++++++++++++-- 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/lib/amd/build/chart_bar.min.js b/lib/amd/build/chart_bar.min.js index 05364fdcb02..b98a8258946 100644 --- a/lib/amd/build/chart_bar.min.js +++ b/lib/amd/build/chart_bar.min.js @@ -1 +1 @@ -define(["core/chart_base"],function(a){function b(){a.prototype.constructor.apply(this,arguments)}return b.prototype=Object.create(a.prototype),b.prototype._horizontal=!1,b.prototype.TYPE="bar",b.prototype.create=function(b,c){var d=a.prototype.create.apply(this,arguments);return d.setHorizontal(c.horizontal),d},b.prototype._setDefaults=function(){a.prototype._setDefaults.apply(this,arguments);var b=this.getYAxis(0,!0);b.setMin(0)},b.prototype.getHorizontal=function(){return this._horizontal},b.prototype.setHorizontal=function(a){var b=this.getXAxis(0,!0);null===b.getMin()&&b.setMin(0),this._horizontal=Boolean(a)},b}); \ No newline at end of file +define(["core/chart_base"],function(a){function b(){a.prototype.constructor.apply(this,arguments)}return b.prototype=Object.create(a.prototype),b.prototype._horizontal=!1,b.prototype._stacked=null,b.prototype.TYPE="bar",b.prototype.create=function(b,c){var d=a.prototype.create.apply(this,arguments);return d.setHorizontal(c.horizontal),d.setStacked(c.stacked),d},b.prototype._setDefaults=function(){a.prototype._setDefaults.apply(this,arguments);var b=this.getYAxis(0,!0);b.setMin(0)},b.prototype.getHorizontal=function(){return this._horizontal},b.prototype.getStacked=function(){return this._stacked},b.prototype.setHorizontal=function(a){var b=this.getXAxis(0,!0);null===b.getMin()&&b.setMin(0),this._horizontal=Boolean(a)},b.prototype.setStacked=function(a){this._stacked=Boolean(a)},b}); \ No newline at end of file diff --git a/lib/amd/build/chart_output_chartjs.min.js b/lib/amd/build/chart_output_chartjs.min.js index c035888d775..62ae60a08f2 100644 --- a/lib/amd/build/chart_output_chartjs.min.js +++ b/lib/amd/build/chart_output_chartjs.min.js @@ -1 +1 @@ -define(["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],function(a,b,c,d,e,f,g,h){function i(){e.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=a(""),this._node.append(this._canvas)),this._build()}var j=function(a,b){return"axis-"+a+"-"+b};return i.prototype=Object.create(e.prototype),i.prototype._config=null,i.prototype._chartjs=null,i.prototype._canvas=null,i.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new b(this._canvas[0],this._config)},i.prototype._getChartType=function(){var a=this._chart.getType();return this._chart.getType()===d.prototype.TYPE&&this._chart.getHorizontal()===!0&&(a="horizontalBar"),a},i.prototype._makeAxisConfig=function(a,b,d){var e={id:j(b,d)};return a.getPosition()!==c.prototype.POS_DEFAULT&&(e.position=a.getPosition()),null!==a.getLabel()&&(e.scaleLabel={display:!0,labelString:a.getLabel()}),null!==a.getStepSize()&&(e.ticks=e.ticks||{},e.ticks.stepSize=a.getStepSize()),null!==a.getMax()&&(e.ticks=e.ticks||{},e.ticks.max=a.getMax()),null!==a.getMin()&&(e.ticks=e.ticks||{},e.ticks.min=a.getMin()),e},i.prototype._makeConfig=function(){var a={type:this._getChartType(),data:{labels:this._chart.getLabels(),datasets:this._makeDatasetsConfig()},options:{title:{display:null!==this._chart.getTitle(),text:this._chart.getTitle()}}};return this._chart.getXAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.xAxes=a.options.scales.xAxes||[],a.options.scales.xAxes[c]=this._makeAxisConfig(b,"x",c),null!==d&&(a.options.scales.xAxes[c].ticks.callback=function(a,b){return d[b]||""})}.bind(this)),this._chart.getYAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.yAxes=a.options.scales.yAxes||[],a.options.scales.yAxes[c]=this._makeAxisConfig(b,"y",c),null!==d&&(a.options.scales.yAxes[c].ticks.callback=function(a){return d[parseInt(a,10)]||""})}.bind(this)),a.options.tooltips={callbacks:{label:this._makeTooltip.bind(this)}},a},i.prototype._makeDatasetsConfig=function(){var a=this._chart.getSeries().map(function(a){var b=a.hasColoredValues()?a.getColors():a.getColor(),c={label:a.getLabel(),data:a.getValues(),type:a.getType(),fill:!1,backgroundColor:b,borderColor:this._chart.getType()==g.prototype.TYPE?null:b,lineTension:this._isSmooth(a)?.3:0};return null!==a.getXAxis()&&(c.xAxisID=j("x",a.getXAxis())),null!==a.getYAxis()&&(c.yAxisID=j("y",a.getYAxis())),c}.bind(this));return a},i.prototype._makeTooltip=function(a,b){var c=this._chart.getSeries()[a.datasetIndex],d=c.getLabel(),e=c.getLabels(),f=b.datasets[a.datasetIndex].data,g=f[a.index],h=d+": "+g;return null!==e&&(h=e[a.index]),h},i.prototype._isSmooth=function(a){var b=!1;return this._chart.getType()===f.prototype.TYPE?(b=a.getSmooth(),null===b&&(b=this._chart.getSmooth())):a.getType()===h.prototype.TYPE_LINE&&(b=a.getSmooth()),b},i.prototype.update=function(){a.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},i}); \ No newline at end of file +define(["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],function(a,b,c,d,e,f,g,h){function i(){e.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=a(""),this._node.append(this._canvas)),this._build()}var j=function(a,b){return"axis-"+a+"-"+b};return i.prototype=Object.create(e.prototype),i.prototype._config=null,i.prototype._chartjs=null,i.prototype._canvas=null,i.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new b(this._canvas[0],this._config)},i.prototype._getChartType=function(){var a=this._chart.getType();return this._chart.getType()===d.prototype.TYPE&&this._chart.getHorizontal()===!0&&(a="horizontalBar"),a},i.prototype._makeAxisConfig=function(a,b,d){var e={id:j(b,d)};return a.getPosition()!==c.prototype.POS_DEFAULT&&(e.position=a.getPosition()),null!==a.getLabel()&&(e.scaleLabel={display:!0,labelString:a.getLabel()}),null!==a.getStepSize()&&(e.ticks=e.ticks||{},e.ticks.stepSize=a.getStepSize()),null!==a.getMax()&&(e.ticks=e.ticks||{},e.ticks.max=a.getMax()),null!==a.getMin()&&(e.ticks=e.ticks||{},e.ticks.min=a.getMin()),e},i.prototype._makeConfig=function(){var a={type:this._getChartType(),data:{labels:this._chart.getLabels(),datasets:this._makeDatasetsConfig()},options:{title:{display:null!==this._chart.getTitle(),text:this._chart.getTitle()}}};return this._chart.getXAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.xAxes=a.options.scales.xAxes||[],a.options.scales.xAxes[c]=this._makeAxisConfig(b,"x",c),null!==d&&(a.options.scales.xAxes[c].ticks.callback=function(a,b){return d[b]||""}),a.options.scales.xAxes[c].stacked=this._isStacked("x")}.bind(this)),this._chart.getYAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.yAxes=a.options.scales.yAxes||[],a.options.scales.yAxes[c]=this._makeAxisConfig(b,"y",c),null!==d&&(a.options.scales.yAxes[c].ticks.callback=function(a){return d[parseInt(a,10)]||""}),a.options.scales.yAxes[c].stacked=this._isStacked("y")}.bind(this)),a.options.tooltips={callbacks:{label:this._makeTooltip.bind(this)}},a},i.prototype._makeDatasetsConfig=function(){var a=this._chart.getSeries().map(function(a){var b=a.hasColoredValues()?a.getColors():a.getColor(),c={label:a.getLabel(),data:a.getValues(),type:a.getType(),fill:!1,backgroundColor:b,borderColor:this._chart.getType()==g.prototype.TYPE?null:b,lineTension:this._isSmooth(a)?.3:0};return null!==a.getXAxis()&&(c.xAxisID=j("x",a.getXAxis())),null!==a.getYAxis()&&(c.yAxisID=j("y",a.getYAxis())),c}.bind(this));return a},i.prototype._makeTooltip=function(a,b){var c=this._chart.getSeries()[a.datasetIndex],d=c.getLabel(),e=c.getLabels(),f=b.datasets[a.datasetIndex].data,g=f[a.index],h=d+": "+g;return null!==e&&(h=e[a.index]),h},i.prototype._isSmooth=function(a){var b=!1;return this._chart.getType()===f.prototype.TYPE?(b=a.getSmooth(),null===b&&(b=this._chart.getSmooth())):a.getType()===h.prototype.TYPE_LINE&&(b=a.getSmooth()),b},i.prototype._isStacked=function(a){var b=!1,c=this._getChartType();return c===d.prototype.TYPE&&"x"==a?b=this._chart.getStacked():"horizontalBar"===c&&"y"==a&&(b=this._chart.getStacked()),b},i.prototype.update=function(){a.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},i}); \ No newline at end of file diff --git a/lib/amd/src/chart_bar.js b/lib/amd/src/chart_bar.js index 13c5596318d..f4eb2b6e2bc 100644 --- a/lib/amd/src/chart_bar.js +++ b/lib/amd/src/chart_bar.js @@ -43,6 +43,14 @@ define(['core/chart_base'], function(Base) { */ Bar.prototype._horizontal = false; + /** + * Whether the bars should be stacked or not. + * + * @type {Bool} + * @protected + */ + Bar.prototype._stacked = null; + /** @override */ Bar.prototype.TYPE = 'bar'; @@ -50,6 +58,7 @@ define(['core/chart_base'], function(Base) { Bar.prototype.create = function(Klass, data) { var chart = Base.prototype.create.apply(this, arguments); chart.setHorizontal(data.horizontal); + chart.setStacked(data.stacked); return chart; }; @@ -69,6 +78,15 @@ define(['core/chart_base'], function(Base) { return this._horizontal; }; + /** + * Get whether the bars should be stacked or not. + * + * @returns {Bool} + */ + Bar.prototype.getStacked = function() { + return this._stacked; + }; + /** * Set whether the bars should be displayed horizontally or not. * @@ -84,6 +102,16 @@ define(['core/chart_base'], function(Base) { this._horizontal = Boolean(horizontal); }; + /** + * Set whether the bars should be stacked or not. + * + * @method setStacked + * @param {Bool} stacked True if the chart should be stacked or false otherwise. + */ + Bar.prototype.setStacked = function(stacked) { + this._stacked = Boolean(stacked); + }; + return Bar; }); diff --git a/lib/amd/src/chart_output_chartjs.js b/lib/amd/src/chart_output_chartjs.js index d73847900e6..dee3915a009 100644 --- a/lib/amd/src/chart_output_chartjs.js +++ b/lib/amd/src/chart_output_chartjs.js @@ -195,6 +195,7 @@ define([ return axisLabels[index] || ''; }; } + config.options.scales.xAxes[i].stacked = this._isStacked('x'); }.bind(this)); this._chart.getYAxes().forEach(function(axis, i) { @@ -209,6 +210,7 @@ define([ return axisLabels[parseInt(value, 10)] || ''; }; } + config.options.scales.yAxes[i].stacked = this._isStacked('y'); }.bind(this)); config.options.tooltips = { @@ -301,6 +303,27 @@ define([ return smooth; }; + /** + * Verify if the bar chart is stacked or not. + * + * @protected + * @param {String} xy The axis of the serie. + * @returns {Bool} + */ + Output.prototype._isStacked = function(xy) { + var stacked = false; + var chartType = this._getChartType(); + + // Check if the axis matches the chart type to avoid set stacked on a unused axis. + if (chartType === Bar.prototype.TYPE && xy == 'x') { + stacked = this._chart.getStacked(); + } else if (chartType === 'horizontalBar' && xy == 'y') { + stacked = this._chart.getStacked(); + } + + return stacked; + }; + /** @override */ Output.prototype.update = function() { $.extend(true, this._config, this._makeConfig()); diff --git a/lib/classes/chart_bar.php b/lib/classes/chart_bar.php index ace3a810609..034d274cb0a 100644 --- a/lib/classes/chart_bar.php +++ b/lib/classes/chart_bar.php @@ -36,7 +36,8 @@ class chart_bar extends chart_base { /** @var bool Whether the bars should be displayed horizontally or not. */ protected $horizontal = false; - + /** @var bool Whether the chart should be stacked or not. */ + protected $stacked = null; /** * Add the horizontal to the parent and return the serialized data. * @@ -45,6 +46,7 @@ class chart_bar extends chart_base { public function jsonSerialize() { // @codingStandardsIgnoreLine (CONTRIB-6469). $data = parent::jsonSerialize(); $data['horizontal'] = $this->get_horizontal(); + $data['stacked'] = $this->get_stacked(); return $data; } @@ -67,11 +69,29 @@ class chart_bar extends chart_base { } /** - * Get Set whether the bars should be displayed horizontally or not. + * Get whether the bars should be stacked or not. + * + * @return bool + */ + public function get_stacked() { + return $this->stacked; + } + + /** + * Set whether the bars should be displayed horizontally or not. * * @param bool $horizontal True if the bars should be displayed horizontally, false otherwise. */ public function set_horizontal($horizontal) { $this->horizontal = $horizontal; } + + /** + * Set whether the bars should be stacked or not. + * + * @param bool $stacked True if the chart should be stacked or false otherwise. + */ + public function set_stacked($stacked) { + $this->stacked = $stacked; + } } From b02e738c4f586dc4a3d1aa2a823843fedc0dcc16 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Thu, 25 Aug 2016 11:59:13 +0800 Subject: [PATCH 2/2] MDL-55710 core: Add support for doughnut charts --- lib/amd/build/chart_output_chartjs.min.js | 2 +- lib/amd/build/chart_pie.min.js | 2 +- lib/amd/src/chart_output_chartjs.js | 10 +++++-- lib/amd/src/chart_pie.js | 35 +++++++++++++++++++++++ lib/classes/chart_pie.php | 32 +++++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/lib/amd/build/chart_output_chartjs.min.js b/lib/amd/build/chart_output_chartjs.min.js index 62ae60a08f2..7b857119178 100644 --- a/lib/amd/build/chart_output_chartjs.min.js +++ b/lib/amd/build/chart_output_chartjs.min.js @@ -1 +1 @@ -define(["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],function(a,b,c,d,e,f,g,h){function i(){e.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=a(""),this._node.append(this._canvas)),this._build()}var j=function(a,b){return"axis-"+a+"-"+b};return i.prototype=Object.create(e.prototype),i.prototype._config=null,i.prototype._chartjs=null,i.prototype._canvas=null,i.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new b(this._canvas[0],this._config)},i.prototype._getChartType=function(){var a=this._chart.getType();return this._chart.getType()===d.prototype.TYPE&&this._chart.getHorizontal()===!0&&(a="horizontalBar"),a},i.prototype._makeAxisConfig=function(a,b,d){var e={id:j(b,d)};return a.getPosition()!==c.prototype.POS_DEFAULT&&(e.position=a.getPosition()),null!==a.getLabel()&&(e.scaleLabel={display:!0,labelString:a.getLabel()}),null!==a.getStepSize()&&(e.ticks=e.ticks||{},e.ticks.stepSize=a.getStepSize()),null!==a.getMax()&&(e.ticks=e.ticks||{},e.ticks.max=a.getMax()),null!==a.getMin()&&(e.ticks=e.ticks||{},e.ticks.min=a.getMin()),e},i.prototype._makeConfig=function(){var a={type:this._getChartType(),data:{labels:this._chart.getLabels(),datasets:this._makeDatasetsConfig()},options:{title:{display:null!==this._chart.getTitle(),text:this._chart.getTitle()}}};return this._chart.getXAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.xAxes=a.options.scales.xAxes||[],a.options.scales.xAxes[c]=this._makeAxisConfig(b,"x",c),null!==d&&(a.options.scales.xAxes[c].ticks.callback=function(a,b){return d[b]||""}),a.options.scales.xAxes[c].stacked=this._isStacked("x")}.bind(this)),this._chart.getYAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.yAxes=a.options.scales.yAxes||[],a.options.scales.yAxes[c]=this._makeAxisConfig(b,"y",c),null!==d&&(a.options.scales.yAxes[c].ticks.callback=function(a){return d[parseInt(a,10)]||""}),a.options.scales.yAxes[c].stacked=this._isStacked("y")}.bind(this)),a.options.tooltips={callbacks:{label:this._makeTooltip.bind(this)}},a},i.prototype._makeDatasetsConfig=function(){var a=this._chart.getSeries().map(function(a){var b=a.hasColoredValues()?a.getColors():a.getColor(),c={label:a.getLabel(),data:a.getValues(),type:a.getType(),fill:!1,backgroundColor:b,borderColor:this._chart.getType()==g.prototype.TYPE?null:b,lineTension:this._isSmooth(a)?.3:0};return null!==a.getXAxis()&&(c.xAxisID=j("x",a.getXAxis())),null!==a.getYAxis()&&(c.yAxisID=j("y",a.getYAxis())),c}.bind(this));return a},i.prototype._makeTooltip=function(a,b){var c=this._chart.getSeries()[a.datasetIndex],d=c.getLabel(),e=c.getLabels(),f=b.datasets[a.datasetIndex].data,g=f[a.index],h=d+": "+g;return null!==e&&(h=e[a.index]),h},i.prototype._isSmooth=function(a){var b=!1;return this._chart.getType()===f.prototype.TYPE?(b=a.getSmooth(),null===b&&(b=this._chart.getSmooth())):a.getType()===h.prototype.TYPE_LINE&&(b=a.getSmooth()),b},i.prototype._isStacked=function(a){var b=!1,c=this._getChartType();return c===d.prototype.TYPE&&"x"==a?b=this._chart.getStacked():"horizontalBar"===c&&"y"==a&&(b=this._chart.getStacked()),b},i.prototype.update=function(){a.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},i}); \ No newline at end of file +define(["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],function(a,b,c,d,e,f,g,h){function i(){e.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=a(""),this._node.append(this._canvas)),this._build()}var j=function(a,b){return"axis-"+a+"-"+b};return i.prototype=Object.create(e.prototype),i.prototype._config=null,i.prototype._chartjs=null,i.prototype._canvas=null,i.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new b(this._canvas[0],this._config)},i.prototype._getChartType=function(){var a=this._chart.getType();return this._chart.getType()===d.prototype.TYPE&&this._chart.getHorizontal()===!0?a="horizontalBar":this._chart.getType()===g.prototype.TYPE&&this._chart.getDoughnut()===!0&&(a="doughnut"),a},i.prototype._makeAxisConfig=function(a,b,d){var e={id:j(b,d)};return a.getPosition()!==c.prototype.POS_DEFAULT&&(e.position=a.getPosition()),null!==a.getLabel()&&(e.scaleLabel={display:!0,labelString:a.getLabel()}),null!==a.getStepSize()&&(e.ticks=e.ticks||{},e.ticks.stepSize=a.getStepSize()),null!==a.getMax()&&(e.ticks=e.ticks||{},e.ticks.max=a.getMax()),null!==a.getMin()&&(e.ticks=e.ticks||{},e.ticks.min=a.getMin()),e},i.prototype._makeConfig=function(){var a={type:this._getChartType(),data:{labels:this._chart.getLabels(),datasets:this._makeDatasetsConfig()},options:{title:{display:null!==this._chart.getTitle(),text:this._chart.getTitle()}}};return this._chart.getXAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.xAxes=a.options.scales.xAxes||[],a.options.scales.xAxes[c]=this._makeAxisConfig(b,"x",c),null!==d&&(a.options.scales.xAxes[c].ticks.callback=function(a,b){return d[b]||""}),a.options.scales.xAxes[c].stacked=this._isStacked("x")}.bind(this)),this._chart.getYAxes().forEach(function(b,c){var d=b.getLabels();a.options.scales=a.options.scales||{},a.options.scales.yAxes=a.options.scales.yAxes||[],a.options.scales.yAxes[c]=this._makeAxisConfig(b,"y",c),null!==d&&(a.options.scales.yAxes[c].ticks.callback=function(a){return d[parseInt(a,10)]||""}),a.options.scales.yAxes[c].stacked=this._isStacked("y")}.bind(this)),a.options.tooltips={callbacks:{label:this._makeTooltip.bind(this)}},a},i.prototype._makeDatasetsConfig=function(){var a=this._chart.getSeries().map(function(a){var b=a.hasColoredValues()?a.getColors():a.getColor(),c={label:a.getLabel(),data:a.getValues(),type:a.getType(),fill:!1,backgroundColor:b,borderColor:this._chart.getType()==g.prototype.TYPE?null:b,lineTension:this._isSmooth(a)?.3:0};return null!==a.getXAxis()&&(c.xAxisID=j("x",a.getXAxis())),null!==a.getYAxis()&&(c.yAxisID=j("y",a.getYAxis())),c}.bind(this));return a},i.prototype._makeTooltip=function(a,b){var c=this._chart.getSeries()[a.datasetIndex],d=c.getLabel(),e=c.getLabels(),f=b.datasets[a.datasetIndex].data,g=f[a.index],h=d+": "+g;return null!==e&&(h=e[a.index]),h},i.prototype._isSmooth=function(a){var b=!1;return this._chart.getType()===f.prototype.TYPE?(b=a.getSmooth(),null===b&&(b=this._chart.getSmooth())):a.getType()===h.prototype.TYPE_LINE&&(b=a.getSmooth()),b},i.prototype._isStacked=function(a){var b=!1,c=this._getChartType();return c===d.prototype.TYPE&&"x"==a?b=this._chart.getStacked():"horizontalBar"===c&&"y"==a&&(b=this._chart.getStacked()),b},i.prototype.update=function(){a.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},i}); \ No newline at end of file diff --git a/lib/amd/build/chart_pie.min.js b/lib/amd/build/chart_pie.min.js index aab6464bd7a..557d2b36bdc 100644 --- a/lib/amd/build/chart_pie.min.js +++ b/lib/amd/build/chart_pie.min.js @@ -1 +1 @@ -define(["core/chart_base"],function(a){function b(){a.prototype.constructor.apply(this,arguments)}return b.prototype=Object.create(a.prototype),b.prototype.TYPE="pie",b.prototype.addSeries=function(b){if(null===b.getColor()){for(var c=[],d=0;d=1)throw new Error("Pie charts only support one serie.");return a.prototype._validateSeries.apply(this,arguments)},b}); \ No newline at end of file +define(["core/chart_base"],function(a){function b(){a.prototype.constructor.apply(this,arguments)}return b.prototype=Object.create(a.prototype),b.prototype.TYPE="pie",b.prototype._doughnut=null,b.prototype.create=function(b,c){var d=a.prototype.create.apply(this,arguments);return d.setDoughnut(c.doughnut),d},b.prototype.addSeries=function(b){if(null===b.getColor()){for(var c=[],d=0;d=1)throw new Error("Pie charts only support one serie.");return a.prototype._validateSeries.apply(this,arguments)},b}); \ No newline at end of file diff --git a/lib/amd/src/chart_output_chartjs.js b/lib/amd/src/chart_output_chartjs.js index dee3915a009..e93fa8b7552 100644 --- a/lib/amd/src/chart_output_chartjs.js +++ b/lib/amd/src/chart_output_chartjs.js @@ -99,11 +99,12 @@ define([ }; /** - * Get the chart type. + * Get the chart type and handles the Chart.js specific chart types. * - * It also handles the bar charts positioning, deciding if the bars should be displayed horizontally. - * Otherwise, get the chart TYPE value. + * By default returns the current chart TYPE value. Also does the handling of specific chart types, for example + * check if the bar chart should be horizontal and the pie chart should be displayed as a doughnut. * + * @method getChartType * @returns {String} the chart type. * @protected */ @@ -113,6 +114,9 @@ define([ // Bars can be displayed vertically and horizontally, defining horizontalBar type. if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) { type = 'horizontalBar'; + } else if (this._chart.getType() === Pie.prototype.TYPE && this._chart.getDoughnut() === true) { + // Pie chart can be displayed as doughnut. + type = 'doughnut'; } return type; diff --git a/lib/amd/src/chart_pie.js b/lib/amd/src/chart_pie.js index 632e1098c6a..bce2ef203ed 100644 --- a/lib/amd/src/chart_pie.js +++ b/lib/amd/src/chart_pie.js @@ -38,6 +38,21 @@ define(['core/chart_base'], function(Base) { /** @override */ Pie.prototype.TYPE = 'pie'; + /** + * Whether the chart should be displayed as doughnut or not. + * + * @type {Bool} + * @protected + */ + Pie.prototype._doughnut = null; + + /** @override */ + Pie.prototype.create = function(Klass, data) { + var chart = Base.prototype.create.apply(this, arguments); + chart.setDoughnut(data.doughnut); + return chart; + }; + /** * Overridden to add appropriate colors to the series. * @@ -54,6 +69,26 @@ define(['core/chart_base'], function(Base) { return Base.prototype.addSeries.apply(this, arguments); }; + /** + * Get whether the chart should be displayed as doughnut or not. + * + * @method getDoughnut + * @returns {Bool} + */ + Pie.prototype.getDoughnut = function() { + return this._doughnut; + }; + + /** + * Set whether the chart should be displayed as doughnut or not. + * + * @method setDoughnut + * @param {Bool} doughnut True for doughnut type, false for pie. + */ + Pie.prototype.setDoughnut = function(doughnut) { + this._doughnut = Boolean(doughnut); + }; + /** * Validate a series. * diff --git a/lib/classes/chart_pie.php b/lib/classes/chart_pie.php index 32745badba8..b4c20410337 100644 --- a/lib/classes/chart_pie.php +++ b/lib/classes/chart_pie.php @@ -33,4 +33,36 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class chart_pie extends chart_base { + + /** @var bool $doughnut Whether the chart should be displayed as doughnut. */ + protected $doughnut = null; + + /** + * Get parent JSON and add specific pie related attributes and values. + * + * @return array + */ + public function jsonSerialize() { // @codingStandardsIgnoreLine (CONTRIB-6469). + $data = parent::jsonSerialize(); + $data['doughnut'] = $this->get_doughnut(); + return $data; + } + + /** + * Get whether the chart should be displayed as doughnut. + * + * @return bool + */ + public function get_doughnut() { + return $this->doughnut; + } + + /** + * Set whether the chart should be displayed as doughnut. + * + * @param bool $doughnut True for doughnut type, false for pie. + */ + public function set_doughnut($doughnut) { + $this->doughnut = $doughnut; + } }