grafana/public/app/plugins/panel/graph/align_yaxes.ts
Stephanie Closson 3acc318d72
Chore: reduce null check errors to 788 (currently over 798) (#23449)
* Fixed ts errors so build will succeed

* Update packages/grafana-data/src/types/graph.ts

Co-Authored-By: Ryan McKinley <ryantxu@gmail.com>

* Feedback from code review

* Leaving out trivial typing's

* Fix error with color being undefined now.

* fix test with timezone issue

* Fixed test

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2020-04-09 08:29:36 +02:00

161 lines
4.7 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: any, level: any) {
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: { max: number; min: number }, yRight: { max: number; min: number }) {
// 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: { min: number; max: number }, yRight: { min: number; max: number }, level: number) {
if (level !== 0) {
yLeft.min -= level;
yLeft.max -= level;
yRight.min -= level;
yRight.max -= level;
}
}
function restoreLevelFromZero(
yLeft: { min: number; max: number },
yRight: { min: number; max: number },
level: number
) {
if (level !== 0) {
yLeft.min += level;
yLeft.max += level;
yRight.min += level;
yRight.max += level;
}
}
interface AxisSide {
max: number;
min: number;
}
function checkCorrectAxis(axis: any[]): boolean {
return axis.length === 2 && checkCorrectAxes(axis[0]) && checkCorrectAxes(axis[1]);
}
function checkCorrectAxes(axes: any): boolean {
return 'min' in axes && 'max' in axes;
}
function checkOneSide(yLeft: AxisSide, yRight: AxisSide): boolean {
// on the one hand with respect to zero
return (yLeft.min >= 0 && yRight.min >= 0) || (yLeft.max <= 0 && yRight.max <= 0);
}
function checkTwoCross(yLeft: AxisSide, yRight: AxisSide): boolean {
// both across zero
return yLeft.min <= 0 && yLeft.max >= 0 && yRight.min <= 0 && yRight.max >= 0;
}
function checkOppositeSides(yLeft: AxisSide, yRight: AxisSide): boolean {
// on the opposite sides with respect to zero
return (yLeft.min >= 0 && yRight.max <= 0) || (yLeft.max <= 0 && yRight.min >= 0);
}
function getRate(yLeft: AxisSide, yRight: AxisSide): number {
if (checkTwoCross(yLeft, yRight)) {
const rateLeft = yRight.min ? yLeft.min / yRight.min : 0;
const rateRight = yRight.max ? yLeft.max / yRight.max : 0;
return rateLeft > rateRight ? rateLeft : rateRight;
}
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 = Math.max(absLeftMin, absLeftMax);
const downLeft = Math.min(absLeftMin, absLeftMax);
const upRight = Math.max(absRightMin, absRightMax);
const downRight = Math.min(absRightMin, absRightMax);
const rateLeft = downLeft !== 0 ? upLeft / downLeft : upLeft;
const rateRight = downRight !== 0 ? upRight / downRight : upRight;
return rateLeft > rateRight ? rateLeft : rateRight;
}
if (yLeft.min > 0 || yRight.min > 0) {
return yLeft.max / yRight.max;
} else {
return yLeft.min / yRight.min;
}
}