feat(xy): add null bars to geometry indexing#1226
Conversation
| const absMinHeight = Math.abs(minBarHeight); | ||
|
|
||
| // safeguard against null y values | ||
| let height = isNil(y0Scaled) || isNil(y) ? 0 : y0Scaled - y; |
There was a problem hiding this comment.
Minor: this could be substituted with height = y0Scaled - y || 0; using isNil doesn't add a lot of documentational value as the types already reveal they can be undefined or null. Still, it's a subjective call.
Also, as the row below sets y to zero if either is nil (in row 86) maybe reordering helps simplify a bit (eg. setting y and y0Scaled to 0 before; in which case the subtraction will result zero)
There was a problem hiding this comment.
I can't replace it with height = y0Scaled - y || 0 because y0Scaled and y can be null and TS rise a warning/error here
| const x = xScaled + xScale.bandwidth * orderIndex + xScale.bandwidth / 2 - width / 2; | ||
|
|
||
| const originalY1Value = stackMode === StackMode.Percentage ? y1 - (y0 ?? 0) : initialY1; | ||
| const originalY1Value = stackMode === StackMode.Percentage ? (isNil(y1) ? null : y1 - (y0 ?? 0)) : initialY1; |
There was a problem hiding this comment.
May be tangential to this PR, but GeometryValue has x and y as any, and maybe it could be tightened up. If it's not possible to do it globally, it could start by perhaps mapping to NaN instead of null so that eventually, y in GeometryValue is always a number
There was a problem hiding this comment.
Yes agree, we can push this into a separate PR I think
| if (y1 !== null && initialY1 !== null && filled?.y1 === undefined) { | ||
| barGeometries.push(barGeometry); | ||
| } |
There was a problem hiding this comment.
Should indexedGeometryMap.set(barGeometry) still be called unconditionally? If that were conditionalized, this predicate could go to the top of the forEach.
Btw. this function is almost 200 lines long with a bunch of let and co-dependent mutations and non-obvious type narrowings to number, and I don't comprehend it enough to do a good review, would be great to refactor before, or as part of feature work otherwise it'll be more and more complicated
There was a problem hiding this comment.
indexedGeometryMap.set(barGeometry) needs to be called unconditionally to take the advantage of the current picking logic.
Definitely a refactoring here is required!
nickofthyme
left a comment
There was a problem hiding this comment.
Changes LGTM. This is a really clean solution! 🎉
| export function getShowNullValues(settings: SettingsSpec): TooltipProps['showNullValues'] { | ||
| const { tooltip } = settings; |
There was a problem hiding this comment.
nit
| export function getShowNullValues(settings: SettingsSpec): TooltipProps['showNullValues'] { | |
| const { tooltip } = settings; | |
| export function getShowNullValues({ tooltip }: SettingsSpec): TooltipProps['showNullValues'] { |
|
|
||
| const absMinHeight = Math.abs(minBarHeight); | ||
| let height = y0Scaled - y; | ||
| if (absMinHeight !== undefined && height !== 0 && Math.abs(height) < absMinHeight) { |
There was a problem hiding this comment.
absMinHeight is always a number, so this part of the condition can be removed.
Also, using a sign rather than retaining the if(height < 0) means that the height !== 0 check is easy to make redundant:
const heightDelta = absMinHeight - Math.abs(height);
if (heightDelta > 0) {
const heightSign = Math.sign(height);
height = heightSign * absMinHeight;
y -= heightSign * heightDelta;
}
| @@ -81,12 +77,15 @@ export function renderBars( | |||
| y0Scaled = y0 === null ? yScale.scale(0) : yScale.scale(y0); | |||
There was a problem hiding this comment.
The let / if imperative construct for y0Scaled may be replaced with a single assignment:
// prettier-ignore
const y0Scaled = yScale.type === ScaleType.Log
? (y0 ?? 0) > 0 ? yScale.scale(y0) : yScale.range[yScale.isInverted ? 1 : 0]
: yScale.scale(y0 || 0);
It's not super pretty, there may be ways to more deeply simplify though
monfera
left a comment
There was a problem hiding this comment.
LGTM, my comments are only about how the render function could be simplified or at least made easier to understand
Thanks @monfera I will consider the simplification in a subsequent PR |
# [33.0.0](v32.0.0...v33.0.0) (2021-07-14) ### Features * **xy:** add null bars to geometry indexing ([#1226](#1226)) ([20b81a9](20b81a9)), closes [#950](#950) * **xy:** hide labels that protrude the bar geometry ([#1233](#1233)) ([be1fb3d](be1fb3d)), closes [#1234](#1234) ### BREAKING CHANGES * **xy:** an API change is introduced: `hideClippedValue` is removed in favor of `overflowConstraints?: Array<LabelOverflowConstraint>;`. The array can contain one or multiple overflow constraints enumerated as `LabelOverflowConstraint`
|
🎉 This PR is included in version 33.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary
The
showNullValuesprop is now available in theSettings.tooltipto allow displayingnullY values in the tooltip.This should goes hand in hand with the right tooltip formatter to catch and correctly format these
nullvalues.Details
This PR replace: #1206 reducing the scope to only show
nullvalues, keeping the current typings intact.The PR consist of removing the null values checks in the geometry generation phase, moving every geometry (visible or not) within the geometry index map (the map used by the tooltip to detect the cursor-geometry collisions). The geometries with null values are not pushed within the arrays of renderable geometries.
Issues
close #950
Checklist
packages/charts/src/index.ts(and stories only import from../srcexcept for test data & storybook)