mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
BarChart: when horiz, allow rotation and skipping of y tick labels (#59354)
This commit is contained in:
parent
ce0bdb2cd9
commit
122f0d947e
@ -6929,11 +6929,12 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/panel/barchart/bars.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"]
|
||||
],
|
||||
"public/app/plugins/panel/barchart/module.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
@ -6944,7 +6945,8 @@ exports[`better eslint`] = {
|
||||
],
|
||||
"public/app/plugins/panel/barchart/utils.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
||||
],
|
||||
"public/app/plugins/panel/candlestick/CandlestickPanel.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
|
@ -0,0 +1,320 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 530,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "decmbytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 14,
|
||||
"w": 11,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"maxDataPoints": 30,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"orientation": "vertical",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelMaxLength": 6,
|
||||
"xTickLabelRotation": 45,
|
||||
"xTickLabelSpacing": 100
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"fields\": [\n {\n \"name\": \"label\",\n \"type\": \"string\",\n \"typeInfo\": {\n \"frame\": \"string\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 600000\n }\n },\n {\n \"name\": \"A-series\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {},\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n \"acquisition\",\n \"extension\",\n \"conductor\",\n \"authorise\",\n \"architect\",\n \"illusion\",\n \"congress\",\n \"highlight\",\n \"partnership\",\n \"understanding\",\n \"disagreement\",\n \"personality\",\n \"commerce\",\n \"systematic\",\n \"hesitate\",\n \"business\",\n \"manufacture\",\n \"incredible\",\n \"constitutional\",\n \"prevalence\",\n \"professor\",\n \"entitlement\",\n \"cooperation\",\n \"sickness\",\n \"contrast\",\n \"reference\",\n \"audience\",\n \"discount\",\n \"apparatus\",\n \"disturbance\",\n \"automatic\",\n \"refrigerator\",\n \"elaborate\",\n \"sympathetic\",\n \"integration\",\n \"president\"\n ],\n [\n 306.78931659492116,\n 200.00696051101917,\n 164.90889283973593,\n 518.9385023737021,\n 999.9040675564702,\n 613.9689830172349,\n 773.2337077340269,\n 317.47395634701644,\n 748.3318338316539,\n 606.8039493787173,\n 426.27771317792866,\n 376.47735643253924,\n 66.30635081800493,\n 401.70654338415505,\n 108.86259550477234,\n 182.40284186231278,\n 867.7047958572101,\n 959.3957783599242,\n 396.7606089549935,\n 455.9625595614323,\n 685.4792456298062,\n 368.6567303946707,\n 157.06596562976327,\n 59.54120602048763,\n 406.72723615743973,\n 440.18247585615575,\n 516.0267558264891,\n 258.76006051667315,\n 952.966531725171,\n 554.8746357628739,\n 86.7279280805682,\n 781.2422516386563,\n 754.2723802427706,\n 435.0305712850233,\n 384.43181614983,\n 459.04164596738127\n ]\n ]\n }\n }\n]",
|
||||
"refId": "A",
|
||||
"scenarioId": "raw_frame"
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"axisSoftMin": 0,
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 0,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"decimals": 7,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 14,
|
||||
"w": 13,
|
||||
"x": 11,
|
||||
"y": 0
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 1,
|
||||
"groupWidth": 0.82,
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"max"
|
||||
],
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"showLegend": true
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"text": {},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelRotation": 45,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, -5\nLondon, 10, 1\nLong value, 15,10",
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_content"
|
||||
}
|
||||
],
|
||||
"title": "Auto sizing & auto show values",
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "decmbytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 18,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 14
|
||||
},
|
||||
"id": 3,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelMaxLength": 5,
|
||||
"xTickLabelRotation": 45,
|
||||
"xTickLabelSpacing": 100
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
"type": "barchart"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"gdev",
|
||||
"panel-tests",
|
||||
"barchart",
|
||||
"graph-ng"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "BarChart - Label Rotation & Skipping",
|
||||
"uid": "xCmMwXdVz",
|
||||
"version": 20,
|
||||
"weekStart": ""
|
||||
}
|
@ -107,6 +107,13 @@ local dashboard = grafana.dashboard;
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('barchart-label-rotation-skipping', import '../dev-dashboards/panel-barchart/barchart-label-rotation-skipping.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
spec+: {
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('barchart-thresholds-mappings', import '../dev-dashboards/panel-barchart/barchart-thresholds-mappings.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ exports[`BarChart utils preparePlotConfigBuilder orientation 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -40,7 +40,7 @@ exports[`BarChart utils preparePlotConfigBuilder orientation 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -167,7 +167,7 @@ exports[`BarChart utils preparePlotConfigBuilder orientation 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -194,7 +194,7 @@ exports[`BarChart utils preparePlotConfigBuilder orientation 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -348,7 +348,7 @@ exports[`BarChart utils preparePlotConfigBuilder orientation 3`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": 0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -475,7 +475,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -502,7 +502,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -629,7 +629,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -656,7 +656,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -783,7 +783,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 3`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -810,7 +810,7 @@ exports[`BarChart utils preparePlotConfigBuilder stacking 3`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -937,7 +937,7 @@ exports[`BarChart utils preparePlotConfigBuilder value visibility 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -964,7 +964,7 @@ exports[`BarChart utils preparePlotConfigBuilder value visibility 1`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
@ -1091,7 +1091,7 @@ exports[`BarChart utils preparePlotConfigBuilder value visibility 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": -0,
|
||||
"rotate": 0,
|
||||
"scale": "x",
|
||||
"show": true,
|
||||
"side": 3,
|
||||
@ -1118,7 +1118,7 @@ exports[`BarChart utils preparePlotConfigBuilder value visibility 2`] = `
|
||||
"width": 1,
|
||||
},
|
||||
"labelGap": 0,
|
||||
"rotate": undefined,
|
||||
"rotate": -0,
|
||||
"scale": "m/s",
|
||||
"show": true,
|
||||
"side": 2,
|
||||
|
@ -51,6 +51,7 @@ export interface BarsOptions {
|
||||
getColor?: (seriesIdx: number, valueIdx: number, value: any) => string | null;
|
||||
fillOpacity?: number;
|
||||
formatValue: (seriesIdx: number, value: any) => string;
|
||||
formatShortValue: (seriesIdx: number, value: any) => string;
|
||||
timeZone?: TimeZone;
|
||||
text?: VizTextDisplayOptions;
|
||||
onHover?: (seriesIdx: number, valueIdx: number) => void;
|
||||
@ -116,7 +117,17 @@ function calculateFontSizeWithMetrics(
|
||||
* @internal
|
||||
*/
|
||||
export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
const { xOri, xDir: dir, rawValue, getColor, formatValue, fillOpacity = 1, showValue, xSpacing = 0 } = opts;
|
||||
const {
|
||||
xOri,
|
||||
xDir: dir,
|
||||
rawValue,
|
||||
getColor,
|
||||
formatValue,
|
||||
formatShortValue,
|
||||
fillOpacity = 1,
|
||||
showValue,
|
||||
xSpacing = 0,
|
||||
} = opts;
|
||||
const isXHorizontal = xOri === ScaleOrientation.Horizontal;
|
||||
const hasAutoValueSize = !Boolean(opts.text?.valueSize);
|
||||
const isStacked = opts.stacking !== StackingMode.None;
|
||||
@ -131,35 +142,34 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
let qt: Quadtree;
|
||||
let hRect: Rect | null;
|
||||
|
||||
const xSplits: Axis.Splits = (u: uPlot) => {
|
||||
const dim = isXHorizontal ? u.bbox.width : u.bbox.height;
|
||||
const _dir = dir * (isXHorizontal ? 1 : -1);
|
||||
// for distr: 2 scales, the splits array should contain indices into data[0] rather than values
|
||||
const xSplits: Axis.Splits | undefined = (u) => Array.from(u.data[0].map((v, i) => i));
|
||||
|
||||
let dataLen = u.data[0].length;
|
||||
let lastIdx = dataLen - 1;
|
||||
const hFilter: Axis.Filter | undefined =
|
||||
xSpacing === 0
|
||||
? undefined
|
||||
: (u, splits) => {
|
||||
// hSpacing?
|
||||
const dim = u.bbox.width;
|
||||
const _dir = dir * (isXHorizontal ? 1 : -1);
|
||||
|
||||
let skipMod = 0;
|
||||
let dataLen = splits.length;
|
||||
let lastIdx = dataLen - 1;
|
||||
|
||||
if (xSpacing !== 0) {
|
||||
let cssDim = dim / devicePixelRatio;
|
||||
let maxTicks = Math.abs(Math.floor(cssDim / xSpacing));
|
||||
let skipMod = 0;
|
||||
|
||||
skipMod = dataLen < maxTicks ? 0 : Math.ceil(dataLen / maxTicks);
|
||||
}
|
||||
let cssDim = dim / uPlot.pxRatio;
|
||||
let maxTicks = Math.abs(Math.floor(cssDim / xSpacing));
|
||||
|
||||
let splits: number[] = [];
|
||||
skipMod = dataLen < maxTicks ? 0 : Math.ceil(dataLen / maxTicks);
|
||||
|
||||
// for distr: 2 scales, the splits array should contain indices into data[0] rather than values
|
||||
u.data[0].forEach((v, i) => {
|
||||
let shouldSkip = skipMod !== 0 && (xSpacing > 0 ? i : lastIdx - i) % skipMod > 0;
|
||||
let splits2 = splits.map((v, i) => {
|
||||
let shouldSkip = skipMod !== 0 && (xSpacing > 0 ? i : lastIdx - i) % skipMod > 0;
|
||||
return shouldSkip ? null : v;
|
||||
});
|
||||
|
||||
if (!shouldSkip) {
|
||||
splits.push(i);
|
||||
}
|
||||
});
|
||||
|
||||
return _dir === 1 ? splits : splits.reverse();
|
||||
};
|
||||
return _dir === 1 ? splits2 : splits2.reverse();
|
||||
};
|
||||
|
||||
// the splits passed into here are data[0] values looked up by the indices returned from splits()
|
||||
const xValues: Axis.Values = (u, splits, axisIdx, foundSpace, foundIncr) => {
|
||||
@ -182,7 +192,7 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
return vals;
|
||||
}
|
||||
|
||||
return splits.map((v) => formatValue(0, v));
|
||||
return splits.map((v) => (isXHorizontal ? formatShortValue(0, v) : formatValue(0, v)));
|
||||
};
|
||||
|
||||
// this expands the distr: 2 scale so that the indicies of each data[0] land at the proper justified positions
|
||||
@ -434,8 +444,8 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
if (seriesIdx === 1) {
|
||||
hRect = null;
|
||||
|
||||
let cx = u.cursor.left! * devicePixelRatio;
|
||||
let cy = u.cursor.top! * devicePixelRatio;
|
||||
let cx = u.cursor.left! * uPlot.pxRatio;
|
||||
let cy = u.cursor.top! * uPlot.pxRatio;
|
||||
|
||||
qt.get(cx, cy, 1, 1, (o) => {
|
||||
if (pointWithin(cx, cy, o.x, o.y, o.x + o.w, o.y + o.h)) {
|
||||
@ -471,10 +481,10 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
}
|
||||
|
||||
return {
|
||||
left: isHovered ? (hRect!.x + widthReduce) / devicePixelRatio : -10,
|
||||
top: isHovered ? hRect!.y / devicePixelRatio : -10,
|
||||
width: isHovered ? (hRect!.w - widthReduce) / devicePixelRatio : 0,
|
||||
height: isHovered ? (hRect!.h - heightReduce) / devicePixelRatio : 0,
|
||||
left: isHovered ? (hRect!.x + widthReduce) / uPlot.pxRatio : -10,
|
||||
top: isHovered ? hRect!.y / uPlot.pxRatio : -10,
|
||||
width: isHovered ? (hRect!.w - widthReduce) / uPlot.pxRatio : 0,
|
||||
height: isHovered ? (hRect!.h - heightReduce) / uPlot.pxRatio : 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
@ -634,6 +644,7 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
|
||||
xRange,
|
||||
xValues,
|
||||
xSplits,
|
||||
hFilter,
|
||||
|
||||
barsBuilder,
|
||||
|
||||
|
@ -138,7 +138,7 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(BarChartPa
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'xTickLabelRotation',
|
||||
name: 'Rotate bar labels',
|
||||
name: 'Rotate X tick labels',
|
||||
defaultValue: defaultPanelOptions.xTickLabelRotation,
|
||||
settings: {
|
||||
min: -90,
|
||||
@ -147,18 +147,16 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(BarChartPa
|
||||
marks: { '-90': '-90°', '-45': '-45°', 0: '0°', 45: '45°', 90: '90°' },
|
||||
included: false,
|
||||
},
|
||||
showIf: (opts) => {
|
||||
return opts.orientation === VizOrientation.Auto || opts.orientation === VizOrientation.Vertical;
|
||||
},
|
||||
})
|
||||
.addNumberInput({
|
||||
path: 'xTickLabelMaxLength',
|
||||
name: 'Bar label max length',
|
||||
description: 'Bar labels will be truncated to the length provided',
|
||||
name: 'X tick label max length',
|
||||
description: 'X labels will be truncated to the length provided',
|
||||
settings: {
|
||||
placeholder: 'None',
|
||||
min: 0,
|
||||
},
|
||||
showIf: (opts) => opts.xTickLabelRotation !== 0,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'xTickLabelSpacing',
|
||||
|
@ -81,15 +81,18 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
|
||||
timeZone,
|
||||
}) => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
const defaultValueFormatter = (seriesIdx: number, value: any) => {
|
||||
return shortenValue(formattedValueToString(frame.fields[seriesIdx].display!(value)), xTickLabelMaxLength);
|
||||
|
||||
const formatValue = (seriesIdx: number, value: any) => {
|
||||
return formattedValueToString(frame.fields[seriesIdx].display!(value));
|
||||
};
|
||||
|
||||
const formatShortValue = (seriesIdx: number, value: any) => {
|
||||
return shortenValue(formatValue(seriesIdx, value), xTickLabelMaxLength);
|
||||
};
|
||||
|
||||
// bar orientation -> x scale orientation & direction
|
||||
const vizOrientation = getBarCharScaleOrientation(orientation);
|
||||
|
||||
const formatValue = defaultValueFormatter;
|
||||
|
||||
// Use bar width when only one field
|
||||
if (frame.fields.length === 2) {
|
||||
groupWidth = barWidth;
|
||||
@ -107,6 +110,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
|
||||
getColor,
|
||||
fillOpacity,
|
||||
formatValue,
|
||||
formatShortValue,
|
||||
timeZone,
|
||||
text,
|
||||
showValue,
|
||||
@ -126,8 +130,13 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
|
||||
|
||||
builder.setTooltipInterpolator(config.interpolateTooltip);
|
||||
|
||||
if (vizOrientation.xOri === ScaleOrientation.Horizontal && xTickLabelRotation !== 0) {
|
||||
builder.setPadding(getRotationPadding(frame, xTickLabelRotation, xTickLabelMaxLength));
|
||||
if (xTickLabelRotation !== 0) {
|
||||
// these are the amount of space we already have available between plot edge and first label
|
||||
// TODO: removing these hardcoded value requires reading back uplot instance props
|
||||
let lftSpace = 50;
|
||||
let btmSpace = vizOrientation.xOri === ScaleOrientation.Horizontal ? 14 : 5;
|
||||
|
||||
builder.setPadding(getRotationPadding(frame, xTickLabelRotation, xTickLabelMaxLength, lftSpace, btmSpace));
|
||||
}
|
||||
|
||||
builder.setPrepData(config.prepData);
|
||||
@ -155,12 +164,13 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
|
||||
placement: xFieldAxisPlacement,
|
||||
label: frame.fields[0].config.custom?.axisLabel,
|
||||
splits: config.xSplits,
|
||||
filter: vizOrientation.xOri === 0 ? config.hFilter : undefined,
|
||||
values: config.xValues,
|
||||
timeZone,
|
||||
grid: { show: false },
|
||||
ticks: { show: false },
|
||||
gap: 15,
|
||||
tickLabelRotation: xTickLabelRotation * -1,
|
||||
tickLabelRotation: vizOrientation.xOri === 0 ? xTickLabelRotation * -1 : 0,
|
||||
theme,
|
||||
show: xFieldAxisShow,
|
||||
});
|
||||
@ -272,6 +282,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
|
||||
size: customConfig.axisWidth,
|
||||
placement,
|
||||
formatValue: (v, decimals) => formattedValueToString(field.display!(v, decimals)),
|
||||
filter: vizOrientation.yOri === 0 ? config.hFilter : undefined,
|
||||
tickLabelRotation: vizOrientation.xOri === 1 ? xTickLabelRotation * -1 : 0,
|
||||
theme,
|
||||
grid: { show: customConfig.axisGridShow },
|
||||
});
|
||||
@ -293,7 +305,13 @@ function shortenValue(value: string, length: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function getRotationPadding(frame: DataFrame, rotateLabel: number, valueMaxLength: number): Padding {
|
||||
function getRotationPadding(
|
||||
frame: DataFrame,
|
||||
rotateLabel: number,
|
||||
valueMaxLength: number,
|
||||
lftSpace = 0,
|
||||
btmSpace = 0
|
||||
): Padding {
|
||||
const values = frame.fields[0].values;
|
||||
const fontSize = UPLOT_AXIS_FONT_SIZE;
|
||||
const displayProcessor = frame.fields[0].display ?? ((v) => v);
|
||||
@ -325,9 +343,15 @@ function getRotationPadding(frame: DataFrame, rotateLabel: number, valueMaxLengt
|
||||
: 0;
|
||||
|
||||
// Add padding to the bottom to avoid clipping the rotated labels.
|
||||
const paddingBottom = Math.sin(((rotateLabel >= 0 ? rotateLabel : rotateLabel * -1) * Math.PI) / 180) * maxLength;
|
||||
const paddingBottom =
|
||||
Math.sin(((rotateLabel >= 0 ? rotateLabel : rotateLabel * -1) * Math.PI) / 180) * maxLength - btmSpace;
|
||||
|
||||
return [Math.round(UPLOT_AXIS_FONT_SIZE * uPlot.pxRatio), paddingRight, paddingBottom, paddingLeft];
|
||||
return [
|
||||
Math.round(UPLOT_AXIS_FONT_SIZE * uPlot.pxRatio),
|
||||
paddingRight,
|
||||
paddingBottom,
|
||||
Math.max(0, paddingLeft - lftSpace),
|
||||
];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
Loading…
Reference in New Issue
Block a user