Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ChartJs line chart - display permanent icon above some data points with text on hover

Tags:

chart.js

I have a chart i need to draw that, in addition to the data points, i want an icon permanently above (some) data points with a custom text string.

I don't need the default value popover as i can make do with a custom legend, but i need to add an icon above one or two points, and on hover of the icon, display a popover. i need to build the popover text string from non-chart related data.

The custom data labels don't appear to be flexible enough to allow different icons/popovers on different data points, i may be wrong though.

Another possibility is chartjs-plugin-datalabels, but I'm not sure about that.

line graph with custom icon

like image 661
Ian Avatar asked Oct 16 '22 03:10

Ian


1 Answers

In case your chart (canvas) is of fixed size, you can easily solve this problem by adding an additional dataset that specifies nothing but the icons to be shown in the chart.

{
  data: data2.map((v, i) => imageIndexes.includes(i) ? v + 1.2 : null),
  fill: false,
  pointStyle: icon,
  pointRadius: 22,
  pointHoverRadius: 22
}

Given the data array data2 and the array imageIndexes, the data of the icons dataset can be built using Array.map. Note that the values - where any - are derived from corresponding values in data2 but slightly increased to make the images appear on top of them.

data2.map((v, i) => imageIndexes.includes(i) ? v + 1.2 : null)

Further you'll need to define a tooltips object inside the chart options in order to style the popup and to make sure, tooltips are only displayed when the mouse hovers over the icons.

tooltips: {
  filter: tooltipItem => tooltipItem.datasetIndex == 2,
  titleFontSize: 16,
  titleAlign: 'center',
  callbacks: {
    title: (tooltipItem) => tooltipItem.length == 0 ? null : tooltipText,
    label: () => null
  }
},

Please have a look at the runnable code snipped below.

const labels = ['A', 'B', 'C', 'D', 'E', 'F'];
const alerts = ['B', 'D'];
const data1 = [0, 2, 1, 3, 2, 1];
const data2 = [1, 3, 3, 4, 3, 2];
const imageIndexes = [1, 3];
const tooltipText = 'Efficiency of Standard Curve\nnot opimal';

var icon = new Image();
icon.src = 'https://i.stack.imgur.com/YvlWY.png';

const chart = new Chart(document.getElementById("myChart"), {
  type: "line",
  data: {
    labels: labels,
    datasets: [{
        data: data1,
        fill: false,
        backgroundColor: 'blue',
        borderColor: 'blue',
        lineTension: 0,
        pointRadius: 5,
        pointHoverRadius: 5,
        pointBorderWidth: 3,
        pointHoverBorderWidth: 3,
        pointBorderColor: 'white',
        pointHoverBorderColor: 'white'
      },
      {
        data: data2,
        fill: false,
        showLine: false,
        backgroundColor: 'orange',
        pointRadius: 4,
        pointHoverRadius: 4
      },
      {
        data: data2.map((v, i) => imageIndexes.includes(i) ? v + 1.2 : null),
        fill: false,
        pointStyle: icon,
        pointRadius: 22,
        pointHoverRadius: 22
      }
    ]
  },
  options: {
    responsive: false,
    title: {
      display: false
    },
    legend: {
      display: false
    },
    tooltips: {
      filter: tooltipItem => tooltipItem.datasetIndex == 2,
      titleFontSize: 16,
      titleAlign: 'center',
      callbacks: {
        title: (tooltipItem) => tooltipItem.length == 0 ? null : tooltipText,
        label: () => null
      }
    },
    scales: {
      yAxes: [{
        ticks: {
          min: 0,
          max: 6,
          stepSize: 1
        }
      }],
      xAxes: [{
        gridLines: {
          display: false
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" style="width: 500px; height: 200px"></canvas>
like image 102
uminder Avatar answered Oct 21 '22 04:10

uminder