1 | <html> |
---|
2 | <head> |
---|
3 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> |
---|
4 | <meta name="layout" content="main"/> |
---|
5 | <title>Visualization</title> |
---|
6 | |
---|
7 | <!--[if lt IE 9]><g:javascript src="jqplot/excanvas.js" /><![endif]--> |
---|
8 | <g:javascript src="jqplot/jquery.jqplot.min.js" /> |
---|
9 | <link rel="stylesheet" type="text/css" href="<g:resource dir='css' file='jquery.jqplot.min.css' />" /> |
---|
10 | |
---|
11 | <!-- jqPlot plugins --> |
---|
12 | <g:javascript src="jqplot/plugins/jqplot.barRenderer.min.js" /> |
---|
13 | <g:javascript src="jqplot/plugins/jqplot.categoryAxisRenderer.min.js" /> |
---|
14 | <g:javascript src="jqplot/src/plugins/jqplot.pointLabels.min.js" /> |
---|
15 | <g:javascript src="jqplot/src/plugins/jqplot.canvasTextRenderer.min.js" /> |
---|
16 | <g:javascript src="jqplot/src/plugins/jqplot.canvasAxisLabelRenderer.min.js" /> |
---|
17 | |
---|
18 | <script type="text/javascript"> |
---|
19 | // We store urls here because they depend on the grails configuration. |
---|
20 | // This way, the URLs are always correct |
---|
21 | var visualizationUrls = { |
---|
22 | "getStudies": "<g:createLink action="getStudies" />", |
---|
23 | "getFields": "<g:createLink action="getFields" />", |
---|
24 | "getVisualizationTypes": "<g:createLink action="getVisualizationTypes" />", |
---|
25 | "getData": "<g:createLink action="getData" />" |
---|
26 | }; |
---|
27 | |
---|
28 | function showError( message ) { |
---|
29 | $( '#ajaxError' ).text( message ); |
---|
30 | $( '#ajaxError' ).show(); |
---|
31 | } |
---|
32 | |
---|
33 | /** |
---|
34 | * Gathers data for the given request type from the form elements on the page |
---|
35 | * @param type String Can be 'getStudies', 'getFields', 'getVisualizationType' or 'getData' |
---|
36 | * @return Object Object with the data to be sent to the server |
---|
37 | */ |
---|
38 | function gatherData( type ) { |
---|
39 | var data = {}; |
---|
40 | |
---|
41 | // different types of request require different data arrays |
---|
42 | // However, some data is required for all types. For that reason, |
---|
43 | // the fallthrough option in the switch statement is used. |
---|
44 | switch( type ) { |
---|
45 | case "getData": |
---|
46 | var typeElement = $( '#type' ); |
---|
47 | data[ "type" ] = { "id": typeElement.val() }; |
---|
48 | case "getVisualizationTypes": |
---|
49 | var rowsElement = $( '#rows' ); |
---|
50 | var columnsElement = $( '#columns' ); |
---|
51 | data[ "rows" ] = [ |
---|
52 | { "id": rowsElement.val() } |
---|
53 | ]; |
---|
54 | data[ "columns" ] = [ |
---|
55 | { "id": columnsElement.val() } |
---|
56 | ]; |
---|
57 | case "getFields": |
---|
58 | var studyElement = $( '#study' ); |
---|
59 | data[ "studies" ] = [ |
---|
60 | { "id": studyElement.val() } |
---|
61 | ]; |
---|
62 | |
---|
63 | case "getStudies": |
---|
64 | } |
---|
65 | |
---|
66 | return data; |
---|
67 | } |
---|
68 | |
---|
69 | /** |
---|
70 | * Executes an ajax call in a standardized way. Retrieves data to be sent with gatherData |
---|
71 | * The ajaxParameters map will be sent to the $.ajax call |
---|
72 | * @param action Name of the action to execute. Is also given to the gatherData method |
---|
73 | * as a parameter and the url will be determined based on this parameter. |
---|
74 | * @param ajaxParameters Hashmap with parameters that are sent to the $.ajax call. The entries |
---|
75 | * url, data and dataType are set by this method. |
---|
76 | * An additional key 'errorMessage' can be given, with the message that will be |
---|
77 | * shown if an error occurrs in this method. In that case, the 'error' method from |
---|
78 | * the ajaxParameters method will be overwritten. |
---|
79 | * @see visualizationUrls |
---|
80 | * @see jQuery.ajax |
---|
81 | */ |
---|
82 | function executeAjaxCall( action, ajaxParameters ) { |
---|
83 | var data = gatherData( action ); |
---|
84 | |
---|
85 | // If no parameters are given, create an empty map |
---|
86 | if( !ajaxParameters ) |
---|
87 | ajaxParameters = {} |
---|
88 | |
---|
89 | if( ajaxParameters[ "errorMessage" ] ) { |
---|
90 | var message = ajaxParameters[ "errorMessage" ]; |
---|
91 | ajaxParameters[ "error" ] = function( jqXHR, textStatus, errorThrown ) { |
---|
92 | // An error occurred while retrieving fields from the server |
---|
93 | showError( "An error occurred while retrieving variables from the server. Please try again or contact a system administrator." ); |
---|
94 | } |
---|
95 | |
---|
96 | // Remove the error message |
---|
97 | delete ajaxParameters[ "errorMessage" ]; |
---|
98 | } |
---|
99 | |
---|
100 | // Retrieve a new list of fields from the controller |
---|
101 | // based on the study we chose |
---|
102 | $.ajax($.extend({ |
---|
103 | url: visualizationUrls[ action ], |
---|
104 | data: "data=" + JSON.stringify( data ), |
---|
105 | dataType: "json", |
---|
106 | }, ajaxParameters ) ); |
---|
107 | } |
---|
108 | |
---|
109 | function changeStudy() { |
---|
110 | executeAjaxCall( "getFields", { |
---|
111 | "errorMessage": "An error occurred while retrieving variables from the server. Please try again or contact a system administrator.", |
---|
112 | "success": function( data, textStatus, jqXHR ) { |
---|
113 | // Remove all previous entries from the list |
---|
114 | $( '#rows, #columns' ).empty(); |
---|
115 | |
---|
116 | // Add all fields to the lists |
---|
117 | $.each( data, function( idx, field ) { |
---|
118 | $( '#rows, #columns' ).append( $( "<option>" ).val( field.id ).text( field.name ) ); |
---|
119 | }); |
---|
120 | |
---|
121 | $( "#step2" ).show(); |
---|
122 | $( "#step3" ).hide(); |
---|
123 | } |
---|
124 | }); |
---|
125 | } |
---|
126 | |
---|
127 | function changeFields() { |
---|
128 | executeAjaxCall( "getVisualizationTypes", { |
---|
129 | "errorMessage": "An error occurred while retrieving visualization types from the server. Please try again or contact a system administrator.", |
---|
130 | "success": function( data, textStatus, jqXHR ) { |
---|
131 | // Remove all previous entries from the list |
---|
132 | $( '#types' ).empty(); |
---|
133 | |
---|
134 | // Add all fields to the lists |
---|
135 | $.each( data, function( idx, field ) { |
---|
136 | $( '#types' ).append( $( "<option>" ).val( field.id ).text( field.name ) ); |
---|
137 | }); |
---|
138 | |
---|
139 | $( "#step3" ).show(); |
---|
140 | } |
---|
141 | }); |
---|
142 | } |
---|
143 | |
---|
144 | function visualize() { |
---|
145 | executeAjaxCall( "getData", { |
---|
146 | "errorMessage": "An error occurred while retrieving data from the server. Please try again or contact a system administrator.", |
---|
147 | "success": function( data, textStatus, jqXHR ) { |
---|
148 | /* |
---|
149 | Data expected: |
---|
150 | { |
---|
151 | "type": "barchart", |
---|
152 | "x": [ "Q1", "Q2", "Q3", "Q4" ], |
---|
153 | "xaxis": { "title": "quarter 2011", "unit": "" }, |
---|
154 | "yaxis": { "title": "temperature", "unit": "degrees C" }, |
---|
155 | "series": [ |
---|
156 | { |
---|
157 | "name": "series name", |
---|
158 | "y": [ 5.1, 3.1, 20.6, 15.4 ], |
---|
159 | "error": [ 0.5, 0.2, 0.4, 0.5 ] |
---|
160 | }, |
---|
161 | ] |
---|
162 | } |
---|
163 | */ |
---|
164 | |
---|
165 | // TODO: error handling if incorrect data is returned |
---|
166 | |
---|
167 | // Retrieve the datapoints from the json object |
---|
168 | var dataPoints = []; |
---|
169 | var series = []; |
---|
170 | |
---|
171 | $.each(data.series, function(idx, element ) { |
---|
172 | dataPoints[ dataPoints.length ] = element.y; |
---|
173 | series[ series.length ] = { "label": element.name }; |
---|
174 | }); |
---|
175 | |
---|
176 | // TODO: create a chart based on the data that is sent by the user and the type of chart |
---|
177 | // chosen by the user |
---|
178 | chart = $.jqplot('visualization', dataPoints, { |
---|
179 | // Tell the plot to stack the bars. |
---|
180 | stackSeries: true, |
---|
181 | captureRightClick: true, |
---|
182 | seriesDefaults:{ |
---|
183 | renderer:$.jqplot.BarRenderer, |
---|
184 | rendererOptions: { |
---|
185 | // Put a 30 pixel margin between bars. |
---|
186 | barMargin: 30, |
---|
187 | // Highlight bars when mouse button pressed. |
---|
188 | // Disables default highlighting on mouse over. |
---|
189 | highlightMouseDown: true |
---|
190 | }, |
---|
191 | pointLabels: {show: true} |
---|
192 | }, |
---|
193 | series: series, |
---|
194 | axes: { |
---|
195 | xaxis: { |
---|
196 | renderer: $.jqplot.CategoryAxisRenderer, |
---|
197 | ticks: data.x, |
---|
198 | label: data[ "xaxis" ].title + " (" + data[ "xaxis" ].unit + ")", |
---|
199 | labelRenderer: $.jqplot.CanvasAxisLabelRenderer |
---|
200 | }, |
---|
201 | yaxis: { |
---|
202 | // Don't pad out the bottom of the data range. By default, |
---|
203 | // axes scaled as if data extended 10% above and below the |
---|
204 | // actual range to prevent data points right on grid boundaries. |
---|
205 | // Don't want to do that here. |
---|
206 | padMin: 0, |
---|
207 | label: data[ "yaxis" ].title + " (" + data[ "yaxis" ].unit + ")", |
---|
208 | labelRenderer: $.jqplot.CanvasAxisLabelRenderer |
---|
209 | } |
---|
210 | }, |
---|
211 | legend: { |
---|
212 | show: true, |
---|
213 | location: 'e', |
---|
214 | placement: 'outside' |
---|
215 | } |
---|
216 | }); |
---|
217 | |
---|
218 | $( "#visualization" ).show(); |
---|
219 | }, |
---|
220 | }); |
---|
221 | } |
---|
222 | </script> |
---|
223 | <style type="text/css"> |
---|
224 | /* #step2, #step3 { display: none; } */ |
---|
225 | #ajaxError { |
---|
226 | display: none; |
---|
227 | border: 1px solid #f99; /* #006dba; */ |
---|
228 | margin-bottom: 10px; |
---|
229 | margin-top: 10px; |
---|
230 | |
---|
231 | background: #ffe0e0 url(${fam.icon( name: 'error' )}) 10px 10px no-repeat; |
---|
232 | padding: 10px 10px 10px 33px; |
---|
233 | } |
---|
234 | |
---|
235 | label { display: inline-block; zoom: 1; *display: inline; width: 110px; margin-top: 10px; } |
---|
236 | |
---|
237 | #visualizationForm { position: relative; margin: 10px 0; font-size: 11px; } |
---|
238 | #visualizationForm h3 { font-size: 13px; } |
---|
239 | #visualizationForm h3 .nummer { display: inline-block; zoom: 1; *display: inline; width: 25px; } |
---|
240 | |
---|
241 | #visualizationForm p { margin-left: 25px; } |
---|
242 | |
---|
243 | table.jqplot-table-legend { width: 100px; } |
---|
244 | </style> |
---|
245 | </head> |
---|
246 | <body> |
---|
247 | |
---|
248 | <h1>Visualize your study</h1> |
---|
249 | |
---|
250 | <g:if test="${flash.error}"> |
---|
251 | <div class="errormessage"> |
---|
252 | ${flash.error.toString().encodeAsHTML()} |
---|
253 | </div> |
---|
254 | </g:if> |
---|
255 | <g:if test="${flash.message}"> |
---|
256 | <div class="message"> |
---|
257 | ${flash.message.toString().encodeAsHTML()} |
---|
258 | </div> |
---|
259 | </g:if> |
---|
260 | |
---|
261 | <div id="ajaxError"> |
---|
262 | </div> |
---|
263 | |
---|
264 | <p class="explanation"> |
---|
265 | Choose a study to visualize |
---|
266 | </p> |
---|
267 | |
---|
268 | <form id="visualizationForm"> |
---|
269 | <h3><span class="nummer">1</span>Studies</h3> |
---|
270 | <p> |
---|
271 | <label>Study</label><g:select from="${studies}" optionKey="id" optionValue="title" name="study" onChange="changeStudy();"/> |
---|
272 | </p> |
---|
273 | |
---|
274 | <div id="step2"> |
---|
275 | <h3><span class="nummer">2</span>Variables</h3> |
---|
276 | <p> |
---|
277 | <label for="rows">Rows</label> <select id="rows" name="rows" onChange="changeFields();"></select><br /> |
---|
278 | <label for="columns">Columns</label> <select id="columns" name="columns" onChange="changeFields();"></select> |
---|
279 | </p> |
---|
280 | </div> |
---|
281 | |
---|
282 | <div id="step3"> |
---|
283 | <h3><span class="nummer">3</span>Visualization type</h3> |
---|
284 | <p> |
---|
285 | <label for"types">Type</label><select id="types" name="types"></select> |
---|
286 | </p> |
---|
287 | <p> |
---|
288 | <label> </label><input type="button" value="Visualize" onClick="visualize();"/> |
---|
289 | </p> |
---|
290 | </div> |
---|
291 | </form> |
---|
292 | |
---|
293 | <div id="visualization"> |
---|
294 | </div> |
---|
295 | </body> |
---|
296 | </html> |
---|
297 | |
---|
298 | |
---|
299 | |
---|