|
|
|
@ -1,19 +1,166 @@ |
|
|
|
|
// Libraries
|
|
|
|
|
import _ from 'lodash'; |
|
|
|
|
|
|
|
|
|
// Utils
|
|
|
|
|
import colors from 'app/core/utils/colors'; |
|
|
|
|
import { TimeSeries, TimeSeriesVMs } from 'app/types'; |
|
|
|
|
|
|
|
|
|
// Types
|
|
|
|
|
import { TimeSeries, TimeSeriesVMs, NullValueMode } from 'app/types'; |
|
|
|
|
|
|
|
|
|
interface Options { |
|
|
|
|
timeSeries: TimeSeries[]; |
|
|
|
|
nullValueMode: NullValueMode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export function getTimeSeriesVMs({ timeSeries }: Options): TimeSeriesVMs { |
|
|
|
|
export function getTimeSeriesVMs({ timeSeries, nullValueMode }: Options): TimeSeriesVMs { |
|
|
|
|
const vmSeries = timeSeries.map((item, index) => { |
|
|
|
|
const colorIndex = index % colors.length; |
|
|
|
|
const label = item.target; |
|
|
|
|
const result = []; |
|
|
|
|
|
|
|
|
|
// stat defaults
|
|
|
|
|
let total = 0; |
|
|
|
|
let max = -Number.MAX_VALUE; |
|
|
|
|
let min = Number.MAX_VALUE; |
|
|
|
|
let logmin = Number.MAX_VALUE; |
|
|
|
|
let avg = null; |
|
|
|
|
let current = null; |
|
|
|
|
let first = null; |
|
|
|
|
let delta = 0; |
|
|
|
|
let diff = null; |
|
|
|
|
let range = null; |
|
|
|
|
let timeStep = Number.MAX_VALUE; |
|
|
|
|
let allIsNull = true; |
|
|
|
|
let allIsZero = true; |
|
|
|
|
|
|
|
|
|
const ignoreNulls = nullValueMode === NullValueMode.Ignore; |
|
|
|
|
const nullAsZero = nullValueMode === NullValueMode.AsZero; |
|
|
|
|
|
|
|
|
|
let currentTime; |
|
|
|
|
let currentValue; |
|
|
|
|
let nonNulls = 0; |
|
|
|
|
let previousTime; |
|
|
|
|
let previousValue = 0; |
|
|
|
|
let previousDeltaUp = true; |
|
|
|
|
|
|
|
|
|
for (let i = 0; i < item.datapoints.length; i++) { |
|
|
|
|
currentValue = item.datapoints[i][0]; |
|
|
|
|
currentTime = item.datapoints[i][1]; |
|
|
|
|
|
|
|
|
|
// Due to missing values we could have different timeStep all along the series
|
|
|
|
|
// so we have to find the minimum one (could occur with aggregators such as ZimSum)
|
|
|
|
|
if (previousTime !== undefined) { |
|
|
|
|
const currentStep = currentTime - previousTime; |
|
|
|
|
if (currentStep < timeStep) { |
|
|
|
|
timeStep = currentStep; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
previousTime = currentTime; |
|
|
|
|
|
|
|
|
|
if (currentValue === null) { |
|
|
|
|
if (ignoreNulls) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (nullAsZero) { |
|
|
|
|
currentValue = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (currentValue !== null) { |
|
|
|
|
if (_.isNumber(currentValue)) { |
|
|
|
|
total += currentValue; |
|
|
|
|
allIsNull = false; |
|
|
|
|
nonNulls++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (currentValue > max) { |
|
|
|
|
max = currentValue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (currentValue < min) { |
|
|
|
|
min = currentValue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (first === null) { |
|
|
|
|
first = currentValue; |
|
|
|
|
} else { |
|
|
|
|
if (previousValue > currentValue) { |
|
|
|
|
// counter reset
|
|
|
|
|
previousDeltaUp = false; |
|
|
|
|
if (i === item.datapoints.length - 1) { |
|
|
|
|
// reset on last
|
|
|
|
|
delta += currentValue; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (previousDeltaUp) { |
|
|
|
|
delta += currentValue - previousValue; // normal increment
|
|
|
|
|
} else { |
|
|
|
|
delta += currentValue; // account for counter reset
|
|
|
|
|
} |
|
|
|
|
previousDeltaUp = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
previousValue = currentValue; |
|
|
|
|
|
|
|
|
|
if (currentValue < logmin && currentValue > 0) { |
|
|
|
|
logmin = currentValue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (currentValue !== 0) { |
|
|
|
|
allIsZero = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result.push([currentTime, currentValue]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (max === -Number.MAX_VALUE) { |
|
|
|
|
max = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (min === Number.MAX_VALUE) { |
|
|
|
|
min = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (result.length && !allIsNull) { |
|
|
|
|
avg = total / nonNulls; |
|
|
|
|
current = result[result.length - 1][1]; |
|
|
|
|
if (current === null && result.length > 1) { |
|
|
|
|
current = result[result.length - 2][1]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (max !== null && min !== null) { |
|
|
|
|
range = max - min; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current !== null && first !== null) { |
|
|
|
|
diff = current - first; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const count = result.length; |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
data: item.datapoints, |
|
|
|
|
data: result, |
|
|
|
|
label: label, |
|
|
|
|
color: colors[colorIndex], |
|
|
|
|
stats: { |
|
|
|
|
total, |
|
|
|
|
min, |
|
|
|
|
max, |
|
|
|
|
current, |
|
|
|
|
logmin, |
|
|
|
|
avg, |
|
|
|
|
diff, |
|
|
|
|
delta, |
|
|
|
|
timeStep, |
|
|
|
|
range, |
|
|
|
|
count, |
|
|
|
|
first, |
|
|
|
|
allIsZero, |
|
|
|
|
allIsNull, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|