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

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

New fancy interface update l33t! w00t!

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