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