Commit 5f964fcf authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '202696-only-display-y-axis-of-data-value-ranges-for-charts' into 'master'

Display the y-axis on the range of data value in the chart

Closes #202696

See merge request gitlab-org/gitlab!24953
parents d9a86c0a bfbfac4b
......@@ -18,6 +18,17 @@ import {
import { makeDataSeries } from '~/helpers/monitor_helper';
import { graphDataValidatorForValues } from '../../utils';
/**
* A "virtual" coordinates system for the deployment icons.
* Deployment icons are displayed along the [min, max]
* range at height `pos`.
*/
const deploymentYAxisCoords = {
min: 0,
pos: 3, // 3% height of chart's grid
max: 100,
};
const THROTTLED_DATAZOOM_WAIT = 1000; // miliseconds
const timestampToISODate = timestamp => new Date(timestamp).toISOString();
......@@ -145,10 +156,33 @@ export default {
}, []);
},
chartOptionSeries() {
return (this.option.series || []).concat(this.scatterSeries ? [this.scatterSeries] : []);
return (this.option.series || []).concat(
this.deploymentSeries ? [this.deploymentSeries] : [],
);
},
chartOptions() {
const option = omit(this.option, 'series');
const dataYAxis = {
name: this.yAxisLabel,
nameGap: 50, // same as gitlab-ui's default
nameLocation: 'center', // same as gitlab-ui's default
boundaryGap: [0.1, 0.1],
scale: true,
axisLabel: {
formatter: num => roundOffFloat(num, 3).toString(),
},
};
const deploymentsYAxis = {
show: false,
min: deploymentYAxisCoords.min,
max: deploymentYAxisCoords.max,
axisLabel: {
// formatter fn required to trigger tooltip re-positioning
formatter: () => {},
},
};
return {
series: this.chartOptionSeries,
xAxis: {
......@@ -161,12 +195,7 @@ export default {
snap: true,
},
},
yAxis: {
name: this.yAxisLabel,
axisLabel: {
formatter: num => roundOffFloat(num, 3).toString(),
},
},
yAxis: [dataYAxis, deploymentsYAxis],
dataZoom: [this.dataZoomConfig],
...option,
};
......@@ -228,10 +257,16 @@ export default {
return acc;
}, []);
},
scatterSeries() {
deploymentSeries() {
return {
type: graphTypes.deploymentData,
data: this.recentDeployments.map(deployment => [deployment.createdAt, 0]),
yAxisIndex: 1, // deploymentsYAxis index
data: this.recentDeployments.map(deployment => [
deployment.createdAt,
deploymentYAxisCoords.pos,
]),
symbol: this.svgs.rocket,
symbolSize: symbolSizes.default,
itemStyle: {
......@@ -265,6 +300,7 @@ export default {
formatTooltipText(params) {
this.tooltip.title = dateFormat(params.value, dateFormats.default);
this.tooltip.content = [];
params.seriesData.forEach(dataPoint => {
if (dataPoint.value) {
const [xVal, yVal] = dataPoint.value;
......
---
title: Display the y-axis on the range of data value in the chart
merge_request: 24953
author:
type: added
......@@ -74,6 +74,8 @@ describe('Time series component', () => {
describe('general functions', () => {
let timeSeriesChart;
const findChart = () => timeSeriesChart.find({ ref: 'chart' });
beforeEach(done => {
timeSeriesChart = makeTimeSeriesChart(mockGraphData, 'area-chart');
timeSeriesChart.vm.$nextTick(done);
......@@ -109,8 +111,6 @@ describe('Time series component', () => {
let startValue;
let endValue;
const findChart = () => timeSeriesChart.find({ ref: 'chart' });
beforeEach(done => {
eChartMock = {
handlers: {},
......@@ -285,6 +285,8 @@ describe('Time series component', () => {
});
describe('computed', () => {
const getChartOptions = () => findChart().props('option');
describe('chartData', () => {
let chartData;
const seriesData = () => chartData[0];
......@@ -329,7 +331,7 @@ describe('Time series component', () => {
});
return timeSeriesChart.vm.$nextTick().then(() => {
expect(timeSeriesChart.vm.chartOptions).toEqual(expect.objectContaining(mockOption));
expect(getChartOptions()).toEqual(expect.objectContaining(mockOption));
});
});
......@@ -345,7 +347,7 @@ describe('Time series component', () => {
});
return timeSeriesChart.vm.$nextTick().then(() => {
const optionSeries = timeSeriesChart.vm.chartOptions.series;
const optionSeries = getChartOptions().series;
expect(optionSeries.length).toEqual(2);
expect(optionSeries[0].name).toEqual(mockSeriesName);
......@@ -354,33 +356,58 @@ describe('Time series component', () => {
});
describe('yAxis formatter', () => {
let format;
let dataFormatter;
let deploymentFormatter;
beforeEach(() => {
format = timeSeriesChart.vm.chartOptions.yAxis.axisLabel.formatter;
dataFormatter = getChartOptions().yAxis[0].axisLabel.formatter;
deploymentFormatter = getChartOptions().yAxis[1].axisLabel.formatter;
});
it('rounds to 3 decimal places', () => {
expect(format(0.88888)).toBe('0.889');
expect(dataFormatter(0.88888)).toBe('0.889');
});
it('deployment formatter is set as is required to display a tooltip', () => {
expect(deploymentFormatter).toEqual(expect.any(Function));
});
});
});
describe('scatterSeries', () => {
describe('deploymentSeries', () => {
it('utilizes deployment data', () => {
expect(timeSeriesChart.vm.scatterSeries.data).toEqual([
['2019-07-16T10:14:25.589Z', 0],
['2019-07-16T11:14:25.589Z', 0],
['2019-07-16T12:14:25.589Z', 0],
expect(timeSeriesChart.vm.deploymentSeries.yAxisIndex).toBe(1); // same as deployment y axis
expect(timeSeriesChart.vm.deploymentSeries.data).toEqual([
['2019-07-16T10:14:25.589Z', expect.any(Number)],
['2019-07-16T11:14:25.589Z', expect.any(Number)],
['2019-07-16T12:14:25.589Z', expect.any(Number)],
]);
expect(timeSeriesChart.vm.scatterSeries.symbolSize).toBe(14);
expect(timeSeriesChart.vm.deploymentSeries.symbolSize).toBe(14);
});
});
describe('yAxisLabel', () => {
it('y axis is configured correctly', () => {
const { yAxis } = getChartOptions();
expect(yAxis).toHaveLength(2);
const [dataAxis, deploymentAxis] = yAxis;
expect(dataAxis.boundaryGap).toHaveLength(2);
expect(dataAxis.scale).toBe(true);
expect(deploymentAxis.show).toBe(false);
expect(deploymentAxis.min).toEqual(expect.any(Number));
expect(deploymentAxis.max).toEqual(expect.any(Number));
expect(deploymentAxis.min).toBeLessThan(deploymentAxis.max);
});
it('constructs a label for the chart y-axis', () => {
expect(timeSeriesChart.vm.yAxisLabel).toBe('Memory Used per Pod');
const { yAxis } = getChartOptions();
expect(yAxis[0].name).toBe('Memory Used per Pod');
});
});
});
......@@ -405,7 +432,7 @@ describe('Time series component', () => {
glChartComponents.forEach(dynamicComponent => {
describe(`GitLab UI: ${dynamicComponent.chartType}`, () => {
let timeSeriesAreaChart;
const findChart = () => timeSeriesAreaChart.find(dynamicComponent.component);
const findChartComponent = () => timeSeriesAreaChart.find(dynamicComponent.component);
beforeEach(done => {
timeSeriesAreaChart = makeTimeSeriesChart(mockGraphData, dynamicComponent.chartType);
......@@ -417,12 +444,12 @@ describe('Time series component', () => {
});
it('is a Vue instance', () => {
expect(findChart().exists()).toBe(true);
expect(findChart().isVueInstance()).toBe(true);
expect(findChartComponent().exists()).toBe(true);
expect(findChartComponent().isVueInstance()).toBe(true);
});
it('receives data properties needed for proper chart render', () => {
const props = findChart().props();
const props = findChartComponent().props();
expect(props.data).toBe(timeSeriesAreaChart.vm.chartData);
expect(props.option).toBe(timeSeriesAreaChart.vm.chartOptions);
......@@ -435,9 +462,9 @@ describe('Time series component', () => {
timeSeriesAreaChart.vm.tooltip.title = mockTitle;
timeSeriesAreaChart.vm.$nextTick(() => {
expect(shallowWrapperContainsSlotText(findChart(), 'tooltipTitle', mockTitle)).toBe(
true,
);
expect(
shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', mockTitle),
).toBe(true);
done();
});
});
......@@ -452,9 +479,9 @@ describe('Time series component', () => {
});
it('uses deployment title', () => {
expect(shallowWrapperContainsSlotText(findChart(), 'tooltipTitle', 'Deployed')).toBe(
true,
);
expect(
shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', 'Deployed'),
).toBe(true);
});
it('renders clickable commit sha in tooltip content', done => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment