3

Does anyone know if it's possible to style a Chart.js tooltip in such a way that the text appears more bolded for the values and less bolded for the text preceding it?

Current version:

current version

Desired Version:

desired version

I have used callbacks with a multistring array so far to create the lines necessary but I am unable to style the tooltips properly.

callbacks: {
  label: function (tooltipItem, data) {
    if (tooltipItem.datasetIndex === 1 || tooltipItem.datasetIndex === 2) {
      let line1, line2, line3, line4, line5;
      line1 = data.datasets[tooltipItem.datasetIndex].name;
      line2 = 'Transaction Volume: ' + data.datasets[tooltipItem.datasetIndex].tv[tooltipItem.index];
      line3 = 'YoY%: ' + data.datasets[tooltipItem.datasetIndex].tvYoY[tooltipItem.index];
      line4 = 'Deal Count: ' + data.datasets[tooltipItem.datasetIndex].dc[tooltipItem.index];
      line5 = 'YoY%: ' + data.datasets[tooltipItem.datasetIndex].dcYoY[tooltipItem.index];
      const multistringText = [line1];
      multistringText.push(line2);
      multistringText.push(line3);
      multistringText.push(line4);
      multistringText.push(line5);
      return multistringText;
    }
    ...

The tooltips callback works ok but it prevents me from styling specific parts of the callback I think? I am struggling to implement the same feature using the custom tooltip feature of chartJS which has very limited documentation.

2 Answers 2

3

To do this you'll need to render a custom tooltip. There is a good example on the Chart.js website.

It's a lot of work as you need to handle everything yourself (like positioning) but also the only way to get such a highly formatted result.

Sign up to request clarification or add additional context in comments.

Comments

0

Here is a example for(https://cdn.jsdelivr.net/npm/chart.js):

var myChart = new Chart(ctx, {
    type: 'line',
    data: {
      labels: xLabels,
      datasets: [generateDataset('starter')]
    },
    options: {
      responsive: true,
      scales: {
        y: {
          beginAtZero: true,
          title: {
            display: true,
            text: 'Pricing per Million Events',
            color: '#374053',
            font: {
              weight: 'bold',
              size: 14
            },
            padding: {
              bottom: 20
            }
          },
          border: {
            display: true,
            color: '#374053',
            width: 2,
          },
          grid: {
            color: function(context) {
              var tickValue = context.tick.value;
              var tickLabels = context.chart.scales.y.ticks.map(tick => tick.value);
              if (tickLabels.length > 0 && tickValue === tickLabels[tickLabels.length - 1]) {
                return 'transparent';
              }
              return '#ccc';
            }
          },
          ticks: {
            callback: function(value, index, values) {
              if (index === values.length - 1) {
                return '';
              }
              return value;
            }
          }
        },
        x: {
          title: {
            display: true,
            text: 'Events',
            color: '#374053',
            font: {
              weight: 'bold',
              size: 14
            },
            padding: {
              top: 20
            }
          },
          border: {
            display: true,
            color: '#374053',
            width: 2,
          },
          ticks: {
            autoSkip: false,
            maxTicksLimit: xLabels.length/25,
            callback: function(index) {
              var label = xLabels[index];
              if (filteredXLabels.includes(label)) {
                return label;
              }
              return '';
            }
          }
        }
      },
      plugins: {
        legend: {
          display: false,
        },
        tooltip: {
          enabled: false, 
          mode: 'index',  
          intersect: false, 
          external: function(context) {
            var tooltipModel = context.tooltip;
            var tooltipEl = document.getElementById('chartjs-tooltip');

            if (!tooltipEl) {
              tooltipEl = document.createElement('div');
              tooltipEl.id = 'chartjs-tooltip';
              tooltipEl.innerHTML = '<table></table>';
              document.body.appendChild(tooltipEl);
            }

            if (tooltipModel.opacity === 0) {
              tooltipEl.style.opacity = 0;
              return;
            }

            tooltipEl.classList.remove('above', 'below', 'no-transform');
            if (tooltipModel.yAlign) {
              tooltipEl.classList.add(tooltipModel.yAlign);
            } else {
              tooltipEl.classList.add('no-transform');
            }

            if (tooltipModel.body) {
              var titleLines = tooltipModel.title || [];
              var bodyLines = tooltipModel.dataPoints.map(function(dataPoint) {
                // Extract only the y-axis value
                return dataPoint.raw;
              });

              var innerHtml = '<thead>';
              innerHtml += '<tr class="tooltip-title"><td>$' + titleLines[0] + ' events </td></tr>';
              innerHtml += '</thead><tbody>';

              // Get the x-axis value from the tooltip model
              var xAxisValue = tooltipModel.dataPoints[0].label;
              var events = parseInt(xAxisValue, 10); // Parse the number of events
              var costPerMillion = calculateCostPerMillion(events);
              
              // Add a new row for cost per million
              innerHtml += '<tr class="tooltip-total-cost"><td> <span class="total-cost">$' + bodyLines[0] + '</span> per month</td></tr>';
              innerHtml += '<tr class="tooltip-cpm"><td>$' + costPerMillion + ' per Million Events</td></tr>';
              
              innerHtml += '</tbody>';

              var tableRoot = tooltipEl.querySelector('table');
              tableRoot.innerHTML = innerHtml;
            }

            var position = context.chart.canvas.getBoundingClientRect();
            tooltipEl.style.opacity = 1;
            tooltipEl.style.position = 'absolute';

            // Adjust the positioning logic here:
            tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + 'px';
            tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + 'px';
            
            // Offset to ensure the top-left corner touches the line
            tooltipEl.style.transform = 'translate(0%, 0%)';
            tooltipEl.style.fontFamily = tooltipModel.options.bodyFont.family;
            tooltipEl.style.fontSize = tooltipModel.options.bodyFont.size + 'px';
            tooltipEl.style.fontStyle = tooltipModel.options.bodyFont.style;
            tooltipEl.style.padding = tooltipModel.padding + 'px ' + tooltipModel.padding + 'px';
            tooltipEl.style.pointerEvents = 'none';
          }
        }
      }
    }
  });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.