1 /* vim: set expandtab sw=4 ts=4 sts=4: */
6 var currentChart = null;
7 var currentSettings = null;
12 function extractDate(dateString) {
14 var dateTimeRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/;
15 var dateRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2}/;
17 matches = dateTimeRegExp.exec(dateString);
18 if (matches !== null && matches.length > 0) {
20 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 matches = dateRegExp.exec(dateString);
23 if (matches !== null && matches.length > 0) {
25 return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2));
31 function PMA_queryChart(data, columnNames, settings) {
32 if ($('#querychart').length === 0) {
38 text : settings.title,
44 background : 'rgba(0,0,0,0)'
48 placement : 'outsideGrid',
53 label : escapeHtml(settings.xaxisLabel)
56 label : settings.yaxisLabel
59 stackSeries : settings.stackSeries
63 var factory = new JQPlotChartFactory();
64 var chart = factory.createChart(settings.type, "querychart");
66 // create the data table and add columns
67 var dataTable = new DataTable();
68 if (settings.type == 'timeline') {
69 dataTable.addColumn(ColumnType.DATE, columnNames[settings.mainAxis]);
70 } else if (settings.type == 'scatter') {
71 dataTable.addColumn(ColumnType.NUMBER, columnNames[settings.mainAxis]);
73 dataTable.addColumn(ColumnType.STRING, columnNames[settings.mainAxis]);
77 if (settings.seriesColumn === null) {
78 $.each(settings.selectedSeries, function (index, element) {
79 dataTable.addColumn(ColumnType.NUMBER, columnNames[element]);
82 // set data to the data table
83 var columnsToExtract = [ settings.mainAxis ];
84 $.each(settings.selectedSeries, function (index, element) {
85 columnsToExtract.push(element);
87 var values = [], newRow, row, col;
88 for (i = 0; i < data.length; i++) {
91 for (var j = 0; j < columnsToExtract.length; j++) {
92 col = columnNames[columnsToExtract[j]];
94 if (settings.type == 'timeline') { // first column is date type
95 newRow.push(extractDate(row[col]));
96 } else if (settings.type == 'scatter') {
97 newRow.push(parseFloat(row[col]));
98 } else { // first column is string type
99 newRow.push(row[col]);
101 } else { // subsequent columns are of type, number
102 newRow.push(parseFloat(row[col]));
107 dataTable.setData(values);
109 var seriesNames = {}, seriesNumber = 1;
110 var seriesColumnName = columnNames[settings.seriesColumn];
111 for (i = 0; i < data.length; i++) {
112 if (! seriesNames[data[i][seriesColumnName]]) {
113 seriesNames[data[i][seriesColumnName]] = seriesNumber;
118 $.each(seriesNames, function (seriesName, seriesNumber) {
119 dataTable.addColumn(ColumnType.NUMBER, seriesName);
122 var valueMap = {}, xValue, value;
123 var mainAxisName = columnNames[settings.mainAxis];
124 var valueColumnName = columnNames[settings.valueColumn];
125 for (i = 0; i < data.length; i++) {
126 xValue = data[i][mainAxisName];
127 value = valueMap[xValue];
130 valueMap[xValue] = value;
132 seriesNumber = seriesNames[data[i][seriesColumnName]];
133 value[seriesNumber] = parseFloat(data[i][valueColumnName]);
137 $.each(valueMap, function(index, value) {
140 dataTable.setData(values);
143 // draw the chart and return the chart object
144 chart.draw(dataTable, plotSettings);
148 function drawChart() {
149 currentSettings.width = $('#resizer').width() - 20;
150 currentSettings.height = $('#resizer').height() - 20;
152 // TODO: a better way using .redraw() ?
153 if (currentChart !== null) {
154 currentChart.destroy();
157 var columnNames = [];
158 $('select[name="chartXAxis"] option').each(function () {
159 columnNames.push($(this).text());
162 currentChart = PMA_queryChart(chart_data, columnNames, currentSettings);
163 if (currentChart != null) {
164 $('#saveChart').attr('href', currentChart.toImageString());
167 PMA_ajaxShowMessage(err.message, false);
171 function getSelectedSeries() {
172 var val = $('select[name="chartSeries"]').val() || [];
174 $.each(val, function (i, v) {
175 ret.push(parseInt(v, 10));
180 function onXAxisChange() {
181 var $xAxisSelect = $('select[name="chartXAxis"]');
182 currentSettings.mainAxis = parseInt($xAxisSelect.val(), 10);
183 if (dateTimeCols.indexOf(currentSettings.mainAxis) != -1) {
184 $('span.span_timeline').show();
186 $('span.span_timeline').hide();
187 if (currentSettings.type == 'timeline') {
188 $('input#radio_line').prop('checked', true);
189 currentSettings.type = 'line';
192 if (numericCols.indexOf(currentSettings.mainAxis) != -1) {
193 $('span.span_scatter').show();
195 $('span.span_scatter').hide();
196 if (currentSettings.type == 'scatter') {
197 $('input#radio_line').prop('checked', true);
198 currentSettings.type = 'line';
201 var xaxis_title = $xAxisSelect.children('option:selected').text();
202 $('input[name="xaxis_label"]').val(xaxis_title);
203 currentSettings.xaxisLabel = xaxis_title;
206 function onDataSeriesChange() {
207 var $seriesSelect = $('select[name="chartSeries"]');
208 currentSettings.selectedSeries = getSelectedSeries();
210 if (currentSettings.selectedSeries.length == 1) {
211 $('span.span_pie').show();
212 yaxis_title = $seriesSelect.children('option:selected').text();
214 $('span.span_pie').hide();
215 if (currentSettings.type == 'pie') {
216 $('input#radio_line').prop('checked', true);
217 currentSettings.type = 'line';
219 yaxis_title = PMA_messages.strYValues;
221 $('input[name="yaxis_label"]').val(yaxis_title);
222 currentSettings.yaxisLabel = yaxis_title;
226 * Unbind all event handlers before tearing down a page
228 AJAX.registerTeardown('tbl_chart.js', function () {
229 $('input[name="chartType"]').unbind('click');
230 $('input[name="barStacked"]').unbind('click');
231 $('input[name="chkAlternative"]').unbind('click');
232 $('input[name="chartTitle"]').unbind('focus').unbind('keyup').unbind('blur');
233 $('select[name="chartXAxis"]').unbind('change');
234 $('select[name="chartSeries"]').unbind('change');
235 $('select[name="chartSeriesColumn"]').unbind('change');
236 $('select[name="chartValueColumn"]').unbind('change');
237 $('input[name="xaxis_label"]').unbind('keyup');
238 $('input[name="yaxis_label"]').unbind('keyup');
239 $('#resizer').unbind('resizestop');
240 $('#tblchartform').unbind('submit');
243 AJAX.registerOnload('tbl_chart.js', function () {
245 // handle manual resize
246 $('#resizer').bind('resizestop', function (event, ui) {
247 // make room so that the handle will still appear
248 $('#querychart').height($('#resizer').height() * 0.96);
249 $('#querychart').width($('#resizer').width() * 0.96);
250 if (currentChart !== null) {
251 currentChart.redraw({
257 // handle chart type changes
258 $('input[name="chartType"]').click(function () {
259 var type = currentSettings.type = $(this).val();
260 if (type == 'bar' || type == 'column' || type == 'area') {
261 $('span.barStacked').show();
263 $('input[name="barStacked"]').prop('checked', false);
264 $.extend(true, currentSettings, {stackSeries : false});
265 $('span.barStacked').hide();
270 // handle chosing alternative data format
271 $('input[name="chkAlternative"]').click(function () {
272 var $seriesColumn = $('select[name="chartSeriesColumn"]');
273 var $valueColumn = $('select[name="chartValueColumn"]');
274 var $chartSeries = $('select[name="chartSeries"]');
275 if ($(this).is(':checked')) {
276 $seriesColumn.prop('disabled', false);
277 $valueColumn.prop('disabled', false);
278 $chartSeries.prop('disabled', true);
279 currentSettings.seriesColumn = parseInt($seriesColumn.val(), 10);
280 currentSettings.valueColumn = parseInt($valueColumn.val(), 10);
282 $seriesColumn.prop('disabled', true);
283 $valueColumn.prop('disabled', true);
284 $chartSeries.prop('disabled', false);
285 currentSettings.seriesColumn = null;
286 currentSettings.valueColumn = null;
291 // handle stacking for bar, column and area charts
292 $('input[name="barStacked"]').click(function () {
293 if ($(this).is(':checked')) {
294 $.extend(true, currentSettings, {stackSeries : true});
296 $.extend(true, currentSettings, {stackSeries : false});
301 // handle changes in chart title
302 $('input[name="chartTitle"]')
304 temp_chart_title = $(this).val();
307 var title = $(this).val();
308 if (title.length === 0) {
311 currentSettings.title = $('input[name="chartTitle"]').val();
315 if ($(this).val() != temp_chart_title) {
320 // handle changing the x-axis
321 $('select[name="chartXAxis"]').change(function () {
326 // handle changing the selected data series
327 $('select[name="chartSeries"]').change(function () {
328 onDataSeriesChange();
332 // handle changing the series column
333 $('select[name="chartSeriesColumn"]').change(function () {
334 currentSettings.seriesColumn = parseInt($(this).val(), 10);
338 // handle changing the value column
339 $('select[name="chartValueColumn"]').change(function () {
340 currentSettings.valueColumn = parseInt($(this).val(), 10);
344 // handle manual changes to the chart x-axis labels
345 $('input[name="xaxis_label"]').keyup(function () {
346 currentSettings.xaxisLabel = $(this).val();
350 // handle manual changes to the chart y-axis labels
351 $('input[name="yaxis_label"]').keyup(function () {
352 currentSettings.yaxisLabel = $(this).val();
356 // handler for ajax form submission
357 $('#tblchartform').submit(function (event) {
360 if (codemirror_editor) {
361 $form[0].elements.sql_query.value = codemirror_editor.getValue();
363 if (!checkSqlQuery($form[0])) {
367 var $msgbox = PMA_ajaxShowMessage();
368 PMA_prepareForAjaxRequest($form);
369 $.post($form.attr('action'), $form.serialize(), function (data) {
370 if (typeof data !== 'undefined' &&
371 data.success === true &&
372 typeof data.chartData !== 'undefined') {
373 chart_data = jQuery.parseJSON(data.chartData);
375 PMA_ajaxRemoveMessage($msgbox);
377 PMA_ajaxShowMessage(data.error, false);
379 }, "json"); // end $.post()
385 $('#resizer').resizable({
389 .width($('#div_view_options').width() - 50)
390 .trigger('resizestop');
394 width : $('#resizer').width() - 20,
395 height : $('#resizer').height() - 20,
396 xaxisLabel : $('input[name="xaxis_label"]').val(),
397 yaxisLabel : $('input[name="yaxis_label"]').val(),
398 title : $('input[name="chartTitle"]').val(),
400 mainAxis : parseInt($('select[name="chartXAxis"]').val(), 10),
401 selectedSeries : getSelectedSeries(),
405 var vals = $('input[name="dateTimeCols"]').val().split(' ');
406 $.each(vals, function (i, v) {
407 dateTimeCols.push(parseInt(v, 10));
410 vals = $('input[name="numericCols"]').val().split(' ');
411 $.each(vals, function (i, v) {
412 numericCols.push(parseInt(v, 10));
416 onDataSeriesChange();
418 $("#tblchartform").submit();