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:
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)?
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;
}