tbl_chart.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. var chart_data = {};
  3. var temp_chart_title;
  4. var currentChart = null;
  5. var currentSettings = null;
  6. function extractDate(dateString) {
  7. var matches, match;
  8. var dateTimeRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/;
  9. var dateRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2}/;
  10. matches = dateTimeRegExp.exec(dateString);
  11. if (matches !== null && matches.length > 0) {
  12. match = matches[0];
  13. return new Date(match.substr(0, 4), match.substr(5, 2), match.substr(8, 2), match.substr(11, 2), match.substr(14, 2), match.substr(17, 2));
  14. } else {
  15. matches = dateRegExp.exec(dateString);
  16. if (matches !== null && matches.length > 0) {
  17. match = matches[0];
  18. return new Date(match.substr(0, 4), match.substr(5, 2), match.substr(8, 2));
  19. }
  20. }
  21. return null;
  22. }
  23. function PMA_queryChart(data, columnNames, settings) {
  24. if ($('#querychart').length === 0) {
  25. return;
  26. }
  27. var jqPlotSettings = {
  28. title : {
  29. text : settings.title,
  30. escapeHtml: true
  31. },
  32. grid : {
  33. drawBorder : false,
  34. shadow : false,
  35. background : 'rgba(0,0,0,0)'
  36. },
  37. legend : {
  38. show : true,
  39. placement : 'outsideGrid',
  40. location : 'e'
  41. },
  42. axes : {
  43. xaxis : {
  44. label : escapeHtml(settings.xaxisLabel)
  45. },
  46. yaxis : {
  47. label : settings.yaxisLabel
  48. }
  49. },
  50. stackSeries : settings.stackSeries
  51. };
  52. // create the chart
  53. var factory = new JQPlotChartFactory();
  54. var chart = factory.createChart(settings.type, "querychart");
  55. // create the data table and add columns
  56. var dataTable = new DataTable();
  57. if (settings.type == 'timeline') {
  58. dataTable.addColumn(ColumnType.DATE, columnNames[settings.mainAxis]);
  59. } else if (settings.type == 'scatter') {
  60. dataTable.addColumn(ColumnType.NUMBER, columnNames[settings.mainAxis]);
  61. } else {
  62. dataTable.addColumn(ColumnType.STRING, columnNames[settings.mainAxis]);
  63. }
  64. $.each(settings.selectedSeries, function (index, element) {
  65. dataTable.addColumn(ColumnType.NUMBER, columnNames[element]);
  66. });
  67. // set data to the data table
  68. var columnsToExtract = [ settings.mainAxis ];
  69. $.each(settings.selectedSeries, function (index, element) {
  70. columnsToExtract.push(element);
  71. });
  72. var values = [], newRow, row, col;
  73. for (var i = 0; i < data.length; i++) {
  74. row = data[i];
  75. newRow = [];
  76. for (var j = 0; j < columnsToExtract.length; j++) {
  77. col = columnNames[columnsToExtract[j]];
  78. if (j === 0) {
  79. if (settings.type == 'timeline') { // first column is date type
  80. newRow.push(extractDate(row[col]));
  81. } else if (settings.type == 'scatter') {
  82. newRow.push(parseFloat(row[col]));
  83. } else { // first column is string type
  84. newRow.push(row[col]);
  85. }
  86. } else { // subsequent columns are of type, number
  87. newRow.push(parseFloat(row[col]));
  88. }
  89. }
  90. values.push(newRow);
  91. }
  92. dataTable.setData(values);
  93. // draw the chart and return the chart object
  94. chart.draw(dataTable, jqPlotSettings);
  95. return chart;
  96. }
  97. function drawChart() {
  98. currentSettings.width = $('#resizer').width() - 20;
  99. currentSettings.height = $('#resizer').height() - 20;
  100. // TODO: a better way using .redraw() ?
  101. if (currentChart !== null) {
  102. currentChart.destroy();
  103. }
  104. var columnNames = [];
  105. $('select[name="chartXAxis"] option').each(function () {
  106. columnNames.push($(this).text());
  107. });
  108. try {
  109. currentChart = PMA_queryChart(chart_data, columnNames, currentSettings);
  110. } catch (err) {
  111. PMA_ajaxShowMessage(err.message, false);
  112. }
  113. }
  114. function getSelectedSeries() {
  115. var val = $('select[name="chartSeries"]').val() || [];
  116. var ret = [];
  117. $.each(val, function (i, v) {
  118. ret.push(parseInt(v, 10));
  119. });
  120. return ret;
  121. }
  122. /**
  123. * Unbind all event handlers before tearing down a page
  124. */
  125. AJAX.registerTeardown('tbl_chart.js', function () {
  126. $('input[name="chartType"]').unbind('click');
  127. $('input[name="barStacked"]').unbind('click');
  128. $('input[name="chartTitle"]').unbind('focus').unbind('keyup').unbind('blur');
  129. $('select[name="chartXAxis"]').unbind('change');
  130. $('select[name="chartSeries"]').unbind('change');
  131. $('input[name="xaxis_label"]').unbind('keyup');
  132. $('input[name="yaxis_label"]').unbind('keyup');
  133. $('#resizer').unbind('resizestop');
  134. });
  135. AJAX.registerOnload('tbl_chart.js', function () {
  136. // from jQuery UI
  137. $('#resizer').resizable({
  138. minHeight: 240,
  139. minWidth: 300
  140. })
  141. .width($('#div_view_options').width() - 50);
  142. $('#resizer').bind('resizestop', function (event, ui) {
  143. // make room so that the handle will still appear
  144. $('#querychart').height($('#resizer').height() * 0.96);
  145. $('#querychart').width($('#resizer').width() * 0.96);
  146. currentChart.redraw({
  147. resetAxes : true
  148. });
  149. });
  150. currentSettings = {
  151. type : 'line',
  152. width : $('#resizer').width() - 20,
  153. height : $('#resizer').height() - 20,
  154. xaxisLabel : $('input[name="xaxis_label"]').val(),
  155. yaxisLabel : $('input[name="yaxis_label"]').val(),
  156. title : $('input[name="chartTitle"]').val(),
  157. stackSeries : false,
  158. mainAxis : parseInt($('select[name="chartXAxis"]').val(), 10),
  159. selectedSeries : getSelectedSeries()
  160. };
  161. // handle chart type changes
  162. $('input[name="chartType"]').click(function () {
  163. var type = currentSettings.type = $(this).val();
  164. if (type == 'bar' || type == 'column' || type == 'area') {
  165. $('span.barStacked').show();
  166. } else {
  167. $('input[name="barStacked"]').attr('checked', false);
  168. $.extend(true, currentSettings, {stackSeries : false});
  169. $('span.barStacked').hide();
  170. }
  171. drawChart();
  172. });
  173. // handle stacking for bar, column and area charts
  174. $('input[name="barStacked"]').click(function () {
  175. if ($(this).is(':checked')) {
  176. $.extend(true, currentSettings, {stackSeries : true});
  177. } else {
  178. $.extend(true, currentSettings, {stackSeries : false});
  179. }
  180. drawChart();
  181. });
  182. // handle changes in chart title
  183. $('input[name="chartTitle"]')
  184. .focus(function () {
  185. temp_chart_title = $(this).val();
  186. })
  187. .keyup(function () {
  188. var title = $(this).val();
  189. if (title.length === 0) {
  190. title = ' ';
  191. }
  192. currentSettings.title = $('input[name="chartTitle"]').val();
  193. drawChart();
  194. })
  195. .blur(function () {
  196. if ($(this).val() != temp_chart_title) {
  197. drawChart();
  198. }
  199. });
  200. var dateTimeCols = [];
  201. var vals = $('input[name="dateTimeCols"]').val().split(' ');
  202. $.each(vals, function (i, v) {
  203. dateTimeCols.push(parseInt(v, 10));
  204. });
  205. var numericCols = [];
  206. var vals = $('input[name="numericCols"]').val().split(' ');
  207. $.each(vals, function (i, v) {
  208. numericCols.push(parseInt(v, 10));
  209. });
  210. // handle changing the x-axis
  211. $('select[name="chartXAxis"]').change(function () {
  212. currentSettings.mainAxis = parseInt($(this).val(), 10);
  213. if (dateTimeCols.indexOf(currentSettings.mainAxis) != -1) {
  214. $('span.span_timeline').show();
  215. } else {
  216. $('span.span_timeline').hide();
  217. if (currentSettings.type == 'timeline') {
  218. $('input#radio_line').prop('checked', true);
  219. currentSettings.type = 'line';
  220. }
  221. }
  222. if (numericCols.indexOf(currentSettings.mainAxis) != -1) {
  223. $('span.span_scatter').show();
  224. } else {
  225. $('span.span_scatter').hide();
  226. if (currentSettings.type == 'scatter') {
  227. $('input#radio_line').prop('checked', true);
  228. currentSettings.type = 'line';
  229. }
  230. }
  231. var xaxis_title = $(this).children('option:selected').text();
  232. $('input[name="xaxis_label"]').val(xaxis_title);
  233. currentSettings.xaxisLabel = xaxis_title;
  234. drawChart();
  235. });
  236. // handle changing the selected data series
  237. $('select[name="chartSeries"]').change(function () {
  238. currentSettings.selectedSeries = getSelectedSeries();
  239. var yaxis_title;
  240. if (currentSettings.selectedSeries.length == 1) {
  241. $('span.span_pie').show();
  242. yaxis_title = $(this).children('option:selected').text();
  243. } else {
  244. $('span.span_pie').hide();
  245. if (currentSettings.type == 'pie') {
  246. $('input#radio_line').prop('checked', true);
  247. currentSettings.type = 'line';
  248. }
  249. yaxis_title = PMA_messages.strYValues;
  250. }
  251. $('input[name="yaxis_label"]').val(yaxis_title);
  252. currentSettings.yaxisLabel = yaxis_title;
  253. drawChart();
  254. });
  255. // handle manual changes to the chart axis labels
  256. $('input[name="xaxis_label"]').keyup(function () {
  257. currentSettings.xaxisLabel = $(this).val();
  258. drawChart();
  259. });
  260. $('input[name="yaxis_label"]').keyup(function () {
  261. currentSettings.yaxisLabel = $(this).val();
  262. drawChart();
  263. });
  264. $("#tblchartform").submit();
  265. });
  266. /**
  267. * Ajax Event handler for 'Go' button click
  268. *
  269. */
  270. $("#tblchartform").live('submit', function (event) {
  271. if (!checkFormElementInRange(this, 'session_max_rows', PMA_messages.strNotValidRowNumber, 1) ||
  272. !checkFormElementInRange(this, 'pos', PMA_messages.strNotValidRowNumber, 0 - 1)
  273. ) {
  274. return false;
  275. }
  276. var $form = $(this);
  277. if (codemirror_editor) {
  278. $form[0].elements['sql_query'].value = codemirror_editor.getValue();
  279. }
  280. if (!checkSqlQuery($form[0])) {
  281. return false;
  282. }
  283. // remove any div containing a previous error message
  284. $('.error').remove();
  285. var $msgbox = PMA_ajaxShowMessage();
  286. PMA_prepareForAjaxRequest($form);
  287. $.post($form.attr('action'), $form.serialize(), function (data) {
  288. if (data.success === true) {
  289. $('.success').fadeOut();
  290. if (typeof data.chartData != 'undefined') {
  291. chart_data = jQuery.parseJSON(data.chartData);
  292. drawChart();
  293. $('div#querychart').height($('div#resizer').height() * 0.96);
  294. $('div#querychart').width($('div#resizer').width() * 0.96);
  295. currentChart.redraw({
  296. resetAxes : true
  297. });
  298. $('#querychart').show();
  299. }
  300. } else {
  301. PMA_ajaxRemoveMessage($msgbox);
  302. PMA_ajaxShowMessage(data.error, false);
  303. }
  304. PMA_ajaxRemoveMessage($msgbox);
  305. }, "json"); // end $.post()
  306. return false;
  307. }); // end