Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 11059 was 11059, checked in by mroscoe, 10 years ago
File size: 22.2 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(@(userName) == null) {
163        $("#@container").append(
164          '<section class="chartContainer">' +
165            '<h1 class="title">Please select a user!</h1>' +
166          '</section>'
167        )
168      }
169      else if(result.length==0) {
170        $("#@container").append(
171          '<section class="chartContainer">' +
172            '<h1 class="title">' + @userName + ' has no tasks for the specified filters!</h1>' +
173          '</section>'
174        )
175      }
176      else {
177        var waitTime;
178        var transferTime;
179        var runTime;
180        var seriesDescriptions = ["Time waiting","Time transferring","Time calculating"];
181
182        //Checks if multipage display, if it is then trims results to
183        //the results for the page to be displayed
184        @ChartHelper.NumberPages("result",limit,container,functionName,pageNumber)
185
186        //Globally accesible, for use when resizing, eliminates extra DB request
187        window["numberTasks"] = result.length;
188
189        //Set display of all errors to none, errors matching the tasks will be reset below
190        $("#@(container)").find(".errorContainer, .errorTitle, .errorTask, .errorMessage").css('display','none');
191
192        //For each result create a seperate collapsable section with a chart and info label
193        for(var i = 0; i < result.length; i++){
194          $("#" + "@container").append(
195            '<section class="chartContainer">' +
196              '<h1 class="title" id="@(container)' + result[i].Key + '">Task ' + result[i].Key + '</h1>' +
197              '<button class="collapse" onclick="CollapseSection(this)">+</button>' +
198              '<div id="@(destinationTag)Plot' + i + '"></div>' +
199              '<label id="@(destinationTag)PlotInfo' + i + '"></label>' +
200            '</section>'
201          )
202          //Re-enables the error display if any of the tasks on the page have Ids matching
203          //those of errors
204          $(".errorTask","#" + "@(container)").each(function() {
205            if($(this).html()==result[i].Key) {
206              $("#@(container)" + result[i].Key).css("color","red");
207              $("#@(container)" + result[i].Key).append(" - ERROR");
208              $(".errorContainer, .errorTitle, .underline").css('display','inline-block');
209              $(this).css('display','inline-block');
210              $(this).next().css('display','inline-block');
211            }
212          });
213          waitTime = [result[i].Value[0]];
214          transferTime = [result[i].Value[1]];
215          runTime = [result[i].Value[2]];
216          window["@(destinationTag)Plot" + i] = $.jqplot("@(destinationTag)Plot" + i, [waitTime,transferTime,runTime], {
217            seriesDefaults:{
218              renderer:$.jqplot.BarRenderer,
219              shadowAngle: 135,
220              pointLabels: {show: true, formatString: '%.3f'}
221            },
222            series:[
223              {label:'Waiting'},
224              {label:'Transferring'},
225              {label:'Calculating'}
226            ],
227            legend: {
228              show: true,
229              location: 'e',
230              placement: 'outside'
231            },
232            axes: {
233              xaxis: {
234                renderer: $.jqplot.CategoryAxisRenderer,
235                showLabel: false,
236                pad: 0
237              },
238              yaxis: {
239                pad: 0
240              }
241            },
242            cursor: {
243              showTooltip: false
244            }
245          });
246          /* Bind a datalistener to each chart and display details of clicked
247            upon data in the label below the chart */
248          $("#" + "@(destinationTag)Plot" + i).bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) {
249            $(this).siblings("label").html(seriesDescriptions[seriesIndex] + ": " + data[1]);
250          });
251
252          CollapsedByDefault(document.getElementById("@(container)" + result[i].Key));
253        }
254      }
255    }});
256  </text>
257}
258
259@helper ResizeTasks(string destinationTag)
260{
261  <text>
262  //Resize event, resets bar width for task charts and replots them
263  $(window).resize(function() {
264    if(typeof numberTasks !== 'undefined') {
265      for(var i = 0; i < numberTasks; i++) {
266        $.each(window[ "@(destinationTag)Plot" + i].series, function(index, series) {
267          series.barWidth = undefined;
268        });
269        if($("#@(destinationTag)Plot" + i).css("display") == "none") {
270          ResizeOpenClose($("#@(destinationTag)Plot" + i).siblings(".collapse"));
271          window["@(destinationTag)Plot" + i].replot({ resetAxes: true });
272          ResizeOpenClose($("#@(destinationTag)Plot" + i).siblings(".collapse"));
273        }
274        else {
275          window["@(destinationTag)Plot" + i].replot({ resetAxes: true });
276        }
277      }
278    }
279  });
280  </text>
281}
282
283@helper SetStreamingProperties(int refresh, int chartLength, int upperY) {
284  <text>
285  //Refresh time (in millisec)
286  var refreshRate = @(refresh);
287  //Number of data points on chart
288  var chartSize = @(chartLength);
289  //Amount to add to max Y value
290  var upperYBuffer = @(upperY);
291
292  //Used to return a string containing the names of the series
293  //to be used in plot creation
294  function GetSeries(numberData,dataName){
295    var result = "[";
296    for(i=0; i < numberData; i++) {
297      if(i < numberData -1) {
298        result += dataName + i + ",";
299      }
300      else {
301        result += dataName + i + "]";
302      }
303    }
304    return result;
305  }
306  </text>
307}
308
309@helper CreateStreamChart(string dataName, string destinationTag, string url, string title, string format = null, double? maxY = null) {
310  <text>
311  //Get current time, used to create initial values
312  var @(dataName)CurrentDate = (new Date()).getTime();
313
314  var @(dataName)Data = [];
315  var @(dataName)CurrentValue = [];
316
317  //Get the most recent value(s) from the given URL
318  $.ajax({
319    async: false, url: '@(url)', datatype: "json", success: function (result) {
320      for(i = 0; i < result.length; i++) {
321        @(dataName)CurrentValue[i] = result[i];
322      }
323    }
324  });
325 
326  //Create a chartSize worth of data using CurrentDate and CurrentValue
327  //for each CurrentValue
328  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
329    window["@(dataName)Data" + i] = [];
330    for (j = 0; j < chartSize; j++) {
331      window[ "@(dataName)Data" + i].push([@(dataName)CurrentDate - (chartSize - 1 - j) * refreshRate, @(dataName)CurrentValue[i]]);
332    }
333  }
334
335  //Options for the chart to be created
336  var @(destinationTag)PlotOptions = {
337    title: "@title",
338    axes: {
339      xaxis: {
340        numberTicks: 4,
341        renderer: $.jqplot.DateAxisRenderer,
342        tickOptions: { formatString: '%H:%M:%S' },
343        min: window["@(dataName)Data" + 0][0][0],
344        max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0]
345      },
346      yaxis: {
347        @if (format != null)
348        {<text>
349        tickOptions: {
350            formatString: "@format",
351        },
352        </text>}
353        min: 0,
354        @if (maxY != null) {
355          @:max: @maxY,
356        }
357        else{
358          @:max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer,
359        }
360        numberTicks: 6
361      }
362    },
363    seriesDefaults: {
364      rendererOptions: { smooth: true },
365      markerOptions: {
366        show: false
367      }
368    }
369  };
370
371  //Declares the jqPlot variable, evals the string of series returned
372  //from getSeries which allows for any number of series
373  window[ "@(destinationTag)Plot"] = $.jqplot('@destinationTag', eval(GetSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
374  </text>
375}
376
377@helper UpdateStreamChart(string dataName, string destinationTag, string url, string fixedY = null) {
378  <text>
379  //If the data is beyond chartSize use shift to trim one off the end
380  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
381    if (window["@(dataName)Data" + i].length > chartSize - 1) {
382      window["@(dataName)Data" + i].shift();
383    }
384  }
385
386  //Get the up-to-date data, each result assigned to it's own array
387  $.ajax({
388    async: false, url: '@(url)', datatype: "json", success: function (result) {
389      for(i = 0; i < result.length; i++) {
390        window[ "@(dataName)Data" + i].push([(new Date()).getTime(), result[i]]);
391      }
392    }
393  });
394
395  //If the plot exists currently destroy it
396  if ( @(destinationTag)Plot) {
397    @(destinationTag)Plot.destroy();
398  }
399
400  //Assign series
401  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
402    @(destinationTag)Plot.series[i].data = window["@(dataName)Data" + i];
403  }
404
405  //Recalculate x and possibly y axis max and mins
406  @(destinationTag)PlotOptions.axes.xaxis.min = window["@(dataName)Data" + 0][0][0];
407  @(destinationTag)PlotOptions.axes.xaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0];
408  @if (fixedY == null) {
409    @:@(destinationTag)PlotOptions.axes.yaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer;
410  }
411
412  //Re-assigns the jqPlot variable, evals the string of series returned
413  //from getSeries which allows for any number of series
414  @(destinationTag)Plot = $.jqplot('@destinationTag', eval(GetSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
415  </text>
416}
417
418@helper SlaveInfoChart(string destinationTag, string url, string limit, bool singleSlave, string startDate=null, string endDate=null, string userName=null, string functionName=null, string pageNumber=null, string slaveId=null) {
419  <text>
420  var GetRequest = "?limit=" + @(limit);
421  @if(startDate!=null) {
422    @:if(@(startDate)!=null) {
423      @:GetRequest += "&start=" + @startDate;
424    @:}
425  }
426  @if(endDate!=null) {
427    @:if(@(endDate)!=null) {
428      @:GetRequest += "&end=" + @endDate;
429    @:}
430  }
431  @if (userName != null) {
432    @:if(@(userName)!=null) {
433      @:GetRequest += "&userName=" + @userName;
434    @:}
435  }
436  @if (slaveId != null) {
437    @:if(@(slaveId)!=null) {
438      @:GetRequest += "&slaveId=" + @slaveId;
439    @:}
440  }
441  $.ajax({
442    async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) {
443
444    //Set chart names for use in creation below, must be set identically in
445    //ResizeSlaves
446    var slaveChartNames = ["TotalUsedCores","TotalUsedMemory","CPUUtilization"];
447
448    var destTag = eval("@(destinationTag)");
449    if(typeof eval("@(destinationTag)") != "string") {
450      destTag = "@(destinationTag)";
451    }
452
453    if(result.length == 0) {
454      $('#' + destTag).append(
455        '<section class="chartContainer">' +
456          '<h1 class="title">No slave information for the specified filters!</h1>' +
457        '</section>'
458      )
459    }
460    else {
461      var time = new Date();
462
463      @if(!singleSlave) {
464        @:$('#' + destTag).html("");
465
466        //Checks if multipage display, if it is then trims results to
467        //the results for the page to be displayed
468        @ChartHelper.NumberPages("result", limit, destinationTag, functionName, pageNumber)
469      }
470
471      //Globally accesible, for use when resizing, eliminates extra DB request
472      window["numberSlaves"] = result.length;
473
474      for(i = 0; i < result.length; i++) {
475        var coreSeries = [];
476        coreSeries[0] = [];
477        coreSeries[1] = [];
478        var memorySeries = [];
479        memorySeries[0] = [];
480        memorySeries[1] = [];
481        var cpuSeries = [];
482        cpuSeries[0] = [];
483        $('#' + destTag).append(
484          '<section class="chartContainer">' +
485            '<h1 class="title" id="' + result[i][0].SlaveID + '">Slave ' + result[i][0].SlaveID + '</h1>' +
486            '<button class="collapse" onclick="CollapseSection(this)">+</button>' +
487            '<div id="' + slaveChartNames[0] + 'Plot' + i + '"></div>' +
488            '<div id="' + slaveChartNames[1] + 'Plot' + i + '"></div>' +
489            '<div id="' + slaveChartNames[2] + 'Plot' + i + '"></div>' +
490          '</section>');
491        for(j = 0; j < result[i].length; j++) {
492          time.setTime(result[i][j].Time.replace(/\D/g,''));
493          coreSeries[0].push([time.toUTCString(),result[i][j].TotalCores]);
494          coreSeries[1].push([time.toUTCString(),result[i][j].UsedCores]);
495          memorySeries[0].push([time.toUTCString(),(result[i][j].TotalMemory / 1000)]);
496          memorySeries[1].push([time.toUTCString(),(result[i][j].UsedMemory / 1000)]);
497          cpuSeries[0].push([time.toUTCString(),result[i][j].CPUUtilization]);
498        }
499        if(result[i].length > 1) {
500          @ChartHelper.LineChartGivenSeries("slaveChartNames[0]","i","coreSeries","Total/Used Cores")
501          @ChartHelper.LineChartGivenSeries("slaveChartNames[1]","i","memorySeries","Total/Used Memory",0)
502          @ChartHelper.LineChartGivenSeries("slaveChartNames[2]","i","cpuSeries","CPU Utilization",0,100,"%.1f%%")
503        }
504        else {
505          @ChartHelper.BarChartGivenSeries("slaveChartNames[0]","i","coreSeries","Total/Used Cores")
506          @ChartHelper.BarChartGivenSeries("slaveChartNames[1]","i","memorySeries","Total/Used Memory",0)
507          @ChartHelper.BarChartGivenSeries("slaveChartNames[2]","i","cpuSeries","CPU Utilization",0,100,"%.1f%%")
508        }
509        for(k = 0; k < slaveChartNames.length; k++) {
510          CollapsedByDefault(document.getElementById(slaveChartNames[k] + "Plot" + i));
511        }
512      }
513    }
514  }});
515  </text>
516}
517
518@helper ResizeSlaves() {
519  <text>
520  //Resize event, resets bar width for slave charts and replots them
521  $(window).resize(function() {
522    if(typeof numberSlaves !== 'undefined') {
523
524      //Set chart names for use in creation below, must be set identically in
525      //SlaveInfoChart
526      var slaveChartNames = ["TotalUsedCores","TotalUsedMemory","CPUUtilization"];
527
528      for(i = 0; i < numberSlaves; i++) {
529        if($("#" + slaveChartNames[0] + "Plot" + i).css("display") == "none") {
530          ResizeOpenClose($("#" + slaveChartNames[0] + "Plot" + i).siblings(".collapse"));
531          for(j = 0; j < slaveChartNames.length; j++) {
532            $.each(window[slaveChartNames[j] + "Plot" + i].series, function(index, series) {
533              series.barWidth = undefined;
534            });
535            window[slaveChartNames[j] + "Plot" + i].replot({ resetAxes: true });
536          }
537          ResizeOpenClose($("#" + slaveChartNames[0] + "Plot" + i).siblings(".collapse"));
538        }
539        else {
540          for(j = 0; j < slaveChartNames.length; j++) {
541            $.each(window[slaveChartNames[j] + "Plot" + i].series, function(index, series) {
542              series.barWidth = undefined;
543            });
544            window[slaveChartNames[j] + "Plot" + i].replot({ resetAxes: true });
545          }
546        }
547      }
548    }
549  });
550  </text>
551}
552
553@helper LineChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null) {
554  <text>
555  window[@(destinationTag) + "Plot" + @(chartId)] = $.jqplot(@(destinationTag) + "Plot" + @(chartId), @series, {
556    title: "@title",
557    axes: {
558      xaxis: {
559        renderer: $.jqplot.DateAxisRenderer,
560        tickOptions:{formatString:'%b %#d, %y'},
561        pad: 0
562      },
563      yaxis: {
564        @if (axisYFormat != null) {
565          <text>
566          tickOptions: {
567              formatString: "@axisYFormat"
568          },
569          </text>
570        }
571        @if (minY != null) {
572            @:min: @minY,
573        }
574        @if (maxY != null) {
575            @:max: @maxY,
576        }
577        pad: 0
578      }
579    },
580    gridPadding: { left: 50, right: 10 },
581    cursor: {
582      show: true,
583      showTooltip: false,
584      zoom: true,
585      clickReset: false,
586      dblClickReset: false,
587      constrainZoomTo: 'x'
588    }
589  });
590  </text>
591}
592
593@helper BarChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null) {
594  <text>
595  window[@(destinationTag) + "Plot" + @(chartId)] = $.jqplot(@(destinationTag) + "Plot" + @(chartId), @series, {
596    title: "@title",
597    seriesDefaults:{
598      renderer:$.jqplot.BarRenderer,
599      shadowAngle: 135,
600      pointLabels: {show: true, formatString: '%.2f'}
601    },
602    axes: {
603      xaxis: {
604        renderer: $.jqplot.CategoryAxisRenderer,
605        tickOptions:{formatString:'%b %#d, %y'},
606        pad: 0
607      },
608      yaxis: {
609        @if (axisYFormat != null) {
610          <text>
611          tickOptions: {
612              formatString: "@axisYFormat"
613          },
614          </text>
615        }
616        @if (minY != null) {
617            @:min: @minY,
618        }
619        @if (maxY != null) {
620            @:max: @maxY,
621        }
622        pad: 0
623      }
624    },
625    gridPadding: { left: 50, right: 10 },
626    cursor: {
627      show: true,
628      showTooltip: false,
629      zoom: true,
630      clickReset: false,
631      dblClickReset: false,
632      constrainZoomTo: 'x'
633    }
634  });
635  </text>
636}
Note: See TracBrowser for help on using the repository browser.