Commit 6ba96149 authored by Phil Hughes's avatar Phil Hughes

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
parents b7dda44e 9857ba18
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
showEmptyState: true, showEmptyState: true,
updateAspectRatio: false, updateAspectRatio: false,
updatedAspectRatios: 0, updatedAspectRatios: 0,
hoverData: {},
resizeThrottled: {}, resizeThrottled: {},
}; };
}, },
...@@ -64,6 +65,10 @@ ...@@ -64,6 +65,10 @@
this.updatedAspectRatios = 0; this.updatedAspectRatios = 0;
} }
}, },
hoverChanged(data) {
this.hoverData = data;
},
}, },
created() { created() {
...@@ -72,10 +77,12 @@ ...@@ -72,10 +77,12 @@
deploymentEndpoint: this.deploymentEndpoint, deploymentEndpoint: this.deploymentEndpoint,
}); });
eventHub.$on('toggleAspectRatio', this.toggleAspectRatio); eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$on('hoverChanged', this.hoverChanged);
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio); eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false); window.removeEventListener('resize', this.resizeThrottled, false);
}, },
...@@ -102,6 +109,7 @@ ...@@ -102,6 +109,7 @@
v-for="(graphData, index) in groupData.metrics" v-for="(graphData, index) in groupData.metrics"
:key="index" :key="index"
:graph-data="graphData" :graph-data="graphData"
:hover-data="hoverData"
:update-aspect-ratio="updateAspectRatio" :update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData" :deployment-data="store.deploymentData"
/> />
......
...@@ -7,12 +7,10 @@ ...@@ -7,12 +7,10 @@
import MonitoringMixin from '../mixins/monitoring_mixins'; import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import measurements from '../utils/measurements'; 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 createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints'; import bp from '../../breakpoints';
const bisectDate = d3.bisector(d => d.time).left;
export default { export default {
props: { props: {
graphData: { graphData: {
...@@ -27,6 +25,11 @@ ...@@ -27,6 +25,11 @@
type: Array, type: Array,
required: true, required: true,
}, },
hoverData: {
type: Object,
required: false,
default: () => ({}),
},
}, },
mixins: [MonitoringMixin], mixins: [MonitoringMixin],
...@@ -52,6 +55,7 @@ ...@@ -52,6 +55,7 @@
currentXCoordinate: 0, currentXCoordinate: 0,
currentFlagPosition: 0, currentFlagPosition: 0,
showFlag: false, showFlag: false,
showFlagContent: false,
showDeployInfo: true, showDeployInfo: true,
timeSeries: [], timeSeries: [],
}; };
...@@ -122,22 +126,14 @@ ...@@ -122,22 +126,14 @@
const d1 = firstTimeSeries.values[overlayIndex]; const d1 = firstTimeSeries.values[overlayIndex];
if (d0 === undefined || d1 === undefined) return; if (d0 === undefined || d1 === undefined) return;
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay; const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
this.currentData = evalTime ? d1 : d0; const hoveredDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
this.currentDataIndex = evalTime ? overlayIndex : (overlayIndex - 1); const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
this.currentXCoordinate = Math.floor(firstTimeSeries.timeSeriesScaleX(this.currentData.time));
const currentDeployXPos = this.mouseOverDeployInfo(point.x); const currentDeployXPos = this.mouseOverDeployInfo(point.x);
if (this.currentXCoordinate > (this.graphWidth - 200)) { eventHub.$emit('hoverChanged', {
this.currentFlagPosition = this.currentXCoordinate - 103; hoveredDate,
} else { currentDeployXPos,
this.currentFlagPosition = this.currentXCoordinate; });
}
if (currentDeployXPos) {
this.showFlag = false;
} else {
this.showFlag = true;
}
}, },
renderAxesPaths() { renderAxesPaths() {
...@@ -194,6 +190,10 @@ ...@@ -194,6 +190,10 @@
eventHub.$emit('toggleAspectRatio'); eventHub.$emit('toggleAspectRatio');
} }
}, },
hoverData() {
this.positionFlag();
},
}, },
mounted() { mounted() {
...@@ -203,7 +203,10 @@ ...@@ -203,7 +203,10 @@
</script> </script>
<template> <template>
<div class="prometheus-graph"> <div
class="prometheus-graph"
@mouseover="showFlagContent = true"
@mouseleave="showFlagContent = false">
<h5 class="text-center graph-title"> <h5 class="text-center graph-title">
{{graphData.title}} {{graphData.title}}
</h5> </h5>
...@@ -257,6 +260,7 @@ ...@@ -257,6 +260,7 @@
:current-flag-position="currentFlagPosition" :current-flag-position="currentFlagPosition"
:graph-height="graphHeight" :graph-height="graphHeight"
:graph-height-offset="graphHeightOffset" :graph-height-offset="graphHeightOffset"
:show-flag-content="showFlagContent"
/> />
<rect <rect
class="prometheus-graph-overlay" class="prometheus-graph-overlay"
......
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
type: Number, type: Number,
required: true, required: true,
}, },
showFlagContent: {
type: Boolean,
required: true,
},
}, },
data() { data() {
...@@ -57,6 +61,7 @@ ...@@ -57,6 +61,7 @@
transform="translate(-5, 20)"> transform="translate(-5, 20)">
</line> </line>
<svg <svg
v-if="showFlagContent"
class="rect-text-metric" class="rect-text-metric"
:x="currentFlagPosition" :x="currentFlagPosition"
y="0"> y="0">
......
import { bisectDate } from '../utils/date_time_formatters';
const mixins = { const mixins = {
methods: { methods: {
mouseOverDeployInfo(mouseXPos) { mouseOverDeployInfo(mouseXPos) {
...@@ -18,6 +20,7 @@ const mixins = { ...@@ -18,6 +20,7 @@ const mixins = {
return dataFound; return dataFound;
}, },
formatDeployments() { formatDeployments() {
this.reducedDeploymentData = this.deploymentData.reduce((deploymentDataArray, deployment) => { this.reducedDeploymentData = this.deploymentData.reduce((deploymentDataArray, deployment) => {
const time = new Date(deployment.created_at); const time = new Date(deployment.created_at);
...@@ -40,6 +43,25 @@ const mixins = { ...@@ -40,6 +43,25 @@ const mixins = {
return deploymentDataArray; 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'; ...@@ -2,6 +2,7 @@ import d3 from 'd3';
export const dateFormat = d3.time.format('%b %-d, %Y'); export const dateFormat = d3.time.format('%b %-d, %Y');
export const timeFormat = d3.time.format('%-I:%M%p'); 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([ export const timeScaleFormat = d3.time.format.multi([
['.%L', d => d.getMilliseconds()], ['.%L', d => d.getMilliseconds()],
......
---
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) { ...@@ -14,19 +14,22 @@ function getCoordinate(component, selector, coordinate) {
return parseInt(coordinateVal, 10); 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', () => { describe('GraphFlag', () => {
it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => { it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
const component = createComponent({ const component = createComponent(defaultValuesComponent);
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
currentData: {
time: new Date('2017-06-04T18:17:33.501Z'),
value: '1.49609375',
},
graphHeight: 300,
graphHeightOffset: 120,
});
expect(getCoordinate(component, '.selected-metric-line', 'x1')) expect(getCoordinate(component, '.selected-metric-line', 'x1'))
.toEqual(component.currentXCoordinate); .toEqual(component.currentXCoordinate);
...@@ -35,17 +38,7 @@ describe('GraphFlag', () => { ...@@ -35,17 +38,7 @@ describe('GraphFlag', () => {
}); });
it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => { it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
const component = createComponent({ const component = createComponent(defaultValuesComponent);
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
currentData: {
time: new Date('2017-06-04T18:17:33.501Z'),
value: '1.49609375',
},
graphHeight: 300,
graphHeightOffset: 120,
});
const svg = component.$el.querySelector('.rect-text-metric'); const svg = component.$el.querySelector('.rect-text-metric');
expect(svg.tagName).toEqual('svg'); expect(svg.tagName).toEqual('svg');
...@@ -54,17 +47,7 @@ describe('GraphFlag', () => { ...@@ -54,17 +47,7 @@ describe('GraphFlag', () => {
describe('Computed props', () => { describe('Computed props', () => {
it('calculatedHeight', () => { it('calculatedHeight', () => {
const component = createComponent({ const component = createComponent(defaultValuesComponent);
currentXCoordinate: 200,
currentYCoordinate: 100,
currentFlagPosition: 100,
currentData: {
time: new Date('2017-06-04T18:17:33.501Z'),
value: '1.49609375',
},
graphHeight: 300,
graphHeightOffset: 120,
});
expect(component.calculatedHeight).toEqual(180); expect(component.calculatedHeight).toEqual(180);
}); });
......
...@@ -86,4 +86,22 @@ describe('Graph', () => { ...@@ -86,4 +86,22 @@ describe('Graph', () => {
expect(component.yAxisLabel).toEqual(component.graphData.y_label); expect(component.yAxisLabel).toEqual(component.graphData.y_label);
expect(component.legendTitle).toEqual(component.graphData.queries[0].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);
});
}); });
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