Search code examples
javascriptcsschartstooltipc3.js

Closing C3 tooltip after interacting with it


I'm learning to use C3.js for charts, and I'd like to get better at customizing tooltip functionality. Normally C3 tooltips appear as you hover over data. Example here. They don't persist, and you can't interact with them.

I found some code here on Stack Overflow (link here) to add a timeout and CSS to make the tooltip persist and allow the user to interact with it, but I don't know how to make the tooltip close again afterwards, either by the user clicking somewhere on the chart or the tooltip, or by using a timeout. I think it's annoying to have the tooltip remain on the chart forever after it appears.

JSFiddle

There should be a function I can call or override, shouldn't there? I tried adding an onclick functionality so that when I clicked a datapoint, it would do something, but I didn't find a way to make it do what I wanted. I followed this link to figure out how to do the onclick.

data: {
  columns: [ ['data1', 40, 50, 60, 70, 80] ],
  types: { data1: 'bar'},
  onclick: function(e) { alert(e.value); }
}

I'm not sure I care specifically how closing the tooltip would get triggered. Here's the code from the JSFiddle that demonstrates interacting with the tooltip and how it doesn't close.

CSS:

.c3-tooltip-container {
    background-color: #ccc;
    border: solid 1px black;
    padding: 20px;
    pointer-events: auto !important;
}

JS:

var features = dates = defects = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10
];

var chart = c3.generate({
    data: {
        columns: [
            ['data1', 30000, 20000, 10000, 40000, 15000, 250000],
            ['data2', 100, 200, 100, 40, 150, 250]
        ],
    },
    tooltip: {
        position: function () {
            var position = c3.chart.internal.fn.tooltipPosition.apply(this, arguments);
            position.top = 0;
            return position;
        },
        contents: function (data, defaultTitleFormat, defaultValueFormat, color) {
            var $$ = this, config = $$.config,
            titleFormat = config.tooltip_format_title || defaultTitleFormat,
            nameFormat = config.tooltip_format_name || function (name) { return name; },
            valueFormat = config.tooltip_format_value || defaultValueFormat,
            text, i, title, value;
            text = "<div id='tooltip' class='d3-tip'>";
            title = dates[data[0].index];
            text += "<span class='info'><b><u>Date</u></b></span><br>";
            text += "<span class='info'>" + title + "</span><br>";
            text += "<span class='info'><b><u>Features</u> : </b> " + features[data[0].index] + "</span><br>";
            text += "<span class='info'><b><u>Enhancements</u> : </b> " + defects[data[0].index] + "</span><br>";
            text += "</div>";
            return text;
        }
    }
});

Solution

  • If you want to hide tooltip when
    (1) you click on it or
    (2) timeout passed
    you need

    • function for changing tooltip visibility
    • function for processing click action
    • timer storage for timer stop/restart

    Something like this:

    // 1
    window.action = function() {
        // do something
        // ...
        clearTimeout(timeout);
        hideTooltip();
    }
    
    // timer storage
    var timeout;
    
    var chart = c3.generate({
        ...
        tooltip: {
            position: ...
            contents: function (...) {
                // 2
                clearTimeout(timeout);
                timeout = setTimeout(hideTooltip, 5000); // auto-hide after 5 seconds
    
                ...
                text = "<div id='tooltip' class='d3-tip' onclick='window.action()'>";
                ...
                return text;
            }
        }
    });
    
    // disable default
    c3.chart.internal.fn.hideTooltip = function (){};
    
    // custom tooltip hiding
    var hideTooltip = function() {
        d3.select('.c3-tooltip-container').style('display', 'none');
    }
    

    Have a look at updated fiddle.