Add support for Berber languages
[phpmyadmin.git] / js / tbl_chart.js
blobb43a2215288f7f99b58546b8a7f33dea40aacb6b
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 var chart_data = {};
4 var temp_chart_title;
6 var currentChart = null;
7 var currentSettings = null;
9 var dateTimeCols = [];
10 var numericCols = [];
12 function extractDate (dateString) {
13     var matches;
14     var match;
15     var dateTimeRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/;
16     var dateRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2}/;
18     matches = dateTimeRegExp.exec(dateString);
19     if (matches !== null && matches.length > 0) {
20         match = matches[0];
21         return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2), match.substr(11, 2), match.substr(14, 2), match.substr(17, 2));
22     } else {
23         matches = dateRegExp.exec(dateString);
24         if (matches !== null && matches.length > 0) {
25             match = matches[0];
26             return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2));
27         }
28     }
29     return null;
32 function PMA_queryChart (data, columnNames, settings) {
33     if ($('#querychart').length === 0) {
34         return;
35     }
37     var plotSettings = {
38         title : {
39             text : settings.title,
40             escapeHtml: true
41         },
42         grid : {
43             drawBorder : false,
44             shadow : false,
45             background : 'rgba(0,0,0,0)'
46         },
47         legend : {
48             show : true,
49             placement : 'outsideGrid',
50             location : 'e',
51             rendererOptions: {
52                 numberColumns: 2
53             }
54         },
55         axes : {
56             xaxis : {
57                 label : escapeHtml(settings.xaxisLabel)
58             },
59             yaxis : {
60                 label : settings.yaxisLabel
61             }
62         },
63         stackSeries : settings.stackSeries
64     };
66     // create the chart
67     var factory = new JQPlotChartFactory();
68     var chart = factory.createChart(settings.type, 'querychart');
70     // create the data table and add columns
71     var dataTable = new DataTable();
72     if (settings.type === 'timeline') {
73         dataTable.addColumn(ColumnType.DATE, columnNames[settings.mainAxis]);
74     } else if (settings.type === 'scatter') {
75         dataTable.addColumn(ColumnType.NUMBER, columnNames[settings.mainAxis]);
76     } else {
77         dataTable.addColumn(ColumnType.STRING, columnNames[settings.mainAxis]);
78     }
80     var i;
81     if (settings.seriesColumn === null) {
82         $.each(settings.selectedSeries, function (index, element) {
83             dataTable.addColumn(ColumnType.NUMBER, columnNames[element]);
84         });
86         // set data to the data table
87         var columnsToExtract = [settings.mainAxis];
88         $.each(settings.selectedSeries, function (index, element) {
89             columnsToExtract.push(element);
90         });
91         var values = [];
92         var newRow;
93         var row;
94         var col;
95         for (i = 0; i < data.length; i++) {
96             row = data[i];
97             newRow = [];
98             for (var j = 0; j < columnsToExtract.length; j++) {
99                 col = columnNames[columnsToExtract[j]];
100                 if (j === 0) {
101                     if (settings.type === 'timeline') { // first column is date type
102                         newRow.push(extractDate(row[col]));
103                     } else if (settings.type === 'scatter') {
104                         newRow.push(parseFloat(row[col]));
105                     } else { // first column is string type
106                         newRow.push(row[col]);
107                     }
108                 } else { // subsequent columns are of type, number
109                     newRow.push(parseFloat(row[col]));
110                 }
111             }
112             values.push(newRow);
113         }
114         dataTable.setData(values);
115     } else {
116         var seriesNames = {};
117         var seriesNumber = 1;
118         var seriesColumnName = columnNames[settings.seriesColumn];
119         for (i = 0; i < data.length; i++) {
120             if (! seriesNames[data[i][seriesColumnName]]) {
121                 seriesNames[data[i][seriesColumnName]] = seriesNumber;
122                 seriesNumber++;
123             }
124         }
126         $.each(seriesNames, function (seriesName, seriesNumber) {
127             dataTable.addColumn(ColumnType.NUMBER, seriesName);
128         });
130         var valueMap = {};
131         var xValue;
132         var value;
133         var mainAxisName = columnNames[settings.mainAxis];
134         var valueColumnName = columnNames[settings.valueColumn];
135         for (i = 0; i < data.length; i++) {
136             xValue = data[i][mainAxisName];
137             value = valueMap[xValue];
138             if (! value) {
139                 value = [xValue];
140                 valueMap[xValue] = value;
141             }
142             seriesNumber = seriesNames[data[i][seriesColumnName]];
143             value[seriesNumber] = parseFloat(data[i][valueColumnName]);
144         }
146         var values = [];
147         $.each(valueMap, function (index, value) {
148             values.push(value);
149         });
150         dataTable.setData(values);
151     }
153     // draw the chart and return the chart object
154     chart.draw(dataTable, plotSettings);
155     return chart;
158 function drawChart () {
159     currentSettings.width = $('#resizer').width() - 20;
160     currentSettings.height = $('#resizer').height() - 20;
162     // TODO: a better way using .redraw() ?
163     if (currentChart !== null) {
164         currentChart.destroy();
165     }
167     var columnNames = [];
168     $('select[name="chartXAxis"] option').each(function () {
169         columnNames.push(escapeHtml($(this).text()));
170     });
171     try {
172         currentChart = PMA_queryChart(chart_data, columnNames, currentSettings);
173         if (currentChart !== null) {
174             $('#saveChart').attr('href', currentChart.toImageString());
175         }
176     } catch (err) {
177         PMA_ajaxShowMessage(err.message, false);
178     }
181 function getSelectedSeries () {
182     var val = $('select[name="chartSeries"]').val() || [];
183     var ret = [];
184     $.each(val, function (i, v) {
185         ret.push(parseInt(v, 10));
186     });
187     return ret;
190 function onXAxisChange () {
191     var $xAxisSelect = $('select[name="chartXAxis"]');
192     currentSettings.mainAxis = parseInt($xAxisSelect.val(), 10);
193     if (dateTimeCols.indexOf(currentSettings.mainAxis) !== -1) {
194         $('span.span_timeline').show();
195     } else {
196         $('span.span_timeline').hide();
197         if (currentSettings.type === 'timeline') {
198             $('input#radio_line').prop('checked', true);
199             currentSettings.type = 'line';
200         }
201     }
202     if (numericCols.indexOf(currentSettings.mainAxis) !== -1) {
203         $('span.span_scatter').show();
204     } else {
205         $('span.span_scatter').hide();
206         if (currentSettings.type === 'scatter') {
207             $('input#radio_line').prop('checked', true);
208             currentSettings.type = 'line';
209         }
210     }
211     var xaxis_title = $xAxisSelect.children('option:selected').text();
212     $('input[name="xaxis_label"]').val(xaxis_title);
213     currentSettings.xaxisLabel = xaxis_title;
216 function onDataSeriesChange () {
217     var $seriesSelect = $('select[name="chartSeries"]');
218     currentSettings.selectedSeries = getSelectedSeries();
219     var yaxis_title;
220     if (currentSettings.selectedSeries.length === 1) {
221         $('span.span_pie').show();
222         yaxis_title = $seriesSelect.children('option:selected').text();
223     } else {
224         $('span.span_pie').hide();
225         if (currentSettings.type === 'pie') {
226             $('input#radio_line').prop('checked', true);
227             currentSettings.type = 'line';
228         }
229         yaxis_title = PMA_messages.strYValues;
230     }
231     $('input[name="yaxis_label"]').val(yaxis_title);
232     currentSettings.yaxisLabel = yaxis_title;
236  * Unbind all event handlers before tearing down a page
237  */
238 AJAX.registerTeardown('tbl_chart.js', function () {
239     $('input[name="chartType"]').off('click');
240     $('input[name="barStacked"]').off('click');
241     $('input[name="chkAlternative"]').off('click');
242     $('input[name="chartTitle"]').off('focus').off('keyup').off('blur');
243     $('select[name="chartXAxis"]').off('change');
244     $('select[name="chartSeries"]').off('change');
245     $('select[name="chartSeriesColumn"]').off('change');
246     $('select[name="chartValueColumn"]').off('change');
247     $('input[name="xaxis_label"]').off('keyup');
248     $('input[name="yaxis_label"]').off('keyup');
249     $('#resizer').off('resizestop');
250     $('#tblchartform').off('submit');
253 AJAX.registerOnload('tbl_chart.js', function () {
254     // handle manual resize
255     $('#resizer').on('resizestop', function (event, ui) {
256         // make room so that the handle will still appear
257         $('#querychart').height($('#resizer').height() * 0.96);
258         $('#querychart').width($('#resizer').width() * 0.96);
259         if (currentChart !== null) {
260             currentChart.redraw({
261                 resetAxes : true
262             });
263         }
264     });
266     // handle chart type changes
267     $('input[name="chartType"]').click(function () {
268         var type = currentSettings.type = $(this).val();
269         if (type === 'bar' || type === 'column' || type === 'area') {
270             $('span.barStacked').show();
271         } else {
272             $('input[name="barStacked"]').prop('checked', false);
273             $.extend(true, currentSettings, { stackSeries : false });
274             $('span.barStacked').hide();
275         }
276         drawChart();
277     });
279     // handle chosing alternative data format
280     $('input[name="chkAlternative"]').click(function () {
281         var $seriesColumn = $('select[name="chartSeriesColumn"]');
282         var $valueColumn  = $('select[name="chartValueColumn"]');
283         var $chartSeries  = $('select[name="chartSeries"]');
284         if ($(this).is(':checked')) {
285             $seriesColumn.prop('disabled', false);
286             $valueColumn.prop('disabled', false);
287             $chartSeries.prop('disabled', true);
288             currentSettings.seriesColumn = parseInt($seriesColumn.val(), 10);
289             currentSettings.valueColumn = parseInt($valueColumn.val(), 10);
290         } else {
291             $seriesColumn.prop('disabled', true);
292             $valueColumn.prop('disabled', true);
293             $chartSeries.prop('disabled', false);
294             currentSettings.seriesColumn = null;
295             currentSettings.valueColumn = null;
296         }
297         drawChart();
298     });
300     // handle stacking for bar, column and area charts
301     $('input[name="barStacked"]').click(function () {
302         if ($(this).is(':checked')) {
303             $.extend(true, currentSettings, { stackSeries : true });
304         } else {
305             $.extend(true, currentSettings, { stackSeries : false });
306         }
307         drawChart();
308     });
310     // handle changes in chart title
311     $('input[name="chartTitle"]')
312         .focus(function () {
313             temp_chart_title = $(this).val();
314         })
315         .keyup(function () {
316             currentSettings.title = $('input[name="chartTitle"]').val();
317             drawChart();
318         })
319         .blur(function () {
320             if ($(this).val() !== temp_chart_title) {
321                 drawChart();
322             }
323         });
325     // handle changing the x-axis
326     $('select[name="chartXAxis"]').change(function () {
327         onXAxisChange();
328         drawChart();
329     });
331     // handle changing the selected data series
332     $('select[name="chartSeries"]').change(function () {
333         onDataSeriesChange();
334         drawChart();
335     });
337     // handle changing the series column
338     $('select[name="chartSeriesColumn"]').change(function () {
339         currentSettings.seriesColumn = parseInt($(this).val(), 10);
340         drawChart();
341     });
343     // handle changing the value column
344     $('select[name="chartValueColumn"]').change(function () {
345         currentSettings.valueColumn = parseInt($(this).val(), 10);
346         drawChart();
347     });
349     // handle manual changes to the chart x-axis labels
350     $('input[name="xaxis_label"]').keyup(function () {
351         currentSettings.xaxisLabel = $(this).val();
352         drawChart();
353     });
355     // handle manual changes to the chart y-axis labels
356     $('input[name="yaxis_label"]').keyup(function () {
357         currentSettings.yaxisLabel = $(this).val();
358         drawChart();
359     });
361     // handler for ajax form submission
362     $('#tblchartform').submit(function (event) {
363         var $form = $(this);
364         if (codemirror_editor) {
365             $form[0].elements.sql_query.value = codemirror_editor.getValue();
366         }
367         if (!checkSqlQuery($form[0])) {
368             return false;
369         }
371         var $msgbox = PMA_ajaxShowMessage();
372         PMA_prepareForAjaxRequest($form);
373         $.post($form.attr('action'), $form.serialize(), function (data) {
374             if (typeof data !== 'undefined' &&
375                     data.success === true &&
376                     typeof data.chartData !== 'undefined') {
377                 chart_data = JSON.parse(data.chartData);
378                 drawChart();
379                 PMA_ajaxRemoveMessage($msgbox);
380             } else {
381                 PMA_ajaxShowMessage(data.error, false);
382             }
383         }, 'json'); // end $.post()
385         return false;
386     });
388     // from jQuery UI
389     $('#resizer').resizable({
390         minHeight: 240,
391         minWidth: 300
392     })
393         .width($('#div_view_options').width() - 50)
394         .trigger('resizestop');
396     currentSettings = {
397         type : 'line',
398         width : $('#resizer').width() - 20,
399         height : $('#resizer').height() - 20,
400         xaxisLabel : $('input[name="xaxis_label"]').val(),
401         yaxisLabel : $('input[name="yaxis_label"]').val(),
402         title : $('input[name="chartTitle"]').val(),
403         stackSeries : false,
404         mainAxis : parseInt($('select[name="chartXAxis"]').val(), 10),
405         selectedSeries : getSelectedSeries(),
406         seriesColumn : null
407     };
409     var vals = $('input[name="dateTimeCols"]').val().split(' ');
410     $.each(vals, function (i, v) {
411         dateTimeCols.push(parseInt(v, 10));
412     });
414     vals = $('input[name="numericCols"]').val().split(' ');
415     $.each(vals, function (i, v) {
416         numericCols.push(parseInt(v, 10));
417     });
419     onXAxisChange();
420     onDataSeriesChange();
422     $('#tblchartform').submit();