Make d3 place nicely with object values (#62004) (#62340)

This commit is contained in:
Joe Reuter 2020-04-03 11:08:31 +02:00 committed by GitHub
parent 4973ddd780
commit a651b23d61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 5 deletions

View file

@ -125,7 +125,7 @@ function DateRangesParamEditor({
</EuiText>
<EuiSpacer size="s" />
{ranges.map(({ from, to, id }) => {
{ranges.map(({ from, to, id }, index) => {
const deleteBtnTitle = i18n.translate(
'visDefaultEditor.controls.dateRanges.removeRangeButtonAriaLabel',
{
@ -154,6 +154,7 @@ function DateRangesParamEditor({
placeholder={FROM_PLACEHOLDER}
value={from || ''}
onChange={ev => onChangeRange(id, 'from', ev.target.value)}
data-test-subj={`visEditorDateRange${index}__from`}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
@ -168,6 +169,7 @@ function DateRangesParamEditor({
description: 'End of a date range, e.g. From 2018-02-26 *To* 2018-02-28',
}
)}
data-test-subj={`visEditorDateRange${index}__to`}
compressed
fullWidth={true}
isInvalid={areBothEmpty || !validateDateMath(to)}
@ -203,7 +205,12 @@ function DateRangesParamEditor({
<EuiSpacer size="s" />
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAddRange} size="xs">
<EuiButtonEmpty
iconType="plusInCircleFilled"
onClick={onAddRange}
size="xs"
data-test-subj="visEditorAddDateRange"
>
<FormattedMessage
id="visDefaultEditor.controls.dateRanges.addRangeButtonLabel"
defaultMessage="Add range"

View file

@ -25,6 +25,26 @@ import { orderXValues } from '../components/zero_injection/ordered_x_keys';
import { labels } from '../components/labels/labels';
import { getFormat } from '../../legacy_imports';
// X axis and split series values in a data table can sometimes be objects,
// e.g. when working with date ranges. d3 casts all ordinal values to strings
// which is a problem for these objects because they just return `[object Object]`
// and thus all map to the same value.
// This little helper overwrites the toString method of an object and keeps it the
// same otherwise - allowing d3 to correctly work with the values.
class D3MappableObject {
constructor(data) {
for (const key in data) {
if (data.hasOwnProperty(key)) {
this[key] = data[key];
}
}
}
toString() {
return JSON.stringify(this);
}
}
/**
* Provides an API for pulling values off the data
* and calculating values using the data
@ -52,9 +72,14 @@ export class Data {
const copyChart = data => {
const newData = {};
Object.keys(data).forEach(key => {
if (key !== 'series') {
newData[key] = data[key];
} else {
if (key === 'xAxisOrderedValues') {
newData[key] = data[key].map(val => {
if (typeof val === 'object') {
return new D3MappableObject(val);
}
return val;
});
} else if (key === 'series') {
newData[key] = data[key].map(seri => {
const converter = getFormat(seri.format);
const zConverter = getFormat(seri.zFormat);
@ -67,12 +92,17 @@ export class Data {
const newVal = _.clone(val);
newVal.extraMetrics = val.extraMetrics;
newVal.series = val.series || seri.label;
if (typeof newVal.x === 'object') {
newVal.x = new D3MappableObject(newVal.x);
}
return newVal;
}),
yAxisFormatter: val => converter.convert(val),
zAxisFormatter: val => zConverter.convert(val),
};
});
} else {
newData[key] = data[key];
}
});

View file

@ -54,6 +54,25 @@ export default function({ getService, getPageObjects }) {
});
});
describe('bar charts range on x axis', () => {
it('should individual bars for each configured range', async function() {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVerticalBarChart();
await PageObjects.visualize.clickNewSearch();
await PageObjects.timePicker.setDefaultAbsoluteRange();
await PageObjects.visEditor.clickBucket('X-axis');
log.debug('Aggregation = Date Range');
await PageObjects.visEditor.selectAggregation('Date Range');
log.debug('Field = @timestamp');
await PageObjects.visEditor.selectField('@timestamp');
await PageObjects.visEditor.clickAddDateRange();
await PageObjects.visEditor.setDateRangeByIndex('1', 'now-2w/w', 'now-1w/w');
await PageObjects.visEditor.clickGo();
const bottomLabels = await PageObjects.visChart.getXAxisLabels();
expect(bottomLabels.length).to.be(2);
});
});
// FLAKY: https://github.com/elastic/kibana/issues/22322
describe.skip('vertical bar chart flaky part', function() {
const vizName1 = 'Visualization VerticalBarChart';

View file

@ -103,6 +103,15 @@ export function VisualizeEditorPageProvider({ getService, getPageObjects }: FtrP
await radioBtn.click();
}
public async clickAddDateRange() {
await testSubjects.click(`visEditorAddDateRange`);
}
public async setDateRangeByIndex(index: string, from: string, to: string) {
await testSubjects.setValue(`visEditorDateRange${index}__from`, from);
await testSubjects.setValue(`visEditorDateRange${index}__to`, to);
}
/**
* Adds new bucket
* @param bucketName bucket name, like 'X-axis', 'Split rows', 'Split series'