summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/memory_graph.vue
blob: 26d7d8e88667c5ae56d081003f9f48dbe52953e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<script>
import { __, sprintf } from '~/locale';
import { getTimeago } from '../../lib/utils/datetime_utility';

export default {
  name: 'MemoryGraph',
  props: {
    metrics: { type: Array, required: true },
    deploymentTime: { type: Number, required: true },
    width: { type: String, required: true },
    height: { type: String, required: true },
  },
  data() {
    return {
      pathD: '',
      pathViewBox: '',
      dotX: '',
      dotY: '',
    };
  },
  computed: {
    getFormattedMedian() {
      const deployedSince = getTimeago().format(this.deploymentTime * 1000);
      return sprintf(__('Deployed %{deployedSince}'), { deployedSince });
    },
  },
  mounted() {
    this.renderGraph(this.deploymentTime, this.metrics);
  },
  methods: {
    /**
     * Returns metric value index in metrics array
     * with timestamp closest to matching median
     */
    getMedianMetricIndex(median, metrics) {
      let matchIndex = 0;
      let timestampDiff = 0;
      let smallestDiff = 0;

      const metricTimestamps = metrics.map(v => v[0]);

      // Find metric timestamp which is closest to deploymentTime
      timestampDiff = Math.abs(metricTimestamps[0] - median);
      metricTimestamps.forEach((timestamp, index) => {
        if (index === 0) {
          // Skip first element
          return;
        }

        smallestDiff = Math.abs(timestamp - median);
        if (smallestDiff < timestampDiff) {
          matchIndex = index;
          timestampDiff = smallestDiff;
        }
      });

      return matchIndex;
    },

    /**
     * Get Graph Plotting values to render Line and Dot
     */
    getGraphPlotValues(median, metrics) {
      const renderData = metrics.map(v => v[1]);
      const medianMetricIndex = this.getMedianMetricIndex(median, metrics);
      let cx = 0;
      let cy = 0;

      // Find Maximum and Minimum values from `renderData` array
      const maxMemory = Math.max.apply(null, renderData);
      const minMemory = Math.min.apply(null, renderData);

      // Find difference between extreme ends
      const diff = maxMemory - minMemory;
      const lineWidth = renderData.length;

      // Iterate over metrics values and perform following
      // 1. Find x & y co-ords for deploymentTime's memory value
      // 2. Return line path against maxMemory
      const linePath = renderData.map((y, x) => {
        if (medianMetricIndex === x) {
          cx = x;
          cy = maxMemory - y;
        }
        return `${x} ${maxMemory - y}`;
      });

      return {
        pathD: linePath,
        pathViewBox: {
          lineWidth,
          diff,
        },
        dotX: cx,
        dotY: cy,
      };
    },

    /**
     * Render Graph based on provided median and metrics values
     */
    renderGraph(median, metrics) {
      const { pathD, pathViewBox, dotX, dotY } = this.getGraphPlotValues(median, metrics);

      // Set props and update graph on UI.
      this.pathD = `M ${pathD}`;
      this.pathViewBox = `0 0 ${pathViewBox.lineWidth} ${pathViewBox.diff}`;
      this.dotX = dotX;
      this.dotY = dotY;
    },
  },
};
</script>

<template>
  <div class="memory-graph-container">
    <svg
      :title="getFormattedMedian"
      :width="width"
      :height="height"
      class="has-tooltip"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path :d="pathD" :viewBox="pathViewBox" />
      <circle :cx="dotX" :cy="dotY" r="1.5" transform="translate(0 -1)" />
    </svg>
  </div>
</template>