Creating tooltips

A tooltip is a small element that provides contextual information when the user locates the pointer over an element. This allows you to provide details without cluttering the visualization. In this section, we will create the tooltip as a reusable chart but with a different structure than that in the previous examples. In the previous charts, we bound the data to a selection of containers for the charts; while in this case, the tooltip chart will be bound to the element on which the tooltip should appear. This implies that the selection argument in the charting function contains the elements on which the tooltip will appear. In the case of the fruit chart, we will want the tooltip to appear when the user moves the pointer over the circles, follow the pointer as it moves over the circle, and disappear when the pointer leaves the circle. We will create a tooltip as a reusable chart, but instead of invoking the tooltip on a selection of containers, we will invoke the tooltip passing it a selection containing the circle under the cursor. We begin by creating the tooltip chart, bearing in mind these considerations:

function tooltipChart() {

    // Tooltip Attributes...

    // Charting function
    function chart(selection) {
        selection.each(function(d) {
            // Bind the mouse events to the container element
            d3.select(this)
                .on('mouseover', create) 
                .on('mousemove', move)
                .on('mouseout',  remove);
        });
    }

    // Accessor methods...

    return chart;
}

Here, we added listeners for the mouseover, mousemove, and mouseout events on the selection argument. The data bound to each element will be passed on to the create, move, and remove listeners. These functions will create, move, and remove the tooltip, respectively. To create the tooltip, we will create a div container under the body element and set its left and top offsets to the pointer position, plus we add a small offset, as shown in the following code:

// Create the tooltip chart
var create = function(data) {

    // Create the tooltip container div
    var tooltipContainer = d3.select('body').append('div')
        .datum(data)
        .attr('class', 'tooltip-container')
        .call(init);

    // Move the tooltip to its initial position
    tooltipContainer
        .style('left', (d3.event.pageX + offset.x) + 'px')
        .style('top', (d3.event.pageY + offset.y) + 'px'),
};

To locate the tooltip near the pointer, we need to set its position to absolute. The pointer events' style must be set to none so that the tooltip doesn't capture the mouse events. We set the position and other style attributes in an inline style element. We also set the style for the tooltip's title and content, as shown in the following code:

<style>
.tooltip-container {
    position: absolute;
    pointer-events: none;
    padding: 2px 4px 2px 6px;
    background-color: #eee;
    border: solid 1px #aaa;
}

.tooltip-title {
    text-align: center;
    font-size: 12px;
    font-weight: bold;
    line-height: 1em;
}

.tooltip-content {
    font-size: 11px;
}
</style>

In the initialization function, we will create the div container for the tooltip and add paragraphs for the title and the content. We also added the title and content methods with their corresponding accessors so that the user can configure the title and content based on the bound data:

// Initialize the tooltip
var init = function(selection) {
    selection.each(function(data) {
        // Create and configure the tooltip container
        d3.select(this)
            .attr('class', 'tooltip-container')
            .style('width', width + 'px'),

        // Tooltip Title
        d3.select(this).append('p')
            .attr('class', 'tooltip-title')
            .text(title(data));

        // Tooltip Content
        d3.select(this).append('p')
            .attr('class', 'tooltip-content')
            .text(content(data));
    });
};

The chart.move method will update the position of the tooltip as the pointer moves, changing its left and top offsets. The chart.remove method will just remove the tooltip from the document:

// Move the tooltip to follow the pointer
var move = function() {
    // Select the tooltip and move it following the pointer
    d3.select('body').select('div.tooltip-container')
        .style('left', (d3.event.pageX + offset.x) + 'px')
        .style('top', (d3.event.pageY + offset.y) + 'px'),
};

// Remove the tooltip
var remove = function() {
    d3.select('div.tooltip-container').remove();
};

Using the tooltip

We can use the tooltip in the fruit chart, and add tooltips when the user moves the pointer over the circles. We will create and configure the tooltip function in the fruit chart closure, as follows:

function fruitChart() {

    // Create and configure the tooltip
    var tooltip = tooltipChart()
        .title(function(d) { return d.name; })
        .content(function(d) { return d.description; });

    // Attributes, charting function and accessors...

    return chart;
}

In the charting function, we can invoke the tooltip function by passing the selection of the circles as an argument, as follows:

function fruitChart() {

    // Chart attributes...

    // Charting Function
    function chart(selection) {
        selection.each(function(data) {
            // Charting function content...

            // The event listeners of the tooltip should be 
            // namespaced to avoid overwriting the listeners of the circles.
            circles
                .on('mouseover', function(d) { ... })
                .on('mouseout', function(d) { ... })
                .call(tooltip);
        });
    }

    // Accessor methods....

    return chart;
}

Tip

Remember that the circles already have listeners for the mouseover and mouseout events. If we add the tooltip as it is, the first listener will be removed before the new listener is added, disabling the highlighting.

To register multiple listeners for the same event type, we can add an optional namespace to the tooltip-related events, as follows:

// Tooltip charting function
function chart(selection) {
    selection.each(function(d) {
        // Bind the mouse events to the container element
        d3.select(this)
            .on('mouseover.tooltip', create)
            .on('mousemove.tooltip', move)
            .on('mouseout.tooltip',  remove);
    });
}

Now, we have the tooltips and highlighting enabled in the fruit chart.

Using the tooltip

The tooltip and the highlighting listeners are enabled for the fruit chart

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset