From dbf0a8d16969e0737fb226191ab8e2ccb4d81c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Fri, 5 Apr 2019 11:01:12 +0200 Subject: [PATCH] Split D3Chart utils axis file (https://github.com/woocommerce/woocommerce-admin/pull/2000) --- .../src/chart/d3chart/utils/axis-x.js | 226 ++++++++++++++ .../src/chart/d3chart/utils/axis-y.js | 76 +++++ .../src/chart/d3chart/utils/axis.js | 293 +----------------- .../d3chart/utils/test/{axis.js => axis-x.js} | 58 +--- .../src/chart/d3chart/utils/test/axis-y.js | 65 ++++ 5 files changed, 370 insertions(+), 348 deletions(-) create mode 100644 plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-x.js create mode 100644 plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-y.js rename plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/{axis.js => axis-x.js} (74%) create mode 100644 plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-y.js diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-x.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-x.js new file mode 100644 index 00000000000..06a16ec0723 --- /dev/null +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-x.js @@ -0,0 +1,226 @@ +/** @format */ + +/** + * External dependencies + */ +import { axisBottom as d3AxisBottom } from 'd3-axis'; +import { smallBreak, wideBreak } from './breakpoints'; +import moment from 'moment'; + +const dayTicksThreshold = 63; +const weekTicksThreshold = 9; +const mediumBreak = 1130; +const smallPoints = 7; +const mediumPoints = 12; +const largePoints = 16; +const mostPoints = 31; + +/** + * Calculate the maximum number of ticks allowed in the x-axis based on the width and mode of the chart + * @param {integer} width - calculated page width + * @param {string} mode - item-comparison or time-comparison + * @returns {integer} number of x-axis ticks based on width and chart mode + */ +const calculateMaxXTicks = ( width, mode ) => { + if ( width < smallBreak ) { + return smallPoints; + } else if ( width >= smallBreak && width <= mediumBreak ) { + return mediumPoints; + } else if ( width > mediumBreak && width <= wideBreak ) { + if ( mode === 'time-comparison' ) { + return largePoints; + } else if ( mode === 'item-comparison' ) { + return mediumPoints; + } + } else if ( width > wideBreak ) { + if ( mode === 'time-comparison' ) { + return mostPoints; + } else if ( mode === 'item-comparison' ) { + return largePoints; + } + } + + return largePoints; +}; + +/** +* Filter out irrelevant dates so only the first date of each month is kept. +* @param {array} dates - string dates. +* @returns {array} Filtered dates. +*/ +const getFirstDatePerMonth = dates => { + return dates.filter( + ( date, i ) => i === 0 || moment( date ).toDate().getMonth() !== moment( dates[ i - 1 ] ).toDate().getMonth() + ); +}; + +/** + * Given an array of dates, returns true if the first and last one belong to the same day. + * @param {array} dates - an array of dates + * @returns {boolean} whether the first and last date are different hours from the same date. + */ +const areDatesInTheSameDay = dates => { + const firstDate = moment( dates [ 0 ] ).toDate(); + const lastDate = moment( dates [ dates.length - 1 ] ).toDate(); + return ( + firstDate.getDate() === lastDate.getDate() && + firstDate.getMonth() === lastDate.getMonth() && + firstDate.getFullYear() === lastDate.getFullYear() + ); +}; + +/** +* Describes `smallestFactor` +* @param {number} inputNum - any double or integer +* @returns {integer} smallest factor of num +*/ +const getFactors = inputNum => { + const numFactors = []; + for ( let i = 1; i <= Math.floor( Math.sqrt( inputNum ) ); i++ ) { + if ( inputNum % i === 0 ) { + numFactors.push( i ); + inputNum / i !== i && numFactors.push( inputNum / i ); + } + } + numFactors.sort( ( x, y ) => x - y ); // numeric sort + + return numFactors; +}; + +/** + * Calculates the increment factor between ticks so there aren't more than maxTicks. + * @param {array} uniqueDates - all the unique dates from the input data for the chart + * @param {integer} maxTicks - maximum number of ticks that can be displayed in the x-axis + * @returns {integer} x-axis ticks increment factor + */ +const calculateXTicksIncrementFactor = ( uniqueDates, maxTicks ) => { + let factors = []; + let i = 1; + // First we get all the factors of the length of the uniqueDates array + // if the number is a prime number or near prime (with 3 factors) then we + // step down by 1 integer and try again. + while ( factors.length <= 3 ) { + factors = getFactors( uniqueDates.length - i ); + i += 1; + } + + return factors.find( f => uniqueDates.length / f < maxTicks ); +}; + +/** + * Get x-axis ticks given the unique dates and the increment factor. + * @param {array} uniqueDates - all the unique dates from the input data for the chart + * @param {integer} incrementFactor - increment factor for the visible ticks. + * @returns {array} Ticks for the x-axis. + */ +const getXTicksFromIncrementFactor = ( uniqueDates, incrementFactor ) => { + const ticks = []; + + for ( let idx = 0; idx < uniqueDates.length; idx = idx + incrementFactor ) { + ticks.push( uniqueDates[ idx ] ); + } + + // If the first date is missing from the ticks array, add it back in. + if ( ticks[ 0 ] !== uniqueDates[ 0 ] ) { + ticks.unshift( uniqueDates[ 0 ] ); + } + + return ticks; +}; + +/** + * Returns ticks for the x-axis. + * @param {array} uniqueDates - all the unique dates from the input data for the chart + * @param {integer} width - calculated page width + * @param {string} mode - item-comparison or time-comparison + * @param {string} interval - string of the interval used in the graph (hour, day, week...) + * @returns {integer} number of x-axis ticks based on width and chart mode + */ +export const getXTicks = ( uniqueDates, width, mode, interval ) => { + const maxTicks = calculateMaxXTicks( width, mode ); + + if ( + ( uniqueDates.length >= dayTicksThreshold && interval === 'day' ) || + ( uniqueDates.length >= weekTicksThreshold && interval === 'week' ) + ) { + uniqueDates = getFirstDatePerMonth( uniqueDates ); + } + if ( uniqueDates.length <= maxTicks || + ( interval === 'hour' && areDatesInTheSameDay( uniqueDates ) && width > smallBreak ) ) { + return uniqueDates; + } + + const incrementFactor = calculateXTicksIncrementFactor( uniqueDates, maxTicks ); + + return getXTicksFromIncrementFactor( uniqueDates, incrementFactor ); +}; + +/** +* Compares 2 strings and returns a list of words that are unique from s2 +* @param {string} s1 - base string to compare against +* @param {string} s2 - string to compare against the base string +* @param {string|Object} splitChar - character or RegExp to use to deliminate words +* @returns {array} of unique words that appear in s2 but not in s1, the base string +*/ +export const compareStrings = ( s1, s2, splitChar = new RegExp( [ ' |,' ], 'g' ) ) => { + const string1 = s1.split( splitChar ); + const string2 = s2.split( splitChar ); + const diff = new Array(); + const long = s1.length > s2.length ? string1 : string2; + for ( let x = 0; x < long.length; x++ ) { + string1[ x ] !== string2[ x ] && diff.push( string2[ x ] ); + } + return diff; +}; + +const removeDuplicateDates = ( d, i, ticks, formatter ) => { + const monthDate = moment( d ).toDate(); + let prevMonth = i !== 0 ? ticks[ i - 1 ] : ticks[ i ]; + prevMonth = prevMonth instanceof Date ? prevMonth : moment( prevMonth ).toDate(); + return i === 0 + ? formatter( monthDate ) + : compareStrings( formatter( prevMonth ), formatter( monthDate ) ).join( ' ' ); +}; + +export const drawXAxis = ( node, params, scales, formats ) => { + const height = scales.yScale.range()[ 0 ]; + let ticks = getXTicks( params.uniqueDates, scales.xScale.range()[ 1 ], params.mode, params.interval ); + if ( params.chartType === 'line' ) { + ticks = ticks.map( d => moment( d ).toDate() ); + } + + node + .append( 'g' ) + .attr( 'class', 'axis' ) + .attr( 'aria-hidden', 'true' ) + .attr( 'transform', `translate(0, ${ height })` ) + .call( + d3AxisBottom( scales.xScale ) + .tickValues( ticks ) + .tickFormat( ( d, i ) => params.interval === 'hour' + ? formats.xFormat( d instanceof Date ? d : moment( d ).toDate() ) + : removeDuplicateDates( d, i, ticks, formats.xFormat ) ) + ); + + node + .append( 'g' ) + .attr( 'class', 'axis axis-month' ) + .attr( 'aria-hidden', 'true' ) + .attr( 'transform', `translate(0, ${ height + 14 })` ) + .call( + d3AxisBottom( scales.xScale ) + .tickValues( ticks ) + .tickFormat( ( d, i ) => removeDuplicateDates( d, i, ticks, formats.x2Format ) ) + ); + + node + .append( 'g' ) + .attr( 'class', 'pipes' ) + .attr( 'transform', `translate(0, ${ height })` ) + .call( + d3AxisBottom( scales.xScale ) + .tickValues( ticks ) + .tickSize( 5 ) + .tickFormat( '' ) + ); +}; diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-y.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-y.js new file mode 100644 index 00000000000..fd6230818b3 --- /dev/null +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis-y.js @@ -0,0 +1,76 @@ +/** @format */ + +/** + * External dependencies + */ +import { axisLeft as d3AxisLeft } from 'd3-axis'; + +const calculateYGridValues = ( numberOfTicks, limit, roundValues ) => { + const grids = []; + + for ( let i = 0; i < numberOfTicks; i++ ) { + const val = ( i + 1 ) / numberOfTicks * limit; + const rVal = roundValues ? Math.round( val ) : val; + if ( grids[ grids.length - 1 ] !== rVal ) { + grids.push( rVal ); + } + } + + return grids; +}; + +const getNegativeYGrids = ( yMin, step ) => { + if ( yMin >= 0 ) { + return []; + } + + const numberOfTicks = Math.ceil( -yMin / step ); + return calculateYGridValues( numberOfTicks, yMin, yMin < -1 ); +}; + +const getPositiveYGrids = ( yMax, step ) => { + if ( yMax <= 0 ) { + return []; + } + + const numberOfTicks = Math.ceil( yMax / step ); + return calculateYGridValues( numberOfTicks, yMax, yMax > 1 ); +}; + +export const getYGrids = ( yMin, yMax, step ) => { + return [ + 0, + ...getNegativeYGrids( yMin, step ), + ...getPositiveYGrids( yMax, step ), + ]; +}; + +export const drawYAxis = ( node, scales, formats, margin, isRTL ) => { + const yGrids = getYGrids( scales.yScale.domain()[ 0 ], scales.yScale.domain()[ 1 ], scales.step ); + const width = scales.xScale.range()[ 1 ]; + const xPosition = isRTL ? width + margin.left + margin.right / 2 - 15 : -margin.left / 2 - 15; + + const withPositiveValuesClass = scales.yMin >= 0 || scales.yMax > 0 ? ' with-positive-ticks' : ''; + node + .append( 'g' ) + .attr( 'class', 'grid' + withPositiveValuesClass ) + .attr( 'transform', `translate(-${ margin.left }, 0)` ) + .call( + d3AxisLeft( scales.yScale ) + .tickValues( yGrids ) + .tickSize( -width - margin.left - margin.right ) + .tickFormat( '' ) + ); + + node + .append( 'g' ) + .attr( 'class', 'axis y-axis' ) + .attr( 'aria-hidden', 'true' ) + .attr( 'transform', 'translate(' + xPosition + ', 12)' ) + .attr( 'text-anchor', 'start' ) + .call( + d3AxisLeft( scales.yScale ) + .tickValues( scales.yMax === 0 && scales.yMin === 0 ? [ yGrids[ 0 ] ] : yGrids ) + .tickFormat( d => formats.yFormat( d !== 0 ? d : 0 ) ) + ); +}; diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js index a76506246fe..d10a92f8465 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js @@ -3,297 +3,8 @@ /** * External dependencies */ -import { axisBottom as d3AxisBottom, axisLeft as d3AxisLeft } from 'd3-axis'; -import { smallBreak, wideBreak } from './breakpoints'; -import moment from 'moment'; - -const dayTicksThreshold = 63; -const weekTicksThreshold = 9; -const mediumBreak = 1130; -const smallPoints = 7; -const mediumPoints = 12; -const largePoints = 16; -const mostPoints = 31; - -/** -* Describes `smallestFactor` -* @param {number} inputNum - any double or integer -* @returns {integer} smallest factor of num -*/ -const getFactors = inputNum => { - const numFactors = []; - for ( let i = 1; i <= Math.floor( Math.sqrt( inputNum ) ); i++ ) { - if ( inputNum % i === 0 ) { - numFactors.push( i ); - inputNum / i !== i && numFactors.push( inputNum / i ); - } - } - numFactors.sort( ( x, y ) => x - y ); // numeric sort - - return numFactors; -}; - -/** - * Calculate the maximum number of ticks allowed in the x-axis based on the width and mode of the chart - * @param {integer} width - calculated page width - * @param {string} mode - item-comparison or time-comparison - * @returns {integer} number of x-axis ticks based on width and chart mode - */ -const calculateMaxXTicks = ( width, mode ) => { - if ( width < smallBreak ) { - return smallPoints; - } else if ( width >= smallBreak && width <= mediumBreak ) { - return mediumPoints; - } else if ( width > mediumBreak && width <= wideBreak ) { - if ( mode === 'time-comparison' ) { - return largePoints; - } else if ( mode === 'item-comparison' ) { - return mediumPoints; - } - } else if ( width > wideBreak ) { - if ( mode === 'time-comparison' ) { - return mostPoints; - } else if ( mode === 'item-comparison' ) { - return largePoints; - } - } - - return largePoints; -}; - -/** - * Get x-axis ticks given the unique dates and the increment factor. - * @param {array} uniqueDates - all the unique dates from the input data for the chart - * @param {integer} incrementFactor - increment factor for the visible ticks. - * @returns {array} Ticks for the x-axis. - */ -const getXTicksFromIncrementFactor = ( uniqueDates, incrementFactor ) => { - const ticks = []; - - for ( let idx = 0; idx < uniqueDates.length; idx = idx + incrementFactor ) { - ticks.push( uniqueDates[ idx ] ); - } - - // If the first date is missing from the ticks array, add it back in. - if ( ticks[ 0 ] !== uniqueDates[ 0 ] ) { - ticks.unshift( uniqueDates[ 0 ] ); - } - - return ticks; -}; - -/** - * Calculates the increment factor between ticks so there aren't more than maxTicks. - * @param {array} uniqueDates - all the unique dates from the input data for the chart - * @param {integer} maxTicks - maximum number of ticks that can be displayed in the x-axis - * @returns {integer} x-axis ticks increment factor - */ -const calculateXTicksIncrementFactor = ( uniqueDates, maxTicks ) => { - let factors = []; - let i = 1; - // First we get all the factors of the length of the uniqueDates array - // if the number is a prime number or near prime (with 3 factors) then we - // step down by 1 integer and try again. - while ( factors.length <= 3 ) { - factors = getFactors( uniqueDates.length - i ); - i += 1; - } - - return factors.find( f => uniqueDates.length / f < maxTicks ); -}; - -/** - * Given an array of dates, returns true if the first and last one belong to the same day. - * @param {array} dates - an array of dates - * @returns {boolean} whether the first and last date are different hours from the same date. - */ -const areDatesInTheSameDay = dates => { - const firstDate = moment( dates [ 0 ] ).toDate(); - const lastDate = moment( dates [ dates.length - 1 ] ).toDate(); - return ( - firstDate.getDate() === lastDate.getDate() && - firstDate.getMonth() === lastDate.getMonth() && - firstDate.getFullYear() === lastDate.getFullYear() - ); -}; - -/** -* Filter out irrelevant dates so only the first date of each month is kept. -* @param {array} dates - string dates. -* @returns {array} Filtered dates. -*/ -const getFirstDatePerMonth = dates => { - return dates.filter( - ( date, i ) => i === 0 || moment( date ).toDate().getMonth() !== moment( dates[ i - 1 ] ).toDate().getMonth() - ); -}; - -/** - * Returns ticks for the x-axis. - * @param {array} uniqueDates - all the unique dates from the input data for the chart - * @param {integer} width - calculated page width - * @param {string} mode - item-comparison or time-comparison - * @param {string} interval - string of the interval used in the graph (hour, day, week...) - * @returns {integer} number of x-axis ticks based on width and chart mode - */ -export const getXTicks = ( uniqueDates, width, mode, interval ) => { - const maxTicks = calculateMaxXTicks( width, mode ); - - if ( - ( uniqueDates.length >= dayTicksThreshold && interval === 'day' ) || - ( uniqueDates.length >= weekTicksThreshold && interval === 'week' ) - ) { - uniqueDates = getFirstDatePerMonth( uniqueDates ); - } - if ( uniqueDates.length <= maxTicks || - ( interval === 'hour' && areDatesInTheSameDay( uniqueDates ) && width > smallBreak ) ) { - return uniqueDates; - } - - const incrementFactor = calculateXTicksIncrementFactor( uniqueDates, maxTicks ); - - return getXTicksFromIncrementFactor( uniqueDates, incrementFactor ); -}; - -/** -* Compares 2 strings and returns a list of words that are unique from s2 -* @param {string} s1 - base string to compare against -* @param {string} s2 - string to compare against the base string -* @param {string|Object} splitChar - character or RegExp to use to deliminate words -* @returns {array} of unique words that appear in s2 but not in s1, the base string -*/ -export const compareStrings = ( s1, s2, splitChar = new RegExp( [ ' |,' ], 'g' ) ) => { - const string1 = s1.split( splitChar ); - const string2 = s2.split( splitChar ); - const diff = new Array(); - const long = s1.length > s2.length ? string1 : string2; - for ( let x = 0; x < long.length; x++ ) { - string1[ x ] !== string2[ x ] && diff.push( string2[ x ] ); - } - return diff; -}; - -const calculateYGridValues = ( numberOfTicks, limit, roundValues ) => { - const grids = []; - - for ( let i = 0; i < numberOfTicks; i++ ) { - const val = ( i + 1 ) / numberOfTicks * limit; - const rVal = roundValues ? Math.round( val ) : val; - if ( grids[ grids.length - 1 ] !== rVal ) { - grids.push( rVal ); - } - } - - return grids; -}; - -const getNegativeYGrids = ( yMin, step ) => { - if ( yMin >= 0 ) { - return []; - } - - const numberOfTicks = Math.ceil( -yMin / step ); - return calculateYGridValues( numberOfTicks, yMin, yMin < -1 ); -}; - -const getPositiveYGrids = ( yMax, step ) => { - if ( yMax <= 0 ) { - return []; - } - - const numberOfTicks = Math.ceil( yMax / step ); - return calculateYGridValues( numberOfTicks, yMax, yMax > 1 ); -}; - -export const getYGrids = ( yMin, yMax, step ) => { - return [ - 0, - ...getNegativeYGrids( yMin, step ), - ...getPositiveYGrids( yMax, step ), - ]; -}; - -const removeDuplicateDates = ( d, i, ticks, formatter ) => { - const monthDate = moment( d ).toDate(); - let prevMonth = i !== 0 ? ticks[ i - 1 ] : ticks[ i ]; - prevMonth = prevMonth instanceof Date ? prevMonth : moment( prevMonth ).toDate(); - return i === 0 - ? formatter( monthDate ) - : compareStrings( formatter( prevMonth ), formatter( monthDate ) ).join( ' ' ); -}; - -const drawXAxis = ( node, params, scales, formats ) => { - const height = scales.yScale.range()[ 0 ]; - let ticks = getXTicks( params.uniqueDates, scales.xScale.range()[ 1 ], params.mode, params.interval ); - if ( params.chartType === 'line' ) { - ticks = ticks.map( d => moment( d ).toDate() ); - } - - node - .append( 'g' ) - .attr( 'class', 'axis' ) - .attr( 'aria-hidden', 'true' ) - .attr( 'transform', `translate(0, ${ height })` ) - .call( - d3AxisBottom( scales.xScale ) - .tickValues( ticks ) - .tickFormat( ( d, i ) => params.interval === 'hour' - ? formats.xFormat( d instanceof Date ? d : moment( d ).toDate() ) - : removeDuplicateDates( d, i, ticks, formats.xFormat ) ) - ); - - node - .append( 'g' ) - .attr( 'class', 'axis axis-month' ) - .attr( 'aria-hidden', 'true' ) - .attr( 'transform', `translate(0, ${ height + 14 })` ) - .call( - d3AxisBottom( scales.xScale ) - .tickValues( ticks ) - .tickFormat( ( d, i ) => removeDuplicateDates( d, i, ticks, formats.x2Format ) ) - ); - - node - .append( 'g' ) - .attr( 'class', 'pipes' ) - .attr( 'transform', `translate(0, ${ height })` ) - .call( - d3AxisBottom( scales.xScale ) - .tickValues( ticks ) - .tickSize( 5 ) - .tickFormat( '' ) - ); -}; - -const drawYAxis = ( node, scales, formats, margin, isRTL ) => { - const yGrids = getYGrids( scales.yScale.domain()[ 0 ], scales.yScale.domain()[ 1 ], scales.step ); - const width = scales.xScale.range()[ 1 ]; - const xPosition = isRTL ? width + margin.left + margin.right / 2 - 15 : -margin.left / 2 - 15; - - const withPositiveValuesClass = scales.yMin >= 0 || scales.yMax > 0 ? ' with-positive-ticks' : ''; - node - .append( 'g' ) - .attr( 'class', 'grid' + withPositiveValuesClass ) - .attr( 'transform', `translate(-${ margin.left }, 0)` ) - .call( - d3AxisLeft( scales.yScale ) - .tickValues( yGrids ) - .tickSize( -width - margin.left - margin.right ) - .tickFormat( '' ) - ); - - node - .append( 'g' ) - .attr( 'class', 'axis y-axis' ) - .attr( 'aria-hidden', 'true' ) - .attr( 'transform', 'translate(' + xPosition + ', 12)' ) - .attr( 'text-anchor', 'start' ) - .call( - d3AxisLeft( scales.yScale ) - .tickValues( scales.yMax === 0 && scales.yMin === 0 ? [ yGrids[ 0 ] ] : yGrids ) - .tickFormat( d => formats.yFormat( d !== 0 ? d : 0 ) ) - ); -}; +import { drawXAxis } from './axis-x'; +import { drawYAxis } from './axis-y'; export const drawAxis = ( node, params, scales, formats, margin, isRTL ) => { drawXAxis( node, params, scales, formats ); diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-x.js similarity index 74% rename from plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis.js rename to plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-x.js index 4518ed5cb78..0e943fdd2ad 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-x.js @@ -6,7 +6,7 @@ /** * Internal dependencies */ -import { compareStrings, getXTicks, getYGrids } from '../axis'; +import { compareStrings, getXTicks } from '../axis-x'; describe( 'getXTicks', () => { describe( 'interval=day', () => { @@ -238,59 +238,3 @@ describe( 'compareStrings', () => { expect( compareStrings( 'Jul, 2018', 'Aug, 2018' ).join( ' ' ) ).toEqual( 'Aug' ); } ); } ); - -describe( 'getYGrids', () => { - it( 'returns a single 0 when yMax and yMin are 0', () => { - expect( getYGrids( 0, 0, 0 ) ).toEqual( [ 0 ] ); - } ); - - describe( 'positive charts', () => { - it( 'returns decimal values when yMax is <= 1 and yMin is 0', () => { - expect( getYGrids( 0, 1, 0.3333333333333333 ) ).toEqual( [ 0, 0.3333333333333333, 0.6666666666666666, 1 ] ); - } ); - - it( 'returns decimal values when yMax and yMin are <= 1', () => { - expect( getYGrids( 1, 1, 0.3333333333333333 ) ).toEqual( [ 0, 0.3333333333333333, 0.6666666666666666, 1 ] ); - } ); - - it( 'doesn\'t return decimal values when yMax is > 1', () => { - expect( getYGrids( 0, 2, 1 ) ).toEqual( [ 0, 1, 2 ] ); - } ); - - it( 'returns up to four values when yMax is a big number', () => { - expect( getYGrids( 0, 12000, 4000 ) ).toEqual( [ 0, 4000, 8000, 12000 ] ); - } ); - } ); - - describe( 'negative charts', () => { - it( 'returns decimal values when yMin is >= -1 and yMax is 0', () => { - expect( getYGrids( -1, 0, 0.3333333333333333 ) ).toEqual( [ 0, -0.3333333333333333, -0.6666666666666666, -1 ] ); - } ); - - it( 'returns decimal values when yMax and yMin are >= -1', () => { - expect( getYGrids( -1, -1, 0.3333333333333333 ) ).toEqual( [ 0, -0.3333333333333333, -0.6666666666666666, -1 ] ); - } ); - - it( 'doesn\'t return decimal values when yMin is < -1', () => { - expect( getYGrids( -2, 0, 1 ) ).toEqual( [ 0, -1, -2 ] ); - } ); - - it( 'returns up to four values when yMin is a big negative number', () => { - expect( getYGrids( -12000, 0, 4000 ) ).toEqual( [ 0, -4000, -8000, -12000 ] ); - } ); - } ); - - describe( 'positive & negative charts', () => { - it( 'returns decimal values when yMax is <= 1 and yMin is 0', () => { - expect( getYGrids( -1, 1, 0.5 ) ).toEqual( [ 0, -0.5, -1, 0.5, 1 ] ); - } ); - - it( 'doesn\'t return decimal values when yMax is > 1', () => { - expect( getYGrids( -2, 2, 1 ) ).toEqual( [ 0, -1, -2, 1, 2 ] ); - } ); - - it( 'returns up to six values when yMax is a big number', () => { - expect( getYGrids( -12000, 12000, 6000 ) ).toEqual( [ 0, -6000, -12000, 6000, 12000 ] ); - } ); - } ); -} ); diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-y.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-y.js new file mode 100644 index 00000000000..6fe6d13db5f --- /dev/null +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/axis-y.js @@ -0,0 +1,65 @@ +/** @format */ +/** + * External dependencies + */ + +/** +* Internal dependencies +*/ +import { getYGrids } from '../axis-y'; + +describe( 'getYGrids', () => { + it( 'returns a single 0 when yMax and yMin are 0', () => { + expect( getYGrids( 0, 0, 0 ) ).toEqual( [ 0 ] ); + } ); + + describe( 'positive charts', () => { + it( 'returns decimal values when yMax is <= 1 and yMin is 0', () => { + expect( getYGrids( 0, 1, 0.3333333333333333 ) ).toEqual( [ 0, 0.3333333333333333, 0.6666666666666666, 1 ] ); + } ); + + it( 'returns decimal values when yMax and yMin are <= 1', () => { + expect( getYGrids( 1, 1, 0.3333333333333333 ) ).toEqual( [ 0, 0.3333333333333333, 0.6666666666666666, 1 ] ); + } ); + + it( 'doesn\'t return decimal values when yMax is > 1', () => { + expect( getYGrids( 0, 2, 1 ) ).toEqual( [ 0, 1, 2 ] ); + } ); + + it( 'returns up to four values when yMax is a big number', () => { + expect( getYGrids( 0, 12000, 4000 ) ).toEqual( [ 0, 4000, 8000, 12000 ] ); + } ); + } ); + + describe( 'negative charts', () => { + it( 'returns decimal values when yMin is >= -1 and yMax is 0', () => { + expect( getYGrids( -1, 0, 0.3333333333333333 ) ).toEqual( [ 0, -0.3333333333333333, -0.6666666666666666, -1 ] ); + } ); + + it( 'returns decimal values when yMax and yMin are >= -1', () => { + expect( getYGrids( -1, -1, 0.3333333333333333 ) ).toEqual( [ 0, -0.3333333333333333, -0.6666666666666666, -1 ] ); + } ); + + it( 'doesn\'t return decimal values when yMin is < -1', () => { + expect( getYGrids( -2, 0, 1 ) ).toEqual( [ 0, -1, -2 ] ); + } ); + + it( 'returns up to four values when yMin is a big negative number', () => { + expect( getYGrids( -12000, 0, 4000 ) ).toEqual( [ 0, -4000, -8000, -12000 ] ); + } ); + } ); + + describe( 'positive & negative charts', () => { + it( 'returns decimal values when yMax is <= 1 and yMin is 0', () => { + expect( getYGrids( -1, 1, 0.5 ) ).toEqual( [ 0, -0.5, -1, 0.5, 1 ] ); + } ); + + it( 'doesn\'t return decimal values when yMax is > 1', () => { + expect( getYGrids( -2, 2, 1 ) ).toEqual( [ 0, -1, -2, 1, 2 ] ); + } ); + + it( 'returns up to six values when yMax is a big number', () => { + expect( getYGrids( -12000, 12000, 6000 ) ).toEqual( [ 0, -6000, -12000, 6000, 12000 ] ); + } ); + } ); +} );