[big number] various improvements (#2912)

* [big number] various improvements

* dynamic number of X axis ticks based on width to prevent label overlap
* corrected overflow on the x axis
* improved tooltips (precise arrow and visible data point circle on hover)

* Fixing tooltips in heatmap viz
This commit is contained in:
Maxime Beauchemin 2017-06-08 08:50:30 -07:00 committed by GitHub
parent 0e6f754af9
commit 24a2f5b8f0
7 changed files with 107 additions and 111 deletions

View File

@ -177,7 +177,7 @@ const px = function () {
$(selector + ' div.alert').remove(); $(selector + ' div.alert').remove();
}, },
width() { width() {
return token.width(); return container.width();
}, },
height() { height() {
let others = 0; let others = 0;

View File

@ -49,7 +49,7 @@
"d3-cloud": "^1.2.1", "d3-cloud": "^1.2.1",
"d3-sankey": "^0.4.1", "d3-sankey": "^0.4.1",
"d3-scale": "^1.0.3", "d3-scale": "^1.0.3",
"d3-tip": "^0.7.1", "d3-tip": "^0.6.7",
"datamaps": "^0.5.8", "datamaps": "^0.5.8",
"datatables-bootstrap3-plugin": "^0.5.0", "datatables-bootstrap3-plugin": "^0.5.0",
"datatables.net": "^1.10.13", "datatables.net": "^1.10.13",

View File

@ -0,0 +1,56 @@
/* from d3-tip */
.d3-tip {
line-height: 1;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
pointer-events: none;
z-index: 1000;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
position: absolute;
pointer-events: none;
}
/* Northward tooltips */
.d3-tip.n:after {
content: "\25BC";
margin: -1px 0 0 0;
top: 100%;
left: 0;
text-align: center;
}
/* Eastward tooltips */
.d3-tip.e:after {
content: "\25C0";
margin: -4px 0 0 0;
top: 50%;
left: -8px;
}
/* Southward tooltips */
.d3-tip.s:after {
content: "\25B2";
margin: 0 0 1px 0;
top: -8px;
left: 0;
text-align: center;
}
/* Westward tooltips */
.d3-tip.w:after {
content: "\25B6";
margin: -4px 0 0 -1px;
top: 50%;
left: 100%;
}

View File

@ -28,12 +28,4 @@
stroke: black; stroke: black;
stroke-width: 1; stroke-width: 1;
} }
.line-tooltip {
position: absolute;
text-align: left;
padding: 10px;
background: #ffffff;
border: 1px solid #ccc;
border-radius: 2px;
pointer-events: none;
}

View File

@ -1,7 +1,9 @@
import d3 from 'd3'; import d3 from 'd3';
import d3tip from 'd3-tip';
import { formatDate } from '../javascripts/modules/dates'; import { formatDate } from '../javascripts/modules/dates';
require('./big_number.css'); import './big_number.css';
import '../stylesheets/d3tip.css';
function bigNumberVis(slice, payload) { function bigNumberVis(slice, payload) {
const div = d3.select(slice.selector); const div = d3.select(slice.selector);
@ -39,9 +41,10 @@ function bigNumberVis(slice, payload) {
const dateExt = d3.extent(data, d => d[0]); const dateExt = d3.extent(data, d => d[0]);
const valueExt = d3.extent(data, d => d[1]); const valueExt = d3.extent(data, d => d[1]);
const margin = 20; const vMargin = 20;
const scaleX = d3.time.scale.utc().domain(dateExt).range([margin, width - margin]); const hMargin = 10;
const scaleY = d3.scale.linear().domain(valueExt).range([height - (margin), margin]); const scaleX = d3.time.scale.utc().domain(dateExt).range([hMargin, width - hMargin]);
const scaleY = d3.scale.linear().domain(valueExt).range([height - (vMargin), vMargin]);
const colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)]; const colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)];
const scaleColor = d3.scale const scaleColor = d3.scale
.linear().domain([-1, 1]) .linear().domain([-1, 1])
@ -126,17 +129,18 @@ function bigNumberVis(slice, payload) {
const xAxis = d3.svg.axis() const xAxis = d3.svg.axis()
.scale(scaleX) .scale(scaleX)
.orient('bottom') .orient('bottom')
.ticks(4) .ticks(Math.round(2 + (width / 150)))
.tickFormat(formatDate); .tickFormat(formatDate);
g.call(xAxis); g.call(xAxis);
g.attr('transform', 'translate(0,' + (height - margin) + ')'); g.attr('transform', 'translate(0,' + (height - vMargin) + ')');
g = gAxis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)'); g = gAxis.append('g').attr('transform', 'translate(' + (width - hMargin) + ',0)');
const yAxis = d3.svg.axis() const yAxis = d3.svg.axis()
.scale(scaleY) .scale(scaleY)
.orient('left') .orient('left')
.tickFormat(d3.format(fd.y_axis_format)) .tickFormat(d3.format(fd.y_axis_format))
.tickValues(valueExt); .tickValues(valueExt);
g.call(yAxis); g.call(yAxis);
g.selectAll('text') g.selectAll('text')
.style('text-anchor', 'end') .style('text-anchor', 'end')
@ -146,44 +150,44 @@ function bigNumberVis(slice, payload) {
g.selectAll('text') g.selectAll('text')
.style('font-size', '10px'); .style('font-size', '10px');
// Define the div for the tooltip
const tooltipEl =
d3.select('body')
.append('div')
.attr('class', 'line-tooltip')
.attr('width', 200)
.attr('height', 200)
.style('opacity', 0);
const renderTooltip = (d) => { const renderTooltip = (d) => {
const date = formatDate(d[0]); const date = formatDate(d[0]);
const value = f(d[1]); const value = f(d[1]);
return ` return `
<div> <div>
<span style="float: left; margin-right: 20px;"><strong>${date}</strong></span> <span style="margin-right: 10px;">${date}: </span>
<span style="float: right">${value}</span> <strong>${value}</strong>
</div> </div>
`; `;
}; };
const tip = d3tip()
.attr('class', 'd3-tip')
.direction('n')
.offset([-5, 0])
.html(renderTooltip);
svg.call(tip);
// Add the scatterplot and trigger the mouse events for the tooltips // Add the scatterplot and trigger the mouse events for the tooltips
svg svg
.selectAll('dot') .selectAll('dot')
.data(data) .data(data)
.enter() .enter()
.append('circle') .append('circle')
.attr('r', 10) .attr('r', 3)
.attr('stroke-width', 15)
.attr('stroke', 'transparent')
.attr('stroke-location', 'outside')
.attr('cx', d => scaleX(d[0])) .attr('cx', d => scaleX(d[0]))
.attr('cy', d => scaleY(d[1])) .attr('cy', d => scaleY(d[1]))
.attr('fill-opacity', '0') .attr('fill-opacity', 0)
.on('mouseover', (d) => { .on('mouseover', function (d) {
tooltipEl.html(renderTooltip(d)) d3.select(this).attr('fill-opacity', 1);
.style('left', (d3.event.pageX) + 'px') tip.show(d);
.style('top', (d3.event.pageY) + 'px');
tooltipEl.transition().duration(200).style('opacity', 0.9);
}) })
.on('mouseout', () => { .on('mouseout', function (d) {
tooltipEl.transition().duration(500).style('opacity', 0); d3.select(this).attr('fill-opacity', 0);
tip.hide(d);
}); });
div.on('mouseover', function () { div.on('mouseover', function () {

View File

@ -28,61 +28,3 @@
image-rendering: pixelated; /* Awesome future-browsers */ image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */ -ms-interpolation-mode: nearest-neighbor; /* IE */
} }
/* from d3-tip */
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
pointer-events: none;
z-index: 1000;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
position: absolute;
pointer-events: none;
}
/* Northward tooltips */
.d3-tip.n:after {
content: "\25BC";
margin: -1px 0 0 0;
top: 100%;
left: 0;
text-align: center;
}
/* Eastward tooltips */
.d3-tip.e:after {
content: "\25C0";
margin: -4px 0 0 0;
top: 50%;
left: -8px;
}
/* Southward tooltips */
.d3-tip.s:after {
content: "\25B2";
margin: 0 0 1px 0;
top: -8px;
left: 0;
text-align: center;
}
/* Westward tooltips */
.d3-tip.w:after {
content: "\25B6";
margin: -4px 0 0 -1px;
top: 50%;
left: 100%;
}

View File

@ -1,10 +1,11 @@
import d3 from 'd3'; import d3 from 'd3';
import $ from 'jquery';
import d3tip from 'd3-tip';
import { colorScalerFactory } from '../javascripts/modules/colors'; import { colorScalerFactory } from '../javascripts/modules/colors';
import '../stylesheets/d3tip.css';
import './heatmap.css';
const $ = require('jquery');
d3.tip = require('d3-tip');
require('./heatmap.css');
// Inspired from http://bl.ocks.org/mbostock/3074470 // Inspired from http://bl.ocks.org/mbostock/3074470
// https://jsfiddle.net/cyril123/h0reyumq/ // https://jsfiddle.net/cyril123/h0reyumq/
@ -105,15 +106,7 @@ function heatmapVis(slice, payload) {
.style('top', headerHeight + 'px') .style('top', headerHeight + 'px')
.style('position', 'absolute'); .style('position', 'absolute');
const rect = svg.append('g') const tip = d3tip()
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.append('rect')
.style('fill-opacity', 0)
.attr('stroke', 'black')
.attr('width', hmWidth)
.attr('height', hmHeight);
const tip = d3.tip()
.attr('class', 'd3-tip') .attr('class', 'd3-tip')
.offset(function () { .offset(function () {
const k = d3.mouse(this); const k = d3.mouse(this);
@ -140,6 +133,17 @@ function heatmapVis(slice, payload) {
return s; return s;
}); });
const rect = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.append('rect')
.attr('pointer-events', 'all')
.on('mousemove', tip.show)
.on('mouseout', tip.hide)
.style('fill-opacity', 0)
.attr('stroke', 'black')
.attr('width', hmWidth)
.attr('height', hmHeight);
rect.call(tip); rect.call(tip);
const xAxis = d3.svg.axis() const xAxis = d3.svg.axis()
@ -171,8 +175,6 @@ function heatmapVis(slice, payload) {
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(yAxis); .call(yAxis);
rect.on('mousemove', tip.show);
rect.on('mouseout', tip.hide);
const context = canvas.node().getContext('2d'); const context = canvas.node().getContext('2d');
context.imageSmoothingEnabled = false; context.imageSmoothingEnabled = false;