BarChart: value label sizing (#34229)
* Bar chart label positioning and sizing * Dev dashbard * Improve autosizing * Remove sync option * Unify text sizing options between stat-ish visualizations and bar chart * Add simple categorical data scenario and update dev dashboard * Remove unused options builder * Add docs annotations * Fix go lint
This commit is contained in:
@@ -0,0 +1,577 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": "-- Grafana --",
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"gnetId": null,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": 441,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 13,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 9,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"showValue": "auto",
|
||||||
|
"text": {},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Plenty od data, automatic value sizing",
|
||||||
|
"type": "barchart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 12,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 13
|
||||||
|
},
|
||||||
|
"id": 10,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"showValue": "auto",
|
||||||
|
"text": {
|
||||||
|
"size": 10,
|
||||||
|
"valueSize": 10
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Plenty od data, fixed value sizing",
|
||||||
|
"type": "barchart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 12,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 25
|
||||||
|
},
|
||||||
|
"id": 11,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"showValue": "auto",
|
||||||
|
"text": {
|
||||||
|
"size": 10
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Auto font size, value auto visible",
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterByValue",
|
||||||
|
"options": {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Bedroom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Cellar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match": "any",
|
||||||
|
"type": "include"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "barchart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 12,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 25
|
||||||
|
},
|
||||||
|
"id": 12,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"showValue": "always",
|
||||||
|
"text": {
|
||||||
|
"size": 10
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Auto font size, value always visible",
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterByValue",
|
||||||
|
"options": {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Bedroom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Cellar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match": "any",
|
||||||
|
"type": "include"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "barchart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 12,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 37
|
||||||
|
},
|
||||||
|
"id": 13,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "horizontal",
|
||||||
|
"showValue": "auto",
|
||||||
|
"text": {
|
||||||
|
"size": 10
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Auto font size, value auto visible",
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterByValue",
|
||||||
|
"options": {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Bedroom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Cellar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match": "any",
|
||||||
|
"type": "include"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "barchart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"axisSoftMin": 0,
|
||||||
|
"fillOpacity": 80,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineWidth": 0
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 12,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 37
|
||||||
|
},
|
||||||
|
"id": 14,
|
||||||
|
"options": {
|
||||||
|
"barWidth": 1,
|
||||||
|
"groupWidth": 1,
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"orientation": "horizontal",
|
||||||
|
"showValue": "always",
|
||||||
|
"text": {
|
||||||
|
"size": 10
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "categorical_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Auto font size, value always visible",
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterByValue",
|
||||||
|
"options": {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Bedroom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"id": "equal",
|
||||||
|
"options": {
|
||||||
|
"value": "Cellar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldName": "location"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match": "any",
|
||||||
|
"type": "include"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "barchart"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "",
|
||||||
|
"schemaVersion": 30,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [
|
||||||
|
"gdev",
|
||||||
|
"panel-tests",
|
||||||
|
"barchart"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-5m",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "BarChart - value text sizing",
|
||||||
|
"uid": "WFlOM-jM1",
|
||||||
|
"version": 9
|
||||||
|
}
|
||||||
@@ -20,14 +20,14 @@ export interface DisplayValue extends FormattedValue {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Explicit control for text settings
|
* Explicit control for text settings
|
||||||
|
* @deprecated Use VizTextDisplayOptions from @grafana/ui instead
|
||||||
*/
|
*/
|
||||||
export interface TextDisplayOptions {
|
export type TextDisplayOptions = {
|
||||||
/* Explicit text size */
|
/* Explicit text size */
|
||||||
titleSize?: number;
|
titleSize?: number;
|
||||||
|
|
||||||
/* Explicit text size */
|
/* Explicit text size */
|
||||||
valueSize?: number;
|
valueSize?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These represents the display value with the longest title and text.
|
* These represents the display value with the longest title and text.
|
||||||
|
|||||||
@@ -15,13 +15,12 @@ import {
|
|||||||
ThresholdsConfig,
|
ThresholdsConfig,
|
||||||
validateFieldConfig,
|
validateFieldConfig,
|
||||||
FieldColorModeId,
|
FieldColorModeId,
|
||||||
TextDisplayOptions,
|
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
import { OptionsWithTextFormatting } from '../../options';
|
||||||
|
|
||||||
export interface SingleStatBaseOptions {
|
export interface SingleStatBaseOptions extends OptionsWithTextFormatting {
|
||||||
reduceOptions: ReduceDataOptions;
|
reduceOptions: ReduceDataOptions;
|
||||||
orientation: VizOrientation;
|
orientation: VizOrientation;
|
||||||
text?: TextDisplayOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionsToKeep = ['reduceOptions', 'orientation'];
|
const optionsToKeep = ['reduceOptions', 'orientation'];
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export * from './axis';
|
|||||||
export * from './hideSeries';
|
export * from './hideSeries';
|
||||||
export * from './legend';
|
export * from './legend';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
|
export * from './text';
|
||||||
export * from './stacking';
|
export * from './stacking';
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { OptionsWithTextFormatting } from '../models.gen';
|
||||||
|
import { PanelOptionsEditorBuilder } from '@grafana/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicit control for visualization text settings
|
||||||
|
* @public
|
||||||
|
**/
|
||||||
|
export interface VizTextDisplayOptions {
|
||||||
|
/* Explicit title text size */
|
||||||
|
titleSize?: number;
|
||||||
|
/* Explicit value text size */
|
||||||
|
valueSize?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds common text control options to a visualization options
|
||||||
|
* @param builder
|
||||||
|
* @param withTitle
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function addTextSizeOptions<T extends OptionsWithTextFormatting>(
|
||||||
|
builder: PanelOptionsEditorBuilder<T>,
|
||||||
|
withTitle = true
|
||||||
|
) {
|
||||||
|
if (withTitle) {
|
||||||
|
builder.addNumberInput({
|
||||||
|
path: 'text.titleSize',
|
||||||
|
category: ['Text size'],
|
||||||
|
name: 'Title',
|
||||||
|
settings: {
|
||||||
|
placeholder: 'Auto',
|
||||||
|
integer: false,
|
||||||
|
min: 1,
|
||||||
|
max: 200,
|
||||||
|
},
|
||||||
|
defaultValue: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addNumberInput({
|
||||||
|
path: 'text.valueSize',
|
||||||
|
category: ['Text size'],
|
||||||
|
name: 'Value',
|
||||||
|
settings: {
|
||||||
|
placeholder: 'Auto',
|
||||||
|
integer: false,
|
||||||
|
min: 1,
|
||||||
|
max: 200,
|
||||||
|
},
|
||||||
|
defaultValue: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,14 +1,25 @@
|
|||||||
// TODO: this should be generated with cue
|
// TODO: this should be generated with cue
|
||||||
|
|
||||||
import { VizLegendOptions, VizTooltipOptions } from '../components';
|
import { VizLegendOptions, VizTooltipOptions } from '../components';
|
||||||
|
import { VizTextDisplayOptions } from './builder/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface OptionsWithLegend {
|
export interface OptionsWithLegend {
|
||||||
legend: VizLegendOptions;
|
legend: VizLegendOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
export interface OptionsWithTooltip {
|
export interface OptionsWithTooltip {
|
||||||
tooltip: VizTooltipOptions;
|
tooltip: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface OptionsWithTextFormatting {
|
||||||
|
text?: VizTextDisplayOptions;
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ const (
|
|||||||
serverError500Query queryType = "server_error_500"
|
serverError500Query queryType = "server_error_500"
|
||||||
logsQuery queryType = "logs"
|
logsQuery queryType = "logs"
|
||||||
nodeGraphQuery queryType = "node_graph"
|
nodeGraphQuery queryType = "node_graph"
|
||||||
|
categoricalDataQuery queryType = "categorical_data"
|
||||||
)
|
)
|
||||||
|
|
||||||
type queryType string
|
type queryType string
|
||||||
@@ -188,6 +189,12 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
|
|||||||
Name: "Node Graph",
|
Name: "Node Graph",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
p.registerScenario(&Scenario{
|
||||||
|
ID: string(categoricalDataQuery),
|
||||||
|
Name: "Categorical Data",
|
||||||
|
handler: p.handleCategoricalDataScenario,
|
||||||
|
})
|
||||||
|
|
||||||
p.queryMux.HandleFunc("", p.handleFallbackScenario)
|
p.queryMux.HandleFunc("", p.handleFallbackScenario)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,6 +695,27 @@ func (p *testDataPlugin) handleLogsScenario(ctx context.Context, req *backend.Qu
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *testDataPlugin) handleCategoricalDataScenario(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||||
|
resp := backend.NewQueryDataResponse()
|
||||||
|
for _, q := range req.Queries {
|
||||||
|
frame := data.NewFrame(q.RefID,
|
||||||
|
data.NewField("location", nil, []string{}),
|
||||||
|
data.NewField("temperature", nil, []int64{}),
|
||||||
|
data.NewField("humidity", nil, []int64{}),
|
||||||
|
data.NewField("pressure", nil, []int64{}),
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := 0; i < len(houseLocations); i++ {
|
||||||
|
frame.AppendRow(houseLocations[i], rand.Int63n(40+40)-40, rand.Int63n(100), rand.Int63n(1020-900)+900)
|
||||||
|
}
|
||||||
|
respD := resp.Responses[q.RefID]
|
||||||
|
respD.Frames = append(respD.Frames, frame)
|
||||||
|
resp.Responses[q.RefID] = respD
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func randomWalk(query backend.DataQuery, model *simplejson.Json, index int) *data.Frame {
|
func randomWalk(query backend.DataQuery, model *simplejson.Json, index int) *data.Frame {
|
||||||
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
|
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
|
||||||
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
|
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
import { DataFrame, TimeRange } from '@grafana/data';
|
import { DataFrame, TimeRange } from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
GraphNG,
|
GraphNG,
|
||||||
@@ -19,7 +20,7 @@ export interface BarChartProps
|
|||||||
extends BarChartOptions,
|
extends BarChartOptions,
|
||||||
Omit<GraphNGProps, 'prepConfig' | 'propsToDiff' | 'renderLegend' | 'theme'> {}
|
Omit<GraphNGProps, 'prepConfig' | 'propsToDiff' | 'renderLegend' | 'theme'> {}
|
||||||
|
|
||||||
const propsToDiff: string[] = ['orientation', 'barWidth', 'groupWidth', 'showValue'];
|
const propsToDiff: string[] = ['orientation', 'barWidth', 'groupWidth', 'showValue', 'text'];
|
||||||
|
|
||||||
export const BarChart: React.FC<BarChartProps> = (props) => {
|
export const BarChart: React.FC<BarChartProps> = (props) => {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
@@ -34,7 +35,8 @@ export const BarChart: React.FC<BarChartProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const prepConfig = (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => {
|
const prepConfig = (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => {
|
||||||
const { timeZone, orientation, barWidth, showValue, groupWidth, stacking, legend, tooltip } = props;
|
const { timeZone, orientation, barWidth, showValue, groupWidth, stacking, legend, tooltip, text } = props;
|
||||||
|
|
||||||
return preparePlotConfigBuilder({
|
return preparePlotConfigBuilder({
|
||||||
frame: alignedFrame,
|
frame: alignedFrame,
|
||||||
getTimeRange,
|
getTimeRange,
|
||||||
@@ -48,12 +50,14 @@ export const BarChart: React.FC<BarChartProps> = (props) => {
|
|||||||
stacking,
|
stacking,
|
||||||
legend,
|
legend,
|
||||||
tooltip,
|
tooltip,
|
||||||
|
text,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GraphNG
|
<GraphNG
|
||||||
{...props}
|
// My heart is bleeding with the clone deep here, but nested options...
|
||||||
|
{...cloneDeep(props)}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
frames={props.frames}
|
frames={props.frames}
|
||||||
prepConfig={prepConfig}
|
prepConfig={prepConfig}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -102,7 +105,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -185,6 +187,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -220,7 +225,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -303,6 +307,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -338,7 +345,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -421,6 +427,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -456,7 +465,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -539,6 +547,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -574,7 +585,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -657,6 +667,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -692,7 +705,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -775,6 +787,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -810,7 +825,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
@@ -893,6 +907,9 @@ Object {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hooks": Object {
|
"hooks": Object {
|
||||||
|
"draw": Array [
|
||||||
|
[Function],
|
||||||
|
],
|
||||||
"drawClear": Array [
|
"drawClear": Array [
|
||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
@@ -928,7 +945,6 @@ Object {
|
|||||||
"paths": [Function],
|
"paths": [Function],
|
||||||
"points": Object {
|
"points": Object {
|
||||||
"fill": undefined,
|
"fill": undefined,
|
||||||
"show": [Function],
|
|
||||||
"size": undefined,
|
"size": undefined,
|
||||||
"stroke": undefined,
|
"stroke": undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,40 +1,22 @@
|
|||||||
import uPlot, { Axis, Series } from 'uplot';
|
import uPlot, { Axis, Series } from 'uplot';
|
||||||
import { Quadtree, Rect, pointWithin } from './quadtree';
|
import { pointWithin, Quadtree, Rect } from './quadtree';
|
||||||
import { distribute, SPACE_BETWEEN } from './distribute';
|
import { distribute, SPACE_BETWEEN } from './distribute';
|
||||||
import { TooltipInterpolator } from '@grafana/ui/src/components/uPlot/types';
|
import { TooltipInterpolator } from '@grafana/ui/src/components/uPlot/types';
|
||||||
import { ScaleDirection, ScaleOrientation } from '@grafana/ui/src/components/uPlot/config';
|
import { BarValueVisibility, ScaleDirection, ScaleOrientation } from '@grafana/ui/src/components/uPlot/config';
|
||||||
|
import { CartesianCoords2D, GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { calculateFontSize, measureText } from '@grafana/ui';
|
||||||
|
import { VizTextDisplayOptions } from '@grafana/ui/src/options/builder';
|
||||||
|
|
||||||
const groupDistr = SPACE_BETWEEN;
|
const groupDistr = SPACE_BETWEEN;
|
||||||
const barDistr = SPACE_BETWEEN;
|
const barDistr = SPACE_BETWEEN;
|
||||||
const font = Math.round(10 * devicePixelRatio) + 'px Arial';
|
|
||||||
|
|
||||||
type WalkTwoCb = null | ((idx: number, offPx: number, dimPx: number) => void);
|
// min.max font size for value label
|
||||||
|
const VALUE_MIN_FONT_SIZE = 8;
|
||||||
function walkTwo(
|
const VALUE_MAX_FONT_SIZE = 30;
|
||||||
groupWidth: number,
|
// % of width/height of the bar that value should fit in when measuring size
|
||||||
barWidth: number,
|
const BAR_FONT_SIZE_RATIO = 0.65;
|
||||||
yIdx: number,
|
// distance between label and a horizontal bar
|
||||||
xCount: number,
|
const HORIZONTAL_BAR_LABEL_OFFSET = 10;
|
||||||
yCount: number,
|
|
||||||
xDim: number,
|
|
||||||
xDraw?: WalkTwoCb,
|
|
||||||
yDraw?: WalkTwoCb
|
|
||||||
) {
|
|
||||||
distribute(xCount, groupWidth, groupDistr, null, (ix, offPct, dimPct) => {
|
|
||||||
let groupOffPx = xDim * offPct;
|
|
||||||
let groupWidPx = xDim * dimPct;
|
|
||||||
|
|
||||||
xDraw && xDraw(ix, groupOffPx, groupWidPx);
|
|
||||||
|
|
||||||
yDraw &&
|
|
||||||
distribute(yCount, barWidth, barDistr, yIdx, (iy, offPct, dimPct) => {
|
|
||||||
let barOffPx = groupWidPx * offPct;
|
|
||||||
let barWidPx = groupWidPx * dimPct;
|
|
||||||
|
|
||||||
yDraw(ix, groupOffPx + barOffPx, barWidPx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@@ -44,18 +26,33 @@ export interface BarsOptions {
|
|||||||
xDir: ScaleDirection;
|
xDir: ScaleDirection;
|
||||||
groupWidth: number;
|
groupWidth: number;
|
||||||
barWidth: number;
|
barWidth: number;
|
||||||
formatValue?: (seriesIdx: number, value: any) => string;
|
showValue: BarValueVisibility;
|
||||||
|
formatValue: (seriesIdx: number, value: any) => string;
|
||||||
|
text?: VizTextDisplayOptions;
|
||||||
onHover?: (seriesIdx: number, valueIdx: number) => void;
|
onHover?: (seriesIdx: number, valueIdx: number) => void;
|
||||||
onLeave?: (seriesIdx: number, valueIdx: number) => void;
|
onLeave?: (seriesIdx: number, valueIdx: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LabelDescriptor extends CartesianCoords2D {
|
||||||
|
formattedValue: string;
|
||||||
|
value: number;
|
||||||
|
textAlign: CanvasTextAlign;
|
||||||
|
textBaseline: CanvasTextBaseline;
|
||||||
|
fontSize: number;
|
||||||
|
barWidth: number;
|
||||||
|
barHeight: number;
|
||||||
|
textWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export function getConfig(opts: BarsOptions) {
|
export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||||
const { xOri: ori, xDir: dir, groupWidth, barWidth, formatValue } = opts;
|
const { xOri: ori, xDir: dir, groupWidth, barWidth, formatValue, showValue } = opts;
|
||||||
|
const hasAutoValueSize = !Boolean(opts.text?.valueSize);
|
||||||
|
|
||||||
let qt: Quadtree;
|
let qt: Quadtree;
|
||||||
|
let labelsSizing: Array<LabelDescriptor | null> = [];
|
||||||
|
|
||||||
const drawBars: Series.PathBuilder = (u, sidx) => {
|
const drawBars: Series.PathBuilder = (u, sidx) => {
|
||||||
return uPlot.orient(
|
return uPlot.orient(
|
||||||
@@ -73,30 +70,119 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
const _dir = dir * (ori === 0 ? 1 : -1);
|
const _dir = dir * (ori === 0 ? 1 : -1);
|
||||||
|
|
||||||
walkTwo(groupWidth, barWidth, sidx - 1, numGroups, barsPerGroup, xDim, null, (ix, x0, wid) => {
|
walkTwo(groupWidth, barWidth, sidx - 1, numGroups, barsPerGroup, xDim, null, (ix, x0, wid) => {
|
||||||
let lft = Math.round(xOff + (_dir === 1 ? x0 : xDim - x0 - wid));
|
let left = Math.round(xOff + (_dir === 1 ? x0 : xDim - x0 - wid));
|
||||||
let barWid = Math.round(wid);
|
let barWid = Math.round(wid);
|
||||||
|
const canvas = u.root.querySelector<HTMLDivElement>('.u-over');
|
||||||
|
const bbox = canvas?.getBoundingClientRect();
|
||||||
|
|
||||||
if (dataY[ix] != null) {
|
if (dataY[ix] != null) {
|
||||||
let yPos = valToPosY(dataY[ix]!, scaleY, yDim, yOff);
|
let yPos = valToPosY(dataY[ix]!, scaleY, yDim, yOff);
|
||||||
|
|
||||||
let btm = Math.round(Math.max(yPos, y0Pos));
|
let btm = Math.round(Math.max(yPos, y0Pos));
|
||||||
let top = Math.round(Math.min(yPos, y0Pos));
|
let top = Math.round(Math.min(yPos, y0Pos));
|
||||||
let barHgt = btm - top;
|
let barHgt = btm - top;
|
||||||
|
|
||||||
let strokeWidth = series.width || 0;
|
let strokeWidth = series.width || 0;
|
||||||
|
|
||||||
if (strokeWidth) {
|
if (strokeWidth) {
|
||||||
rect(stroke, lft + strokeWidth / 2, top + strokeWidth / 2, barWid - strokeWidth, barHgt - strokeWidth);
|
rect(stroke, left + strokeWidth / 2, top + strokeWidth / 2, barWid - strokeWidth, barHgt - strokeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
rect(fill, lft, top, barWid, barHgt);
|
rect(fill, left, top, barWid, barHgt);
|
||||||
|
|
||||||
let x = ori === 0 ? Math.round(lft - xOff) : Math.round(top - yOff);
|
let x = ori === ScaleOrientation.Horizontal ? Math.round(left - xOff) : Math.round(top - yOff);
|
||||||
let y = ori === 0 ? Math.round(top - yOff) : Math.round(lft - xOff);
|
let y = ori === ScaleOrientation.Horizontal ? Math.round(top - yOff) : Math.round(left - xOff);
|
||||||
let w = ori === 0 ? barWid : barHgt;
|
let width = ori === ScaleOrientation.Horizontal ? barWid : barHgt;
|
||||||
let h = ori === 0 ? barHgt : barWid;
|
let height = ori === ScaleOrientation.Horizontal ? barHgt : barWid;
|
||||||
|
|
||||||
qt.add({ x, y, w, h, sidx: sidx, didx: ix });
|
qt.add({ x, y, w: width, h: height, sidx: sidx, didx: ix });
|
||||||
|
|
||||||
|
// Collect labels sizes and placements
|
||||||
|
const value = formatValue(sidx, dataY[ix]);
|
||||||
|
let labelX = ori === ScaleOrientation.Horizontal ? Math.round(left) : Math.round(top);
|
||||||
|
let labelY = ori === ScaleOrientation.Horizontal ? Math.round(top) : Math.round(left);
|
||||||
|
|
||||||
|
let availableSpaceForText;
|
||||||
|
|
||||||
|
if (ori === ScaleOrientation.Horizontal) {
|
||||||
|
availableSpaceForText =
|
||||||
|
dataY[ix]! >= 0 ? y / devicePixelRatio : bbox!.height - (y + height) / devicePixelRatio;
|
||||||
|
} else {
|
||||||
|
availableSpaceForText =
|
||||||
|
dataY[ix]! >= 0 ? bbox!.width - (x + width) / devicePixelRatio : x / devicePixelRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snippet below is for debugging the available space for text. Leaving it for the future bugs...
|
||||||
|
*/
|
||||||
|
// u.ctx.beginPath();
|
||||||
|
// u.ctx.strokeStyle = '#0000ff';
|
||||||
|
|
||||||
|
// if (dataY[ix]! >= 0) {
|
||||||
|
// if (ori === ScaleOrientation.Horizontal) {
|
||||||
|
// u.ctx.moveTo(left, top - availableSpaceForText * devicePixelRatio);
|
||||||
|
// u.ctx.lineTo(left + width, top - availableSpaceForText * devicePixelRatio);
|
||||||
|
// u.ctx.lineTo(left + width, top);
|
||||||
|
// u.ctx.lineTo(left, top);
|
||||||
|
// } else {
|
||||||
|
// u.ctx.moveTo(top + width, left);
|
||||||
|
// u.ctx.lineTo(top + width + availableSpaceForText * devicePixelRatio, left);
|
||||||
|
// u.ctx.lineTo(top + width + availableSpaceForText * devicePixelRatio, left + height);
|
||||||
|
// u.ctx.lineTo(top + width, left + height);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (ori === ScaleOrientation.Horizontal) {
|
||||||
|
// u.ctx.moveTo(left, top + height + availableSpaceForText * devicePixelRatio);
|
||||||
|
// u.ctx.lineTo(left + width, top + height + availableSpaceForText * devicePixelRatio);
|
||||||
|
// u.ctx.lineTo(left + width, top + height);
|
||||||
|
// u.ctx.lineTo(left, top + height);
|
||||||
|
// } else {
|
||||||
|
// u.ctx.moveTo(top, left);
|
||||||
|
// u.ctx.lineTo(top - availableSpaceForText * devicePixelRatio, left);
|
||||||
|
// u.ctx.lineTo(top - availableSpaceForText * devicePixelRatio, left + height);
|
||||||
|
// u.ctx.lineTo(top, left + height);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// u.ctx.closePath();
|
||||||
|
// u.ctx.stroke();
|
||||||
|
|
||||||
|
let fontSize = opts.text?.valueSize ?? VALUE_MIN_FONT_SIZE;
|
||||||
|
|
||||||
|
if (hasAutoValueSize) {
|
||||||
|
const size =
|
||||||
|
ori === ScaleOrientation.Horizontal
|
||||||
|
? calculateFontSize(
|
||||||
|
value,
|
||||||
|
(width / devicePixelRatio) * BAR_FONT_SIZE_RATIO,
|
||||||
|
availableSpaceForText * BAR_FONT_SIZE_RATIO,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
: calculateFontSize(
|
||||||
|
value,
|
||||||
|
availableSpaceForText,
|
||||||
|
(height * BAR_FONT_SIZE_RATIO) / devicePixelRatio,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
fontSize = size > VALUE_MAX_FONT_SIZE ? VALUE_MAX_FONT_SIZE : size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const textAlign = ori === ScaleOrientation.Horizontal ? 'center' : 'left';
|
||||||
|
const textBaseline = (ori === ScaleOrientation.Horizontal ? 'bottom' : 'alphabetic') as CanvasTextBaseline;
|
||||||
|
const textMeasurement = measureText(value, fontSize * devicePixelRatio);
|
||||||
|
let labelPosition: CartesianCoords2D = { x: labelX, y: labelY };
|
||||||
|
|
||||||
|
// Collect labels szes
|
||||||
|
labelsSizing.push({
|
||||||
|
formattedValue: value,
|
||||||
|
value: dataY[ix]!,
|
||||||
|
textAlign,
|
||||||
|
textBaseline,
|
||||||
|
fontSize: Math.floor(fontSize),
|
||||||
|
barWidth: width,
|
||||||
|
barHeight: height,
|
||||||
|
textWidth: textMeasurement.width,
|
||||||
|
...labelPosition,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
labelsSizing.push(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,44 +194,74 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawPoints: Series.Points.Show =
|
// uPlot hook to draw the labels on the bar chart
|
||||||
formatValue == null
|
const draw = (u: uPlot) => {
|
||||||
? false
|
let minFontSize = labelsSizing.reduce((min, s) => (s && s.fontSize < min ? s.fontSize : min), Infinity);
|
||||||
: (u, sidx) => {
|
|
||||||
u.ctx.font = font;
|
|
||||||
u.ctx.fillStyle = 'white';
|
|
||||||
|
|
||||||
uPlot.orient(
|
if (minFontSize === Infinity) {
|
||||||
u,
|
return;
|
||||||
sidx,
|
}
|
||||||
(series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
|
|
||||||
let numGroups = dataX.length;
|
|
||||||
let barsPerGroup = u.series.length - 1;
|
|
||||||
|
|
||||||
const _dir = dir * (ori === 0 ? 1 : -1);
|
for (let i = 0; i < labelsSizing.length; i++) {
|
||||||
|
const label = labelsSizing[i];
|
||||||
|
let x = 0,
|
||||||
|
y = 0;
|
||||||
|
if (label === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
walkTwo(groupWidth, barWidth, sidx - 1, numGroups, barsPerGroup, xDim, null, (ix, x0, wid) => {
|
const fontSize = hasAutoValueSize ? minFontSize : label.fontSize;
|
||||||
let lft = Math.round(xOff + (_dir === 1 ? x0 : xDim - x0 - wid));
|
|
||||||
let barWid = Math.round(wid);
|
|
||||||
|
|
||||||
// prettier-ignore
|
if (showValue === BarValueVisibility.Never) {
|
||||||
if (dataY[ix] != null) {
|
return;
|
||||||
let yPos = valToPosY(dataY[ix]!, scaleY, yDim, yOff);
|
}
|
||||||
|
|
||||||
let x = ori === 0 ? Math.round(lft + barWid / 2) : Math.round(yPos);
|
if (showValue !== BarValueVisibility.Always) {
|
||||||
let y = ori === 0 ? Math.round(yPos) : Math.round(lft + barWid / 2);
|
if (
|
||||||
|
hasAutoValueSize &&
|
||||||
|
((ori === ScaleOrientation.Horizontal && label.textWidth > label.barWidth) ||
|
||||||
|
minFontSize < VALUE_MIN_FONT_SIZE)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u.ctx.textAlign = ori === 0 ? 'center' : dataY[ix]! >= 0 ? 'left' : 'right';
|
// Calculate final labels positions according to unified text size
|
||||||
u.ctx.textBaseline = ori === 1 ? 'middle' : dataY[ix]! >= 0 ? 'bottom' : 'top';
|
const textMeasurement = measureText(label.formattedValue, fontSize * devicePixelRatio);
|
||||||
|
const actualLineHeight = textMeasurement.fontBoundingBoxAscent + textMeasurement.fontBoundingBoxDescent;
|
||||||
|
|
||||||
u.ctx.fillText(formatValue(sidx, dataY[ix]), x, y);
|
if (ori === ScaleOrientation.Horizontal) {
|
||||||
}
|
x = label.x + label.barWidth / 2;
|
||||||
});
|
y = label.y + (label.value >= 0 ? 0 : label.barHeight + actualLineHeight);
|
||||||
}
|
} else {
|
||||||
);
|
x =
|
||||||
|
label.x +
|
||||||
|
(label.value >= 0
|
||||||
|
? label.barWidth + HORIZONTAL_BAR_LABEL_OFFSET
|
||||||
|
: -textMeasurement.width - HORIZONTAL_BAR_LABEL_OFFSET);
|
||||||
|
y =
|
||||||
|
label.y +
|
||||||
|
(label.barHeight + textMeasurement.actualBoundingBoxAscent + textMeasurement.actualBoundingBoxDescent) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
};
|
* Snippet below is for debugging the available space for text. Leaving it for the future bugs...
|
||||||
|
*/
|
||||||
|
// u.ctx.beginPath();
|
||||||
|
// u.ctx.fillStyle = '#0000ff';
|
||||||
|
// u.ctx.arc(label.x, label.y, 10, 0, Math.PI * 2, true);
|
||||||
|
// u.ctx.closePath();
|
||||||
|
// u.ctx.fill();
|
||||||
|
|
||||||
|
u.ctx.fillStyle = theme.colors.text.primary;
|
||||||
|
u.ctx.font = `${fontSize * devicePixelRatio}px ${theme.typography.fontFamily}`;
|
||||||
|
u.ctx.textAlign = label.textAlign;
|
||||||
|
u.ctx.textBaseline = label.textBaseline;
|
||||||
|
u.ctx.fillText(label.formattedValue, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const xSplits: Axis.Splits = (u: uPlot) => {
|
const xSplits: Axis.Splits = (u: uPlot) => {
|
||||||
const dim = ori === 0 ? u.bbox.width : u.bbox.height;
|
const dim = ori === 0 ? u.bbox.width : u.bbox.height;
|
||||||
@@ -153,8 +269,8 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
|
|
||||||
let splits: number[] = [];
|
let splits: number[] = [];
|
||||||
|
|
||||||
distribute(u.data[0].length, groupWidth, groupDistr, null, (di, lftPct, widPct) => {
|
distribute(u.data[0].length, groupWidth, groupDistr, null, (di, leftPct, widPct) => {
|
||||||
let groupLftPx = (dim * lftPct) / devicePixelRatio;
|
let groupLftPx = (dim * leftPct) / devicePixelRatio;
|
||||||
let groupWidPx = (dim * widPct) / devicePixelRatio;
|
let groupWidPx = (dim * widPct) / devicePixelRatio;
|
||||||
|
|
||||||
let groupCenterPx = groupLftPx + groupWidPx / 2;
|
let groupCenterPx = groupLftPx + groupWidPx / 2;
|
||||||
@@ -185,6 +301,8 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
|
|
||||||
qt.clear();
|
qt.clear();
|
||||||
|
|
||||||
|
labelsSizing = [];
|
||||||
|
|
||||||
// clear the path cache to force drawBars() to rebuild new quadtree
|
// clear the path cache to force drawBars() to rebuild new quadtree
|
||||||
u.series.forEach((s) => {
|
u.series.forEach((s) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -241,7 +359,7 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
|
|
||||||
// pathbuilders
|
// pathbuilders
|
||||||
drawBars,
|
drawBars,
|
||||||
drawPoints,
|
draw,
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
init,
|
init,
|
||||||
@@ -249,3 +367,31 @@ export function getConfig(opts: BarsOptions) {
|
|||||||
interpolateBarChartTooltip,
|
interpolateBarChartTooltip,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WalkTwoCb = null | ((idx: number, offPx: number, dimPx: number) => void);
|
||||||
|
|
||||||
|
function walkTwo(
|
||||||
|
groupWidth: number,
|
||||||
|
barWidth: number,
|
||||||
|
yIdx: number,
|
||||||
|
xCount: number,
|
||||||
|
yCount: number,
|
||||||
|
xDim: number,
|
||||||
|
xDraw?: WalkTwoCb,
|
||||||
|
yDraw?: WalkTwoCb
|
||||||
|
) {
|
||||||
|
distribute(xCount, groupWidth, groupDistr, null, (ix, offPct, dimPct) => {
|
||||||
|
let groupOffPx = xDim * offPct;
|
||||||
|
let groupWidPx = xDim * dimPct;
|
||||||
|
|
||||||
|
xDraw && xDraw(ix, groupOffPx, groupWidPx);
|
||||||
|
|
||||||
|
yDraw &&
|
||||||
|
distribute(yCount, barWidth, barDistr, yIdx, (iy, offPct, dimPct) => {
|
||||||
|
let barOffPx = groupWidPx * offPct;
|
||||||
|
let barWidPx = groupWidPx * dimPct;
|
||||||
|
|
||||||
|
yDraw(ix, groupOffPx + barOffPx, barWidPx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export const plugin = new PanelPlugin<BarChartOptions, BarChartFieldConfig>(BarC
|
|||||||
|
|
||||||
commonOptionsBuilder.addTooltipOptions(builder);
|
commonOptionsBuilder.addTooltipOptions(builder);
|
||||||
commonOptionsBuilder.addLegendOptions(builder);
|
commonOptionsBuilder.addLegendOptions(builder);
|
||||||
|
commonOptionsBuilder.addTextSizeOptions(builder, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
function countNumberFields(data?: DataFrame[]): number {
|
function countNumberFields(data?: DataFrame[]): number {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
GraphGradientMode,
|
GraphGradientMode,
|
||||||
HideableFieldConfig,
|
HideableFieldConfig,
|
||||||
OptionsWithLegend,
|
OptionsWithLegend,
|
||||||
|
OptionsWithTextFormatting,
|
||||||
OptionsWithTooltip,
|
OptionsWithTooltip,
|
||||||
StackingMode,
|
StackingMode,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
@@ -12,7 +13,7 @@ import {
|
|||||||
/**
|
/**
|
||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
export interface BarChartOptions extends OptionsWithLegend, OptionsWithTooltip {
|
export interface BarChartOptions extends OptionsWithLegend, OptionsWithTooltip, OptionsWithTextFormatting {
|
||||||
orientation: VizOrientation;
|
orientation: VizOrientation;
|
||||||
stacking: StackingMode;
|
stacking: StackingMode;
|
||||||
showValue: BarValueVisibility;
|
showValue: BarValueVisibility;
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ describe('BarChart utils', () => {
|
|||||||
tooltip: {
|
tooltip: {
|
||||||
mode: TooltipDisplayMode.None,
|
mode: TooltipDisplayMode.None,
|
||||||
},
|
},
|
||||||
|
text: {
|
||||||
|
valueSize: 10,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it.each([VizOrientation.Auto, VizOrientation.Horizontal, VizOrientation.Vertical])('orientation', (v) => {
|
it.each([VizOrientation.Auto, VizOrientation.Horizontal, VizOrientation.Vertical])('orientation', (v) => {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { BarChartFieldConfig, BarChartOptions, defaultBarChartFieldConfig } from
|
|||||||
import { BarsOptions, getConfig } from './bars';
|
import { BarsOptions, getConfig } from './bars';
|
||||||
import {
|
import {
|
||||||
AxisPlacement,
|
AxisPlacement,
|
||||||
BarValueVisibility,
|
|
||||||
FIXED_UNIT,
|
FIXED_UNIT,
|
||||||
ScaleDirection,
|
ScaleDirection,
|
||||||
ScaleDistribution,
|
ScaleDistribution,
|
||||||
@@ -47,6 +46,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
|||||||
showValue,
|
showValue,
|
||||||
groupWidth,
|
groupWidth,
|
||||||
barWidth,
|
barWidth,
|
||||||
|
text,
|
||||||
}) => {
|
}) => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
const defaultValueFormatter = (seriesIdx: number, value: any) =>
|
const defaultValueFormatter = (seriesIdx: number, value: any) =>
|
||||||
@@ -55,7 +55,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
|||||||
// bar orientation -> x scale orientation & direction
|
// bar orientation -> x scale orientation & direction
|
||||||
const vizOrientation = getBarCharScaleOrientation(orientation);
|
const vizOrientation = getBarCharScaleOrientation(orientation);
|
||||||
|
|
||||||
const formatValue = showValue !== BarValueVisibility.Never ? defaultValueFormatter : undefined;
|
const formatValue = defaultValueFormatter;
|
||||||
|
|
||||||
// Use bar width when only one field
|
// Use bar width when only one field
|
||||||
if (frame.fields.length === 2) {
|
if (frame.fields.length === 2) {
|
||||||
@@ -69,12 +69,16 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
|||||||
groupWidth,
|
groupWidth,
|
||||||
barWidth,
|
barWidth,
|
||||||
formatValue,
|
formatValue,
|
||||||
|
text,
|
||||||
|
showValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = getConfig(opts);
|
const config = getConfig(opts, theme);
|
||||||
|
|
||||||
builder.addHook('init', config.init);
|
builder.addHook('init', config.init);
|
||||||
builder.addHook('drawClear', config.drawClear);
|
builder.addHook('drawClear', config.drawClear);
|
||||||
|
builder.addHook('draw', config.draw);
|
||||||
|
|
||||||
builder.setTooltipInterpolator(config.interpolateBarChartTooltip);
|
builder.setTooltipInterpolator(config.interpolateBarChartTooltip);
|
||||||
|
|
||||||
builder.addScale({
|
builder.addScale({
|
||||||
@@ -117,12 +121,10 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
|||||||
pxAlign: false,
|
pxAlign: false,
|
||||||
lineWidth: customConfig.lineWidth,
|
lineWidth: customConfig.lineWidth,
|
||||||
lineColor: seriesColor,
|
lineColor: seriesColor,
|
||||||
//lineStyle: customConfig.lineStyle,
|
|
||||||
fillOpacity: customConfig.fillOpacity,
|
fillOpacity: customConfig.fillOpacity,
|
||||||
theme,
|
theme,
|
||||||
colorMode,
|
colorMode,
|
||||||
pathBuilder: config.drawBars,
|
pathBuilder: config.drawBars,
|
||||||
pointsBuilder: config.drawPoints,
|
|
||||||
show: !customConfig.hideFrom?.viz,
|
show: !customConfig.hideFrom?.viz,
|
||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: field.config.thresholds,
|
thresholds: field.config.thresholds,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { sharedSingleStatPanelChangedHandler } from '@grafana/ui';
|
import { commonOptionsBuilder, sharedSingleStatPanelChangedHandler } from '@grafana/ui';
|
||||||
import { PanelPlugin } from '@grafana/data';
|
import { PanelPlugin } from '@grafana/data';
|
||||||
import { BarGaugePanel } from './BarGaugePanel';
|
import { BarGaugePanel } from './BarGaugePanel';
|
||||||
import { BarGaugeOptions, displayModes } from './types';
|
import { BarGaugeOptions, displayModes } from './types';
|
||||||
import { addOrientationOption, addStandardDataReduceOptions, addTextSizeOptions } from '../stat/types';
|
import { addOrientationOption, addStandardDataReduceOptions } from '../stat/types';
|
||||||
import { barGaugePanelMigrationHandler } from './BarGaugeMigrations';
|
import { barGaugePanelMigrationHandler } from './BarGaugeMigrations';
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
|
export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
|
||||||
@@ -10,7 +10,7 @@ export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
|
|||||||
.setPanelOptions((builder) => {
|
.setPanelOptions((builder) => {
|
||||||
addStandardDataReduceOptions(builder);
|
addStandardDataReduceOptions(builder);
|
||||||
addOrientationOption(builder);
|
addOrientationOption(builder);
|
||||||
addTextSizeOptions(builder);
|
commonOptionsBuilder.addTextSizeOptions(builder);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.addRadio({
|
.addRadio({
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { PanelPlugin } from '@grafana/data';
|
import { PanelPlugin } from '@grafana/data';
|
||||||
import { GaugePanel } from './GaugePanel';
|
import { GaugePanel } from './GaugePanel';
|
||||||
import { GaugeOptions } from './types';
|
import { GaugeOptions } from './types';
|
||||||
import { addStandardDataReduceOptions, addTextSizeOptions } from '../stat/types';
|
import { addStandardDataReduceOptions } from '../stat/types';
|
||||||
import { gaugePanelMigrationHandler, gaugePanelChangedHandler } from './GaugeMigrations';
|
import { gaugePanelMigrationHandler, gaugePanelChangedHandler } from './GaugeMigrations';
|
||||||
|
import { commonOptionsBuilder } from '@grafana/ui';
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
|
export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
|
||||||
.useFieldConfig()
|
.useFieldConfig()
|
||||||
@@ -23,7 +24,7 @@ export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
|
|||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
addTextSizeOptions(builder);
|
commonOptionsBuilder.addTextSizeOptions(builder);
|
||||||
})
|
})
|
||||||
.setPanelChangeHandler(gaugePanelChangedHandler)
|
.setPanelChangeHandler(gaugePanelChangedHandler)
|
||||||
.setMigrationHandler(gaugePanelMigrationHandler);
|
.setMigrationHandler(gaugePanelMigrationHandler);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { BigValueTextMode, sharedSingleStatMigrationHandler } from '@grafana/ui';
|
import { BigValueTextMode, commonOptionsBuilder, sharedSingleStatMigrationHandler } from '@grafana/ui';
|
||||||
import { PanelPlugin } from '@grafana/data';
|
import { PanelPlugin } from '@grafana/data';
|
||||||
import { addOrientationOption, addStandardDataReduceOptions, addTextSizeOptions, StatPanelOptions } from './types';
|
import { addOrientationOption, addStandardDataReduceOptions, StatPanelOptions } from './types';
|
||||||
import { StatPanel } from './StatPanel';
|
import { StatPanel } from './StatPanel';
|
||||||
import { statPanelChangedHandler } from './StatMigrations';
|
import { statPanelChangedHandler } from './StatMigrations';
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ export const plugin = new PanelPlugin<StatPanelOptions>(StatPanel)
|
|||||||
|
|
||||||
addStandardDataReduceOptions(builder);
|
addStandardDataReduceOptions(builder);
|
||||||
addOrientationOption(builder, mainCategory);
|
addOrientationOption(builder, mainCategory);
|
||||||
addTextSizeOptions(builder);
|
commonOptionsBuilder.addTextSizeOptions(builder);
|
||||||
|
|
||||||
builder.addSelect({
|
builder.addSelect({
|
||||||
path: 'textMode',
|
path: 'textMode',
|
||||||
|
|||||||
@@ -119,31 +119,3 @@ export function addOrientationOption<T extends SingleStatBaseOptions>(
|
|||||||
defaultValue: VizOrientation.Auto,
|
defaultValue: VizOrientation.Auto,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addTextSizeOptions<T extends SingleStatBaseOptions>(builder: PanelOptionsEditorBuilder<T>) {
|
|
||||||
builder.addNumberInput({
|
|
||||||
path: 'text.titleSize',
|
|
||||||
category: ['Text size'],
|
|
||||||
name: 'Title',
|
|
||||||
settings: {
|
|
||||||
placeholder: 'Auto',
|
|
||||||
integer: false,
|
|
||||||
min: 1,
|
|
||||||
max: 200,
|
|
||||||
},
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.addNumberInput({
|
|
||||||
path: 'text.valueSize',
|
|
||||||
category: ['Text size'],
|
|
||||||
name: 'Value',
|
|
||||||
settings: {
|
|
||||||
placeholder: 'Auto',
|
|
||||||
integer: false,
|
|
||||||
min: 1,
|
|
||||||
max: 200,
|
|
||||||
},
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user