Merge branch '38036-hover-and-legend-data-should-be-linked' into 'master'

Resolve "Hover and legend data should be linked"

Closes #38036

See merge request gitlab-org/gitlab-ce!14400
This commit is contained in:
Phil Hughes 2017-10-05 08:52:06 +00:00
commit 6ba961499c
8 changed files with 97 additions and 51 deletions

View file

@ -29,6 +29,7 @@
showEmptyState: true,
updateAspectRatio: false,
updatedAspectRatios: 0,
hoverData: {},
resizeThrottled: {},
};
},
@ -64,6 +65,10 @@
this.updatedAspectRatios = 0;
}
},
hoverChanged(data) {
this.hoverData = data;
},
},
created() {
@ -72,10 +77,12 @@
deploymentEndpoint: this.deploymentEndpoint,
});
eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$on('hoverChanged', this.hoverChanged);
},
beforeDestroy() {
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false);
},
@ -102,6 +109,7 @@
v-for="(graphData, index) in groupData.metrics"
:key="index"
:graph-data="graphData"
:hover-data="hoverData"
:update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData"
/>

View file

@ -7,12 +7,10 @@
import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub';
import measurements from '../utils/measurements';
import { timeScaleFormat } from '../utils/date_time_formatters';
import { timeScaleFormat, bisectDate } from '../utils/date_time_formatters';
import createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints';
const bisectDate = d3.bisector(d => d.time).left;
export default {
props: {
graphData: {
@ -27,6 +25,11 @@
type: Array,
required: true,
},
hoverData: {
type: Object,
required: false,
default: () => ({}),
},
},
mixins: [MonitoringMixin],
@ -52,6 +55,7 @@
currentXCoordinate: 0,
currentFlagPosition: 0,
showFlag: false,
showFlagContent: false,
showDeployInfo: true,
timeSeries: [],
};
@ -122,22 +126,14 @@
const d1 = firstTimeSeries.values[overlayIndex];
if (d0 === undefined || d1 === undefined) return;
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
this.currentData = evalTime ? d1 : d0;
this.currentDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
this.currentXCoordinate = Math.floor(firstTimeSeries.timeSeriesScaleX(this.currentData.time));
const hoveredDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
const currentDeployXPos = this.mouseOverDeployInfo(point.x);
if (this.currentXCoordinate > (this.graphWidth - 200)) {
this.currentFlagPosition = this.currentXCoordinate - 103;
} else {
this.currentFlagPosition = this.currentXCoordinate;
}
if (currentDeployXPos) {
this.showFlag = false;
} else {
this.showFlag = true;
}
eventHub.$emit('hoverChanged', {
hoveredDate,
currentDeployXPos,
});
},
renderAxesPaths() {
@ -194,6 +190,10 @@
eventHub.$emit('toggleAspectRatio');
}
},
hoverData() {
this.positionFlag();
},
},
mounted() {
@ -203,7 +203,10 @@
</script>
<template>
<div class="prometheus-graph">
<div
class="prometheus-graph"
@mouseover="showFlagContent = true"
@mouseleave="showFlagContent = false">
<h5 class="text-center graph-title">
{{graphData.title}}
</h5>
@ -257,6 +260,7 @@
:current-flag-position="currentFlagPosition"
:graph-height="graphHeight"
:graph-height-offset="graphHeightOffset"
:show-flag-content="showFlagContent"
/>
<rect
class="prometheus-graph-overlay"

View file

@ -23,6 +23,10 @@
type: Number,
required: true,
},
showFlagContent: {
type: Boolean,
required: true,
},
},
data() {
@ -57,6 +61,7 @@
transform="translate(-5, 20)">
</line>
<svg
v-if="showFlagContent"
class="rect-text-metric"
:x="currentFlagPosition"
y="0">

View file

@ -1,3 +1,5 @@
import { bisectDate } from '../utils/date_time_formatters';
const mixins = {
methods: {
mouseOverDeployInfo(mouseXPos) {
@ -18,6 +20,7 @@ const mixins = {
return dataFound;
},
formatDeployments() {
this.reducedDeploymentData = this.deploymentData.reduce((deploymentDataArray, deployment) => {
const time = new Date(deployment.created_at);
@ -40,6 +43,25 @@ const mixins = {
return deploymentDataArray;
}, []);
},
positionFlag() {
const timeSeries = this.timeSeries[0];
const hoveredDataIndex = bisectDate(timeSeries.values, this.hoverData.hoveredDate, 1);
this.currentData = timeSeries.values[hoveredDataIndex];
this.currentDataIndex = hoveredDataIndex;
this.currentXCoordinate = Math.floor(timeSeries.timeSeriesScaleX(this.currentData.time));
if (this.currentXCoordinate > (this.graphWidth - 200)) {
this.currentFlagPosition = this.currentXCoordinate - 103;
} else {
this.currentFlagPosition = this.currentXCoordinate;
}
if (this.hoverData.currentDeployXPos) {
this.showFlag = false;
} else {
this.showFlag = true;
}
},
},
};

View file

@ -2,6 +2,7 @@ import d3 from 'd3';
export const dateFormat = d3.time.format('%b %-d, %Y');
export const timeFormat = d3.time.format('%-I:%M%p');
export const bisectDate = d3.bisector(d => d.time).left;
export const timeScaleFormat = d3.time.format.multi([
['.%L', d => d.getMilliseconds()],

View file

@ -0,0 +1,5 @@
---
title: Sync up hover and legend data across all graphs for the prometheus dashboard
merge_request:
author:
type: fixed

View file

@ -14,9 +14,7 @@ function getCoordinate(component, selector, coordinate) {
return parseInt(coordinateVal, 10);
}
describe('GraphFlag', () => {
it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
const component = createComponent({
const defaultValuesComponent = {
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
@ -26,7 +24,12 @@ describe('GraphFlag', () => {
},
graphHeight: 300,
graphHeightOffset: 120,
});
showFlagContent: true,
};
describe('GraphFlag', () => {
it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
const component = createComponent(defaultValuesComponent);
expect(getCoordinate(component, '.selected-metric-line', 'x1'))
.toEqual(component.currentXCoordinate);
@ -35,17 +38,7 @@ describe('GraphFlag', () => {
});
it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
const component = createComponent({
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
currentData: {
time: new Date('2017-06-04T18:17:33.501Z'),
value: '1.49609375',
},
graphHeight: 300,
graphHeightOffset: 120,
});
const component = createComponent(defaultValuesComponent);
const svg = component.$el.querySelector('.rect-text-metric');
expect(svg.tagName).toEqual('svg');
@ -54,17 +47,7 @@ describe('GraphFlag', () => {
describe('Computed props', () => {
it('calculatedHeight', () => {
const component = createComponent({
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
currentData: {
time: new Date('2017-06-04T18:17:33.501Z'),
value: '1.49609375',
},
graphHeight: 300,
graphHeightOffset: 120,
});
const component = createComponent(defaultValuesComponent);
expect(component.calculatedHeight).toEqual(180);
});

View file

@ -86,4 +86,22 @@ describe('Graph', () => {
expect(component.yAxisLabel).toEqual(component.graphData.y_label);
expect(component.legendTitle).toEqual(component.graphData.queries[0].label);
});
it('sets the currentData object based on the hovered data index', () => {
const component = createComponent({
graphData: convertedMetrics[1],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
graphIdentifier: 0,
hoverData: {
hoveredDate: new Date('Sun Aug 27 2017 06:11:51 GMT-0500 (CDT)'),
currentDeployXPos: null,
},
});
component.positionFlag();
expect(component.currentData).toBe(component.timeSeries[0].values[10]);
expect(component.currentDataIndex).toEqual(10);
});
});