]> git.proxmox.com Git - proxmox-widget-toolkit.git/commitdiff
rrd chart: fix y-axis segmentation when using powerOfTwo
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Fri, 16 Apr 2021 19:53:45 +0000 (21:53 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Sat, 17 Apr 2021 17:20:53 +0000 (19:20 +0200)
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>
src/panel/RRDChart.js

index 3cea635992a2df54bfe6d24e14e76d09b4ce7f56..41c839efec87a75709e75505811bf54aa7358e2a 100644 (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;