Wednesday, November 14, 2018

Sorting C3 chart tooltip

C3 is very simple free JavaScript library that allows to create various types of chart literally in few lines of code. C3 is based on D3 so we must plugin it as well

  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
  2. <script src="https://unpkg.com/c3@0.6.8/c3.js"></script>
  3. <link href="https://unpkg.com/c3@0.6.8/c3.css" rel="stylesheet">
  4. <div id="chart"></div>
  5. <script>
  6. var chart = c3.generate({
  7. bindto: '#chart',
  8. data: {
  9. columns: [
  10. ['data1', 30, 200, 100, 400, 250],
  11. ['data2', 50, 20, 10, 40, 25],
  12. ['data3', 150, 10, 40, 40, 15],
  13. ['data4', 80, 40, 70, 20, 45],
  14. ['data5', 30, 60, 35, 90, 40]
  15. ]}
  16. });
  17. </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
  <script src="https://unpkg.com/c3@0.6.8/c3.js"></script>
  <link href="https://unpkg.com/c3@0.6.8/c3.css" rel="stylesheet">

  <div id="chart"></div>
  <script>
    var chart = c3.generate({
     bindto: '#chart',
     data: {
       columns: [
        ['data1', 30, 200, 100, 400, 250],
        ['data2', 50, 20, 10, 40, 25],
        ['data3', 150, 10, 40, 40, 15],
        ['data4', 80, 40, 70, 20, 45],
        ['data5', 30, 60, 35, 90, 40]
       ]}
      });
  </script>

That small code snippet produces such a beautiful chart with a tooltip:


0123405010015020025030035040001234data1data2data3data4data5


But as you can see, the data in the tooltip are not sorted. The goal of this post is to show how to sort it. 

Unfortunately, there is no a simple option to achieve this. We have to override whole the tooltip code for that. The key property here is contents. It allows to use a custom template for tooltip appearance

  1. <script>
  2. var chart = c3.generate({
  3. bindto: '#chart',
  4. data: {
  5. columns: [
  6. ['data1', 30, 200, 100, 400, 250],
  7. ['data2', 50, 20, 10, 40, 25],
  8. ['data3', 150, 10, 40, 40, 15],
  9. ['data4', 80, 40, 70, 20, 45],
  10. ['data5', 30, 60, 35, 90, 40]
  11. ]},
  12. tooltip: {
  13. contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
  14. var $$ = this, config = $$.config,
  15. titleFormat = config.tooltip_format_title || defaultTitleFormat,
  16. nameFormat = config.tooltip_format_name || function (name) { return name; },
  17. valueFormat = config.tooltip_format_value || defaultValueFormat,
  18. text, i, title, value, name, bgcolor;
  19. for (i = 0; i < d.length; i++) {
  20. if (!(d[i] && (d[i].value || d[i].value === 0))) { continue; }
  21. if (!text) {
  22. title = titleFormat ? titleFormat(d[i].x) : d[i].x;
  23. text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
  24. }
  25. name = nameFormat(d[i].name);
  26. value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
  27. bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
  28. text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
  29. text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
  30. text += "<td class='value'>" + value + "</td>";
  31. text += "</tr>";
  32. }
  33. return text + "</table>";
  34. }
  35. }
  36. });
  37. </script>
 <script>
  var chart = c3.generate({
   bindto: '#chart',
   data: {
   columns: [
    ['data1', 30, 200, 100, 400, 250],
    ['data2', 50, 20, 10, 40, 25],
    ['data3', 150, 10, 40, 40, 15],
    ['data4', 80, 40, 70, 20, 45],
    ['data5', 30, 60, 35, 90, 40]
   ]},
   tooltip: {
      contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
         var $$ = this, config = $$.config,
         titleFormat = config.tooltip_format_title || defaultTitleFormat,
         nameFormat = config.tooltip_format_name || function (name) { return name; },
         valueFormat = config.tooltip_format_value || defaultValueFormat,
         text, i, title, value, name, bgcolor;
         for (i = 0; i < d.length; i++) {
            if (!(d[i] && (d[i].value || d[i].value === 0))) { continue; }
            if (!text) {
               title = titleFormat ? titleFormat(d[i].x) : d[i].x;
               text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
            }
            name = nameFormat(d[i].name);
            value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
            bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
            text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
            text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
            text += "<td class='value'>" + value + "</td>";
            text += "</tr>";
         }
         return text + "</table>";
      }
    }
  });
 </script>

0123405010015020025030035040001234data1data2data3data4data5


Awesome! Tooltip items are sorted now. But what if we want to sort the items values ascend? We have to add the following sort function:

  1. d.sort(function(a, b){
  2. return a.value - b.value;
  3. });
         d.sort(function(a, b){
            return a.value - b.value;
         });


The entire contents:

  1. contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
  2. var $$ = this, config = $$.config,
  3. titleFormat = config.tooltip_format_title || defaultTitleFormat,
  4. nameFormat = config.tooltip_format_name || function (name) { return name; },
  5. valueFormat = config.tooltip_format_value || defaultValueFormat,
  6. text, i, title, value, name, bgcolor;
  7. d.sort(function(a, b){
  8. return a.value - b.value;
  9. });
  10. for (i = 0; i < d.length; i++) {
  11. if (!(d[i] && (d[i].value || d[i].value === 0))) { continue; }
  12. if (!text) {
  13. title = titleFormat ? titleFormat(d[i].x) : d[i].x;
  14. text = "" + (title || title === 0 ? "" : "");
  15. }
  16. name = nameFormat(d[i].name);
  17. value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
  18. bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
  19. text += "";
  20. text += "";
  21. text += "";
  22. text += "";
  23. }
  24. return text + "<table class="&quot; + $$.CLASS.tooltip + &quot;"><tbody>
  25. <tr><th colspan="2">" + title + "</th></tr>
  26. <tr class="&quot; + $$.CLASS.tooltipName + &quot;-&quot; + d[i].id + &quot;"><td class="name"><span style="background-color: &quot; + bgcolor + &quot;;"></span>" + name + "</td><td class="value">" + value + "</td></tr>
  27. </tbody></table>";
  28. }
      contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
         var $$ = this, config = $$.config,
         titleFormat = config.tooltip_format_title || defaultTitleFormat,
         nameFormat = config.tooltip_format_name || function (name) { return name; },
         valueFormat = config.tooltip_format_value || defaultValueFormat,
         text, i, title, value, name, bgcolor;
         d.sort(function(a, b){
            return a.value - b.value;
         });
         for (i = 0; i < d.length; i++) {
            if (!(d[i] && (d[i].value || d[i].value === 0))) { continue; }
            if (!text) {
               title = titleFormat ? titleFormat(d[i].x) : d[i].x;
               text = "" + (title || title === 0 ? "" : "");
            }
            name = nameFormat(d[i].name);
            value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
            bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
            text += "";
            text += "";
            text += "";
            text += "";
         }
         return text + "<table class="&quot; + $$.CLASS.tooltip + &quot;"><tbody>
<tr><th colspan="2">" + title + "</th></tr>
<tr class="&quot; + $$.CLASS.tooltipName + &quot;-&quot; + d[i].id + &quot;"><td class="name"><span style="background-color: &quot; + bgcolor + &quot;;"></span>" + name + "</td><td class="value">" + value + "</td></tr>
</tbody></table>";
      }

0123405010015020025030035040001234data1data2data3data4data5


You can try it on the JSFiddler:
https://jsfiddle.net/AndrewBuntsev/abqt8zgh

No comments:

Post a Comment