From 9604c77e64dcb14863bc2f5ee9f8c95622cbb530 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Fri, 16 Aug 2019 22:19:46 +0200 Subject: [PATCH 1/4] refactor(scales): clean ScaleContinuous constructor arguments --- .../annotations/annotation_marker.test.tsx | 6 +- .../annotations/annotation_utils.test.ts | 14 ++- .../store/chart_state.interactions.test.ts | 13 ++- .../xy_chart/store/chart_state.test.ts | 10 +-- src/chart_types/xy_chart/store/utils.test.ts | 9 +- src/chart_types/xy_chart/utils/scales.ts | 31 +++---- .../stacked_percent_series_utils.test.ts | 2 +- src/utils/scales/scale_continuous.test.ts | 35 ++++---- src/utils/scales/scale_continuous.ts | 87 +++++++++++-------- src/utils/scales/scale_time.test.ts | 40 ++++++--- src/utils/scales/scales.test.ts | 28 +++--- 11 files changed, 167 insertions(+), 108 deletions(-) diff --git a/src/chart_types/xy_chart/annotations/annotation_marker.test.tsx b/src/chart_types/xy_chart/annotations/annotation_marker.test.tsx index 65c9ca2bb0..2958252a23 100644 --- a/src/chart_types/xy_chart/annotations/annotation_marker.test.tsx +++ b/src/chart_types/xy_chart/annotations/annotation_marker.test.tsx @@ -21,7 +21,11 @@ describe('annotation marker', () => { const maxRange = 100; const continuousData = [0, 10]; - const continuousScale = new ScaleContinuous(ScaleType.Linear, continuousData, [minRange, maxRange]); + const continuousScale = new ScaleContinuous({ + type: ScaleType.Linear, + domain: continuousData, + range: [minRange, maxRange], + }); const chartDimensions: Dimensions = { width: 10, diff --git a/src/chart_types/xy_chart/annotations/annotation_utils.test.ts b/src/chart_types/xy_chart/annotations/annotation_utils.test.ts index c22e24fddb..450ebce0c3 100644 --- a/src/chart_types/xy_chart/annotations/annotation_utils.test.ts +++ b/src/chart_types/xy_chart/annotations/annotation_utils.test.ts @@ -50,7 +50,14 @@ describe('annotation utils', () => { const maxRange = 100; const continuousData = [0, 10]; - const continuousScale = new ScaleContinuous(ScaleType.Linear, continuousData, [minRange, maxRange], 0, 1); + const continuousScale = new ScaleContinuous( + { + type: ScaleType.Linear, + domain: continuousData, + range: [minRange, maxRange], + }, + { bandwidth: 0, minInterval: 1 }, + ); const ordinalData = ['a', 'b', 'c', 'd', 'a', 'b', 'c']; const ordinalScale = new ScaleBand(ordinalData, [minRange, maxRange]); @@ -1345,7 +1352,10 @@ describe('annotation utils', () => { const yScales: Map = new Map(); yScales.set(groupId, continuousScale); - const xScale: Scale = new ScaleContinuous(ScaleType.Linear, continuousData, [minRange, maxRange], 1, 1); + const xScale: Scale = new ScaleContinuous( + { type: ScaleType.Linear, domain: continuousData, range: [minRange, maxRange] }, + { bandwidth: 1, minInterval: 1 }, + ); const annotationRectangle: RectAnnotationSpec = { annotationId: getAnnotationId('rect'), diff --git a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts index 5876210644..323b546e48 100644 --- a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts @@ -174,9 +174,16 @@ describe('Chart state pointer interactions', () => { }); test('can respond to tooltip types changes', () => { - store.xScale = new ScaleContinuous(ScaleType.Linear, [0, 1], [0, 100], 50, 0.5); + store.xScale = new ScaleContinuous( + { + type: ScaleType.Linear, + domain: [0, 1], + range: [0, 100], + }, + { bandwidth: 50, minInterval: 0.5 }, + ); store.yScales = new Map(); - store.yScales.set(GROUP_ID, new ScaleContinuous(ScaleType.Linear, [0, 1], [0, 100])); + store.yScales.set(GROUP_ID, new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 1], range: [0, 100] })); store.geometriesIndex.set(0, [indexedGeom1Red]); store.geometriesIndexKeys.push(0); store.tooltipType.set(TooltipType.None); @@ -376,7 +383,7 @@ function mouseOverTestSuite(scaleType: ScaleType) { const singleValueScale = store.xScale!.type === ScaleType.Ordinal ? new ScaleBand(['a'], [0, 0]) - : new ScaleContinuous(ScaleType.Linear, [1, 1], [0, 0]); + : new ScaleContinuous({ type: ScaleType.Linear, domain: [1, 1], range: [0, 0] }); store.xScale = singleValueScale; }); test('horizontal chart rotation', () => { diff --git a/src/chart_types/xy_chart/store/chart_state.test.ts b/src/chart_types/xy_chart/store/chart_state.test.ts index 7ef834ceb8..53a1542f2b 100644 --- a/src/chart_types/xy_chart/store/chart_state.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.test.ts @@ -680,7 +680,7 @@ describe('Chart Store', () => { test('can disable brush based on scale and listener', () => { store.xScale = undefined; expect(store.isBrushEnabled()).toBe(false); - store.xScale = new ScaleContinuous(ScaleType.Linear, [0, 100], [0, 100]); + store.xScale = new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 100], range: [0, 100] }); store.onBrushEndListener = undefined; expect(store.isBrushEnabled()).toBe(false); store.setOnBrushEndListener(() => ({})); @@ -700,7 +700,7 @@ describe('Chart Store', () => { isXValue: false, seriesKey: 'a', }; - store.xScale = new ScaleContinuous(ScaleType.Linear, [0, 100], [0, 100]); + store.xScale = new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 100], range: [0, 100] }); store.cursorPosition.x = 1; store.cursorPosition.y = 1; store.tooltipType.set(TooltipType.Crosshairs); @@ -791,7 +791,7 @@ describe('Chart Store', () => { expect(clickListener.mock.calls[1][0]).toEqual([geom1.value, geom2.value]); }); test('can compute annotation tooltip state', () => { - const scale = new ScaleContinuous(ScaleType.Linear, [0, 100], [0, 100]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 100], range: [0, 100] }); store.rawCursorPosition.x = -1; store.rawCursorPosition.y = 0; @@ -895,7 +895,7 @@ describe('Chart Store', () => { }; beforeEach(() => { - store.xScale = new ScaleContinuous(ScaleType.Linear, [0, 100], [0, 100]); + store.xScale = new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 100], range: [0, 100] }); }); test('when cursor is outside of chart bounds', () => { @@ -976,7 +976,7 @@ describe('Chart Store', () => { getPosition, })); - const scale = new ScaleContinuous(ScaleType.Linear, [0, 100], [0, 100]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain: [0, 100], range: [0, 100] }); beforeEach(() => { // @ts-ignore store.setCursorPosition = jest.fn(); diff --git a/src/chart_types/xy_chart/store/utils.test.ts b/src/chart_types/xy_chart/store/utils.test.ts index 3def34ddc0..05a46ec0ce 100644 --- a/src/chart_types/xy_chart/store/utils.test.ts +++ b/src/chart_types/xy_chart/store/utils.test.ts @@ -1035,7 +1035,14 @@ describe('Chart State utils', () => { const range: [number, number] = [0, 100]; const bandwidth = 10; const barsPadding = 0.5; - const scale = new ScaleContinuous(ScaleType.Linear, domain, range, bandwidth, 0, 'utc', 1, barsPadding); + const scale = new ScaleContinuous( + { + type: ScaleType.Linear, + domain, + range, + }, + { bandwidth, minInterval: 0, timeZone: 'utc', totalBarsInCluster: 1, barsPadding }, + ); const histogramModeEnabled = true; const histogramModeDisabled = false; diff --git a/src/chart_types/xy_chart/utils/scales.ts b/src/chart_types/xy_chart/utils/scales.ts index acac6cfdef..790cb5f847 100644 --- a/src/chart_types/xy_chart/utils/scales.ts +++ b/src/chart_types/xy_chart/utils/scales.ts @@ -87,31 +87,22 @@ export function computeXScale( const intervalCount = (adjustedDomain[1] - adjustedDomain[0]) / minInterval; const intervalCountOffest = isSingleValueHistogram ? 0 : 1; const bandwidth = rangeDiff / (intervalCount + intervalCountOffest); - const { start, end } = getBandScaleRange(isInverse, isSingleValueHistogram, minRange, maxRange, bandwidth); const scale = new ScaleContinuous( - scaleType, - adjustedDomain, - [start, end], - bandwidth / totalBarsInCluster, - minInterval, - timeZone, - totalBarsInCluster, - barsPadding, + { + type: scaleType, + domain: adjustedDomain, + range: [start, end], + }, + { bandwidth: bandwidth / totalBarsInCluster, minInterval, timeZone, totalBarsInCluster, barsPadding }, ); return scale; } else { return new ScaleContinuous( - scaleType, - domain, - [minRange, maxRange], - 0, - minInterval, - timeZone, - totalBarsInCluster, - barsPadding, + { type: scaleType, domain, range: [minRange, maxRange] }, + { bandwidth: 0, minInterval, timeZone, totalBarsInCluster, barsPadding }, ); } } @@ -126,7 +117,11 @@ export function computeYScales(yDomains: YDomain[], minRange: number, maxRange: const yScales: Map = new Map(); yDomains.forEach((yDomain) => { - const yScale = new ScaleContinuous(yDomain.scaleType, yDomain.domain, [minRange, maxRange]); + const yScale = new ScaleContinuous({ + type: yDomain.scaleType, + domain: yDomain.domain, + range: [minRange, maxRange], + }); yScales.set(yDomain.groupId, yScale); }); diff --git a/src/chart_types/xy_chart/utils/stacked_percent_series_utils.test.ts b/src/chart_types/xy_chart/utils/stacked_percent_series_utils.test.ts index 1716894e8b..c658ccc497 100644 --- a/src/chart_types/xy_chart/utils/stacked_percent_series_utils.test.ts +++ b/src/chart_types/xy_chart/utils/stacked_percent_series_utils.test.ts @@ -163,7 +163,7 @@ describe('Stacked Series Utils', () => { }, ]; - describe.only('Format stacked dataset', () => { + describe('Format stacked dataset', () => { test('format data without nulls', () => { const formattedData = formatStackedDataSeriesValues(STANDARD_DATA_SET, false, true); const data0 = formattedData[0].data[0]; diff --git a/src/utils/scales/scale_continuous.test.ts b/src/utils/scales/scale_continuous.test.ts index 8be8896afc..3e97941151 100644 --- a/src/utils/scales/scale_continuous.test.ts +++ b/src/utils/scales/scale_continuous.test.ts @@ -11,7 +11,7 @@ describe('Scale Continuous', () => { const domain: Domain = [0, 2]; const minRange = 0; const maxRange = 100; - const scale = new ScaleContinuous(ScaleType.Linear, domain, [minRange, maxRange]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain, range: [minRange, maxRange] }); expect(scale.invert(0)).toBe(0); expect(scale.invert(50)).toBe(1); expect(scale.invert(100)).toBe(2); @@ -23,7 +23,7 @@ describe('Scale Continuous', () => { const domain = [startTime.toMillis(), endTime.toMillis()]; const minRange = 0; const maxRange = 100; - const scale = new ScaleContinuous(ScaleType.Time, domain, [minRange, maxRange]); + const scale = new ScaleContinuous({ type: ScaleType.Time, domain, range: [minRange, maxRange] }); expect(scale.invert(0)).toBe(startTime.toMillis()); expect(scale.invert(50)).toBe(midTime.toMillis()); expect(scale.invert(100)).toBe(endTime.toMillis()); @@ -31,10 +31,10 @@ describe('Scale Continuous', () => { test('check if a scale is log scale', () => { const domain: Domain = [0, 2]; const range: [number, number] = [0, 100]; - const scaleLinear = new ScaleContinuous(ScaleType.Linear, domain, range); - const scaleLog = new ScaleContinuous(ScaleType.Log, domain, range); - const scaleTime = new ScaleContinuous(ScaleType.Time, domain, range); - const scaleSqrt = new ScaleContinuous(ScaleType.Sqrt, domain, range); + const scaleLinear = new ScaleContinuous({ type: ScaleType.Linear, domain, range }); + const scaleLog = new ScaleContinuous({ type: ScaleType.Log, domain, range }); + const scaleTime = new ScaleContinuous({ type: ScaleType.Time, domain, range }); + const scaleSqrt = new ScaleContinuous({ type: ScaleType.Sqrt, domain, range }); const scaleBand = new ScaleBand(domain, range); expect(isLogarithmicScale(scaleLinear)).toBe(false); expect(isLogarithmicScale(scaleLog)).toBe(true); @@ -46,7 +46,7 @@ describe('Scale Continuous', () => { const domain: Domain = [0, 2]; const data = [0, 0.5, 0.8, 2]; const range: [number, number] = [0, 2]; - const scaleLinear = new ScaleContinuous(ScaleType.Linear, domain, range); + const scaleLinear = new ScaleContinuous({ type: ScaleType.Linear, domain, range }); expect(scaleLinear.bandwidth).toBe(0); expect(scaleLinear.invertWithStep(0, data)).toBe(0); expect(scaleLinear.invertWithStep(0.1, data)).toBe(0); @@ -97,7 +97,10 @@ describe('Scale Continuous', () => { // we tweak the maxRange removing the bandwidth to correctly compute // a band linear scale in computeXScale const range: [number, number] = [0, 100 - 10]; - const scaleLinear = new ScaleContinuous(ScaleType.Linear, domain, range, 10, 10); + const scaleLinear = new ScaleContinuous( + { type: ScaleType.Linear, domain, range }, + { bandwidth: 10, minInterval: 10 }, + ); expect(scaleLinear.bandwidth).toBe(10); expect(scaleLinear.invertWithStep(0, data)).toBe(0); expect(scaleLinear.invertWithStep(10, data)).toBe(10); @@ -118,7 +121,7 @@ describe('Scale Continuous', () => { }; const scaleLinear = computeXScale(xDomain, 1, 0, 110, 0); - // const scaleLinear = new ScaleContinuous(ScaleType.Linear, domain, range, 10, 10); + // const scaleLinear = new ScaleContinuous({type: ScaleType.Linear, domain, range}, 10, 10); expect(scaleLinear.bandwidth).toBe(10); expect(scaleLinear.invertWithStep(0, data)).toBe(0); @@ -142,15 +145,15 @@ describe('Scale Continuous', () => { describe('isSingleValue', () => { test('should return true for domain with fewer than 2 values', () => { - const scale = new ScaleContinuous(ScaleType.Linear, [], [0, 100]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain: [], range: [0, 100] }); expect(scale.isSingleValue()).toBe(true); }); test('should return true for domain with equal min and max values', () => { - const scale = new ScaleContinuous(ScaleType.Linear, [1, 1], [0, 100]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain: [1, 1], range: [0, 100] }); expect(scale.isSingleValue()).toBe(true); }); test('should return false for domain with differing min and max values', () => { - const scale = new ScaleContinuous(ScaleType.Linear, [1, 2], [0, 100]); + const scale = new ScaleContinuous({ type: ScaleType.Linear, domain: [1, 2], range: [0, 100] }); expect(scale.isSingleValue()).toBe(false); }); }); @@ -160,12 +163,8 @@ describe('Scale Continuous', () => { function getTicksForDomain(domainStart: number, domainEnd: number) { const scale = new ScaleContinuous( - ScaleType.Time, - [domainStart, domainEnd], - [0, 100], - 0, - 0, - Settings.defaultZoneName, + { type: ScaleType.Time, domain: [domainStart, domainEnd], range: [0, 100] }, + { bandwidth: 0, minInterval: 0, timeZone: Settings.defaultZoneName }, ); return scale.tickValues; } diff --git a/src/utils/scales/scale_continuous.ts b/src/utils/scales/scale_continuous.ts index dde9f6a561..2f92f3697f 100644 --- a/src/utils/scales/scale_continuous.ts +++ b/src/utils/scales/scale_continuous.ts @@ -1,7 +1,7 @@ import { bisectLeft } from 'd3-array'; import { scaleLinear, scaleLog, scaleSqrt, scaleUtc } from 'd3-scale'; import { DateTime } from 'luxon'; -import { clamp } from '../commons'; +import { clamp, mergePartial } from '../commons'; import { ScaleContinuousType, ScaleType, Scale } from './scales'; const SCALES = { @@ -60,6 +60,45 @@ export function limitLogScaleDomain(domain: any[]) { } return domain; } +interface ScaleData { + /** The Type of continuous scale */ + type: ScaleContinuousType; + /** The data input domain */ + domain: any[]; + /** The data output range */ + range: [number, number]; +} + +interface ScaleOptions { + /** + * The desidered bandwidth for a linear band scale. + * @default 0 + */ + bandwidth: number; + /** + * The min interval computed on the XDomain. Not available for yDomains. + * @default 0 + */ + minInterval: number; + /** + * A time zone identifier. Can be any IANA zone supported by he host environment, + * or a fixed-offset name of the form 'utc+3', or the strings 'local' or 'utc'. + * @default 'utc' + */ + timeZone: string; + /** + * The number of bars in the cluster. Used to correctly compute scales when + * using padding between bars. + * @default 1 + */ + totalBarsInCluster: number; + /** + * The proportion of the range that is reserved for blank space between bands + * A number between 0 and 1. + * @default 0 + */ + barsPadding: number; +} export class ScaleContinuous implements Scale { readonly bandwidth: number; @@ -76,39 +115,19 @@ export class ScaleContinuous implements Scale { readonly barsPadding: number; private readonly d3Scale: any; - constructor( - type: ScaleContinuousType, - domain: any[], - range: [number, number], - /** - * The desidered bandwidth for a linear band scale. - * @default 0 - */ - bandwidth: number = 0, - /** - * The min interval computed on the XDomain. Not available for yDomains. - * @default 0 - */ - minInterval: number = 0, - /** - * A time zone identifier. Can be any IANA zone supported by he host environment, - * or a fixed-offset name of the form 'utc+3', or the strings 'local' or 'utc'. - * @default 'utc' - */ - timeZone: string = 'utc', - /** - * The number of bars in the cluster. Used to correctly compute scales when - * using padding between bars. - * @default 1 - */ - totalBarsInCluster: number = 1, - /** - * The proportion of the range that is reserved for blank space between bands - * A number between 0 and 1. - * @default 0 - */ - barsPadding: number = 0, - ) { + constructor(scaleData: ScaleData, options?: Partial) { + const { type, domain, range } = scaleData; + const scaleOptions: ScaleOptions = mergePartial( + { + bandwidth: 0, + minInterval: 0, + timeZone: 'utc', + totalBarsInCluster: 1, + barsPadding: 0, + }, + options, + ); + const { bandwidth, minInterval, timeZone, totalBarsInCluster, barsPadding } = scaleOptions; this.d3Scale = SCALES[type](); if (type === ScaleType.Log) { this.domain = limitLogScaleDomain(domain); diff --git a/src/utils/scales/scale_time.test.ts b/src/utils/scales/scale_time.test.ts index ed03e4b081..d1fd1b45ba 100644 --- a/src/utils/scales/scale_time.test.ts +++ b/src/utils/scales/scale_time.test.ts @@ -74,7 +74,14 @@ describe('[Scale Time] - timezones', () => { const minRange = 0; const maxRange = 100; const minInterval = (endTime - startTime) / 2; - const scale = new ScaleContinuous(ScaleType.Time, domain, [minRange, maxRange], undefined, minInterval, 'local'); + const scale = new ScaleContinuous( + { + type: ScaleType.Time, + domain, + range: [minRange, maxRange], + }, + { bandwidth: undefined, minInterval, timeZone: 'local' }, + ); expect(scale.invert(0)).toBe(startTime); expect(scale.invert(50)).toBe(midTime); expect(scale.invert(100)).toBe(endTime); @@ -99,7 +106,10 @@ describe('[Scale Time] - timezones', () => { const minRange = 0; const maxRange = 100; const minInterval = (endTime - startTime) / 2; - const scale = new ScaleContinuous(ScaleType.Time, domain, [minRange, maxRange], undefined, minInterval, 'utc'); + const scale = new ScaleContinuous( + { type: ScaleType.Time, domain, range: [minRange, maxRange] }, + { bandwidth: undefined, minInterval, timeZone: 'utc' }, + ); expect(scale.invert(0)).toBe(startTime); expect(scale.invert(50)).toBe(midTime); expect(scale.invert(100)).toBe(endTime); @@ -124,7 +134,14 @@ describe('[Scale Time] - timezones', () => { const minRange = 0; const maxRange = 100; const minInterval = (endTime - startTime) / 2; - const scale = new ScaleContinuous(ScaleType.Time, domain, [minRange, maxRange], undefined, minInterval, 'utc+8'); + const scale = new ScaleContinuous( + { + type: ScaleType.Time, + domain, + range: [minRange, maxRange], + }, + { bandwidth: undefined, minInterval, timeZone: 'utc+8' }, + ); expect(scale.invert(0)).toBe(startTime); expect(scale.invert(50)).toBe(midTime); expect(scale.invert(100)).toBe(endTime); @@ -149,7 +166,14 @@ describe('[Scale Time] - timezones', () => { const minRange = 0; const maxRange = 100; const minInterval = (endTime - startTime) / 2; - const scale = new ScaleContinuous(ScaleType.Time, domain, [minRange, maxRange], undefined, minInterval, 'utc-8'); + const scale = new ScaleContinuous( + { + type: ScaleType.Time, + domain, + range: [minRange, maxRange], + }, + { bandwidth: undefined, minInterval, timeZone: 'utc-8' }, + ); expect(scale.invert(0)).toBe(startTime); expect(scale.invert(50)).toBe(midTime); expect(scale.invert(100)).toBe(endTime); @@ -179,12 +203,8 @@ describe('[Scale Time] - timezones', () => { const maxRange = 100; const minInterval = (endTime - startTime) / 2; const scale = new ScaleContinuous( - ScaleType.Time, - domain, - [minRange, maxRange], - undefined, - minInterval, - timezone, + { type: ScaleType.Time, domain, range: [minRange, maxRange] }, + { bandwidth: undefined, minInterval, timeZone: timezone }, ); const formatFunction = (d: number) => { return DateTime.fromMillis(d, { zone: timezone }).toISO(); diff --git a/src/utils/scales/scales.test.ts b/src/utils/scales/scales.test.ts index 97fac45698..1530d78a89 100644 --- a/src/utils/scales/scales.test.ts +++ b/src/utils/scales/scales.test.ts @@ -26,7 +26,7 @@ describe('Scale Test', () => { const data = [0, 10]; const minRange = 0; const maxRange = 100; - const linearScale = new ScaleContinuous(ScaleType.Linear, data, [minRange, maxRange]); + const linearScale = new ScaleContinuous({ type: ScaleType.Linear, domain: data, range: [minRange, maxRange] }); const { domain, range } = linearScale; expect(domain).toEqual([0, 10]); expect(range).toEqual([minRange, maxRange]); @@ -50,7 +50,7 @@ describe('Scale Test', () => { const data = [date1, date3]; const minRange = 0; const maxRange = 100; - const timeScale = new ScaleContinuous(ScaleType.Time, data, [minRange, maxRange]); + const timeScale = new ScaleContinuous({ type: ScaleType.Time, domain: data, range: [minRange, maxRange] }); const { domain, range } = timeScale; expect(domain).toEqual([date1, date3]); expect(range).toEqual([minRange, maxRange]); @@ -65,7 +65,7 @@ describe('Scale Test', () => { const data = [1, 10]; const minRange = 0; const maxRange = 100; - const logScale = new ScaleContinuous(ScaleType.Log, data, [minRange, maxRange]); + const logScale = new ScaleContinuous({ type: ScaleType.Log, domain: data, range: [minRange, maxRange] }); const { domain, range } = logScale; expect(domain).toEqual([1, 10]); expect(range).toEqual([minRange, maxRange]); @@ -78,7 +78,7 @@ describe('Scale Test', () => { const data = [0, 10]; const minRange = 0; const maxRange = 100; - const logScale = new ScaleContinuous(ScaleType.Log, data, [minRange, maxRange]); + const logScale = new ScaleContinuous({ type: ScaleType.Log, domain: data, range: [minRange, maxRange] }); const { domain, range } = logScale; expect(domain).toEqual([1, 10]); expect(range).toEqual([minRange, maxRange]); @@ -91,7 +91,7 @@ describe('Scale Test', () => { const data = [0, 10]; const minRange = 0; const maxRange = 100; - const sqrtScale = new ScaleContinuous(ScaleType.Sqrt, data, [minRange, maxRange]); + const sqrtScale = new ScaleContinuous({ type: ScaleType.Sqrt, domain: data, range: [minRange, maxRange] }); const { domain, range } = sqrtScale; expect(domain).toEqual([0, 10]); expect(range).toEqual([minRange, maxRange]); @@ -149,11 +149,8 @@ describe('Scale Test', () => { const maxRange = 120; const bandwidth = maxRange / 3; const linearScale = new ScaleContinuous( - ScaleType.Linear, - domainLinear, - [minRange, maxRange - bandwidth], // we currently limit the range like that a band linear scale - bandwidth, - 1, + { type: ScaleType.Linear, domain: domainLinear, range: [minRange, maxRange - bandwidth] }, // we currently limit the range like that a band linear scale + { bandwidth, minInterval: 1 }, ); const ordinalScale = new ScaleBand(domainOrdinal, [minRange, maxRange]); expect(ordinalScale.invertWithStep(0)).toBe(0); @@ -170,11 +167,12 @@ describe('Scale Test', () => { const maxRange = 100; const bandwidth = maxRange / 2; const linearScale = new ScaleContinuous( - ScaleType.Linear, - dataLinear, - [minRange, maxRange - bandwidth], // we currently limit the range like that a band linear scale - bandwidth, - 1, + { + type: ScaleType.Linear, + domain: dataLinear, + range: [minRange, maxRange - bandwidth], + }, // we currently limit the range like that a band linear scale + { bandwidth, minInterval: 1 }, ); const ordinalScale = new ScaleBand(dataOrdinal, [minRange, maxRange]); From 0916abcf368af30f9ab8240fce2e926f92d872d4 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Fri, 16 Aug 2019 23:19:05 +0200 Subject: [PATCH 2/4] feat(axes): specify the number of ticks for the y axis --- .../rendering/rendering.areas.test.ts | 19 ++++---- .../rendering/rendering.bands.test.ts | 8 ++-- .../xy_chart/rendering/rendering.bars.test.ts | 10 ++-- .../rendering/rendering.lines.test.ts | 16 +++---- .../store/chart_state.interactions.test.ts | 2 +- src/chart_types/xy_chart/store/utils.ts | 2 +- src/chart_types/xy_chart/utils/axis_utils.ts | 2 +- src/chart_types/xy_chart/utils/scales.ts | 28 +++++++---- src/chart_types/xy_chart/utils/specs.ts | 2 + src/utils/scales/scale_continuous.ts | 12 +++-- stories/axis.tsx | 47 ++++++++++++++++--- 11 files changed, 101 insertions(+), 47 deletions(-) diff --git a/src/chart_types/xy_chart/rendering/rendering.areas.test.ts b/src/chart_types/xy_chart/rendering/rendering.areas.test.ts index d262e1675a..6c4d8c2ccd 100644 --- a/src/chart_types/xy_chart/rendering/rendering.areas.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.areas.test.ts @@ -28,7 +28,10 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ + yDomains: pointSeriesDomains.yDomain, + range: [100, 0], + }); let renderedArea: { areaGeometry: AreaGeometry; indexedGeometries: Map; @@ -77,7 +80,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; indexedGeometries: Map; @@ -188,7 +191,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { areaGeometry: AreaGeometry; @@ -352,7 +355,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -458,7 +461,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { areaGeometry: AreaGeometry; @@ -621,7 +624,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -727,7 +730,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { areaGeometry: AreaGeometry; @@ -875,7 +878,7 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; diff --git a/src/chart_types/xy_chart/rendering/rendering.bands.test.ts b/src/chart_types/xy_chart/rendering/rendering.bands.test.ts index 6e0418b1a4..9deaaf8b00 100644 --- a/src/chart_types/xy_chart/rendering/rendering.bands.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.bands.test.ts @@ -29,7 +29,7 @@ describe('Rendering bands - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; indexedGeometries: Map; @@ -79,7 +79,7 @@ describe('Rendering bands - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; indexedGeometries: Map; @@ -217,7 +217,7 @@ describe('Rendering bands - areas', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; indexedGeometries: Map; @@ -394,7 +394,7 @@ describe('Rendering bands - areas', () => { barSeriesMap.set(SPEC_ID, barSeriesSpec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars', () => { const { barGeometries } = renderBars( diff --git a/src/chart_types/xy_chart/rendering/rendering.bars.test.ts b/src/chart_types/xy_chart/rendering/rendering.bars.test.ts index ebb70cf0f7..541c516087 100644 --- a/src/chart_types/xy_chart/rendering/rendering.bars.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.bars.test.ts @@ -28,7 +28,7 @@ describe('Rendering bars', () => { const customDomain = [0, 1]; const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map(), customDomain); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars within domain', () => { const { barGeometries } = renderBars( @@ -208,7 +208,7 @@ describe('Rendering bars', () => { barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { const { barGeometries } = renderBars( @@ -393,7 +393,7 @@ describe('Rendering bars', () => { barSeriesMap.set(SPEC_ID, barSeriesSpec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars', () => { const { barGeometries } = renderBars( @@ -508,7 +508,7 @@ describe('Rendering bars', () => { barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { const { barGeometries } = renderBars( @@ -707,7 +707,7 @@ describe('Rendering bars', () => { barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { const { barGeometries } = renderBars( diff --git a/src/chart_types/xy_chart/rendering/rendering.lines.test.ts b/src/chart_types/xy_chart/rendering/rendering.lines.test.ts index 2cb1b0e80e..41d593b8b6 100644 --- a/src/chart_types/xy_chart/rendering/rendering.lines.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.lines.test.ts @@ -29,7 +29,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; indexedGeometries: Map; @@ -75,7 +75,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; indexedGeometries: Map; @@ -181,7 +181,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { lineGeometry: LineGeometry; @@ -343,7 +343,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; @@ -448,7 +448,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { lineGeometry: LineGeometry; @@ -609,7 +609,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; @@ -714,7 +714,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { lineGeometry: LineGeometry; @@ -862,7 +862,7 @@ describe('Rendering points - line', () => { pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); - const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; diff --git a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts index 323b546e48..431153f9cb 100644 --- a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts @@ -222,7 +222,7 @@ function mouseOverTestSuite(scaleType: ScaleType) { barSeriesMap.set(SPEC_ID, spec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); const barSeriesScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); - const yScales = computeYScales(barSeriesDomains.yDomain, 0, 100); + const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [0, 100] }); store.xScale = barSeriesScale; store.yScales = yScales; store.geometriesIndex.set(0, [indexedGeom1Red]); diff --git a/src/chart_types/xy_chart/store/utils.ts b/src/chart_types/xy_chart/store/utils.ts index f3a45bb76a..ceb14173a1 100644 --- a/src/chart_types/xy_chart/store/utils.ts +++ b/src/chart_types/xy_chart/store/utils.ts @@ -216,7 +216,7 @@ export function computeSeriesGeometries( // compute scales const xScale = computeXScale(xDomain, totalBarsInCluster, 0, width, barsPadding, enableHistogramMode); - const yScales = computeYScales(yDomain, height, 0); + const yScales = computeYScales({ yDomains: yDomain, range: [height, 0] }); // compute colors diff --git a/src/chart_types/xy_chart/utils/axis_utils.ts b/src/chart_types/xy_chart/utils/axis_utils.ts index f40705a0d4..2e3421fc02 100644 --- a/src/chart_types/xy_chart/utils/axis_utils.ts +++ b/src/chart_types/xy_chart/utils/axis_utils.ts @@ -128,7 +128,7 @@ export function getScaleForAxisSpec( const axisIsYDomain = isYDomain(axisSpec.position, chartRotation); if (axisIsYDomain) { - const yScales = computeYScales(yDomain, minRange, maxRange); + const yScales = computeYScales({ yDomains: yDomain, range: [minRange, maxRange], ticks: axisSpec.ticks }); if (yScales.has(axisSpec.groupId)) { return yScales.get(axisSpec.groupId)!; } diff --git a/src/chart_types/xy_chart/utils/scales.ts b/src/chart_types/xy_chart/utils/scales.ts index 790cb5f847..12ddb051a5 100644 --- a/src/chart_types/xy_chart/utils/scales.ts +++ b/src/chart_types/xy_chart/utils/scales.ts @@ -108,21 +108,31 @@ export function computeXScale( } } +interface YScaleOptions { + yDomains: YDomain[]; + range: [number, number]; + ticks?: number; +} /** * Compute the y scales, one per groupId for the y axis. * @param yDomains the y domains * @param axisLength the axisLength of the y axis */ -export function computeYScales(yDomains: YDomain[], minRange: number, maxRange: number): Map { +export function computeYScales(options: YScaleOptions): Map { const yScales: Map = new Map(); - - yDomains.forEach((yDomain) => { - const yScale = new ScaleContinuous({ - type: yDomain.scaleType, - domain: yDomain.domain, - range: [minRange, maxRange], - }); - yScales.set(yDomain.groupId, yScale); + const { yDomains, range, ticks } = options; + yDomains.forEach(({ scaleType: type, domain, groupId }) => { + const yScale = new ScaleContinuous( + { + type, + domain, + range, + }, + { + ticks, + }, + ); + yScales.set(groupId, yScale); }); return yScales; diff --git a/src/chart_types/xy_chart/utils/specs.ts b/src/chart_types/xy_chart/utils/specs.ts index 458375aa2e..6f278f34c4 100644 --- a/src/chart_types/xy_chart/utils/specs.ts +++ b/src/chart_types/xy_chart/utils/specs.ts @@ -227,6 +227,8 @@ export interface AxisSpec { tickFormat: TickFormatter; /** The degrees of rotation of the tick labels */ tickLabelRotation?: number; + /** An approximate count of how many ticks will be generated */ + ticks?: number; /** The axis title */ title?: string; /** If specified, it constrains the domain for these values */ diff --git a/src/utils/scales/scale_continuous.ts b/src/utils/scales/scale_continuous.ts index 2f92f3697f..fbc6c03a55 100644 --- a/src/utils/scales/scale_continuous.ts +++ b/src/utils/scales/scale_continuous.ts @@ -98,6 +98,11 @@ interface ScaleOptions { * @default 0 */ barsPadding: number; + /** + * The approximated number of ticks. + * @default 10 + */ + ticks: number; } export class ScaleContinuous implements Scale { @@ -124,10 +129,11 @@ export class ScaleContinuous implements Scale { timeZone: 'utc', totalBarsInCluster: 1, barsPadding: 0, + ticks: 10, }, options, ); - const { bandwidth, minInterval, timeZone, totalBarsInCluster, barsPadding } = scaleOptions; + const { bandwidth, minInterval, timeZone, totalBarsInCluster, barsPadding, ticks } = scaleOptions; this.d3Scale = SCALES[type](); if (type === ScaleType.Log) { this.domain = limitLogScaleDomain(domain); @@ -156,7 +162,7 @@ export class ScaleContinuous implements Scale { const shiftedDomainMax = endDomain.plus({ minutes: offset }).toMillis(); const tzShiftedScale = scaleUtc().domain([shiftedDomainMin, shiftedDomainMax]); - const rawTicks = tzShiftedScale.ticks(); + const rawTicks = tzShiftedScale.ticks(ticks); const timePerTick = (shiftedDomainMax - shiftedDomainMin) / rawTicks.length; const hasHourTicks = timePerTick < 1000 * 60 * 60 * 12; @@ -172,7 +178,7 @@ export class ScaleContinuous implements Scale { return this.domain[0] + i * this.minInterval; }); } else { - this.tickValues = this.d3Scale.ticks(); + this.tickValues = this.d3Scale.ticks(ticks); } } } diff --git a/stories/axis.tsx b/stories/axis.tsx index e3730461df..1a896674f4 100644 --- a/stories/axis.tsx +++ b/stories/axis.tsx @@ -17,7 +17,9 @@ import { Position, ScaleType, Settings, + niceTimeFormatter, } from '../src/'; +import { KIBANA_METRICS } from '../src/utils/data_samples/test_dataset_kibana'; function createThemeAction(title: string, min: number, max: number, value: number) { return number( @@ -55,9 +57,14 @@ function renderAxisWithOptions(position: Position, seriesGroup: string, show: bo storiesOf('Axis', module) .add('basic', () => { const customStyle = { - tickLabelPadding: number('Tick Label Padding', 0), + tickLabelPadding: number('Tick Label Padding', 0, { + range: true, + min: 2, + max: 30, + step: 1, + }), }; - + const data = KIBANA_METRICS.metrics.kibana_os_load[0].data.slice(0, 30); return ( @@ -65,8 +72,21 @@ storiesOf('Axis', module) id={getAxisId('bottom')} position={Position.Bottom} title={'Bottom axis'} - showOverlappingTicks={true} style={customStyle} + showOverlappingLabels={boolean('Bottom overlap labels', true, 'Bottom Axis')} + showOverlappingTicks={boolean('Bottom overlap ticks', true, 'Bottom Axis')} + ticks={number( + 'Number of ticks on bottom', + 10, + { + range: true, + min: 2, + max: 20, + step: 1, + }, + 'Bottom Axis', + )} + tickFormat={niceTimeFormatter([data[0][0], data[data.length - 1][0]])} /> Number(d).toFixed(2)} style={customStyle} + showOverlappingLabels={boolean('Left overlap labels', true, 'Left Axis')} + showOverlappingTicks={boolean('Left overlap ticks', true, 'Left Axis')} + ticks={number( + 'Number of ticks on left', + 10, + { + range: true, + min: 2, + max: 20, + step: 1, + }, + 'Left Axis', + )} /> ); From ecb8976a0addc5b93da606de93a6e798adb87b52 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Fri, 16 Aug 2019 23:49:20 +0200 Subject: [PATCH 3/4] feat(axes): add ticks for X axis --- .../crosshair_utils.linear_snap.test.ts | 30 ++++++++++-- .../crosshair_utils.ordinal_snap.test.ts | 30 ++++++++++-- .../rendering/rendering.areas.test.ts | 48 +++++++++++++++---- .../rendering/rendering.bands.test.ts | 24 ++++++++-- .../xy_chart/rendering/rendering.bars.test.ts | 30 ++++++++++-- .../rendering/rendering.lines.test.ts | 48 +++++++++++++++---- .../store/chart_state.interactions.test.ts | 6 ++- src/chart_types/xy_chart/store/utils.ts | 2 +- src/chart_types/xy_chart/utils/axis_utils.ts | 13 +++-- src/chart_types/xy_chart/utils/scales.test.ts | 24 +++++++--- src/chart_types/xy_chart/utils/scales.ts | 33 +++++++------ src/utils/scales/scale_continuous.test.ts | 4 +- stories/axis.tsx | 6 +-- 13 files changed, 232 insertions(+), 66 deletions(-) diff --git a/src/chart_types/xy_chart/crosshair/crosshair_utils.linear_snap.test.ts b/src/chart_types/xy_chart/crosshair/crosshair_utils.linear_snap.test.ts index 2fbec6c398..556732778c 100644 --- a/src/chart_types/xy_chart/crosshair/crosshair_utils.linear_snap.test.ts +++ b/src/chart_types/xy_chart/crosshair/crosshair_utils.linear_snap.test.ts @@ -82,11 +82,31 @@ describe('Crosshair utils linear scale', () => { mixedLinesBarsMap.set(barSeries2SpecId, barSeries2); const mixedLinesBarsSeriesDomains = computeSeriesDomains(mixedLinesBarsMap, new Map()); - const barSeriesScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 120); - const multiBarSeriesScale = computeXScale(multiBarSeriesDomains.xDomain, multiBarSeriesMap.size, 0, 120); - const lineSeriesScale = computeXScale(lineSeriesDomains.xDomain, lineSeriesMap.size, 0, 120); - const multiLineSeriesScale = computeXScale(multiLineSeriesDomains.xDomain, multiLineSeriesMap.size, 0, 120); - const mixedLinesBarsSeriesScale = computeXScale(mixedLinesBarsSeriesDomains.xDomain, mixedLinesBarsMap.size, 0, 120); + const barSeriesScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 120], + }); + const multiBarSeriesScale = computeXScale({ + xDomain: multiBarSeriesDomains.xDomain, + totalBarsInCluster: multiBarSeriesMap.size, + range: [0, 120], + }); + const lineSeriesScale = computeXScale({ + xDomain: lineSeriesDomains.xDomain, + totalBarsInCluster: lineSeriesMap.size, + range: [0, 120], + }); + const multiLineSeriesScale = computeXScale({ + xDomain: multiLineSeriesDomains.xDomain, + totalBarsInCluster: multiLineSeriesMap.size, + range: [0, 120], + }); + const mixedLinesBarsSeriesScale = computeXScale({ + xDomain: mixedLinesBarsSeriesDomains.xDomain, + totalBarsInCluster: mixedLinesBarsMap.size, + range: [0, 120], + }); /** * if we have lines on a linear scale, the snap position and band should diff --git a/src/chart_types/xy_chart/crosshair/crosshair_utils.ordinal_snap.test.ts b/src/chart_types/xy_chart/crosshair/crosshair_utils.ordinal_snap.test.ts index 16a85e6171..74edfdeb1f 100644 --- a/src/chart_types/xy_chart/crosshair/crosshair_utils.ordinal_snap.test.ts +++ b/src/chart_types/xy_chart/crosshair/crosshair_utils.ordinal_snap.test.ts @@ -81,11 +81,31 @@ describe('Crosshair utils ordinal scales', () => { mixedLinesBarsMap.set(barSeries2SpecId, barSeries2); const mixedLinesBarsSeriesDomains = computeSeriesDomains(mixedLinesBarsMap, new Map()); - const barSeriesScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 120); - const multiBarSeriesScale = computeXScale(multiBarSeriesDomains.xDomain, multiBarSeriesMap.size, 0, 120); - const lineSeriesScale = computeXScale(lineSeriesDomains.xDomain, lineSeriesMap.size, 0, 120); - const multiLineSeriesScale = computeXScale(multiLineSeriesDomains.xDomain, multiLineSeriesMap.size, 0, 120); - const mixedLinesBarsSeriesScale = computeXScale(mixedLinesBarsSeriesDomains.xDomain, mixedLinesBarsMap.size, 0, 120); + const barSeriesScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 120], + }); + const multiBarSeriesScale = computeXScale({ + xDomain: multiBarSeriesDomains.xDomain, + totalBarsInCluster: multiBarSeriesMap.size, + range: [0, 120], + }); + const lineSeriesScale = computeXScale({ + xDomain: lineSeriesDomains.xDomain, + totalBarsInCluster: lineSeriesMap.size, + range: [0, 120], + }); + const multiLineSeriesScale = computeXScale({ + xDomain: multiLineSeriesDomains.xDomain, + totalBarsInCluster: multiLineSeriesMap.size, + range: [0, 120], + }); + const mixedLinesBarsSeriesScale = computeXScale({ + xDomain: mixedLinesBarsSeriesDomains.xDomain, + totalBarsInCluster: mixedLinesBarsMap.size, + range: [0, 120], + }); test('can snap position on scale ordinal bar', () => { let snappedPosition = getSnapPosition('a', barSeriesScale); diff --git a/src/chart_types/xy_chart/rendering/rendering.areas.test.ts b/src/chart_types/xy_chart/rendering/rendering.areas.test.ts index 6c4d8c2ccd..d3b8f12407 100644 --- a/src/chart_types/xy_chart/rendering/rendering.areas.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.areas.test.ts @@ -27,7 +27,11 @@ describe('Rendering points - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0], @@ -79,7 +83,11 @@ describe('Rendering points - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -190,7 +198,11 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -354,7 +366,11 @@ describe('Rendering points - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { @@ -460,7 +476,11 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -623,7 +643,11 @@ describe('Rendering points - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { @@ -729,7 +753,11 @@ describe('Rendering points - areas', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -877,7 +905,11 @@ describe('Rendering points - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 90], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { diff --git a/src/chart_types/xy_chart/rendering/rendering.bands.test.ts b/src/chart_types/xy_chart/rendering/rendering.bands.test.ts index 9deaaf8b00..f08c0fd324 100644 --- a/src/chart_types/xy_chart/rendering/rendering.bands.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.bands.test.ts @@ -28,7 +28,11 @@ describe('Rendering bands - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -78,7 +82,11 @@ describe('Rendering bands - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -216,7 +224,11 @@ describe('Rendering bands - areas', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedArea: { areaGeometry: AreaGeometry; @@ -393,7 +405,11 @@ describe('Rendering bands - areas', () => { const barSeriesMap = new Map(); barSeriesMap.set(SPEC_ID, barSeriesSpec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars', () => { diff --git a/src/chart_types/xy_chart/rendering/rendering.bars.test.ts b/src/chart_types/xy_chart/rendering/rendering.bars.test.ts index 541c516087..5c071c3370 100644 --- a/src/chart_types/xy_chart/rendering/rendering.bars.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.bars.test.ts @@ -27,7 +27,11 @@ describe('Rendering bars', () => { barSeriesMap.set(SPEC_ID, barSeriesSpec); const customDomain = [0, 1]; const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map(), customDomain); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars within domain', () => { @@ -207,7 +211,11 @@ describe('Rendering bars', () => { barSeriesMap.set(spec1Id, barSeriesSpec1); barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { @@ -392,7 +400,11 @@ describe('Rendering bars', () => { const barSeriesMap = new Map(); barSeriesMap.set(SPEC_ID, barSeriesSpec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('Can render two bars', () => { @@ -507,7 +519,11 @@ describe('Rendering bars', () => { barSeriesMap.set(spec1Id, barSeriesSpec1); barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { @@ -706,7 +722,11 @@ describe('Rendering bars', () => { barSeriesMap.set(spec1Id, barSeriesSpec1); barSeriesMap.set(spec2Id, barSeriesSpec2); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const xScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [100, 0] }); test('can render first spec bars', () => { diff --git a/src/chart_types/xy_chart/rendering/rendering.lines.test.ts b/src/chart_types/xy_chart/rendering/rendering.lines.test.ts index 41d593b8b6..1e1de5e138 100644 --- a/src/chart_types/xy_chart/rendering/rendering.lines.test.ts +++ b/src/chart_types/xy_chart/rendering/rendering.lines.test.ts @@ -28,7 +28,11 @@ describe('Rendering points - line', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; @@ -74,7 +78,11 @@ describe('Rendering points - line', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { lineGeometry: LineGeometry; @@ -180,7 +188,11 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -342,7 +354,11 @@ describe('Rendering points - line', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { @@ -447,7 +463,11 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -608,7 +628,11 @@ describe('Rendering points - line', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { @@ -713,7 +737,11 @@ describe('Rendering points - line', () => { pointSeriesMap.set(spec1Id, pointSeriesSpec1); pointSeriesMap.set(spec2Id, pointSeriesSpec2); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let firstLine: { @@ -861,7 +889,11 @@ describe('Rendering points - line', () => { const pointSeriesMap = new Map(); pointSeriesMap.set(SPEC_ID, pointSeriesSpec); const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); - const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); + const xScale = computeXScale({ + xDomain: pointSeriesDomains.xDomain, + totalBarsInCluster: pointSeriesMap.size, + range: [0, 90], + }); const yScales = computeYScales({ yDomains: pointSeriesDomains.yDomain, range: [100, 0] }); let renderedLine: { diff --git a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts index 431153f9cb..1a7daff38a 100644 --- a/src/chart_types/xy_chart/store/chart_state.interactions.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.interactions.test.ts @@ -221,7 +221,11 @@ function mouseOverTestSuite(scaleType: ScaleType) { const barSeriesMap = new Map(); barSeriesMap.set(SPEC_ID, spec); const barSeriesDomains = computeSeriesDomains(barSeriesMap, new Map()); - const barSeriesScale = computeXScale(barSeriesDomains.xDomain, barSeriesMap.size, 0, 100); + const barSeriesScale = computeXScale({ + xDomain: barSeriesDomains.xDomain, + totalBarsInCluster: barSeriesMap.size, + range: [0, 100], + }); const yScales = computeYScales({ yDomains: barSeriesDomains.yDomain, range: [0, 100] }); store.xScale = barSeriesScale; store.yScales = yScales; diff --git a/src/chart_types/xy_chart/store/utils.ts b/src/chart_types/xy_chart/store/utils.ts index ceb14173a1..87c7f8779e 100644 --- a/src/chart_types/xy_chart/store/utils.ts +++ b/src/chart_types/xy_chart/store/utils.ts @@ -215,7 +215,7 @@ export function computeSeriesGeometries( const { stackedBarsInCluster, totalBarsInCluster } = countBarsInCluster(stacked, nonStacked); // compute scales - const xScale = computeXScale(xDomain, totalBarsInCluster, 0, width, barsPadding, enableHistogramMode); + const xScale = computeXScale({ xDomain, totalBarsInCluster, range: [0, width], barsPadding, enableHistogramMode }); const yScales = computeYScales({ yDomains: yDomain, range: [height, 0] }); // compute colors diff --git a/src/chart_types/xy_chart/utils/axis_utils.ts b/src/chart_types/xy_chart/utils/axis_utils.ts index 2e3421fc02..31f698f2eb 100644 --- a/src/chart_types/xy_chart/utils/axis_utils.ts +++ b/src/chart_types/xy_chart/utils/axis_utils.ts @@ -126,15 +126,22 @@ export function getScaleForAxisSpec( enableHistogramMode?: boolean, ): Scale | null { const axisIsYDomain = isYDomain(axisSpec.position, chartRotation); - + const range: [number, number] = [minRange, maxRange]; if (axisIsYDomain) { - const yScales = computeYScales({ yDomains: yDomain, range: [minRange, maxRange], ticks: axisSpec.ticks }); + const yScales = computeYScales({ yDomains: yDomain, range, ticks: axisSpec.ticks }); if (yScales.has(axisSpec.groupId)) { return yScales.get(axisSpec.groupId)!; } return null; } else { - return computeXScale(xDomain, totalBarsInCluster, minRange, maxRange, barsPadding, enableHistogramMode); + return computeXScale({ + xDomain, + totalBarsInCluster, + range, + barsPadding, + enableHistogramMode, + ticks: axisSpec.ticks, + }); } } diff --git a/src/chart_types/xy_chart/utils/scales.test.ts b/src/chart_types/xy_chart/utils/scales.test.ts index 9b621c540d..5c909d09cc 100644 --- a/src/chart_types/xy_chart/utils/scales.test.ts +++ b/src/chart_types/xy_chart/utils/scales.test.ts @@ -22,7 +22,7 @@ describe('Series scales', () => { }; test('should compute X Scale linear min, max with bands', () => { - const scale = computeXScale(xDomainLinear, 1, 0, 120); + const scale = computeXScale({ xDomain: xDomainLinear, totalBarsInCluster: 1, range: [0, 120] }); const expectedBandwidth = 120 / 4; expect(scale.bandwidth).toBe(expectedBandwidth); expect(scale.scale(0)).toBe(expectedBandwidth * 0); @@ -32,7 +32,7 @@ describe('Series scales', () => { }); test('should compute X Scale linear inverse min, max with bands', () => { - const scale = computeXScale(xDomainLinear, 1, 120, 0); + const scale = computeXScale({ xDomain: xDomainLinear, totalBarsInCluster: 1, range: [120, 0] }); const expectedBandwidth = 120 / 4; expect(scale.bandwidth).toBe(expectedBandwidth); expect(scale.scale(0)).toBe(expectedBandwidth * 3); @@ -56,7 +56,13 @@ describe('Series scales', () => { }; const enableHistogramMode = true; - const scale = computeXScale(xDomainSingleValue, 1, 0, maxRange, 0, enableHistogramMode); + const scale = computeXScale({ + xDomain: xDomainSingleValue, + totalBarsInCluster: 1, + range: [0, maxRange], + barsPadding: 0, + enableHistogramMode, + }); expect(scale.bandwidth).toBe(maxRange); expect(scale.domain).toEqual([singleDomainValue, singleDomainValue + minInterval]); expect(scale.range).toEqual([0, maxRange]); @@ -72,7 +78,13 @@ describe('Series scales', () => { }; const enableHistogramMode = false; - const scale = computeXScale(xDomainSingleValue, 1, 0, maxRange, 0, enableHistogramMode); + const scale = computeXScale({ + xDomain: xDomainSingleValue, + totalBarsInCluster: 1, + range: [0, maxRange], + barsPadding: 0, + enableHistogramMode, + }); expect(scale.bandwidth).toBe(maxRange); expect(scale.domain).toEqual([singleDomainValue, singleDomainValue]); expect(scale.range).toEqual([0, 0]); @@ -80,13 +92,13 @@ describe('Series scales', () => { }); test('should compute X Scale ordinal', () => { - const nonZeroGroupScale = computeXScale(xDomainOrdinal, 1, 120, 0); + const nonZeroGroupScale = computeXScale({ xDomain: xDomainOrdinal, totalBarsInCluster: 1, range: [120, 0] }); const expectedBandwidth = 60; expect(nonZeroGroupScale.bandwidth).toBe(expectedBandwidth); expect(nonZeroGroupScale.scale('a')).toBe(expectedBandwidth); expect(nonZeroGroupScale.scale('b')).toBe(0); - const zeroGroupScale = computeXScale(xDomainOrdinal, 0, 120, 0); + const zeroGroupScale = computeXScale({ xDomain: xDomainOrdinal, totalBarsInCluster: 0, range: [120, 0] }); expect(zeroGroupScale.bandwidth).toBe(expectedBandwidth); }); diff --git a/src/chart_types/xy_chart/utils/scales.ts b/src/chart_types/xy_chart/utils/scales.ts index 12ddb051a5..afa529a9bd 100644 --- a/src/chart_types/xy_chart/utils/scales.ts +++ b/src/chart_types/xy_chart/utils/scales.ts @@ -55,27 +55,30 @@ function getBandScaleRange( return { start, end }; } +interface XScaleOptions { + xDomain: XDomain; + totalBarsInCluster: number; + range: [number, number]; + barsPadding?: number; + enableHistogramMode?: boolean; + ticks?: number; +} + /** * Compute the x scale used to align geometries to the x axis. * @param xDomain the x domain * @param totalBarsInCluster the total number of grouped series * @param axisLength the length of the x axis */ -export function computeXScale( - xDomain: XDomain, - totalBarsInCluster: number, - minRange: number, - maxRange: number, - barsPadding?: number, - enableHistogramMode?: boolean, -): Scale { +export function computeXScale(options: XScaleOptions): Scale { + const { xDomain, totalBarsInCluster, range, barsPadding, enableHistogramMode, ticks } = options; const { scaleType, minInterval, domain, isBandScale, timeZone } = xDomain; - const rangeDiff = Math.abs(maxRange - minRange); - const isInverse = maxRange < minRange; + const rangeDiff = Math.abs(range[1] - range[0]); + const isInverse = range[1] < range[0]; if (scaleType === ScaleType.Ordinal) { const dividend = totalBarsInCluster > 0 ? totalBarsInCluster : 1; const bandwidth = rangeDiff / (domain.length * dividend); - return new ScaleBand(domain, [minRange, maxRange], bandwidth, barsPadding); + return new ScaleBand(domain, range, bandwidth, barsPadding); } else { if (isBandScale) { const [domainMin, domainMax] = domain; @@ -87,7 +90,7 @@ export function computeXScale( const intervalCount = (adjustedDomain[1] - adjustedDomain[0]) / minInterval; const intervalCountOffest = isSingleValueHistogram ? 0 : 1; const bandwidth = rangeDiff / (intervalCount + intervalCountOffest); - const { start, end } = getBandScaleRange(isInverse, isSingleValueHistogram, minRange, maxRange, bandwidth); + const { start, end } = getBandScaleRange(isInverse, isSingleValueHistogram, range[0], range[1], bandwidth); const scale = new ScaleContinuous( { @@ -95,14 +98,14 @@ export function computeXScale( domain: adjustedDomain, range: [start, end], }, - { bandwidth: bandwidth / totalBarsInCluster, minInterval, timeZone, totalBarsInCluster, barsPadding }, + { bandwidth: bandwidth / totalBarsInCluster, minInterval, timeZone, totalBarsInCluster, barsPadding, ticks }, ); return scale; } else { return new ScaleContinuous( - { type: scaleType, domain, range: [minRange, maxRange] }, - { bandwidth: 0, minInterval, timeZone, totalBarsInCluster, barsPadding }, + { type: scaleType, domain, range }, + { bandwidth: 0, minInterval, timeZone, totalBarsInCluster, barsPadding, ticks }, ); } } diff --git a/src/utils/scales/scale_continuous.test.ts b/src/utils/scales/scale_continuous.test.ts index 3e97941151..a18e147ef0 100644 --- a/src/utils/scales/scale_continuous.test.ts +++ b/src/utils/scales/scale_continuous.test.ts @@ -78,7 +78,7 @@ describe('Scale Continuous', () => { type: 'xDomain', }; - const scaleLinear = computeXScale(xDomain, 1, 0, 120, 0); + const scaleLinear = computeXScale({ xDomain, totalBarsInCluster: 1, range: [0, 120], barsPadding: 0 }); expect(scaleLinear.bandwidth).toBe(40); expect(scaleLinear.invertWithStep(0, data)).toBe(0); expect(scaleLinear.invertWithStep(40, data)).toBe(1); @@ -120,7 +120,7 @@ describe('Scale Continuous', () => { type: 'xDomain', }; - const scaleLinear = computeXScale(xDomain, 1, 0, 110, 0); + const scaleLinear = computeXScale({ xDomain, totalBarsInCluster: 1, range: [0, 110], barsPadding: 0 }); // const scaleLinear = new ScaleContinuous({type: ScaleType.Linear, domain, range}, 10, 10); expect(scaleLinear.bandwidth).toBe(10); diff --git a/stories/axis.tsx b/stories/axis.tsx index 1a896674f4..c90b262974 100644 --- a/stories/axis.tsx +++ b/stories/axis.tsx @@ -64,7 +64,7 @@ storiesOf('Axis', module) step: 1, }), }; - const data = KIBANA_METRICS.metrics.kibana_os_load[0].data.slice(0, 30); + const data = KIBANA_METRICS.metrics.kibana_os_load[0].data.slice(0, 60); return ( @@ -73,7 +73,7 @@ storiesOf('Axis', module) position={Position.Bottom} title={'Bottom axis'} style={customStyle} - showOverlappingLabels={boolean('Bottom overlap labels', true, 'Bottom Axis')} + showOverlappingLabels={boolean('Bottom overlap labels', false, 'Bottom Axis')} showOverlappingTicks={boolean('Bottom overlap ticks', true, 'Bottom Axis')} ticks={number( 'Number of ticks on bottom', @@ -94,7 +94,7 @@ storiesOf('Axis', module) position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} style={customStyle} - showOverlappingLabels={boolean('Left overlap labels', true, 'Left Axis')} + showOverlappingLabels={boolean('Left overlap labels', false, 'Left Axis')} showOverlappingTicks={boolean('Left overlap ticks', true, 'Left Axis')} ticks={number( 'Number of ticks on left', From 8406289d173b2c661677c9498ed47772c045f3ea Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Fri, 16 Aug 2019 23:51:48 +0200 Subject: [PATCH 4/4] fix: fix opacity for horizontal axis debug rect --- src/components/react_canvas/axis.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/react_canvas/axis.tsx b/src/components/react_canvas/axis.tsx index 7483ce766d..72157ce7de 100644 --- a/src/components/react_canvas/axis.tsx +++ b/src/components/react_canvas/axis.tsx @@ -220,6 +220,7 @@ export class Axis extends React.PureComponent { stroke="black" strokeWidth={1} fill="violet" + opacity={0.2} /> )}