]>
git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/RRDChart.js
1 Ext
.define('Proxmox.chart.axis.segmenter.NumericBase2', {
2 extend
: 'Ext.chart.axis.segmenter.Numeric',
3 alias
: 'segmenter.numericBase2',
5 // derived from the original numeric segmenter but using 2 instead of 10 as base
6 preferredStep: function(min
, estStepSize
) {
7 // Getting an order of magnitude of the estStepSize with a common logarithm.
8 let order
= Math
.floor(Math
.log2(estStepSize
));
9 let scale
= Math
.pow(2, order
);
13 // FIXME: below is not useful when using base 2 instead of base 10, we could
14 // just directly set estStepSize to 2
15 if (estStepSize
<= 1) {
17 } else if (estStepSize
< 2) {
22 // When passed estStepSize is less than 1, its order of magnitude
23 // is equal to -number_of_leading_zeros in the estStepSize.
24 fixes
: -order
, // Number of fractional digits.
32 * Wraps the provided estimated step size of a range without altering it into a step size object.
34 * @param {*} min The start point of range.
35 * @param {*} estStepSize The estimated step size.
36 * @return {Object} Return the step size by an object of step x unit.
37 * @return {Number} return.step The step count of units.
38 * @return {Object} return.unit The unit.
40 // derived from the original numeric segmenter but using 2 instead of 10 as base
41 exactStep: function(min
, estStepSize
) {
42 let order
= Math
.floor(Math
.log2(estStepSize
));
43 let scale
= Math
.pow(2, order
);
47 // add one decimal point if estStepSize is not a multiple of scale
48 fixes
: -order
+ (estStepSize
% scale
=== 0 ? 0 : 1),
56 Ext
.define('Proxmox.widget.RRDChart', {
57 extend
: 'Ext.chart.CartesianChart',
58 alias
: 'widget.proxmoxRRDChart',
60 unit
: undefined, // bytes, bytespersecond, percent
64 // set to empty string to suppress warning in debug mode
65 downloadServerUrl
: '-',
68 xclass
: 'Ext.app.ViewController',
70 init: function(view
) {
71 this.powerOfTwo
= view
.powerOfTwo
;
74 convertToUnits: function(value
) {
75 let units
= ['', 'k', 'M', 'G', 'T', 'P'];
78 if (value
< 0.1) format
+= '#';
79 const baseValue
= this.powerOfTwo
? 1024 : 1000;
80 while (value
>= baseValue
&& si
< units
.length
-1) {
81 value
= value
/ baseValue
;
85 // javascript floating point weirdness
86 value
= Ext
.Number
.correctFloat(value
);
88 // limit decimal points
89 value
= Ext
.util
.Format
.number(value
, format
);
92 if (this.powerOfTwo
) unit
+= 'i';
94 return `${value.toString()} ${unit}`;
97 leftAxisRenderer: function(axis
, label
, layoutContext
) {
99 return me
.convertToUnits(label
);
102 onSeriesTooltipRender: function(tooltip
, record
, item
) {
103 let view
= this.getView();
106 if (view
.unit
=== 'percent') {
108 } else if (view
.unit
=== 'bytes') {
110 } else if (view
.unit
=== 'bytespersecond') {
114 let prefix
= item
.field
;
115 if (view
.fieldTitles
&& view
.fieldTitles
[view
.fields
.indexOf(item
.field
)]) {
116 prefix
= view
.fieldTitles
[view
.fields
.indexOf(item
.field
)];
118 let v
= this.convertToUnits(record
.get(item
.field
));
119 let t
= new Date(record
.get('time'));
120 tooltip
.setHtml(`${prefix}: ${v}${suffix}<br>${t}`);
123 onAfterAnimation: function(chart
, eopts
) {
124 if (!chart
.header
|| !chart
.header
.tools
) {
127 // if the undo button is disabled, disable our tool
128 let ourUndoZoomButton
= chart
.header
.tools
[0];
129 let undoButton
= chart
.interactions
[0].getUndoButton();
130 ourUndoZoomButton
.setDisabled(undoButton
.isDisabled());
148 fn
: 'onAfterAnimation',
155 constructor: function(config
) {
158 let segmenter
= config
.powerOfTwo
? 'numericBase2' : 'numeric';
164 renderer
: 'leftAxisRenderer',
175 me
.callParent([config
]);
178 initComponent: function() {
182 throw "cannot work without store";
186 throw "cannot work without fields";
191 // add correct label for left axis
193 if (me
.unit
=== 'percent') {
195 } else if (me
.unit
=== 'bytes') {
197 } else if (me
.unit
=== 'bytespersecond') {
198 axisTitle
= "Bytes/s";
199 } else if (me
.fieldTitles
&& me
.fieldTitles
.length
=== 1) {
200 axisTitle
= me
.fieldTitles
[0];
201 } else if (me
.fields
.length
=== 1) {
202 axisTitle
= me
.fields
[0];
205 me
.axes
[0].setTitle(axisTitle
);
209 if (me
.header
&& me
.legend
) {
210 me
.header
.padding
= '4 9 4';
211 me
.header
.add(me
.legend
);
212 me
.legend
= undefined;
219 tooltip
: gettext('Undo Zoom'),
220 handler: function() {
221 let undoButton
= me
.interactions
[0].getUndoButton();
222 if (undoButton
.handler
) {
223 undoButton
.handler();
229 // add a series for each field we get
230 me
.fields
.forEach(function(item
, index
) {
232 if (me
.fieldTitles
&& me
.fieldTitles
[index
]) {
233 title
= me
.fieldTitles
[index
];
235 me
.addSeries(Ext
.apply(
260 renderer
: 'onSeriesTooltipRender',
267 // enable animation after the store is loaded
268 me
.store
.onAfter('load', function() {
269 me
.setAnimation(true);
270 }, this, { single
: true });