javascriptd3.jsjquery-tooltiptipsy

Long text in tipsy tooltips


I'm happily using tipsy for my d3.js graphs, but now I noticed that tipsy is cutting off text if it's too long.

For instance the line containing the word CALCULATOR is cut off:

Text of tooltip is cut off

Is there a way to extend the width of the tooltip or autosize it according to the longest line of the tooltip text (I didn't find anything in the docs)?


Solution

  • I ended up writing my own tooltips module for D3 (see below). It uses require.js. I use it like this:

    define('myD3module',
    // This module depends on the following modules
    ['tooltips', 'd3'], 
        function (tooltips, d3){
    
    // Code omitted...
    
    var node = svg.selectAll('g.node');
    var nodeEnter = node.enter().append('g')
    .on('mouseover', onMouseOver)                  
    .on('mouseout', onMouseOut);
    
    // Code omitted...
    
    var onMouseOver = function(d){
           tooltips.showTooltip(d, getTooltipText);
    };
    
    var onMouseOut = function(d){
            tooltips.hideTooltip(d);
    };
    
    // Code omitted...
    var getTooltipText = function(d){
        var tipText = '';
        var name = d.name;
        if(typeof name != 'undefined'){
            tipText += 'Name = ' + name + '<br>';
        }
        return tipText;
    };
    

    This is the module.

    // This module shows tooltips near the user's cursor. The text of the tooltip must be provided by the consumer of this module. This module can be used with require.js.
    define('tooltips',
    // Required modules:
    ['d3','jquery'],
    function (d3, $){
    
        // Contains the tooltip. This div will be repositioned as needed.
        var tooltip = d3.select('body').append('div')   
                        .attr('class', 'tooltip')               
                        .style('opacity', 0);
    
        // This CSS styles the tooltip
        var css = './config/tooltip.css';
        var link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = css;
        document.getElementsByTagName('head')[0].appendChild(link);
    
        var hideTooltip = function (d) {       
                tooltip.style('opacity', 0);   
            },
    
            /** Show the tooltip. The text is defined by a function and the element the mouse cursor is placed on. */
            showTooltip = function (elem, getTooltipText){      
                tooltip.style('opacity', 0.9);      
                var text = getTooltipText(elem);
                var tipWidth = getTooltipWidth(text);
                // Draw the tips below the mouse cursor
                var tipYpos = d3.event.pageY + 20;
                tooltip.html(text)  
                    // The tooltip is centered below the cursor
                    .style('left', (d3.event.pageX - tipWidth/2) + 'px')     
                    .style('top', tipYpos + 'px')
                    .style('width', tipWidth + 'px')
                    .style('height', getTooltipHeight(text) + 'px');
            },
    
            /**
             * The tooltip spans all the text's lines vertically.
             */
             getTooltipHeight = function (text) {
    
                var totalHeight = 0;
                var lines = text.split('<br>');
                for (var i = 0; i < lines.length; i++){
                    var line = $.trim(lines[i]);
                    // Ignore empty strings
                    if(line.length > 0){
                        var span = document.createElement('span');
                        span.innerHTML = line;
                        $('body').append(span);
                        totalHeight +=  $(span).height();
                        $(span).remove();
                    }
                }
                return totalHeight;
            },
    
            /*
             * The width of the tooltip is the width of the longest line in the tooltip text
             */
            getTooltipWidth = function (text){
    
                var lines = text.split('<br>');
                // Append a dummy span containing the current line to the DOM. The browser calculates the width of that span
                var maxWidth = d3.max(lines, function(line) {
                        var span = document.createElement('span');
                        span.innerHTML = line;
                        $('body').append(span);
                        var spanWidth = $(span).width();
                        $(span).remove();
                        return spanWidth; 
                        });
                return maxWidth;
            };
    
            // These functions are public
            return {
                showTooltip: showTooltip,
                hideTooltip: hideTooltip
            };
        }
    );
    

    This is the tooltip.css:

    .tooltip {   
        position: absolute;           
        text-align: center;           
        font: 12px sans-serif;        
        background-color: rgb(95,230,245);   
        border-radius: 2px;           
        pointer-events: none;         
    }