From 5669eb4b1abef539dafd4f3d35683f55a8fedbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Fri, 14 Sep 2018 14:57:09 +0200 Subject: [PATCH] Make it possible to navigate charts with the keyboard (https://github.com/woocommerce/woocommerce-admin/pull/399) * Hide tooltip when mouse leaves chart bars * Allow focus on chart lines/bars and show tooltip * Extract position calculation to a function * Make columns focusable instead of individual points in line charts --- .../client/components/chart/utils.js | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/plugins/woocommerce-admin/client/components/chart/utils.js b/plugins/woocommerce-admin/client/components/chart/utils.js index 91ed5a43c69..aaa2108cf36 100644 --- a/plugins/woocommerce-admin/client/components/chart/utils.js +++ b/plugins/woocommerce-admin/client/components/chart/utils.js @@ -13,7 +13,7 @@ import { scaleLinear as d3ScaleLinear, scaleTime as d3ScaleTime, } from 'd3-scale'; -import { mouse as d3Mouse, select as d3Select } from 'd3-selection'; +import { event as d3Event, mouse as d3Mouse, select as d3Select } from 'd3-selection'; import { line as d3Line } from 'd3-shape'; /** * Internal dependencies @@ -297,9 +297,9 @@ export const drawAxis = ( node, params ) => { .remove(); }; -const showTooltip = ( node, params, d ) => { +const showTooltip = ( node, params, d, position ) => { const chartCoords = node.node().getBoundingClientRect(); - let [ xPosition, yPosition ] = d3Mouse( node.node() ); + let [ xPosition, yPosition ] = position ? position : d3Mouse( node.node() ); xPosition = xPosition > chartCoords.width - 340 ? xPosition - 340 : xPosition + 100; yPosition = yPosition > chartCoords.height - 150 ? yPosition - 200 : yPosition + 20; const keys = params.orderedKeys.filter( row => row.visible ).map( @@ -327,25 +327,25 @@ const showTooltip = ( node, params, d ) => { ` ); }; -const handleMouseOverBarChart = ( d, i, nodes, node, data, params ) => { +const handleMouseOverBarChart = ( d, i, nodes, node, data, params, position ) => { d3Select( nodes[ i ].parentNode ) .select( '.barfocus' ) .attr( 'opacity', '0.1' ); - showTooltip( node, params, d ); + showTooltip( node, params, d, position ); }; const handleMouseOutBarChart = ( d, i, nodes, params ) => { d3Select( nodes[ i ].parentNode ) .select( '.barfocus' ) .attr( 'opacity', '0' ); - params.tooltip.style( 'display', 'flex' ); + params.tooltip.style( 'display', 'none' ); }; -const handleMouseOverLineChart = ( d, i, nodes, node, data, params ) => { +const handleMouseOverLineChart = ( d, i, nodes, node, data, params, position ) => { d3Select( nodes[ i ].parentNode ) .select( '.focus-grid' ) .attr( 'opacity', '1' ); - showTooltip( node, params, data.find( e => e.date === d.date ) ); + showTooltip( node, params, data.find( e => e.date === d.date ), position ); }; const handleMouseOutLineChart = ( d, i, nodes, params ) => { @@ -355,6 +355,12 @@ const handleMouseOutLineChart = ( d, i, nodes, params ) => { params.tooltip.style( 'display', 'none' ); }; +const calculatePositionInChart = ( element, chart ) => { + const elementCoords = element.getBoundingClientRect(); + const chartCoords = chart.getBoundingClientRect(); + return [ elementCoords.x - chartCoords.x, elementCoords.y - chartCoords.y ]; +}; + export const drawLines = ( node, data, params ) => { const series = node .append( 'g' ) @@ -424,10 +430,15 @@ export const drawLines = ( node, data, params ) => { .attr( 'width', d => d.width ) .attr( 'height', params.height ) .attr( 'opacity', 0 ) + .attr( 'tabindex', '0' ) .on( 'mouseover', ( d, i, nodes ) => handleMouseOverLineChart( d, i, nodes, node, data, params ) ) - .on( 'mouseout', ( d, i, nodes ) => handleMouseOutLineChart( d, i, nodes, params ) ); + .on( 'focus', ( d, i, nodes ) => { + const position = calculatePositionInChart( d3Event.target, node.node() ); + handleMouseOverLineChart( d, i, nodes, node, data, params, position ); + } ) + .on( 'mouseout blur', ( d, i, nodes ) => handleMouseOutLineChart( d, i, nodes, params ) ); }; export const drawBars = ( node, data, params ) => { @@ -485,8 +496,13 @@ export const drawBars = ( node, data, params ) => { .attr( 'width', params.xGroupScale.range()[ 1 ] ) .attr( 'height', params.height ) .attr( 'opacity', '0' ) + .attr( 'tabindex', '0' ) .on( 'mouseover', ( d, i, nodes ) => handleMouseOverBarChart( d, i, nodes, node, data, params ) ) - .on( 'mouseout', ( d, i, nodes ) => handleMouseOutBarChart( d, i, nodes, params ) ); + .on( 'focus', ( d, i, nodes ) => { + const position = calculatePositionInChart( d3Event.target, node.node() ); + handleMouseOverBarChart( d, i, nodes, node, data, params, position ); + } ) + .on( 'mouseout blur', ( d, i, nodes ) => handleMouseOutBarChart( d, i, nodes, params ) ); };