Merge branch 'MDL-85158' of https://github.com/pedrojordao/moodle into main

This commit is contained in:
Paul Holden
2025-06-18 10:01:45 +01:00
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);