Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
d3 bootstrap popovers

Uses the markup and css from bootstrap to make pretty popovers. 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="tooltip.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="tooltip.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, _len1, _ref, _ref1;
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];
_ref1 = d3.range(0, width - spacing, spacing);
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
j = _ref1[_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: "popover",
title: "It's a me, Rectangle",
content: svg,
detection: "shape",
placement: "fixed",
gravity: "right",
position: [d.x, d.y],
displacement: [r + 2, -72],
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