Chartjs - how to pass 2 values in from datasets.data?

Viewed 40

I need to show in tooltip 2 values from datasets:

chartData2: {
        labels: ["1 June", "15 June", "30 June"],
        datasets: [
          {
            slabel: "Active Accounts",
            data: [
              {amount: 150000, percent: '+5.27%'}, 
              {amount: 95000, percent: '+2.27%'}, 
              {amount: 350000, percent: '+3.27%'}
            ],
          },
          {
            slabel: "New Accounts",
            data: [
              {amount: 150000, percent: '+2.27%'}, 
              {amount: 250000, percent: '+2.27%'}, 
              {amount: 750000, percent: '+5.27%'}
            ],
          }
        ]
      },

How i can parse second value from tooltip? Chart rendering only with amount, but second value must be in tooltip.

Im write custom tooltip function, but i cant find in tooltip instance second value or index, for parse second value percent

tooltip: {
                // Disable the on-canvas tooltip
                enabled: false,

                external: (context) => {
                    // Tooltip Element
                    let tooltipEl = document.getElementById('chartjs-tooltip');

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

                    // Hide if no tooltip
                    const tooltipModel = context.tooltip;
                    if (tooltipModel.opacity === 0) {
                        tooltipEl.style.opacity = 0;
                        return;
                    }

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


                    function getBody(bodyItem) {
                      return bodyItem.lines;
                    }

                    // Set Text
                    if (tooltipModel.body) {
                        const titleLines = tooltipModel.title || [];
                        const bodyLines = tooltipModel.body.map(getBody);

                        console.log(tooltipModel)

                        let innerHtml = '<thead>';

                        titleLines.forEach(function(title) {
                            innerHtml += '<tr><th class="chartjs-tooltip-title">' + title + '</th></tr>';
                        });
                        innerHtml += '</thead><tbody>';

                        bodyLines.forEach((body, i) => {
                          
                          const colors = tooltipModel.labelColors[i];
                          let style = 'background:' + colors.backgroundColor;
                          style += '; border-color:' + colors.borderColor;
                          style += '; border-width: 2px';
                          const span = '<span style="' + style + '"></span>';
                          innerHtml += '<tr><td>' + this.data.datasets[i].slabel + ': <span class="tooltip-rl-text">' + body + '</span>' + '</td></tr>';
                        });
                        innerHtml += '</tbody>';

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

                    const position = context.chart.canvas.getBoundingClientRect();
                    // const bodyFont = Chart.helpers.toFont(tooltipModel.options.bodyFont);

                    // Display, position, and set styles for font
            
                    tooltipEl.style.opacity = 1;
                    tooltipEl.style.position = 'absolute';
                    tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX - tooltipEl.clientWidth / 2   +'px';
                    tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY  + 50 + 'px';
                    // tooltipEl.style.font = bodyFont.string;
                    tooltipEl.style.padding = tooltipModel.padding + 'px ' + tooltipModel.padding + 'px';
                    tooltipEl.style.pointerEvents = 'none';
                }
            }

What i can do? for show in tooltip both values, but paint chart only by amount?

1 Answers

All the data is available in the context you get like so:

external: (context) => {
  const rawDataPointInfo = context.tooltip.dataPoints[0].raw.percent;
}

Live example:

const getOrCreateTooltip = (chart) => {
  let tooltipEl = chart.canvas.parentNode.querySelector('div');

  if (!tooltipEl) {
    tooltipEl = document.createElement('div');
    tooltipEl.style.background = 'rgba(0, 0, 0, 0.7)';
    tooltipEl.style.borderRadius = '3px';
    tooltipEl.style.color = 'white';
    tooltipEl.style.opacity = 1;
    tooltipEl.style.pointerEvents = 'none';
    tooltipEl.style.position = 'absolute';
    tooltipEl.style.transform = 'translate(-50%, 0)';
    tooltipEl.style.transition = 'all .1s ease';

    const table = document.createElement('table');
    table.style.margin = '0px';

    tooltipEl.appendChild(table);
    chart.canvas.parentNode.appendChild(tooltipEl);
  }

  return tooltipEl;
};

const externalTooltipHandler = (context) => {
  // Tooltip Element
  const {
    chart,
    tooltip
  } = context;
  const tooltipEl = getOrCreateTooltip(chart);

  // Hide if no tooltip
  if (tooltip.opacity === 0) {
    tooltipEl.style.opacity = 0;
    return;
  }

  // Set Text
  if (tooltip.body) {
    const titleLines = tooltip.title || [];
    const bodyLines = tooltip.body.map((b, i) => `${b.lines} ${tooltip.dataPoints[i].raw.percent}`); // This line gets the extra info from the data array out of the tooltip

    const tableHead = document.createElement('thead');

    titleLines.forEach(title => {
      const tr = document.createElement('tr');
      tr.style.borderWidth = 0;

      const th = document.createElement('th');
      th.style.borderWidth = 0;
      const text = document.createTextNode(title);

      th.appendChild(text);
      tr.appendChild(th);
      tableHead.appendChild(tr);
    });

    const tableBody = document.createElement('tbody');
    bodyLines.forEach((body, i) => {
      const colors = tooltip.labelColors[i];

      const span = document.createElement('span');
      span.style.background = colors.backgroundColor;
      span.style.borderColor = colors.borderColor;
      span.style.borderWidth = '2px';
      span.style.marginRight = '10px';
      span.style.height = '10px';
      span.style.width = '10px';
      span.style.display = 'inline-block';

      const tr = document.createElement('tr');
      tr.style.backgroundColor = 'inherit';
      tr.style.borderWidth = 0;

      const td = document.createElement('td');
      td.style.borderWidth = 0;

      const text = document.createTextNode(body);

      td.appendChild(span);
      td.appendChild(text);
      tr.appendChild(td);
      tableBody.appendChild(tr);
    });

    const tableRoot = tooltipEl.querySelector('table');

    // Remove old children
    while (tableRoot.firstChild) {
      tableRoot.firstChild.remove();
    }

    // Add new children
    tableRoot.appendChild(tableHead);
    tableRoot.appendChild(tableBody);
  }

  const {
    offsetLeft: positionX,
    offsetTop: positionY
  } = chart.canvas;

  // Display, position, and set styles for font
  tooltipEl.style.opacity = 1;
  tooltipEl.style.left = positionX + tooltip.caretX + 'px';
  tooltipEl.style.top = positionY + tooltip.caretY + 'px';
  tooltipEl.style.font = tooltip.options.bodyFont.string;
  tooltipEl.style.padding = tooltip.options.padding + 'px ' + tooltip.options.padding + 'px';
};

const options = {
  type: 'line',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
      label: '# of Votes',
      data: [{
        x: "Red",
        amount: 12,
        percent: '+45%'
      }, {
        x: "Blue",
        amount: 19,
        percent: '+35%'
      }, {
        x: "Yellow",
        amount: 3,
        percent: '+25%'
      }, {
        x: "Green",
        amount: 5,
        percent: '+55%'
      }, {
        x: "Purple",
        amount: 2,
        percent: '-5%'
      }, {
        x: "Orange",
        amount: 3,
        percent: '+58%'
      }],
      borderColor: 'orange'
    }]
  },
  options: {
    parsing: {
      yAxisKey: 'amount'
    },
    plugins: {
      tooltip: {
        enabled: false,
        external: externalTooltipHandler
      }
    }
  }
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <div>
    <canvas id="chartJSContainer" width="600" height="400"></canvas>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
</body>

Related