2

I have a c3.js line graph that represents the evolution of 2 values. I need that the tooltip of the line graph to be a pie chart (tooltip = another c3.js graph).

Here is what I succeeded:

http://jsfiddle.net/owhxgaqm/80/

 // c3 - custom tooltip
function generateGraph(data1,data2) {
 console.log(data1.name + '\t' + data1.value + '\t' + data2.name + '\t' + data2.value);
var chart1 = c3.generate(
            {
                bindto: "#t",
                data: {columns : [[data1.name, data1.value],[data2.name, data2.value]],
                    type : 'pie'}           
            });
}
var chart = c3.generate({
    data: {
        columns: [
            ['data1', 1000, 200, 150, 300, 200],
            ['data2', 400, 500, 250, 700, 300], ]
    },
    tooltip: {
        contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
                 generateGraph(d[0], d[1]);
            var divt = document.getElementById("t");
            return '';


        }
    }
});

As you can see I'm binding the "tooltip" with an already existing div so this is not really what I want from c3.js.

Any idea is welcome.

Thanks.

Litra Eros
  • 21
  • 1
  • 3

1 Answers1

2

Adding a Chart inside a C3 Tooltip

You can use the tooltip element that c3 already has. In your contents function call the generateGraph function (see next step). Pass in the tooltip element available in this.tooltip in addition to the data.

    ...
    tooltip: {
        contents: function (d) {
            // this creates a chart inside the tooltips
            var content = generateGraph(this.tooltip, d[0], d[1])
            // we don't return anything - see .html function below
        }
    }
    ...

Your generateGraph function basically creates a c3 chart in your tooltip element (bindto supports a d3 element). We do a bit of optimization (if the data is same, the chart is not recreated) and cleanup (when a chart is recreated it is destroyed and removed from the DOM)

function generateGraph(tooltip, data1, data2) {
    // if the data is same as before don't regenrate the graph - this avoids flicker
    if (tooltip.data1 && 
        (tooltip.data1.name === data1.name) && (tooltip.data1.value === data1.value) && 
        (tooltip.data2.name === data2.name) && (tooltip.data2.value === data2.value))
        return;
    tooltip.data1 = data1;
    tooltip.data2 = data2;

    // remove the existing chart
    if (tooltip.chart) {
        tooltip.chart = tooltip.chart.destroy();
        tooltip.selectAll('*').remove();
    }

    // create new chart
    tooltip.chart = c3.generate({
        bindto: tooltip,
        size: {
            width: 200,
            height: 200
        },
        data: {
            columns: [[data1.name, data1.value], [data2.name, data2.value]],
            type: 'pie'
        }
    });
    // creating a chart on an element sets its position attribute to relative
    // reset it to absolute (the tooltip was absolute originally) for proper positioning
    tooltip.style('position', 'absolute');
}

Note that we set the chart size so that it's more like tooltip content instead of a subchart.


The last bit is a bit hacky - since c3 requires that we set a HTML (which we don't want to do) and because we don't have any other callbacks we can easily hitch onto after the content handler, we have to disable the function that c3 uses to set the html content on the tooltip (this will affect only this chart's tooltip) i.e. .tooltip.html

// MONKEY PATCHING (MAY break if library updates change the code that sets tooltip content)
// we override the html function for the tooltip to not do anything (since we've already created the tooltip content inside it)
chart.internal.tooltip.html = function () {
    // this needs to return the tooltip - it's used for positioning the tooltip
    return chart.internal.tooltip;
}

Fiddle - http://jsfiddle.net/muuqvf1a/


Tooltip Positioning

Instead of using c3's tooltip positioning you could also size and position the tooltip at the bottom of the chart. Just style .c3-tooltip-container.

Alternatives

Note that c3 also support subcharts (http://c3js.org/reference.html#subchart-show) and data.mouseover (http://c3js.org/reference.html#data-onmouseover) which could also be a cleaner avenues worth exploring.

potatopeelings
  • 40,709
  • 7
  • 95
  • 119