-
Notifications
You must be signed in to change notification settings - Fork 121
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
feat(axis): option to hide duplicate axes #370
feat(axis): option to hide duplicate axes #370
Conversation
* Option to hide axes based on tick labels, position and title. * Refactor axes render function. closes elastic#368
Codecov Report
@@ Coverage Diff @@
## master #370 +/- ##
=========================================
Coverage ? 98.25%
=========================================
Files ? 38
Lines ? 2801
Branches ? 661
=========================================
Hits ? 2752
Misses ? 44
Partials ? 5
Continue to review full report at Codecov.
|
|
||
let hasDuplicate = false; | ||
tickMap.forEach(({ tickLabels: axisTickLabels }, axisId) => { | ||
if ( |
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.
Instead of a let hasDuplicate
and forEach
, let's use a tickmap.some(...)
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.
Ya would totally agree unfortunately this is a Map
not an Array
which doesn't have the some
prototype. 😞
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.
Ah indeed! We could do tickMap.keys().some(...)
tickMap.entries().some(...)
but these would already visit all elements; a for
or while
loop feeding from an iterator could bail early but probably not worth the hassle.
@@ -844,6 +845,35 @@ export class ChartStore { | |||
this.annotationSpecs.delete(annotationId); | |||
} | |||
|
|||
isDuplicateAxis( |
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.
On an initial look, this method isn't using this
, it would be better to turn it into a regular function const isDuplicateAxis = ():({}) = {}
completely outside anything that's to do with objects/classes. Even if such functions use this
here and there, it'd be advantageous to represent logic as that; we can still pass this.foo
or whatever upon invocation. This lets us lighten up our objects, make the logic reusable and refactorable (even into another file if needed), and help us reduce object orientation.
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.
Sure I agree with that idea and we can make an effort to use that here and going forward, also in components.
const ids = [...axesVisibleTicks.keys()]; | ||
|
||
return ids.reduce( | ||
(acc, id) => { |
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.
I'd usually retain reduce
for slightly more complex cases. Here it's essentially a ids.filter().map()
except that you want to avoid the recalculation of ticks, axisSpec, axisTicksDimensions and axisPosition. But the result already carries these, so we could use ids.map(id => {... return {..., configured: ticks && axisSpec && axisTicksDimensions && axisPosition}}).filter(({configured}) => configured)
- not sure if configured is the right name - or just make the map
return null
when a condition fails and then .filter(identity)
where const identity = d => d
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.
Ok that's fine, I just tend to use reduce to avoid multiple loops. What is the performance difference for large arrays using 1 loop vs 2+?
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.
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.
Sure thing, and I think we don't really have guidelines for this level of coding questions anyway
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.
Absolutely, esp. if the retained set can be large.
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.
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.
Fixed in 1f27b60
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.
Functionality looks good to me, does what the issue asks, code looks good, pending CI and PR checkbox ticks. As I'm a new reviewer in this code base pls. @markov00 also take a look.
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.
Let's also add a check on the number of desired ticks
in the axis spec before merge this
ticks: axesVisibleTicks.get(id), | ||
axisSpec: axesSpecs.get(id), | ||
axisTicksDimensions: axesTicksDimensions.get(id), | ||
axisPosition: axesPositions.get(id), |
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.
you can map this to something that respect the props of the <Axis>
component like {key, ticks, axisSpec, axisTickDimensions, axisPosition }` so then you can just render it like
<Axis
{...axis}
chartTheme={chartTheme}
debug={debug}
chartDimensions={chartDimensions}
/>
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.
see 2474776
) { | ||
const spec = specMap.get(axisId); | ||
|
||
if (spec && spec.position === position && ((!title && !spec.title) || title === spec.title)) { |
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.
can we simplify this using spec && spec.position === position && title == spec.title
?
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.
see 2474776
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.
left a comment to address
@@ -134,7 +134,7 @@ export const isDuplicateAxis = ( | |||
) { | |||
const spec = specMap.get(axisId); | |||
|
|||
if (spec && spec.position === position && ((!title && !spec.title) || title === spec.title)) { | |||
if (spec && spec.position === position && title === spec.title) { |
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.
it's a double equal here if we want to mark as duplicate if one title is null and the other undefined (that in our case we can threat as no value)
if (spec && spec.position === position && title === spec.title) { | |
if (spec && spec.position === position && title == spec.title) { |
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.
The value cannot be null
based on the types correct?
Nonetheless, I also don't like double equals in javascript because it is loose equality, and generally a bad practice. It also can cause unwanted conversions producing inaccurate results. I'd like to enforce this throughout the code eventually.
I think the explicit equality adding twice the code to clearly indicate the comparison is worth it.
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.
yep that value cannot be null, but I was thinking on the case the chart used in a JS world (people can do strange things there).
You are right about the loose equality, I use that only in rare case checking when checking for null and undefined, in that case you are right, we can get some strange results. So please ignore my comment here
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.
To your point about people using this library in javaScript and not minding the types.
I 100% agree, but I think if we want to address that there are numerous places where we assume values to be provided/required. I think the Theme
is a perfect example where we assume options are provided on the type were in js they may not.
chartDimensions={chartDimensions} | ||
/> | ||
return axes.map(({ key, ...axisProps }) => ( | ||
<Axis {...axisProps} key={key} chartTheme={chartTheme} debug={debug} chartDimensions={chartDimensions} /> |
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.
Have you extracted the key a bit more explicit on the code?
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.
Sorry what do you mean by this?
I tried spreading the props with the key included and I get a linting error not adding the key to map
d child. Is that what you mean?
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.
yes, sorry :(
strange that the ts linter doesn't know about that
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.
jenkins, test this please |
🎉 This PR is included in version 12.1.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
# [12.1.0](elastic/elastic-charts@v12.0.2...v12.1.0) (2019-09-19) ### Features * **axis:** option to hide duplicate axes ([opensearch-project#370](elastic/elastic-charts#370)) ([4381734](elastic/elastic-charts@4381734)), closes [opensearch-project#368](elastic/elastic-charts#368)
Summary
Adds prop
hideDuplicateAxes
to settings to hide axes based on tick labels, position and title.Axis will be hidden if all of the following conditions are true:
tickFormat
) matchlength
of the ticks matchtitles
match, can be bothundefined
position
on the spec matchcloses #368
Checklist
src/index.ts
(and stories only import from../src
except for test data & storybook)