@grafana/ui
Version:
Grafana Components Library
495 lines (492 loc) • 16 kB
JavaScript
import { jsx } from 'react/jsx-runtime';
import tinycolor from 'tinycolor2';
import { FieldType, formattedValueToString } from '@grafana/data';
import { GraphDrawStyle, PercentChangeColorMode } from '@grafana/schema';
import { getTextColorForAlphaBackground } from '../../utils/colors.mjs';
import { calculateFontSize } from '../../utils/measureText.mjs';
import { Sparkline } from '../Sparkline/Sparkline.mjs';
import { BigValueColorMode, BigValueTextMode, BigValueJustifyMode } from './BigValue.mjs';
import { percentChangeString } from './PercentChange.mjs';
"use strict";
const LINE_HEIGHT = 1.2;
const MAX_TITLE_SIZE = 30;
const VALUE_FONT_WEIGHT = 500;
class BigValueLayout {
constructor(props) {
this.props = props;
var _a;
const { width, height, value, text } = props;
this.valueColor = (_a = value.color) != null ? _a : "gray";
this.panelPadding = height > 100 ? 12 : 8;
this.textValues = getTextValues(props);
this.justifyCenter = shouldJustifyCenter(props.justifyMode, this.textValues.title);
this.valueToAlignTo = this.textValues.valueToAlignTo;
this.titleToAlignTo = this.textValues.titleToAlignTo;
this.titleFontSize = 0;
this.valueFontSize = 0;
this.percentFontSize = 0;
this.chartHeight = 0;
this.chartWidth = 0;
this.maxTextWidth = width - this.panelPadding * 2;
this.maxTextHeight = height - this.panelPadding * 2;
if (text) {
if (text.titleSize) {
this.titleFontSize = text.titleSize;
this.titleToAlignTo = void 0;
}
if (text.valueSize) {
this.valueFontSize = text.valueSize;
this.valueToAlignTo = "";
}
if (text.percentSize) {
this.percentFontSize = text.percentSize;
}
}
}
getTitleStyles() {
const styles = {
fontSize: `${this.titleFontSize}px`,
lineHeight: LINE_HEIGHT
};
if (this.props.colorMode === BigValueColorMode.Background || this.props.colorMode === BigValueColorMode.BackgroundSolid) {
styles.color = getTextColorForAlphaBackground(this.valueColor, this.props.theme.isDark);
}
return styles;
}
getValueStyles() {
const styles = {
fontSize: this.valueFontSize,
fontWeight: VALUE_FONT_WEIGHT,
lineHeight: LINE_HEIGHT,
position: "relative",
zIndex: 1
};
if (this.justifyCenter) {
styles.textAlign = "center";
}
switch (this.props.colorMode) {
case BigValueColorMode.Value:
styles.color = this.valueColor;
break;
case BigValueColorMode.Background:
case BigValueColorMode.BackgroundSolid:
styles.color = getTextColorForAlphaBackground(this.valueColor, this.props.theme.isDark);
break;
case BigValueColorMode.None:
styles.color = this.props.theme.colors.text.primary;
break;
}
return styles;
}
getPercentChangeStyles(percentChange, percentChangeColorMode, valueStyles) {
const VALUE_TO_PERCENT_CHANGE_RATIO = 2.5;
const valueContainerStyles = this.getValueAndTitleContainerStyles();
const percentFontSize = this.percentFontSize || Math.max(this.valueFontSize / VALUE_TO_PERCENT_CHANGE_RATIO, 12);
let iconSize = this.percentFontSize ? this.percentFontSize - 3 : Math.max(this.valueFontSize / 3, 10);
const themeVisualizationColors = this.props.theme.visualization;
const color = getPercentChangeColor(percentChange, percentChangeColorMode, valueStyles, themeVisualizationColors);
const containerStyles = {
fontSize: percentFontSize,
fontWeight: VALUE_FONT_WEIGHT,
lineHeight: LINE_HEIGHT,
position: "relative",
display: "flex",
alignItems: "center",
gap: Math.max(percentFontSize / 3, 4),
zIndex: 1,
color
};
if (this.justifyCenter) {
containerStyles.textAlign = "center";
}
if (valueContainerStyles.flexDirection === "column" && percentFontSize > 12) {
containerStyles.marginTop = -(percentFontSize / 4);
}
if (valueContainerStyles.flexDirection === "row") {
containerStyles.alignItems = "baseline";
containerStyles.lineHeight = LINE_HEIGHT * VALUE_TO_PERCENT_CHANGE_RATIO;
}
switch (this.props.colorMode) {
case BigValueColorMode.Background:
case BigValueColorMode.BackgroundSolid:
containerStyles.color = getTextColorForAlphaBackground(this.valueColor, this.props.theme.isDark);
break;
}
if (this.props.textMode === BigValueTextMode.None) {
containerStyles.fontSize = calculateFontSize(
percentChangeString(percentChange),
this.maxTextWidth * 0.8,
this.maxTextHeight * 0.8,
LINE_HEIGHT,
void 0,
VALUE_FONT_WEIGHT
);
iconSize = containerStyles.fontSize * 0.8;
}
return {
containerStyles,
iconSize
};
}
getValueAndTitleContainerStyles() {
const styles = {
display: "flex",
flexWrap: "wrap"
};
if (this.justifyCenter) {
styles.alignItems = "center";
styles.justifyContent = "center";
styles.flexGrow = 1;
styles.gap = "0.75ch";
}
return styles;
}
getPanelStyles() {
const { width, height, theme, colorMode, textMode } = this.props;
const panelStyles = {
width: `${width}px`,
height: `${height}px`,
padding: `${textMode === BigValueTextMode.None ? 2 : this.panelPadding}px`,
position: "relative",
display: "flex"
};
const themeFactor = theme.isDark ? 1 : -0.7;
switch (colorMode) {
case BigValueColorMode.Background:
const bgColor2 = tinycolor(this.valueColor).darken(15 * themeFactor).spin(8).toRgbString();
const bgColor3 = tinycolor(this.valueColor).darken(5 * themeFactor).spin(-8).toRgbString();
panelStyles.background = `linear-gradient(120deg, ${bgColor2}, ${bgColor3})`;
break;
case BigValueColorMode.BackgroundSolid:
panelStyles.background = tinycolor(this.valueColor).toString();
break;
case BigValueColorMode.Value:
panelStyles.background = `transparent`;
break;
}
if (this.justifyCenter) {
panelStyles.alignItems = "center";
panelStyles.flexDirection = "row";
}
return panelStyles;
}
renderChart() {
var _a;
const { sparkline, colorMode } = this.props;
if (!sparkline || ((_a = sparkline.y) == null ? void 0 : _a.type) !== FieldType.number) {
return null;
}
let fillColor;
let lineColor;
switch (colorMode) {
case BigValueColorMode.Background:
case BigValueColorMode.BackgroundSolid:
fillColor = "rgba(255,255,255,0.4)";
lineColor = tinycolor(this.valueColor).brighten(40).toRgbString();
break;
case BigValueColorMode.None:
case BigValueColorMode.Value:
default:
lineColor = this.valueColor;
fillColor = tinycolor(this.valueColor).setAlpha(0.2).toRgbString();
break;
}
const config = {
custom: {
drawStyle: GraphDrawStyle.Line,
lineWidth: 1,
fillColor,
lineColor
}
};
return /* @__PURE__ */ jsx("div", { style: this.getChartStyles(), children: /* @__PURE__ */ jsx(
Sparkline,
{
height: this.chartHeight,
width: this.chartWidth,
sparkline,
config,
theme: this.props.theme
}
) });
}
getChartStyles() {
return {
position: "absolute",
right: 0,
bottom: 0
};
}
}
class WideNoChartLayout extends BigValueLayout {
constructor(props) {
var _a, _b;
super(props);
const valueWidthPercent = ((_a = this.titleToAlignTo) == null ? void 0 : _a.length) ? 0.3 : 1;
if (this.valueToAlignTo.length) {
let valueHeight = this.maxTextHeight;
if (props.value.percentChange != null) {
valueHeight = valueHeight * 0.75;
}
this.valueFontSize = calculateFontSize(
this.valueToAlignTo,
this.maxTextWidth * valueWidthPercent,
valueHeight,
LINE_HEIGHT,
void 0,
VALUE_FONT_WEIGHT
);
}
if ((_b = this.titleToAlignTo) == null ? void 0 : _b.length) {
this.titleFontSize = calculateFontSize(
this.titleToAlignTo,
this.maxTextWidth * 0.6,
this.maxTextHeight,
LINE_HEIGHT,
MAX_TITLE_SIZE
);
this.titleFontSize = Math.min(this.valueFontSize * 0.7, this.titleFontSize);
}
}
getValueAndTitleContainerStyles() {
const styles = super.getValueAndTitleContainerStyles();
styles.flexDirection = "row";
styles.alignItems = "center";
styles.flexGrow = 1;
if (!this.justifyCenter) {
styles.justifyContent = "space-between";
}
return styles;
}
renderChart() {
return null;
}
getPanelStyles() {
const panelStyles = super.getPanelStyles();
panelStyles.alignItems = "center";
return panelStyles;
}
}
class WideWithChartLayout extends BigValueLayout {
constructor(props) {
var _a;
super(props);
const { width, height } = props;
const chartHeightPercent = 0.5;
const titleWidthPercent = 0.6;
const valueWidthPercent = 1 - titleWidthPercent;
const textHeightPercent = 0.4;
this.chartWidth = width;
this.chartHeight = height * chartHeightPercent;
if ((_a = this.titleToAlignTo) == null ? void 0 : _a.length) {
this.titleFontSize = calculateFontSize(
this.titleToAlignTo,
this.maxTextWidth * titleWidthPercent,
this.maxTextHeight * textHeightPercent,
LINE_HEIGHT,
MAX_TITLE_SIZE
);
}
if (this.valueToAlignTo.length) {
this.valueFontSize = calculateFontSize(
this.valueToAlignTo,
this.maxTextWidth * valueWidthPercent,
this.maxTextHeight * chartHeightPercent,
LINE_HEIGHT,
void 0,
VALUE_FONT_WEIGHT
);
}
}
getValueAndTitleContainerStyles() {
const styles = super.getValueAndTitleContainerStyles();
styles.flexDirection = "row";
styles.flexGrow = 1;
if (!this.justifyCenter) {
styles.justifyContent = "space-between";
}
return styles;
}
getPanelStyles() {
const styles = super.getPanelStyles();
styles.flexDirection = "row";
styles.justifyContent = "space-between";
return styles;
}
}
class StackedWithChartLayout extends BigValueLayout {
constructor(props) {
var _a, _b;
super(props);
const { width, height } = props;
const titleHeightPercent = 0.15;
const chartHeightPercent = 0.25;
let titleHeight = 0;
this.chartHeight = height * chartHeightPercent;
this.chartWidth = width;
if ((_a = this.titleToAlignTo) == null ? void 0 : _a.length) {
this.titleFontSize = calculateFontSize(
this.titleToAlignTo,
this.maxTextWidth,
height * titleHeightPercent,
LINE_HEIGHT,
MAX_TITLE_SIZE
);
titleHeight = this.titleFontSize * LINE_HEIGHT;
}
if (this.valueToAlignTo.length) {
this.valueFontSize = calculateFontSize(
this.valueToAlignTo,
this.maxTextWidth,
this.maxTextHeight - this.chartHeight - titleHeight,
LINE_HEIGHT,
void 0,
VALUE_FONT_WEIGHT
);
}
if ((_b = this.titleToAlignTo) == null ? void 0 : _b.length) {
this.titleFontSize = Math.min(this.valueFontSize * 0.7, this.titleFontSize);
}
this.chartHeight = height - this.titleFontSize * LINE_HEIGHT - this.valueFontSize * LINE_HEIGHT;
}
getValueAndTitleContainerStyles() {
const styles = super.getValueAndTitleContainerStyles();
styles.flexDirection = "column";
styles.justifyContent = "center";
return styles;
}
getPanelStyles() {
const styles = super.getPanelStyles();
styles.flexDirection = "column";
return styles;
}
}
class StackedWithNoChartLayout extends BigValueLayout {
constructor(props) {
var _a, _b;
super(props);
const { height } = props;
const titleHeightPercent = 0.15;
let titleHeight = 0;
if ((_a = this.titleToAlignTo) == null ? void 0 : _a.length) {
this.titleFontSize = calculateFontSize(
this.titleToAlignTo,
this.maxTextWidth,
height * titleHeightPercent,
LINE_HEIGHT,
MAX_TITLE_SIZE
);
titleHeight = this.titleFontSize * LINE_HEIGHT;
}
if (this.valueToAlignTo.length) {
let valueHeight = this.maxTextHeight - titleHeight;
if (props.value.percentChange != null) {
valueHeight = valueHeight * 0.75;
}
this.valueFontSize = calculateFontSize(
this.valueToAlignTo,
this.maxTextWidth,
valueHeight,
LINE_HEIGHT,
void 0,
VALUE_FONT_WEIGHT
);
}
if ((_b = this.titleToAlignTo) == null ? void 0 : _b.length) {
this.titleFontSize = Math.min(this.valueFontSize * 0.7, this.titleFontSize);
}
}
getValueAndTitleContainerStyles() {
const styles = super.getValueAndTitleContainerStyles();
styles.flexDirection = "column";
styles.flexGrow = 1;
return styles;
}
renderChart() {
return null;
}
getPanelStyles() {
const styles = super.getPanelStyles();
styles.alignItems = "center";
return styles;
}
}
function buildLayout(props) {
const { width, height, sparkline } = props;
const useWideLayout = width / height > 2.5 && !props.disableWideLayout;
if (useWideLayout) {
if (height > 50 && !!sparkline && sparkline.y.values.length > 1) {
return new WideWithChartLayout(props);
} else {
return new WideNoChartLayout(props);
}
}
if (height > 100 && sparkline && sparkline.y.values.length > 1) {
return new StackedWithChartLayout(props);
} else {
return new StackedWithNoChartLayout(props);
}
}
function shouldJustifyCenter(justifyMode, title) {
if (justifyMode === BigValueJustifyMode.Center) {
return true;
}
return (title != null ? title : "").length === 0;
}
function getTextValues(props) {
const { value, alignmentFactors, count } = props;
let { textMode } = props;
const titleToAlignTo = alignmentFactors ? alignmentFactors.title : value.title;
const valueToAlignTo = formattedValueToString(alignmentFactors ? alignmentFactors : value);
if (textMode === BigValueTextMode.Auto && (count != null ? count : 1) === 1) {
textMode = BigValueTextMode.Value;
}
switch (textMode) {
case BigValueTextMode.Name:
return {
...value,
title: void 0,
prefix: void 0,
suffix: void 0,
text: value.title || "",
titleToAlignTo: void 0,
valueToAlignTo: titleToAlignTo != null ? titleToAlignTo : "",
tooltip: formattedValueToString(value)
};
case BigValueTextMode.Value:
return {
...value,
title: void 0,
titleToAlignTo: void 0,
valueToAlignTo,
tooltip: value.title
};
case BigValueTextMode.None:
return {
numeric: value.numeric,
color: value.color,
title: void 0,
text: "",
titleToAlignTo: void 0,
valueToAlignTo: "1",
tooltip: `Name: ${value.title}
Value: ${formattedValueToString(value)}`
};
case BigValueTextMode.ValueAndName:
default:
return {
...value,
titleToAlignTo,
valueToAlignTo
};
}
}
function getPercentChangeColor(percentChange, percentChangeColorMode, valueStyles, themeVisualizationColors) {
if (percentChangeColorMode === PercentChangeColorMode.SameAsValue) {
return valueStyles.color;
} else {
return percentChange * (percentChangeColorMode === PercentChangeColorMode.Inverted ? -1 : 1) > 0 ? themeVisualizationColors.getColorByName("green") : themeVisualizationColors.getColorByName("red");
}
}
export { BigValueLayout, StackedWithChartLayout, StackedWithNoChartLayout, WideNoChartLayout, WideWithChartLayout, buildLayout, getPercentChangeColor, shouldJustifyCenter };
//# sourceMappingURL=BigValueLayout.mjs.map