diff --git a/addons/survey/static/src/js/survey_session_chart.js b/addons/survey/static/src/js/survey_session_chart.js
index 2198afcceee..a4e74555193 100644
--- a/addons/survey/static/src/js/survey_session_chart.js
+++ b/addons/survey/static/src/js/survey_session_chart.js
@@ -166,6 +166,89 @@ publicWidget.registry.SurveySessionChart = publicWidget.Widget.extend({
}
}
},
+ plugins: [{
+ /**
+ * The way it works is each label is an array of words.
+ * eg.: if we have a chart label: "this is an example of a label"
+ * The library will split it as: ["this is an example", "of a label"]
+ * Each value of the array represents a line of the label.
+ * So for this example above: it will be displayed as:
+ * "this is an examble
of a label", breaking the label in 2 parts and put on 2 lines visually.
+ *
+ * What we do here is rework the labels with our own algorithm to make them fit better in screen space
+ * based on breakpoints based on number of columns to display.
+ * So this example will become: ["this is an", "example of", "a label"] if we have a lot of labels to put in the chart.
+ * Which will be displayed as "this is an
example of
a label"
+ * Obviously, the more labels you have, the more columns, and less screen space is available.
+ *
+ * We also adapt the font size based on the width available in the chart.
+ *
+ * So we counterbalance multiple times:
+ * - Based on number of columns (i.e. number of survey.question.answer of your current survey.question),
+ * we split the words of every labels to make them display on more rows.
+ * - Based on the width of the chart (which is equivalent to screen width),
+ * we reduce the chart font to be able to fit more characters.
+ * - Based on the longest word present in the labels, we apply a certain ratio with the width of the chart
+ * to get a more accurate font size for the space available.
+ *
+ * @param {Object} chart
+ */
+ beforeInit: function (chart) {
+ const nbrCol = chart.data.labels.length;
+ const minRatio = 0.4;
+ // Numbers of maximum characters per line to print based on the number of columns and default ratio for the font size
+ // Between 1 and 2 -> 25, 3 and 4 -> 20, 5 and 6 -> 15, ...
+ const charPerLineBreakpoints = [
+ [1, 2, 25, minRatio],
+ [3, 4, 20, minRatio],
+ [5, 6, 15, 0.45],
+ [7, 8, 10, 0.65],
+ [9, null, 7, 0.7],
+ ];
+
+ let charPerLine;
+ let fontRatio;
+ charPerLineBreakpoints.forEach(([lowerBound, upperBound, value, ratio]) => {
+ if (nbrCol >= lowerBound && (upperBound === null || nbrCol <= upperBound)) {
+ charPerLine = value;
+ fontRatio = ratio;
+ }
+ });
+
+ // Adapt font size if the number of characters per line is under the maximum
+ if (charPerLine < 25) {
+ const allWords = chart.data.labels.reduce((accumulator, words) => accumulator.concat(' '.concat(words)));
+ const maxWordLength = Math.max(...allWords.split(' ').map((word) => word.length));
+ fontRatio = maxWordLength > charPerLine ? minRatio : fontRatio;
+ chart.options.scales.xAxes[0].ticks.fontSize = Math.min(parseInt(chart.options.scales.xAxes[0].ticks.fontSize), chart.width * fontRatio / (nbrCol));
+ }
+
+ chart.data.labels.forEach(function (label, index, labelsList) {
+ // Split all the words of the label
+ const words = label.split(" ");
+ let resultLines = [];
+ let currentLine = [];
+ for (let i = 0; i < words.length; i++) {
+ // If the word we are adding exceed already the number of characters for the line, we add it anyway before passing to a new line
+ currentLine.push(words[i]);
+
+ // Continue to add words in the line if there is enough space and if there is at least one more word to add
+ const nextWord = i+1 < words.length ? words[i+1] : null;
+ if (nextWord) {
+ const nextLength = currentLine.join(' ').length + nextWord.length;
+ if (nextLength <= charPerLine) {
+ continue;
+ }
+ }
+ // Add the constructed line and reset the variable for the next line
+ const newLabelLine = currentLine.join(' ');
+ resultLines.push(newLabelLine);
+ currentLine = [];
+ }
+ labelsList[index] = resultLines;
+ });
+ },
+ }],
};
},
@@ -176,7 +259,7 @@ publicWidget.registry.SurveySessionChart = publicWidget.Widget.extend({
*/
_extractChartLabels: function () {
return this.questionStatistics.map(function (point) {
- return point.text.length > 20 ? point.text.substring(0, 17) + '...' : point.text;
+ return point.text;
});
},