[heatmap] fix bug to display this view properly in dashboards. fix bug to display their d3-tip tooltips in dashboards. don't show empty tooltips on heatmap. update logic for margins so they fit dynamically based on label size. (#301)
This commit is contained in:
parent
0afa5d2cba
commit
ef64884e53
|
|
@ -1,5 +1,13 @@
|
|||
.heatmap .slice_container {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.heatmap .axis text {
|
||||
font: 10px sans-serif;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.heatmap .axis path,
|
||||
|
|
@ -30,6 +38,7 @@
|
|||
color: #fff;
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* Creates a small triangle extender for the tooltip */
|
||||
|
|
|
|||
|
|
@ -11,19 +11,15 @@ require('./heatmap.css');
|
|||
// Inspired from http://bl.ocks.org/mbostock/3074470
|
||||
// https://jsfiddle.net/cyril123/h0reyumq/
|
||||
function heatmapVis(slice) {
|
||||
var margins = {
|
||||
t: 10,
|
||||
r: 10,
|
||||
b: 50,
|
||||
l: 60
|
||||
};
|
||||
|
||||
function refresh() {
|
||||
var width = slice.width();
|
||||
var height = slice.height();
|
||||
var hmWidth = width - (margins.l + margins.r);
|
||||
var hmHeight = height - (margins.b + margins.t);
|
||||
var fp = d3.format('.3p');
|
||||
var margin = {
|
||||
top: 10,
|
||||
right: 10,
|
||||
bottom: 35,
|
||||
left: 35
|
||||
};
|
||||
|
||||
d3.json(slice.jsonEndpoint(), function (error, payload) {
|
||||
var matrix = {};
|
||||
if (error) {
|
||||
|
|
@ -33,6 +29,24 @@ function heatmapVis(slice) {
|
|||
var fd = payload.form_data;
|
||||
var data = payload.data;
|
||||
|
||||
// Dynamically adjusts based on max x / y category lengths
|
||||
function adjustMargins(data, margins) {
|
||||
var pixelsPerCharX = 4.5; // approx, depends on font size
|
||||
var pixelsPerCharY = 6.8; // approx, depends on font size
|
||||
var longestX = 1;
|
||||
var longestY = 1;
|
||||
var datum;
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
datum = data[i];
|
||||
longestX = Math.max(longestX, datum.x.length || 1);
|
||||
longestY = Math.max(longestY, datum.y.length || 1);
|
||||
}
|
||||
|
||||
margins.left = Math.ceil(Math.max(margins.left, pixelsPerCharY * longestY));
|
||||
margins.bottom = Math.ceil(Math.max(margins.bottom, pixelsPerCharX * longestX));
|
||||
}
|
||||
|
||||
function ordScale(k, rangeBands, reverse) {
|
||||
if (reverse === undefined) {
|
||||
reverse = false;
|
||||
|
|
@ -53,12 +67,20 @@ function heatmapVis(slice) {
|
|||
return d3.scale.ordinal().domain(domain).rangeBands(rangeBands);
|
||||
}
|
||||
}
|
||||
adjustMargins(data, margin);
|
||||
|
||||
var width = slice.width();
|
||||
var height = slice.height();
|
||||
var hmWidth = width - (margin.left + margin.right);
|
||||
var hmHeight = height - (margin.bottom + margin.top);
|
||||
var fp = d3.format('.3p');
|
||||
|
||||
var xScale = ordScale('x');
|
||||
var yScale = ordScale('y', undefined, true);
|
||||
var xRbScale = ordScale('x', [0, hmWidth]);
|
||||
var yRbScale = ordScale('y', [hmHeight, 0]);
|
||||
var X = 0,
|
||||
Y = 1;
|
||||
Y = 1;
|
||||
var heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];
|
||||
|
||||
var color = px.color.colorScalerFactory(fd.linear_color_scheme);
|
||||
|
|
@ -72,10 +94,7 @@ function heatmapVis(slice) {
|
|||
.range([0, hmHeight])
|
||||
];
|
||||
|
||||
var container = d3.select(slice.selector)
|
||||
.style("left", "0px")
|
||||
.style("position", "relative")
|
||||
.style("top", "0px");
|
||||
var container = d3.select(slice.selector);
|
||||
|
||||
var canvas = container.append("canvas")
|
||||
.attr("width", heatmapDim[X])
|
||||
|
|
@ -83,8 +102,8 @@ function heatmapVis(slice) {
|
|||
.style("width", hmWidth + "px")
|
||||
.style("height", hmHeight + "px")
|
||||
.style("image-rendering", fd.canvas_image_rendering)
|
||||
.style("left", margins.l + "px")
|
||||
.style("top", margins.t + "px")
|
||||
.style("left", margin.left + "px")
|
||||
.style("top", margin.top + "px")
|
||||
.style("position", "absolute");
|
||||
|
||||
var svg = container.append("svg")
|
||||
|
|
@ -95,7 +114,7 @@ function heatmapVis(slice) {
|
|||
.style("position", "absolute");
|
||||
|
||||
var rect = svg.append('g')
|
||||
.attr("transform", "translate(" + margins.l + "," + margins.t + ")")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
||||
.append('rect')
|
||||
.style('fill-opacity', 0)
|
||||
.attr('stroke', 'black')
|
||||
|
|
@ -110,18 +129,23 @@ function heatmapVis(slice) {
|
|||
return [k[1] - 20, x];
|
||||
})
|
||||
.html(function (d) {
|
||||
var s = "";
|
||||
var k = d3.mouse(this);
|
||||
var m = Math.floor(scale[0].invert(k[0]));
|
||||
var n = Math.floor(scale[1].invert(k[1]));
|
||||
if (m in matrix && n in matrix[m]) {
|
||||
var obj = matrix[m][n];
|
||||
var s = "";
|
||||
s += "<div><b>" + fd.all_columns_x + ": </b>" + obj.x + "<div>";
|
||||
s += "<div><b>" + fd.all_columns_y + ": </b>" + obj.y + "<div>";
|
||||
s += "<div><b>" + fd.metric + ": </b>" + obj.v + "<div>";
|
||||
s += "<div><b>%: </b>" + fp(obj.perc) + "<div>";
|
||||
return s;
|
||||
tip.style("display", null);
|
||||
} else {
|
||||
// this is a hack to hide the tooltip because we have map it to a single <rect>
|
||||
// d3-tip toggles opacity and calling hide here is undone by the lib after this call
|
||||
tip.style("display", "none");
|
||||
}
|
||||
return s;
|
||||
});
|
||||
|
||||
rect.call(tip);
|
||||
|
|
@ -133,6 +157,7 @@ function heatmapVis(slice) {
|
|||
return !(i % (parseInt(fd.xscale_interval, 10)));
|
||||
}))
|
||||
.orient("bottom");
|
||||
|
||||
var yAxis = d3.svg.axis()
|
||||
.scale(yRbScale)
|
||||
.tickValues(yRbScale.domain().filter(
|
||||
|
|
@ -143,16 +168,15 @@ function heatmapVis(slice) {
|
|||
|
||||
svg.append("g")
|
||||
.attr("class", "x axis")
|
||||
.attr("transform", "translate(" + margins.l + "," + (margins.t + hmHeight) + ")")
|
||||
.attr("transform", "translate(" + margin.left + "," + (margin.top + hmHeight) + ")")
|
||||
.call(xAxis)
|
||||
.selectAll("text")
|
||||
.style("text-anchor", "end")
|
||||
.attr("transform", "rotate(-45)")
|
||||
.style("font-weight", "bold");
|
||||
.attr("transform", "rotate(-45)");
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.attr("transform", "translate(" + margins.l + ", 0)")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
||||
.call(yAxis);
|
||||
|
||||
rect.on('mousemove', tip.show);
|
||||
|
|
@ -196,6 +220,7 @@ function heatmapVis(slice) {
|
|||
context.putImageData(image, 0, 0);
|
||||
imageObj.src = canvas.node().toDataURL();
|
||||
}
|
||||
|
||||
slice.done();
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class FormFactory(object):
|
|||
'Color Scheme', choices=self.choicify([
|
||||
'fire', 'blue_white_yellow', 'white_black',
|
||||
'black_white']),
|
||||
default='fire',
|
||||
default='blue_white_yellow',
|
||||
description=""),
|
||||
'normalize_across': SelectField(
|
||||
'Normalize Across', choices=self.choicify([
|
||||
|
|
|
|||
Loading…
Reference in New Issue