-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Refactoring: Adapt getTicks to increase reusability of code #3393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f9300ae
0d036db
8be78fe
870db7e
28384be
c8cd40e
5687ab1
f237c59
73ef784
6673d05
788c725
9bca9b1
bb57619
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { CartesianTickItem } from '../../util/types'; | ||
|
|
||
| /** | ||
| * Given an array and a number N, return a new array which contains every nTh | ||
| * element of the input array. For n below 1, an empty array is returned. | ||
| * @param {T[]} array An input array. | ||
| * @param {integer} n A number | ||
| * @returns {T[]} The result array of the same type as the input array. | ||
| */ | ||
| function getEveryNth<Type>(array: Type[], n: number): Type[] { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be on it's own. Maybe in something like
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this isn't 'tick' specific per se. Also if we're going to move to different naming conventions for We'll end up having files in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find that things should be as close to their usage as possible. If used all across the places, a top level utils folder makes sense. But if used only within CartesianAxis, I would argue that is where it should live. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now it's only used in CartesianAxis. But when the need for the functionality comes along outside of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough. For consistency I will move it back to a shared utils. |
||
| if (n < 1) { | ||
| return []; | ||
| } | ||
| if (n === 1) { | ||
| return array; | ||
| } | ||
| const result = []; | ||
| for (let i = 0; i < array.length; i += n) { | ||
| result.push(array[i]); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| export function getNumberIntervalTicks(ticks: CartesianTickItem[], interval: number) { | ||
| return getEveryNth(ticks, interval + 1); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { getTicks } from '../../src/cartesian/TickUtils'; | ||
| import { getTicks } from '../../../src/cartesian/ticks/getTicks'; | ||
|
|
||
| const EXAMPLE_INPUT = { | ||
| axisLine: true, | ||
|
|
@@ -14,11 +14,12 @@ const EXAMPLE_INPUT = { | |
| tickMargin: 2, | ||
| tickSize: 6, | ||
| ticks: [ | ||
| { value: 10, coordinate: 50 }, | ||
| { value: 1000, coordinate: 100 }, | ||
| { value: 20, coordinate: 150 }, | ||
| { value: 40, coordinate: 200 }, | ||
| { value: 90, coordinate: 250 }, | ||
| { value: '10', coordinate: 50 }, | ||
| { value: '1000', coordinate: 100 }, | ||
| { value: '20', coordinate: 150 }, | ||
| { value: '40', coordinate: 200 }, | ||
| { value: '90', coordinate: 250 }, | ||
| { value: 'A', coordinate: 300 }, | ||
| ], | ||
| length: 5, | ||
| viewBox: { x: 0, y: 0, width: 500, height: 500 }, | ||
|
|
@@ -27,9 +28,9 @@ const EXAMPLE_INPUT = { | |
| y: 100, | ||
| }; | ||
|
|
||
| jest.mock('../../src/util/DOMUtils', () => ({ | ||
| jest.mock('../../../src/util/DOMUtils', () => ({ | ||
| // We mock string size measurement, because getStringSize else returns 0 in these tests. | ||
| getStringSize: jest.fn(() => ({ width: 20, height: 20 })), | ||
| getStringSize: jest.fn((text: string) => ({ width: text.length, height: 20 })), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this adds any indication of actual text length. Better maybe than no variation, but certainly not accurate.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, but this enables me to test with larger labels on different positions (i.e. first tick, second tick, third tick, etc.) |
||
| })); | ||
|
|
||
| // These tests have been generated by merely documenting existing behaviour. | ||
|
|
@@ -42,11 +43,12 @@ describe('getTicks', () => { | |
| const result = getTicks(input); | ||
|
|
||
| expect(result).toEqual([ | ||
| { value: 10, coordinate: 50, tickCoord: 50, isShow: true }, | ||
| { value: 1000, coordinate: 100, tickCoord: 100, isShow: true }, | ||
| { value: 20, coordinate: 150, tickCoord: 150, isShow: true }, | ||
| { value: 40, coordinate: 200, tickCoord: 200, isShow: true }, | ||
| { value: 90, coordinate: 250, tickCoord: 250, isShow: true }, | ||
| { value: '10', coordinate: 50, tickCoord: 50, isShow: true }, | ||
| { value: '1000', coordinate: 100, tickCoord: 100, isShow: true }, | ||
| { value: '20', coordinate: 150, tickCoord: 150, isShow: true }, | ||
| { value: '40', coordinate: 200, tickCoord: 200, isShow: true }, | ||
| { value: '90', coordinate: 250, tickCoord: 250, isShow: true }, | ||
| { value: 'A', coordinate: 300, tickCoord: 300, isShow: true }, | ||
| ]); | ||
| }); | ||
|
|
||
|
|
@@ -56,16 +58,17 @@ describe('getTicks', () => { | |
| const result = getTicks(input); | ||
|
|
||
| expect(result).toEqual([ | ||
| { value: 10, coordinate: 50, tickCoord: 50, isShow: true }, | ||
| { value: 1000, coordinate: 100, tickCoord: 100, isShow: true }, | ||
| { value: 20, coordinate: 150, tickCoord: 150, isShow: true }, | ||
| { value: 40, coordinate: 200, tickCoord: 200, isShow: true }, | ||
| { value: 90, coordinate: 250, tickCoord: 250, isShow: true }, | ||
| { value: '10', coordinate: 50, tickCoord: 50, isShow: true }, | ||
| { value: '1000', coordinate: 100, tickCoord: 100, isShow: true }, | ||
| { value: '20', coordinate: 150, tickCoord: 150, isShow: true }, | ||
| { value: '40', coordinate: 200, tickCoord: 200, isShow: true }, | ||
| { value: '90', coordinate: 250, tickCoord: 250, isShow: true }, | ||
| { value: 'A', coordinate: 300, tickCoord: 300, isShow: true }, | ||
| ]); | ||
| }); | ||
| }); | ||
|
|
||
| describe('If not all ticks can be shown, the interval is respected', () => { | ||
| describe('The interval is respected', () => { | ||
| const viewBoxWithSmallWidth = { x: 0, y: 0, width: 30, height: 500 }; | ||
|
|
||
| test.each([ | ||
|
|
@@ -74,7 +77,7 @@ describe('getTicks', () => { | |
| [ | ||
| { | ||
| coordinate: 50, | ||
| value: 10, | ||
| value: '10', | ||
| }, | ||
| ], | ||
| ], | ||
|
|
@@ -83,11 +86,11 @@ describe('getTicks', () => { | |
| [ | ||
| { | ||
| coordinate: 50, | ||
| value: 10, | ||
| value: '10', | ||
| }, | ||
| { | ||
| coordinate: 200, | ||
| value: 40, | ||
| value: '40', | ||
| }, | ||
| ], | ||
| ], | ||
|
|
@@ -96,15 +99,15 @@ describe('getTicks', () => { | |
| [ | ||
| { | ||
| coordinate: 50, | ||
| value: 10, | ||
| value: '10', | ||
| }, | ||
| { | ||
| coordinate: 150, | ||
| value: 20, | ||
| value: '20', | ||
| }, | ||
| { | ||
| coordinate: 250, | ||
| value: 90, | ||
| value: '90', | ||
| }, | ||
| ], | ||
| ], | ||
|
|
@@ -113,34 +116,38 @@ describe('getTicks', () => { | |
| [ | ||
| { | ||
| coordinate: 50, | ||
| value: 10, | ||
| value: '10', | ||
| }, | ||
| { | ||
| coordinate: 100, | ||
| value: 1000, | ||
| value: '1000', | ||
| }, | ||
| { | ||
| coordinate: 150, | ||
| value: 20, | ||
| value: '20', | ||
| }, | ||
| { | ||
| coordinate: 200, | ||
| value: 40, | ||
| value: '40', | ||
| }, | ||
| { | ||
| coordinate: 250, | ||
| value: 90, | ||
| value: '90', | ||
| }, | ||
| { | ||
| coordinate: 300, | ||
| value: 'A', | ||
| }, | ||
| ], | ||
| ], | ||
| [ | ||
| 'preserveStartEnd' as const, | ||
| [ | ||
| { | ||
| coordinate: 250, | ||
| coordinate: 300, | ||
| isShow: true, | ||
| tickCoord: 20, | ||
| value: 90, | ||
| tickCoord: 29.5, | ||
| value: 'A', | ||
| }, | ||
| ], | ||
| ], | ||
|
|
@@ -149,25 +156,15 @@ describe('getTicks', () => { | |
| 'preserveEnd' as const, | ||
| [ | ||
| { | ||
| coordinate: 250, | ||
| coordinate: 300, | ||
| isShow: true, | ||
| tickCoord: 20, | ||
| value: 90, | ||
| tickCoord: 29.5, | ||
| value: 'A', | ||
| }, | ||
| ], | ||
| ], | ||
| [-1, []], | ||
| [ | ||
| undefined, | ||
| [ | ||
| { | ||
| coordinate: 250, | ||
| isShow: true, | ||
| tickCoord: 20, | ||
| value: 90, | ||
| }, | ||
| ], | ||
| ], | ||
| [undefined, [{ coordinate: 300, isShow: true, tickCoord: 29.5, value: 'A' }]], | ||
| ])(`interval %s works`, (interval, expectedResult) => { | ||
| const input = { | ||
| ...EXAMPLE_INPUT, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My personal preference is for the early returns as in before the changes, but since you moved the isShow filtering here it makes sense to try and reduce code duplication.
However it could also make sense that to not stop here but create and use an additional layer like
But then you have to go and change every usage of getTicks to keep existing behaviour (and it probably does not work too well with the following PR?).
Alternatively, if we would want to go one step further in reducing code duplication we could introduce a holder for these like
and then just
to
get rid ofhide the branching altogetherThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the ideas, and will most probably come back to them - but only when following up with this file after landing the feature enhancement. For now I want to only refactor as much as I need to, in order to nicely implement the equidistant ticks.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the following PR this also has the benefit that adding the new option is just
instead of essentially adding back the duplicated code that this PR removed. With that context I would argue even more so that the conditions should still be separate and not share the branch for 'preserveStart' and 'preserveStartEnd'.