diff --git a/package.json b/package.json index d45b5dae11fa7faedf7b2c3af0309f19561662bc..d9fc9c4f7b75cbbd2018fadd6e47df08a1e8d914 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "angularytics": "0.3.0", "crossfilter": "1.3.11", "d3": "3.5.3", + "d3-tip": "^0.6.7", "dc": "2.0.0-beta.1", "fixed-data-table": "0.2.0", "jquery": "2.1.4", diff --git a/resources/frontend_client/app/card/card.charting.js b/resources/frontend_client/app/card/card.charting.js index 3a9833d3ed22f7ebd3c489359f56590994dced2a..dcc3c03244c36455df79b9866467eaa393522f10 100644 --- a/resources/frontend_client/app/card/card.charting.js +++ b/resources/frontend_client/app/card/card.charting.js @@ -8,6 +8,9 @@ import d3 from 'd3'; import dc from 'dc'; import moment from 'moment'; +import tip from 'd3-tip'; +tip(d3); + // ---------------------------------------- TODO - Maybe. Lots of these things never worked in the first place. ---------------------------------------- // IMPORTANT // - 'titles' (tooltips) @@ -358,12 +361,31 @@ function applyChartColors(dcjsChart, card) { return dcjsChart.ordinalColors([chartColor].concat(colorList)); } -function applyChartTooltips(dcjsChart, card) { - // set the title (tooltip) function for points / bars on the chart - console.log('tip tip tip'); - return dcjsChart.title(function(d) { - var commasFormatter = d3.format(",.0f"); - return d.key + ": " + commasFormatter(d.value); +function applyChartTooltips(dcjsChart, card, cols) { + dcjsChart.renderlet(function(chart) { + // Remove old tooltips which are sometimes not removed due to chart being rerendered while tip is visible + // We should only ever have one tooltip on screen, right? + Array.prototype.forEach.call(document.querySelectorAll('.Tooltip'), (t) => t.parentNode.removeChild(t)); + + var valueFormatter = d3.format(',.0f'); + + var tip = d3.tip() + .attr('class', 'Tooltip') + .direction('n') + .offset([-10, 0]) + .html(function(d) { + return ( + '<div><span class="Tooltip-key">' + cols[0].name + '</span> <span class="Tooltip-value">' + d.data.key + '</span></div>' + + '<div><span class="Tooltip-key">' + cols[1].name + '</span> <span class="Tooltip-value">' + valueFormatter(d.data.value) + '</span></div>' + ); + }); + + chart.selectAll('rect.bar,circle.dot,g.pie-slice path,circle.bubble,g.row rect') + .call(tip) + .on('mouseover.tip', tip.show) + .on('mouseleave.tip', tip.hide); + + chart.selectAll('title').remove(); }); } @@ -824,7 +846,7 @@ export var CardRenderer = { // TODO: if we are multi-series this could be split axis applyChartYAxis(chart, card, result.cols, data, MIN_PIXELS_PER_TICK.y); - applyChartTooltips(chart, card); + applyChartTooltips(chart, card, result.cols); applyChartColors(chart, card); // if the chart supports 'brushing' (brush-based range filter), disable this since it intercepts mouse hovers which means we can't see tooltips @@ -901,7 +923,7 @@ export var CardRenderer = { // TODO: if we are multi-series this could be split axis applyChartYAxis(chart, card, result.cols, data, MIN_PIXELS_PER_TICK.y); - applyChartTooltips(chart, card); + applyChartTooltips(chart, card, result.cols); applyChartColors(chart, card); // if the chart supports 'brushing' (brush-based range filter), disable this since it intercepts mouse hovers which means we can't see tooltips diff --git a/resources/frontend_client/app/components/tooltip/tooltip.css b/resources/frontend_client/app/components/tooltip/tooltip.css new file mode 100644 index 0000000000000000000000000000000000000000..9323f19e160c367af8909b36c5c1bd708cada5e8 --- /dev/null +++ b/resources/frontend_client/app/components/tooltip/tooltip.css @@ -0,0 +1,67 @@ +/* based on https://rawgit.com/Caged/d3-tip/master/examples/example-styles.css */ + +.Tooltip { + line-height: 1; + padding: 12px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; + pointer-events: none; + border-radius: 4px; +} + +/* Creates a small triangle extender for the tooltip */ +.Tooltip: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 */ +.Tooltip.n:after { + content: "\25BC"; + margin: -1px 0 0 0; + top: 100%; + left: 0; + text-align: center; +} + +/* Eastward tooltips */ +.Tooltip.e:after { + content: "\25C0"; + margin: -4px 0 0 0; + top: 50%; + left: -8px; +} + +/* Southward tooltips */ +.Tooltip.s:after { + content: "\25B2"; + margin: 0 0 1px 0; + top: -8px; + left: 0; + text-align: center; +} + +/* Westward tooltips */ +.Tooltip.w:after { + content: "\25B6"; + margin: -4px 0 0 -1px; + top: 50%; + left: 100%; +} + +.Tooltip-key { + font-weight: bold; +} +.Tooltip-key:after { + content: ":"; +} + +.Tooltip-value { +} diff --git a/webpack.config.js b/webpack.config.js index 971839e6fb174e5e93af67ffbf2bcb8e2dc61427..a1eae0e5784cfdf9dfe9edf59869b82572a5b27f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -98,6 +98,7 @@ module.exports = { 'd3': __dirname + '/node_modules/d3/d3.min.js', 'crossfilter': __dirname + '/node_modules/crossfilter/index.js', 'dc': __dirname + '/node_modules/dc/dc.js', + 'd3-tip': __dirname + '/node_modules/d3-tip/index.js' } },