javascripthtml5-canvaschart.js

How can I automatically wrap tooltip text content to multiple lines?


I'm using ChartJS to generate some charts. The data point tooltips are generated using callbacks via the configurations option:

tooltips: {
    position: 'average',
    mode: 'index',
    intersect: false,
    callbacks: {
        title: tooltipTitleCallback,
        label: tooltipLabelCallback
    }
},

The callbacks return a string of varying length. My problem is that ChartJS doesn't seem to provide any way to automatically wrap the text to multiple lines (similar to a Bootstrap tooltip). Instead, any text that doesn't fit on 1 line is truncated.

truncated tooltip

It does allow the callback to return an array of strings which it will separate by line break. Currently the only workaround I can think of is to measure the length of each tooltip and split the text into an array if it's sufficiently long (not responsive or ideal). I'd rather not re-make the wheel if there's a simple solution to this problem. Thanks for your help.


Solution

  • A solution for ChartJS 2.0. We can provide a function to build a HTML tooltip.

    Here are some examples of using custom tooltips.

    We turn off canvas tooltips.

    enabled: false

    We use the tooltips opacity state to show or hide our custom tooltip. The state is updated when a hover event is triggered.

    Our tooltipTitleCallback and tooltipLabelCallback functions will need to be modified depending on the parameters we're passing in. In this example, we're using the tooltip's dataPoints property in our tooltipTitleCallback function. The items which are available in the data property is determined by the interaction mode used.

    Here are some other properties in the tooltip model.

    To prevent the tooltip from going over the right hand side of the screen, we set the right position property instead of the left.

    Working example

    const ctx = document.getElementById("myChart").getContext("2d");
    
    const customTooltip = {
      mode: "index",
      enabled: false,
      custom: function(model) {
        const tooltip = document.getElementById("tooltip");
    
        if (model.opacity === 0) {
          tooltip.style.opacity = 0;
          return;
        }
    
        if (model.body) {
          const title = "<strong>" + tooltipTitleCallback(model.dataPoints) + "</strong>";
          const label =
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pellentesque eros non massa consequat, ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pellentesque eros non massa consequat, ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pellentesque eros non massa consequat, ac.";
    
          tooltip.innerHTML = title + "<br />" + label;
    
          tooltip.style.left = "auto";
          tooltip.style.right = "auto";
    
          const pos = this._chart.canvas.getBoundingClientRect();
    
          if (model.xAlign === "left") {
            tooltip.style.left = pos.left + model.caretX + "px";
          } else {
            tooltip.style.right = pos.right - model.caretX + "px";
          }
    
          tooltip.style.top = -50 + pos.top + model.caretY + "px";
          tooltip.style.opacity = 1;
        }
      }
    };
    
    const myChart = new Chart(ctx, {
      type: "line",
      data: {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [{
          label: "My First dataset",
          backgroundColor: "rgb(255, 99, 132)",
          borderColor: "rgb(255, 99, 132)",
          data: [0, 10, 5, 2, 20, 30, 45],
          fill: false
        }]
      },
      options: {
        tooltips: customTooltip
      }
    });
    
    function tooltipTitleCallback(items) {
      if (items.length > 0) {
        const item = items[0];
    
        if (item.label) {
          return item.label;
        }
    
        return "No title";
      }
    }
    #tooltip {
      opacity: 0;
      position: absolute;
      background: rgba(0, 0, 0, 0.7);
      color: white;
      border-radius: 3px;
      -webkit-transition: all 0.1s ease;
      transition: all 0.1s ease;
      pointer-events: none;
      padding: 4px;
      margin: 15px;
      font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
      font-size: 13px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <canvas id="myChart" width="400" height="200"></canvas>
    <div id="tooltip"></div>

    Codepen