TimeSeriesPanel: Fixes overlapping time axis ticks (#31332)

* GraphNG: Fixes overlapping time axis ticks

* Review tweaks
This commit is contained in:
Torkel Ödegaard 2021-02-19 12:10:48 +01:00 committed by GitHub
parent aeb4bcb3ed
commit ce63df425d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 529 additions and 21 deletions

View File

@ -19,7 +19,9 @@
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards"
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [

View File

@ -16,7 +16,15 @@
"gnetId": null,
"graphTooltip": 0,
"id": 391,
"links": [],
"links": [
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [
{
"datasource": null,

View File

@ -19,7 +19,9 @@
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards"
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [

View File

@ -19,7 +19,9 @@
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards"
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [

View File

@ -0,0 +1,470 @@
{
"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,
"links": [
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 41,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 8,
"x": 0,
"y": 0
},
"id": 2,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "1s",
"timeShift": null,
"title": "Sub second range ",
"type": "timeseries"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 17,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 8,
"x": 8,
"y": 0
},
"id": 3,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "1m",
"timeShift": null,
"title": "Sub minute range",
"type": "timeseries"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 30,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 8,
"x": 16,
"y": 0
},
"id": 4,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "1h",
"timeShift": null,
"title": "Sub hour range",
"type": "timeseries"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 37,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 9
},
"id": 5,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "1d",
"timeShift": null,
"title": "Sub day range",
"type": "timeseries"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 37,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 9
},
"id": 6,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "2d",
"timeShift": null,
"title": "Last days (shows date)",
"type": "timeseries"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 37,
"gradientMode": "opacity",
"hideFrom": {
"graph": false,
"legend": false,
"tooltip": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 9
},
"id": 7,
"maxDataPoints": 50,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "hidden",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"timeFrom": "5y",
"timeShift": null,
"title": "Last 5 days (year only)",
"type": "timeseries"
}
],
"schemaVersion": 27,
"style": "dark",
"tags": ["gdev", "panel-tests", "graph-ng"],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Panel Tests - GraphNG - Time Axis",
"uid": "sd27_CPGz",
"version": 3
}

View File

@ -19,7 +19,9 @@
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards"
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [

View File

@ -19,7 +19,9 @@
{
"icon": "external link",
"tags": ["gdev", "graph-ng"],
"type": "dashboards"
"type": "dashboards",
"asDropdown": true,
"title": "Graph Tests"
}
],
"panels": [

View File

@ -99,13 +99,24 @@ export class UPlotAxisBuilder extends PlotConfigBuilder<AxisProps, Axis> {
/* Minimum grid & tick spacing in CSS pixels */
function calculateSpace(self: uPlot, axisIdx: number, scaleMin: number, scaleMax: number, plotDim: number): number {
const axis = self.axes[axisIdx];
const scale = self.scales[axis.scale!];
// For x-axis (bottom) we need bigger spacing between labels
if (axis.side === 2) {
return 55;
// for axis left & right
if (axis.side !== 2 || !scale) {
return 30;
}
return 30;
const defaultSpacing = 40;
if (scale.time) {
const maxTicks = plotDim / defaultSpacing;
const increment = (scaleMax - scaleMin) / maxTicks;
const sample = formatTime(self, [scaleMin], axisIdx, defaultSpacing, increment);
const width = measureText(sample[0], 12).width + 18;
return width;
}
return defaultSpacing;
}
/** height of x axis or width of y axis in CSS pixels alloted for values, gap & ticks, but excluding axis label */
@ -129,29 +140,38 @@ function calculateAxisSize(self: uPlot, values: string[], axisIdx: number) {
return measureText(maxLength, 12).width + 18;
}
const timeUnitSize = {
second: 1000,
minute: 60 * 1000,
hour: 60 * 60 * 1000,
day: 24 * 60 * 60 * 1000,
month: 28 * 24 * 60 * 60 * 1000,
year: 365 * 24 * 60 * 60 * 1000,
};
/** Format time axis ticks */
function formatTime(self: uPlot, splits: number[], axisIdx: number, foundSpace: number, foundIncr: number): string[] {
const timeZone = (self.axes[axisIdx] as any).timeZone;
const scale = self.scales.x;
const range = ((scale?.max ?? 0) - (scale?.min ?? 0)) / 1e3;
const oneDay = 86400;
const oneYear = 31536000;
foundIncr /= 1e3;
const range = (scale?.max ?? 0) - (scale?.min ?? 0);
const yearRoundedToDay = Math.round(timeUnitSize.year / timeUnitSize.day) * timeUnitSize.day;
const incrementRoundedToDay = Math.round(foundIncr / timeUnitSize.day) * timeUnitSize.day;
let format = systemDateFormats.interval.minute;
if (foundIncr < 1) {
if (foundIncr < timeUnitSize.second) {
format = systemDateFormats.interval.second.replace('ss', 'ss.SS');
} else if (foundIncr <= 45) {
} else if (foundIncr <= timeUnitSize.minute) {
format = systemDateFormats.interval.second;
} else if (foundIncr <= 7200 || range <= oneDay) {
} else if (foundIncr <= timeUnitSize.hour || range <= timeUnitSize.day) {
format = systemDateFormats.interval.minute;
} else if (foundIncr <= 80000) {
} else if (foundIncr <= timeUnitSize.day) {
format = systemDateFormats.interval.hour;
} else if (foundIncr <= 2419200 || range <= oneYear) {
} else if (foundIncr <= timeUnitSize.month || range < timeUnitSize.year) {
format = systemDateFormats.interval.day;
} else if (foundIncr <= 31536000) {
} else if (incrementRoundedToDay === yearRoundedToDay) {
format = systemDateFormats.interval.year;
} else if (foundIncr <= timeUnitSize.year) {
format = systemDateFormats.interval.month;
}