MDL-85158 libraries: Configure responsive options for ChartJS

Currently, the attributes to configure the responsiveness of a chart
are being set statically. With this change it will be possible to
update these static attributes in order to change the aspectRatio and
resizeDelay of the chart.
This commit is contained in:
Pedro Jordao
2025-05-14 09:34:33 -03:00
parent 9242f9619a
commit 4a1bf4304b
9 changed files with 78 additions and 4 deletions
@@ -0,0 +1,8 @@
issueNumber: MDL-85158
notes:
core:
- message: >-
Added support for configurable `aspectRatio` in charts rendered using
Chart.js. This enables developers to control chart sizing more precisely
via the `chart_base` API and the frontend renderer.
type: improved
+1 -1
View File
@@ -5,6 +5,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @module core/chart_base
*/
define("core/chart_base",["core/chart_series","core/chart_axis"],(function(Series,Axis){function Base(){this._series=[],this._labels=[],this._xaxes=[],this._yaxes=[],this._setDefaults()}return Base.prototype._series=null,Base.prototype._labels=null,Base.prototype._legendOptions=null,Base.prototype._title=null,Base.prototype._xaxes=null,Base.prototype._yaxes=null,Base.prototype.COLORSET=["#f3c300","#875692","#f38400","#a1caf1","#be0032","#c2b280","#7f180d","#008856","#e68fac","#0067a5"],Base.prototype._configColorSet=null,Base.prototype.TYPE=null,Base.prototype.addSeries=function(series){if(this._validateSeries(series),this._series.push(series),null===series.getColor()){var configColorSet=this.getConfigColorSet()||Base.prototype.COLORSET;series.setColor(configColorSet[this._series.length%configColorSet.length])}},Base.prototype.create=function(Klass,data){var Chart=new Klass;return Chart.setConfigColorSet(data.config_colorset),Chart.setLabels(data.labels),Chart.setTitle(data.title),data.legend_options&&Chart.setLegendOptions(data.legend_options),data.series.forEach((function(seriesData){Chart.addSeries(Series.prototype.create(seriesData))})),data.axes.x.forEach((function(axisData,i){Chart.setXAxis(Axis.prototype.create(axisData),i)})),data.axes.y.forEach((function(axisData,i){Chart.setYAxis(Axis.prototype.create(axisData),i)})),Chart},Base.prototype.__getAxis=function(xy,index,createIfNotExists){var axis,axes="x"===xy?this._xaxes:this._yaxes,setAxis=("x"===xy?this.setXAxis:this.setYAxis).bind(this);if(createIfNotExists=void 0!==createIfNotExists&&createIfNotExists,void 0===(axis=axes[index=void 0===index?0:index])){if(!createIfNotExists)throw new Error("Unknown axis.");setAxis(axis=new Axis,index)}return axis},Base.prototype.getConfigColorSet=function(){return this._configColorSet},Base.prototype.getLabels=function(){return this._labels},Base.prototype.getLegendOptions=function(){return this._legendOptions},Base.prototype.getSeries=function(){return this._series},Base.prototype.getTitle=function(){return this._title},Base.prototype.getType=function(){if(!this.TYPE)throw new Error("The TYPE property has not been set.");return this.TYPE},Base.prototype.getXAxes=function(){return this._xaxes},Base.prototype.getXAxis=function(index,createIfNotExists){return this.__getAxis("x",index,createIfNotExists)},Base.prototype.getYAxes=function(){return this._yaxes},Base.prototype.getYAxis=function(index,createIfNotExists){return this.__getAxis("y",index,createIfNotExists)},Base.prototype.setConfigColorSet=function(colorset){this._configColorSet=colorset},Base.prototype._setDefaults=function(){},Base.prototype.setLabels=function(labels){if(labels.length&&this._series.length&&this._series[0].length!=labels.length)throw new Error("Series must match label values.");this._labels=labels},Base.prototype.setLegendOptions=function(legendOptions){if("object"!=typeof legendOptions)throw new Error("Setting legend with non-object value:"+legendOptions);this._legendOptions=legendOptions},Base.prototype.setTitle=function(title){this._title=title},Base.prototype.setXAxis=function(axis,index){index=void 0===index?0:index,this._validateAxis("x",axis,index),this._xaxes[index]=axis},Base.prototype.setYAxis=function(axis,index){index=void 0===index?0:index,this._validateAxis("y",axis,index),this._yaxes[index]=axis},Base.prototype._validateAxis=function(xy,axis,index){if((index=void 0===index?0:index)>0&&void 0===("x"==xy?this._xaxes:this._yaxes)[index-1])throw new Error("Missing "+xy+" axis at index lower than "+index)},Base.prototype._validateSeries=function(series){if(this._series.length&&this._series[0].getCount()!=series.getCount())throw new Error("Series do not have an equal number of values.");if(this._labels.length&&this._labels.length!=series.getCount())throw new Error("Series must match label values.")},Base}));
define("core/chart_base",["core/chart_series","core/chart_axis"],(function(Series,Axis){function Base(){this._series=[],this._labels=[],this._xaxes=[],this._yaxes=[],this._setDefaults()}return Base.prototype._series=null,Base.prototype._labels=null,Base.prototype._legendOptions=null,Base.prototype._title=null,Base.prototype._xaxes=null,Base.prototype._yaxes=null,Base.prototype.COLORSET=["#f3c300","#875692","#f38400","#a1caf1","#be0032","#c2b280","#7f180d","#008856","#e68fac","#0067a5"],Base.prototype._configColorSet=null,Base.prototype.TYPE=null,Base.prototype._responsiveOptions=null,Base.prototype.addSeries=function(series){if(this._validateSeries(series),this._series.push(series),null===series.getColor()){var configColorSet=this.getConfigColorSet()||Base.prototype.COLORSET;series.setColor(configColorSet[this._series.length%configColorSet.length])}},Base.prototype.create=function(Klass,data){var Chart=new Klass;return Chart.setConfigColorSet(data.config_colorset),Chart.setLabels(data.labels),Chart.setTitle(data.title),data.legend_options&&Chart.setLegendOptions(data.legend_options),data.responsive_options&&Chart.setResponsiveOptions(data.responsive_options),data.series.forEach((function(seriesData){Chart.addSeries(Series.prototype.create(seriesData))})),data.axes.x.forEach((function(axisData,i){Chart.setXAxis(Axis.prototype.create(axisData),i)})),data.axes.y.forEach((function(axisData,i){Chart.setYAxis(Axis.prototype.create(axisData),i)})),Chart},Base.prototype.__getAxis=function(xy,index,createIfNotExists){var axis,axes="x"===xy?this._xaxes:this._yaxes,setAxis=("x"===xy?this.setXAxis:this.setYAxis).bind(this);if(createIfNotExists=void 0!==createIfNotExists&&createIfNotExists,void 0===(axis=axes[index=void 0===index?0:index])){if(!createIfNotExists)throw new Error("Unknown axis.");setAxis(axis=new Axis,index)}return axis},Base.prototype.getConfigColorSet=function(){return this._configColorSet},Base.prototype.getLabels=function(){return this._labels},Base.prototype.getLegendOptions=function(){return this._legendOptions},Base.prototype.getSeries=function(){return this._series},Base.prototype.getTitle=function(){return this._title},Base.prototype.getType=function(){if(!this.TYPE)throw new Error("The TYPE property has not been set.");return this.TYPE},Base.prototype.getXAxes=function(){return this._xaxes},Base.prototype.getXAxis=function(index,createIfNotExists){return this.__getAxis("x",index,createIfNotExists)},Base.prototype.getYAxes=function(){return this._yaxes},Base.prototype.getYAxis=function(index,createIfNotExists){return this.__getAxis("y",index,createIfNotExists)},Base.prototype.getResponsiveOptions=function(){return this._responsiveOptions},Base.prototype.setConfigColorSet=function(colorset){this._configColorSet=colorset},Base.prototype._setDefaults=function(){},Base.prototype.setLabels=function(labels){if(labels.length&&this._series.length&&this._series[0].length!=labels.length)throw new Error("Series must match label values.");this._labels=labels},Base.prototype.setLegendOptions=function(legendOptions){if("object"!=typeof legendOptions)throw new Error("Setting legend with non-object value:"+legendOptions);this._legendOptions=legendOptions},Base.prototype.setTitle=function(title){this._title=title},Base.prototype.setXAxis=function(axis,index){index=void 0===index?0:index,this._validateAxis("x",axis,index),this._xaxes[index]=axis},Base.prototype.setYAxis=function(axis,index){index=void 0===index?0:index,this._validateAxis("y",axis,index),this._yaxes[index]=axis},Base.prototype.setResponsiveOptions=function(responsiveOptions){if("object"!=typeof responsiveOptions)throw new Error("Setting responsive options with non-object value:"+responsiveOptions);this._responsiveOptions=responsiveOptions},Base.prototype._validateAxis=function(xy,axis,index){if((index=void 0===index?0:index)>0&&void 0===("x"==xy?this._xaxes:this._yaxes)[index-1])throw new Error("Missing "+xy+" axis at index lower than "+index)},Base.prototype._validateSeries=function(series){if(this._series.length&&this._series[0].getCount()!=series.getCount())throw new Error("Series do not have an equal number of values.");if(this._labels.length&&this._labels.length!=series.getCount())throw new Error("Series must match label values.")},Base}));
//# sourceMappingURL=chart_base.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+32
View File
@@ -114,6 +114,14 @@ define(['core/chart_series', 'core/chart_axis'], function(Series, Axis) {
*/
Base.prototype.TYPE = null;
/**
* Options for chart responsiveness.
*
* @protected
* @type {Object}
*/
Base.prototype._responsiveOptions = null;
/**
* Add a series to the chart.
*
@@ -153,6 +161,9 @@ define(['core/chart_series', 'core/chart_axis'], function(Series, Axis) {
if (data.legend_options) {
Chart.setLegendOptions(data.legend_options);
}
if (data.responsive_options) {
Chart.setResponsiveOptions(data.responsive_options);
}
data.series.forEach(function(seriesData) {
Chart.addSeries(Series.prototype.create(seriesData));
});
@@ -292,6 +303,15 @@ define(['core/chart_series', 'core/chart_axis'], function(Series, Axis) {
return this.__getAxis('y', index, createIfNotExists);
};
/**
* Get responsive options for the chart.
*
* @return {Object}
*/
Base.prototype.getResponsiveOptions = function() {
return this._responsiveOptions;
};
/**
* Set colours defined by setting.
*
@@ -379,6 +399,18 @@ define(['core/chart_series', 'core/chart_axis'], function(Series, Axis) {
this._yaxes[index] = axis;
};
/**
* Set responsive options for chart.
*
* @param {Object} responsiveOptions
*/
Base.prototype.setResponsiveOptions = function(responsiveOptions) {
if (typeof responsiveOptions !== 'object') {
throw new Error('Setting responsive options with non-object value:' + responsiveOptions);
}
this._responsiveOptions = responsiveOptions;
};
/**
* Validate an axis.
*
+11
View File
@@ -222,6 +222,17 @@ define([
config.options.plugins.legend = legendOptions;
}
var responsiveOptions = this._chart.getResponsiveOptions();
if (responsiveOptions) {
// Possible values to be changed in the properties related to the chart's responsiveness.
const responsiveProperties = ['aspectRatio', 'maintainAspectRatio', 'responsive', 'resizeDelay'];
for (const key of responsiveProperties) {
const value = responsiveOptions[key];
if (value !== null && value !== undefined) {
config.options[key] = value;
}
}
}
this._chart.getXAxes().forEach(function(axis, i) {
var axisLabels = axis.getLabels();
+22
View File
@@ -50,6 +50,8 @@ class chart_base implements JsonSerializable, renderable {
protected $yaxes = [];
/** @var array Options for the chart legend. */
protected $legendoptions = [];
/** @var array Options for the chart responsiveness. */
protected $responsiveoptions = [];
/**
* Constructor.
@@ -89,6 +91,7 @@ class chart_base implements JsonSerializable, renderable {
'y' => $this->yaxes,
],
'legend_options' => !empty($this->legendoptions) ? $this->legendoptions : null,
'responsive_options' => !empty($this->responsiveoptions) ? $this->responsiveoptions : null,
'config_colorset' => !empty($CFG->chart_colorset) ? $CFG->chart_colorset : null
];
}
@@ -211,6 +214,15 @@ class chart_base implements JsonSerializable, renderable {
return $this->get_axis('y', $index, $createifnotexists);
}
/**
* Get an array of responsive options for the chart.
*
* @return array
*/
public function get_responsive_options() {
return $this->responsiveoptions;
}
/**
* Set the defaults for this chart type.
*
@@ -282,6 +294,16 @@ class chart_base implements JsonSerializable, renderable {
return $this->yaxes[$index] = $axis;
}
/**
* Set responsive options for the chart.
* See https://www.chartjs.org/docs/latest/configuration/responsive.html for options.
*
* @param array $responsiveoptions Whether or not to display the chart extra options.
*/
public function set_responsive_options(array $responsiveoptions) {
$this->responsiveoptions = $responsiveoptions;
}
/**
* Validate an axis.
*
+1
View File
@@ -54,6 +54,7 @@ $chart3->set_title('TENSIONED LINES CHART');
$chart3->add_series($sales);
$chart3->add_series($expenses);
$chart3->set_labels($labels);
$chart3->set_responsive_options(['aspectRatio' => 2, 'maintainAspectRatio' => true, 'resizeDelay' => 1]);
$chart4 = new \core\chart_line();
$chart4->set_smooth(true);