Skip to content

Instantly share code, notes, and snippets.

@zmaril
Forked from mbostock/.block
Created June 24, 2012 03:16
Show Gist options
  • Save zmaril/2981335 to your computer and use it in GitHub Desktop.
Save zmaril/2981335 to your computer and use it in GitHub Desktop.
d3 bootstrap tooltips

Uses the markup and css from bootstrap to make pretty tooltips. Find the files here.

<!doctype html>
<head>
<style>
body {
font: 10px sans-serif;
}
#main {
left: 25%;
position: absolute;
}
#main #text {
padding-bottom: 10px;
}
</style>
<link rel="stylesheet" href="plugin.css">
<script src="http://d3js.org/d3.v2.min.js?2.8.1"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.7.2.min.js"><\/script>')</script>
<script src="plugin.js"></script>
<script src="index.js"></script>
</head>
<body>
<div id="graphic"></div>
</body>
</html>
var graphic;
graphic = new Object;
graphic.create = function() {
var g, height, i, j, points, size, spacing, width, _i, _j, _len, _len2, _ref, _ref2;
width = $(document).width() / 2;
height = $(document).height() * .85;
size = d3.min([width, height]);
graphic.svg = d3.select("#graphic").append("svg").attr("width", size).attr("height", size);
g = graphic.svg.append("g");
points = [];
spacing = 30;
_ref = d3.range(0, height - spacing, spacing);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
i = _ref[_i];
_ref2 = d3.range(0, width - spacing, spacing);
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
j = _ref2[_j];
points.push({
x: i,
y: j
});
}
}
return g.selectAll("circle").data(points).enter().append("circle").attr("cx", function(d, i) {
return d.x;
}).attr("cy", function(d, i) {
return d.y;
}).attr("r", function(d, i) {
return Math.round(Math.random() * spacing / 2 + 1);
}).tooltip(function(d, i) {
var r, svg;
r = +d3.select(this).attr('r');
svg = d3.select(document.createElement("svg")).attr("height", 50);
g = svg.append("g");
g.append("rect").attr("width", r * 10).attr("height", 10);
g.append("text").text("10 times the radius of the cirlce").attr("dy", "25");
return {
type: "tooltip",
text: "Tip for circle of radius " + r,
detection: "shape",
placement: "fixed",
gravity: "right",
position: [d.x, d.y],
displacement: [r+2, -20],
mousemove: false
};
});
};
$(document).ready(graphic.create);
/* Taken from bootstrap: https://github.com/twitter/bootstrap/blob/master/less/tooltip.less */
.fade {
opacity: 0;
-webkit-transition: opacity 0.15s linear;
-moz-transition: opacity 0.15s linear;
-ms-transition: opacity 0.15s linear;
-o-transition: opacity 0.15s linear;
transition: opacity 0.15s linear;
}
.fade.in {
opacity: 1;
}
.tooltip {
position: absolute;
z-index: 1020;
display: block;
padding: 5px;
font-size: 11px;
opacity: 0;
filter: alpha(opacity=0);
visibility: visible;
}
.tooltip.in {
opacity: 0.8;
filter: alpha(opacity=80);
}
.tooltip.top {
margin-top: -2px;
}
.tooltip.right {
margin-left: 2px;
}
.tooltip.bottom {
margin-top: 2px;
}
.tooltip.left {
margin-left: -2px;
}
.tooltip.top .arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top: 5px solid #000000;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
}
.tooltip.left .arrow {
top: 50%;
right: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid #000000;
}
.tooltip.bottom .arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-right: 5px solid transparent;
border-bottom: 5px solid #000000;
border-left: 5px solid transparent;
}
.tooltip.right .arrow {
top: 50%;
left: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-right: 5px solid #000000;
border-bottom: 5px solid transparent;
}
.tooltip-inner {
max-width: 200px;
padding: 3px 8px;
color: #ffffff;
text-align: center;
text-decoration: none;
background-color: #000000;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.arrow {
position: absolute;
width: 0;
height: 0;
}
.popover {
position: absolute;
top: 0;
left: 0;
z-index: 1010;
display: none;
padding: 5px;
}
.popover.top {
margin-top: -5px;
}
.popover.right {
margin-left: 5px;
}
.popover.bottom {
margin-top: 5px;
}
.popover.left {
margin-left: -5px;
}
.popover.top .arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top: 5px solid #000000;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
}
.popover.right .arrow {
top: 50%;
left: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-right: 5px solid #000000;
border-bottom: 5px solid transparent;
}
.popover.bottom .arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-right: 5px solid transparent;
border-bottom: 5px solid #000000;
border-left: 5px solid transparent;
}
.popover.left .arrow {
top: 50%;
right: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid #000000;
}
.popover-inner {
width: 280px;
padding: 3px;
overflow: hidden;
background: #000000;
background: rgba(0, 0, 0, 0.8);
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
}
.popover-title {
padding: 9px 15px;
line-height: 1;
background-color: #f5f5f5;
border-bottom: 1px solid #eee;
-webkit-border-radius: 3px 3px 0 0;
-moz-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
margin: 0;
}
.popover-content {
padding: 14px;
background-color: #ffffff;
-webkit-border-radius: 0 0 3px 3px;
-moz-border-radius: 0 0 3px 3px;
border-radius: 0 0 3px 3px;
-webkit-background-clip: padding-box;
-moz-background-clip: padding-box;
background-clip: padding-box;
}
.popover-content p,
.popover-content ul,
.popover-content ol {
margin-bottom: 0;
}
d3.selection.prototype.tooltip = function(o, f) {
var body, clipped, clipper, d, defaults, height, holder, optionsList, parent, positions, sets, voronois, width;
if (arguments.length < 2) {
f = o;
}
body = d3.select('body');
defaults = {
type: "tooltip",
text: "You need to pass in a string for the text value",
title: "Title value",
content: "Content examples",
detection: "shape",
placement: "fixed",
gravity: "right",
position: [100, 100],
displacement: [0, 0],
mousemove: false
};
optionsList = [];
voronois = [];
this.each(function(d, i) {
var opt;
opt = f.apply(this, arguments);
optionsList.push(opt);
if (opt.detection === 'voronoi') {
return voronois.push([opt, i]);
}
});
if (voronois.length !== 0) {
parent = d3.select(this[0][0].ownerSVGElement);
holder = parent.append("g").attr("id", "__clip__holder__");
console.log(voronois);
positions = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = voronois.length; _i < _len; _i++) {
d = voronois[_i];
_results.push(d[0].position);
}
return _results;
})();
console.log(positions);
sets = d3.geom.voronoi(positions);
height = parent.attr("height");
width = parent.attr("width");
clipper = d3.geom.polygon([[0, 0], [0, height], [width, height], [width, 0]]).clip;
clipped = positions.map(clipper);
holder.append("g").attr("id", "clipPaths").selectAll("clipPath").data(voronois).enter().append("clipPath").attr("id", function(d, i) {
return "clip-" + i;
}).append("circle").attr("cx", function(d) {
return d[0].position[0];
}).attr("cy", function(d) {
return d[0].position[1];
}).attr("r", function(d) {
return 20;
});
holder.append("g").attr("id", "clipped").selectAll("path").data(voronois).enter().append("path").attr("d", function(d, i) {
return "M" + (clipped[i].join('L')) + "Z";
}).attr("clip-path", function(d, i) {
return "url(#clip-" + i + ")";
});
}
return this.each(function(d, i) {
var el, move_tip, options;
options = optionsList[i];
el = d3.select(this);
move_tip = function(selection) {
var center, offsets;
center = [0, 0];
if (options.placement === "mouse") {
center = d3.mouse(body.node());
} else {
offsets = this.ownerSVGElement.getBoundingClientRect();
center[0] = offsets.left;
center[1] = offsets.top;
center[0] += options.position[0];
center[1] += options.position[1];
center[0] += window.scrollX;
center[1] += window.scrollY;
}
center[0] += options.displacement[0];
center[1] += options.displacement[1];
return selection.style("left", "" + center[0] + "px").style("top", "" + center[1] + "px").style("display", "block");
};
el.on("mouseover", function() {
var inner, tip;
tip = body.append("div").classed(options.type, true).classed(options.gravity, true).classed('fade', true).style("display", "none");
if (options.type === "tooltip") {
tip.append("div").html(options.text).attr("class", "tooltip-inner");
}
if (options.type === "popover") {
inner = tip.append("div").attr("class", "popover-inner");
inner.append("h3").text(options.title).attr("class", "popover-title");
inner.append("div").attr("class", "popover-content").append("p").html(options.content[0][0].outerHTML);
}
tip.append("div").attr("class", "arrow");
setTimeout(function() {
return tip.classed('in', true);
}, 10);
return tip.style("display", "").call(move_tip.bind(this));
});
if (options.mousemove) {
el.on("mousemove", function() {
return d3.select("." + options.type).call(move_tip.bind(this));
});
}
return el.on("mouseout", function() {
var tip;
tip = d3.selectAll("." + options.type).classed('in', false);
return setTimeout(function() {
return tip.remove();
}, 150);
});
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment