Translated using Weblate (Italian)
[phpmyadmin.git] / js / chart.js
blobac7874f17b6884853ad82ce954d5f2a3e0c7ee69
1 /**
2  * Chart type enumerations
3  */
4 var ChartType = {
5     LINE : 'line',
6     SPLINE : 'spline',
7     AREA : 'area',
8     BAR : 'bar',
9     COLUMN : 'column',
10     PIE : 'pie',
11     TIMELINE: 'timeline',
12     SCATTER: 'scatter'
15 /**
16  * Abstract chart factory which defines the contract for chart factories
17  */
18 var ChartFactory = function () {
20 ChartFactory.prototype = {
21     createChart : function (type, options) {
22         throw new Error("createChart must be implemented by a subclass");
23     }
26 /**
27  * Abstract chart which defines the contract for charts
28  *
29  * @param elementId
30  *            id of the div element the chart is drawn in
31  */
32 var Chart = function (elementId) {
33     this.elementId = elementId;
35 Chart.prototype = {
36     draw : function (data, options) {
37         throw new Error("draw must be implemented by a subclass");
38     },
39     redraw : function (options) {
40         throw new Error("redraw must be implemented by a subclass");
41     },
42     destroy : function () {
43         throw new Error("destroy must be implemented by a subclass");
44     }
47 /**
48  * Abstract representation of charts that operates on DataTable where,<br />
49  * <ul>
50  * <li>First column provides index to the data.</li>
51  * <li>Each subsequent columns are of type
52  * <code>ColumnType.NUMBER<code> and represents a data series.</li>
53  * </ul>
54  * Line chart, area chart, bar chart, column chart are typical examples.
55  *
56  * @param elementId
57  *            id of the div element the chart is drawn in
58  */
59 var BaseChart = function (elementId) {
60     Chart.call(this, elementId);
62 BaseChart.prototype = new Chart();
63 BaseChart.prototype.constructor = BaseChart;
64 BaseChart.prototype.validateColumns = function (dataTable) {
65     var columns = dataTable.getColumns();
66     if (columns.length < 2) {
67         throw new Error("Minimum of two columns are required for this chart");
68     }
69     for (var i = 1; i < columns.length; i++) {
70         if (columns[i].type != ColumnType.NUMBER) {
71             throw new Error("Column " + (i + 1) + " should be of type 'Number'");
72         }
73     }
74     return true;
77 /**
78  * Abstract pie chart
79  *
80  * @param elementId
81  *            id of the div element the chart is drawn in
82  */
83 var PieChart = function (elementId) {
84     BaseChart.call(this, elementId);
86 PieChart.prototype = new BaseChart();
87 PieChart.prototype.constructor = PieChart;
88 PieChart.prototype.validateColumns = function (dataTable) {
89     var columns = dataTable.getColumns();
90     if (columns.length > 2) {
91         throw new Error("Pie charts can draw only one series");
92     }
93     return BaseChart.prototype.validateColumns.call(this, dataTable);
96 /**
97  * Abstract timeline chart
98  *
99  * @param elementId
100  *            id of the div element the chart is drawn in
101  */
102 var TimelineChart = function (elementId) {
103     BaseChart.call(this, elementId);
105 TimelineChart.prototype = new BaseChart();
106 TimelineChart.prototype.constructor = TimelineChart;
107 TimelineChart.prototype.validateColumns = function (dataTable) {
108     var result = BaseChart.prototype.validateColumns.call(this, dataTable);
109     if (result) {
110         var columns = dataTable.getColumns();
111         if (columns[0].type != ColumnType.DATE) {
112             throw new Error("First column of timeline chart need to be a date column");
113         }
114     }
115     return result;
119  * Abstract scatter chart
121  * @param elementId
122  *            id of the div element the chart is drawn in
123  */
124 var ScatterChart = function(elementId) {
125     BaseChart.call(this, elementId);
127 ScatterChart.prototype = new BaseChart();
128 ScatterChart.prototype.constructor = ScatterChart;
129 ScatterChart.prototype.validateColumns = function (dataTable) {
130     var result = BaseChart.prototype.validateColumns.call(this, dataTable);
131     if (result) {
132         var columns = dataTable.getColumns();
133         if (columns[0].type != ColumnType.NUMBER) {
134             throw new Error("First column of scatter chart need to be a numeric column");
135         }
136     }
137     return result;
141  * The data table contains column information and data for the chart.
142  */
143 var DataTable = function () {
144     var columns = [];
145     var data = null;
147     this.addColumn = function (type, name) {
148         columns.push({
149             'type' : type,
150             'name' : name
151         });
152     };
154     this.getColumns = function () {
155         return columns;
156     };
158     this.setData = function (rows) {
159         data = rows;
160         fillMissingValues();
161     };
163     this.getData = function () {
164         return data;
165     };
167     var fillMissingValues = function () {
168         if (columns.length === 0) {
169             throw new Error("Set columns first");
170         }
171         var row;
172         for (var i = 0; i < data.length; i++) {
173             row = data[i];
174             if (row.length > columns.length) {
175                 row.splice(columns.length - 1, row.length - columns.length);
176             } else if (row.length < columns.length) {
177                 for (var j = row.length; j < columns.length; j++) {
178                     row.push(null);
179                 }
180             }
181         }
182     };
186  * Column type enumeration
187  */
188 var ColumnType = {
189     STRING : 'string',
190     NUMBER : 'number',
191     BOOLEAN : 'boolean',
192     DATE : 'date'
195 /*******************************************************************************
196  * JQPlot specific code
197  ******************************************************************************/
200  * Chart factory that returns JQPlotCharts
201  */
202 var JQPlotChartFactory = function () {
204 JQPlotChartFactory.prototype = new ChartFactory();
205 JQPlotChartFactory.prototype.createChart = function (type, elementId) {
206     var chart = null;
207     switch (type) {
208     case ChartType.LINE:
209         chart = new JQPlotLineChart(elementId);
210         break;
211     case ChartType.SPLINE:
212         chart = new JQPlotSplineChart(elementId);
213         break;
214     case ChartType.TIMELINE:
215         chart = new JQPlotTimelineChart(elementId);
216         break;
217     case ChartType.AREA:
218         chart = new JQPlotAreaChart(elementId);
219         break;
220     case ChartType.BAR:
221         chart = new JQPlotBarChart(elementId);
222         break;
223     case ChartType.COLUMN:
224         chart = new JQPlotColumnChart(elementId);
225         break;
226     case ChartType.PIE:
227         chart = new JQPlotPieChart(elementId);
228         break;
229     case ChartType.SCATTER:
230         chart = new JQPlotScatterChart(elementId);
231         break;
232     }
234     return chart;
238  * Abstract JQplot chart
240  * @param elementId
241  *            id of the div element the chart is drawn in
242  */
243 var JQPlotChart = function (elementId) {
244     Chart.call(this, elementId);
245     this.plot = null;
246     this.validator;
248 JQPlotChart.prototype = new Chart();
249 JQPlotChart.prototype.constructor = JQPlotChart;
250 JQPlotChart.prototype.draw = function (data, options) {
251     if (this.validator.validateColumns(data)) {
252         this.plot = $.jqplot(this.elementId, this.prepareData(data), this
253                 .populateOptions(data, options));
254     }
256 JQPlotChart.prototype.destroy = function () {
257     if (this.plot !== null) {
258         this.plot.destroy();
259     }
261 JQPlotChart.prototype.redraw = function (options) {
262     if (this.plot !== null) {
263         this.plot.replot(options);
264     }
266 JQPlotChart.prototype.populateOptions = function (dataTable, options) {
267     throw new Error("populateOptions must be implemented by a subclass");
269 JQPlotChart.prototype.prepareData = function (dataTable) {
270     throw new Error("prepareData must be implemented by a subclass");
274  * JQPlot line chart
276  * @param elementId
277  *            id of the div element the chart is drawn in
278  */
279 var JQPlotLineChart = function (elementId) {
280     JQPlotChart.call(this, elementId);
281     this.validator = BaseChart.prototype;
283 JQPlotLineChart.prototype = new JQPlotChart();
284 JQPlotLineChart.prototype.constructor = JQPlotLineChart;
286 JQPlotLineChart.prototype.populateOptions = function (dataTable, options) {
287     var columns = dataTable.getColumns();
288     var optional = {
289         axes : {
290             xaxis : {
291                 label : columns[0].name,
292                 renderer : $.jqplot.CategoryAxisRenderer,
293                 ticks : []
294             },
295             yaxis : {
296                 label : (columns.length == 2 ? columns[1].name : 'Values'),
297                 labelRenderer : $.jqplot.CanvasAxisLabelRenderer
298             }
299         },
300         highlighter: {
301             show: true,
302             tooltipAxes: 'y',
303             formatString:'%d'
304         },
305         series : []
306     };
307     $.extend(true, optional, options);
309     if (optional.series.length === 0) {
310         for (var i = 1; i < columns.length; i++) {
311             optional.series.push({
312                 label : columns[i].name.toString()
313             });
314         }
315     }
316     if (optional.axes.xaxis.ticks.length === 0) {
317         var data = dataTable.getData();
318         for (var i = 0; i < data.length; i++) {
319             optional.axes.xaxis.ticks.push(data[i][0].toString());
320         }
321     }
322     return optional;
325 JQPlotLineChart.prototype.prepareData = function (dataTable) {
326     var data = dataTable.getData(), row;
327     var retData = [], retRow;
328     for (var i = 0; i < data.length; i++) {
329         row = data[i];
330         for (var j = 1; j < row.length; j++) {
331             retRow = retData[j - 1];
332             if (retRow === undefined) {
333                 retRow = [];
334                 retData[j - 1] = retRow;
335             }
336             retRow.push(row[j]);
337         }
338     }
339     return retData;
343  * JQPlot spline chart
345  * @param elementId
346  *            id of the div element the chart is drawn in
347  */
348 var JQPlotSplineChart = function (elementId) {
349     JQPlotLineChart.call(this, elementId);
351 JQPlotSplineChart.prototype = new JQPlotLineChart();
352 JQPlotSplineChart.prototype.constructor = JQPlotSplineChart;
354 JQPlotSplineChart.prototype.populateOptions = function (dataTable, options) {
355     var optional = {};
356     var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
357             options);
358     var compulsory = {
359         seriesDefaults : {
360             rendererOptions : {
361                 smooth : true
362             }
363         }
364     };
365     $.extend(true, optional, opt, compulsory);
366     return optional;
370  * JQPlot scatter chart
372  * @param elementId
373  *            id of the div element the chart is drawn in
374  */
375 var JQPlotScatterChart = function (elementId) {
376     JQPlotChart.call(this, elementId);
377     this.validator = ScatterChart.prototype;
379 JQPlotScatterChart.prototype = new JQPlotChart();
380 JQPlotScatterChart.prototype.constructor = JQPlotScatterChart;
382 JQPlotScatterChart.prototype.populateOptions = function (dataTable, options) {
383     var columns = dataTable.getColumns();
384     var optional = {
385         axes : {
386             xaxis : {
387                 label : columns[0].name
388             },
389             yaxis : {
390                 label : (columns.length == 2 ? columns[1].name : 'Values'),
391                 labelRenderer : $.jqplot.CanvasAxisLabelRenderer
392             }
393         },
394         highlighter: {
395             show: true,
396             tooltipAxes: 'xy',
397             formatString:'%d, %d'
398         },
399         series : []
400     };
401     for (var i = 1; i < columns.length; i++) {
402         optional.series.push({
403             label : columns[i].name.toString()
404         });
405     }
407     var compulsory = {
408         seriesDefaults : {
409             showLine: false,
410             markerOptions: {
411                 size: 7,
412                 style: "x"
413             }
414         }
415     };
417     $.extend(true, optional, options, compulsory);
418     return optional;
421 JQPlotScatterChart.prototype.prepareData = function (dataTable) {
422     var data = dataTable.getData(), row;
423     var retData = [], retRow;
424     for (var i = 0; i < data.length; i++) {
425         row = data[i];
426         if (row[0]) {
427             for (var j = 1; j < row.length; j++) {
428                 retRow = retData[j - 1];
429                 if (retRow === undefined) {
430                     retRow = [];
431                     retData[j - 1] = retRow;
432                 }
433                 retRow.push([row[0], row[j]]);
434             }
435         }
436     }
437     return retData;
441  * JQPlot timeline chart
443  * @param elementId
444  *            id of the div element the chart is drawn in
445  */
446 var JQPlotTimelineChart = function (elementId) {
447     JQPlotLineChart.call(this, elementId);
448     this.validator = TimelineChart.prototype;
450 JQPlotTimelineChart.prototype = new JQPlotLineChart();
451 JQPlotTimelineChart.prototype.constructor = JQPlotTimelineChart;
453 JQPlotTimelineChart.prototype.populateOptions = function (dataTable, options) {
454     var optional = {
455         axes : {
456             xaxis : {
457                 tickOptions : {
458                     formatString: '%b %#d, %y'
459                 }
460             }
461         }
462     };
463     var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, options);
464     var compulsory = {
465         axes : {
466             xaxis : {
467                 renderer : $.jqplot.DateAxisRenderer
468             }
469         }
470     };
471     $.extend(true, optional, opt, compulsory);
472     return optional;
475 JQPlotTimelineChart.prototype.prepareData = function (dataTable) {
476     var data = dataTable.getData(), row, d;
477     var retData = [], retRow;
478     for (var i = 0; i < data.length; i++) {
479         row = data[i];
480         d = row[0];
481         for (var j = 1; j < row.length; j++) {
482             retRow = retData[j - 1];
483             if (retRow === undefined) {
484                 retRow = [];
485                 retData[j - 1] = retRow;
486             }
487             if (d !== null) {
488                 retRow.push([d.getTime(), row[j]]);
489             }
490         }
491     }
492     return retData;
496  * JQPlot area chart
498  * @param elementId
499  *            id of the div element the chart is drawn in
500  */
501 var JQPlotAreaChart = function (elementId) {
502     JQPlotLineChart.call(this, elementId);
504 JQPlotAreaChart.prototype = new JQPlotLineChart();
505 JQPlotAreaChart.prototype.constructor = JQPlotAreaChart;
507 JQPlotAreaChart.prototype.populateOptions = function (dataTable, options) {
508     var optional = {
509         seriesDefaults : {
510             fillToZero : true
511         }
512     };
513     var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
514             options);
515     var compulsory = {
516         seriesDefaults : {
517             fill : true
518         }
519     };
520     $.extend(true, optional, opt, compulsory);
521     return optional;
525  * JQPlot column chart
527  * @param elementId
528  *            id of the div element the chart is drawn in
529  */
530 var JQPlotColumnChart = function (elementId) {
531     JQPlotLineChart.call(this, elementId);
533 JQPlotColumnChart.prototype = new JQPlotLineChart();
534 JQPlotColumnChart.prototype.constructor = JQPlotColumnChart;
536 JQPlotColumnChart.prototype.populateOptions = function (dataTable, options) {
537     var optional = {
538         seriesDefaults : {
539             fillToZero : true
540         }
541     };
542     var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
543             options);
544     var compulsory = {
545         seriesDefaults : {
546             renderer : $.jqplot.BarRenderer
547         }
548     };
549     $.extend(true, optional, opt, compulsory);
550     return optional;
554  * JQPlot bar chart
556  * @param elementId
557  *            id of the div element the chart is drawn in
558  */
559 var JQPlotBarChart = function (elementId) {
560     JQPlotLineChart.call(this, elementId);
562 JQPlotBarChart.prototype = new JQPlotLineChart();
563 JQPlotBarChart.prototype.constructor = JQPlotBarChart;
565 JQPlotBarChart.prototype.populateOptions = function (dataTable, options) {
566     var columns = dataTable.getColumns();
567     var optional = {
568         axes : {
569             yaxis : {
570                 label : columns[0].name,
571                 labelRenderer : $.jqplot.CanvasAxisLabelRenderer,
572                 renderer : $.jqplot.CategoryAxisRenderer,
573                 ticks : []
574             },
575             xaxis : {
576                 label : (columns.length == 2 ? columns[1].name : 'Values'),
577                 labelRenderer : $.jqplot.CanvasAxisLabelRenderer
578             }
579         },
580         highlighter: {
581             show: true,
582             tooltipAxes: 'x',
583             formatString:'%d'
584         },
585         series : [],
586         seriesDefaults : {
587             fillToZero : true
588         }
589     };
590     var compulsory = {
591         seriesDefaults : {
592             renderer : $.jqplot.BarRenderer,
593             rendererOptions : {
594                 barDirection : 'horizontal'
595             }
596         }
597     };
598     $.extend(true, optional, options, compulsory);
600     if (optional.axes.yaxis.ticks.length === 0) {
601         var data = dataTable.getData();
602         for (var i = 0; i < data.length; i++) {
603             optional.axes.yaxis.ticks.push(data[i][0].toString());
604         }
605     }
606     if (optional.series.length === 0) {
607         for (var i = 1; i < columns.length; i++) {
608             optional.series.push({
609                 label : columns[i].name.toString()
610             });
611         }
612     }
613     return optional;
617  * JQPlot pie chart
619  * @param elementId
620  *            id of the div element the chart is drawn in
621  */
622 var JQPlotPieChart = function (elementId) {
623     JQPlotChart.call(this, elementId);
624     this.validator = PieChart.prototype;
626 JQPlotPieChart.prototype = new JQPlotChart();
627 JQPlotPieChart.prototype.constructor = JQPlotPieChart;
629 JQPlotPieChart.prototype.populateOptions = function (dataTable, options) {
630     var optional = {
631         highlighter: {
632             show: true,
633             tooltipAxes: 'xy',
634             formatString:'%s, %d',
635             useAxesFormatters: false
636         }
637     };
638     var compulsory = {
639         seriesDefaults : {
640             renderer : $.jqplot.PieRenderer
641         }
642     };
643     $.extend(true, optional, options, compulsory);
644     return optional;
647 JQPlotPieChart.prototype.prepareData = function (dataTable) {
648     var data = dataTable.getData(), row;
649     var retData = [];
650     for (var i = 0; i < data.length; i++) {
651         row = data[i];
652         retData.push([ row[0], row[1] ]);
653     }
654     return [ retData ];