Skip to content

Commit

Permalink
tooltips: add move,show,hide,text functions
Browse files Browse the repository at this point in the history
   - also add panelutil function get_object_position
  • Loading branch information
kbroman committed Jun 8, 2020
1 parent f2322af commit 472d328
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 122 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## d3panels 1.6.1 (2020-06-07)
## d3panels 1.6.2 (2020-06-08)

- Implemented custom tool tips in order to drop the
[d3-tip]http://labratrevenge.com/d3-tip) library, which is no longer
Expand Down
136 changes: 84 additions & 52 deletions d3panels.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
!function() { // encapsulate d3panels functions
var d3panels = {
version: "1.6.1"
version: "1.6.2"
};
"use strict";

Expand Down Expand Up @@ -1059,6 +1059,18 @@ d3panels.check_listarg_v_default = function (arg, defaults) {
}

return arg;
}; // get x,y client position of an object


d3panels.object_position = function (object) {
var obj, x, y;
obj = object.node().getBoundingClientRect();
x = obj.left / 2.0 + obj.right / 2.0;
y = obj.top / 2.0 + obj.bottom / 2.0;
return {
x: x,
y: y
};
};"use strict";

// Generated by CoffeeScript 2.5.1
Expand Down Expand Up @@ -7099,7 +7111,7 @@ d3panels.double_slider = function (chartOpts) {
// Generated by CoffeeScript 2.5.1
// tool tips
d3panels.tooltip_create = function (selection, objects, options, tooltip_func) {
var direction, fill, fontcolor, fontsize, in_duration, out_duration, pad, ref, ref1, ref2, ref3, ref4, tipclass, tipdiv, triChar, tridiv;
var direction, fill, fontcolor, fontsize, in_duration, out_duration, pad, ref, ref1, ref2, ref3, ref4, tipclass, tipdiv, tipgroup, triChar, tridiv;
tipclass = (ref = options != null ? options.tipclass : void 0) != null ? ref : "d3panels-tooltip";
direction = (ref1 = options != null ? options.direction : void 0) != null ? ref1 : "east";
out_duration = (ref2 = options != null ? options.out_duration : void 0) != null ? ref2 : 1000;
Expand All @@ -7108,7 +7120,11 @@ d3panels.tooltip_create = function (selection, objects, options, tooltip_func) {
fill = options != null ? options.fill : void 0;
fontcolor = options != null ? options.fontcolor : void 0;
fontsize = options != null ? options.fontsize : void 0;
tipdiv = selection.append("div").attr("class", "d3panels-tooltip " + tipclass).style("opacity", 0);
tipgroup = selection.append("g").attr("class", "d3panels-tooltip " + tipclass).style("opacity", 0).datum({
direction: direction,
pad: pad
});
tipdiv = tipgroup.append("div").attr("class", "d3panels-tooltip " + tipclass);

if (direction === "east") {
triChar = "\u25C0"; // triangle pointing left
Expand All @@ -7122,7 +7138,7 @@ d3panels.tooltip_create = function (selection, objects, options, tooltip_func) {
d3panels.displayError("tooltip_create: invalid direction (" + direction + ")");
}

tridiv = selection.append("div").attr("class", "d3panels-tooltip-tri " + tipclass).style("opacity", 0).html(triChar);
tridiv = tipgroup.append("div").attr("class", "d3panels-tooltip-tri " + tipclass).html(triChar);

if (fill != null) {
tipdiv.style("background", fill);
Expand All @@ -7142,65 +7158,81 @@ d3panels.tooltip_create = function (selection, objects, options, tooltip_func) {

if (fontsize != null) {
tridiv.style("font-size", fontsize + "px");
} // make sure we have the font size

}

fontsize = tridiv.style("font-size").replace("px", "") * 1.0;
pad = pad * 1.0 + fontsize;
objects.on("mouseover." + tipclass, function (d, i) {
var divpad, mouseX, mouseY, posX, posY, shiftX, shiftY, tipbox_height, tipbox_width, triX, triY; // mouse position; make sure these are numbers
var mouseX, mouseY; // mouse position; make sure these are numbers

mouseX = d3.event.pageX * 1.0;
mouseY = d3.event.pageY * 1.0;
tipdiv.html(tooltip_func(d, i));
tipbox_height = tipdiv.node().getBoundingClientRect().height * 1.0;
tipbox_width = tipdiv.node().getBoundingClientRect().width * 1.0;
shiftX = shiftY = 0; // <- for triangle, relative to tool tip box

if (direction === "east") {
posX = mouseX + pad;
posY = mouseY - tipbox_height / 2.0;
divpad = tipdiv.style("padding-left").replace("px", "") * 1.0;
triChar = "\u25C0";
shiftX = -fontsize - divpad;
shiftY = tipbox_height / 2.0 - fontsize / 2.0;
} else if (direction === "west") {
posX = mouseX - tipbox_width * 1.0 - pad;
posY = mouseY - tipbox_height / 2.0;
divpad = tipdiv.style("padding-right").replace("px", "") * 1.0;
triChar = "\u25B6";
shiftX = tipbox_width - fontsize + divpad;
shiftY = tipbox_height / 2.0 - fontsize / 2.0;
} else if (direction === "north") {
posX = mouseX - tipbox_width / 2.0;
posY = mouseY - tipbox_height - pad;
divpad = tipdiv.style("padding-bottom").replace("px", "") * 1.0;
triChar = "\u25BC";
shiftX = tipbox_width / 2.0 - fontsize;
shiftY = tipbox_height + divpad / 2.0 - fontsize / 2.0;
} else if (direction === "south") {
posX = mouseX - tipbox_width / 2.0;
posY = mouseY + pad;
divpad = tipdiv.style("padding-top").replace("px", "") * 1.0;
triChar = "\u25B2";
shiftX = +tipbox_width / 2.0 - fontsize;
shiftY = -fontsize;
}

tipdiv.style("left", posX + "px").style("top", posY + "px").transition().duration(in_duration).style("opacity", 1.0);
triX = posX + shiftX;
triY = posY + shiftY;
return tridiv.style("left", triX + "px").style("top", triY + "px").style("width", tipbox_width).style("height", tipbox_height).transition().duration(in_duration).style("opacity", 1.0);
d3panels.tooltip_move(tipgroup, mouseX, mouseY);
return d3panels.tooltip_show(tipgroup, in_duration);
});
objects.on("mouseout." + tipclass, function (d) {
tipdiv.transition().duration(out_duration).style("opacity", 0);
return tridiv.transition().duration(out_duration).style("opacity", 0);
return d3panels.tooltip_hide(tipgroup, out_duration);
});
return tipdiv;
return tipgroup;
};

d3panels.tooltip_move = function (tipgroup, x, y) {
var direction, divpad, fontsize, pad, posX, posY, shiftX, shiftY, tipbox_height, tipbox_width, tipdiv, triX, triY, tridiv;
tipdiv = tipgroup.select("div.d3panels-tooltip");
tridiv = tipgroup.select("div.d3panels-tooltip-tri");
tipbox_height = tipdiv.node().getBoundingClientRect().height * 1.0;
tipbox_width = tipdiv.node().getBoundingClientRect().width * 1.0; // make sure we have the font size

fontsize = tridiv.style("font-size").replace("px", "") * 1.0;
pad = tipgroup.datum().pad * 1.0 + fontsize;
direction = tipgroup.datum().direction;
shiftX = shiftY = 0; // <- for triangle, relative to tool tip box

if (direction === "east") {
posX = x + pad;
posY = y - tipbox_height / 2.0;
divpad = tipdiv.style("padding-left").replace("px", "") * 1.0;
shiftX = -fontsize - divpad;
shiftY = tipbox_height / 2.0 - fontsize / 2.0;
} else if (direction === "west") {
posX = x - tipbox_width * 1.0 - pad;
posY = y - tipbox_height / 2.0;
divpad = tipdiv.style("padding-right").replace("px", "") * 1.0;
shiftX = tipbox_width - fontsize + divpad;
shiftY = tipbox_height / 2.0 - fontsize / 2.0;
} else if (direction === "north") {
posX = x - tipbox_width / 2.0;
posY = y - tipbox_height - pad;
divpad = tipdiv.style("padding-bottom").replace("px", "") * 1.0;
shiftX = tipbox_width / 2.0 - fontsize;
shiftY = tipbox_height + divpad / 2.0 - fontsize / 2.0;
} else if (direction === "south") {
posX = x - tipbox_width / 2.0;
posY = y + pad;
divpad = tipdiv.style("padding-top").replace("px", "") * 1.0;
shiftX = +tipbox_width / 2.0 - fontsize;
shiftY = -fontsize;
}

tipdiv.style("left", posX + "px").style("top", posY + "px");
triX = posX + shiftX;
triY = posY + shiftY;
return tridiv.style("left", triX + "px").style("top", triY + "px").style("width", tipbox_width).style("height", tipbox_height);
};

d3panels.tooltip_text = function (tipgroup, text) {
return tipgroup.select("div.d3panels-tooltip").html(text);
};

d3panels.tooltip_show = function (tipgroup, duration) {
return tipgroup.transition().duration(duration).style("opacity", 1);
};

d3panels.tooltip_hide = function (tipgroup, duration) {
return tipgroup.transition().duration(duration).style("opacity", 0);
};

d3panels.tooltip_destroy = function (tipdiv) {
return tipdiv.remove();
d3panels.tooltip_destroy = function (tipgroup) {
return tipgroup.remove();
}; if (typeof define === "function" && define.amd) this.d3panels = d3panels, define(d3panels); else if (typeof module === "object" && module.exports) module.exports = d3panels; else this.d3panels = d3panels;

}(); // bottom of d3panels encapsulation
2 changes: 1 addition & 1 deletion d3panels.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "d3panels",
"version": "1.6.1",
"version": "1.6.2",
"description": "D3-based graphics panels",
"author": "Karl Broman <[email protected]> (https://kbroman.org)",
"repository": "github:kbroman/d3panels",
Expand Down
2 changes: 1 addition & 1 deletion src/d3panels_top.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!function() { // encapsulate d3panels functions
var d3panels = {
version: "1.6.1"
version: "1.6.2"
};
7 changes: 7 additions & 0 deletions src/panelutil.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,10 @@ d3panels.check_listarg_v_default = (arg, defaults) ->
for key of defaults
arg[key] = defaults[key] unless arg[key]?
arg

# get x,y client position of an object
d3panels.object_position = (object) ->
obj = object.node().getBoundingClientRect()
x = obj.left/2.0 + obj.right/2.0
y = obj.top/2.0 + obj.bottom/2.0
{x:x, y:y}
141 changes: 75 additions & 66 deletions src/tooltips.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ d3panels.tooltip_create = (selection, objects, options, tooltip_func) ->
fontcolor = options?.fontcolor
fontsize = options?.fontsize

tipdiv = selection.append("div")
.attr("class", "d3panels-tooltip #{tipclass}")
.style("opacity", 0)
tipgroup = selection.append("g")
.attr("class", "d3panels-tooltip #{tipclass}")
.style("opacity",0)
.datum({direction:direction, pad:pad})
tipdiv = tipgroup.append("div")
.attr("class", "d3panels-tooltip #{tipclass}")

if direction == "east"
triChar = '\u25C0' # triangle pointing left
Expand All @@ -25,95 +28,101 @@ d3panels.tooltip_create = (selection, objects, options, tooltip_func) ->
else
d3panels.displayError("tooltip_create: invalid direction (#{direction})")

tridiv = selection.append("div")
.attr("class", "d3panels-tooltip-tri #{tipclass}")
.style("opacity", 0)
.html(triChar)
tridiv = tipgroup.append("div")
.attr("class", "d3panels-tooltip-tri #{tipclass}")
.html(triChar)

tipdiv.style("background", fill) if fill?
tipdiv.style("color", fontcolor) if fontcolor?
tipdiv.style("font-size", "#{fontsize}px") if fontsize?
tridiv.style("color", fill) if fill?
tridiv.style("font-size", "#{fontsize}px") if fontsize?

# make sure we have the font size
fontsize = tridiv.style("font-size").replace("px", "")*1.0
pad = pad * 1.0 + fontsize

objects.on("mouseover.#{tipclass}", (d,i) ->
# mouse position; make sure these are numbers
mouseX = d3.event.pageX*1.0
mouseY = d3.event.pageY*1.0

tipdiv.html(tooltip_func(d,i))

tipbox_height = tipdiv.node().getBoundingClientRect().height*1.0
tipbox_width = tipdiv.node().getBoundingClientRect().width*1.0
d3panels.tooltip_move(tipgroup, mouseX, mouseY)
d3panels.tooltip_show(tipgroup, in_duration))

objects.on("mouseout.#{tipclass}", (d) ->
d3panels.tooltip_hide(tipgroup, out_duration))

tipgroup

d3panels.tooltip_move = (tipgroup, x, y) ->
tipdiv = tipgroup.select("div.d3panels-tooltip")
tridiv = tipgroup.select("div.d3panels-tooltip-tri")

tipbox_height = tipdiv.node().getBoundingClientRect().height*1.0
tipbox_width = tipdiv.node().getBoundingClientRect().width*1.0

# make sure we have the font size
fontsize = tridiv.style("font-size").replace("px", "")*1.0
pad = tipgroup.datum().pad * 1.0 + fontsize
direction = tipgroup.datum().direction

shiftX = shiftY = 0 # <- for triangle, relative to tool tip box
if direction == "east"
posX = mouseX + pad
posY = mouseY - tipbox_height/2.0
shiftX = shiftY = 0 # <- for triangle, relative to tool tip box
if direction == "east"
posX = x + pad
posY = y - tipbox_height/2.0

divpad = tipdiv.style("padding-left").replace("px", "")*1.0
divpad = tipdiv.style("padding-left").replace("px", "")*1.0

triChar = '\u25C0'
shiftX = -fontsize - divpad
shiftY = tipbox_height/2.0 - fontsize/2.0
else if direction == "west"
posX = mouseX - tipbox_width*1.0 - pad
posY = mouseY - tipbox_height/2.0
shiftX = -fontsize - divpad
shiftY = tipbox_height/2.0 - fontsize/2.0
else if direction == "west"
posX = x - tipbox_width*1.0 - pad
posY = y - tipbox_height/2.0

divpad = tipdiv.style("padding-right").replace("px", "")*1.0
divpad = tipdiv.style("padding-right").replace("px", "")*1.0

triChar = '\u25B6'
shiftX = tipbox_width - fontsize + divpad
shiftY = tipbox_height/2.0-fontsize/2.0
else if direction == "north"
posX = mouseX - tipbox_width/2.0
posY = mouseY - tipbox_height - pad
shiftX = tipbox_width - fontsize + divpad
shiftY = tipbox_height/2.0-fontsize/2.0
else if direction == "north"
posX = x - tipbox_width/2.0
posY = y - tipbox_height - pad

divpad = tipdiv.style("padding-bottom").replace("px", "")*1.0
divpad = tipdiv.style("padding-bottom").replace("px", "")*1.0

triChar = '\u25BC'
shiftX = tipbox_width/2.0-fontsize
shiftY = tipbox_height+divpad/2.0-fontsize/2.0
else if direction == "south"
posX = mouseX - tipbox_width/2.0
posY = mouseY + pad
shiftX = tipbox_width/2.0-fontsize
shiftY = tipbox_height+divpad/2.0-fontsize/2.0
else if direction == "south"
posX = x - tipbox_width/2.0
posY = y + pad

divpad = tipdiv.style("padding-top").replace("px", "")*1.0
divpad = tipdiv.style("padding-top").replace("px", "")*1.0

triChar = '\u25B2'
shiftX = +tipbox_width/2.0-fontsize
shiftY = -fontsize
shiftX = +tipbox_width/2.0-fontsize
shiftY = -fontsize

tipdiv.style("left", "#{posX}px")
.style("top", "#{posY}px")
.transition()
.duration(in_duration)
.style("opacity", 1.0)
tipdiv.style("left", "#{posX}px")
.style("top", "#{posY}px")

triX = posX + shiftX
triY = posY + shiftY
triX = posX + shiftX
triY = posY + shiftY

tridiv.style("left", "#{triX}px")
.style("top", "#{triY}px")
.style("width", tipbox_width)
.style("height", tipbox_height)
.transition()
.duration(in_duration)
.style("opacity", 1.0))
tridiv.style("left", "#{triX}px")
.style("top", "#{triY}px")
.style("width", tipbox_width)
.style("height", tipbox_height)

objects.on("mouseout.#{tipclass}", (d) ->
tipdiv.transition()
.duration(out_duration)
.style("opacity", 0)
tridiv.transition()
.duration(out_duration)
.style("opacity", 0))

tipdiv
d3panels.tooltip_text = (tipgroup, text) ->
tipgroup.select("div.d3panels-tooltip").html(text)

d3panels.tooltip_show = (tipgroup, duration) ->
tipgroup.transition()
.duration(duration)
.style("opacity", 1)

d3panels.tooltip_hide = (tipgroup, duration) ->
tipgroup.transition()
.duration(duration)
.style("opacity", 0)

d3panels.tooltip_destroy = (tipdiv) ->
tipdiv.remove()
d3panels.tooltip_destroy = (tipgroup) ->
tipgroup.remove()

0 comments on commit 472d328

Please sign in to comment.