Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/ChartHelper.cshtml @ 11036

Last change on this file since 11036 was 11036, checked in by mroscoe, 10 years ago
File size: 19.5 KB
Line 
1@* HeuristicLab
2 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
3 *
4 * This file is part of HeuristicLab.
5 *
6 * HeuristicLab is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * HeuristicLab is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
18 *@
19
20@helper AjaxDataRenderer()
21{
22    <script>
23        var ajaxDataRenderer = function (url, plot, options) {
24            var ret = null;
25            $.ajax({
26                async: false,
27                url: url,
28                dataType: "json",
29                success: function (data) {
30                    ret = data;
31                }
32            });
33            return ret;
34        };
35    </script>
36}
37
38@helper LineChartTime(string destinationTag, string url, string title = "", double? minY = null, double? maxY = null, string axisYFormat = null)
39{
40    <script>
41        var @(destinationTag)Plot = $.jqplot("@destinationTag", "@url", {
42            title: "@title",
43            highlighter: {
44                show: true,
45                sizeAdjust: 7.5
46            },
47            seriesDefaults: {
48                markerOptions: { show: false }
49            },
50            dataRenderer: ajaxDataRenderer,
51            axes: {
52                xaxis: {
53                    renderer: $.jqplot.DateAxisRenderer,
54                    pad: 0
55                },
56                yaxis: {
57                    @if (axisYFormat != null)
58                    {<text>
59                    tickOptions: {
60                        formatString: "@axisYFormat",
61                    },
62                    </text>}
63                    autoscale: true,
64                    pad: 0,
65                    @if (minY != null)
66                    {
67                        @:min: @minY,
68                    }
69                    @if (maxY != null)
70                    {
71                        @:max: @maxY,
72                    }
73                },
74            },
75            gridPadding: { left: 50, right: 10 },
76            cursor: {
77                show: true,
78                showTooltip: false,
79                zoom: true,
80                clickReset: false,
81                dblClickReset: false,
82                constrainZoomTo: 'x'
83            }
84        });
85       
86        $(window).resize(function() {
87            @(destinationTag)Plot.replot({ resetAxes: true });
88        });
89    </script>
90}
91
92@helper RefreshChart(string destinationTag, string url, string startDate, string endDate)
93{
94  <text>
95  $.ajax({url: "@(new HtmlString(url))?start=" + @startDate + "&end=" + @endDate, datatype: "json", success: function(result) {
96    for (var i = 0; i < result.length; i++) {
97      @(destinationTag)Plot.series[i].data = result[i];
98    }
99    @(destinationTag)Plot.replot({ resetAxes: true })
100  }});
101  </text>
102}
103
104@helper NumberPages(string records, string limit, string container, string functionName, string currentPage = null)
105{
106  <text>
107    if(@(records).length > @limit) {
108      $("#@container").append('<label class="pageTitle">Page: </label>')
109      var pages = Math.floor(@(records).length/@(limit)) + 1;
110      for(var i=0; i < pages; i++) {
111        $("#" + "@container").append('<a id="@(container)Page' + (i + 1) + '" class="page">' + (i + 1) + '</a>')
112      }
113      if(@currentPage != null) {
114        $("#@(container)Page" + @currentPage).css('color','#F7921D');
115      }
116      else {
117        $("#@(container)Page1").css('color','#F7921D');
118      }
119      $(".page").click(function () {
120        pageNumber = $(this).html();
121        @(functionName)();
122      });
123      if(@currentPage != null) {
124        @(records).splice(0,(@(currentPage)-1)*@(limit));
125        if (@(records).length > @(limit)) {
126          @(records).splice(@(limit), @(records).length - @(limit));
127        }
128      }
129      else {
130        @(records).splice(@(limit), @(records).length - @(limit));
131      }
132    }
133  </text>
134}
135
136@helper TasksForUser(string container, string destinationTag, string url, string functionName, string userName, string limit, string startDate = null, string endDate = null, string jobId=null, string taskState=null, string pageNumber=null)
137{
138  <text>
139    var GetRequest = "?userName=" + @(userName) + "&limit=" + @(limit);
140    @if(startDate!=null) {
141      @:if(@(startDate)!=null) {
142        @:GetRequest += "&start=" + @startDate;
143      @:}
144    }
145    @if(endDate!=null) {
146      @:if(@(endDate)!=null) {
147        @:GetRequest += "&end=" + @endDate;
148      @:}
149    }
150    @if(jobId!=null) {
151      @:if(@(jobId)!=null) {
152        @:GetRequest += "&jobId=" + @jobId;
153      @:}
154    }
155    @if(taskState!=null) {
156      @:if(@(taskState)!=null) {
157        @:GetRequest += "&taskState=" + @taskState;
158      @:}
159    }
160    $.ajax({
161      async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) {
162      if(result.length==0) {
163        $("#@container").append(
164          '<section class="chartContainer"><h1 class="title">' + @userName + ' has no tasks for the specified filters!</h1></section>'
165        )
166      }
167      var waitTime;
168      var transferTime;
169      var runTime;
170      var seriesDescriptions = ["Time waiting","Time transferring","Time calculating"];
171
172      //Checks if multipage display, if it is then trims results to
173      //the results for the page to be displayed
174      @ChartHelper.NumberPages("result",limit,container,functionName,pageNumber)
175
176      //Globally accesible, for use when resizing, eliminates extra DB request
177      window["numberTasks"] = result.length;
178
179      //Set display of all errors to none, errors matching the tasks will be reset below
180      $(".errorContainer, .errorTitle, .errorTask, .errorMessage").css('display','none');
181
182      //For each result create a seperate collapsable section with a chart and info label
183      for(var i = 0; i < result.length; i++){
184        $("#" + "@container").append(
185          '<section class="chartContainer"><h1 class="title" id="' + result[i].Key + '">Task ' + result[i].Key +
186          '</h1><button class="collapse" onclick="collapseSection(this)">+</button><div id="@(destinationTag)' + i +
187          '"></div><label id="@(destinationTag)' + i + 'Info"></label></section>'
188        )
189        //Re-enables the error display if any of the tasks on the page have Ids matching
190        //those of errors
191        $(".errorTask").each(function() {
192          if($(this).html()==result[i].Key) {
193            $("#" + result[i].Key).css("color","red");
194            $("#" + result[i].Key).append(" - ERROR");
195            $(".errorContainer, .errorTitle, .underline").css('display','inline-block');
196            $(this).css('display','inline-block');
197            $(this).next().css('display','inline-block');
198          }
199        });
200        waitTime = [result[i].Value[0]];
201        transferTime = [result[i].Value[1]];
202        runTime = [result[i].Value[2]];
203        window["@(destinationTag)Plot" + i] = $.jqplot("@destinationTag" + i, [waitTime,transferTime,runTime], {
204          seriesDefaults:{
205            renderer:$.jqplot.BarRenderer,
206            shadowAngle: 135,
207            pointLabels: {show: true, formatString: '%.3f'}
208          },
209          series:[
210            {label:'Waiting'},
211            {label:'Transferring'},
212            {label:'Calculating'}
213          ],
214          legend: {
215            show: true,
216            location: 'e',
217            placement: 'outside'
218          },
219          axes: {
220            xaxis: {
221              renderer: $.jqplot.CategoryAxisRenderer,
222              showLabel: false,
223              pad: 0
224            },
225            yaxis: {
226              pad: 0
227            }
228          },
229          cursor: {
230            showTooltip: false
231          }
232        });
233        /* Bind a datalistener to each chart and display details of clicked
234          upon data in the label below the chart */
235        $("#" + "@(destinationTag)" + i).bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) {
236          $("#" + $(this).attr('id') + "Info").html(seriesDescriptions[seriesIndex] + ': ' + data[1]);
237        });
238
239        collapsedByDefault(document.getElementById("@(destinationTag)" + i));
240      }
241    }});
242  </text>
243}
244
245@helper ResizeTasks(string destinationTag)
246{
247  <text>
248  //Resize event, resets bar width for task charts and replots them
249  $(window).resize(function() {
250    for(var i = 0; i < numberTasks; i++) {
251      $.each(window[ "@(destinationTag)Plot" + i].series, function(index, series) {
252        series.barWidth = undefined;
253      });
254      window["@(destinationTag)Plot" + i].replot({ resetAxes: true });
255    }
256  });
257  </text>
258}
259
260@helper SetStreamingProperties(int refresh, int chartLength, int upperY) {
261  <text>
262  //Refresh time (in millisec)
263  var refreshRate = @(refresh);
264  //Number of data points on chart
265  var chartSize = @(chartLength);
266  //Amount to add to max Y value
267  var upperYBuffer = @(upperY);
268
269  //Used to return a string containing the names of the series
270  //to be used in plot creation
271  function getSeries(numberData,dataName){
272    var result = "[";
273    for(i=0; i < numberData; i++) {
274      if(i < numberData -1) {
275        result += dataName + i + ",";
276      }
277      else {
278        result += dataName + i + "]";
279      }
280    }
281    return result;
282  }
283  </text>
284}
285
286@helper CreateStreamChart(string dataName, string destinationTag, string url, string title, string format = null, double? maxY = null) {
287  <text>
288  //Get current time, used to create initial values
289  var @(dataName)CurrentDate = (new Date()).getTime();
290
291  var @(dataName)Data = [];
292  var @(dataName)CurrentValue = [];
293
294  //Get the most recent value(s) from the given URL
295  $.ajax({
296    async: false, url: '@(url)', datatype: "json", success: function (result) {
297      for(i = 0; i < result.length; i++) {
298        @(dataName)CurrentValue[i] = result[i];
299      }
300    }
301  });
302 
303  //Create a chartSize worth of data using CurrentDate and CurrentValue
304  //for each CurrentValue
305  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
306    window["@(dataName)Data" + i] = [];
307    for (j = 0; j < chartSize; j++) {
308      window[ "@(dataName)Data" + i].push([@(dataName)CurrentDate - (chartSize - 1 - j) * refreshRate, @(dataName)CurrentValue[i]]);
309    }
310  }
311
312  //Options for the chart to be created
313  var @(destinationTag)PlotOptions = {
314    title: "@title",
315    axes: {
316      xaxis: {
317        numberTicks: 4,
318        renderer: $.jqplot.DateAxisRenderer,
319        tickOptions: { formatString: '%H:%M:%S' },
320        min: window["@(dataName)Data" + 0][0][0],
321        max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0]
322      },
323      yaxis: {
324        @if (format != null)
325        {<text>
326        tickOptions: {
327            formatString: "@format",
328        },
329        </text>}
330        min: 0,
331        @if (maxY != null) {
332          @:max: @maxY,
333        }
334        else{
335          @:max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer,
336        }
337        numberTicks: 6
338      }
339    },
340    seriesDefaults: {
341      rendererOptions: { smooth: true },
342      markerOptions: {
343        show: false
344      }
345    }
346  };
347
348  //Declares the jqPlot variable, evals the string of series returned
349  //from getSeries which allows for any number of series
350  window[ "@(destinationTag)Plot"] = $.jqplot('@destinationTag', eval(getSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
351  </text>
352}
353
354@helper UpdateStreamChart(string dataName, string destinationTag, string url, string fixedY = null)
355{
356  <text>
357  //If the data is beyond chartSize use shift to trim one off the end
358  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
359    if (window["@(dataName)Data" + i].length > chartSize - 1) {
360      window["@(dataName)Data" + i].shift();
361    }
362  }
363
364  //Get the up-to-date data, each result assigned to it's own array
365  $.ajax({
366    async: false, url: '@(url)', datatype: "json", success: function (result) {
367      for(i = 0; i < result.length; i++) {
368        window[ "@(dataName)Data" + i].push([(new Date()).getTime(), result[i]]);
369      }
370    }
371  });
372
373  //If the plot exists currently destroy it
374  if ( @(destinationTag)Plot) {
375    @(destinationTag)Plot.destroy();
376  }
377
378  //Assign series
379  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
380    @(destinationTag)Plot.series[i].data = window["@(dataName)Data" + i];
381  }
382
383  //Recalculate x and possibly y axis max and mins
384  @(destinationTag)PlotOptions.axes.xaxis.min = window["@(dataName)Data" + 0][0][0];
385  @(destinationTag)PlotOptions.axes.xaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0];
386  @if (fixedY == null) {
387    @:@(destinationTag)PlotOptions.axes.yaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer;
388  }
389
390  //Re-assigns the jqPlot variable, evals the string of series returned
391  //from getSeries which allows for any number of series
392  @(destinationTag)Plot = $.jqplot('@destinationTag', eval(getSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
393  </text>
394}
395
396@helper SlaveInfoChart(string destinationTag, string url, string limit, string startDate, string endDate, string userName, string functionName, string pageNumber=null)
397{
398  <text>
399  var GetRequest = "?limit=" + @(limit);
400  @if(startDate!=null) {
401    @:if(@(startDate)!=null) {
402      @:GetRequest += "&start=" + @startDate;
403    @:}
404  }
405  @if(endDate!=null) {
406    @:if(@(endDate)!=null) {
407      @:GetRequest += "&end=" + @endDate;
408    @:}
409  }
410  @if (userName != null) {
411    @:if(@(userName)!=null) {
412      @:GetRequest += "&userName=" + @userName;
413    @:}
414  }
415  $.ajax({
416    async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) {
417    $("#@(destinationTag)").html("");
418    var time = new Date();
419
420    //Checks if multipage display, if it is then trims results to
421    //the results for the page to be displayed
422    @ChartHelper.NumberPages("result",limit,destinationTag,functionName,pageNumber)
423
424    for(i = 0; i < result.length; i++) {
425      var coreSeries = [];
426      coreSeries[0] = [];
427      coreSeries[1] = [];
428      var memorySeries = [];
429      memorySeries[0] = [];
430      memorySeries[1] = [];
431      var cpuSeries = [];
432      cpuSeries[0] = [];
433      $("#@(destinationTag)").append('<section class="chartContainer"><h1 class="title" id="' + result[i][0].SlaveID + '">Slave '
434        + result[i][0].SlaveID + '</h1><button class="collapse" onclick="collapseSection(this)">+</button>' +
435        '<div id="TotalUsedCores' + result[i][0].SlaveID + '"></div><div id="TotalUsedMemory' + result[i][0].SlaveID + '"></div>' +
436        '<div id="CPUUtilization' + result[i][0].SlaveID + '"></div></section>');
437        for(j = 0; j < result[i].length; j++) {
438          time.setTime(result[i][j].Time.replace(/\D/g,''));
439          coreSeries[0].push([time.toUTCString(),result[i][j].TotalCores]);
440          coreSeries[1].push([time.toUTCString(),result[i][j].UsedCores]);
441          memorySeries[0].push([time.toUTCString(),(result[i][j].TotalMemory / 1000)]);
442          memorySeries[1].push([time.toUTCString(),(result[i][j].UsedMemory / 1000)]);
443          cpuSeries[0].push([time.toUTCString(),result[i][j].CPUUtilization]);
444        }
445      if(result[i].length > 1) {
446        @ChartHelper.LineChartGivenSeries("TotalUsedCores","result[i][0].SlaveID","coreSeries","Total/Used Cores")
447        @ChartHelper.LineChartGivenSeries("TotalUsedMemory","result[i][0].SlaveID","memorySeries","Total/Used Memory")
448        @ChartHelper.LineChartGivenSeries("CPUUtilization","result[i][0].SlaveID","cpuSeries","CPU Utilization",0,100,"%.1f%%")
449      }
450      else {
451        @ChartHelper.BarChartGivenSeries("TotalUsedCores","result[i][0].SlaveID","coreSeries","Total/Used Cores")
452        @ChartHelper.BarChartGivenSeries("TotalUsedMemory","result[i][0].SlaveID","memorySeries","Total/Used Memory")
453        @ChartHelper.BarChartGivenSeries("CPUUtilization","result[i][0].SlaveID","cpuSeries","CPU Utilization",0,100,"%.1f%%")
454      }
455      collapsedByDefault(document.getElementById("UsedTotalCores" + result[i][0].SlaveID));
456      collapsedByDefault(document.getElementById("UsedTotalMemory" + result[i][0].SlaveID));
457      collapsedByDefault(document.getElementById("CPUUtilization" + result[i][0].SlaveID));
458    }
459  }});
460  </text>
461}
462
463@helper LineChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null)
464{
465  <text>
466  window["@(destinationTag)" + @(chartId) + "Plot"] = $.jqplot("@(destinationTag)" + @(chartId), @series, {
467    title: "@title",
468    axes: {
469      xaxis: {
470        renderer: $.jqplot.DateAxisRenderer,
471        tickOptions:{formatString:'%b %#d, %y'},
472        pad: 0
473      },
474      yaxis: {
475        @if (axisYFormat != null) {
476          <text>
477          tickOptions: {
478              formatString: "@axisYFormat"
479          },
480          </text>
481        }
482        @if (minY != null) {
483            @:min: @minY,
484        }
485        @if (maxY != null) {
486            @:max: @maxY,
487        }
488        pad: 0
489      }
490    },
491    gridPadding: { left: 50, right: 10 },
492    cursor: {
493      show: true,
494      showTooltip: false,
495      zoom: true,
496      clickReset: false,
497      dblClickReset: false,
498      constrainZoomTo: 'x'
499    }
500  });
501
502  $(window).resize(function() {
503    window["@(destinationTag)" + @(chartId) + "Plot"].replot({ resetAxes: true });
504  });
505  </text>
506}
507
508@helper BarChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null)
509{
510  <text>
511  window["@(destinationTag)" + @(chartId) + "Plot"] = $.jqplot("@(destinationTag)" + @(chartId), @series, {
512    title: "@title",
513    seriesDefaults:{
514      renderer:$.jqplot.BarRenderer,
515      shadowAngle: 135,
516      pointLabels: {show: true, formatString: '%.2f'}
517    },
518    axes: {
519      xaxis: {
520        renderer: $.jqplot.CategoryAxisRenderer,
521        tickOptions:{formatString:'%b %#d, %y'},
522        pad: 0
523      },
524      yaxis: {
525        @if (axisYFormat != null) {
526          <text>
527          tickOptions: {
528              formatString: "@axisYFormat"
529          },
530          </text>
531        }
532        @if (minY != null) {
533            @:min: @minY,
534        }
535        @if (maxY != null) {
536            @:max: @maxY,
537        }
538        pad: 0
539      }
540    },
541    gridPadding: { left: 50, right: 10 },
542    cursor: {
543      show: true,
544      showTooltip: false,
545      zoom: true,
546      clickReset: false,
547      dblClickReset: false,
548      constrainZoomTo: 'x'
549    }
550  });
551
552  $(window).resize(function() {
553    $.each(window["@(destinationTag)" + @(chartId) + "Plot"].series, function(index, series) {
554      series.barWidth = undefined;
555    });
556    window["@(destinationTag)" + @(chartId) + "Plot"].replot({ resetAxes: true });
557  });
558
559  </text>
560}
Note: See TracBrowser for help on using the repository browser.