├── .gitattributes
├── .gitignore
├── d3.v2.js
├── dist
├── css
│ └── d3-bootstrap-plugins.min.css
└── js
│ ├── d3-bootstrap-plugins.js
│ └── d3-bootstrap-plugins.min.js
├── examples
├── popover
│ ├── index.coffee
│ ├── index.css
│ ├── index.html
│ └── index.js
└── tooltip
│ ├── index.coffee
│ ├── index.css
│ ├── index.html
│ └── index.js
├── grunt.js
├── package.json
├── readme.md
└── src
├── css
└── plugins.css
└── js
├── begin.js
├── end.js
└── plugins.coffee
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Build and node
2 | node_modules
3 | build
4 |
5 | # Numerous always-ignore extensions
6 | *.diff
7 | *.err
8 | *.orig
9 | *.log
10 | *.rej
11 | *.swo
12 | *.swp
13 | *.vi
14 | *~
15 | *.sass-cache
16 |
17 | # OS or Editor folders
18 | .DS_Store
19 | Thumbs.db
20 | .cache
21 | .project
22 | .settings
23 | .tmproj
24 | nbproject
25 | *.sublime-project
26 | *.sublime-workspace
27 |
28 | # Dreamweaver added files
29 | _notes
30 | dwsync.xml
31 |
32 | # Komodo
33 | *.komodoproject
34 | .komodotools
35 |
36 | # Espresso
37 | *.esproj
38 | *.espressostorage
39 |
40 | # Folders to ignore
41 | .hg
42 | .svn
43 | .CVS
44 | intermediate
45 | publish
46 | .idea
47 |
48 | # build script local files
49 | build/buildinfo.properties
50 | build/config/buildinfo.properties
51 |
52 | #emacs junk
53 | *~
54 | \#*\#
55 | /.emacs.desktop
56 | /.emacs.desktop.lock
57 | .elc
58 | auto-save-list
59 | tramp
60 | .\#*
61 |
62 | # Org-mode
63 | .org-id-locations
64 | *_archive
--------------------------------------------------------------------------------
/dist/css/d3-bootstrap-plugins.min.css:
--------------------------------------------------------------------------------
1 | .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 #000;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 #000}.tooltip.bottom .arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.tooltip.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-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 #000;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 #000;border-bottom:5px solid transparent}.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;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 #000}.popover-inner{width:280px;padding:3px;overflow:hidden;background:#000;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:#fff;-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}
--------------------------------------------------------------------------------
/dist/js/d3-bootstrap-plugins.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 |
4 | var annotate;
5 |
6 | annotate = function(options, create) {
7 | var el, move_tip;
8 | el = d3.select(this);
9 | move_tip = function(selection) {
10 | var center, offsets;
11 | center = [0, 0];
12 | var body;
13 | body = d3.select('body');
14 | if (options.placement === "mouse") {
15 | center = d3.mouse(body.node());
16 | } else {
17 | offsets = this.ownerSVGElement.getBoundingClientRect();
18 | center[0] = offsets.left;
19 | center[1] = offsets.top;
20 | center[0] += options.position[0];
21 | center[1] += options.position[1];
22 | center[0] += window.scrollX;
23 | center[1] += window.scrollY;
24 | }
25 | center[0] += options.displacement[0];
26 | center[1] += options.displacement[1];
27 | return selection.style("left", "" + center[0] + "px").style("top", "" + center[1] + "px").style("display", "block");
28 | };
29 | el.on("mouseover", function() {
30 | var inner, tip;
31 | tip = create();
32 | tip.classed("annotation", true).classed(options.gravity, true).classed('fade', true).style("display", "none");
33 | tip.append("div").attr("class", "arrow");
34 | inner = function() {
35 | return tip.classed('in', true);
36 | };
37 | setTimeout(inner, 10);
38 | return tip.style("display", "").call(move_tip.bind(this));
39 | });
40 | if (options.mousemove) {
41 | el.on("mousemove", function() {
42 | return d3.select(".annotation").call(move_tip.bind(this));
43 | });
44 | }
45 | return el.on("mouseout", function() {
46 | var remover, tip;
47 | tip = d3.selectAll(".annotation").classed('in', false);
48 | remover = function() {
49 | return tip.remove();
50 | };
51 | return setTimeout(remover, 150);
52 | });
53 | };
54 |
55 | d3.selection.prototype.popover = function(f) {
56 | var body;
57 | body = d3.select('body');
58 | return this.each(function(d, i) {
59 | var create_popover, options;
60 | options = f.apply(this, arguments);
61 | create_popover = function() {
62 | var inner, tip;
63 | tip = body.append("div").classed("popover", true);
64 | inner = tip.append("div").attr("class", "popover-inner");
65 | inner.append("h3").text(options.title).attr("class", "popover-title");
66 | inner.append("div").attr("class", "popover-content").append("p").html(options.content[0][0].outerHTML);
67 | return tip;
68 | };
69 | return annotate.call(this, options, create_popover);
70 | });
71 | };
72 |
73 | d3.selection.prototype.tooltip = function(f) {
74 | var body;
75 | body = d3.select('body');
76 | return this.each(function(d, i) {
77 | var create_tooltip, options;
78 | options = f.apply(this, arguments);
79 | create_tooltip = function() {
80 | var tip;
81 | tip = body.append("div").classed("tooltip", true);
82 | tip.append("div").html(options.text).attr("class", "tooltip-inner");
83 | return tip;
84 | };
85 | return annotate.call(this, options, create_tooltip);
86 | });
87 | };
88 |
89 | ;})();
90 |
--------------------------------------------------------------------------------
/dist/js/d3-bootstrap-plugins.min.js:
--------------------------------------------------------------------------------
1 | /*! d3-bootstrap-plugins - v0.0.1 - 2012-07-07
2 | * https://github.com/zmaril/d3-bootstrap-plugins
3 | * Copyright (c) 2012 Zack Maril; Licensed MIT */
4 | (function(){var a;a=function(a,b){var c,d;return c=d3.select(this),d=function(b){var c,d;return c=[0,0],a.placement==="mouse"?c=d3.mouse(body.node()):(d=this.ownerSVGElement.getBoundingClientRect(),c[0]=d.left,c[1]=d.top,c[0]+=a.position[0],c[1]+=a.position[1],c[0]+=window.scrollX,c[1]+=window.scrollY),c[0]+=a.displacement[0],c[1]+=a.displacement[1],b.style("left",""+c[0]+"px").style("top",""+c[1]+"px").style("display","block")},c.on("mouseover",function(){var c,e;return e=b(),e.classed("annotation",!0).classed(a.gravity,!0).classed("fade",!0).style("display","none"),e.append("div").attr("class","arrow"),c=function(){return e.classed("in",!0)},setTimeout(c,10),e.style("display","").call(d.bind(this))}),a.mousemove&&c.on("mousemove",function(){return d3.select(".annotation").call(d.bind(this))}),c.on("mouseout",function(){var a,b;return b=d3.selectAll(".annotation").classed("in",!1),a=function(){return b.remove()},setTimeout(a,150)})},d3.selection.prototype.popover=function(b){var c;return c=d3.select("body"),this.each(function(d,e){var g,h;return h=b.apply(this,arguments),g=function(){var a,b;return b=c.append("div").classed("popover",!0),a=b.append("div").attr("class","popover-inner"),a.append("h3").text(h.title).attr("class","popover-title"),a.append("div").attr("class","popover-content").append("p").html(h.content[0][0].outerHTML),b},a.call(this,h,g)})},d3.selection.prototype.tooltip=function(b){var c;return c=d3.select("body"),this.each(function(d,e){var g,h;return h=b.apply(this,arguments),g=function(){var a;return a=c.append("div").classed("tooltip",!0),a.append("div").html(h.text).attr("class","tooltip-inner"),a},a.call(this,h,g)})}})();
--------------------------------------------------------------------------------
/examples/popover/index.coffee:
--------------------------------------------------------------------------------
1 | graphic = new Object
2 |
3 | graphic.create = ()->
4 | width = $(document).width()/2
5 | height = $(document).height()*.85
6 | size = d3.min([width,height])
7 | graphic.svg = d3.select("#graphic")
8 | .append("svg")
9 | .attr("width",size)
10 | .attr("height",size)
11 |
12 | g = graphic.svg.append("g")
13 |
14 | points = []
15 | spacing = 30
16 | for i in d3.range(0,height-spacing,spacing)
17 | for j in d3.range(0,width-spacing,spacing)
18 | points.push(x: i, y: j)
19 |
20 | g.selectAll("circle")
21 | .data(points).enter()
22 | .append("circle")
23 | .attr("cx",(d,i)-> d.x)
24 | .attr("cy",(d,i)-> d.y)
25 | .attr("r",(d,i)-> Math.round(Math.random()*spacing/2+1))
26 | .popover(
27 | (d,i)->
28 | r = +d3.select(this).attr('r')
29 |
30 | svg = d3.select(document.createElement("svg"))
31 | .attr("height",50)
32 |
33 | g = svg.append("g")
34 |
35 | g.append("rect")
36 | .attr("width",r*10)
37 | .attr("height",10)
38 |
39 | g.append("text")
40 | .text("10 times the radius of the cirlce")
41 | .attr("dy","25")
42 |
43 | {
44 | title: "It's a me, Rectangle"
45 | content: svg
46 |
47 | detection: "shape"
48 |
49 | placement: "fixed"
50 | gravity: "right"
51 | position: [d.x,d.y]
52 | displacement: [r+2,-72]
53 | mousemove: false
54 | }
55 | )
56 |
57 | $(document).ready(graphic.create)
58 |
--------------------------------------------------------------------------------
/examples/popover/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 10px sans-serif;
3 | }
4 | #main {
5 | left: 25%;
6 | position: absolute;
7 | }
8 | #main #text {
9 | padding-bottom: 10px;
10 | }
11 |
12 | body {
13 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
14 | font-size: 13px;
15 | line-height: 18px;
16 | color: #333;
17 | }
--------------------------------------------------------------------------------
/examples/popover/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
Popovers.
30 | Hover to display them.
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/examples/popover/index.js:
--------------------------------------------------------------------------------
1 | var graphic;
2 |
3 | graphic = new Object;
4 |
5 | graphic.create = function() {
6 | var g, height, i, j, points, size, spacing, width, _i, _j, _len, _len2, _ref, _ref2;
7 | width = $(document).width() / 2;
8 | height = $(document).height() * .85;
9 | size = d3.min([width, height]);
10 | graphic.svg = d3.select("#graphic").append("svg").attr("width", size).attr("height", size);
11 | g = graphic.svg.append("g");
12 | points = [];
13 | spacing = 30;
14 | _ref = d3.range(0, height - spacing, spacing);
15 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
16 | i = _ref[_i];
17 | _ref2 = d3.range(0, width - spacing, spacing);
18 | for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
19 | j = _ref2[_j];
20 | points.push({
21 | x: i,
22 | y: j
23 | });
24 | }
25 | }
26 | return g.selectAll("circle").data(points).enter().append("circle").attr("cx", function(d, i) {
27 | return d.x;
28 | }).attr("cy", function(d, i) {
29 | return d.y;
30 | }).attr("r", function(d, i) {
31 | return Math.round(Math.random() * spacing / 2 + 1);
32 | }).popover(function(d, i) {
33 | var r, svg;
34 | r = +d3.select(this).attr('r');
35 | svg = d3.select(document.createElement("svg")).attr("height", 50);
36 | g = svg.append("g");
37 | g.append("rect").attr("width", r * 10).attr("height", 10);
38 | g.append("text").text("10 times the radius of the cirlce").attr("dy", "25");
39 | return {
40 | title: "It's a me, Rectangle",
41 | content: svg,
42 | detection: "shape",
43 | placement: "fixed",
44 | gravity: "right",
45 | position: [d.x, d.y],
46 | displacement: [r + 2, -72],
47 | mousemove: false
48 | };
49 | });
50 | };
51 |
52 | $(document).ready(graphic.create);
53 |
--------------------------------------------------------------------------------
/examples/tooltip/index.coffee:
--------------------------------------------------------------------------------
1 | graphic = new Object
2 |
3 | graphic.create = ()->
4 | width = $(document).width()/2
5 | height = $(document).height()*.85
6 | size = d3.min([width,height])
7 | graphic.svg = d3.select("#graphic")
8 | .append("svg")
9 | .attr("width",size)
10 | .attr("height",size)
11 |
12 | g = graphic.svg.append("g")
13 |
14 | points = []
15 | spacing = 30
16 | for i in d3.range(0,height-spacing,spacing)
17 | for j in d3.range(0,width-spacing,spacing)
18 | points.push(x: i, y: j)
19 |
20 | g.selectAll("circle")
21 | .data(points).enter()
22 | .append("circle")
23 | .attr("cx",(d,i)-> d.x)
24 | .attr("cy",(d,i)-> d.y)
25 | .attr("r",(d,i)-> Math.round(Math.random()*spacing/2+1))
26 | .tooltip(
27 | (d,i)->
28 | r = +d3.select(this).attr('r')
29 |
30 | svg = d3.select(document.createElement("svg"))
31 | .attr("height",50)
32 |
33 | g = svg.append("g")
34 |
35 | g.append("rect")
36 | .attr("width",r*10)
37 | .attr("height",10)
38 |
39 | g.append("text")
40 | .text("10 times the radius of the cirlce")
41 | .attr("dy","25")
42 |
43 | {
44 | type: "tooltip"
45 | text: "Tip for circle of radius #{r}"
46 |
47 | detection: "shape"
48 |
49 | placement: "fixed"
50 | gravity: "right"
51 | position: [d.x,d.y]
52 | displacement:[r+2,-20]
53 | mousemove: false
54 | }
55 | )
56 |
57 | $(document).ready(graphic.create)
58 |
--------------------------------------------------------------------------------
/examples/tooltip/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 10px sans-serif;
3 | }
4 | #main {
5 | left: 25%;
6 | position: absolute;
7 | }
8 | #main #text {
9 | padding-bottom: 10px;
10 | }
11 |
12 | body {
13 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
14 | font-size: 13px;
15 | line-height: 18px;
16 | color: #333;
17 | }
--------------------------------------------------------------------------------
/examples/tooltip/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
Tooltip.
30 | Hover to display them.
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/examples/tooltip/index.js:
--------------------------------------------------------------------------------
1 | var graphic;
2 |
3 | graphic = new Object;
4 |
5 | graphic.create = function() {
6 | var g, height, i, j, points, size, spacing, width, _i, _j, _len, _len2, _ref, _ref2;
7 | width = $(document).width() / 2;
8 | height = $(document).height() * .85;
9 | size = d3.min([width, height]);
10 | graphic.svg = d3.select("#graphic").append("svg").attr("width", size).attr("height", size);
11 | g = graphic.svg.append("g");
12 | points = [];
13 | spacing = 30;
14 | _ref = d3.range(0, height - spacing, spacing);
15 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
16 | i = _ref[_i];
17 | _ref2 = d3.range(0, width - spacing, spacing);
18 | for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
19 | j = _ref2[_j];
20 | points.push({
21 | x: i,
22 | y: j
23 | });
24 | }
25 | }
26 | return g.selectAll("circle").data(points).enter().append("circle").attr("cx", function(d, i) {
27 | return d.x;
28 | }).attr("cy", function(d, i) {
29 | return d.y;
30 | }).attr("r", function(d, i) {
31 | return Math.round(Math.random() * spacing / 2 + 1);
32 | }).tooltip(function(d, i) {
33 | var r, svg;
34 | r = +d3.select(this).attr('r');
35 | svg = d3.select(document.createElement("svg")).attr("height", 50);
36 | g = svg.append("g");
37 | g.append("rect").attr("width", r * 10).attr("height", 10);
38 | g.append("text").text("10 times the radius of the cirlce").attr("dy", "25");
39 | return {
40 | type: "tooltip",
41 | text: "Tip for circle of radius " + r,
42 | detection: "shape",
43 | placement: "fixed",
44 | gravity: "right",
45 | position: [d.x, d.y],
46 | displacement: [r+2, -20],
47 | mousemove: false
48 | };
49 | });
50 | };
51 |
52 | $(document).ready(graphic.create);
53 |
--------------------------------------------------------------------------------
/grunt.js:
--------------------------------------------------------------------------------
1 | /*global module:false*/
2 | module.exports = function(grunt) {
3 | //Load in the coffee and css grunt machines!
4 | grunt.loadNpmTasks('grunt-coffee'); // http://github.com/avalade/grunt-coffee
5 | grunt.loadNpmTasks('grunt-css'); // http://github.com/jzaefferer/grunt-css
6 | // Project configuration.
7 | grunt.initConfig({
8 | pkg: '',
9 | meta: {
10 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
11 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
12 | '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
13 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
14 | ' Licensed <%= pkg.license %> */'
15 | },
16 | coffee:{
17 | coffee:{
18 | src: ["src/js/plugins.coffee"],
19 | dest: 'build/js/',
20 | options:{
21 | bare: true
22 | }
23 | }
24 | },
25 | concat: {
26 | dist: {
27 | src: ['src/js/begin.js','build/js/plugins.js','src/js/end.js'],
28 | dest: 'dist/js/<%= pkg.name %>.js'
29 | }
30 | },
31 | min: {
32 | dist: {
33 | src: ['', ''],
34 | dest: 'dist/js/<%= pkg.name %>.min.js'
35 | }
36 | },
37 | cssmin:{
38 | dist:{
39 | src:["src/css/*.css"],
40 | dest:"dist/css/<%= pkg.name %>.min.css"
41 | }
42 | },
43 | watch: {
44 | files: ["src/*/*"],
45 | tasks: 'coffee concat min cssmin'
46 | }
47 | }
48 | );
49 |
50 | // Default task.
51 | grunt.registerTask('default', 'watch');
52 | grunt.registerTask('build','coffee concat min cssmin');
53 | };
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "d3-bootstrap-plugins",
3 | "version": "0.0.1",
4 | "author": "Zack Maril ",
5 | "homepage": "https://github.com/zmaril/d3-bootstrap-plugins",
6 | "description": "js/css duo for bootstrap style tooltips and popovers in d3.",
7 | "author":{
8 | "name": "Zack Maril",
9 | "email": "zack@zacharymaril.com"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/zmaril/d3-bootstrap-plugins"
14 | },
15 | "keywords": [
16 | "d3",
17 | "bootstrap",
18 | "tooltip",
19 | "popover"
20 | ],
21 | "dependencies" : {
22 | "d3" : "2.x.x"
23 | },
24 | "noAnalyze": true,
25 | "devDependencies": {
26 | "grunt" : "0.3.11",
27 | "grunt-css" : "0.2.1",
28 | "grunt-coffee" : "0.0.2"
29 | },
30 | "bundleDependencies": [
31 | ],
32 | "license": "MIT"
33 | }
34 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # d3.js meets bootstrap
2 | js/css duo for bootstrap style [tooltips](http://bl.ocks.org/2981335) and [popovers](http://bl.ocks.org/3012212).
3 |
4 | ## How does it work?
5 | The tooltip function attaches event listeners to
6 | selections that go and display bootstrap tooltips or popovers when
7 | the specified events are detected.
8 |
9 | An example of how to use it:
10 | ```javascript
11 | selection.tooltip(function(d,i){
12 | return {
13 | //The text within the tooltip
14 | text: d.title
15 | //Where
16 | placement: "fixed"
17 | // Base positioning. Not used when placement is "mouse"
18 | position: [d.x,d.y]
19 | //How far the tooltip is shifted from the base
20 | displacement: [0,20] //Shifting parts of the graph over.
21 | //If "mouse"" is the base poistion, then mousemove true allows
22 | //the tooltip to move with the mouse
23 | mousemove: false
24 | };
25 | });
26 |
27 | selection.popover(function(d,i){
28 | //TODO: add in a svg element here based on data
29 | return {
30 | // The title that will be displayed on the popover
31 | title: "A title"
32 | //A d3 svg element
33 | content: svg
34 | placement: "fixed"
35 | gravity: "right"
36 | position: [d.x,d.y]
37 | displacement: [0,20]
38 | mousemove: false
39 | };
40 | });
41 |
42 | ```
43 |
44 | Viola! Tooltips! Popovers!
45 |
46 | ## Current TODOS
47 | * Get easy voronoi detection working without breaking
48 | everything. Checkout the
49 | [voronoi](https://github.com/zmaril/d3-bootstrap-plugins/tree/voronoi)
50 | branch for current work on this.
51 | * Bring over the less files from bootstrap directly instead of
52 | replying on their css.
53 | * Write some tests.
54 | * Use it in production.
55 |
56 | ## Contributing
57 |
58 | Local development uses grunt (`npm install grunt`)
59 |
60 | `grunt watch`- automatically compile the files as you change the src directory
61 |
62 | `grunt build`- goes through concatenation and minification of js and
63 | css.
64 |
65 | If you are adding new features, please create an example that
66 | demonstrates that feature specifically.
67 |
68 | ## License
69 |
70 | ### Major components:
71 | * d3.js: [License](https://github.com/mbostock/d3/blob/master/LICENSE)
72 | * Bootstrap: [License](https://github.com/twitter/bootstrap/blob/master/LICENSE)
73 |
74 | ### Everything else:
75 |
76 | MIT License.
77 |
--------------------------------------------------------------------------------
/src/css/plugins.css:
--------------------------------------------------------------------------------
1 | /* Taken from bootstrap: https://github.com/twitter/bootstrap/blob/master/less/tooltip.less */
2 | .fade {
3 | opacity: 0;
4 | -webkit-transition: opacity 0.15s linear;
5 | -moz-transition: opacity 0.15s linear;
6 | -ms-transition: opacity 0.15s linear;
7 | -o-transition: opacity 0.15s linear;
8 | transition: opacity 0.15s linear;
9 | }
10 |
11 | .fade.in {
12 | opacity: 1;
13 | }
14 |
15 | .tooltip {
16 | position: absolute;
17 | z-index: 1020;
18 | display: block;
19 | padding: 5px;
20 | font-size: 11px;
21 | opacity: 0;
22 | filter: alpha(opacity=0);
23 | visibility: visible;
24 | }
25 |
26 | .tooltip.in {
27 | opacity: 0.8;
28 | filter: alpha(opacity=80);
29 | }
30 |
31 | .tooltip.top {
32 | margin-top: -2px;
33 | }
34 |
35 | .tooltip.right {
36 | margin-left: 2px;
37 | }
38 |
39 | .tooltip.bottom {
40 | margin-top: 2px;
41 | }
42 |
43 | .tooltip.left {
44 | margin-left: -2px;
45 | }
46 |
47 | .tooltip.top .arrow {
48 | bottom: 0;
49 | left: 50%;
50 | margin-left: -5px;
51 | border-top: 5px solid #000000;
52 | border-right: 5px solid transparent;
53 | border-left: 5px solid transparent;
54 | }
55 |
56 | .tooltip.left .arrow {
57 | top: 50%;
58 | right: 0;
59 | margin-top: -5px;
60 | border-top: 5px solid transparent;
61 | border-bottom: 5px solid transparent;
62 | border-left: 5px solid #000000;
63 | }
64 |
65 | .tooltip.bottom .arrow {
66 | top: 0;
67 | left: 50%;
68 | margin-left: -5px;
69 | border-right: 5px solid transparent;
70 | border-bottom: 5px solid #000000;
71 | border-left: 5px solid transparent;
72 | }
73 |
74 | .tooltip.right .arrow {
75 | top: 50%;
76 | left: 0;
77 | margin-top: -5px;
78 | border-top: 5px solid transparent;
79 | border-right: 5px solid #000000;
80 | border-bottom: 5px solid transparent;
81 | }
82 |
83 | .tooltip-inner {
84 | max-width: 200px;
85 | padding: 3px 8px;
86 | color: #ffffff;
87 | text-align: center;
88 | text-decoration: none;
89 | background-color: #000000;
90 | -webkit-border-radius: 4px;
91 | -moz-border-radius: 4px;
92 | border-radius: 4px;
93 | }
94 |
95 | .arrow {
96 | position: absolute;
97 | width: 0;
98 | height: 0;
99 | }
100 |
101 | .popover {
102 | position: absolute;
103 | top: 0;
104 | left: 0;
105 | z-index: 1010;
106 | display: none;
107 | padding: 5px;
108 | }
109 |
110 | .popover.top {
111 | margin-top: -5px;
112 | }
113 |
114 | .popover.right {
115 | margin-left: 5px;
116 | }
117 |
118 | .popover.bottom {
119 | margin-top: 5px;
120 | }
121 |
122 | .popover.left {
123 | margin-left: -5px;
124 | }
125 |
126 | .popover.top .arrow {
127 | bottom: 0;
128 | left: 50%;
129 | margin-left: -5px;
130 | border-top: 5px solid #000000;
131 | border-right: 5px solid transparent;
132 | border-left: 5px solid transparent;
133 | }
134 |
135 | .popover.right .arrow {
136 | top: 50%;
137 | left: 0;
138 | margin-top: -5px;
139 | border-top: 5px solid transparent;
140 | border-right: 5px solid #000000;
141 | border-bottom: 5px solid transparent;
142 | }
143 |
144 | .popover.bottom .arrow {
145 | top: 0;
146 | left: 50%;
147 | margin-left: -5px;
148 | border-right: 5px solid transparent;
149 | border-bottom: 5px solid #000000;
150 | border-left: 5px solid transparent;
151 | }
152 |
153 | .popover.left .arrow {
154 | top: 50%;
155 | right: 0;
156 | margin-top: -5px;
157 | border-top: 5px solid transparent;
158 | border-bottom: 5px solid transparent;
159 | border-left: 5px solid #000000;
160 | }
161 |
162 | .popover-inner {
163 | width: 280px;
164 | padding: 3px;
165 | overflow: hidden;
166 | background: #000000;
167 | background: rgba(0, 0, 0, 0.8);
168 | -webkit-border-radius: 6px;
169 | -moz-border-radius: 6px;
170 | border-radius: 6px;
171 | -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
172 | -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
173 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
174 | }
175 |
176 | .popover-title {
177 | padding: 9px 15px;
178 | line-height: 1;
179 | background-color: #f5f5f5;
180 | border-bottom: 1px solid #eee;
181 | -webkit-border-radius: 3px 3px 0 0;
182 | -moz-border-radius: 3px 3px 0 0;
183 | border-radius: 3px 3px 0 0;
184 | margin: 0;
185 | }
186 |
187 | .popover-content {
188 | padding: 14px;
189 | background-color: #ffffff;
190 | -webkit-border-radius: 0 0 3px 3px;
191 | -moz-border-radius: 0 0 3px 3px;
192 | border-radius: 0 0 3px 3px;
193 | -webkit-background-clip: padding-box;
194 | -moz-background-clip: padding-box;
195 | background-clip: padding-box;
196 | }
197 |
198 | .popover-content p,
199 | .popover-content ul,
200 | .popover-content ol {
201 | margin-bottom: 0;
202 | }
--------------------------------------------------------------------------------
/src/js/begin.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 |
--------------------------------------------------------------------------------
/src/js/end.js:
--------------------------------------------------------------------------------
1 | ;})();
--------------------------------------------------------------------------------
/src/js/plugins.coffee:
--------------------------------------------------------------------------------
1 | annotate = (options,create)->
2 | el = d3.select(this)
3 |
4 | move_tip = (selection)->
5 | center = [0,0]
6 |
7 | if options.placement is "mouse"
8 | center = d3.mouse(d3.select('body').node())
9 | else
10 | offsets = @ownerSVGElement.getBoundingClientRect()
11 | center[0] = offsets.left
12 | center[1] = offsets.top
13 |
14 | center[0] += options.position[0]
15 | center[1] += options.position[1]
16 |
17 | center[0]+= window.pageXOffset
18 | center[1]+= window.pageYOffset
19 |
20 | center[0] += options.displacement[0]
21 | center[1] += options.displacement[1]
22 |
23 | selection
24 | .style("left","#{center[0]}px")
25 | .style("top","#{center[1]}px")
26 | .style("display","block")
27 |
28 | el.on("mouseover",()->
29 | tip = create()
30 |
31 | tip.classed("annotation", true)
32 | .classed(options.gravity, true)
33 | .classed('fade', true)
34 | .style("display","none")
35 |
36 | tip.append("div")
37 | .attr("class","arrow")
38 |
39 | inner = ()-> tip.classed('in', true)
40 |
41 | setTimeout(inner,10)
42 |
43 | tip.style("display","").call(move_tip.bind(this))
44 | )
45 |
46 | if options.mousemove
47 | el.on("mousemove",()->
48 | d3.select(".annotation").call(move_tip.bind(this))
49 | )
50 |
51 | el.on("mouseout",()->
52 | tip = d3.selectAll(".annotation").classed('in', false)
53 | remover = ()-> tip.remove()
54 | setTimeout(remover,150)
55 | )
56 |
57 | d3.selection.prototype.popover = (f)->
58 | body = d3.select('body')
59 |
60 | this.each((d,i)->
61 | options = f.apply(this,arguments)
62 |
63 | create_popover = ()->
64 |
65 | tip = body.append("div")
66 | .classed("popover", true)
67 |
68 | inner = tip.append("div")
69 | .attr("class","popover-inner")
70 |
71 | inner.append("h3")
72 | .text(options.title)
73 | .attr("class","popover-title")
74 |
75 | inner.append("div")
76 | .attr("class","popover-content")
77 | .append("p")
78 | .html(options.content[0][0].outerHTML)
79 |
80 | return tip
81 |
82 | annotate.call(this,options,create_popover)
83 | )
84 |
85 |
86 | d3.selection.prototype.tooltip = (f)->
87 | body = d3.select('body')
88 |
89 | this.each (d,i)->
90 |
91 | options = f.apply(this,arguments)
92 |
93 | create_tooltip = ()->
94 | tip = body.append("div")
95 | .classed("tooltip", true)
96 |
97 | tip.append("div")
98 | .html(options.text)
99 | .attr("class","tooltip-inner")
100 |
101 | return tip
102 |
103 | annotate.call(this,options,create_tooltip)
104 |
--------------------------------------------------------------------------------