diff --git a/ui/app/components/http-requests-bar-chart.js b/ui/app/components/http-requests-bar-chart.js index 35328ac98b..d53fb21e5c 100644 --- a/ui/app/components/http-requests-bar-chart.js +++ b/ui/app/components/http-requests-bar-chart.js @@ -3,6 +3,7 @@ import d3 from 'd3-selection'; import d3Scale from 'd3-scale'; import d3Axis from 'd3-axis'; import d3TimeFormat from 'd3-time-format'; +import d3Tip from 'd3-tip'; import { assign } from '@ember/polyfills'; import { computed } from '@ember/object'; import { run } from '@ember/runloop'; @@ -27,13 +28,12 @@ import { task, waitForEvent } from 'ember-concurrency'; */ const HEIGHT = 240; +const HOVER_PADDING = 12; export default Component.extend({ classNames: ['http-requests-bar-chart-container'], counters: null, - - /* eslint-disable ember/avoid-leaking-state-in-ember-objects */ - margin: { top: 24, right: 16, bottom: 24, left: 16 }, + margin: Object.freeze({ top: 24, right: 16, bottom: 24, left: 16 }), padding: 0.04, width: 0, height() { @@ -84,10 +84,24 @@ export default Component.extend({ }, renderBarChart() { - const { margin, width, xScale, yScale, parsedCounters } = this; + const { margin, width, xScale, yScale, parsedCounters, elementId } = this; const height = this.height(); const barChartSVG = d3.select('.http-requests-bar-chart'); - const barsContainer = d3.select('#bars-container'); + const barsContainer = d3.select(`#bars-container-${elementId}`); + + // initialize the tooltip + const tip = d3Tip() + .attr('class', 'd3-tooltip') + .offset([HOVER_PADDING / 2, 0]) + .html(function(d) { + const formatter = d3TimeFormat.utcFormat('%B %Y'); + return ` +
${formatter(d.start_time)}
+${Intl.NumberFormat().format(d.total)} Requests
+ `; + }); + + barChartSVG.call(tip); // render the chart d3.select('.http-requests-bar-chart') @@ -127,8 +141,6 @@ export default Component.extend({ // render the bars const bars = barsContainer.selectAll('.bar').data(parsedCounters, c => +c.start_time); - bars.exit().remove(); - const barsEnter = bars .enter() .append('rect') @@ -138,9 +150,35 @@ export default Component.extend({ .merge(barsEnter) .attr('width', xScale.bandwidth()) .attr('height', counter => height - yScale(counter.total)) - // the offset between each bar .attr('x', counter => xScale(counter.start_time)) .attr('y', counter => yScale(counter.total)); + + bars.exit().remove(); + + // render transparent bars and bind the tooltip to them since we cannot + // bind the tooltip to the actual bars. this is because the bars are + // within a clipPath & you cannot bind DOM events to non-display elements. + const shadowBarsContainer = d3.select('.shadow-bars'); + + const shadowBars = shadowBarsContainer.selectAll('.bar').data(parsedCounters, c => +c.start_time); + + const shadowBarsEnter = shadowBars + .enter() + .append('rect') + .attr('class', 'bar') + .on('mouseenter', tip.show) + .on('mouseleave', tip.hide); + + shadowBars + .merge(shadowBarsEnter) + .attr('width', xScale.bandwidth()) + .attr('height', counter => height - yScale(counter.total) + HOVER_PADDING) + .attr('x', counter => xScale(counter.start_time)) + .attr('y', counter => yScale(counter.total) - HOVER_PADDING) + .attr('fill', 'transparent') + .attr('stroke', 'transparent'); + + shadowBars.exit().remove(); }, updateDimensions() { diff --git a/ui/app/styles/components/http-requests-bar-chart.scss b/ui/app/styles/components/http-requests-bar-chart.scss index d2dded3e06..2c62196684 100644 --- a/ui/app/styles/components/http-requests-bar-chart.scss +++ b/ui/app/styles/components/http-requests-bar-chart.scss @@ -37,3 +37,30 @@ } } } + +.d3-tooltip { + line-height: 1.25; + padding: $spacing-s; + background: $grey; + color: $ui-gray-010; + border-radius: 2px; +} + +/* Creates a small triangle extender for the tooltip */ +.d3-tooltip::after { + box-sizing: border-box; + display: inline; + font-size: 10px; + width: 100%; + color: $grey; + content: '\25BC'; + position: absolute; + text-align: center; +} + +/* Style northward tooltips differently */ +.d3-tooltip.n::after { + margin-top: -4px; + top: 100%; + left: 0; +} diff --git a/ui/app/templates/components/http-requests-bar-chart.hbs b/ui/app/templates/components/http-requests-bar-chart.hbs index 583b8e73aa..59458a68bd 100644 --- a/ui/app/templates/components/http-requests-bar-chart.hbs +++ b/ui/app/templates/components/http-requests-bar-chart.hbs @@ -10,9 +10,10 @@