rrd chart: fix y-axis segmentation when using powerOfTwo

The chart axis get initialized really, so changing the segmenter in
initComponent is not possible anymore, we can only alter the chart
base config in the constructor.

Luckily, the actual segmentation happens later, so we can pass a
flag to the y-axis and hook into the segmenter directly by creating
a new one derived from 'Ext.chart.axis.segmenter.Numeric'.

There we override the preferStep and exactStep methods to decide if
we want to calculate with base 10 or base 2.

So add a constructor to RRDChart and set the axis with the respective
segmenter, depending on the powerOfTwo config, up there initially.

Note: that makes overwriting the axes from a caller impossible, but
we do not use that anywhere, and we can control the more important
parts of the axes, like label or units already otherwise, so seems
not really required, and if, its not to hard to solve (either by
always using our new segmenter by default and handle the different
bases there directly, or by adding an explicit do not touch axes
config flag, or the like).

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2021-04-16 21:53:45 +02:00
parent 4337ad5b74
commit 9531c6594e

View File

@ -1,3 +1,58 @@
Ext.define('Proxmox.chart.axis.segmenter.NumericBase2', {
extend: 'Ext.chart.axis.segmenter.Numeric',
alias: 'segmenter.numericBase2',
// derived from the original numeric segmenter but using 2 instead of 10 as base
preferredStep: function(min, estStepSize) {
// Getting an order of magnitude of the estStepSize with a common logarithm.
let order = Math.floor(Math.log2(estStepSize));
let scale = Math.pow(2, order);
estStepSize /= scale;
// FIXME: below is not useful when using base 2 instead of base 10, we could
// just directly set estStepSize to 2
if (estStepSize <= 1) {
estStepSize = 1;
} else if (estStepSize < 2) {
estStepSize = 2;
}
return {
unit: {
// When passed estStepSize is less than 1, its order of magnitude
// is equal to -number_of_leading_zeros in the estStepSize.
fixes: -order, // Number of fractional digits.
scale: scale,
},
step: estStepSize,
};
},
/**
* Wraps the provided estimated step size of a range without altering it into a step size object.
*
* @param {*} min The start point of range.
* @param {*} estStepSize The estimated step size.
* @return {Object} Return the step size by an object of step x unit.
* @return {Number} return.step The step count of units.
* @return {Object} return.unit The unit.
*/
// derived from the original numeric segmenter but using 2 instead of 10 as base
exactStep: function(min, estStepSize) {
let order = Math.floor(Math.log2(estStepSize));
let scale = Math.pow(2, order);
return {
unit: {
// add one decimal point if estStepSize is not a multiple of scale
fixes: -order + (estStepSize % scale === 0 ? 0 : 1),
scale: 1,
},
step: estStepSize,
};
},
});
Ext.define('Proxmox.widget.RRDChart', {
extend: 'Ext.chart.CartesianChart',
alias: 'widget.proxmoxRRDChart',
@ -81,25 +136,33 @@ Ext.define('Proxmox.widget.RRDChart', {
legend: {
padding: 0,
},
axes: [
{
type: 'numeric',
position: 'left',
grid: true,
renderer: 'leftAxisRenderer',
minimum: 0,
},
{
type: 'time',
position: 'bottom',
grid: true,
fields: ['time'],
},
],
listeners: {
animationend: 'onAfterAnimation',
},
constructor: function(config) {
let me = this;
let segmenter = config.powerOfTwo ? 'numericBase2' : 'numeric';
config.axes = [
{
type: 'numeric',
position: 'left',
grid: true,
renderer: 'leftAxisRenderer',
minimum: 0,
segmenter,
},
{
type: 'time',
position: 'bottom',
grid: true,
fields: ['time'],
},
];
me.callParent([config]);
},
initComponent: function() {
let me = this;