26

I have some bar charts that have really long labels and they affect the size of the charts.

Example: http://jsfiddle.net/norbiu/aqa8w19d/4/

I'm trying to truncate the labels that show up under the chart while keeping the label that shows up in the tooltips when hovering over a bar. The problem is that the tooltips and the canvas labels both get their values from the labels array in the data structure. Truncating the value will show the shortened version in both locations.

sales: ko.observable({
    labels: ['A really really long label', 'Another long labe', 'A third label that is long', 'Q4', 'Q5', 'Q6'],
    datasets: [{
        label: 'Helados',
        fillColor: '#152491',
        data: [70, 32, 6, 23, 63, 43]
    }]
}),

The documentation has nothing on this. Any ideas?

Norbert
  • 2,741
  • 8
  • 56
  • 111

4 Answers4

41

In Chart JS V2 you can truncate labels passing the options object. Also you can customize the tooltips.

options:{
    scales: {
        xAxes: [{
            ticks: {
                callback: function(value) {
                    return value.substr(0, 10);//truncate
                },
            }
        }],
        yAxes: [{}]
    },
    tooltips: {
        enabled: true,
        mode: 'label',
        callbacks: {
            title: function(tooltipItems, data) {
                var idx = tooltipItems[0].index;
                return 'Title:' + data.labels[idx];//do something with title
            },
            label: function(tooltipItems, data) {
                //var idx = tooltipItems.index;
                //return data.labels[idx] + ' €';
                return tooltipItems.xLabel + ' €';
            }
        }
    },
}
ursuleacv
  • 1,119
  • 14
  • 16
  • 1
    How can we do this for the Radar Chart? The problem I encountered is When I used the lengthy label then the Chart become smaller than we expect. For that I am trying to truncate the Point Labels. But when I truncate the labels it's affect the Point Labels and as well as the Tooltip Title or the Label. – Hariprasath Oct 23 '18 at 03:43
  • What about the latest `ChartJS` library. Is that working in it – Awais Nov 20 '19 at 07:45
1

So the way i went about this was to add a new option called labelLength which, if passed a number greater than 0, will trim the labels on the x axis to that length.

It happens in the scale class of the chart and will only apply to the axis label and not the tool tip.

If you wanted you could extract the relevant bits and just override the scale class and also the build scale function in the bar chart to include the new option.

In the scale class here is what was added

 Chart.Scale = Chart.Element.extend({
        initialize: function() {
            //truncate the labels if option is grater than 0
            this.xLabels = this.labelLength > 0 ? this.xLabels.map(this.truncateLabel, this) : this.xLabels;
            this.fit();
        },
        truncateLabel: function(label) {
            return label.substring(0, this.labelLength);
        },

        addXLabel: function(label) {
            //also added here for when adding single items of data to a graph
            this.xLabels.push(this.labelLength > 0 ? this.truncateLabel(label) : label);
            this.valuesCount++;
            this.fit();
        },

}

then in the bar buildscale function you would need to pass the option to the scale.

Or i have included this in my fork of chart js (https://github.com/leighquince/Chart.js) to use just pass the option labelLength with your desired labels length, example below

var randomScalingFactor = function() {
  return Math.round(Math.random() * 100)
};

var barChartData = {
  labels: ["January a really long label", "February a really long label", "March a really long label", "April a really long label", "May a really long label", "June a really long label", "July a really long label"],
  datasets: [{
    fillColor: "rgba(220,220,220,0.5)",
    strokeColor: "rgba(220,220,220,0.8)",
    highlightFill: "rgba(220,220,220,0.75)",
    highlightStroke: "rgba(220,220,220,1)",
    data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
  }, {
    fillColor: "rgba(151,187,205,0.5)",
    strokeColor: "rgba(151,187,205,0.8)",
    highlightFill: "rgba(151,187,205,0.75)",
    highlightStroke: "rgba(151,187,205,1)",
    data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
  }, {
    fillColor: "rgba(15,18,20,0.5)",
    strokeColor: "rgba(15,18,20,0.8)",
    highlightFill: "rgba(15,18,20,0.75)",
    highlightStroke: "rgba(15,18,20,1)",
    data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
  }]

}
window.onload = function() {
  var ctx = document.getElementById("canvas").getContext("2d");
  window.myBar = new Chart(ctx).Bar(barChartData, {
    labelLength: 10,
  });
}
<script src="http://www.quincewebdesign.com/cdn/Chart.js"></script>
<div style="width: 50%">
  <canvas id="canvas" height="450" width="600"></canvas>
</div>
Quince
  • 14,790
  • 6
  • 60
  • 69
  • 1
    This is excellent. You can improve it a bit visually by adding an ellipsis to the end of the truncated labels, to indicate that they have been truncated. Also, there could be situations where multiple labels share first words, for example. "English", "English History" and "English Geography". If my `labelLength` is set to 7, then all three labels will say "English", instead of "English" for the first label and "English..." for the last two. Users will expect more text there and wil get it on hover. – Norbert Feb 06 '15 at 15:00
  • 2
    cheers for the feedback, yeah i like the idea about the ellipse to show visually it has been truncated, the second example seems very specific but I agree that just being able to trim a set amount is limiting. perhaps instead the option for the labelLength can also be a function that receives the label as an argument and returns the desired label. In cases like this you could get it to output whatever you wanted. – Quince Feb 09 '15 at 10:42
  • That would be useful, but I'm not sure how that could work with a user specific array of labels coming from the server. – Norbert Feb 12 '15 at 13:05
  • 1
    @Quince, totally failed to make this work with chartjs 2 – iamcastelli Mar 25 '16 at 06:48
  • 1
    @iamcastelli Yeah in 2.x they treat the scale and the axis differently – Quince Mar 25 '16 at 07:02
  • @Quince Any ideas about how to approach that in CJ2? – iamcastelli Mar 25 '16 at 12:11
  • In Chart JS V2 you can truncate labels passing the options object: options: { scales: { xAxes: [{ ticks: { callback: function(value) { return value.substr(0, 10);//truncate }, } }], yAxes: [{}] }, } – ursuleacv Sep 16 '16 at 17:59
  • @ursuleacv this will truncate your ticks, not labels. – Vitalij Nov 14 '16 at 10:50
  • @Quince Is it applicable for the Radar chart? I am really struggling to do this for the Radar Chart. – Hariprasath Oct 23 '18 at 03:27
0

Just some additional info (can't comment, but thought this would be helpful) I added a small bit of code to the answer above to get "..." to show if labels are truncated.

truncateLabel: function(label) {
    var xSubstring = label.substring(0, this.labelLength);
    if(xSubstring.length < this.labelLength) {
        return xSubstring;  
    } else {
        // Check if a word is cut off
        if ( ' ' != label.charAt( (this.labelLength-1) ) && ' ' != label.charAt( this.labelLength ) ) {
            // If so, cut the label off at the last space instead of mid-word
            var last_space_pos = label.lastIndexOf(" ", this.labelLength);
            last_space_pos = (0 > last_space_pos)? this.labelLength: last_space_pos;
            xSubstring = label.substring(0, last_space_pos);
        }
        return xSubstring+"...";
    }
},
Philip
  • 2,888
  • 2
  • 24
  • 36
Dustin Maxey
  • 125
  • 1
  • 12
0

This can be achieved without modifying the plugin code with customTooltips:function(tooltip) option documented here.
A sample code is also provided here to modifying tooltips for line graph. Using that snippet its fairly easy to achieve the desired behavior.
- Create a div for custom tooltip.
- Truncate the labels for x-axis but keep the mapping to original text in an array.
- In customTooltip function, populate tooltip div with original text by using tooltip.text as key in mapping array.

Terminal
  • 1,969
  • 5
  • 21
  • 37