-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Lens] New value labels config option for bar charts #81776
Changes from 20 commits
cb9777a
db0d21b
b5c55bb
95bfb64
8bae6e6
6f97d07
8a3f7ff
908160b
9a1173a
fe00a1b
75d9013
47b1046
1119bf7
6fcf5ad
a54028c
4a235c6
5facb32
7ca4e34
25522d5
f3d1ec1
36a6c3e
b46016c
b82da66
1f6f324
b96c188
d9562aa
036bbde
6bac751
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,10 @@ import { | |
GeometryValue, | ||
XYChartSeriesIdentifier, | ||
StackMode, | ||
RecursivePartial, | ||
Theme, | ||
VerticalAlignment, | ||
HorizontalAlignment, | ||
} from '@elastic/charts'; | ||
import { I18nProvider } from '@kbn/i18n/react'; | ||
import { | ||
|
@@ -125,6 +129,11 @@ export const xyChart: ExpressionFunctionDefinition< | |
defaultMessage: 'Define how missing values are treated', | ||
}), | ||
}, | ||
valueLabels: { | ||
flash1293 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
types: ['string'], | ||
options: ['hide', 'inside'], | ||
help: '', | ||
}, | ||
tickLabelsVisibilitySettings: { | ||
types: ['lens_xy_tickLabelsConfig'], | ||
help: i18n.translate('xpack.lens.xyChart.tickLabelsSettings.help', { | ||
|
@@ -206,6 +215,40 @@ export const getXyChartRenderer = (dependencies: { | |
}, | ||
}); | ||
|
||
function mergeThemeWithValueLabelsStyling( | ||
theme: RecursivePartial<Theme>, | ||
valuesLabelMode: string = 'hide', | ||
isHorizontal: boolean | ||
) { | ||
const VALUE_LABELS_MAX_FONTSIZE = 15; | ||
const VALUE_LABELS_MIN_FONTSIZE = 10; | ||
const VALUE_LABELS_VERTICAL_OFFSET = -10; | ||
const VALUE_LABELS_HORIZONTAL_OFFSET = 10; | ||
|
||
if (valuesLabelMode === 'hide') { | ||
return theme; | ||
} | ||
return { | ||
...theme, | ||
...{ | ||
barSeriesStyle: { | ||
...theme.barSeriesStyle, | ||
displayValue: { | ||
fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, | ||
fill: { textInverted: true, textBorder: 2 }, | ||
alignment: isHorizontal | ||
? { | ||
vertical: VerticalAlignment.Middle, | ||
} | ||
: { horizontal: HorizontalAlignment.Center }, | ||
offsetX: isHorizontal ? VALUE_LABELS_HORIZONTAL_OFFSET : 0, | ||
offsetY: isHorizontal ? 0 : VALUE_LABELS_VERTICAL_OFFSET, | ||
}, | ||
}, | ||
}, | ||
Comment on lines
+242
to
+256
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. As described here elastic/elastic-charts#886 (comment) we should move these changes into the EUI chart theme. |
||
}; | ||
} | ||
|
||
function getIconForSeriesType(seriesType: SeriesType): IconType { | ||
return visualizationTypes.find((c) => c.id === seriesType)!.icon || 'empty'; | ||
} | ||
|
@@ -245,7 +288,7 @@ export function XYChart({ | |
onClickValue, | ||
onSelectRange, | ||
}: XYChartRenderProps) { | ||
const { legend, layers, fittingFunction, gridlinesVisibilitySettings } = args; | ||
const { legend, layers, fittingFunction, gridlinesVisibilitySettings, valueLabels } = args; | ||
const chartTheme = chartsThemeService.useChartsTheme(); | ||
const chartBaseTheme = chartsThemeService.useChartsBaseTheme(); | ||
|
||
|
@@ -387,6 +430,16 @@ export function XYChart({ | |
return style; | ||
}; | ||
|
||
const shouldShowValueLabels = | ||
// No stacked bar charts | ||
filteredLayers.every((layer) => !layer.seriesType.includes('stacked')) && | ||
// No histogram charts | ||
!isHistogramViz; | ||
|
||
const baseThemeWithMaybeValueLabels = !shouldShowValueLabels | ||
? chartTheme | ||
: mergeThemeWithValueLabelsStyling(chartTheme, valueLabels, shouldRotate); | ||
|
||
return ( | ||
<Chart> | ||
<Settings | ||
|
@@ -397,7 +450,7 @@ export function XYChart({ | |
} | ||
legendPosition={legend.position} | ||
showLegendExtra={false} | ||
theme={chartTheme} | ||
theme={baseThemeWithMaybeValueLabels} | ||
baseTheme={chartBaseTheme} | ||
tooltip={{ | ||
headerFormatter: (d) => safeXAccessorLabelRenderer(d.value), | ||
|
@@ -601,6 +654,10 @@ export function XYChart({ | |
}); | ||
} | ||
|
||
const yAxis = yAxesConfiguration.find((axisConfiguration) => | ||
axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) | ||
); | ||
|
||
const seriesProps: SeriesSpec = { | ||
splitSeriesAccessors: splitAccessor ? [splitAccessor] : [], | ||
stackAccessors: seriesType.includes('stacked') ? [xAccessor as string] : [], | ||
|
@@ -611,9 +668,7 @@ export function XYChart({ | |
xScaleType: xAccessor ? xScaleType : 'ordinal', | ||
yScaleType, | ||
color: () => getSeriesColor(layer, accessor), | ||
groupId: yAxesConfiguration.find((axisConfiguration) => | ||
axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) | ||
)?.groupId, | ||
groupId: yAxis?.groupId, | ||
enableHistogramMode: | ||
isHistogram && | ||
(seriesType.includes('stacked') || !splitAccessor) && | ||
|
@@ -685,7 +740,19 @@ export function XYChart({ | |
case 'bar_horizontal': | ||
case 'bar_horizontal_stacked': | ||
case 'bar_horizontal_percentage_stacked': | ||
return <BarSeries key={index} {...seriesProps} />; | ||
const valueLabelsSettings = { | ||
displayValueSettings: { | ||
// This format double fixes two issues in elastic-chart | ||
// * when rotating the chart, the formatter is not correctly picked | ||
// * in some scenarios value labels are not strings, and this breaks the elastic-chart lib | ||
valueFormatter: (d: unknown) => yAxis?.formatter?.convert(d) || '', | ||
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. Is this an elastic-charts bug? If yes we should open an issue for it. Also, it seems like this behavior is complex enough to cover it with a unit test. 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. The latter bug (non-string value handling) has been reported already. The former needs to be reported. 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. Gotcha, thanks for confirming. LGTM if it's tested and reported. |
||
showValueLabel: shouldShowValueLabels && valueLabels !== 'hide', | ||
isAlternatingValueLabel: false, | ||
isValueContainedInElement: true, | ||
hideClippedValue: true, | ||
}, | ||
}; | ||
return <BarSeries key={index} {...seriesProps} {...valueLabelsSettings} />; | ||
case 'area_stacked': | ||
case 'area_percentage_stacked': | ||
return ( | ||
|
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.
Not sure about this workaround - maybe @MichaelMarcialis has an idea how to improve this.
For context: To show why an option in the popover is disabled, a tooltip icon is added, but it's slightly too large to fit into the same row for the standard width of these popovers, so it has to get enlarged:
The only thing I can think of is to put the tooltip on the disabled form element itself instead of an additional icon, then the popover is wide enough and we don't need a separate class. The downside is the missing affordance - does the user know they have to hover the form element to get a reason for it being disabled?
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.
Just realized we have something like this in lens already - it looks like this for the colors:
No strong opinion which route to go but we should make sure to do it the same way in both places
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, this was the reason of the conditional icon state. I'll update the PR with a better alignment 👍
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.
Hey, all. If I'm understanding correctly, and the "missing values" field is one that will always be disabled when any visualization other than line and area are selected, my first instinct would be to conditionally remove that form field altogether in those instances. I'm not a fan of showing users disabled form fields where users have little-to-no ability to re-enable (assuming the currently selected visualization type is the desired one).
For example, if I know I want a bar chart for my visualization, why even present me with a field that I'll never be able to interact with?
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.
Updated PR to hide the field when the chart is not of type area or line.
Also improved icon alignment as in the picture above for
Series color
.