score:2

Accepted answer

You can put any custom/advance datas to dataset for example (imgUrls, productIds, imgDataset ) :

var chartdata = {
            labels: ["Swimming", "Golf", "Soccer"],
    datasets: [{
        label: "Choices",
        data: [4, 10, 6],
        backgroundColor: ["#a19828", "#b15928", "#fb9a99"],
        imgDataUrls:['img1','img2','img3'],
        imgDataSet:'imgDataset',
        productIds:['id1','id2','id3'],
    }]
};

Then you can use datasetIndex, dataIndex in Tooltip Item Context to get your custom/advance datas.

// Index of the dataset the item comes from
datasetIndex: number,

    // Index of this data item in the dataset
dataIndex: number,

https://github.com/chartjs/Chart.js/blob/master/docs/samples/tooltip/html.md

score:1

Dont know how you get your data so I assume you somehow get it together with your normal data. In this case you can add a custom property to the dataset and pass it to the tooltip. Then it will be available in your context of your external handler in the following namespace: context.tooltip.dataPoints[0].dataset[customPropertyName].

Then you can just create an image element and add it to the head:

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);

  // THIS BLOCK ADDED
  const imageTh = document.createElement('th');
  th.style.borderWidth = 0;
  const image = document.createElement('img');
  image.style = 'width:20px'
  image.src = context.tooltip.dataPoints[0].dataset.url;
  imageTh.appendChild(image);

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

Fiddle: https://jsfiddle.net/Leelenaleee/xhrs2wvc/17/

Full code (since stack snipet doesnt seem to like creating the elements):

<body>
    <canvas id="chartJSContainer" width="600" height="400"></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
</body>
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 => b.lines);

    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);

            // THIS BLOCK ADDED
      const imageTh = document.createElement('th');
      th.style.borderWidth = 0;
      const image = document.createElement('img');
      image.style = 'width:20px'
      image.src = context.tooltip.dataPoints[0].dataset.url;
      imageTh.appendChild(image);

      tr.appendChild(th);
      tr.appendChild(imageTh);
      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: [12, 19, 3, 5, 2, 3],
        borderColor: 'pink',
        backgroundColor: 'pink',
        url: 'https://www.chartjs.org/img/chartjs-logo.svg'
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        borderColor: 'orange',
        backgroundColor: 'orange',
        url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/512px-Stack_Overflow_icon.svg.png'
      }
    ]
  },
  options: {
    plugins: {
      tooltip: {
        enabled: false,
        position: 'nearest',
        external: externalTooltipHandler
      }
    }
  }
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);


Related Query