dimple-js
Version:
Dimple is an object-oriented API allowing you to create flexible axis-based charts using [d3.js](http://d3js.org "d3.js").
179 lines (165 loc) • 8.8 kB
JavaScript
// Copyright: 2015 AlignAlytics
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/methods/_showBarTooltip.js
dimple._showBarTooltip = function (e, shape, chart, series) {
// The margin between the text and the box
var textMargin = 5,
// The margin between the ring and the popup
popupMargin = 10,
// The popup animation duration in ms
animDuration = 750,
// Collect some facts about the highlighted bar
selectedShape = d3.select(shape),
x = selectedShape.node().getBBox().x,
y = selectedShape.node().getBBox().y,
width = selectedShape.node().getBBox().width,
height = selectedShape.node().getBBox().height,
//transform = selectedShape.attr("transform"),
opacity = selectedShape.attr("opacity"),
fill = selectedShape.attr("fill"),
dropDest = series._dropLineOrigin(),
// Fade the popup stroke mixing the shape fill with 60% white
popupStrokeColor = d3.rgb(
d3.rgb(fill).r + 0.6 * (255 - d3.rgb(fill).r),
d3.rgb(fill).g + 0.6 * (255 - d3.rgb(fill).g),
d3.rgb(fill).b + 0.6 * (255 - d3.rgb(fill).b)
),
// Fade the popup fill mixing the shape fill with 80% white
popupFillColor = d3.rgb(
d3.rgb(fill).r + 0.8 * (255 - d3.rgb(fill).r),
d3.rgb(fill).g + 0.8 * (255 - d3.rgb(fill).g),
d3.rgb(fill).b + 0.8 * (255 - d3.rgb(fill).b)
),
t,
box,
tipText = series.getTooltipText(e),
// The running y value for the text elements
yRunning = 0,
// The maximum bounds of the text elements
w = 0,
h = 0,
// Values to shift the popup
translateX,
translateY,
transformer,
offset,
transformPoint = function (x, y) {
var matrix = selectedShape.node().getCTM(),
position = chart.svg.node().createSVGPoint();
position.x = x || 0;
position.y = y || 0;
return position.matrixTransform(matrix);
};
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
chart._tooltipGroup.remove();
}
chart._tooltipGroup = chart.svg.append("g");
if (!series.p) {
offset = (series._isStacked() ? 1 : width / 2);
// Add a drop line to the x axis
if (!series.x._hasCategories() && dropDest.y !== null) {
chart._tooltipGroup.append("line")
.attr("x1", (x < series.x._origin ? x + offset : x + width - offset))
.attr("y1", (y < dropDest.y ? y + height : y))
.attr("x2", (x < series.x._origin ? x + offset : x + width - offset))
.attr("y2", (y < dropDest.y ? y + height : y))
.style("fill", "none")
.style("stroke", fill)
.style("stroke-width", 2)
.style("stroke-dasharray", ("3, 3"))
.style("opacity", opacity)
.transition()
.delay(animDuration / 2)
.duration(animDuration / 2)
.ease("linear")
// Added 1px offset to cater for svg issue where a transparent
// group overlapping a line can sometimes hide it in some browsers
// Issue #10
.attr("y2", (y < dropDest.y ? dropDest.y - 1 : dropDest.y + 1));
}
offset = (series._isStacked() ? 1 : height / 2);
// Add a drop line to the y axis
if (!series.y._hasCategories() && dropDest.x !== null) {
chart._tooltipGroup.append("line")
.attr("x1", (x < dropDest.x ? x + width : x))
.attr("y1", (y < series.y._origin ? y + offset : y + height - offset))
.attr("x2", (x < dropDest.x ? x + width : x))
.attr("y2", (y < series.y._origin ? y + offset : y + height - offset))
.style("fill", "none")
.style("stroke", fill)
.style("stroke-width", 2)
.style("stroke-dasharray", ("3, 3"))
.style("opacity", opacity)
.transition()
.delay(animDuration / 2)
.duration(animDuration / 2)
.ease("linear")
// Added 1px offset to cater for svg issue where a transparent
// group overlapping a line can sometimes hide it in some browsers
// Issue #10
.attr("x2", (x < dropDest.x ? dropDest.x - 1 : dropDest.x + 1));
}
}
// Add a group for text
t = chart._tooltipGroup.append("g");
// Create a box for the popup in the text group
box = t.append("rect")
.attr("class", "dimple-tooltip " + chart.customClassList.tooltipBox);
// Create a text object for every row in the popup
t.selectAll(".dimple-dont-select-any").data(tipText).enter()
.append("text")
.attr("class", "dimple-tooltip " + chart.customClassList.tooltipLabel)
.text(function (d) { return d; })
.style("font-family", series.tooltipFontFamily)
.style("font-size", series._getTooltipFontSize());
// Get the max height and width of the text items
t.each(function () {
w = (this.getBBox().width > w ? this.getBBox().width : w);
h = (this.getBBox().width > h ? this.getBBox().height : h);
});
// Position the text relative to the bar, the absolute positioning
// will be done by translating the group
t.selectAll("text")
.attr("x", 0)
.attr("y", function () {
// Increment the y position
yRunning += this.getBBox().height;
// Position the text at the centre point
return yRunning - (this.getBBox().height / 2);
});
// Draw the box with a margin around the text
box.attr("x", -textMargin)
.attr("y", -textMargin)
.attr("height", Math.floor(yRunning + textMargin) - 0.5)
.attr("width", w + 2 * textMargin)
.attr("rx", 5)
.attr("ry", 5)
.style("fill", popupFillColor)
.style("stroke", popupStrokeColor)
.style("stroke-width", 2)
.style("opacity", 0.95);
// Shift the popup around to avoid overlapping the svg edge
if (transformPoint(x + width + textMargin + popupMargin + w).x < parseFloat(chart.svg.node().getBBox().width)) {
// Draw centre right
translateX = (x + width + textMargin + popupMargin);
translateY = (y + (height / 2) - ((yRunning - (h - textMargin)) / 2));
} else if (transformPoint(x - (textMargin + popupMargin + w)).x > 0) {
// Draw centre left
translateX = (x - (textMargin + popupMargin + w));
translateY = (y + (height / 2) - ((yRunning - (h - textMargin)) / 2));
} else if (transformPoint(0, y + height + yRunning + popupMargin + textMargin).y < parseFloat(chart.svg.node().getBBox().height)) {
// Draw centre below
translateX = (x + (width / 2) - (2 * textMargin + w) / 2);
translateX = (translateX > 0 ? translateX : popupMargin);
translateX = (translateX + w < parseFloat(chart.svg.node().getBBox().width) ? translateX : parseFloat(chart.svg.node().getBBox().width) - w - popupMargin);
translateY = (y + height + 2 * textMargin);
} else {
// Draw centre above
translateX = (x + (width / 2) - (2 * textMargin + w) / 2);
translateX = (translateX > 0 ? translateX : popupMargin);
translateX = (translateX + w < parseFloat(chart.svg.node().getBBox().width) ? translateX : parseFloat(chart.svg.node().getBBox().width) - w - popupMargin);
translateY = (y - yRunning - (h - textMargin));
}
transformer = transformPoint(translateX, translateY);
t.attr("transform", "translate(" + transformer.x + " , " + transformer.y + ")");
};