@* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . *@ @helper AjaxDataRenderer() { } @helper LineChartTime(string destinationTag, string url, string title = "", double? minY = null, double? maxY = null, string axisYFormat = null) { } @helper RefreshChart(string destinationTag, string url, string startDate, string endDate, double? minY = null, double? maxY = null) { $.ajax({url: "@(new HtmlString(url))?start=" + @startDate + "&end=" + @endDate, datatype: "json", success: function(result) { for (var i = 0; i < result.length; i++) { @(destinationTag)Plot.series[i].data = result[i]; } //Resets only the xaxis, still need to resize y with given min/max @(destinationTag)Plot.replot({resetAxes:true}); @if (minY != null) { //If min Y was provided set the plot's min Y value @:@(destinationTag)Plot.axes.yaxis.min = @minY; } @if (maxY != null) { //If max Y was provided set the plot's max Y value @:@(destinationTag)Plot.axes.yaxis.max = @maxY; } @(destinationTag)Plot.axes.yaxis.reset(); //A final replot to redraw possible new Y axis values @(destinationTag)Plot.replot({resetAxes:['xaxis']}); @* @(destinationTag)Plot.replot({ resetAxes:true });*@ }}); } @helper ResizeCharts() { function resizeCharts(caller) { //If current plot is collapsed if($(caller).css("display") == "none") { //Display the contents of chartContainer ResizeOpenClose($(caller).siblings(".collapse")); //Reset barWidth for bar charts $.each(window[caller.id].series, function(index, series) { series.barWidth = undefined; }); //Replot the chart with same name as element id window[caller.id].replot({ resetAxes: false }); //Hide the contents of the current div ResizeOpenClose($(caller).siblings(".collapse")); } //Current plot is expanded else { //Reset barWidth for bar charts $.each(window[caller.id].series, function(index, series) { series.barWidth = undefined; }); //Replot the chart with same name as element id window[caller.id].replot({ resetAxes: false }); } } $(window).resize(function() { $("div.jqplot-target",".chartContainer").each(function() { var potentialTab = $(this).parent().parent().parent(); //If the section is tabular and currently hidden if(potentialTab.hasClass("tabSection") && potentialTab.css("display") == "none") { ResizeOpenCloseTabular(potentialTab); resizeCharts(this); ResizeOpenCloseTabular(potentialTab); } else { resizeCharts(this); } }); }); } @helper NumberPages(string records, string limit, string container, string functionName, string currentPage = null) { if(@(records).length > @limit) { var appendPages = '
'; var pages = Math.floor(@(records).length/@(limit)) + 1; for(var i=0; i < pages; i++) { appendPages += '' + (i + 1) + ''; } appendPages += '
'; $("#@container").append(appendPages); if(@currentPage != null) { $("#@(container)Page" + @currentPage).css('color','#F7921D'); } else { $("#@(container)Page1").css('color','#F7921D'); } $(".page").click(function () { pageNumber = $(this).html(); @(functionName)(); }); if(@currentPage != null) { @(records).splice(0,(@(currentPage)-1)*@(limit)); if (@(records).length > @(limit)) { @(records).splice(@(limit), @(records).length - @(limit)); } } else { @(records).splice(@(limit), @(records).length - @(limit)); } }
} @helper TaskContainers(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) { var GetRequest = "?userName=" + @(userName); @if (startDate != null) { @:if(@(startDate)!=null) { @:GetRequest += "&start=" + @startDate; @:} } @if (endDate != null) { @:if(@(endDate)!=null) { @:GetRequest += "&end=" + @endDate; @:} } @if (jobId != null) { @:if(@(jobId)!=null) { @:GetRequest += "&jobId=" + @jobId; @:} } @if (taskState != null) { @:if(@(taskState)!=null) { @:GetRequest += "&taskState=" + @taskState; @:} } $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { if(@(userName) == null) { $("#@(destinationTag)").append( '
' + '

Please select a user!

' + '
' ) } else if(result.length==0) { $("#@(destinationTag)").append( '
' + '

' + @userName + ' has no tasks for the specified filters!

' + '
' ) } else { //Checks if multipage display, if it is then trims results to //the results for the page to be displayed @ChartHelper.NumberPages("result", limit, destinationTag, functionName, pageNumber) //Set display of all errors to none, errors matching the tasks will be reset below $("#@(destinationTag)").find(".errorContainer, .errorTitle, .errorTask, .errorMessage").css('display','none'); //Set variable for tracking jobId and open first job grouping var currentJob = result[0].JobId; //For each result create a seperate collapsable section with a chart and info label for(var i = 0; i < result.length; i++){ if(currentJob != result[i].JobId || i == 0) { $("#@(destinationTag)").append( '
' + '

' + result[i].JobName + '

' + '
' + '

Job Overview - ' + result[i].JobName + '

' + '' + '
' + '' + '
' + '
' ); CollapsedByDefault(document.getElementById("@(destinationTag)JobOverviewPlot" + i)); currentJob = result[i].JobId; } $("#" + currentJob).append( '
' + '

Task ' + result[i].TaskId + '

' + '' + '
' + '' + 'More Info' + '
' ); //Re-enables the error display if any of the tasks on the page have Ids matching //those of errors $(".errorTask","#" + "@(destinationTag)").each(function() { if($(this).html()==result[i].TaskId) { $("#@(destinationTag)" + result[i].TaskId + "PlotTitle").css("color","red"); $("#@(destinationTag)" + result[i].TaskId + "PlotTitle").append(" - ERROR"); $(".errorContainer, .errorTitle, .underline","#@(destinationTag)").css('display','inline-block'); $(this).css('display','inline-block'); $(this).next().css('display','inline-block'); } }); CollapsedByDefault(document.getElementById("@(destinationTag)Plot" + i)); } } }});
} @helper LoadJob(string url) { function LoadJob(caller) { CheckFilters(); if($(caller).next().html()=="") { var plotName = $(caller).next().attr('id'); //Set current job id var jobId = $(caller).parent().parent().attr('id'); var GetRequest = "?jobId=" + jobId; $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { CollapseSection(caller); var seriesDescription = ['Waiting','Transferring','Calculating','Finished','Error']; window[plotName] = $.jqplot(plotName, [[result.Wait],[result.Transfer],[result.Calculate],[result.Finish],[result.Error]], { seriesDefaults:{ renderer:$.jqplot.BarRenderer, shadowAngle: 135, pointLabels: {show: true, formatString: '%.0f'} }, series:[ {label:seriesDescription[0]}, {label:seriesDescription[1]}, {label:seriesDescription[2]}, {label:seriesDescription[3]}, {label:seriesDescription[4]} ], legend: { show: true, location: 'e', placement: 'outside' }, axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, showLabel: false, pad: 0 }, yaxis: { padMax: 1.5 } }, cursor: { showTooltip: false } }); /* Bind a datalistener to each chart and display details of clicked upon data in the label below the chart */ $("#" + plotName).bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) { $(this).next("label").html("Tasks " + seriesDescription[seriesIndex] + ": " + data[1]); }); }}); } else { CollapseSection(caller); } } } @helper LoadTask(string url) { function LoadTask(caller) { CheckFilters(); if($(caller).next().html()=="") { var plotName = $(caller).next().attr('id'); //Set current slave id var currentTask = $(caller).siblings('a.moreInfo').attr('id'); var GetRequest = "?taskId=" + currentTask; $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { var waitTime; var transferTime; var runTime; var seriesDescriptions = ["Time waiting","Time transferring","Time calculating"]; CollapseSection(caller); for(i = 0; i < result.length; i++) { waitTime = [result[i].TotalWaiting]; transferTime = [result[i].TotalTransfer]; runTime = [result[i].TotalRuntime]; window[plotName] = $.jqplot(plotName, [waitTime,transferTime,runTime], { seriesDefaults:{ renderer:$.jqplot.BarRenderer, shadowAngle: 135, pointLabels: {show: true, formatString: '%.3f'} }, series:[ {label:'Waiting'}, {label:'Transferring'}, {label:'Calculating'} ], legend: { show: true, location: 'e', placement: 'outside' }, axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, showLabel: false, pad: 0 }, yaxis: { pad: 0 } }, cursor: { showTooltip: false } }); /* Bind a datalistener to each chart and display details of clicked upon data in the label below the chart */ $("#" + plotName).bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) { $(this).next("label").html(seriesDescriptions[seriesIndex] + ": " + data[1].toFixed(4) + " seconds"); }); } }}); } else { CollapseSection(caller); } } } @helper SetStreamingProperties(int refresh, int chartLength, int upperY) { //Refresh time (in millisec) var refreshRate = @(refresh); //Number of data points on chart var chartSize = @(chartLength); //Amount to add to max Y value var upperYBuffer = @(upperY); //Used to return a string containing the names of the series //to be used in plot creation function GetSeries(numberData,dataName){ var result = "["; for(i=0; i < numberData; i++) { if(i < numberData -1) { result += dataName + i + ","; } else { result += dataName + i + "]"; } } return result; } } @helper CreateStreamChart(string dataName, string destinationTag, string url, string title, string slaveState, string format = null, double? maxY = null) { //Get current time, used to create initial values var @(dataName)CurrentDate = (new Date()).getTime(); var @(dataName)Data = []; var @(dataName)CurrentValue = []; //Get the most recent value(s) from the given URL $.ajax({ async: false, url: "@(url)?state=" + @(slaveState), datatype: "json", success: function (result) { for(i = 0; i < result.length; i++) { @(dataName)CurrentValue[i] = result[i]; } } }); //Create a chartSize worth of data using CurrentDate and CurrentValue //for each CurrentValue for(i = 0; i < @(dataName)CurrentValue.length; i++) { window["@(dataName)Data" + i] = []; for (j = 0; j < chartSize; j++) { window[ "@(dataName)Data" + i].push([@(dataName)CurrentDate - (chartSize - 1 - j) * refreshRate, @(dataName)CurrentValue[i]]); } } //Options for the chart to be created var @(destinationTag)PlotOptions = { title: "@title", highlighter: { show: true, sizeAdjust: 7.5 }, axes: { xaxis: { numberTicks: 4, renderer: $.jqplot.DateAxisRenderer, tickOptions: { formatString: '%H:%M:%S' }, min: window["@(dataName)Data" + 0][0][0], max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0] }, yaxis: { @if (format != null) { tickOptions: { formatString: "@format", }, } min: 0, @if (maxY != null) { @:max: @maxY, } else { @:max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer, } numberTicks: 5 } }, seriesDefaults: { rendererOptions: { smooth: true }, markerOptions: { show: false } }, cursor: { show: true, showTooltip: false, zoom: true, clickReset: false, dblClickReset: false, constrainZoomTo: 'x' } }; //Declares the jqPlot variable, evals the string of series returned //from getSeries which allows for any number of series window[ "@(destinationTag)Plot"] = $.jqplot('@destinationTag', eval(GetSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions); } @helper UpdateStreamChart(string dataName, string destinationTag, string url, string slaveState, string fixedY = null) { //If the data is beyond chartSize use shift to trim one off the end for(i = 0; i < @(dataName)CurrentValue.length; i++) { if (window["@(dataName)Data" + i].length > chartSize - 1) { window["@(dataName)Data" + i].shift(); } } //Get the up-to-date data, each result assigned to it's own array $.ajax({ async: false, url: "@(url)?state=" + @(slaveState), datatype: "json", success: function (result) { for(i = 0; i < result.length; i++) { window[ "@(dataName)Data" + i].push([(new Date()).getTime(), result[i]]); } } }); //If the plot exists currently destroy it if ( @(destinationTag)Plot) { @(destinationTag)Plot.destroy(); } //Assign series for(i = 0; i < @(dataName)CurrentValue.length; i++) { @(destinationTag)Plot.series[i].data = window["@(dataName)Data" + i]; } //Recalculate x and possibly y axis max and mins @(destinationTag)PlotOptions.axes.xaxis.min = window["@(dataName)Data" + 0][0][0]; @(destinationTag)PlotOptions.axes.xaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0]; @if (fixedY == null) { @:@(destinationTag)PlotOptions.axes.yaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer; } //Re-assigns the jqPlot variable, evals the string of series returned //from getSeries which allows for any number of series @(destinationTag)Plot = $.jqplot('@destinationTag', eval(GetSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions); } @helper SlaveContainers(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) { var GetRequest = ""; @if (startDate != null) { @:if(@(startDate)!=null) { @:if(GetRequest == "") { @:GetRequest += "?start=" + @startDate; @:} @:else { @:GetRequest += "&start=" + @startDate; @:} @:} } @if (endDate != null) { @:if(@(endDate)!=null) { @:if(GetRequest == "") { @:GetRequest += "?end=" + @endDate; @:} @:else { @:GetRequest += "&end=" + @endDate; @:} @:} } @if (userName != null) { @:if(@(userName)!=null) { @:if(GetRequest == "") { @:GetRequest += "?userName=" + @userName; @:} @:else { @:GetRequest += "&userName=" + @userName; @:} @:} } @if (slaveId != null) { @:if(@(slaveId)!=null) { @:if(GetRequest == "") { @:GetRequest += "?slaveId=" + @slaveId; @:} @:else { @:GetRequest += "&slaveId=" + @slaveId; @:} @:} } $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { //Set chart names for use in creation below, must be set identically in LoadSlave and ResizeSlaves var slaveChartNames = ["TotalUsedCores","TotalUsedMemory","CPUUtilization"]; @if (!singleSlave) { @:$('#@(destinationTag)').html(""); //Checks if multipage display, if it is then trims results to //the results for the page to be displayed @ChartHelper.NumberPages("result", limit, destinationTag, functionName, pageNumber) @:var destTag = "@(destinationTag)"; } else { @:var destTag = @(destinationTag); } if(result.length == 0) { @if (!singleSlave) { @:$('#' + destTag).html(""); } $('#' + destTag).append( '
' + '

No slave information for the specified filters!

' + '
' ) } for(i = 0; i < result.length; i++) { $('#' + destTag).append( '
' + '

Slave ' + result[i][0].ClientName + '

' + '' + '
' + '
' + '
' + 'More Info' + '
'); for(k = 0; k < slaveChartNames.length; k++) { CollapsedByDefault(document.getElementById(destTag + slaveChartNames[k] + "Plot" + result[i][0].SlaveID)); } } }});
} @helper LoadSlave(string url, string limit, string startDate = null, string endDate = null, string userName = null, string pageNumber = null) { function LoadSlave(caller) { CheckFilters(); if($(caller).next().html()=="") { var destTag = $(caller).parent().parent().attr('id'); //Set current slave id var currentSlave = $(caller).siblings('a.moreInfo').attr('id'); var GetRequest = "?slaveId=" + currentSlave; @if (startDate != null) { @:if(@(startDate)!=null) { @:GetRequest += "&start=" + @startDate; @:} } @if (endDate != null) { @:if(@(endDate)!=null) { @:GetRequest += "&end=" + @endDate; @:} } @if (userName != null) { @:if(@(userName)!=null) { @:GetRequest += "&userName=" + @userName; @:} } $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { //Set chart names for use in creation below, must be set identically in SlaveContainers and ResizeSlaves var slaveChartNames = ["TotalUsedCores","TotalUsedMemory","CPUUtilization"]; CollapseSection(caller); var time = new Date(); var coreSeries = []; coreSeries[0] = []; coreSeries[1] = []; var memorySeries = []; memorySeries[0] = []; memorySeries[1] = []; var cpuSeries = []; cpuSeries[0] = []; for(i = 0; i < result.length; i++) { time.setTime(result[i].Time.replace(/\D/g,'')); coreSeries[0].push([time.toUTCString(),result[i].TotalCores]); coreSeries[1].push([time.toUTCString(),result[i].UsedCores]); memorySeries[0].push([time.toUTCString(),(result[i].TotalMemory / 1000)]); memorySeries[1].push([time.toUTCString(),(result[i].UsedMemory / 1000)]); cpuSeries[0].push([time.toUTCString(),result[i].CPUUtilization]); } if(result.length > 1) { @ChartHelper.LineChartGivenSeries("destTag + slaveChartNames[0]", "currentSlave", "coreSeries", "Total/Used Cores") @ChartHelper.LineChartGivenSeries("destTag + slaveChartNames[1]", "currentSlave", "memorySeries", "Total/Used Memory", 0) @ChartHelper.LineChartGivenSeries("destTag + slaveChartNames[2]", "currentSlave", "cpuSeries", "CPU Utilization", 0, 100, "%.1f%%") } else { @ChartHelper.BarChartGivenSeries("destTag + slaveChartNames[0]", "currentSlave", "coreSeries", "Total/Used Cores") @ChartHelper.BarChartGivenSeries("destTag + slaveChartNames[1]", "currentSlave", "memorySeries", "Total/Used Memory", 0) @ChartHelper.BarChartGivenSeries("destTag + slaveChartNames[2]", "currentSlave", "cpuSeries", "CPU Utilization", 0, 100, "%.1f%%") } }}); } else { CollapseSection(caller); } } } @helper LineChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null) { window[@(destinationTag) + "Plot" + @(chartId)] = $.jqplot(@(destinationTag) + "Plot" + @(chartId), @series, { title: "@title", axes: { xaxis: { renderer: $.jqplot.DateAxisRenderer, tickOptions:{formatString:'%b %#d, %y'}, pad: 0 }, yaxis: { @if (axisYFormat != null) { tickOptions: { formatString: "@axisYFormat" }, } pad: 0, @if (minY != null) { @:min: @minY, } @if (maxY != null) { @:max: @maxY, } } }, gridPadding: { left: 50, right: 10 }, cursor: { show: true, showTooltip: false, zoom: true, clickReset: false, dblClickReset: false, constrainZoomTo: 'x' } }); } @helper BarChartGivenSeries(string destinationTag, string chartId, string series, string title, double? minY = null, double? maxY = null, string axisYFormat = null) { window[@(destinationTag) + "Plot" + @(chartId)] = $.jqplot(@(destinationTag) + "Plot" + @(chartId), @series, { title: "@title", seriesDefaults:{ renderer:$.jqplot.BarRenderer, shadowAngle: 135, pointLabels: {show: true, formatString: '%.2f'} }, axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, tickOptions:{formatString:'%b %#d, %y'}, pad: 0 }, yaxis: { @if (axisYFormat != null) { tickOptions: { formatString: "@axisYFormat" }, } pad: 0, @if (minY != null) { @:min: @minY, } @if (maxY != null) { @:max: @maxY, } } }, gridPadding: { left: 50, right: 10 }, cursor: { show: true, showTooltip: false, zoom: true, clickReset: false, dblClickReset: false, constrainZoomTo: 'x' } }); } @helper UserTasks(string url, string insertAfter, string taskState) { var GetRequest = "?taskState=@(taskState)"; $.ajax({ async: false, url: "@(new HtmlString(url))" + GetRequest, datatype: "json", success: function(result) { if(result.length==0) { $("@(insertAfter)").after( '
' + '

No users currently have any tasks ' + @(taskState) + '!

' + '
' ) } else { $("@(insertAfter)").after( '
' + '

@(taskState) Tasks

' + '' + '
' + '' + '
' ); } var userTasks = []; var userNameLabels = []; var userNames = []; for (i=0; i < result.length; i++) { userTasks[i] = [result[i].Value]; userNameLabels[i] = { label: result[i].Key }; userNames[i] = result[i].Key; } window["UserTask@(taskState)Plot"] = $.jqplot("UserTask@(taskState)Plot", userTasks, { title: "Users with @(taskState) Tasks", seriesDefaults:{ renderer:$.jqplot.BarRenderer, shadowAngle: 135, pointLabels: {show: true, formatString: '%.3f'} }, series: userNameLabels, legend: { show: true, location: 'e', placement: 'outside' }, axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, showTicks: false, pad: 0 }, yaxis: { padMax: 1.5 } }, cursor: { showTooltip: false } }); /* Bind a datalistener to each chart and display details of clicked upon data in the label below the chart */ $("#UserTask" + "@(taskState)Plot").bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) { $(this).next("label").html(userNames[seriesIndex] + " Tasks @(taskState): " + data[1]); }); }});
}