UNPKG

@gooddata/react-components

Version:

GoodData.UI - A powerful JavaScript library for building analytical applications

586 lines (538 loc) • 20.3 kB
// (C) 2019 GoodData Corporation import { adjustTicks, ALIGNED, alignToBaseAxis, customAdjustTickAmount, getDirection, getSelectionRange, getYAxisScore, MOVE_ZERO_LEFT, MOVE_ZERO_RIGHT, preventDataCutOff, shouldBeHandledByHighcharts, Y_AXIS_SCORE, } from "../adjustTickAmount"; import { IHighchartsAxisExtend } from "../../../../../../interfaces/HighchartsExtend"; import { VisualizationTypes } from "../../../../../../constants/visualizationTypes"; describe("adjustTickAmount - general", () => { const Y_AXIS = { hasData: () => true, coll: "yAxis", options: { startOnTick: true, endOnTick: true, }, }; it("should not adjust tick on no-data axis", () => { const axis: IHighchartsAxisExtend = { hasData: () => false, }; const result = customAdjustTickAmount.call(axis); expect(result).toBeFalsy(); }); describe("should adjust tick amount without user-input min/max", () => { const chart: any = { axes: [], userOptions: { yAxis: [{ isUserMinMax: false }, { isUserMinMax: false }], }, }; // min/max are calculated in 'getZeroAlignConfiguration' const getLeftAxis = () => ({ ...Y_AXIS, chart, tickAmount: 8, tickInterval: 300, tickPositions: [-1200, -900, -600, -300, 0, 300, 600, 900, 1200], // 9 ticks opposite: false, dataMin: 137, dataMax: 986, min: -986, max: 986, }); const getRightAxis = () => ({ ...Y_AXIS, chart, tickAmount: 8, tickInterval: 3000, tickPositions: [-12000, -9000, -6000, -3000, 0, 3000, 6000, 9000, 12000], // 9 ticks opposite: true, dataMin: -8895, dataMax: -1239, min: -8895, max: 8895, }); it.each([ ["left", getLeftAxis(), [-900, -600, -300, 0, 300, 600, 900, 1200]], // reduced to 8 ticks ["right", getRightAxis(), [-12000, -9000, -6000, -3000, 0, 3000, 6000, 9000]], // reduced to 8 ticks ])( "should return %s tick positions aligned zero with opposite", (_side: string, axis: IHighchartsAxisExtend, expectation: number) => { customAdjustTickAmount.call(axis); expect(axis.tickPositions).toEqual(expectation); }, ); it.each([["left", getLeftAxis(), -900, 1200], ["right", getRightAxis(), -12000, 9000]])( "should min/max be updated on %s axis", (_side: string, axis: IHighchartsAxisExtend, min: number, max: number) => { customAdjustTickAmount.call(axis); expect(axis.min).toBe(min); expect(axis.max).toBe(max); }, ); }); describe("should adjust tick amount with user-input min/max", () => { const chart: any = { axes: [], userOptions: { yAxis: [{ isUserMinMax: true }, { isUserMinMax: true }], }, }; const leftAxis = { ...Y_AXIS, chart, tickAmount: 8, tickInterval: 15, tickPositions: [-90, -75, -60, -45, -30, -15, 0], // 7 ticks opposite: false, dataMin: -656, dataMax: 986, min: -100, max: 0, }; const rightAxis = { ...Y_AXIS, chart, tickAmount: 8, tickInterval: 800, tickPositions: [-4800, -4000, -3200, -2400, -1600, -800, 0], // 7 ticks opposite: true, dataMin: -8895, dataMax: 7661, min: 0, max: -4500, }; beforeAll(() => { chart.axes = [leftAxis, rightAxis]; customAdjustTickAmount.call(leftAxis); customAdjustTickAmount.call(rightAxis); }); it.each([ ["left", leftAxis, [-105, -90, -75, -60, -45, -30, -15, 0]], // adjusted to 8 ticks ["right", rightAxis, [-5600, -4800, -4000, -3200, -2400, -1600, -800, 0]], // adjusted to 8 ticks ])( "should return %s tick positions aligned zero with opposite", (_side: string, axis: IHighchartsAxisExtend, expectation: number) => { expect(axis.tickPositions).toEqual(expectation); }, ); it.each([["left", leftAxis, -105, 0], ["right", rightAxis, -5600, 0]])( "should min/max be updated on %s axis", (_side: string, axis: IHighchartsAxisExtend, min: number, max: number) => { expect(axis.min).toBe(min); expect(axis.max).toBe(max); }, ); it("should two axes be zero aligned", () => { expect(leftAxis.tickPositions.indexOf(0)).toBe(rightAxis.tickPositions.indexOf(0)); }); }); }); describe("adjustTickAmount - detail", () => { describe("adjustTicks", () => { it("should not adjust any tick", () => { const axis: IHighchartsAxisExtend = { tickAmount: 1, tickPositions: [100], }; expect(adjustTicks(axis)).toBeFalsy(); }); it("should add tick with negative data", () => { const axis: IHighchartsAxisExtend = { tickInterval: 10, tickAmount: 3, tickPositions: [-20, -10], dataMin: -20, dataMax: -10, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([-30, -20, -10]); }); it("should add tick with negative data and positive min/max", () => { // tick should be added with direction from data set const axis: IHighchartsAxisExtend = { tickInterval: 5, tickAmount: 3, tickPositions: [10, 15], min: 5, max: 15, dataMin: -20, dataMax: -10, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([5, 10, 15]); }); it("should add tick with positive data", () => { const axis: IHighchartsAxisExtend = { tickInterval: 10, tickAmount: 3, tickPositions: [10, 20], dataMin: 10, dataMax: 20, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([10, 20, 30]); }); it("should add tick to first with negative-to-positive data and negative min/max", () => { // tick should be added with direction from data set const axis: IHighchartsAxisExtend = { tickInterval: 5, tickAmount: 3, tickPositions: [-15, -10], min: -20, max: -10, dataMin: -10, dataMax: 20, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([-20, -15, -10]); }); it("should add tick to end with negative-to-positive data and positive min/max", () => { // tick should be added with direction from data set const axis: IHighchartsAxisExtend = { tickInterval: 5, tickAmount: 3, tickPositions: [-15, -10], min: 20, max: 10, dataMin: -10, dataMax: 20, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([-15, -10, -5]); }); it("should add tick to last where min starts from 0", () => { const axis: IHighchartsAxisExtend = { tickInterval: 50, tickAmount: 4, tickPositions: [0, 50, 100], dataMin: -50, dataMax: 200, min: 0, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([0, 50, 100, 150]); }); it("should add tick to first by default", () => { const axis: IHighchartsAxisExtend = { tickInterval: 100, tickAmount: 3, tickPositions: [-50, 50], }; adjustTicks(axis); expect(axis.tickPositions).toEqual([-150, -50, 50]); }); it("should reduce tick at the start", () => { const axis: IHighchartsAxisExtend = { tickInterval: 100, tickAmount: 3, tickPositions: [0, 100, 200, 300, 400], dataMin: 50, dataMax: 350, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([200, 300, 400]); }); it("should reduce tick at the end", () => { const axis: IHighchartsAxisExtend = { tickInterval: 100, tickAmount: 3, tickPositions: [-400, -300, -200, -100, 0], dataMin: -350, dataMax: -50, }; adjustTicks(axis); expect(axis.tickPositions).toEqual([-400, -300, -200]); }); }); describe("alignToBaseAxis", () => { it("should not handle base axis", () => { const leftAxis: IHighchartsAxisExtend = { opposite: false, tickPositions: [-2, -1, 0, 1, 2, 3], chart: {}, }; const rightAxis: IHighchartsAxisExtend = { opposite: true, tickPositions: [-200, -100, 0, 100, 200, 300], chart: {}, }; expect(alignToBaseAxis(leftAxis, rightAxis)).toBeFalsy(); }); it("should do nothing with aligned axes", () => { const leftAxis: IHighchartsAxisExtend = { opposite: false, tickPositions: [-2, -1, 0, 1, 2, 3], chart: {}, }; const rightAxis: IHighchartsAxisExtend = { opposite: true, tickPositions: [-200, -100, 0, 100, 200, 300], chart: {}, }; alignToBaseAxis(leftAxis, rightAxis); expect(rightAxis.tickPositions).toEqual([-200, -100, 0, 100, 200, 300]); }); it("should zero move right on right axis", () => { const leftAxis: IHighchartsAxisExtend = { coll: "yAxis", opposite: false, tickPositions: [-2, -1, 0, 1, 2, 3], chart: {}, }; const rightAxis: IHighchartsAxisExtend = { coll: "yAxis", opposite: true, tickInterval: 100, tickPositions: [0, 100, 200, 300, 400, 500], chart: {}, }; alignToBaseAxis(rightAxis, leftAxis); expect(rightAxis.tickPositions).toEqual([-200, -100, 0, 100, 200, 300]); expect(leftAxis.tickPositions).toEqual([-2, -1, 0, 1, 2, 3]); }); it("should zero move left on right axis", () => { const leftAxis: IHighchartsAxisExtend = { coll: "yAxis", opposite: false, tickPositions: [-2, -1, 0, 1, 2, 3], chart: {}, }; const rightAxis: IHighchartsAxisExtend = { coll: "yAxis", opposite: true, tickInterval: 100, tickPositions: [-400, -300, -200, -100, 0, 100], chart: {}, }; alignToBaseAxis(rightAxis, leftAxis); expect(rightAxis.tickPositions).toEqual([-200, -100, 0, 100, 200, 300]); expect(leftAxis.tickPositions).toEqual([-2, -1, 0, 1, 2, 3]); }); }); describe("preventDataCutOff", () => { it("should not run with chart having user-input min/max", () => { const axis = { opposite: true, chart: { userOptions: { yAxis: [{ isUserMinMax: true }, { isUserMinMax: true }], }, }, }; expect(preventDataCutOff(axis)).toBeFalsy(); }); it("should not run with non-cut-off chart", () => { const axis = { opposite: true, chart: { userOptions: { yAxis: [{ isUserMinMax: false }, { isUserMinMax: false }], }, }, min: 0, max: 100, dataMin: 10, dataMax: 90, }; expect(preventDataCutOff(axis)).toBeFalsy(); }); it("should double tick interval and tick positions to zoom out axis", () => { const axis = { opposite: true, options: { startOnTick: true, endOnTick: true, }, chart: { userOptions: { yAxis: [{ isUserMinMax: false }, { isUserMinMax: false }], }, }, min: 20, max: 80, dataMin: 10, dataMax: 90, tickInterval: 10, tickPositions: [0, 10, 20, 30, 40], }; preventDataCutOff(axis); expect(axis.min).toBe(0); expect(axis.max).toBe(80); expect(axis.tickInterval).toBe(20); expect(axis.tickPositions).toEqual([0, 20, 40, 60, 80]); }); }); describe("shouldBeHandledByHighcharts", () => { it("should let Highcharts handle X axis", () => { const xAxis = { coll: "xAxis", }; expect(shouldBeHandledByHighcharts(xAxis)).toBeTruthy(); }); it("should let Highcharts handle single Y", () => { const yAxis = { coll: "yAxis", chart: { axes: [ { coll: "yAxis", }, ], }, }; expect(shouldBeHandledByHighcharts(yAxis)).toBeTruthy(); }); it("should let Highcharts handle line chart", () => { const yAxis: Partial<IHighchartsAxisExtend> = { coll: "yAxis", series: [], chart: { axes: [ { coll: "yAxis", }, { coll: "yAxis", }, ], userOptions: { chart: { type: VisualizationTypes.LINE, }, }, }, }; expect(shouldBeHandledByHighcharts(yAxis)).toBeTruthy(); }); it("should let Highcharts handle combo line-line chart", () => { const yAxis = { coll: "yAxis", series: [ { type: VisualizationTypes.LINE, }, ], chart: { axes: [ { coll: "yAxis", }, { coll: "yAxis", }, ], }, }; // use cast here because mock object does not have enough required props expect(shouldBeHandledByHighcharts(yAxis as Partial<IHighchartsAxisExtend>)).toBeTruthy(); }); it("should let Highcharts handle if any Y axis is disable", () => { const yAxis: Partial<IHighchartsAxisExtend> = { coll: "yAxis", series: [], chart: { axes: [ { coll: "yAxis", visible: false, }, { coll: "yAxis", }, ], }, }; expect(shouldBeHandledByHighcharts(yAxis)).toBeTruthy(); }); }); describe("getYAxisScore", () => { it.each([ [Y_AXIS_SCORE.NO_DATA, 0, 0], [Y_AXIS_SCORE.ONLY_NEGATIVE_OR_POSITIVE_DATA, 5, 10], [Y_AXIS_SCORE.ONLY_NEGATIVE_OR_POSITIVE_DATA, -10, -5], [Y_AXIS_SCORE.NEGATIVE_AND_POSITIVE_DATA, -10, 10], ])("should score equal to %s", (score: number, dataMin: number, dataMax: number) => { const axis: IHighchartsAxisExtend = { dataMin, dataMax, }; expect(getYAxisScore(axis)).toBe(score); }); }); describe("getDirection", () => { it.each([["left", null, {}], ["right", {}, null]])( "should return ALIGN when %s axis is null", (_axisSide: string, primaryAxis: IHighchartsAxisExtend, secondaryAxis: IHighchartsAxisExtend) => { expect(getDirection(primaryAxis, secondaryAxis)).toBe(ALIGNED); }, ); it("should return ALIGN when both axes are empty", () => { const axis: IHighchartsAxisExtend = { tickPositions: [] }; expect(getDirection(axis, axis)).toBe(ALIGNED); }); it("should return ALIGN when both axes are aligned", () => { const axis: IHighchartsAxisExtend = { tickPositions: [-2, -1, 0, 1, 2] }; expect(getDirection(axis, axis)).toBe(ALIGNED); }); it("should return MOVE_ZERO_RIGHT", () => { const primaryAxis: IHighchartsAxisExtend = { tickPositions: [-2, -1, 0, 1, 2] }; const secondaryAxis: IHighchartsAxisExtend = { tickPositions: [-1, 0, 1, 2, 3] }; expect(getDirection(primaryAxis, secondaryAxis)).toBe(MOVE_ZERO_RIGHT); }); it("should return MOVE_ZERO_LEFT", () => { const primaryAxis: IHighchartsAxisExtend = { tickPositions: [-2, -1, 0, 1, 2] }; const secondaryAxis: IHighchartsAxisExtend = { tickPositions: [-3, -2, -1, 0, 1] }; expect(getDirection(primaryAxis, secondaryAxis)).toBe(MOVE_ZERO_LEFT); }); }); describe("getSelectionRange", () => { it("should return range with data min >= 0", () => { const axis: IHighchartsAxisExtend = { dataMin: 10, dataMax: 50, tickAmount: 4, tickPositions: [0, 20, 40, 60, 80], }; expect(getSelectionRange(axis)).toEqual([1, 5]); }); it("should return range with data max <= 0", () => { const axis: IHighchartsAxisExtend = { dataMin: -50, dataMax: -10, tickAmount: 4, tickPositions: [-80, -60, -40, -20, 0], }; expect(getSelectionRange(axis)).toEqual([0, 4]); }); it("should return range trimmed from negative", () => { const axis: IHighchartsAxisExtend = { dataMin: -70, dataMax: 30, tickAmount: 6, tickPositions: [-80, -60, -40, -20, 0, 20, 40], }; expect(getSelectionRange(axis)).toEqual([1, 7]); }); it("should return range trimmed from positive", () => { const axis: IHighchartsAxisExtend = { dataMin: -30, dataMax: 70, tickAmount: 6, tickPositions: [-40, -20, 0, 20, 40, 60, 80], }; expect(getSelectionRange(axis)).toEqual([0, 6]); }); }); });