Based on this previous gist, but robust to changes in browser zoom level (text inside tooltip doesn't get cut off when zoom < 100%).
forked from jebeck's block: Browser-zoom robust foreignObject tooltips
xxxxxxxxxx
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>
SVG foreignObject tooltips in D3
</title>
<script src='https://d3js.org/d3.v3.min.js' charset='utf-8'></script>
<style type='text/css'>
svg {
display: block;
margin: 0 auto;
}
.svg-tooltip {
pointer-events: none;
}
.tooltip {
padding: 0.8333333333em;
color: #4A22FF;
}
.lead {
font-style: italic;
}
p {
margin: 0.4166666667em 0em;
font-size: 1em;
}
polygon {
pointer-events: none;
}
</style>
</head>
<body>
<script type="text/javascript" src='detect-zoom.min.js'></script>
<script type='text/javascript'>
var zoomPercentage = window.detectZoom.device();
d3.select(window).on('resize', function() {
zoomPercentage = window.detectZoom.device();
});
var margin = {top: 20, right: 10, bottom: 20, left: 10};
var width = 800 - margin.left - margin.right;
var height = 480 - margin.top - margin.bottom;
var svg = d3.select('body')
.append('svg')
.attr({
'width': width + margin.left + margin.right,
'height': height + margin.top + margin.bottom
})
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('rect')
.attr({
'width': width * 0.8,
'height': height * 0.8,
'x': width * 0.1,
'y': height * 0.1,
'fill': '#F8F8F8'
});
var foWidth = 300;
var anchor = {'w': width/3, 'h': height/3};
var t = 50;
var k = 15;
var tip = {'w': (3/4 * t), 'h': k};
svg.append('circle')
.attr({
'r': 50,
'cx': anchor.w,
'cy': anchor.h,
'fill': '#12e72b',
'opacity': 0.35
})
.on('mouseover', function() {
var fo = svg.append('foreignObject')
.attr({
'x': anchor.w - tip.w,
'y': anchor.h + tip.h,
'width': foWidth,
'class': 'svg-tooltip'
});
var div = fo.append('xhtml:div')
.append('div')
.attr({
'class': 'tooltip'
});
div.append('p')
.attr('class', 'lead')
.html('Holmes was certainly not a difficult man to live with.');
div.append('p')
.html('He was quiet in his ways, and his habits were regular. It was rare for him to be up after ten at night, and he had invariably breakfasted and gone out before I rose in the morning.');
var foHeight = div[0][0].getBoundingClientRect().height;
console.log('Orig foHeight', foHeight);
console.log('zoomPercentage', zoomPercentage);
foHeight = foHeight/zoomPercentage;
console.log('New foHeight', foHeight);
fo.attr({
'height': foHeight
});
svg.insert('polygon', '.svg-tooltip')
.attr({
'points': "0,0 0," + foHeight + " " +
foWidth + "," + foHeight + " " +
foWidth + ",0 " + (t) + ",0 " +
tip.w + "," + (-tip.h) + " " +
(t/2) + ",0",
'height': foHeight + tip.h,
'width': foWidth,
'fill': '#D8D8D8',
'opacity': 0.75,
'transform': 'translate(' + (anchor.w - tip.w) + ',' + (anchor.h + tip.h) + ')'
});
})
.on('mouseout', function() {
svg.selectAll('.svg-tooltip').remove();
svg.selectAll('polygon').remove();
});
</script>
</body>
</html>
https://d3js.org/d3.v3.min.js