Translated using Weblate (Bengali)
[phpmyadmin.git] / js / tbl_zoom_plot_jqplot.js
bloba99bf6cefe983b3584cd543b14cffe6d4520622d
1 // TODO: change the axis
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4  ** @fileoverview JavaScript functions used on tbl_select.php
5  **
6  ** @requires    jQuery
7  ** @requires    js/functions.js
8  **/
11 /**
12  **  Display Help/Info
13  **/
14 function displayHelp() {
15     $('<div />')
16         .append(PMA_messages.strDisplayHelp)
17         .appendTo('#page_content')
18         .dialog({
19             width: 450,
20             height: 'auto',
21             title: PMA_messages.strHelpTitle
22         });
23     return false;
26 /**
27  ** Extend the array object for max function
28  ** @param array
29  **/
30 Array.max = function (array) {
31     return Math.max.apply(Math, array);
34 /**
35  ** Extend the array object for min function
36  ** @param array
37  **/
38 Array.min = function (array) {
39     return Math.min.apply(Math, array);
42 /**
43  ** Checks if a string contains only numeric value
44  ** @param n: String (to be checked)
45  **/
46 function isNumeric(n) {
47     return !isNaN(parseFloat(n)) && isFinite(n);
50 /**
51  ** Checks if an object is empty
52  ** @param n: Object (to be checked)
53  **/
54 function isEmpty(obj) {
55     var name;
56     for (name in obj) {
57         return false;
58     }
59     return true;
62 /**
63  ** Converts a date/time into timestamp
64  ** @param val  String Date
65  ** @param type Sring  Field type(datetime/timestamp/time/date)
66  **/
67 function getTimeStamp(val, type) {
68     if (type.toString().search(/datetime/i) != -1 ||
69         type.toString().search(/timestamp/i) != -1
70     ) {
71         return $.datepicker.parseDateTime('yy-mm-dd', 'HH:mm:ss', val);
72     }
73     else if (type.toString().search(/time/i) != -1) {
74         return $.datepicker.parseDateTime('yy-mm-dd', 'HH:mm:ss', '1970-01-01 ' + val);
75     }
76     else if (type.toString().search(/date/i) != -1) {
77         return $.datepicker.parseDate('yy-mm-dd', val);
78     }
81 /**
82  ** Classifies the field type into numeric,timeseries or text
83  ** @param field: field type (as in database structure)
84  **/
85 function getType(field) {
86     if (field.toString().search(/int/i) != -1 ||
87         field.toString().search(/decimal/i) != -1 ||
88         field.toString().search(/year/i) != -1
89     ) {
90         return 'numeric';
91     } else if (field.toString().search(/time/i) != -1 ||
92         field.toString().search(/date/i) != -1
93     ) {
94         return 'time';
95     } else {
96         return 'text';
97     }
101  ** Scrolls the view to the display section
102  **/
103 function scrollToChart() {
104     var x = $('#dataDisplay').offset().top - 100; // 100 provides buffer in viewport
105     $('html,body').animate({scrollTop: x}, 500);
109  * Unbind all event handlers before tearing down a page
110  */
111 AJAX.registerTeardown('tbl_zoom_plot_jqplot.js', function () {
112     $('#tableid_0').unbind('change');
113     $('#tableid_1').unbind('change');
114     $('#tableid_2').unbind('change');
115     $('#tableid_3').unbind('change');
116     $('#inputFormSubmitId').unbind('click');
117     $('#togglesearchformlink').unbind('click');
118     $(document).off('keydown', "#dataDisplay :input");
119     $('button.button-reset').unbind('click');
120     $('div#resizer').unbind('resizestop');
121     $('div#querychart').unbind('jqplotDataClick');
124 AJAX.registerOnload('tbl_zoom_plot_jqplot.js', function () {
125     var cursorMode = ($("input[name='mode']:checked").val() == 'edit') ? 'crosshair' : 'pointer';
126     var currentChart = null;
127     var searchedDataKey = null;
128     var xLabel = $('#tableid_0').val();
129     var yLabel = $('#tableid_1').val();
130     // will be updated via Ajax
131     var xType = $('#types_0').val();
132     var yType = $('#types_1').val();
133     var dataLabel = $('#dataLabel').val();
134     var lastX;
135     var lastY;
136     var zoomRatio = 1;
139     // Get query result
140     var searchedData;
141     try {
142         searchedData = JSON.parse($('#querydata').html());
143     } catch (err) {
144         searchedData = null;
145     }
147     /**
148      ** Input form submit on field change
149      **/
151     // first column choice corresponds to the X axis
152     $('#tableid_0').change(function () {
153         //AJAX request for field type, collation, operators, and value field
154         $.post('tbl_zoom_select.php', {
155             'ajax_request' : true,
156             'change_tbl_info' : true,
157             'server' : PMA_commonParams.get('server'),
158             'db' : PMA_commonParams.get('db'),
159             'table' : PMA_commonParams.get('table'),
160             'field' : $('#tableid_0').val(),
161             'it' : 0,
162             'token' : PMA_commonParams.get('token')
163         }, function (data) {
164             $('#tableFieldsId').find('tr:eq(1) td:eq(0)').html(data.field_type);
165             $('#tableFieldsId').find('tr:eq(1) td:eq(1)').html(data.field_collation);
166             $('#tableFieldsId').find('tr:eq(1) td:eq(2)').html(data.field_operators);
167             $('#tableFieldsId').find('tr:eq(1) td:eq(3)').html(data.field_value);
168             xLabel = $('#tableid_0').val();
169             $('#types_0').val(data.field_type);
170             xType = data.field_type;
171             $('#collations_0').val(data.field_collations);
172             addDateTimePicker();
173         });
174     });
176     // second column choice corresponds to the Y axis
177     $('#tableid_1').change(function () {
178         //AJAX request for field type, collation, operators, and value field
179         $.post('tbl_zoom_select.php', {
180             'ajax_request' : true,
181             'change_tbl_info' : true,
182             'server' : PMA_commonParams.get('server'),
183             'db' : PMA_commonParams.get('db'),
184             'table' : PMA_commonParams.get('table'),
185             'field' : $('#tableid_1').val(),
186             'it' : 1,
187             'token' : PMA_commonParams.get('token')
188         }, function (data) {
189             $('#tableFieldsId').find('tr:eq(3) td:eq(0)').html(data.field_type);
190             $('#tableFieldsId').find('tr:eq(3) td:eq(1)').html(data.field_collation);
191             $('#tableFieldsId').find('tr:eq(3) td:eq(2)').html(data.field_operators);
192             $('#tableFieldsId').find('tr:eq(3) td:eq(3)').html(data.field_value);
193             yLabel = $('#tableid_1').val();
194             $('#types_1').val(data.field_type);
195             yType = data.field_type;
196             $('#collations_1').val(data.field_collations);
197             addDateTimePicker();
198         });
199     });
201     $('#tableid_2').change(function () {
202         //AJAX request for field type, collation, operators, and value field
203         $.post('tbl_zoom_select.php', {
204             'ajax_request' : true,
205             'change_tbl_info' : true,
206             'server' : PMA_commonParams.get('server'),
207             'db' : PMA_commonParams.get('db'),
208             'table' : PMA_commonParams.get('table'),
209             'field' : $('#tableid_2').val(),
210             'it' : 2,
211             'token' : PMA_commonParams.get('token')
212         }, function (data) {
213             $('#tableFieldsId').find('tr:eq(6) td:eq(0)').html(data.field_type);
214             $('#tableFieldsId').find('tr:eq(6) td:eq(1)').html(data.field_collation);
215             $('#tableFieldsId').find('tr:eq(6) td:eq(2)').html(data.field_operators);
216             $('#tableFieldsId').find('tr:eq(6) td:eq(3)').html(data.field_value);
217             $('#types_2').val(data.field_type);
218             $('#collations_2').val(data.field_collations);
219             addDateTimePicker();
220         });
221     });
223     $('#tableid_3').change(function () {
224         //AJAX request for field type, collation, operators, and value field
225         $.post('tbl_zoom_select.php', {
226             'ajax_request' : true,
227             'change_tbl_info' : true,
228             'server' : PMA_commonParams.get('server'),
229             'db' : PMA_commonParams.get('db'),
230             'table' : PMA_commonParams.get('table'),
231             'field' : $('#tableid_3').val(),
232             'it' : 3,
233             'token' : PMA_commonParams.get('token')
234         }, function (data) {
235             $('#tableFieldsId').find('tr:eq(8) td:eq(0)').html(data.field_type);
236             $('#tableFieldsId').find('tr:eq(8) td:eq(1)').html(data.field_collation);
237             $('#tableFieldsId').find('tr:eq(8) td:eq(2)').html(data.field_operators);
238             $('#tableFieldsId').find('tr:eq(8) td:eq(3)').html(data.field_value);
239             $('#types_3').val(data.field_type);
240             $('#collations_3').val(data.field_collations);
241             addDateTimePicker();
242         });
243     });
245     /**
246      * Input form validation
247      **/
248     $('#inputFormSubmitId').click(function () {
249         if ($('#tableid_0').get(0).selectedIndex === 0 || $('#tableid_1').get(0).selectedIndex === 0) {
250             PMA_ajaxShowMessage(PMA_messages.strInputNull);
251         } else if (xLabel == yLabel) {
252             PMA_ajaxShowMessage(PMA_messages.strSameInputs);
253         }
254     });
256     /**
257       ** Prepare a div containing a link, otherwise it's incorrectly displayed
258       ** after a couple of clicks
259       **/
260     $('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
261         .insertAfter('#zoom_search_form')
262         // don't show it until we have results on-screen
263         .hide();
265     $('#togglesearchformlink')
266         .html(PMA_messages.strShowSearchCriteria)
267         .bind('click', function () {
268             var $link = $(this);
269             $('#zoom_search_form').slideToggle();
270             if ($link.text() == PMA_messages.strHideSearchCriteria) {
271                 $link.text(PMA_messages.strShowSearchCriteria);
272             } else {
273                 $link.text(PMA_messages.strHideSearchCriteria);
274             }
275             // avoid default click action
276             return false;
277         });
279     /**
280      ** Set dialog properties for the data display form
281      **/
282     var buttonOptions = {};
283     /*
284      * Handle saving of a row in the editor
285      */
286     buttonOptions[PMA_messages.strSave] = function () {
287         //Find changed values by comparing form values with selectedRow Object
288         var newValues = {};//Stores the values changed from original
289         var sqlTypes = {};
290         var it = 0;
291         var xChange = false;
292         var yChange = false;
293         var key;
294         var tempGetVal = function () {
295             return $(this).val();
296         };
297         for (key in selectedRow) {
298             var oldVal = selectedRow[key];
299             var newVal = ($('#edit_fields_null_id_' + it).prop('checked')) ? null : $('#edit_fieldID_' + it).val();
300             if (newVal instanceof Array) { // when the column is of type SET
301                 newVal =  $('#edit_fieldID_' + it).map(tempGetVal).get().join(",");
302             }
303             if (oldVal != newVal) {
304                 selectedRow[key] = newVal;
305                 newValues[key] = newVal;
306                 if (key == xLabel) {
307                     xChange = true;
308                     searchedData[searchedDataKey][xLabel] = newVal;
309                 } else if (key == yLabel) {
310                     yChange = true;
311                     searchedData[searchedDataKey][yLabel] = newVal;
312                 }
313             }
314             var $input = $('#edit_fieldID_' + it);
315             if ($input.hasClass('bit')) {
316                 sqlTypes[key] = 'bit';
317             } else {
318                 sqlTypes[key] = null;
319             }
320             it++;
321         } //End data update
323         //Update the chart series and replot
324         if (xChange || yChange) {
325             //Logic similar to plot generation, replot only if xAxis changes or yAxis changes.
326             //Code includes a lot of checks so as to replot only when necessary
327             if (xChange) {
328                 xCord[searchedDataKey] = selectedRow[xLabel];
329                 // [searchedDataKey][0] contains the x value
330                 if (xType == 'numeric') {
331                     series[0][searchedDataKey][0] = selectedRow[xLabel];
332                 } else if (xType == 'time') {
333                     series[0][searchedDataKey][0] =
334                         getTimeStamp(selectedRow[xLabel], $('#types_0').val());
335                 } else {
336                     series[0][searchedDataKey][0] = '';
337                     // TODO: text values
338                 }
339                 currentChart.series[0].data = series[0];
340                 // TODO: axis changing
341                 currentChart.replot();
343             }
344             if (yChange) {
345                 yCord[searchedDataKey] = selectedRow[yLabel];
346                 // [searchedDataKey][1] contains the y value
347                 if (yType == 'numeric') {
348                     series[0][searchedDataKey][1] = selectedRow[yLabel];
349                 } else if (yType == 'time') {
350                     series[0][searchedDataKey][1] =
351                         getTimeStamp(selectedRow[yLabel], $('#types_1').val());
352                 } else {
353                     series[0][searchedDataKey][1] = '';
354                     // TODO: text values
355                 }
356                 currentChart.series[0].data = series[0];
357                 // TODO: axis changing
358                 currentChart.replot();
359             }
360         } //End plot update
362         //Generate SQL query for update
363         if (!isEmpty(newValues)) {
364             var sql_query = 'UPDATE `' + PMA_commonParams.get('table') + '` SET ';
365             for (key in newValues) {
366                 sql_query += '`' + key + '`=';
367                 var value = newValues[key];
369                 // null
370                 if (value === null) {
371                     sql_query += 'NULL, ';
373                 // empty
374                 } else if ($.trim(value) === '') {
375                     sql_query += "'', ";
377                 // other
378                 } else {
379                     // type explicitly identified
380                     if (sqlTypes[key] !== null) {
381                         if (sqlTypes[key] == 'bit') {
382                             sql_query += "b'" + value + "', ";
383                         }
384                     // type not explicitly identified
385                     } else {
386                         if (!isNumeric(value)) {
387                             sql_query += "'" + value + "', ";
388                         } else {
389                             sql_query += value + ', ';
390                         }
391                     }
392                 }
393             }
394             // remove two extraneous characters ', '
395             sql_query = sql_query.substring(0, sql_query.length - 2);
396             sql_query += ' WHERE ' + PMA_urldecode(searchedData[searchedDataKey].where_clause);
398             //Post SQL query to sql.php
399             $.post('sql.php', {
400                     'token' : PMA_commonParams.get('token'),
401                     'server' : PMA_commonParams.get('server'),
402                     'db' : PMA_commonParams.get('db'),
403                     'ajax_request' : true,
404                     'sql_query' : sql_query,
405                     'inline_edit' : false
406                 }, function (data) {
407                     if (typeof data !== 'undefined' && data.success === true) {
408                         $('#sqlqueryresultsouter').html(data.sql_query);
409                         PMA_highlightSQL($('#sqlqueryresultsouter'));
410                     } else {
411                         PMA_ajaxShowMessage(data.error, false);
412                     }
413                 }); //End $.post
414         }//End database update
415         $("#dataDisplay").dialog('close');
416     };
417     buttonOptions[PMA_messages.strCancel] = function () {
418         $(this).dialog('close');
419     };
420     $("#dataDisplay").dialog({
421         autoOpen: false,
422         title: PMA_messages.strDataPointContent,
423         modal: true,
424         buttons: buttonOptions,
425         width: $('#dataDisplay').width() + 80,
426         open: function () {
427             $(this).find('input[type=checkbox]').css('margin', '0.5em');
428         }
429     });
430     /**
431      * Attach Ajax event handlers for input fields
432      * in the dialog. Used to submit the Ajax
433      * request when the ENTER key is pressed.
434      */
435     $(document).on('keydown', "#dataDisplay :input", function (e) {
436         if (e.which === 13) { // 13 is the ENTER key
437             e.preventDefault();
438             if (typeof buttonOptions[PMA_messages.strSave] === 'function') {
439                 buttonOptions[PMA_messages.strSave].call();
440             }
441         }
442     });
445     /*
446      * Generate plot using jqplot
447      */
449     if (searchedData !== null) {
450         $('#zoom_search_form')
451          .slideToggle()
452          .hide();
453         $('#togglesearchformlink')
454          .text(PMA_messages.strShowSearchCriteria);
455         $('#togglesearchformdiv').show();
456         var selectedRow;
457         var colorCodes = ['#FF0000', '#00FFFF', '#0000FF', '#0000A0', '#FF0080', '#800080', '#FFFF00', '#00FF00', '#FF00FF'];
458         var series = [];
459         var xCord = [];
460         var yCord = [];
461         var tempX, tempY;
462         var it = 0;
463         var xMax; // xAxis extreme max
464         var xMin; // xAxis extreme min
465         var yMax; // yAxis extreme max
466         var yMin; // yAxis extreme min
467         var xVal;
468         var yVal;
469         var format;
471         var options = {
472             series: [
473                 // for a scatter plot
474                 { showLine: false }
475             ],
476             grid: {
477                 drawBorder: false,
478                 shadow: false,
479                 background: 'rgba(0,0,0,0)'
480             },
481             axes: {
482                 xaxis: {
483                     label: $('#tableid_0').val(),
484                     labelRenderer: $.jqplot.CanvasAxisLabelRenderer
485                 },
486                 yaxis: {
487                     label: $('#tableid_1').val(),
488                     labelRenderer: $.jqplot.CanvasAxisLabelRenderer
489                 }
490             },
491             highlighter: {
492                 show: true,
493                 tooltipAxes: 'y',
494                 yvalues: 2,
495                 // hide the first y value
496                 formatString: '<span class="hide">%s</span>%s'
497             },
498             cursor: {
499                 show: true,
500                 zoom: true,
501                 showTooltip: false
502             }
503         };
505         // If data label is not set, do not show tooltips
506         if (dataLabel === '') {
507             options.highlighter.show = false;
508         }
510         // Classify types as either numeric,time,text
511         xType = getType(xType);
512         yType = getType(yType);
514         // could have multiple series but we'll have just one
515         series[0] = [];
517         if (xType == 'time') {
518             var originalXType = $('#types_0').val();
519             if (originalXType == 'date') {
520                 format = '%Y-%m-%d';
521             }
522             // TODO: does not seem to work
523             //else if (originalXType == 'time') {
524               //  format = '%H:%M';
525             //} else {
526             //    format = '%Y-%m-%d %H:%M';
527             //}
528             $.extend(options.axes.xaxis, {
529                 renderer: $.jqplot.DateAxisRenderer,
530                 tickOptions: {
531                     formatString: format
532                 }
533             });
534         }
535         if (yType == 'time') {
536             var originalYType = $('#types_1').val();
537             if (originalYType == 'date') {
538                 format = '%Y-%m-%d';
539             }
540             $.extend(options.axes.yaxis, {
541                 renderer: $.jqplot.DateAxisRenderer,
542                 tickOptions: {
543                     formatString: format
544                 }
545             });
546         }
548         $.each(searchedData, function (key, value) {
549             if (xType == 'numeric') {
550                 xVal = parseFloat(value[xLabel]);
551             }
552             if (xType == 'time') {
553                 xVal = getTimeStamp(value[xLabel], originalXType);
554             }
555             if (yType == 'numeric') {
556                 yVal = parseFloat(value[yLabel]);
557             }
558             if (yType == 'time') {
559                 yVal = getTimeStamp(value[yLabel], originalYType);
560             }
561             series[0].push([
562                 xVal,
563                 yVal,
564                 // extra Y values
565                 value[dataLabel], // for highlighter
566                                   // (may set an undefined value)
567                 value.where_clause, // for click on point
568                 key               // key from searchedData
569             ]);
570         });
572         // under IE 8, the initial display is mangled; after a manual
573         // resizing, it's ok
574         // under IE 9, everything is fine
575         currentChart = $.jqplot('querychart', series, options);
576         currentChart.resetZoom();
578         $('button.button-reset').click(function (event) {
579             event.preventDefault();
580             currentChart.resetZoom();
581         });
583         $('div#resizer').resizable();
584         $('div#resizer').bind('resizestop', function (event, ui) {
585             // make room so that the handle will still appear
586             $('div#querychart').height($('div#resizer').height() * 0.96);
587             $('div#querychart').width($('div#resizer').width() * 0.96);
588             currentChart.replot({resetAxes: true});
589         });
591         $('div#querychart').bind('jqplotDataClick',
592             function (event, seriesIndex, pointIndex, data) {
593                 searchedDataKey = data[4]; // key from searchedData (global)
594                 var field_id = 0;
595                 var post_params = {
596                     'ajax_request' : true,
597                     'get_data_row' : true,
598                     'server' : PMA_commonParams.get('server'),
599                     'db' : PMA_commonParams.get('db'),
600                     'table' : PMA_commonParams.get('table'),
601                     'where_clause' : data[3],
602                     'token' : PMA_commonParams.get('token')
603                 };
605                 $.post('tbl_zoom_select.php', post_params, function (data) {
606                     // Row is contained in data.row_info,
607                     // now fill the displayResultForm with row values
608                     var key;
609                     for (key in data.row_info) {
610                         var $field = $('#edit_fieldID_' + field_id);
611                         var $field_null = $('#edit_fields_null_id_' + field_id);
612                         if (data.row_info[key] === null) {
613                             $field_null.prop('checked', true);
614                             $field.val('');
615                         } else {
616                             $field_null.prop('checked', false);
617                             if ($field.attr('multiple')) { // when the column is of type SET
618                                 $field.val(data.row_info[key].split(','));
619                             } else {
620                                 $field.val(data.row_info[key]);
621                             }
622                         }
623                         field_id++;
624                     }
625                     selectedRow = data.row_info;
626                 });
628                 $("#dataDisplay").dialog("open");
629             }
630         );
631     }