mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-05 19:15:03 +00:00
Reworked timeseries legend
This commit is contained in:
parent
67df762b7f
commit
c2a2626dd6
4 changed files with 480 additions and 446 deletions
|
|
@ -10,157 +10,191 @@ import formatterUtils from "../formatter-utils";
|
|||
|
||||
/* This function return the default config for dygraph charts */
|
||||
function getDefaultConfig() {
|
||||
return {
|
||||
labelsSeparateLines: true,
|
||||
legend: "follow",
|
||||
connectSeparatedPoints: true,
|
||||
includeZero: true,
|
||||
drawPoints: true,
|
||||
highlightSeriesBackgroundAlpha: 0.7,
|
||||
highlightSeriesOpts: {
|
||||
strokeWidth: 2,
|
||||
pointSize: 3,
|
||||
highlightCircleSize: 6,
|
||||
},
|
||||
axisLabelFontSize: 12,
|
||||
axes: {
|
||||
x: {
|
||||
axisLabelWidth: 90
|
||||
}
|
||||
},
|
||||
};
|
||||
return {
|
||||
labelsSeparateLines: true,
|
||||
legend: "follow",
|
||||
connectSeparatedPoints: true,
|
||||
includeZero: true,
|
||||
drawPoints: true,
|
||||
highlightSeriesBackgroundAlpha: 0.7,
|
||||
highlightSeriesOpts: {
|
||||
strokeWidth: 2,
|
||||
pointSize: 3,
|
||||
highlightCircleSize: 6,
|
||||
},
|
||||
axisLabelFontSize: 12,
|
||||
axes: {
|
||||
x: {
|
||||
axisLabelWidth: 90
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
/* This function put the correct formatters in the configuration */
|
||||
function changeFormatters(config, options) {
|
||||
if (options.formatters.length > 1) {
|
||||
/* Multiple formatters */
|
||||
/* NOTE: at most 2 formatters can be used */
|
||||
config.axes.y1 = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[0]));
|
||||
config.axes.y2 = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[1]));
|
||||
} else if (options.formatters.length == 1) {
|
||||
/* Single formatter */
|
||||
config.axes.y = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[0]));
|
||||
}
|
||||
if (options.formatters.length > 1) {
|
||||
/* Multiple formatters */
|
||||
/* NOTE: at most 2 formatters can be used */
|
||||
config.axes.y1 = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[0]));
|
||||
config.axes.y2 = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[1]));
|
||||
} else if (options.formatters.length == 1) {
|
||||
/* Single formatter */
|
||||
config.axes.y = getAxisConfiguration(formatterUtils.getFormatter(options.formatters[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
/* This function return the color of the serie when highlighted */
|
||||
function getHighlightColor() {
|
||||
const is_dark_mode = document.getElementsByClassName('body dark').length > 0;
|
||||
let highlight_color = 'rgb(255, 255, 255)';
|
||||
if (is_dark_mode) {
|
||||
highlight_color = 'rgb(13, 17, 23)';
|
||||
}
|
||||
return highlight_color;
|
||||
const is_dark_mode = document.getElementsByClassName('body dark').length > 0;
|
||||
let highlight_color = 'rgb(255, 255, 255)';
|
||||
if (is_dark_mode) {
|
||||
highlight_color = 'rgb(13, 17, 23)';
|
||||
}
|
||||
return highlight_color;
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
/* This function is used to format the value on the legend */
|
||||
function getAxisConfiguration(formatter) {
|
||||
return {
|
||||
axisLabelFormatter: formatter,
|
||||
valueFormatter: function (num_or_millis, opts, seriesName, dygraph, row, col) {
|
||||
const serie_point = dygraph?.rawData_?.[row][col];
|
||||
let data = '';
|
||||
if (typeof (serie_point) == "object") {
|
||||
/* This is the case for the serie with bounds */
|
||||
serie_point.forEach((el) => {
|
||||
data = `${data} / ${formatter(el || 0)}`;
|
||||
})
|
||||
data = data.substring(3); /* Remove the first three characters ' / ' */
|
||||
} else {
|
||||
/* This is the standard case */
|
||||
data = formatter(num_or_millis);
|
||||
}
|
||||
return (data);
|
||||
},
|
||||
axisLabelWidth: 80,
|
||||
}
|
||||
return {
|
||||
axisLabelFormatter: formatter,
|
||||
valueFormatter: function (num_or_millis, opts, seriesName, dygraph, row, col) {
|
||||
const serie_point = dygraph?.rawData_?.[row][col];
|
||||
let data = '';
|
||||
if (typeof (serie_point) == "object") {
|
||||
/* This is the case for the serie with bounds */
|
||||
serie_point.forEach((el) => {
|
||||
data = `${data} / ${formatter(el || 0)}`;
|
||||
})
|
||||
data = data.substring(3); /* Remove the first three characters ' / ' */
|
||||
} else {
|
||||
/* This is the standard case */
|
||||
data = formatter(num_or_millis);
|
||||
}
|
||||
return (data);
|
||||
},
|
||||
axisLabelWidth: 80,
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
/* This function is used to format the value on the legend */
|
||||
function getDefaultLegendFormatter(options) {
|
||||
return function (data) {
|
||||
if (!data.x) return ""; // no hover
|
||||
const timeBadge = `<h6><span class="badge bg-light mb-1 text-dark">${data.xHTML}</span></h6>`;
|
||||
let total = 0
|
||||
let setTotal = false
|
||||
let totalString = ''
|
||||
|
||||
// Entries
|
||||
const seriesHTML = data.series.filter(s => s.isVisible && s.yHTML).map(s => {
|
||||
if (!s.isVisible) return "";
|
||||
if (!isNaN(s.y) && !s.labelHTML.includes("Ago")) {
|
||||
// Skip e.g. 30 min Ago series from the total
|
||||
setTotal = true;
|
||||
total = total + Math.abs(s.y)
|
||||
}
|
||||
const colorDot = `<span class="badge rounded-pill me-1" style="background-color:${s.color}"> </span>`;
|
||||
return `<div class="mt-1 d-flex"><div class="me-4">${colorDot}<strong>${s.labelHTML}</strong></div><div class="ms-auto">${s.yHTML}</div></div>`;
|
||||
}).join("");
|
||||
|
||||
if (setTotal) {
|
||||
const formatter = formatterUtils.getFormatter(options.formatters[0])
|
||||
totalString = `<div class="mt-1 d-flex"><div class="me-4"><strong>Total</strong></div><div class="ms-auto">${formatter(total)}</div></div>`
|
||||
}
|
||||
|
||||
return `<div style="font-size:13px; line-height:1.4;">${timeBadge}${totalString}${seriesHTML}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
/* This function merges the default config with the options requested */
|
||||
function buildChartOptions(options) {
|
||||
const interpolated_colors = colorsInterpolation.transformColors(options.colors);
|
||||
const highlight_color = getHighlightColor();
|
||||
const config = getDefaultConfig();
|
||||
const interpolated_colors = colorsInterpolation.transformColors(options.colors);
|
||||
const highlight_color = getHighlightColor();
|
||||
const config = getDefaultConfig();
|
||||
const legendFormatter = getDefaultLegendFormatter(options);
|
||||
|
||||
config.customBars = options.customBars;
|
||||
config.labels = options.labels;
|
||||
config.series = options.properties;
|
||||
config.data = options.serie;
|
||||
config.stackedGraph = options.stacked;
|
||||
config.valueRange = options.value_range;
|
||||
config.highlightSeriesBackgroundColor = highlight_color;
|
||||
config.colors = interpolated_colors;
|
||||
config.disableTsList = options.disable_ts_list;
|
||||
config.yRangePad = options.yRangePad || 1;
|
||||
config.customBars = options.customBars;
|
||||
config.labels = options.labels;
|
||||
config.series = options.properties;
|
||||
config.data = options.serie;
|
||||
config.stackedGraph = options.stacked;
|
||||
config.valueRange = options.value_range;
|
||||
config.highlightSeriesBackgroundColor = highlight_color;
|
||||
config.colors = interpolated_colors;
|
||||
config.disableTsList = options.disable_ts_list;
|
||||
config.yRangePad = options.yRangePad || 1;
|
||||
config.legendFormatter = legendFormatter;
|
||||
|
||||
/* Change the plotter */
|
||||
if (options.plotter) {
|
||||
config.plotter = options.plotter;
|
||||
}
|
||||
/* Change the plotter */
|
||||
if (options.plotter) {
|
||||
config.plotter = options.plotter;
|
||||
}
|
||||
|
||||
changeFormatters(config, options);
|
||||
changeFormatters(config, options);
|
||||
|
||||
return config;
|
||||
return config;
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
function formatSerieProperties(type) {
|
||||
switch (type) {
|
||||
case 'dash':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokePattern: Dygraph.DASHED_LINE
|
||||
};
|
||||
case 'point':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokeWidth: 0.0,
|
||||
pointSize: 2.0,
|
||||
};
|
||||
case 'bounds':
|
||||
return {
|
||||
fillGraph: false,
|
||||
strokeWidth: 1.0,
|
||||
pointSize: 1.5,
|
||||
fillAlpha: 0.5
|
||||
};
|
||||
case 'line':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokeWidth: 1.5,
|
||||
pointSize: 1.5,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
fillGraph: true,
|
||||
customBars: false,
|
||||
strokeWidth: 1.0,
|
||||
pointSize: 1.5,
|
||||
fillAlpha: 0.5
|
||||
};
|
||||
}
|
||||
switch (type) {
|
||||
case 'dash':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokePattern: Dygraph.DASHED_LINE
|
||||
};
|
||||
case 'point':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokeWidth: 0.0,
|
||||
pointSize: 2.0,
|
||||
};
|
||||
case 'bounds':
|
||||
return {
|
||||
fillGraph: false,
|
||||
strokeWidth: 1.0,
|
||||
pointSize: 1.5,
|
||||
fillAlpha: 0.5
|
||||
};
|
||||
case 'line':
|
||||
return {
|
||||
fillGraph: false,
|
||||
customBars: false,
|
||||
strokeWidth: 1.5,
|
||||
pointSize: 1.5,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
fillGraph: true,
|
||||
customBars: false,
|
||||
strokeWidth: 1.0,
|
||||
pointSize: 1.5,
|
||||
fillAlpha: 0.5
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
const dygraphConfig = function () {
|
||||
return {
|
||||
buildChartOptions,
|
||||
formatSerieProperties
|
||||
};
|
||||
return {
|
||||
buildChartOptions,
|
||||
formatSerieProperties
|
||||
};
|
||||
}();
|
||||
|
||||
export default dygraphConfig;
|
||||
Loading…
Add table
Add a link
Reference in a new issue