Charlie Coplestone
Charlie Coplestone

Reputation: 375

Always show last tooltip on all datasets, leave the rest to display on hover? ChartJS

I'm a little stuck on how I would achieve this since it's a little unorthodox in relation to what the plugin does.

I'm attempting for each dataset to keep the last tooltip open at all times and leave the rest to be displayed on hover.

Currently, I'm using this to keep them all displayed:

    Chart.plugins.register({
        beforeRender: function (chart) {
            if (chart.config.options.showAllTooltips) {
                chart.pluginTooltips = [];
                chart.config.data.datasets.forEach(function (dataset, i) {
                    console.log(chart);
                    chart.getDatasetMeta(i).data.forEach(function (sector, j) {
                        console.log(sector);
                        chart.pluginTooltips.push(new Chart.Tooltip({
                            _chart: chart.chart,
                            _chartInstance: chart,
                            _data: chart.data,
                            _options: chart.options.tooltips,
                            _active: [sector]
                        }, chart));
                    });
                });

                chart.options.tooltips.enabled = false;
            }
        },
        afterDraw: function (chart, easing) {
            if (chart.config.options.showAllTooltips) {
                if (!chart.allTooltipsOnce) {
                    if (easing !== 1) {
                        return;
                    }
                    chart.allTooltipsOnce = true;
                }

                chart.options.tooltips.enabled = true;
                Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
                    tooltip.initialize();
                    tooltip.update();
                    tooltip.pivot();
                    tooltip.transition(easing).draw();
                });
                chart.options.tooltips.enabled = false;
            }
        }
    }); 

Is there a way to only do this for the last tooltip in each dataset?

I've come across a way to hide tooltips:

filter: function (tooltipItem, data) {
    var label = data.labels[tooltipItem.index];
    if (label === labels[labels.length - 1]) {
        console.log(tooltipItem);
    } else {
        return true;
    }
}

But this just doesn't display them whatsoever since it's returning false.

Ultimately it will look like this, with the other tooltips displaying on hover of the corresponding node:

enter image description here

Any help greatly appreciated.

Upvotes: 1

Views: 1100

Answers (2)

tristan202
tristan202

Reputation: 1129

So this is the entire hmtl file with all relevant code. As I said, I am no programmer. This effort is from loads of trial and error, including several bits of code from stackoverflow questions.

<script>
    $(document).ready(function () {
        showtempGraph();
    });

    function showtempGraph()
    {
        {
            $.post("temperaturedata.php",
            function (data)
            {
                console.log(data);
                var temptime = [];
                var temp = [];

                for (var i in data) {
                    temptime.push(data[i].timestamp);
                    temp.push(data[i].temperature);
                }
                
                var tempmin = Math.min(...temp);
                var tempmax = Math.max(...temp);

                var charttempdata = {
                    labels: temptime,
                    datasets: [
                        {
                            label: 'Temperatur',
                            pointRadius: 3,
                            backgroundColor: 'rgba(26, 137, 245, 0.2)',
                            borderColor: 'rgba(26, 137, 245, 1)',
                            hoverBackgroundColor: 'rgba(255, 255, 255, 1)',
                            hoverBorderColor: 'rgba(255, 255, 255, 1)',
                            pointBackgroundColor: 'rgba(12, 68, 122, 1)',
                            pointHoverBorderColor: "rgba(255, 255, 255, 0.8)",
                            data: temp
                        }
                    ]
                };

                var graphtempTarget = $("#tempgraphCanvas");

                var linetempGraph = new Chart(graphtempTarget, {
                    type: 'line',
                    data: charttempdata,
                    options: {
                        maintainAspectRatio: false,
                        tooltips: {
                            enabled: true,
                            custom: function(tooltip) {
                                if (!tooltip) return;
                                tooltip.displayColors = false;
                            },
                            callbacks: {
                                title: function(tooltipItems, tempdata) {
                                return 'Klokken: ' + tooltipItems[0].xLabel;    
                                },
                                label: function(tooltipItem, tempdata) {
                                return 'Temperatur: ' + Number(tooltipItem.yLabel).toFixed(2) + '°C';
                                }
                            }

                        },
                        legend: {
                            display: false,
                        },
                        responsive: true,
                        scales: {
                          xAxes: [{
                            type: 'time',
                            time: {
                                displayFormats: {
                                    hour: 'HH:mm'
                                },
                                tooltipFormat: 'HH:mm',
                            },
                            unit : 'day',
                            gridLines: {
                              color: '#999999',
                              lineWidth: 1
                            },
                            ticks: {
                                fontColor: "#fff",
                                }                               
                          }],
                          yAxes: [
                          { 
                            type: 'linear',
                            position: 'left',
                            gridLines: {
                              color: '#999999',
                              lineWidth: 1
                            },
                            ticks: {
                                fontColor: "#fff",
                                }
                          }, {
                            type: 'linear',
                            position: "right",
                            afterUpdate: function(scaleInstance) {
                              console.dir(scaleInstance);
                            },
                            gridLines: {
                              color: '#999999)',
                              lineWidth: 0.5
                            },
                            ticks: {
                                stepSize: tempmax - tempmin,
                                min: tempmin,
                                max: tempmax,
                                mirror: true,
                                padding: -10,
                                fontColor: "#fff",
                                fontSize: 18,
                                callback: function(value) {
                                    return value + '°C';
                                }
                            },
                            scaleLabel: {
                                display: true,
                                labelString: '°C',
                                fontColor: "#fff",
                                fontSize: 14
                            }                               
                          }]
                        },
                    }
                });
            });
        }
    }
    </script>

Upvotes: -1

tukan
tukan

Reputation: 17337

I would try to use chartjs-plugin-datalabels for such task.

You can try it out directly on their pages - scriptable interactions

setup

Setting some random data:

var DATA_COUNT = 8;
var labels = [];

Utils.srand(100);

for (var i = 0; i < DATA_COUNT; ++i) {
  labels.push('' + i);
}

var DATA_COUNT = 8;
var labels = [];

Utils.srand(100);

for (var i = 0; i < DATA_COUNT; ++i) {
  labels.push('' + i);
}

config

Here I did some changes

{
  type: 'line',
  data: {
    labels: labels,
    datasets: [{
      label: 'France',
      backgroundColor: Utils.color(0),
      borderColor: Utils.color(0),
      data: Utils.numbers({
        count: DATA_COUNT,
        min: 10,
        max: 100
      }),
      datalabels: {
        align: function(context) {
          return context.active ? 'start' : 'center';
        }
      }
    }, {
      label: 'Canada',
      backgroundColor: Utils.color(1),
      borderColor: Utils.color(1),
      data: Utils.numbers({
        count: DATA_COUNT,
        min: 0,
        max: 100
      })
    }, {
      label: 'USA',
      backgroundColor: Utils.color(2),
      borderColor: Utils.color(2),
      data: Utils.numbers({
        count: DATA_COUNT,
        min: 0,
        max: 100
      }),
      datalabels: {
        align: function(context) {
          return context.active ? 'end' : 'center';
        }
      }
    }]
  },
  options: {
    plugins: {
      datalabels: {
        backgroundColor: function(context) {
          return context.active ? context.dataset.backgroundColor : 'white';
        },
        borderColor: function(context) {
          return context.dataset.backgroundColor;
        },
        borderRadius: function(context) {
          return context.active ? 0 : 1;
        },
        borderWidth: 1,
        color: function(context) {
          return context.active ? 'white' : context.dataset.backgroundColor;
        },
        font: {
          weight: 'bold'
        },
        formatter: function(value, context) {
          value = Math.round(value * 100) / 100;
          if (context.dataIndex === context.dataset.data.length - 1) {
            return context.dataset.label + '\n' + value + '%';
          } else {
            return context.active
              ? context.dataset.label + '\n' + value + '%'
              : ''
          }
        },
        offset: 8,
        padding: 0,
        textAlign: 'center'
      }
    },

    // Core options
    aspectRatio: 5 / 3,
    layout: {
      padding: {
        bottom: 16,
        right: 40,
        left: 8,
        top: 40
      }
    },
    hover: {
      mode: 'index',
      intersect: false
    },
    elements: {
      line: {
        fill: false
      }
    },
    scales: {
      yAxes: [{
        stacked: true
      }]
    }
  }
} 

The main part here is:

formatter: function(value, context) {
          value = Math.round(value * 100) / 100;
          if (context.dataIndex === context.dataset.data.length - 1) {
            return context.dataset.label + '\n' + value + '%';
          } else {
            return context.active
              ? context.dataset.label + '\n' + value + '%'
              : ''
          }
        },

The formatter: where I show the label permanently only for context.dataIndex === context.dataset.data.length - 1.

In other cases if it is inactive I show only empty box in other case (hover) I show the information.

How does it look?

  • No hover

No hover with mouse

  • Hover with mouse

Hover with mouse

Upvotes: 3

Related Questions