1 /* vim: set expandtab sw=4 ts=4 sts=4: */
6 var currentChart = null;
7 var currentSettings = null;
12 function extractDate (dateString) {
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) {
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));
23 matches = dateRegExp.exec(dateString);
24 if (matches !== null && matches.length > 0) {
26 return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2));
32 function PMA_queryChart (data, columnNames, settings) {
33 if ($('#querychart').length === 0) {
39 text : settings.title,
45 background : 'rgba(0,0,0,0)'
49 placement : 'outsideGrid',
57 label : escapeHtml(settings.xaxisLabel)
60 label : settings.yaxisLabel
63 stackSeries : settings.stackSeries
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]);
77 dataTable.addColumn(ColumnType.STRING, columnNames[settings.mainAxis]);
81 if (settings.seriesColumn === null) {
82 $.each(settings.selectedSeries, function (index, element) {
83 dataTable.addColumn(ColumnType.NUMBER, columnNames[element]);
86 // set data to the data table
87 var columnsToExtract = [settings.mainAxis];
88 $.each(settings.selectedSeries, function (index, element) {
89 columnsToExtract.push(element);
95 for (i = 0; i < data.length; i++) {
98 for (var j = 0; j < columnsToExtract.length; j++) {
99 col = columnNames[columnsToExtract[j]];
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]);
108 } else { // subsequent columns are of type, number
109 newRow.push(parseFloat(row[col]));
114 dataTable.setData(values);
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;
126 $.each(seriesNames, function (seriesName, seriesNumber) {
127 dataTable.addColumn(ColumnType.NUMBER, seriesName);
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];
140 valueMap[xValue] = value;
142 seriesNumber = seriesNames[data[i][seriesColumnName]];
143 value[seriesNumber] = parseFloat(data[i][valueColumnName]);
147 $.each(valueMap, function (index, value) {
150 dataTable.setData(values);
153 // draw the chart and return the chart object
154 chart.draw(dataTable, plotSettings);
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();
167 var columnNames = [];
168 $('select[name="chartXAxis"] option').each(function () {
169 columnNames.push(escapeHtml($(this).text()));
172 currentChart = PMA_queryChart(chart_data, columnNames, currentSettings);
173 if (currentChart !== null) {
174 $('#saveChart').attr('href', currentChart.toImageString());
177 PMA_ajaxShowMessage(err.message, false);
181 function getSelectedSeries () {
182 var val = $('select[name="chartSeries"]').val() || [];
184 $.each(val, function (i, v) {
185 ret.push(parseInt(v, 10));
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();
196 $('span.span_timeline').hide();
197 if (currentSettings.type === 'timeline') {
198 $('input#radio_line').prop('checked', true);
199 currentSettings.type = 'line';
202 if (numericCols.indexOf(currentSettings.mainAxis) !== -1) {
203 $('span.span_scatter').show();
205 $('span.span_scatter').hide();
206 if (currentSettings.type === 'scatter') {
207 $('input#radio_line').prop('checked', true);
208 currentSettings.type = 'line';
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();
220 if (currentSettings.selectedSeries.length === 1) {
221 $('span.span_pie').show();
222 yaxis_title = $seriesSelect.children('option:selected').text();
224 $('span.span_pie').hide();
225 if (currentSettings.type === 'pie') {
226 $('input#radio_line').prop('checked', true);
227 currentSettings.type = 'line';
229 yaxis_title = PMA_messages.strYValues;
231 $('input[name="yaxis_label"]').val(yaxis_title);
232 currentSettings.yaxisLabel = yaxis_title;
236 * Unbind all event handlers before tearing down a page
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({
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();
272 $('input[name="barStacked"]').prop('checked', false);
273 $.extend(true, currentSettings, { stackSeries : false });
274 $('span.barStacked').hide();
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);
291 $seriesColumn.prop('disabled', true);
292 $valueColumn.prop('disabled', true);
293 $chartSeries.prop('disabled', false);
294 currentSettings.seriesColumn = null;
295 currentSettings.valueColumn = null;
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 });
305 $.extend(true, currentSettings, { stackSeries : false });
310 // handle changes in chart title
311 $('input[name="chartTitle"]')
313 temp_chart_title = $(this).val();
316 currentSettings.title = $('input[name="chartTitle"]').val();
320 if ($(this).val() !== temp_chart_title) {
325 // handle changing the x-axis
326 $('select[name="chartXAxis"]').change(function () {
331 // handle changing the selected data series
332 $('select[name="chartSeries"]').change(function () {
333 onDataSeriesChange();
337 // handle changing the series column
338 $('select[name="chartSeriesColumn"]').change(function () {
339 currentSettings.seriesColumn = parseInt($(this).val(), 10);
343 // handle changing the value column
344 $('select[name="chartValueColumn"]').change(function () {
345 currentSettings.valueColumn = parseInt($(this).val(), 10);
349 // handle manual changes to the chart x-axis labels
350 $('input[name="xaxis_label"]').keyup(function () {
351 currentSettings.xaxisLabel = $(this).val();
355 // handle manual changes to the chart y-axis labels
356 $('input[name="yaxis_label"]').keyup(function () {
357 currentSettings.yaxisLabel = $(this).val();
361 // handler for ajax form submission
362 $('#tblchartform').submit(function (event) {
364 if (codemirror_editor) {
365 $form[0].elements.sql_query.value = codemirror_editor.getValue();
367 if (!checkSqlQuery($form[0])) {
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);
379 PMA_ajaxRemoveMessage($msgbox);
381 PMA_ajaxShowMessage(data.error, false);
383 }, 'json'); // end $.post()
389 $('#resizer').resizable({
393 .width($('#div_view_options').width() - 50)
394 .trigger('resizestop');
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(),
404 mainAxis : parseInt($('select[name="chartXAxis"]').val(), 10),
405 selectedSeries : getSelectedSeries(),
409 var vals = $('input[name="dateTimeCols"]').val().split(' ');
410 $.each(vals, function (i, v) {
411 dateTimeCols.push(parseInt(v, 10));
414 vals = $('input[name="numericCols"]').val().split(' ');
415 $.each(vals, function (i, v) {
416 numericCols.push(parseInt(v, 10));
420 onDataSeriesChange();
422 $('#tblchartform').submit();