source: trunk/web-app/js/visualization.js @ 2014

Last change on this file since 2014 was 2014, checked in by tjeerd@…, 8 years ago

Further awesome additions to the visualization interface

File size: 12.6 KB
Line 
1/**
2 * This variable holds the currently displayed visualization
3 */
4var visualization = null;
5
6$(document).ready(function() {
7    $(".menu_item").mouseover(
8        function() {
9            $( this ).css("width","150px");
10            $(this).find("div.formulier").show();
11                }
12    ).mouseout(
13        function() {
14            $( this ).find("div.formulier").hide();
15            $( this ).css("width","88px");
16                }
17    );
18    $("#menu_go").unbind('mouseover').unbind('mouseout');
19});
20
21/**
22 * Retrieve new fields based on the study that the user has selected.
23 */
24function changeStudy() {
25    $( "#menu_study" ).find("div.formulier").hide();
26
27    if($( '#study option:selected' ).val()!="") {
28        $( "#menu_study" ).find("img.spinner").show();
29        $( "#menu_study" ).find("div.menu_item_info").html("<br />"+$( '#study option:selected' ).text());
30
31        executeAjaxCall( "getFields", {
32            "errorMessage": "An error occurred while retrieving variables from the server. Please try again or contact a system administrator.",
33            "success": function( data, textStatus, jqXHR ) {
34                // Remove all previous entries from the list
35                $( '#rows, #columns' ).empty();
36
37                if(data.infoMessage) {
38                    showError(data.infoMessage,"warning");
39                }
40
41                clearStep(".menu_item");
42               
43                // Add all fields to the lists
44                if( data.returnData ) {
45                    var returnData = data.returnData;
46
47                    var prevCat = "";
48                        $.each( returnData, function( idx, field ) {
49                        if(field.category!=prevCat) {
50                            $( '#rows, #columns' )
51                                    .append( $( "<option>" )
52                                    .val( "" )
53                                    .text( field.source+": "+field.category )
54                                    .attr("disabled","disabled")
55                                    .css("font-weight","bold")
56                                    .css("color","white")
57                                    .css("background-color","#333") );
58                            prevCat = field.category;
59                        }
60                            $( '#rows, #columns' ).append( $( "<option>" ).val( field.id ).text( field.name ) );
61                        });
62                       
63                        $( "#menu_study" ).find("div.menu_item_info").html("<br />"+$( '#study option:selected' ).text());
64                        $( "#menu_study" ).addClass("menu_item_done");
65                        $( "#menu_row, #menu_column" ).addClass("menu_item_fill");
66                }
67            }
68        },'menu_study');
69    } else {
70        $( '#rows, #columns' ).empty();
71        clearStep(".menu_item");
72        $( "#menu_study" ).addClass("menu_item_fill");
73    }
74}
75
76/**
77 * Retrieve the possible visualization types based on the fields that the user has selected.
78 */
79function changeFields(divid) {
80    $( "#"+divid ).find("div.formulier").hide();
81
82    var type = "rows";
83    if(divid=="menu_column") type = "columns";
84
85    if($( '#'+type+' option:selected' ).val()!="") {
86
87        $( "#"+divid ).find("img.spinner").show();
88
89        executeAjaxCall( "getVisualizationTypes", {
90            "errorMessage": "An error occurred while retrieving visualization types from the server. Please try again or contact a system administrator.",
91            "success": function( data, textStatus, jqXHR ) {
92                // Remove all previous entries from the list
93                $( '#types' ).empty();
94
95                if(data.infoMessage!=null) {
96                    showError(data.infoMessage,"warning");
97                } else {
98
99                    // Add all fields to the lists
100                    var returnData = data.returnData;
101
102                    $.each( returnData, function( idx, field ) {
103                        $( '#types' ).append( $( "<option>" ).val( field.id ).text( field.name ) );
104                    });
105
106                    clearStep("#menu_vis");
107                }
108
109                clearStep("#"+divid);
110                $( "#"+divid ).find("div.menu_item_info").html("<br />"+$( '#'+type+' option:selected' ).text());
111                $( "#"+divid ).addClass("menu_item_done");
112
113                if((!$( "#menu_vis" ).hasClass("menu_item_done")) &&
114                        ($( "#menu_row" ).hasClass("menu_item_done") || divid=="menu_row") &&
115                        ($( "#menu_column" ).hasClass("menu_item_done") || divid=="menu_column")
116                        ) {
117                    clearStep("#menu_vis");
118                    $( "#menu_vis" ).addClass("menu_item_fill");
119                    if($( '#types option' ).length==1) {
120                        $( '#types :first-child' ).attr("selected","selected");
121                        changeVis();
122                    }
123                }
124
125
126            }
127        },divid);
128    } else {
129        clearStep("#menu_vis, #"+divid);
130        $( "#"+divid ).addClass("menu_item_fill");
131    }
132}
133
134/**
135 *
136 */
137function changeVis() {
138    $( "#menu_vis" ).find("div.formulier").hide();
139    if($( '#types option:selected' ).val()!="") {
140        $( "#menu_vis" ).removeClass().addClass("menu_item menu_item_done");
141        $( "#menu_vis" ).find("div.menu_item_info").html("<br />"+$( '#types option:selected' ).text());
142    } else {
143        $( "#menu_vis" ).find("div.menu_item_info").html("");
144        $( "#menu_vis" ).removeClass().addClass("menu_item menu_item_fill");
145    }
146    if($("#autovis").attr("checked")=="checked") {
147        visualize();
148    }
149
150}
151
152
153/**
154 * Create a visualization based on the parameters entered in the form
155 * The data for the visualization is retrieved from the serverside getData method
156 */ 
157function visualize() {
158
159    if(!$( "#menu_vis" ).hasClass("menu_item_done") ||
160        !$( "#menu_row" ).hasClass("menu_item_done") ||
161        !$( "#menu_row" ).hasClass("menu_item_done") ||
162        !$( "#menu_row" ).hasClass("menu_item_done") ) {
163
164        $( ".menu_item" ).not(".menu_item_done").removeClass().addClass("menu_item menu_item_warning");
165    } else {
166
167        $( "#menu_go" ).find("img.spinner").show();
168
169        executeAjaxCall( "getData", {
170            "errorMessage": "An error occurred while retrieving data from the server. Please try again or contact a system administrator.",
171            "success": function( data, textStatus, jqXHR ) {
172                // Remove old chart, if available
173                if( visualization )
174                    visualization.destroy();
175
176                if(data.infoMessage!=null) {
177                    showError(data.infoMessage,"warning");
178                }
179                // Handle erroneous data
180                /*if( !checkCorrectData( data.returnData ) ) {
181                    showError( "Unfortunately the server returned data in a format that we did not expect.", "error" );
182                    return;
183                }*/
184
185                // Retrieve the datapoints from the json object
186                var dataPoints = [];
187                var series = [];
188
189
190                var returnData = data.returnData;
191                $.each(returnData.series, function(idx, element ) {
192                    dataPoints[ dataPoints.length ] = element.y;
193                    series[ series.length ] = { "label": element.name };
194                });
195
196                var xlabel = returnData[ "xaxis" ].unit=="" ? returnData[ "xaxis" ].title : returnData[ "xaxis" ].title + " (" + returnData[ "xaxis" ].unit + ")";
197                var ylabel = returnData[ "yaxis" ].unit=="" ? returnData[ "yaxis" ].title : returnData[ "yaxis" ].title + " (" + returnData[ "yaxis" ].unit + ")";
198
199                // TODO: create a chart based on the data that is sent by the user and the type of chart
200                // chosen by the user
201                visualization = $.jqplot('visualization', dataPoints, {
202                    // Tell the plot to stack the bars.
203                    stackSeries: true,
204                    seriesDefaults:{
205                        renderer:$.jqplot.BarRenderer,
206                        rendererOptions: {
207                                // Put a 30 pixel margin between bars.
208                                barMargin: 30,
209                                // Highlight bars when mouse button pressed.
210                                // Disables default highlighting on mouse over.
211                                highlightMouseDown: true
212                        },
213                        pointLabels: {show: true}
214                    },
215                    series: series,
216                    axes: {
217                        xaxis: {
218                                renderer: $.jqplot.CategoryAxisRenderer,
219                                ticks: returnData.x,
220                                label: xlabel,
221                                labelRenderer: $.jqplot.CanvasAxisLabelRenderer
222                        },
223                        yaxis: {
224                            label: ylabel,
225                            labelRenderer: $.jqplot.CanvasAxisLabelRenderer
226                        }
227                    }
228
229                });
230
231                $( "#visualization" ).show();
232                $( "#menu_go" ).find("img.spinner").hide();
233            }
234        }, "menu_go");
235    }
236}
237
238/**
239 * Shows an error message in a proper way
240 * @param message       String  Message to show
241 */
242function showError( message, strClass ) {
243        $( '#message' ).html( message );
244    $( '#message' ).removeClass().addClass(strClass);
245        $( '#message' ).fadeIn();
246    $(document).bind('click',function() {
247        $( '#message' ).removeClass();
248        $( '#message' ).html("");
249        $(document).unbind('click');
250    });
251}
252
253
254/**
255 * Clears one or multiple steps
256 * @param data
257 */
258function clearStep(strSelector) {
259    $( strSelector ).removeClass().addClass("menu_item");
260    $( strSelector ).find(".menu_item_info").html("");
261    $( strSelector ).find("img.spinner").hide();
262}
263
264/**
265 * Checks whether the data in the getData call can be handled correctly
266 * @param       JSON object to check
267 * @return      boolean True if the data is correctly formatted, false otherwise
268 */
269function checkCorrectData( data ) {
270        /*
271        Data expected:
272        {
273                "type": "barchart",
274                "x": [ "Q1", "Q2", "Q3", "Q4" ],
275                "xaxis": { "title": "quarter 2011", "unit": "" },
276                "yaxis": { "title": "temperature", "unit": "degrees C" },
277                "series": [
278                        {
279                                "name": "series name",
280                                "y": [ 5.1, 3.1, 20.6, 15.4 ],
281                                "error": [ 0.5, 0.2, 0.4, 0.5 ]
282                        },
283                ]
284        }
285        */
286
287        return ( "type" in data && "x" in data && "xaxis" in data && "yaxis" in data && "series" in data && $.isArray( data.series ) );
288}
289
290/**
291 * Gathers data for the given request type from the form elements on the page
292 * @param type  String  Can be 'getStudies', 'getFields', 'getVisualizationType' or 'getData'
293 * @return Object               Object with the data to be sent to the server
294 */
295function gatherData( type ) {
296        // For simplicity, we send the whole form to the server. In the
297        // future this might be enhanced, based on the given type
298        return $( 'form#visualizationForm' ).serialize();
299}
300
301/**
302 * Executes an ajax call in a standardized way. Retrieves data to be sent with gatherData
303 * The ajaxParameters map will be sent to the $.ajax call
304 * @param action                        Name of the action to execute. Is also given to the gatherData method
305 *                                                      as a parameter and the url will be determined based on this parameter.
306 * @param ajaxParameters        Hashmap with parameters that are sent to the $.ajax call. The entries
307 *                                                      url, data and dataType are set by this method.
308 *                                                      An additional key 'errorMessage' can be given, with the message that will be
309 *                                                      shown if an error occurrs in this method. In that case, the 'error' method from
310 *                                                      the ajaxParameters method will be overwritten.
311 * @see visualizationUrls
312 * @see jQuery.ajax
313 */
314function executeAjaxCall( action, ajaxParameters, divid ) {
315        var data = gatherData( action );
316
317        // If no parameters are given, create an empty map
318        if( !ajaxParameters ) 
319                ajaxParameters = {}
320
321        if( ajaxParameters[ "errorMessage" ] ) {
322                var message = ajaxParameters[ "errorMessage" ];
323                ajaxParameters[ "error" ] = function( jqXHR, textStatus, errorThrown ) {
324                        // An error occurred while retrieving fields from the server
325                        showError( "An error occurred while retrieving variables from the server. Please try again or contact a system administrator.<br />"+textStatus, "error" );
326            $( "#"+divid ).removeClass().addClass('menu_item menu_item_error');
327            $( "#"+divid ).find("img.spinner").hide();
328                }
329
330                // Remove the error message
331                delete ajaxParameters[ "errorMessage" ];
332        }
333       
334        // Retrieve a new list of fields from the controller
335        // based on the study we chose
336        $.ajax($.extend({
337                url: visualizationUrls[ action ],
338                data: data,
339                dataType: "json"
340        }, ajaxParameters ) );
341}
Note: See TracBrowser for help on using the repository browser.