Fix product comparison + color scale on charts with lots of options (https://github.com/woocommerce/woocommerce-admin/pull/1481)

* Fix color scale on charts with lots of options

* Fix product comparison
This commit is contained in:
Justin Shreve 2019-02-06 10:46:37 -05:00 committed by GitHub
parent 43f3aba8dc
commit 81fcab5709
11 changed files with 49 additions and 31 deletions

View File

@ -31,7 +31,7 @@ class ProductsReport extends Component {
const isProductDetailsView =
'top_items' === query.filter ||
'top_sales' === query.filter ||
'single_product' === query.filter;
'compare-products' === query.filter;
const mode =
isProductDetailsView || ( isSingleProductView && isSingleProductVariable )

View File

@ -2,6 +2,8 @@
- Improves display of charts where all values are 0.
- Fix X-axis labels in hourly bar charts.
- New `<Search>` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags.
- Number of selectable chart elements is now limited to 5.
- Color scale logic for charts with lots of items has been fixed.
# 1.4.2
- Add emoji-flags dependency

View File

@ -0,0 +1,13 @@
/** @format */
// This is the max number of items that can be selected/shown on a chart at one time.
// If this number changes, the color scale also needs to be adjusted.
export const selectionLimit = 5;
export const colorScales = [
[],
[ 0.5 ],
[ 0.333, 0.667 ],
[ 0.25, 0.50, 0.75 ],
[ 0.20, 0.40, 0.60, 0.80 ],
[ 0.16, 0.32, 0.48, 0.64, 0.80 ],
];

View File

@ -116,6 +116,7 @@ class D3Chart extends Component {
const compact = this.shouldBeCompact();
const uniqueKeys = getUniqueKeys( data );
const newOrderedKeys = orderedKeys || getOrderedKeys( data, uniqueKeys );
const visibleKeys = newOrderedKeys.filter( key => key.visible );
const lineData = getLineData( data, newOrderedKeys );
const yMax = getYMax( lineData );
const yScale = getYScale( adjHeight, yMax );
@ -135,6 +136,7 @@ class D3Chart extends Component {
margin,
mode,
orderedKeys: newOrderedKeys,
visibleKeys,
parseDate,
tooltipPosition,
tooltipLabelFormat: getFormatter( tooltipLabelFormat, d3TimeFormat ),

View File

@ -2,7 +2,7 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import classNames from 'classnames';
import { Component, createRef } from '@wordpress/element';
import PropTypes from 'prop-types';
@ -12,6 +12,7 @@ import PropTypes from 'prop-types';
*/
import { getFormatter } from './utils/index';
import { getColor } from './utils/color';
import { selectionLimit } from '../constants';
/**
* A legend specifically designed for the WooCommerce admin charts.
@ -60,7 +61,9 @@ class D3Legend extends Component {
} = this.props;
const { isScrollable } = this.state;
const numberOfRowsVisible = data.filter( row => row.visible ).length;
const showTotalLabel = legendDirection === 'column' && data.length > 5 && totalLabel;
const showTotalLabel = legendDirection === 'column' && data.length > numberOfRowsVisible && totalLabel;
const visibleKeys = data.filter( key => key.visible );
return (
<div
@ -96,10 +99,13 @@ class D3Legend extends Component {
id={ row.key }
disabled={
( row.visible && numberOfRowsVisible <= 1 ) ||
( ! row.visible && numberOfRowsVisible >= 5 ) ||
( ! row.visible && numberOfRowsVisible >= selectionLimit ) ||
! interactive
}
title={ numberOfRowsVisible >= 5 ? __( 'You may select up to 5 items.', 'wc-admin' ) : '' }
title={ numberOfRowsVisible >= selectionLimit
? sprintf( __( 'You may select up to %d items.', 'wc-admin' ), selectionLimit )
: ''
}
>
<div className="woocommerce-legend__item-container" id={ row.key }>
<span
@ -107,7 +113,7 @@ class D3Legend extends Component {
'woocommerce-legend__item-checkmark-checked': row.visible,
} ) }
id={ row.key }
style={ { color: getColor( row.key, data, colorScheme ) } }
style={ { color: getColor( row.key, visibleKeys, colorScheme ) } }
/>
<span className="woocommerce-legend__item-title" id={ row.key }>
{ row.key }

View File

@ -76,7 +76,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 => getColor( d.key, params.orderedKeys, params.colorScheme ) )
.attr( 'fill', d => getColor( d.key, params.visibleKeys, params.colorScheme ) )
.attr( 'pointer-events', 'none' )
.attr( 'tabindex', '0' )
.attr( 'aria-label', d => {

View File

@ -1,25 +1,18 @@
/** @format */
/**
* Internal dependencies
*/
import { colorScales, selectionLimit } from '../../constants';
/**
* External dependencies
*/
import { findIndex } from 'lodash';
export const getColor = ( key, orderedKeys, colorScheme ) => {
const smallColorScales = [
[],
[ 0.5 ],
[ 0.333, 0.667 ],
[ 0.2, 0.5, 0.8 ],
[ 0.12, 0.375, 0.625, 0.88 ],
];
let keyValue = 0;
const len = orderedKeys.length;
const len = orderedKeys.length > selectionLimit ? selectionLimit : orderedKeys.length;
const idx = findIndex( orderedKeys, d => d.key === key );
if ( len < 5 ) {
keyValue = smallColorScales[ len ][ idx ];
} else {
keyValue = idx / ( orderedKeys.length - 1 );
}
const keyValue = idx <= ( selectionLimit - 1 ) ? colorScales[ len ][ idx ] : 0;
return colorScheme( keyValue );
};

View File

@ -43,7 +43,7 @@ export const drawLines = ( node, data, params, xOffset ) => {
.attr( 'stroke-width', lineStroke )
.attr( 'stroke-linejoin', 'round' )
.attr( 'stroke-linecap', 'round' )
.attr( 'stroke', d => getColor( d.key, params.orderedKeys, params.colorScheme ) )
.attr( 'stroke', d => getColor( d.key, params.visibleKeys, params.colorScheme ) )
.style( 'opacity', d => {
const opacity = d.focus ? 1 : 0.1;
return d.visible ? opacity : 0;
@ -59,7 +59,7 @@ export const drawLines = ( node, data, params, xOffset ) => {
.enter()
.append( 'circle' )
.attr( 'r', dotRadius )
.attr( 'fill', d => getColor( d.key, params.orderedKeys, params.colorScheme ) )
.attr( 'fill', d => getColor( d.key, params.visibleKeys, params.colorScheme ) )
.attr( 'stroke', '#fff' )
.attr( 'stroke-width', lineStroke + 1 )
.style( 'opacity', d => {
@ -112,7 +112,7 @@ export const drawLines = ( node, data, params, xOffset ) => {
.enter()
.append( 'circle' )
.attr( 'r', dotRadius + 2 )
.attr( 'fill', d => getColor( d.key, params.orderedKeys, params.colorScheme ) )
.attr( 'fill', d => getColor( d.key, params.visibleKeys, params.colorScheme ) )
.attr( 'stroke', '#fff' )
.attr( 'stroke-width', lineStroke + 2 )
.attr( 'cx', d => params.xLineScale( moment( d.date ).toDate() ) + xOffset )

View File

@ -115,13 +115,13 @@ const getTooltipRowLabel = ( d, row, params ) => {
};
export const showTooltip = ( params, d, position ) => {
const keys = params.orderedKeys.filter( row => row.visible ).map(
const keys = params.visibleKeys.map(
row => `
<li class="key-row">
<div class="key-container">
<span
class="key-color"
style="background-color:${ getColor( row.key, params.orderedKeys, params.colorScheme ) }">
style="background-color:${ getColor( row.key, params.visibleKeys, params.colorScheme ) }">
</span>
<span class="key-key">${ getTooltipRowLabel( d, row, params ) }</span>
</div>

View File

@ -24,6 +24,7 @@ import { updateQueryString } from '@woocommerce/navigation';
import ChartPlaceholder from './placeholder';
import { H, Section } from '../section';
import { D3Chart, D3Legend } from './d3chart';
import { selectionLimit } from './constants';
function getD3CurrencyFormat( symbol, position ) {
switch ( position ) {
@ -74,7 +75,7 @@ function getOrderedKeys( props, previousOrderedKeys = [] ) {
return updatedKeys.filter( key => key.total > 0 ).map( ( key, index ) => {
return {
...key,
visible: index < 5 || key.visible,
visible: index < selectionLimit || key.visible,
};
} );
}

View File

@ -142,10 +142,11 @@ class TableCard extends Component {
}
onCompare() {
// Reset selected rows so the user can start a comparison again.
this.setState( {
selectedRows: [],
} );
const { compareBy, compareParam, onQueryChange } = this.props;
const { selectedRows } = this.state;
if ( compareBy ) {
onQueryChange( 'compare' )( compareBy, compareParam, selectedRows.join( ',' ) );
}
}
onSearch( values ) {