mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 10:03:33 -06:00
155 lines
4.4 KiB
TypeScript
155 lines
4.4 KiB
TypeScript
import _ from 'lodash';
|
|
|
|
/**
|
|
* To align two Y axes by Y level
|
|
* @param yAxes data [{min: min_y1, min: max_y1}, {min: min_y2, max: max_y2}]
|
|
* @param level Y level
|
|
*/
|
|
export function alignYLevel(yAxes, level) {
|
|
if (isNaN(level) || !checkCorrectAxis(yAxes)) {
|
|
return;
|
|
}
|
|
|
|
const [yLeft, yRight] = yAxes;
|
|
moveLevelToZero(yLeft, yRight, level);
|
|
|
|
expandStuckValues(yLeft, yRight);
|
|
|
|
// one of graphs on zero
|
|
const zero = yLeft.min === 0 || yRight.min === 0 || yLeft.max === 0 || yRight.max === 0;
|
|
|
|
const oneSide = checkOneSide(yLeft, yRight);
|
|
|
|
if (zero && oneSide) {
|
|
yLeft.min = yLeft.max > 0 ? 0 : yLeft.min;
|
|
yLeft.max = yLeft.max > 0 ? yLeft.max : 0;
|
|
yRight.min = yRight.max > 0 ? 0 : yRight.min;
|
|
yRight.max = yRight.max > 0 ? yRight.max : 0;
|
|
} else {
|
|
if (checkOppositeSides(yLeft, yRight)) {
|
|
if (yLeft.min >= 0) {
|
|
yLeft.min = -yLeft.max;
|
|
yRight.max = -yRight.min;
|
|
} else {
|
|
yLeft.max = -yLeft.min;
|
|
yRight.min = -yRight.max;
|
|
}
|
|
} else {
|
|
const rate = getRate(yLeft, yRight);
|
|
|
|
if (oneSide) {
|
|
// all graphs above the Y level
|
|
if (yLeft.min > 0) {
|
|
yLeft.min = yLeft.max / rate;
|
|
yRight.min = yRight.max / rate;
|
|
} else {
|
|
yLeft.max = yLeft.min / rate;
|
|
yRight.max = yRight.min / rate;
|
|
}
|
|
} else {
|
|
if (checkTwoCross(yLeft, yRight)) {
|
|
yLeft.min = yRight.min ? yRight.min * rate : yLeft.min;
|
|
yRight.min = yLeft.min ? yLeft.min / rate : yRight.min;
|
|
yLeft.max = yRight.max ? yRight.max * rate : yLeft.max;
|
|
yRight.max = yLeft.max ? yLeft.max / rate : yRight.max;
|
|
} else {
|
|
yLeft.min = yLeft.min > 0 ? yRight.min * rate : yLeft.min;
|
|
yRight.min = yRight.min > 0 ? yLeft.min / rate : yRight.min;
|
|
yLeft.max = yLeft.max < 0 ? yRight.max * rate : yLeft.max;
|
|
yRight.max = yRight.max < 0 ? yLeft.max / rate : yRight.max;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
restoreLevelFromZero(yLeft, yRight, level);
|
|
}
|
|
|
|
function expandStuckValues(yLeft, yRight) {
|
|
// wide Y min and max using increased wideFactor
|
|
const wideFactor = 0.25;
|
|
if (yLeft.max === yLeft.min) {
|
|
yLeft.min -= wideFactor;
|
|
yLeft.max += wideFactor;
|
|
}
|
|
if (yRight.max === yRight.min) {
|
|
yRight.min -= wideFactor;
|
|
yRight.max += wideFactor;
|
|
}
|
|
}
|
|
|
|
function moveLevelToZero(yLeft, yRight, level) {
|
|
if (level !== 0) {
|
|
yLeft.min -= level;
|
|
yLeft.max -= level;
|
|
yRight.min -= level;
|
|
yRight.max -= level;
|
|
}
|
|
}
|
|
|
|
function restoreLevelFromZero(yLeft, yRight, level) {
|
|
if (level !== 0) {
|
|
yLeft.min += level;
|
|
yLeft.max += level;
|
|
yRight.min += level;
|
|
yRight.max += level;
|
|
}
|
|
}
|
|
|
|
function checkCorrectAxis(axis) {
|
|
return axis.length === 2 && checkCorrectAxes(axis[0]) && checkCorrectAxes(axis[1]);
|
|
}
|
|
|
|
function checkCorrectAxes(axes) {
|
|
return 'min' in axes && 'max' in axes;
|
|
}
|
|
|
|
function checkOneSide(yLeft, yRight) {
|
|
// on the one hand with respect to zero
|
|
return (yLeft.min >= 0 && yRight.min >= 0) || (yLeft.max <= 0 && yRight.max <= 0);
|
|
}
|
|
|
|
function checkTwoCross(yLeft, yRight) {
|
|
// both across zero
|
|
return yLeft.min <= 0 && yLeft.max >= 0 && yRight.min <= 0 && yRight.max >= 0;
|
|
}
|
|
|
|
function checkOppositeSides(yLeft, yRight) {
|
|
// on the opposite sides with respect to zero
|
|
return (yLeft.min >= 0 && yRight.max <= 0) || (yLeft.max <= 0 && yRight.min >= 0);
|
|
}
|
|
|
|
function getRate(yLeft, yRight) {
|
|
let rateLeft, rateRight, rate;
|
|
if (checkTwoCross(yLeft, yRight)) {
|
|
rateLeft = yRight.min ? yLeft.min / yRight.min : 0;
|
|
rateRight = yRight.max ? yLeft.max / yRight.max : 0;
|
|
} else {
|
|
if (checkOneSide(yLeft, yRight)) {
|
|
const absLeftMin = Math.abs(yLeft.min);
|
|
const absLeftMax = Math.abs(yLeft.max);
|
|
const absRightMin = Math.abs(yRight.min);
|
|
const absRightMax = Math.abs(yRight.max);
|
|
const upLeft = _.max([absLeftMin, absLeftMax]);
|
|
const downLeft = _.min([absLeftMin, absLeftMax]);
|
|
const upRight = _.max([absRightMin, absRightMax]);
|
|
const downRight = _.min([absRightMin, absRightMax]);
|
|
|
|
rateLeft = downLeft ? upLeft / downLeft : upLeft;
|
|
rateRight = downRight ? upRight / downRight : upRight;
|
|
} else {
|
|
if (yLeft.min > 0 || yRight.min > 0) {
|
|
rateLeft = yLeft.max / yRight.max;
|
|
rateRight = 0;
|
|
} else {
|
|
rateLeft = 0;
|
|
rateRight = yLeft.min / yRight.min;
|
|
}
|
|
}
|
|
}
|
|
|
|
rate = rateLeft > rateRight ? rateLeft : rateRight;
|
|
|
|
return rate;
|
|
}
|