Merge branch 'prettify-monitoring-code' into 'master'
Clean up monitoring components See merge request gitlab-org/gitlab-ce!18030
This commit is contained in:
commit
092445a402
8 changed files with 719 additions and 752 deletions
|
@ -1,162 +1,155 @@
|
|||
<script>
|
||||
import _ from 'underscore';
|
||||
import Flash from '../../flash';
|
||||
import MonitoringService from '../services/monitoring_service';
|
||||
import GraphGroup from './graph_group.vue';
|
||||
import Graph from './graph.vue';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import MonitoringStore from '../stores/monitoring_store';
|
||||
import eventHub from '../event_hub';
|
||||
import _ from 'underscore';
|
||||
import Flash from '../../flash';
|
||||
import MonitoringService from '../services/monitoring_service';
|
||||
import GraphGroup from './graph_group.vue';
|
||||
import Graph from './graph.vue';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import MonitoringStore from '../stores/monitoring_store';
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Graph,
|
||||
GraphGroup,
|
||||
EmptyState,
|
||||
export default {
|
||||
components: {
|
||||
Graph,
|
||||
GraphGroup,
|
||||
EmptyState,
|
||||
},
|
||||
props: {
|
||||
hasMetrics: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
|
||||
props: {
|
||||
hasMetrics: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
showLegend: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
showPanels: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
forceSmallGraph: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
documentationPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
settingsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
clustersPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tagsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
metricsEndpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
deploymentEndpoint: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
emptyGettingStartedSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyLoadingSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyNoDataSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyUnableToConnectSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showLegend: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
store: new MonitoringStore(),
|
||||
state: 'gettingStarted',
|
||||
showEmptyState: true,
|
||||
updateAspectRatio: false,
|
||||
updatedAspectRatios: 0,
|
||||
hoverData: {},
|
||||
resizeThrottled: {},
|
||||
};
|
||||
showPanels: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
|
||||
created() {
|
||||
this.service = new MonitoringService({
|
||||
metricsEndpoint: this.metricsEndpoint,
|
||||
deploymentEndpoint: this.deploymentEndpoint,
|
||||
});
|
||||
eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
|
||||
eventHub.$on('hoverChanged', this.hoverChanged);
|
||||
forceSmallGraph: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
|
||||
eventHub.$off('hoverChanged', this.hoverChanged);
|
||||
window.removeEventListener('resize', this.resizeThrottled, false);
|
||||
documentationPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.resizeThrottled = _.throttle(this.resize, 600);
|
||||
if (!this.hasMetrics) {
|
||||
this.state = 'gettingStarted';
|
||||
} else {
|
||||
this.getGraphsData();
|
||||
window.addEventListener('resize', this.resizeThrottled, false);
|
||||
settingsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
clustersPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tagsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
metricsEndpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
deploymentEndpoint: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
emptyGettingStartedSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyLoadingSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyNoDataSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyUnableToConnectSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
store: new MonitoringStore(),
|
||||
state: 'gettingStarted',
|
||||
showEmptyState: true,
|
||||
updateAspectRatio: false,
|
||||
updatedAspectRatios: 0,
|
||||
hoverData: {},
|
||||
resizeThrottled: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.service = new MonitoringService({
|
||||
metricsEndpoint: this.metricsEndpoint,
|
||||
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);
|
||||
},
|
||||
mounted() {
|
||||
this.resizeThrottled = _.throttle(this.resize, 600);
|
||||
if (!this.hasMetrics) {
|
||||
this.state = 'gettingStarted';
|
||||
} else {
|
||||
this.getGraphsData();
|
||||
window.addEventListener('resize', this.resizeThrottled, false);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getGraphsData() {
|
||||
this.state = 'loading';
|
||||
Promise.all([
|
||||
this.service.getGraphsData().then(data => this.store.storeMetrics(data)),
|
||||
this.service
|
||||
.getDeploymentData()
|
||||
.then(data => this.store.storeDeploymentData(data))
|
||||
.catch(() => new Flash('Error getting deployment information.')),
|
||||
])
|
||||
.then(() => {
|
||||
if (this.store.groups.length < 1) {
|
||||
this.state = 'noData';
|
||||
return;
|
||||
}
|
||||
this.showEmptyState = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.state = 'unableToConnect';
|
||||
});
|
||||
},
|
||||
resize() {
|
||||
this.updateAspectRatio = true;
|
||||
},
|
||||
toggleAspectRatio() {
|
||||
this.updatedAspectRatios = this.updatedAspectRatios += 1;
|
||||
if (this.store.getMetricsCount() === this.updatedAspectRatios) {
|
||||
this.updateAspectRatio = !this.updateAspectRatio;
|
||||
this.updatedAspectRatios = 0;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getGraphsData() {
|
||||
this.state = 'loading';
|
||||
Promise.all([
|
||||
this.service.getGraphsData()
|
||||
.then(data => this.store.storeMetrics(data)),
|
||||
this.service.getDeploymentData()
|
||||
.then(data => this.store.storeDeploymentData(data))
|
||||
.catch(() => new Flash('Error getting deployment information.')),
|
||||
])
|
||||
.then(() => {
|
||||
if (this.store.groups.length < 1) {
|
||||
this.state = 'noData';
|
||||
return;
|
||||
}
|
||||
this.showEmptyState = false;
|
||||
})
|
||||
.catch(() => { this.state = 'unableToConnect'; });
|
||||
},
|
||||
|
||||
resize() {
|
||||
this.updateAspectRatio = true;
|
||||
},
|
||||
|
||||
toggleAspectRatio() {
|
||||
this.updatedAspectRatios = this.updatedAspectRatios += 1;
|
||||
if (this.store.getMetricsCount() === this.updatedAspectRatios) {
|
||||
this.updateAspectRatio = !this.updateAspectRatio;
|
||||
this.updatedAspectRatios = 0;
|
||||
}
|
||||
},
|
||||
|
||||
hoverChanged(data) {
|
||||
this.hoverData = data;
|
||||
},
|
||||
hoverChanged(data) {
|
||||
this.hoverData = data;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,91 +1,90 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
documentationPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
settingsPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
clustersPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
selectedState: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyGettingStartedSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyLoadingSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyNoDataSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyUnableToConnectSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
documentationPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
states: {
|
||||
gettingStarted: {
|
||||
svgUrl: this.emptyGettingStartedSvgPath,
|
||||
title: 'Get started with performance monitoring',
|
||||
description: `Stay updated about the performance and health
|
||||
settingsPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
clustersPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
selectedState: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyGettingStartedSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyLoadingSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyNoDataSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyUnableToConnectSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
states: {
|
||||
gettingStarted: {
|
||||
svgUrl: this.emptyGettingStartedSvgPath,
|
||||
title: 'Get started with performance monitoring',
|
||||
description: `Stay updated about the performance and health
|
||||
of your environment by configuring Prometheus to monitor your deployments.`,
|
||||
buttonText: 'Install Prometheus on clusters',
|
||||
buttonPath: this.clustersPath,
|
||||
secondaryButtonText: 'Configure existing Prometheus',
|
||||
secondaryButtonPath: this.settingsPath,
|
||||
},
|
||||
loading: {
|
||||
svgUrl: this.emptyLoadingSvgPath,
|
||||
title: 'Waiting for performance data',
|
||||
description: `Creating graphs uses the data from the Prometheus server.
|
||||
If this takes a long time, ensure that data is available.`,
|
||||
buttonText: 'View documentation',
|
||||
buttonPath: this.documentationPath,
|
||||
},
|
||||
noData: {
|
||||
svgUrl: this.emptyNoDataSvgPath,
|
||||
title: 'No data found',
|
||||
description: `You are connected to the Prometheus server, but there is currently
|
||||
no data to display.`,
|
||||
buttonText: 'Configure Prometheus',
|
||||
buttonPath: this.settingsPath,
|
||||
},
|
||||
unableToConnect: {
|
||||
svgUrl: this.emptyUnableToConnectSvgPath,
|
||||
title: 'Unable to connect to Prometheus server',
|
||||
description: 'Ensure connectivity is available from the GitLab server to the ',
|
||||
buttonText: 'View documentation',
|
||||
buttonPath: this.documentationPath,
|
||||
},
|
||||
buttonText: 'Install Prometheus on clusters',
|
||||
buttonPath: this.clustersPath,
|
||||
secondaryButtonText: 'Configure existing Prometheus',
|
||||
secondaryButtonPath: this.settingsPath,
|
||||
},
|
||||
loading: {
|
||||
svgUrl: this.emptyLoadingSvgPath,
|
||||
title: 'Waiting for performance data',
|
||||
description: `Creating graphs uses the data from the Prometheus server.
|
||||
If this takes a long time, ensure that data is available.`,
|
||||
buttonText: 'View documentation',
|
||||
buttonPath: this.documentationPath,
|
||||
},
|
||||
noData: {
|
||||
svgUrl: this.emptyNoDataSvgPath,
|
||||
title: 'No data found',
|
||||
description: `You are connected to the Prometheus server, but there is currently
|
||||
no data to display.`,
|
||||
buttonText: 'Configure Prometheus',
|
||||
buttonPath: this.settingsPath,
|
||||
},
|
||||
unableToConnect: {
|
||||
svgUrl: this.emptyUnableToConnectSvgPath,
|
||||
title: 'Unable to connect to Prometheus server',
|
||||
description: 'Ensure connectivity is available from the GitLab server to the ',
|
||||
buttonText: 'View documentation',
|
||||
buttonPath: this.documentationPath,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentState() {
|
||||
return this.states[this.selectedState];
|
||||
},
|
||||
|
||||
showButtonDescription() {
|
||||
if (this.selectedState === 'unableToConnect') return true;
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentState() {
|
||||
return this.states[this.selectedState];
|
||||
},
|
||||
};
|
||||
showButtonDescription() {
|
||||
if (this.selectedState === 'unableToConnect') return true;
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,236 +1,229 @@
|
|||
<script>
|
||||
import { scaleLinear, scaleTime } from 'd3-scale';
|
||||
import { axisLeft, axisBottom } from 'd3-axis';
|
||||
import { max, extent } from 'd3-array';
|
||||
import { select } from 'd3-selection';
|
||||
import GraphLegend from './graph/legend.vue';
|
||||
import GraphFlag from './graph/flag.vue';
|
||||
import GraphDeployment from './graph/deployment.vue';
|
||||
import GraphPath from './graph/path.vue';
|
||||
import MonitoringMixin from '../mixins/monitoring_mixins';
|
||||
import eventHub from '../event_hub';
|
||||
import measurements from '../utils/measurements';
|
||||
import { bisectDate, timeScaleFormat } from '../utils/date_time_formatters';
|
||||
import createTimeSeries from '../utils/multiple_time_series';
|
||||
import bp from '../../breakpoints';
|
||||
import { scaleLinear, scaleTime } from 'd3-scale';
|
||||
import { axisLeft, axisBottom } from 'd3-axis';
|
||||
import { max, extent } from 'd3-array';
|
||||
import { select } from 'd3-selection';
|
||||
import GraphLegend from './graph/legend.vue';
|
||||
import GraphFlag from './graph/flag.vue';
|
||||
import GraphDeployment from './graph/deployment.vue';
|
||||
import GraphPath from './graph/path.vue';
|
||||
import MonitoringMixin from '../mixins/monitoring_mixins';
|
||||
import eventHub from '../event_hub';
|
||||
import measurements from '../utils/measurements';
|
||||
import { bisectDate, timeScaleFormat } from '../utils/date_time_formatters';
|
||||
import createTimeSeries from '../utils/multiple_time_series';
|
||||
import bp from '../../breakpoints';
|
||||
|
||||
const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select };
|
||||
const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select };
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GraphLegend,
|
||||
GraphFlag,
|
||||
GraphDeployment,
|
||||
GraphPath,
|
||||
export default {
|
||||
components: {
|
||||
GraphLegend,
|
||||
GraphFlag,
|
||||
GraphDeployment,
|
||||
GraphPath,
|
||||
},
|
||||
mixins: [MonitoringMixin],
|
||||
props: {
|
||||
graphData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
mixins: [MonitoringMixin],
|
||||
|
||||
props: {
|
||||
graphData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
updateAspectRatio: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
deploymentData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
hoverData: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tagsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showLegend: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
smallGraph: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
updateAspectRatio: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
|
||||
data() {
|
||||
deploymentData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
hoverData: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tagsPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showLegend: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
smallGraph: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
baseGraphHeight: 450,
|
||||
baseGraphWidth: 600,
|
||||
graphHeight: 450,
|
||||
graphWidth: 600,
|
||||
graphHeightOffset: 120,
|
||||
margin: {},
|
||||
unitOfDisplay: '',
|
||||
yAxisLabel: '',
|
||||
legendTitle: '',
|
||||
reducedDeploymentData: [],
|
||||
measurements: measurements.large,
|
||||
currentData: {
|
||||
time: new Date(),
|
||||
value: 0,
|
||||
},
|
||||
currentDataIndex: 0,
|
||||
currentXCoordinate: 0,
|
||||
currentFlagPosition: 0,
|
||||
showFlag: false,
|
||||
showFlagContent: false,
|
||||
timeSeries: [],
|
||||
realPixelRatio: 1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
outerViewBox() {
|
||||
return `0 0 ${this.baseGraphWidth} ${this.baseGraphHeight}`;
|
||||
},
|
||||
innerViewBox() {
|
||||
return `0 0 ${this.baseGraphWidth - 150} ${this.baseGraphHeight}`;
|
||||
},
|
||||
axisTransform() {
|
||||
return `translate(70, ${this.graphHeight - 100})`;
|
||||
},
|
||||
paddingBottomRootSvg() {
|
||||
return {
|
||||
baseGraphHeight: 450,
|
||||
baseGraphWidth: 600,
|
||||
graphHeight: 450,
|
||||
graphWidth: 600,
|
||||
graphHeightOffset: 120,
|
||||
margin: {},
|
||||
unitOfDisplay: '',
|
||||
yAxisLabel: '',
|
||||
legendTitle: '',
|
||||
reducedDeploymentData: [],
|
||||
measurements: measurements.large,
|
||||
currentData: {
|
||||
time: new Date(),
|
||||
value: 0,
|
||||
},
|
||||
currentDataIndex: 0,
|
||||
currentXCoordinate: 0,
|
||||
currentFlagPosition: 0,
|
||||
showFlag: false,
|
||||
showFlagContent: false,
|
||||
timeSeries: [],
|
||||
realPixelRatio: 1,
|
||||
paddingBottom: `${Math.ceil(this.baseGraphHeight * 100) / this.baseGraphWidth || 0}%`,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
outerViewBox() {
|
||||
return `0 0 ${this.baseGraphWidth} ${this.baseGraphHeight}`;
|
||||
},
|
||||
|
||||
innerViewBox() {
|
||||
return `0 0 ${this.baseGraphWidth - 150} ${this.baseGraphHeight}`;
|
||||
},
|
||||
|
||||
axisTransform() {
|
||||
return `translate(70, ${this.graphHeight - 100})`;
|
||||
},
|
||||
|
||||
paddingBottomRootSvg() {
|
||||
return {
|
||||
paddingBottom: `${(Math.ceil(this.baseGraphHeight * 100) / this.baseGraphWidth) || 0}%`,
|
||||
};
|
||||
},
|
||||
|
||||
deploymentFlagData() {
|
||||
return this.reducedDeploymentData.find(deployment => deployment.showDeploymentFlag);
|
||||
},
|
||||
deploymentFlagData() {
|
||||
return this.reducedDeploymentData.find(deployment => deployment.showDeploymentFlag);
|
||||
},
|
||||
|
||||
watch: {
|
||||
updateAspectRatio() {
|
||||
if (this.updateAspectRatio) {
|
||||
this.graphHeight = 450;
|
||||
this.graphWidth = 600;
|
||||
this.measurements = measurements.large;
|
||||
this.draw();
|
||||
eventHub.$emit('toggleAspectRatio');
|
||||
}
|
||||
},
|
||||
|
||||
hoverData() {
|
||||
this.positionFlag();
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
updateAspectRatio() {
|
||||
if (this.updateAspectRatio) {
|
||||
this.graphHeight = 450;
|
||||
this.graphWidth = 600;
|
||||
this.measurements = measurements.large;
|
||||
this.draw();
|
||||
eventHub.$emit('toggleAspectRatio');
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.draw();
|
||||
hoverData() {
|
||||
this.positionFlag();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.draw();
|
||||
},
|
||||
methods: {
|
||||
draw() {
|
||||
const breakpointSize = bp.getBreakpointSize();
|
||||
const query = this.graphData.queries[0];
|
||||
this.margin = measurements.large.margin;
|
||||
if (this.smallGraph || breakpointSize === 'xs' || breakpointSize === 'sm') {
|
||||
this.graphHeight = 300;
|
||||
this.margin = measurements.small.margin;
|
||||
this.measurements = measurements.small;
|
||||
}
|
||||
this.unitOfDisplay = query.unit || '';
|
||||
this.yAxisLabel = this.graphData.y_label || 'Values';
|
||||
this.legendTitle = query.label || 'Average';
|
||||
this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right;
|
||||
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
|
||||
this.baseGraphHeight = this.graphHeight;
|
||||
this.baseGraphWidth = this.graphWidth;
|
||||
|
||||
methods: {
|
||||
draw() {
|
||||
const breakpointSize = bp.getBreakpointSize();
|
||||
const query = this.graphData.queries[0];
|
||||
this.margin = measurements.large.margin;
|
||||
if (this.smallGraph || breakpointSize === 'xs' || breakpointSize === 'sm') {
|
||||
this.graphHeight = 300;
|
||||
this.margin = measurements.small.margin;
|
||||
this.measurements = measurements.small;
|
||||
}
|
||||
this.unitOfDisplay = query.unit || '';
|
||||
this.yAxisLabel = this.graphData.y_label || 'Values';
|
||||
this.legendTitle = query.label || 'Average';
|
||||
this.graphWidth = this.$refs.baseSvg.clientWidth -
|
||||
this.margin.left - this.margin.right;
|
||||
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
|
||||
this.baseGraphHeight = this.graphHeight;
|
||||
this.baseGraphWidth = this.graphWidth;
|
||||
// pixel offsets inside the svg and outside are not 1:1
|
||||
this.realPixelRatio = this.$refs.baseSvg.clientWidth / this.baseGraphWidth;
|
||||
|
||||
// pixel offsets inside the svg and outside are not 1:1
|
||||
this.realPixelRatio = (this.$refs.baseSvg.clientWidth / this.baseGraphWidth);
|
||||
|
||||
this.renderAxesPaths();
|
||||
this.formatDeployments();
|
||||
},
|
||||
|
||||
handleMouseOverGraph(e) {
|
||||
let point = this.$refs.graphData.createSVGPoint();
|
||||
point.x = e.clientX;
|
||||
point.y = e.clientY;
|
||||
point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse());
|
||||
point.x = point.x += 7;
|
||||
const firstTimeSeries = this.timeSeries[0];
|
||||
const timeValueOverlay = firstTimeSeries.timeSeriesScaleX.invert(point.x);
|
||||
const overlayIndex = bisectDate(firstTimeSeries.values, timeValueOverlay, 1);
|
||||
const d0 = firstTimeSeries.values[overlayIndex - 1];
|
||||
const d1 = firstTimeSeries.values[overlayIndex];
|
||||
if (d0 === undefined || d1 === undefined) return;
|
||||
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
|
||||
const hoveredDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
|
||||
const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
|
||||
const currentDeployXPos = this.mouseOverDeployInfo(point.x);
|
||||
|
||||
eventHub.$emit('hoverChanged', {
|
||||
hoveredDate,
|
||||
currentDeployXPos,
|
||||
});
|
||||
},
|
||||
|
||||
renderAxesPaths() {
|
||||
this.timeSeries = createTimeSeries(
|
||||
this.graphData.queries,
|
||||
this.graphWidth,
|
||||
this.graphHeight,
|
||||
this.graphHeightOffset,
|
||||
);
|
||||
|
||||
if (!this.showLegend) {
|
||||
this.baseGraphHeight -= 50;
|
||||
} else if (this.timeSeries.length > 3) {
|
||||
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
|
||||
}
|
||||
|
||||
const axisXScale = d3.scaleTime()
|
||||
.range([0, this.graphWidth - 70]);
|
||||
const axisYScale = d3.scaleLinear()
|
||||
.range([this.graphHeight - this.graphHeightOffset, 0]);
|
||||
|
||||
const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []);
|
||||
axisXScale.domain(d3.extent(allValues, d => d.time));
|
||||
axisYScale.domain([0, d3.max(allValues.map(d => d.value))]);
|
||||
|
||||
const xAxis = d3.axisBottom()
|
||||
.scale(axisXScale)
|
||||
.ticks(this.graphWidth / 120)
|
||||
.tickFormat(timeScaleFormat);
|
||||
|
||||
const yAxis = d3.axisLeft()
|
||||
.scale(axisYScale)
|
||||
.ticks(measurements.yTicks);
|
||||
|
||||
d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis);
|
||||
|
||||
const width = this.graphWidth;
|
||||
d3.select(this.$refs.baseSvg).select('.y-axis').call(yAxis)
|
||||
.selectAll('.tick')
|
||||
.each(function createTickLines(d, i) {
|
||||
if (i > 0) {
|
||||
d3.select(this).select('line')
|
||||
.attr('x2', width)
|
||||
.attr('class', 'axis-tick');
|
||||
} // Avoid adding the class to the first tick, to prevent coloring
|
||||
}); // This will select all of the ticks once they're rendered
|
||||
},
|
||||
this.renderAxesPaths();
|
||||
this.formatDeployments();
|
||||
},
|
||||
};
|
||||
handleMouseOverGraph(e) {
|
||||
let point = this.$refs.graphData.createSVGPoint();
|
||||
point.x = e.clientX;
|
||||
point.y = e.clientY;
|
||||
point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse());
|
||||
point.x = point.x += 7;
|
||||
const firstTimeSeries = this.timeSeries[0];
|
||||
const timeValueOverlay = firstTimeSeries.timeSeriesScaleX.invert(point.x);
|
||||
const overlayIndex = bisectDate(firstTimeSeries.values, timeValueOverlay, 1);
|
||||
const d0 = firstTimeSeries.values[overlayIndex - 1];
|
||||
const d1 = firstTimeSeries.values[overlayIndex];
|
||||
if (d0 === undefined || d1 === undefined) return;
|
||||
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
|
||||
const hoveredDataIndex = evalTime ? overlayIndex : overlayIndex - 1;
|
||||
const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
|
||||
const currentDeployXPos = this.mouseOverDeployInfo(point.x);
|
||||
|
||||
eventHub.$emit('hoverChanged', {
|
||||
hoveredDate,
|
||||
currentDeployXPos,
|
||||
});
|
||||
},
|
||||
renderAxesPaths() {
|
||||
this.timeSeries = createTimeSeries(
|
||||
this.graphData.queries,
|
||||
this.graphWidth,
|
||||
this.graphHeight,
|
||||
this.graphHeightOffset,
|
||||
);
|
||||
|
||||
if (!this.showLegend) {
|
||||
this.baseGraphHeight -= 50;
|
||||
} else if (this.timeSeries.length > 3) {
|
||||
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
|
||||
}
|
||||
|
||||
const axisXScale = d3.scaleTime().range([0, this.graphWidth - 70]);
|
||||
const axisYScale = d3.scaleLinear().range([this.graphHeight - this.graphHeightOffset, 0]);
|
||||
|
||||
const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []);
|
||||
axisXScale.domain(d3.extent(allValues, d => d.time));
|
||||
axisYScale.domain([0, d3.max(allValues.map(d => d.value))]);
|
||||
|
||||
const xAxis = d3
|
||||
.axisBottom()
|
||||
.scale(axisXScale)
|
||||
.ticks(this.graphWidth / 120)
|
||||
.tickFormat(timeScaleFormat);
|
||||
|
||||
const yAxis = d3
|
||||
.axisLeft()
|
||||
.scale(axisYScale)
|
||||
.ticks(measurements.yTicks);
|
||||
|
||||
d3
|
||||
.select(this.$refs.baseSvg)
|
||||
.select('.x-axis')
|
||||
.call(xAxis);
|
||||
|
||||
const width = this.graphWidth;
|
||||
d3
|
||||
.select(this.$refs.baseSvg)
|
||||
.select('.y-axis')
|
||||
.call(yAxis)
|
||||
.selectAll('.tick')
|
||||
.each(function createTickLines(d, i) {
|
||||
if (i > 0) {
|
||||
d3
|
||||
.select(this)
|
||||
.select('line')
|
||||
.attr('x2', width)
|
||||
.attr('class', 'axis-tick');
|
||||
} // Avoid adding the class to the first tick, to prevent coloring
|
||||
}); // This will select all of the ticks once they're rendered
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
deploymentData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
graphHeightOffset: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
deploymentData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
||||
computed: {
|
||||
calculatedHeight() {
|
||||
return this.graphHeight - this.graphHeightOffset;
|
||||
},
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
|
||||
methods: {
|
||||
transformDeploymentGroup(deployment) {
|
||||
return `translate(${Math.floor(deployment.xPos) - 5}, 20)`;
|
||||
},
|
||||
graphHeightOffset: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
calculatedHeight() {
|
||||
return this.graphHeight - this.graphHeightOffset;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
transformDeploymentGroup(deployment) {
|
||||
return `translate(${Math.floor(deployment.xPos) - 5}, 20)`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<g class="deploy-info">
|
||||
|
|
|
@ -1,127 +1,119 @@
|
|||
<script>
|
||||
import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
|
||||
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
|
||||
import icon from '../../../vue_shared/components/icon.vue';
|
||||
import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
|
||||
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
|
||||
import icon from '../../../vue_shared/components/icon.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
icon,
|
||||
export default {
|
||||
components: {
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
currentXCoordinate: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
currentXCoordinate: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
currentData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
deploymentFlagData: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
graphHeightOffset: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
realPixelRatio: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showFlagContent: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
timeSeries: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
unitOfDisplay: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentDataIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
legendTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
computed: {
|
||||
formatTime() {
|
||||
return this.deploymentFlagData ?
|
||||
timeFormat(this.deploymentFlagData.time) :
|
||||
timeFormat(this.currentData.time);
|
||||
},
|
||||
|
||||
formatDate() {
|
||||
return this.deploymentFlagData ?
|
||||
dateFormat(this.deploymentFlagData.time) :
|
||||
dateFormat(this.currentData.time);
|
||||
},
|
||||
|
||||
cursorStyle() {
|
||||
const xCoordinate = this.deploymentFlagData ?
|
||||
this.deploymentFlagData.xPos :
|
||||
this.currentXCoordinate;
|
||||
|
||||
const offsetTop = 20 * this.realPixelRatio;
|
||||
const offsetLeft = (70 + xCoordinate) * this.realPixelRatio;
|
||||
const height = (this.graphHeight - this.graphHeightOffset) * this.realPixelRatio;
|
||||
|
||||
return {
|
||||
top: `${offsetTop}px`,
|
||||
left: `${offsetLeft}px`,
|
||||
height: `${height}px`,
|
||||
};
|
||||
},
|
||||
|
||||
flagOrientation() {
|
||||
if (this.currentXCoordinate * this.realPixelRatio > 120) {
|
||||
return 'left';
|
||||
}
|
||||
return 'right';
|
||||
},
|
||||
deploymentFlagData: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
|
||||
methods: {
|
||||
seriesMetricValue(series) {
|
||||
const index = this.deploymentFlagData ?
|
||||
this.deploymentFlagData.seriesIndex :
|
||||
this.currentDataIndex;
|
||||
const value = series.values[index] &&
|
||||
series.values[index].value;
|
||||
if (isNaN(value)) {
|
||||
return '-';
|
||||
}
|
||||
return `${formatRelevantDigits(value)}${this.unitOfDisplay}`;
|
||||
},
|
||||
|
||||
seriesMetricLabel(index, series) {
|
||||
if (this.timeSeries.length < 2) {
|
||||
return this.legendTitle;
|
||||
}
|
||||
if (series.metricTag) {
|
||||
return series.metricTag;
|
||||
}
|
||||
return `series ${index + 1}`;
|
||||
},
|
||||
|
||||
strokeDashArray(type) {
|
||||
if (type === 'dashed') return '6, 3';
|
||||
if (type === 'dotted') return '3, 3';
|
||||
return null;
|
||||
},
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
graphHeightOffset: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
realPixelRatio: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showFlagContent: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
timeSeries: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
unitOfDisplay: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentDataIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
legendTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
formatTime() {
|
||||
return this.deploymentFlagData
|
||||
? timeFormat(this.deploymentFlagData.time)
|
||||
: timeFormat(this.currentData.time);
|
||||
},
|
||||
formatDate() {
|
||||
return this.deploymentFlagData
|
||||
? dateFormat(this.deploymentFlagData.time)
|
||||
: dateFormat(this.currentData.time);
|
||||
},
|
||||
cursorStyle() {
|
||||
const xCoordinate = this.deploymentFlagData
|
||||
? this.deploymentFlagData.xPos
|
||||
: this.currentXCoordinate;
|
||||
|
||||
const offsetTop = 20 * this.realPixelRatio;
|
||||
const offsetLeft = (70 + xCoordinate) * this.realPixelRatio;
|
||||
const height = (this.graphHeight - this.graphHeightOffset) * this.realPixelRatio;
|
||||
|
||||
return {
|
||||
top: `${offsetTop}px`,
|
||||
left: `${offsetLeft}px`,
|
||||
height: `${height}px`,
|
||||
};
|
||||
},
|
||||
flagOrientation() {
|
||||
if (this.currentXCoordinate * this.realPixelRatio > 120) {
|
||||
return 'left';
|
||||
}
|
||||
return 'right';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
seriesMetricValue(series) {
|
||||
const index = this.deploymentFlagData
|
||||
? this.deploymentFlagData.seriesIndex
|
||||
: this.currentDataIndex;
|
||||
const value = series.values[index] && series.values[index].value;
|
||||
if (isNaN(value)) {
|
||||
return '-';
|
||||
}
|
||||
return `${formatRelevantDigits(value)}${this.unitOfDisplay}`;
|
||||
},
|
||||
seriesMetricLabel(index, series) {
|
||||
if (this.timeSeries.length < 2) {
|
||||
return this.legendTitle;
|
||||
}
|
||||
if (series.metricTag) {
|
||||
return series.metricTag;
|
||||
}
|
||||
return `series ${index + 1}`;
|
||||
},
|
||||
strokeDashArray(type) {
|
||||
if (type === 'dashed') return '6, 3';
|
||||
if (type === 'dotted') return '3, 3';
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,127 +1,119 @@
|
|||
<script>
|
||||
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
|
||||
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
graphWidth: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
margin: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
measurements: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
legendTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
yAxisLabel: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
timeSeries: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
unitOfDisplay: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentDataIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showLegendGroup: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
graphWidth: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
yLabelWidth: 0,
|
||||
yLabelHeight: 0,
|
||||
seriesXPosition: 0,
|
||||
metricUsageXPosition: 0,
|
||||
};
|
||||
graphHeight: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
textTransform() {
|
||||
const yCoordinate = (((this.graphHeight - this.margin.top)
|
||||
+ this.measurements.axisLabelLineOffset) / 2) || 0;
|
||||
|
||||
return `translate(15, ${yCoordinate}) rotate(-90)`;
|
||||
},
|
||||
|
||||
rectTransform() {
|
||||
const yCoordinate = (((this.graphHeight - this.margin.top)
|
||||
+ this.measurements.axisLabelLineOffset) / 2)
|
||||
+ (this.yLabelWidth / 2) || 0;
|
||||
|
||||
return `translate(0, ${yCoordinate}) rotate(-90)`;
|
||||
},
|
||||
|
||||
xPosition() {
|
||||
return (((this.graphWidth + this.measurements.axisLabelLineOffset) / 2)
|
||||
- this.margin.right) || 0;
|
||||
},
|
||||
|
||||
yPosition() {
|
||||
return ((this.graphHeight - this.margin.top) + this.measurements.axisLabelLineOffset) || 0;
|
||||
},
|
||||
|
||||
margin: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const bbox = this.$refs.ylabel.getBBox();
|
||||
this.metricUsageXPosition = 0;
|
||||
this.seriesXPosition = 0;
|
||||
if (this.$refs.legendTitleSvg != null) {
|
||||
this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width;
|
||||
}
|
||||
if (this.$refs.seriesTitleSvg != null) {
|
||||
this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width;
|
||||
}
|
||||
this.yLabelWidth = bbox.width + 10; // Added some padding
|
||||
this.yLabelHeight = bbox.height + 5;
|
||||
});
|
||||
measurements: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
methods: {
|
||||
translateLegendGroup(index) {
|
||||
return `translate(0, ${12 * (index)})`;
|
||||
},
|
||||
|
||||
formatMetricUsage(series) {
|
||||
const value = series.values[this.currentDataIndex] &&
|
||||
series.values[this.currentDataIndex].value;
|
||||
if (isNaN(value)) {
|
||||
return '-';
|
||||
}
|
||||
return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`;
|
||||
},
|
||||
|
||||
createSeriesString(index, series) {
|
||||
if (series.metricTag) {
|
||||
return `${series.metricTag} ${this.formatMetricUsage(series)}`;
|
||||
}
|
||||
return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`;
|
||||
},
|
||||
|
||||
strokeDashArray(type) {
|
||||
if (type === 'dashed') return '6, 3';
|
||||
if (type === 'dotted') return '3, 3';
|
||||
return null;
|
||||
},
|
||||
legendTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
yAxisLabel: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
timeSeries: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
unitOfDisplay: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentDataIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showLegendGroup: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
yLabelWidth: 0,
|
||||
yLabelHeight: 0,
|
||||
seriesXPosition: 0,
|
||||
metricUsageXPosition: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
textTransform() {
|
||||
const yCoordinate =
|
||||
(this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0;
|
||||
|
||||
return `translate(15, ${yCoordinate}) rotate(-90)`;
|
||||
},
|
||||
rectTransform() {
|
||||
const yCoordinate =
|
||||
(this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 +
|
||||
this.yLabelWidth / 2 || 0;
|
||||
|
||||
return `translate(0, ${yCoordinate}) rotate(-90)`;
|
||||
},
|
||||
xPosition() {
|
||||
return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0;
|
||||
},
|
||||
yPosition() {
|
||||
return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const bbox = this.$refs.ylabel.getBBox();
|
||||
this.metricUsageXPosition = 0;
|
||||
this.seriesXPosition = 0;
|
||||
if (this.$refs.legendTitleSvg != null) {
|
||||
this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width;
|
||||
}
|
||||
if (this.$refs.seriesTitleSvg != null) {
|
||||
this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width;
|
||||
}
|
||||
this.yLabelWidth = bbox.width + 10; // Added some padding
|
||||
this.yLabelHeight = bbox.height + 5;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
translateLegendGroup(index) {
|
||||
return `translate(0, ${12 * index})`;
|
||||
},
|
||||
formatMetricUsage(series) {
|
||||
const value =
|
||||
series.values[this.currentDataIndex] && series.values[this.currentDataIndex].value;
|
||||
if (isNaN(value)) {
|
||||
return '-';
|
||||
}
|
||||
return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`;
|
||||
},
|
||||
createSeriesString(index, series) {
|
||||
if (series.metricTag) {
|
||||
return `${series.metricTag} ${this.formatMetricUsage(series)}`;
|
||||
}
|
||||
return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`;
|
||||
},
|
||||
strokeDashArray(type) {
|
||||
if (type === 'dashed') return '6, 3';
|
||||
if (type === 'dotted') return '3, 3';
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<g class="axis-label-container">
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
generatedLinePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
generatedAreaPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
lineStyle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
lineColor: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
areaColor: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
generatedLinePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
strokeDashArray() {
|
||||
if (this.lineStyle === 'dashed') return '3, 1';
|
||||
if (this.lineStyle === 'dotted') return '1, 1';
|
||||
return null;
|
||||
},
|
||||
generatedAreaPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
lineStyle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
lineColor: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
areaColor: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
strokeDashArray() {
|
||||
if (this.lineStyle === 'dashed') return '3, 1';
|
||||
if (this.lineStyle === 'dotted') return '1, 1';
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<g>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showPanels: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
showPanels: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
Loading…
Reference in a new issue