0

I have a chart being created using chart.js version 2.8 running on an Angular application. I need the tooltips to always be visible on the chart by default and not just when the mouse is hovering over the points (the chart is a scatter plot). I have looked into how to set this up and most sources seem to recommend using the pluginService to register a fix to enable the possibility. However chart.config.options.showAllTooltips needs to already exist whereas it just doesn't seem to in chart.js v2.8 anymore.

this.LQChart = new Chart(this.myChart, {
                type: 'bubble',
                data: {
                    labels:['Jobs']
                }, options: {
                    plugins:{
                        colorschemes: {
                            scheme: 'brewer.YlOrBr9'
                        },
                        zoom:{
                            pan: {
                                enabled: true,
                                mode: 'xy',
                                rangeMin: {
                                    x: null,
                                    y: null
                                },
                                rangeMax:{
                                    x: null,
                                    y: null
                                }
                            },
                            zoom:{
                                enabled: true,
                                drag: false,
                                mode:'xy',
                                rangeMin: {
                                    x: null,
                                    y: null
                                },
                                rangeMax:{
                                    x: null,
                                    y: null
                                },
                                speed:0.1
                            }
                        },
                        // datalabels: {
                        //     color: 'white',
                        //     font: {
                        //         weight:'bold'
                        //     },
                        //     display: function (context) {
                        //         console.log("Algo: "+context);
                        //         return context.dataset.data[context.dataIndex] > 15;
                        //     },
                        //     formatter: function(value, context) {
                        //         console.log("Forma: "+value+" : "+context);
                        //         return context.dataIndex + ':' + Math.round(value*100) + '%';
                        //     }
                        // }
                    }, tooltips: {
                        callbacks: {
                            label: function(tooltipItem, data) {
                                var label = data.datasets[tooltipItem.datasetIndex].label || '';
                                return label
                            }
                        }
                    },legend: {
                        display: false
                    }, title: {
                        display: true,
                        text: 'Location Quotient of Jobs in Region'
                    }, scales: {
                        yAxes: [{ 
                            scaleLabel: {
                                display: true,
                                labelString: "# of Jobs"
                            },
                            id:'y-axis-0',
                            type:'linear',
                            gridLines: {
                                display:true
                            },
                            ticks: {
                                callback: function(value, index, values) {
                                    return Number(value.toString());
                                }
                            },
                            position:'left'
                        }],
                        xAxes: [{
                            scaleLabel: {
                                display: true,
                                labelString: "LQ"
                            },
                            id: 'x-axis-0',
                            type: 'linear',
                            position: 'bottom',
                        }]
                    }, annotation: {
                        annotations: [{
                            borderColor: 'black',
                            //borderDash: [2, 2],
                            borderWidth: 2,
                            mode: 'vertical',
                            type: 'line',
                            value: 1.0,
                            scaleID: 'x-axis-0'
                        }]
                    }
                }
            });

This is the code I am using to create my chart, I just need to know how to set chart tooltips to always visible.

Kron
  • 473
  • 5
  • 20

2 Answers2

2

There have been many discussions around this issue in V2 of ChartJs which you can find here, here and here.

Overall, what you need to do is register your own plugin for ChartJs which you can then use via the options property.

So if you add the following plugin registration:

Chart.pluginService.register({
            beforeRender: function (chart) {
                if (chart.config.options.showAllTooltips) {
                    // create an array of tooltips
                    // we can't use the chart tooltip because there is only one tooltip per chart
                    chart.pluginTooltips = [];
                    chart.config.data.datasets.forEach(function (dataset, i) {
                        chart.getDatasetMeta(i).data.forEach(function (sector, j) {
                            chart.pluginTooltips.push(new Chart.Tooltip({
                                _chart: chart.chart,
                                _chartInstance: chart,
                                _data: chart.data,
                                _options: chart.options.tooltips,
                                _active: [sector]
                            }, chart));
                        });
                    });

                    // turn off normal tooltips
                    chart.options.tooltips.enabled = false;
                }
            },
            afterDraw: function (chart, easing) {
                if (chart.config.options.showAllTooltips) {
                    // we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
                    if (!chart.allTooltipsOnce) {
                        if (easing !== 1)
                            return;
                        chart.allTooltipsOnce = true;
                    }

                    // turn on tooltips
                    chart.options.tooltips.enabled = true;
                    Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
                        tooltip.initialize();
                        tooltip.update();
                        // we don't actually need this since we are not animating tooltips
                        tooltip.pivot();
                        tooltip.transition(easing).draw();
                    });
                    chart.options.tooltips.enabled = false;
                }
            }
        })

Then you can add the showAllTooltips property in your options like so:

options: {
        showAllTooltips: true
        ...

Take a look at this illustration of your code with some sample data.

ViqMontana
  • 5,090
  • 3
  • 19
  • 54
  • Yeah this is what I was talking about. This solution is what I encountered before. When I try to put it into the code I get the following errors: `if(chart.config.options.showAllTooltips) {` gives me: "Property 'showAllTooltips' does not exist on type 'ChartOptions'." `chart.pluginTooltips` gives me "Property 'pluginTooltips' does not exist on type 'Chart'." `chart.pluginTooltips.push(new Chart.Tooltips({...}));` gives me: "Cannot use 'new' with an expression whose type lacks a call or construct signature." among others – Kron Jul 01 '19 at 14:41
  • Did you take a look at how I've done it in the StackBlitz in my answer? – ViqMontana Jul 01 '19 at 14:53
  • Yes I did. Now I've done some playing with it and I am still getting all of the errors that I mentioned. In fact my code in Visual Studio Code is just littered with red lines and error warning. However when I press 'run' it all works fine and displays the tooltips by default exactly as I wanted. I will mark the issue as solved for now. Thank you for your help. I just need to figure out why I'm seeing errors where there are none. – Kron Jul 01 '19 at 15:18
  • Sounds like all your error are due to the typings, i.e. vscode thinks the properties don't exist on your specified types. – ViqMontana Jul 01 '19 at 15:19
  • I've done some reformatting and removed most of them. Two errors remain though. At `new Chart.Tooltip({...})` it still gives me "Cannot use 'new' with an expression whose type lacks a call or construct signature." And at `easing !== 1` it gives me "This condition will always return 'true' since the types 'Easing' and '1' have no overlap." – Kron Jul 01 '19 at 15:26
  • Define `easing` as `any` in the `afterDraw` function and do the same with `Chart`, i.e. `new (Chart as any).Tooltip({...` – ViqMontana Jul 01 '19 at 15:28
  • Finally got it sorted. Final code posted in the next answer. Thank you for the help! – Kron Jul 01 '19 at 15:35
0

Viqas definitely gave me the right answer but I wanted to amend the following: If anyone is having the same issue that I was having where the pluginService.register code throws all manner of errors I want to post here my register code after modification:

Chart.pluginService.register({
    beforeRender: function (chart) {
        if (chart.config.options['showAllTooltips']) {
            // create an array of tooltips
            // we can't use the chart tooltip because there is only one tooltip per chart
            chart['pluginTooltips'] = [];
            chart.config.data.datasets.forEach(function (dataset, i) {
                chart.getDatasetMeta(i).data.forEach(function (sector, j) {
                    chart['pluginTooltips'].push(new (Chart as any).Tooltip({
                        _chart: chart['chart'],
                        _chartInstance: chart,
                        _data: chart.data,
                        _options: chart['options']['tooltips'],
                        _active: [sector]
                    }, chart));
                });
            });

            // turn off normal tooltips
            chart['options']['tooltips']['enabled'] = false;
        }
    },
    afterDraw: function (chart, easing: any) {
        if (chart.config.options['showAllTooltips']) {
            // we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
            if (!chart['allTooltipsOnce']) {
                if (easing !== 1)
                    return;
                chart['allTooltipsOnce'] = true;
            }

            // turn on tooltips
            chart['options']['tooltips']['enabled'] = true;
            Chart.helpers.each(chart['pluginTooltips'], function (tooltip) {
                tooltip.initialize();
                tooltip.update();
                // we don't actually need this since we are not animating tooltips
                tooltip.pivot();
                tooltip.transition(easing).draw();
            });
            chart['options']['tooltips']['enabled'] = false;
        }
    }
})

This worked for me and I hope anyone else who runs into the same issue will find it helpful.

Kron
  • 473
  • 5
  • 20