Skip to content

Commit

Permalink
[Lens] Build endzone markers (#97849)
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Apr 27, 2021
1 parent c983283 commit 6b8c44d
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 12 deletions.

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
Expand Up @@ -79,4 +79,16 @@ describe('Axes Settings', () => {
false
);
});

it('hides the endzone visibility flag if no setter is passed in', () => {
const component = shallow(<AxisSettingsPopover {...props} />);
expect(component.find('[data-test-subj="lnsshowEndzones"]').length).toBe(0);
});

it('shows the switch if setter is present', () => {
const component = shallow(
<AxisSettingsPopover {...props} endzonesVisible={true} setEndzoneVisibility={() => {}} />
);
expect(component.find('[data-test-subj="lnsshowEndzones"]').prop('checked')).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ export interface AxisSettingsPopoverProps {
* Toggles the axis title visibility
*/
toggleAxisTitleVisibility: (axis: AxesSettingsConfigKeys, checked: boolean) => void;
/**
* Set endzone visibility
*/
setEndzoneVisibility?: (checked: boolean) => void;
/**
* Flag whether endzones are visible
*/
endzonesVisible?: boolean;
}
const popoverConfig = (
axis: AxesSettingsConfigKeys,
Expand Down Expand Up @@ -138,6 +146,8 @@ export const AxisSettingsPopover: React.FunctionComponent<AxisSettingsPopoverPro
areGridlinesVisible,
isAxisTitleVisible,
toggleAxisTitleVisibility,
setEndzoneVisibility,
endzonesVisible,
}) => {
const [title, setTitle] = useState<string | undefined>(axisTitle);

Expand Down Expand Up @@ -212,6 +222,20 @@ export const AxisSettingsPopover: React.FunctionComponent<AxisSettingsPopoverPro
onChange={() => toggleGridlinesVisibility(axis)}
checked={areGridlinesVisible}
/>
{setEndzoneVisibility && (
<>
<EuiSpacer size="m" />
<EuiSwitch
compressed
data-test-subj={`lnsshowEndzones`}
label={i18n.translate('xpack.lens.xyChart.showEnzones', {
defaultMessage: 'Show partial data markers',
})}
onChange={() => setEndzoneVisibility(!Boolean(endzonesVisible))}
checked={Boolean(endzonesVisible)}
/>
</>
)}
</ToolbarPopover>
);
};
130 changes: 130 additions & 0 deletions x-pack/plugins/lens/public/xy_visualization/expression.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { createMockExecutionContext } from '../../../../../src/plugins/expressio
import { mountWithIntl } from '@kbn/test/jest';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import { EmptyPlaceholder } from '../shared_components/empty_placeholder';
import { XyEndzones } from './x_domain';

const onClickValue = jest.fn();
const onSelectRange = jest.fn();
Expand Down Expand Up @@ -549,6 +550,135 @@ describe('xy_expression', () => {
}
`);
});

describe('endzones', () => {
const { args } = sampleArgs();
const data: LensMultiTable = {
type: 'lens_multitable',
tables: {
first: createSampleDatatableWithRows([
{ a: 1, b: 2, c: new Date('2021-04-22').valueOf(), d: 'Foo' },
{ a: 1, b: 2, c: new Date('2021-04-23').valueOf(), d: 'Foo' },
{ a: 1, b: 2, c: new Date('2021-04-24').valueOf(), d: 'Foo' },
]),
},
dateRange: {
// first and last bucket are partial
fromDate: new Date('2021-04-22T12:00:00.000Z'),
toDate: new Date('2021-04-24T12:00:00.000Z'),
},
};
const timeArgs: XYArgs = {
...args,
layers: [
{
...args.layers[0],
seriesType: 'line',
xScaleType: 'time',
isHistogram: true,
splitAccessor: undefined,
},
],
};

test('it extends interval if data is exceeding it', () => {
const component = shallow(
<XYChart
{...defaultProps}
minInterval={24 * 60 * 60 * 1000}
data={data}
args={timeArgs}
/>
);

expect(component.find(Settings).prop('xDomain')).toEqual({
// shortened to 24th midnight (elastic-charts automatically adds one min interval)
max: new Date('2021-04-24').valueOf(),
// extended to 22nd midnight because of first bucket
min: new Date('2021-04-22').valueOf(),
minInterval: 24 * 60 * 60 * 1000,
});
});

test('it renders endzone component bridging gap between domain and extended domain', () => {
const component = shallow(
<XYChart
{...defaultProps}
minInterval={24 * 60 * 60 * 1000}
data={data}
args={timeArgs}
/>
);

expect(component.find(XyEndzones).dive().find('Endzones').props()).toEqual(
expect.objectContaining({
domainStart: new Date('2021-04-22T12:00:00.000Z').valueOf(),
domainEnd: new Date('2021-04-24T12:00:00.000Z').valueOf(),
domainMin: new Date('2021-04-22').valueOf(),
domainMax: new Date('2021-04-24').valueOf(),
})
);
});

test('should pass enabled histogram mode and min interval to endzones component', () => {
const component = shallow(
<XYChart
{...defaultProps}
minInterval={24 * 60 * 60 * 1000}
data={data}
args={timeArgs}
/>
);

expect(component.find(XyEndzones).dive().find('Endzones').props()).toEqual(
expect.objectContaining({
interval: 24 * 60 * 60 * 1000,
isFullBin: false,
})
);
});

test('should pass disabled histogram mode and min interval to endzones component', () => {
const component = shallow(
<XYChart
{...defaultProps}
minInterval={24 * 60 * 60 * 1000}
data={data}
args={{
...args,
layers: [
{
...args.layers[0],
seriesType: 'bar',
xScaleType: 'time',
isHistogram: true,
},
],
}}
/>
);

expect(component.find(XyEndzones).dive().find('Endzones').props()).toEqual(
expect.objectContaining({
interval: 24 * 60 * 60 * 1000,
isFullBin: true,
})
);
});

test('it does not render endzones if disabled via settings', () => {
const component = shallow(
<XYChart
{...defaultProps}
minInterval={24 * 60 * 60 * 1000}
data={data}
args={{ ...timeArgs, hideEndzones: true }}
/>
);

expect(component.find(XyEndzones).length).toEqual(0);
});
});
});

test('it has xDomain undefined if the x is not a time scale or a histogram', () => {
Expand Down
50 changes: 40 additions & 10 deletions x-pack/plugins/lens/public/xy_visualization/expression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { desanitizeFilterContext } from '../utils';
import { fittingFunctionDefinitions, getFitOptions } from './fitting_functions';
import { getAxesConfiguration } from './axes_configuration';
import { getColorAssignments } from './color_assignment';
import { getXDomain, XyEndzones } from './x_domain';

declare global {
interface Window {
Expand Down Expand Up @@ -183,6 +184,13 @@ export const xyChart: ExpressionFunctionDefinition<
defaultMessage: 'Define how curve type is rendered for a line chart',
}),
},
hideEndzones: {
types: ['boolean'],
default: false,
help: i18n.translate('xpack.lens.xyChart.hideEndzones.help', {
defaultMessage: 'Hide endzone markers for partial data',
}),
},
},
fn(data: LensMultiTable, args: XYArgs) {
return {
Expand Down Expand Up @@ -330,9 +338,17 @@ export function XYChart({
renderMode,
syncColors,
}: XYChartRenderProps) {
const { legend, layers, fittingFunction, gridlinesVisibilitySettings, valueLabels } = args;
const {
legend,
layers,
fittingFunction,
gridlinesVisibilitySettings,
valueLabels,
hideEndzones,
} = args;
const chartTheme = chartsThemeService.useChartsTheme();
const chartBaseTheme = chartsThemeService.useChartsBaseTheme();
const darkMode = chartsThemeService.useDarkMode();
const filteredLayers = getFilteredLayers(layers, data);

if (filteredLayers.length === 0) {
Expand Down Expand Up @@ -387,15 +403,13 @@ export function XYChart({
const isTimeViz = data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time');
const isHistogramViz = filteredLayers.every((l) => l.isHistogram);

const xDomain = isTimeViz
? {
min: data.dateRange?.fromDate.getTime(),
max: data.dateRange?.toDate.getTime(),
minInterval,
}
: isHistogramViz
? { minInterval }
: undefined;
const { baseDomain: rawXDomain, extendedDomain: xDomain } = getXDomain(
layers,
data,
minInterval,
Boolean(isTimeViz),
Boolean(isHistogramViz)
);

const getYAxesTitles = (
axisSeries: Array<{ layer: string; accessor: string }>,
Expand Down Expand Up @@ -602,6 +616,22 @@ export function XYChart({
/>
))}

{!hideEndzones && (
<XyEndzones
baseDomain={rawXDomain}
extendedDomain={xDomain}
darkMode={darkMode}
histogramMode={filteredLayers.every(
(layer) =>
layer.isHistogram &&
(layer.seriesType.includes('stacked') || !layer.splitAccessor) &&
(layer.seriesType.includes('stacked') ||
!layer.seriesType.includes('bar') ||
!chartHasMoreThanOneBarSeries)
)}
/>
)}

{filteredLayers.flatMap((layer, layerIndex) =>
layer.accessors.map((accessor, accessorIndex) => {
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe('#toExpression', () => {
fittingFunction: 'Carry',
tickLabelsVisibilitySettings: { x: false, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: false, yLeft: true, yRight: true },
hideEndzones: true,
layers: [
{
layerId: 'first',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export const buildExpression = (
},
],
valueLabels: [state?.valueLabels || 'hide'],
hideEndzones: [state?.hideEndzones || false],
layers: validLayers.map((layer) => {
const columnToLabel = getColumnToLabelMap(layer, datasourceLayers[layer.layerId]);

Expand Down
Loading

0 comments on commit 6b8c44d

Please sign in to comment.