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:
commit
6ba961499c
8 changed files with 97 additions and 51 deletions
|
@ -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"
|
||||
/>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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()],
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Sync up hover and legend data across all graphs for the prometheus dashboard
|
||||
merge_request:
|
||||
author:
|
||||
type: fixed
|
|
@ -14,19 +14,22 @@ function getCoordinate(component, selector, coordinate) {
|
|||
return parseInt(coordinateVal, 10);
|
||||
}
|
||||
|
||||
const defaultValuesComponent = {
|
||||
currentXCoordinate: 200,
|
||||
currentYCoordinate: 100,
|
||||
currentFlagPosition: 100,
|
||||
currentData: {
|
||||
time: new Date('2017-06-04T18:17:33.501Z'),
|
||||
value: '1.49609375',
|
||||
},
|
||||
graphHeight: 300,
|
||||
graphHeightOffset: 120,
|
||||
showFlagContent: true,
|
||||
};
|
||||
|
||||
describe('GraphFlag', () => {
|
||||
it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
|
||||
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(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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue