]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - panel/RRDChart.js
718b32b9b23502dc56611f48a424ee4b6a03049a
[proxmox-widget-toolkit.git] / panel / RRDChart.js
1 Ext.define('Proxmox.widget.RRDChart', {
2 extend: 'Ext.chart.CartesianChart',
3 alias: 'widget.proxmoxRRDChart',
4
5 unit: undefined, // bytes, bytespersecond, percent
6
7 controller: {
8 xclass: 'Ext.app.ViewController',
9
10 convertToUnits: function(value) {
11 var units = ['', 'k', 'M', 'G', 'T', 'P'];
12 var si = 0;
13 let format = '0.##';
14 if (value < 0.1) format += '#';
15 while (value >= 1000 && si < units.length -1) {
16 value = value / 1000;
17 si++;
18 }
19
20 // javascript floating point weirdness
21 value = Ext.Number.correctFloat(value);
22
23 // limit decimal points
24 value = Ext.util.Format.number(value, format);
25
26 return value.toString() + " " + units[si];
27 },
28
29 leftAxisRenderer: function(axis, label, layoutContext) {
30 var me = this;
31 return me.convertToUnits(label);
32 },
33
34 onSeriesTooltipRender: function(tooltip, record, item) {
35 var me = this.getView();
36
37 var suffix = '';
38
39 if (me.unit === 'percent') {
40 suffix = '%';
41 } else if (me.unit === 'bytes') {
42 suffix = 'B';
43 } else if (me.unit === 'bytespersecond') {
44 suffix = 'B/s';
45 }
46
47 var prefix = item.field;
48 if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
49 prefix = me.fieldTitles[me.fields.indexOf(item.field)];
50 }
51 let v = this.convertToUnits(record.get(item.field));
52 let t = new Date(record.get('time'));
53 tooltip.setHtml(`${prefix}: ${v}${suffix}<br>${t}`);
54 },
55
56 onAfterAnimation: function(chart, eopts) {
57 // if the undo button is disabled, disable our tool
58 var ourUndoZoomButton = chart.header.tools[0];
59 var undoButton = chart.interactions[0].getUndoButton();
60 ourUndoZoomButton.setDisabled(undoButton.isDisabled());
61 },
62 },
63
64 width: 770,
65 height: 300,
66 animation: false,
67 interactions: [
68 {
69 type: 'crosszoom',
70 },
71 ],
72 legend: {
73 padding: 0,
74 },
75 axes: [
76 {
77 type: 'numeric',
78 position: 'left',
79 grid: true,
80 renderer: 'leftAxisRenderer',
81 minimum: 0,
82 },
83 {
84 type: 'time',
85 position: 'bottom',
86 grid: true,
87 fields: ['time'],
88 },
89 ],
90 listeners: {
91 animationend: 'onAfterAnimation',
92 },
93
94 initComponent: function() {
95 var me = this;
96 var series = {};
97
98 if (!me.store) {
99 throw "cannot work without store";
100 }
101
102 if (!me.fields) {
103 throw "cannot work without fields";
104 }
105
106 me.callParent();
107
108 // add correct label for left axis
109 var axisTitle = "";
110 if (me.unit === 'percent') {
111 axisTitle = "%";
112 } else if (me.unit === 'bytes') {
113 axisTitle = "Bytes";
114 } else if (me.unit === 'bytespersecond') {
115 axisTitle = "Bytes/s";
116 } else if (me.fieldTitles && me.fieldTitles.length === 1) {
117 axisTitle = me.fieldTitles[0];
118 } else if (me.fields.length === 1) {
119 axisTitle = me.fields[0];
120 }
121
122 me.axes[0].setTitle(axisTitle);
123
124 me.updateHeader();
125
126 if (me.header && me.legend) {
127 me.header.padding = '4 9 4';
128 me.header.add(me.legend);
129 }
130
131 if (!me.noTool) {
132 me.addTool({
133 type: 'minus',
134 disabled: true,
135 tooltip: gettext('Undo Zoom'),
136 handler: function() {
137 var undoButton = me.interactions[0].getUndoButton();
138 if (undoButton.handler) {
139 undoButton.handler();
140 }
141 },
142 });
143 }
144
145 // add a series for each field we get
146 me.fields.forEach(function(item, index) {
147 var title = item;
148 if (me.fieldTitles && me.fieldTitles[index]) {
149 title = me.fieldTitles[index];
150 }
151 me.addSeries(Ext.apply(
152 {
153 type: 'line',
154 xField: 'time',
155 yField: item,
156 title: title,
157 fill: true,
158 style: {
159 lineWidth: 1.5,
160 opacity: 0.60,
161 },
162 marker: {
163 opacity: 0,
164 scaling: 0.01,
165 fx: {
166 duration: 200,
167 easing: 'easeOut',
168 },
169 },
170 highlightCfg: {
171 opacity: 1,
172 scaling: 1.5,
173 },
174 tooltip: {
175 trackMouse: true,
176 renderer: 'onSeriesTooltipRender',
177 },
178 },
179 me.seriesConfig,
180 ));
181 });
182
183 // enable animation after the store is loaded
184 me.store.onAfter('load', function() {
185 me.setAnimation(true);
186 }, this, { single: true });
187 },
188 });