diff --git a/plugins/woocommerce-admin/client/components/chart/charts.js b/plugins/woocommerce-admin/client/components/chart/charts.js index 44bb2dd6bc2..64dea44550c 100644 --- a/plugins/woocommerce-admin/client/components/chart/charts.js +++ b/plugins/woocommerce-admin/client/components/chart/charts.js @@ -3,16 +3,13 @@ /** * External dependencies */ - +import { isEqual } from 'lodash'; import { Component, createRef } from '@wordpress/element'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { findIndex, isEqual } from 'lodash'; import { format as d3Format } from 'd3-format'; import { timeFormat as d3TimeFormat } from 'd3-time-format'; import { select as d3Select } from 'd3-selection'; -import { range as d3Range } from 'd3-array'; -import { scaleOrdinal as d3ScaleOrdinal } from 'd3-scale'; /** * Internal dependencies @@ -68,8 +65,7 @@ class D3Chart extends Component { } drawChart = ( node, params ) => { - const { margin, type } = this.props; - const { data } = this.state; + const { data, margin, type } = this.props; const g = node .attr( 'id', 'chart' ) .append( 'g' ) @@ -80,7 +76,6 @@ class D3Chart extends Component { width: params.width - margin.left - margin.right, tooltip: d3Select( this.tooltipRef.current ), } ); - drawAxis( g, adjParams ); type === 'line' && drawLines( g, data, adjParams ); type === 'bar' && drawBars( g, data, adjParams ); @@ -89,7 +84,7 @@ class D3Chart extends Component { }; getParams = node => { - const { data, height, margin, orderedKeys, type, xFormat, yFormat } = this.props; + const { colorScheme, data, height, margin, orderedKeys, type, xFormat, yFormat } = this.props; const { width } = this.state; const calculatedWidth = width || node.offsetWidth; const calculatedHeight = height || node.offsetHeight; @@ -104,14 +99,11 @@ class D3Chart extends Component { const uniqueDates = getUniqueDates( lineData ); const xLineScale = getXLineScale( uniqueDates, adjWidth ); const xScale = getXScale( uniqueDates, adjWidth ); - const colorScale = d3ScaleOrdinal().range( - d3Range( 0, 1.1, 100 / ( newOrderedKeys.length - 1 ) / 100 ) - ); return { - colorScale: key => colorScale( findIndex( orderedKeys, d => d.key === key ) ), + colorScheme, dateSpaces: getDateSpaces( uniqueDates, adjWidth, xLineScale ), height: calculatedHeight, - line: getLine( data, xLineScale, yScale ), + line: getLine( xLineScale, yScale ), lineData, margin, orderedKeys: newOrderedKeys, @@ -154,6 +146,7 @@ class D3Chart extends Component { } D3Chart.propTypes = { + colorScheme: PropTypes.func, className: PropTypes.string, data: PropTypes.array.isRequired, height: PropTypes.number, diff --git a/plugins/woocommerce-admin/client/components/chart/index.js b/plugins/woocommerce-admin/client/components/chart/index.js index 45fc0a5e51c..04141c60f49 100644 --- a/plugins/woocommerce-admin/client/components/chart/index.js +++ b/plugins/woocommerce-admin/client/components/chart/index.js @@ -6,6 +6,7 @@ import classNames from 'classnames'; import { isEqual } from 'lodash'; import { Component, createRef } from '@wordpress/element'; import PropTypes from 'prop-types'; +import { interpolateViridis as d3InterpolateViridis } from 'd3-scale-chromatic'; /** * Internal dependencies @@ -122,6 +123,7 @@ class Chart extends Component { const legend = ( { width > WIDE_BREAKPOINT && legendDirection === 'column' && legend } - { data.map( ( row, i ) => ( + { data.map( row => (
  • { row.key } @@ -63,6 +70,7 @@ class Legend extends Component { Legend.propTypes = { className: PropTypes.string, + colorScheme: PropTypes.func, data: PropTypes.array.isRequired, handleLegendToggle: PropTypes.func, handleLegendHover: PropTypes.func, diff --git a/plugins/woocommerce-admin/client/components/chart/utils.js b/plugins/woocommerce-admin/client/components/chart/utils.js index 822121b87f9..fc2ef9f6782 100644 --- a/plugins/woocommerce-admin/client/components/chart/utils.js +++ b/plugins/woocommerce-admin/client/components/chart/utils.js @@ -4,6 +4,7 @@ * External dependencies */ +import { findIndex } from 'lodash'; import { max as d3Max } from 'd3-array'; import { axisBottom as d3AxisBottom, axisLeft as d3AxisLeft } from 'd3-axis'; import { format as d3Format } from 'd3-format'; @@ -14,7 +15,6 @@ import { } from 'd3-scale'; import { mouse as d3Mouse, select as d3Select } from 'd3-selection'; import { line as d3Line } from 'd3-shape'; -import { interpolateViridis as d3InterpolateViridis } from 'd3-scale-chromatic'; import { timeFormat as d3TimeFormat, utcParse as d3UTCParse } from 'd3-time-format'; export const parseDate = d3UTCParse( '%Y-%m-%d' ); @@ -86,6 +86,14 @@ export const getUniqueDates = lineData => { ].sort( ( a, b ) => parseDate( a ) - parseDate( b ) ); }; +export const getColor = ( key, params ) => { + const keyValue = + params.orderedKeys.length > 1 + ? findIndex( params.orderedKeys, d => d.key === key ) / ( params.orderedKeys.length - 1 ) + : 0; + return params.colorScheme( keyValue ); +}; + /** * Describes getXScale * @param {array} uniqueDates - from `getUniqueDates` @@ -106,7 +114,7 @@ export const getXScale = ( uniqueDates, width ) => */ export const getXGroupScale = ( orderedKeys, xScale ) => d3ScaleBand() - .domain( orderedKeys.map( d => d.key ) ) + .domain( orderedKeys.filter( d => d.visible ).map( d => d.key ) ) .rangeRound( [ 0, xScale.bandwidth() ] ) .padding( 0.07 ); @@ -154,12 +162,11 @@ export const getYTickOffset = ( height, scale, yMax ) => /** * Describes getyTickOffset - * @param {array} data - The chart component's `data` prop. * @param {function} xLineScale - from `getXLineScale`. * @param {function} yScale - from `getYScale`. * @returns {function} the D3 line function for plotting all category values */ -export const getLine = ( data, xLineScale, yScale ) => +export const getLine = ( xLineScale, yScale ) => d3Line() .x( d => xLineScale( new Date( d.date ) ) ) .y( d => yScale( d.value ) ); @@ -248,16 +255,14 @@ const showTooltip = ( node, params, d ) => { let [ xPosition, yPosition ] = d3Mouse( node.node() ); xPosition = xPosition > chartCoords.width - 200 ? xPosition - 200 : xPosition + 20; yPosition = yPosition > chartCoords.height - 150 ? yPosition - 200 : yPosition + 20; - const keys = params.orderedKeys.map( + const keys = params.orderedKeys.filter( row => row.visible ).map( row => ` -
  • - - ${ row.key }: - ${ d3Format( ',.0f' )( d[ row.key ] ) } -
  • - ` +
  • + + ${ row.key }: + ${ d3Format( ',.0f' )( d[ row.key ] ) } +
  • + ` ); params.tooltip @@ -337,7 +342,7 @@ export const drawLines = ( node, data, params ) => { .append( 'g' ) .attr( 'class', 'lines' ) .selectAll( '.line-g' ) - .data( params.lineData ) + .data( params.lineData.filter( d => d.visible ) ) .enter() .append( 'g' ) .attr( 'class', 'line-g' ); @@ -348,7 +353,7 @@ export const drawLines = ( node, data, params ) => { .attr( 'stroke-width', 3 ) .attr( 'stroke-linejoin', 'round' ) .attr( 'stroke-linecap', 'round' ) - .attr( 'stroke', d => d3InterpolateViridis( params.colorScale( d.key ) ) ) + .attr( 'stroke', d => getColor( d.key, params ) ) .style( 'opacity', d => { const opacity = d.focus ? 1 : 0.1; return d.visible ? opacity : 0; @@ -362,7 +367,7 @@ export const drawLines = ( node, data, params ) => { .append( 'circle' ) .attr( 'r', 3.5 ) .attr( 'fill', '#fff' ) - .attr( 'stroke', d => d3InterpolateViridis( params.colorScale( d.key ) ) ) + .attr( 'stroke', d => getColor( d.key, params ) ) .attr( 'stroke-width', 3 ) .style( 'opacity', d => { const opacity = d.focus ? 1 : 0.1; @@ -395,7 +400,7 @@ export const drawBars = ( node, data, params ) => { barGroup .selectAll( '.bar' ) .data( d => - params.orderedKeys.map( row => ( { + params.orderedKeys.filter( row => row.visible ).map( row => ( { key: row.key, focus: row.focus, value: d[ row.key ], @@ -409,7 +414,7 @@ export const drawBars = ( node, data, params ) => { .attr( 'y', d => params.yScale( d.value ) ) .attr( 'width', params.xGroupScale.bandwidth() ) .attr( 'height', d => params.height - params.yScale( d.value ) ) - .attr( 'fill', d => d3InterpolateViridis( params.colorScale( d.key ) ) ) + .attr( 'fill', d => getColor( d.key, params ) ) .style( 'opacity', d => { const opacity = d.focus ? 1 : 0.1; return d.visible ? opacity : 0;