From df61405d058233a9fa219fbd6954d8c8fd70daec Mon Sep 17 00:00:00 2001 From: Pedro Jordao Date: Mon, 13 Jan 2025 11:22:38 -0300 Subject: [PATCH] MDL-78365 libraries: Truncate ChartJs labels to avoid display issues If the chart label is too large, it is breaking the display, so we will add ellipsis to the label and display the full text in the tooltip. --- lib/amd/build/chart_output_chartjs.min.js | 2 +- lib/amd/build/chart_output_chartjs.min.js.map | 2 +- lib/amd/src/chart_output_chartjs.js | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/amd/build/chart_output_chartjs.min.js b/lib/amd/build/chart_output_chartjs.min.js index 37237e0b650..84ec0cbd037 100644 --- a/lib/amd/build/chart_output_chartjs.min.js +++ b/lib/amd/build/chart_output_chartjs.min.js @@ -5,6 +5,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @module core/chart_output_chartjs */ -define("core/chart_output_chartjs",["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],(function($,Chartjs,Axis,Bar,Base,Line,Pie,Series){var makeAxisId=function(xy,index){return"axis-"+xy+"-"+index};function Output(){Base.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=$(""),this._node.append(this._canvas)),this._build()}return Output.prototype=Object.create(Base.prototype),Output.prototype._config=null,Output.prototype._chartjs=null,Output.prototype._canvas=null,Output.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new Chartjs(this._canvas[0],this._config)},Output.prototype._cleanData=function(data){return data instanceof Array?data.map((function(value){return $("").html(value).text()})):$("").html(data).text()},Output.prototype._getChartType=function(){var type=this._chart.getType();return this._chart.getType()===Bar.prototype.TYPE&&!0===this._chart.getHorizontal()?type="horizontalBar":this._chart.getType()===Pie.prototype.TYPE&&!0===this._chart.getDoughnut()&&(type="doughnut"),type},Output.prototype._makeAxisConfig=function(axis,xy,index){var scaleData={id:makeAxisId(xy,index)};return axis.getPosition()!==Axis.prototype.POS_DEFAULT&&(scaleData.position=axis.getPosition()),null!==axis.getLabel()&&(scaleData.title={display:!0,text:this._cleanData(axis.getLabel())}),null!==axis.getStepSize()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.stepSize=axis.getStepSize()),null!==axis.getMax()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.max=axis.getMax()),null!==axis.getMin()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.min=axis.getMin()),scaleData},Output.prototype._makeConfig=function(){var charType=this._getChartType(),config={type:charType,data:{labels:this._cleanData(this._chart.getLabels()),datasets:this._makeDatasetsConfig()},options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:null!==this._chart.getTitle(),text:this._cleanData(this._chart.getTitle())}}}};"horizontalBar"===charType&&(config.type="bar",config.options.indexAxis="y");var legendOptions=this._chart.getLegendOptions();return legendOptions&&(config.options.plugins.legend=legendOptions),this._chart.getXAxes().forEach(function(axis,i){var axisLabels=axis.getLabels();config.options.scales=config.options.scales||{},config.options.scales.x=config.options.scales.x||{},config.options.scales.x[i]=this._makeAxisConfig(axis,"x",i),null!==axisLabels&&(config.options.scales.x[i].ticks.callback=function(value,index){return axisLabels[index]||""}),config.options.scales.x.stacked=this._isStacked()}.bind(this)),this._chart.getYAxes().forEach(function(axis,i){var axisLabels=axis.getLabels();config.options.scales=config.options.scales||{},config.options.scales.y=config.options.scales.yAxes||{},config.options.scales.y[i]=this._makeAxisConfig(axis,"y",i),null!==axisLabels&&(config.options.scales.y[i].ticks.callback=function(value){return axisLabels[parseInt(value,10)]||""}),config.options.scales.y.stacked=this._isStacked()}.bind(this)),config.options.plugins.tooltip={callbacks:{label:this._makeTooltip.bind(this)}},config},Output.prototype._makeDatasetsConfig=function(){return this._chart.getSeries().map(function(series){var colors=series.hasColoredValues()?series.getColors():series.getColor(),dataset={label:this._cleanData(series.getLabel()),data:series.getValues(),type:series.getType(),fill:series.getFill(),backgroundColor:colors,borderColor:this._chart.getType()==Pie.prototype.TYPE?"#fff":colors,tension:this._isSmooth(series)?.3:0};return null!==series.getXAxis()&&(dataset.xAxisID=makeAxisId("x",series.getXAxis())),null!==series.getYAxis()&&(dataset.yAxisID=makeAxisId("y",series.getYAxis())),dataset}.bind(this))},Output.prototype._makeTooltip=function(tooltipItem){var serieLabel=this._chart.getSeries()[tooltipItem.datasetIndex].getLabel(),tooltipData=tooltipItem.dataset.data[tooltipItem.dataIndex],tooltip=[];if(this._chart.getType()===Pie.prototype.TYPE){var chartLabels=this._cleanData(this._chart.getLabels());tooltip.push(chartLabels[tooltipItem.dataIndex]+" - "+this._cleanData(serieLabel)+": "+tooltipData)}else tooltip.push(this._cleanData(serieLabel)+": "+tooltipData);return tooltip},Output.prototype._isSmooth=function(series){var smooth=!1;return this._chart.getType()===Line.prototype.TYPE?null===(smooth=series.getSmooth())&&(smooth=this._chart.getSmooth()):series.getType()===Series.prototype.TYPE_LINE&&(smooth=series.getSmooth()),smooth},Output.prototype._isStacked=function(){var stacked=!1;return this._chart.getType()===Bar.prototype.TYPE&&(stacked=this._chart.getStacked()),stacked},Output.prototype.update=function(){$.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},Output})); +define("core/chart_output_chartjs",["jquery","core/chartjs","core/chart_axis","core/chart_bar","core/chart_output_base","core/chart_line","core/chart_pie","core/chart_series"],(function($,Chartjs,Axis,Bar,Base,Line,Pie,Series){var makeAxisId=function(xy,index){return"axis-"+xy+"-"+index};function Output(){Base.prototype.constructor.apply(this,arguments),this._canvas=this._node,"CANVAS"!=this._canvas.prop("tagName")&&(this._canvas=$(""),this._node.append(this._canvas)),this._build()}return Output.prototype=Object.create(Base.prototype),Output.prototype._config=null,Output.prototype._chartjs=null,Output.prototype._canvas=null,Output.prototype._build=function(){this._config=this._makeConfig(),this._chartjs=new Chartjs(this._canvas[0],this._config)},Output.prototype._cleanData=function(data){return data instanceof Array?data.map((function(value){return $("").html(value).text()})):$("").html(data).text()},Output.prototype._getChartType=function(){var type=this._chart.getType();return this._chart.getType()===Bar.prototype.TYPE&&!0===this._chart.getHorizontal()?type="horizontalBar":this._chart.getType()===Pie.prototype.TYPE&&!0===this._chart.getDoughnut()&&(type="doughnut"),type},Output.prototype._makeAxisConfig=function(axis,xy,index){var scaleData={id:makeAxisId(xy,index)};return axis.getPosition()!==Axis.prototype.POS_DEFAULT&&(scaleData.position=axis.getPosition()),null!==axis.getLabel()&&(scaleData.title={display:!0,text:this._cleanData(axis.getLabel())}),null!==axis.getStepSize()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.stepSize=axis.getStepSize()),null!==axis.getMax()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.max=axis.getMax()),null!==axis.getMin()&&(scaleData.ticks=scaleData.ticks||{},scaleData.ticks.min=axis.getMin()),scaleData},Output.prototype._makeConfig=function(){var charType=this._getChartType(),labels=this._cleanData(this._chart.getLabels()),config={type:charType,data:{labels:labels.map((label=>label.length>25?"".concat(label.substring(0,25),"..."):label)),datasets:this._makeDatasetsConfig()},options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:null!==this._chart.getTitle(),text:this._cleanData(this._chart.getTitle())}}}};"horizontalBar"===charType&&(config.type="bar",config.options.indexAxis="y");var legendOptions=this._chart.getLegendOptions();return legendOptions&&(config.options.plugins.legend=legendOptions),this._chart.getXAxes().forEach(function(axis,i){var axisLabels=axis.getLabels();config.options.scales=config.options.scales||{},config.options.scales.x=config.options.scales.x||{},config.options.scales.x[i]=this._makeAxisConfig(axis,"x",i),null!==axisLabels&&(config.options.scales.x[i].ticks.callback=function(value,index){return axisLabels[index]||""}),config.options.scales.x.stacked=this._isStacked()}.bind(this)),this._chart.getYAxes().forEach(function(axis,i){var axisLabels=axis.getLabels();config.options.scales=config.options.scales||{},config.options.scales.y=config.options.scales.yAxes||{},config.options.scales.y[i]=this._makeAxisConfig(axis,"y",i),null!==axisLabels&&(config.options.scales.y[i].ticks.callback=function(value){return axisLabels[parseInt(value,10)]||""}),config.options.scales.y.stacked=this._isStacked()}.bind(this)),config.options.plugins.tooltip={callbacks:{title:ctx=>labels[ctx[0].dataIndex].match(/.{1,80}/g),label:this._makeTooltip.bind(this)}},config},Output.prototype._makeDatasetsConfig=function(){return this._chart.getSeries().map(function(series){var colors=series.hasColoredValues()?series.getColors():series.getColor(),dataset={label:this._cleanData(series.getLabel()),data:series.getValues(),type:series.getType(),fill:series.getFill(),backgroundColor:colors,borderColor:this._chart.getType()==Pie.prototype.TYPE?"#fff":colors,tension:this._isSmooth(series)?.3:0};return null!==series.getXAxis()&&(dataset.xAxisID=makeAxisId("x",series.getXAxis())),null!==series.getYAxis()&&(dataset.yAxisID=makeAxisId("y",series.getYAxis())),dataset}.bind(this))},Output.prototype._makeTooltip=function(tooltipItem){var serieLabel=this._chart.getSeries()[tooltipItem.datasetIndex].getLabel(),tooltipData=tooltipItem.dataset.data[tooltipItem.dataIndex],tooltip=[];if(this._chart.getType()===Pie.prototype.TYPE){var chartLabels=this._cleanData(this._chart.getLabels());tooltip.push(chartLabels[tooltipItem.dataIndex]+" - "+this._cleanData(serieLabel)+": "+tooltipData)}else tooltip.push(this._cleanData(serieLabel)+": "+tooltipData);return tooltip},Output.prototype._isSmooth=function(series){var smooth=!1;return this._chart.getType()===Line.prototype.TYPE?null===(smooth=series.getSmooth())&&(smooth=this._chart.getSmooth()):series.getType()===Series.prototype.TYPE_LINE&&(smooth=series.getSmooth()),smooth},Output.prototype._isStacked=function(){var stacked=!1;return this._chart.getType()===Bar.prototype.TYPE&&(stacked=this._chart.getStacked()),stacked},Output.prototype.update=function(){$.extend(!0,this._config,this._makeConfig()),this._chartjs.update()},Output})); //# sourceMappingURL=chart_output_chartjs.min.js.map \ No newline at end of file diff --git a/lib/amd/build/chart_output_chartjs.min.js.map b/lib/amd/build/chart_output_chartjs.min.js.map index 0acf2c7d24d..0b6efb427c6 100644 --- a/lib/amd/build/chart_output_chartjs.min.js.map +++ b/lib/amd/build/chart_output_chartjs.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chart_output_chartjs.min.js","sources":["../src/chart_output_chartjs.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Chart output for chart.js.\n *\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @module core/chart_output_chartjs\n */\ndefine([\n 'jquery',\n 'core/chartjs',\n 'core/chart_axis',\n 'core/chart_bar',\n 'core/chart_output_base',\n 'core/chart_line',\n 'core/chart_pie',\n 'core/chart_series'\n], function($, Chartjs, Axis, Bar, Base, Line, Pie, Series) {\n\n /**\n * Makes an axis ID.\n *\n * @param {String} xy Accepts 'x' and 'y'.\n * @param {Number} index The axis index.\n * @return {String}\n */\n var makeAxisId = function(xy, index) {\n return 'axis-' + xy + '-' + index;\n };\n\n /**\n * Chart output for Chart.js.\n *\n * @class\n * @extends {module:core/chart_output_base}\n */\n function Output() {\n Base.prototype.constructor.apply(this, arguments);\n\n // Make sure that we've got a canvas tag.\n this._canvas = this._node;\n if (this._canvas.prop('tagName') != 'CANVAS') {\n this._canvas = $('');\n this._node.append(this._canvas);\n }\n\n this._build();\n }\n Output.prototype = Object.create(Base.prototype);\n\n /**\n * Reference to the chart config object.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._config = null;\n\n /**\n * Reference to the instance of chart.js.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._chartjs = null;\n\n /**\n * Reference to the canvas node.\n *\n * @type {Jquery}\n * @protected\n */\n Output.prototype._canvas = null;\n\n /**\n * Builds the config and the chart.\n *\n * @protected\n */\n Output.prototype._build = function() {\n this._config = this._makeConfig();\n this._chartjs = new Chartjs(this._canvas[0], this._config);\n };\n\n /**\n * Clean data.\n *\n * @param {(String|String[])} data A single string or an array of strings.\n * @returns {(String|String[])}\n * @protected\n */\n Output.prototype._cleanData = function(data) {\n if (data instanceof Array) {\n return data.map(function(value) {\n return $('').html(value).text();\n });\n } else {\n return $('').html(data).text();\n }\n };\n\n /**\n * Get the chart type and handles the Chart.js specific chart types.\n *\n * By default returns the current chart TYPE value. Also does the handling of specific chart types, for example\n * check if the bar chart should be horizontal and the pie chart should be displayed as a doughnut.\n *\n * @method getChartType\n * @returns {String} the chart type.\n * @protected\n */\n Output.prototype._getChartType = function() {\n var type = this._chart.getType();\n\n // Bars can be displayed vertically and horizontally, defining horizontalBar type.\n if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) {\n type = 'horizontalBar';\n } else if (this._chart.getType() === Pie.prototype.TYPE && this._chart.getDoughnut() === true) {\n // Pie chart can be displayed as doughnut.\n type = 'doughnut';\n }\n\n return type;\n };\n\n /**\n * Make the axis config.\n *\n * @protected\n * @param {module:core/chart_axis} axis The axis.\n * @param {String} xy Accepts 'x' or 'y'.\n * @param {Number} index The axis index.\n * @return {Object} The axis config.\n */\n Output.prototype._makeAxisConfig = function(axis, xy, index) {\n var scaleData = {\n id: makeAxisId(xy, index)\n };\n\n if (axis.getPosition() !== Axis.prototype.POS_DEFAULT) {\n scaleData.position = axis.getPosition();\n }\n\n if (axis.getLabel() !== null) {\n scaleData.title = {\n display: true,\n text: this._cleanData(axis.getLabel())\n };\n }\n\n if (axis.getStepSize() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.stepSize = axis.getStepSize();\n }\n\n if (axis.getMax() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.max = axis.getMax();\n }\n\n if (axis.getMin() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.min = axis.getMin();\n }\n\n return scaleData;\n };\n\n /**\n * Make the config config.\n *\n * @protected\n * @return {Object} The axis config.\n */\n Output.prototype._makeConfig = function() {\n var charType = this._getChartType();\n var config = {\n type: charType,\n data: {\n labels: this._cleanData(this._chart.getLabels()),\n datasets: this._makeDatasetsConfig()\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n title: {\n display: this._chart.getTitle() !== null,\n text: this._cleanData(this._chart.getTitle())\n }\n }\n }\n };\n\n if (charType === 'horizontalBar') {\n config.type = 'bar';\n config.options.indexAxis = 'y';\n }\n\n var legendOptions = this._chart.getLegendOptions();\n if (legendOptions) {\n config.options.plugins.legend = legendOptions;\n }\n\n\n this._chart.getXAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.x = config.options.scales.x || {};\n config.options.scales.x[i] = this._makeAxisConfig(axis, 'x', i);\n\n if (axisLabels !== null) {\n config.options.scales.x[i].ticks.callback = function(value, index) {\n return axisLabels[index] || '';\n };\n }\n config.options.scales.x.stacked = this._isStacked();\n }.bind(this));\n\n this._chart.getYAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.y = config.options.scales.yAxes || {};\n config.options.scales.y[i] = this._makeAxisConfig(axis, 'y', i);\n\n if (axisLabels !== null) {\n config.options.scales.y[i].ticks.callback = function(value) {\n return axisLabels[parseInt(value, 10)] || '';\n };\n }\n config.options.scales.y.stacked = this._isStacked();\n }.bind(this));\n\n config.options.plugins.tooltip = {\n callbacks: {\n label: this._makeTooltip.bind(this)\n }\n };\n\n return config;\n };\n\n /**\n * Get the datasets configurations.\n *\n * @protected\n * @return {Object[]}\n */\n Output.prototype._makeDatasetsConfig = function() {\n var sets = this._chart.getSeries().map(function(series) {\n var colors = series.hasColoredValues() ? series.getColors() : series.getColor();\n var dataset = {\n label: this._cleanData(series.getLabel()),\n data: series.getValues(),\n type: series.getType(),\n fill: series.getFill(),\n backgroundColor: colors,\n // Pie charts look better without borders.\n borderColor: this._chart.getType() == Pie.prototype.TYPE ? '#fff' : colors,\n tension: this._isSmooth(series) ? 0.3 : 0\n };\n\n if (series.getXAxis() !== null) {\n dataset.xAxisID = makeAxisId('x', series.getXAxis());\n }\n if (series.getYAxis() !== null) {\n dataset.yAxisID = makeAxisId('y', series.getYAxis());\n }\n\n return dataset;\n }.bind(this));\n return sets;\n };\n\n /**\n * Get the chart data, add labels and rebuild the tooltip.\n *\n * @param {Object[]} tooltipItem The tooltip item object.\n * @returns {Array}\n * @protected\n */\n Output.prototype._makeTooltip = function(tooltipItem) {\n\n // Get series and chart data to rebuild the tooltip and add labels.\n var series = this._chart.getSeries()[tooltipItem.datasetIndex];\n var serieLabel = series.getLabel();\n var chartData = tooltipItem.dataset.data;\n var tooltipData = chartData[tooltipItem.dataIndex];\n\n // Build default tooltip.\n var tooltip = [];\n\n // Pie and doughnut charts tooltip are different.\n if (this._chart.getType() === Pie.prototype.TYPE) {\n var chartLabels = this._cleanData(this._chart.getLabels());\n tooltip.push(chartLabels[tooltipItem.dataIndex] + ' - ' + this._cleanData(serieLabel) + ': ' + tooltipData);\n } else {\n tooltip.push(this._cleanData(serieLabel) + ': ' + tooltipData);\n }\n\n return tooltip;\n };\n\n /**\n * Verify if the chart line is smooth or not.\n *\n * @protected\n * @param {module:core/chart_series} series The series.\n * @returns {Bool}\n */\n Output.prototype._isSmooth = function(series) {\n var smooth = false;\n if (this._chart.getType() === Line.prototype.TYPE) {\n smooth = series.getSmooth();\n if (smooth === null) {\n smooth = this._chart.getSmooth();\n }\n } else if (series.getType() === Series.prototype.TYPE_LINE) {\n smooth = series.getSmooth();\n }\n\n return smooth;\n };\n\n /**\n * Verify if the bar chart is stacked or not.\n *\n * @protected\n * @returns {Bool}\n */\n Output.prototype._isStacked = function() {\n var stacked = false;\n\n // Stacking is (currently) only supported for bar charts.\n if (this._chart.getType() === Bar.prototype.TYPE) {\n stacked = this._chart.getStacked();\n }\n\n return stacked;\n };\n\n /** @override */\n Output.prototype.update = function() {\n $.extend(true, this._config, this._makeConfig());\n this._chartjs.update();\n };\n\n return Output;\n\n});\n"],"names":["define","$","Chartjs","Axis","Bar","Base","Line","Pie","Series","makeAxisId","xy","index","Output","prototype","constructor","apply","this","arguments","_canvas","_node","prop","append","_build","Object","create","_config","_chartjs","_makeConfig","_cleanData","data","Array","map","value","html","text","_getChartType","type","_chart","getType","TYPE","getHorizontal","getDoughnut","_makeAxisConfig","axis","scaleData","id","getPosition","POS_DEFAULT","position","getLabel","title","display","getStepSize","ticks","stepSize","getMax","max","getMin","min","charType","config","labels","getLabels","datasets","_makeDatasetsConfig","options","responsive","maintainAspectRatio","plugins","getTitle","indexAxis","legendOptions","getLegendOptions","legend","getXAxes","forEach","i","axisLabels","scales","x","callback","stacked","_isStacked","bind","getYAxes","y","yAxes","parseInt","tooltip","callbacks","label","_makeTooltip","getSeries","series","colors","hasColoredValues","getColors","getColor","dataset","getValues","fill","getFill","backgroundColor","borderColor","tension","_isSmooth","getXAxis","xAxisID","getYAxis","yAxisID","tooltipItem","serieLabel","datasetIndex","tooltipData","dataIndex","chartLabels","push","smooth","getSmooth","TYPE_LINE","getStacked","update","extend"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"chart_output_chartjs.min.js","sources":["../src/chart_output_chartjs.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Chart output for chart.js.\n *\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @module core/chart_output_chartjs\n */\ndefine([\n 'jquery',\n 'core/chartjs',\n 'core/chart_axis',\n 'core/chart_bar',\n 'core/chart_output_base',\n 'core/chart_line',\n 'core/chart_pie',\n 'core/chart_series'\n], function($, Chartjs, Axis, Bar, Base, Line, Pie, Series) {\n\n /**\n * Makes an axis ID.\n *\n * @param {String} xy Accepts 'x' and 'y'.\n * @param {Number} index The axis index.\n * @return {String}\n */\n var makeAxisId = function(xy, index) {\n return 'axis-' + xy + '-' + index;\n };\n\n /**\n * Chart output for Chart.js.\n *\n * @class\n * @extends {module:core/chart_output_base}\n */\n function Output() {\n Base.prototype.constructor.apply(this, arguments);\n\n // Make sure that we've got a canvas tag.\n this._canvas = this._node;\n if (this._canvas.prop('tagName') != 'CANVAS') {\n this._canvas = $('');\n this._node.append(this._canvas);\n }\n\n this._build();\n }\n Output.prototype = Object.create(Base.prototype);\n\n /**\n * Reference to the chart config object.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._config = null;\n\n /**\n * Reference to the instance of chart.js.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._chartjs = null;\n\n /**\n * Reference to the canvas node.\n *\n * @type {Jquery}\n * @protected\n */\n Output.prototype._canvas = null;\n\n /**\n * Builds the config and the chart.\n *\n * @protected\n */\n Output.prototype._build = function() {\n this._config = this._makeConfig();\n this._chartjs = new Chartjs(this._canvas[0], this._config);\n };\n\n /**\n * Clean data.\n *\n * @param {(String|String[])} data A single string or an array of strings.\n * @returns {(String|String[])}\n * @protected\n */\n Output.prototype._cleanData = function(data) {\n if (data instanceof Array) {\n return data.map(function(value) {\n return $('').html(value).text();\n });\n } else {\n return $('').html(data).text();\n }\n };\n\n /**\n * Get the chart type and handles the Chart.js specific chart types.\n *\n * By default returns the current chart TYPE value. Also does the handling of specific chart types, for example\n * check if the bar chart should be horizontal and the pie chart should be displayed as a doughnut.\n *\n * @method getChartType\n * @returns {String} the chart type.\n * @protected\n */\n Output.prototype._getChartType = function() {\n var type = this._chart.getType();\n\n // Bars can be displayed vertically and horizontally, defining horizontalBar type.\n if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) {\n type = 'horizontalBar';\n } else if (this._chart.getType() === Pie.prototype.TYPE && this._chart.getDoughnut() === true) {\n // Pie chart can be displayed as doughnut.\n type = 'doughnut';\n }\n\n return type;\n };\n\n /**\n * Make the axis config.\n *\n * @protected\n * @param {module:core/chart_axis} axis The axis.\n * @param {String} xy Accepts 'x' or 'y'.\n * @param {Number} index The axis index.\n * @return {Object} The axis config.\n */\n Output.prototype._makeAxisConfig = function(axis, xy, index) {\n var scaleData = {\n id: makeAxisId(xy, index)\n };\n\n if (axis.getPosition() !== Axis.prototype.POS_DEFAULT) {\n scaleData.position = axis.getPosition();\n }\n\n if (axis.getLabel() !== null) {\n scaleData.title = {\n display: true,\n text: this._cleanData(axis.getLabel())\n };\n }\n\n if (axis.getStepSize() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.stepSize = axis.getStepSize();\n }\n\n if (axis.getMax() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.max = axis.getMax();\n }\n\n if (axis.getMin() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.min = axis.getMin();\n }\n\n return scaleData;\n };\n\n /**\n * Make the config config.\n *\n * @protected\n * @return {Object} The axis config.\n */\n Output.prototype._makeConfig = function() {\n var charType = this._getChartType();\n var labels = this._cleanData(this._chart.getLabels());\n var config = {\n type: charType,\n data: {\n // If the label is longer than 25 characters, truncate it and add an\n // ellipsis to avoid breaking the chart.\n labels: labels.map((label) => {\n return label.length > 25 ? `${label.substring(0, 25)}...` : label;\n }),\n datasets: this._makeDatasetsConfig()\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n title: {\n display: this._chart.getTitle() !== null,\n text: this._cleanData(this._chart.getTitle())\n }\n }\n }\n };\n\n if (charType === 'horizontalBar') {\n config.type = 'bar';\n config.options.indexAxis = 'y';\n }\n\n var legendOptions = this._chart.getLegendOptions();\n if (legendOptions) {\n config.options.plugins.legend = legendOptions;\n }\n\n\n this._chart.getXAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.x = config.options.scales.x || {};\n config.options.scales.x[i] = this._makeAxisConfig(axis, 'x', i);\n\n if (axisLabels !== null) {\n config.options.scales.x[i].ticks.callback = function(value, index) {\n return axisLabels[index] || '';\n };\n }\n config.options.scales.x.stacked = this._isStacked();\n }.bind(this));\n\n this._chart.getYAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.y = config.options.scales.yAxes || {};\n config.options.scales.y[i] = this._makeAxisConfig(axis, 'y', i);\n\n if (axisLabels !== null) {\n config.options.scales.y[i].ticks.callback = function(value) {\n return axisLabels[parseInt(value, 10)] || '';\n };\n }\n config.options.scales.y.stacked = this._isStacked();\n }.bind(this));\n\n config.options.plugins.tooltip = {\n callbacks: {\n title: (ctx) => {\n // Add line breaks to the tooltip title to prevent the tooltip from cutting\n // off if the title has a character count that overlaps the width of the chart.\n var label = labels[ctx[0].dataIndex];\n return label.match(/.{1,80}/g);\n },\n label: this._makeTooltip.bind(this)\n }\n };\n\n return config;\n };\n\n /**\n * Get the datasets configurations.\n *\n * @protected\n * @return {Object[]}\n */\n Output.prototype._makeDatasetsConfig = function() {\n var sets = this._chart.getSeries().map(function(series) {\n var colors = series.hasColoredValues() ? series.getColors() : series.getColor();\n var dataset = {\n label: this._cleanData(series.getLabel()),\n data: series.getValues(),\n type: series.getType(),\n fill: series.getFill(),\n backgroundColor: colors,\n // Pie charts look better without borders.\n borderColor: this._chart.getType() == Pie.prototype.TYPE ? '#fff' : colors,\n tension: this._isSmooth(series) ? 0.3 : 0\n };\n\n if (series.getXAxis() !== null) {\n dataset.xAxisID = makeAxisId('x', series.getXAxis());\n }\n if (series.getYAxis() !== null) {\n dataset.yAxisID = makeAxisId('y', series.getYAxis());\n }\n\n return dataset;\n }.bind(this));\n return sets;\n };\n\n /**\n * Get the chart data, add labels and rebuild the tooltip.\n *\n * @param {Object[]} tooltipItem The tooltip item object.\n * @returns {Array}\n * @protected\n */\n Output.prototype._makeTooltip = function(tooltipItem) {\n\n // Get series and chart data to rebuild the tooltip and add labels.\n var series = this._chart.getSeries()[tooltipItem.datasetIndex];\n var serieLabel = series.getLabel();\n var chartData = tooltipItem.dataset.data;\n var tooltipData = chartData[tooltipItem.dataIndex];\n\n // Build default tooltip.\n var tooltip = [];\n\n // Pie and doughnut charts tooltip are different.\n if (this._chart.getType() === Pie.prototype.TYPE) {\n var chartLabels = this._cleanData(this._chart.getLabels());\n tooltip.push(chartLabels[tooltipItem.dataIndex] + ' - ' + this._cleanData(serieLabel) + ': ' + tooltipData);\n } else {\n tooltip.push(this._cleanData(serieLabel) + ': ' + tooltipData);\n }\n\n return tooltip;\n };\n\n /**\n * Verify if the chart line is smooth or not.\n *\n * @protected\n * @param {module:core/chart_series} series The series.\n * @returns {Bool}\n */\n Output.prototype._isSmooth = function(series) {\n var smooth = false;\n if (this._chart.getType() === Line.prototype.TYPE) {\n smooth = series.getSmooth();\n if (smooth === null) {\n smooth = this._chart.getSmooth();\n }\n } else if (series.getType() === Series.prototype.TYPE_LINE) {\n smooth = series.getSmooth();\n }\n\n return smooth;\n };\n\n /**\n * Verify if the bar chart is stacked or not.\n *\n * @protected\n * @returns {Bool}\n */\n Output.prototype._isStacked = function() {\n var stacked = false;\n\n // Stacking is (currently) only supported for bar charts.\n if (this._chart.getType() === Bar.prototype.TYPE) {\n stacked = this._chart.getStacked();\n }\n\n return stacked;\n };\n\n /** @override */\n Output.prototype.update = function() {\n $.extend(true, this._config, this._makeConfig());\n this._chartjs.update();\n };\n\n return Output;\n\n});\n"],"names":["define","$","Chartjs","Axis","Bar","Base","Line","Pie","Series","makeAxisId","xy","index","Output","prototype","constructor","apply","this","arguments","_canvas","_node","prop","append","_build","Object","create","_config","_chartjs","_makeConfig","_cleanData","data","Array","map","value","html","text","_getChartType","type","_chart","getType","TYPE","getHorizontal","getDoughnut","_makeAxisConfig","axis","scaleData","id","getPosition","POS_DEFAULT","position","getLabel","title","display","getStepSize","ticks","stepSize","getMax","max","getMin","min","charType","labels","getLabels","config","label","length","substring","datasets","_makeDatasetsConfig","options","responsive","maintainAspectRatio","plugins","getTitle","indexAxis","legendOptions","getLegendOptions","legend","getXAxes","forEach","i","axisLabels","scales","x","callback","stacked","_isStacked","bind","getYAxes","y","yAxes","parseInt","tooltip","callbacks","ctx","dataIndex","match","_makeTooltip","getSeries","series","colors","hasColoredValues","getColors","getColor","dataset","getValues","fill","getFill","backgroundColor","borderColor","tension","_isSmooth","getXAxis","xAxisID","getYAxis","yAxisID","tooltipItem","serieLabel","datasetIndex","tooltipData","chartLabels","push","smooth","getSmooth","TYPE_LINE","getStacked","update","extend"],"mappings":"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"} \ 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 ddd6c71927b..4981cb8fb53 100644 --- a/lib/amd/src/chart_output_chartjs.js +++ b/lib/amd/src/chart_output_chartjs.js @@ -188,10 +188,15 @@ define([ */ Output.prototype._makeConfig = function() { var charType = this._getChartType(); + var labels = this._cleanData(this._chart.getLabels()); var config = { type: charType, data: { - labels: this._cleanData(this._chart.getLabels()), + // If the label is longer than 25 characters, truncate it and add an + // ellipsis to avoid breaking the chart. + labels: labels.map((label) => { + return label.length > 25 ? `${label.substring(0, 25)}...` : label; + }), datasets: this._makeDatasetsConfig() }, options: { @@ -249,6 +254,12 @@ define([ config.options.plugins.tooltip = { callbacks: { + title: (ctx) => { + // Add line breaks to the tooltip title to prevent the tooltip from cutting + // off if the title has a character count that overlaps the width of the chart. + var label = labels[ctx[0].dataIndex]; + return label.match(/.{1,80}/g); + }, label: this._makeTooltip.bind(this) } };