Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/11/13 14:40:04 (12 years ago)
Author:
fschoepp
Message:

#1888:

  • Added an Update / GetExperiment... methods to the controller for updating and querying experiments.
  • The AlgorithmConverter class now properly converts from/to JSON format.
  • Integrated backbone js as MVC provider for JavaScript + jquery.
  • Added experiment.model.js + experiment.view.js + experiment.controller.js containing the MVC impl. for the Experiment pages.
  • Added new methods to the ExperimentController usable by the backbone js model implementation.
  • Added the experiment dialog from HL 3.3.7 (variate experiment parameters). It's capable of variating the algorithm parameters.
Location:
branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment/Index.cshtml

    r9215 r9305  
    6060@section submenu {
    6161    <ul>
    62         <li class="selected">@Html.ActionLink("Build", "Index")</li>   
    63         <li>@Html.ActionLink("Edit", "Edit")</li>
     62        <li class="selected">@Html.ActionLink("Build", "New")</li>   
     63        <li>@Html.ActionLink("Edit", "NewEdit")</li>
    6464        <li>@Html.ActionLink("Status", "Index", "Status")</li>
    6565    </ul>
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment/New.cshtml

    r9227 r9305  
    11@model HeuristicLab.Services.Optimization.Web.Models.ExperimentViewModel
    2 @{
    3     ViewBag.Title = "Index.cshtml";
    4 }
    5 
     2<script type="text/template" id="node_template">
     3  <li><%= title%></li> 
     4</script>
     5
     6<script type="text/template" id="tree_template">
     7  <div id="<%= id %>" class="treeStyle">
     8    <ul>     
     9    </ul>
     10  </div>
     11</script>
     12
     13<script type="text/template" id="draggable_template">
     14  <div id="<%= nodeId %>" data-isExperiment="<%= isExperiment%>" data-name="<%= title%>" class="dragables"><p><%= title %></p></div>
     15</script>
     16
     17<script type="text/template" id="stepwizard_template">
     18  <input style="margin-top:5px;" class="remove-button" name="RemoveNode" type="button" value="Remove" disabled="disabled" />
     19  <input style="margin-top:5px;" class="variate-button" name="VariateNode" type="button" value="Variate" disabled="disabled" />
     20</script>           
     21
     22<script type="text/template" id="parameter_template">
     23<div>
     24  <div class="leftEntry"><%= Name %>:</div>
     25  <div class="rightEntry"></div> 
     26</div>
     27</script>       
     28
     29<script type="text/template" id="validationhints_template">
     30<div class="validator" title="<%= header %>">
     31  <p><span class="ui-icon ui-icon-alert" style="float: left; margin: 0 7px 20px 0;"></span>
     32  <%= text %>
     33  </p>
     34</div>
     35</script>       
     36
     37<script type="text/template" id="variationdialog_template">
     38<div class="variationDialog" title="Variate algorithm">
     39  <h1>Select parameter</h1>
     40  <select class="variationDialogContent"> 
     41  </select>
     42  <input type="checkbox" name="active" /> Active
     43  <div class="variationDetails">         
     44  </div> 
     45</div>
     46</script>       
     47
     48<script type="text/template" id="variationentry_template">
     49<option data-index='<%= Index %>'><%= Name %></option>
     50</script>       
     51
     52<script type="text/template" id="variationcontent_template">
     53<div>
     54 
     55 
     56</div>
     57</script>       
     58
     59<script type="text/template" id="variation_boolean_template">
     60<p>Boolean paramter: True / False</p>
     61</script>       
     62
     63<script type="text/template" id="variation_number_template">
     64<div>
     65    <input type="button" name="generate" value="Generate..."/>   
     66    <div></div>
     67</div>
     68</script>       
     69
     70<script type="text/template" id="checkbox_template">
     71<div>
     72    <input type="checkbox" name="<%=name%>"/><%=text%><br/>
     73</div>
     74</script>       
     75
     76<script type="text/template" id="variation_generator_template">
     77<div title="Generate Values">
     78 <div class="leftEntry">Minimum:</div>
     79 <div class="rightEntry"><input type="text" name="minimum" value="0"/></div> 
     80 <div class="leftEntry">Maximum:</div>
     81 <div class="rightEntry"><input type="text" name="maximum" value="2"/></div> 
     82 <div class="leftEntry">Step:</div>
     83 <div class="rightEntry"><input type="text" name="step" value="1"/></div> 
     84</div>
     85</script>       
     86
     87<script type="text/template" id="loading_template">
     88<div>
     89  <p>Loading ... </p>
     90  <img src="@Url.Content("~/Content/ajax-loader.gif")" alt="Loading animation" class="loader" /> 
     91</div>
     92</script>   
    693
    794<script type="text/javascript">
    8   function Experiment() {
    9     this.algorithms = [];
    10     this.nodeMapping = {};
    11     this.name = "My Experiment"
    12   }
    13    
    14   Experiment.prototype.buildAndStore = function(node, index, tree, ctx) {
    15     var result = this.build(node, index, tree, 'Experiment');
    16     this.algorithms = result.algorithms;
    17     this.nodeMapping = result.mapping;
    18   }
    19 
    20   Experiment.prototype.build = function(node, index, tree, ctx) {
    21     var stack = new Array();
    22     var root = {name : node.title, children: [], context: ctx};
    23     var nodeMapping = {};
    24     this.fetchNode(root, node, index, tree);
    25     if (node.title != 'Experiment')
    26       nodeMapping[node.key] = root;
    27      
    28     if (node.children)
    29         for (var i=0; i < node.children.length; i++) {
    30           stack.push({parent: root, child: node.children[node.children.length - 1 - i], index: node.children.length - 1 - i});
    31         }
    32     while(stack.length > 0) {
    33       var tmp = stack.pop();
    34       var parent = tmp.parent;
    35       var child = tmp.child;
    36       var newChild = { name : child.title, children: [], context: ctx}
    37       // fetch the nodes from the server
    38       this.fetchNode(newChild, child, tmp.index, tree);
    39       nodeMapping[tmp.child.key] = newChild;     
    40       parent.children.push(newChild);
    41       if (child.children)
    42           for (var i=0; i < child.children.length; i++) {
    43             stack.push({parent: newChild, child: child.children[child.children.length - 1 - i], index: child.children.length - 1 - i});
    44           }
    45     }
    46     return {algorithms: root, mapping: nodeMapping};
    47   }
    48 
    49   Experiment.prototype.fetchNode = function(modelNode, dynaNode, index, tree) {
    50     if (modelNode.name == 'Experiment')
    51       return;
    52     var self = this;
    53     var node = tree.getNodeByKey(dynaNode.key);
    54     $.ajax({
    55         type: "GET",
    56         url: '/Experiment/GetParameters',
    57         data: { scenario: modelNode.name, context: modelNode.context, index: index },
    58         contentType: "application/json; charset=utf-8",
    59         dataType: "json",
    60         success: function (result) {
    61             if (result.Type == "Complex") {
    62                 // extend the tree element
    63                 node.removeChildren();
    64                 var parent = self.nodeMapping[node.data.key];
    65                 for (var i=0; i < result.Subnames.length; i++) {
    66                     // add node to dynatree
    67                     var childNode = node.addChild({title: result.Subnames[i]});
    68                     var internalResult = self.build(childNode.toDict(true), i, tree, modelNode.name); 
    69                     parent.children.push(internalResult.algorithms);
    70                     for (var attrname in internalResult.mapping) { self.nodeMapping[attrname] = internalResult.mapping[attrname]; }                 
    71                 }
    72             } else if (result.Type == "Basic") {     
    73                 // replace the wizard   
    74                 previousWizards[node.data.key] = replaceWizard(result);
    75                 saveParameters(previousWizards[node.data.key], node);
    76             }
    77         }
     95    var controller = new ExperimentPageController();
     96    $(document).ready(function () {
     97        controller.create();
    7898    });
    79   }
    80 
    81   Experiment.prototype.pushNode = function(parentKey, nodeKey, entryName, ctx) {
    82     var entry = {name: entryName, children: [], context: ctx};
    83     this.nodeMapping[parentKey].children.push(entry);
    84     this.nodeMapping[nodeKey] = entry;
    85   }
    86 
    87   var experiment = new Experiment();
    88   var previousWizards = {};
    89 
    90   function saveExperiment() {
    91     $('.buttonFinish').attr('disabled', 'disabled');
    92     experiment["name"] = $('#name').val();
    93     experiment["run"] = $('#runImmediately').attr('checked') == 'checked';
    94     experiment["repititions"] = $('#repititions').val();
    95     experiment["group"] = $('#group').val();
    96 
    97      $.ajax({ type: "POST",
    98       url: '/Experiment/SaveExperiment',
    99       data: JSON.stringify(experiment),
    100       contentType: "application/json; charset=utf-8",
    101       dataType: "json",
    102       success: function (result) {
    103         $('#status-dialog').dialog("open");
    104       },
    105       error: function (result) {
    106       }
    107      });
    108   }
    109 
    110   function treeIndexOf(sibling) {
    111     var i = 0;
    112     var prev = sibling.getPrevSibling()
    113     while (prev != null) {
    114         i++;
    115         prev = prev.getPrevSibling()
    116     }
    117     return i;
    118   }
    119 
    120   function saveParameters(wiz, node) {
    121     var wiz = typeof wiz !== 'undefined' ? $(wiz) : $('.wizard', '#parameter-dialog-content');
    122     var id = wiz.attr('id');
    123     var node = typeof node !== 'undefined' ? node : $('#container2').dynatree("getActiveNode");
    124     var data = {};   
    125 
    126     for (var i = 1; i < 3; i++) {
    127       var stepId = '#' + id + '_' + i;
    128       var step = $(stepId);
    129       if (step.length == 0) {
    130         break;
    131       }
    132       var stepDesc = $('a[href="' + stepId + '"] span', wiz).contents()[0].data;
    133       var dataEntries = $('input, select', step);
    134       var entry = { };
    135       var mapper = new DatatypeMapper();
    136       for (var j = 0; j < dataEntries.length; j++) {
    137         entry[dataEntries[j].name] = mapper.mapString(dataEntries[j].value);
    138       }
    139       data[stepDesc] = entry;
    140     }
    141    
    142     // aggregate tables:
    143     var mapper = new DatatypeMapper();
    144     mapper.aggregateTables(data);
    145 
    146     var experimentEntry = experiment.nodeMapping[node.data.key];
    147     // we are at the node, update data
    148     experimentEntry["data"] = data;
    149     // Close dialog
    150     $('#params').dialog("close");
    151   }
    152 
    153   function createParamterDiv(name, parameters) {
    154     var mapper = new DatatypeMapper();
    155     // get algorithm parameters
    156     var paramsDiv = $('<div />').data("name", name);
    157     for (var i=0; i < parameters.length; i++) {
    158       var property = parameters[i];
    159       var content = mapper.mapHtml(property.Value);
    160 
    161       // add to canvas             
    162       $('<h2/>').text(property.Value.Name).appendTo(paramsDiv);
    163       content.appendTo(paramsDiv);
    164       $('<div />').addClass('clearer').appendTo(paramsDiv);
    165     }
    166     return paramsDiv;
    167   }
    168 
    169   function createWizard(name, steps) {
    170     var wizard = $('<div />', { id: name }).addClass('wizard swMain');
    171     var stepMenu = $('<ul />');
    172     var prefix = name + '_';
    173     for (var i = 0; i < steps.length; i++) {
    174       var step = steps[i];
    175       var a = $('<a></a>', {href: '#' + prefix + (i + 1)});
    176       $('<label />').addClass("stepNumber").text((i + 1)).appendTo(a);
    177       $('<span />').addClass("stepDesc").html(step.heading + '<br /><small>' + step.description + '</small>').appendTo(a);
    178       var li = $('<li />').append(a);
    179       li.appendTo(stepMenu);
    180     }
    181     stepMenu.appendTo(wizard);
    182     for (var i = 0; i < steps.length; i++) {
    183       var div = $('<div />', { id: prefix + (i + 1) });
    184       if (steps[i].content && steps[i].content != null)
    185         div.append(steps[i].content);
    186       div.appendTo(wizard);
    187     }
    188     return wizard;
    189   }
    190 
    191 
    192   function makeTree() {
    193     var tree = $('#container').dynatree({
    194       onActivate: function (node) {
    195         if (node && node.data.title !== "Experiment") {
    196           $('input[name="RemoveNode"]').removeAttr("disabled");
    197         } else if (node) {
    198           $('input[name="RemoveNode"]').attr("disabled", "disabled");
    199         }
    200       },
    201       onDeactivate: function (node) {
    202       },
    203       dnd: {
    204         autoExpandMS: 750,
    205 
    206         onDragStart: function (node) {
    207           return node.data.title !== "Experiment";
    208         },
    209         onDragEnter: function (node, sourceNode) {
    210           return true;
    211         },
    212         onDragOver: function (node, sourceNode, hitMode) {
    213           return node.data.title !== "Experiment" || hitMode === "over";
    214         },
    215         onDrop: function (node, sourceNode, hitMode, ui, draggable) {
    216           if (sourceNode) {
    217             sourceNode.move(node, hitMode);
    218           }
    219           else {
    220             newNode = { title: draggable.element[0].id };
    221             if (hitMode == "over") {
    222               node.addChild(newNode);
    223               node.expand(true);
    224             }
    225             else if (hitMode == "before") {
    226               node.parent.addChild(newNode, node);
    227             }
    228             else {
    229               node.parent.addChild(newNode, node.getNextSibling());
    230             }
    231           }
    232         },
    233         onDragLeave: function (node, sourceNode) {
    234         }
    235       }
    236     });
    237 
    238     $('.dragables').each(function () {
    239       $(this).draggable({
    240         revert: true,
    241         connectToDynatree: true,
    242         cursorAt: { top: -5, left: -5 },
    243         helper: "clone"
    244       });
    245     });
    246 
    247     $('input[name="RemoveNode"]').click(function () {
    248       var node = $("#container").dynatree("getActiveNode");
    249       if (node && node.data.title !== "Experiment")
    250         node.remove();
    251       $(this).attr("disabled", "disabled");
    252     });
    253   }
    254 
    255   function leaveStep(obj) {
    256     var stepNum = obj.attr("rel");
    257     return validateStep(stepNum);
    258   }
    259 
    260   function validateStep(stepNum) {
    261     var isStepValid = true;
    262     if (stepNum == 1) {
    263       previousWizards = {}
    264       experiment = new Experiment();
    265       var data = $("#container").dynatree("getTree").toDict().children;
    266       $("#container2").dynatree({
    267         onActivate: editElement
    268       });
    269       var rootNode = $("#container2").dynatree("getRoot");
    270       rootNode.removeChildren();
    271       rootNode.addChild(data);
    272       // based on the data rebuild the experiment
    273       experiment.buildAndStore(data[0], 0, $("#container2").dynatree("getTree"));
    274     }
    275     return isStepValid;
    276   }
    277 
    278   function resetDialog() {
    279     var canvas = $('#parameter-dialog-content');
    280     canvas.empty();
    281     $('<img />').attr('alt', 'Loading animation').attr('src', '@Url.Content("~/Content/ajax-loader.gif")').attr('class', 'loader').appendTo(canvas);
    282     $('<div />').text("Loading...").appendTo(canvas);       
    283   }
    284 
    285   globalCounter = 0;
    286 
    287   function replaceWizard(result) {
    288     var canvas = $('#parameter-dialog-content');
    289     canvas.empty();
    290 
    291     // get parameters as div
    292     var algoParamsDiv = null;
    293 
    294     if (result.Algorithm.Parameters) {
    295         algoParamsDiv = createParamterDiv("Algorithm Parameters", result.Algorithm.Parameters.Items);
    296     }
    297 
    298     var problemParamsDiv = null;
    299     if (result.Algorithm.Problem && result.Algorithm.Problem.Parameters) {
    300      problemParamsDiv = createParamterDiv("Problem Parameters", result.Algorithm.Problem.Parameters.Items);
    301     }
    302 
    303     var wizard = null;
    304     if (result.Algorithm.Problem)
    305      wizard = createWizard("TestWizard", [
    306         { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoParamsDiv },
    307         { heading: "Problem Parameters", description: "Adjust problem parameters", content: problemParamsDiv }
    308     ]);
    309     else
    310      wizard = createWizard("TestWizard", [
    311         { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoParamsDiv }
    312     ]);
    313 
    314     wizard.appendTo(canvas);
    315     $(".wizard", canvas).smartWizard({
    316         onFinish: saveParameters,
    317         labelFinish: 'Save'
    318     });
    319     return wizard;
    320   }
    321 
    322   function editElement(node) {
    323     resetDialog();
    324     $("#params").dialog("open");
    325     // if we opened this windows before, use the previously created wizard
    326     if (node.data.key in previousWizards) {
    327       var canvas = $('#parameter-dialog-content');
    328       canvas.empty(); 
    329       $(previousWizards[node.data.key]).appendTo(canvas);
    330       var wiz = $(".wizard", canvas).smartWizard({
    331         onFinish: saveParameters,
    332         labelFinish: 'Save'
    333       });
    334       // we have to recreate the wizard, otherwise it is not responsive -> remove some multiple occuring wizard elements.
    335       var parent = $('.stepContainer.content', wiz).parent('.stepContainer:not(.content)');
    336       var elem = $('.stepContainer.content .content', wiz).detach();
    337       elem.appendTo(parent);
    338       $('.stepContainer.content', wiz).detach();
    339       $('.actionBar.content', wiz).detach();
    340     }
    341     else {
    342         $.ajax({
    343           type: "GET",
    344           url: '/Experiment/GetParameters',
    345           data: { scenario: node.data.title, context: experiment.nodeMapping[node.data.key].context, index: treeIndexOf(node) },
    346           contentType: "application/json; charset=utf-8",
    347           dataType: "json",
    348           success: function (result) {
    349             if (result.Type == "Complex") $("#params").dialog("close");
    350             /*if (result.Type == "Complex") {
    351               // extend the tree element     
    352               $("#params").dialog("close");     
    353               node.removeChildren();
    354               for (var i=0; i < result.Subnames.length; i++) {
    355                 // add node to dynatree
    356                 var childNode = node.addChild({title: result.Subnames[i]});
    357                 // add node to model
    358                 experiment.pushNode(node.data.key, childNode.data.key, result.Subnames[i], node.data.title);
    359               }
    360             } else*/
    361             if (result.Type == "Basic") {     
    362               // replace the wizard   
    363               previousWizards[node.data.key] = replaceWizard(result);
    364               saveParameters(previousWizards[node.data.key], node);
    365             }
    366           }
    367         });
    368      }
    369   }
    370 
    371   $(document).ready(function () {
    372     var wiz = $(".wizard").smartWizard({
    373       /*updateHeight: false*/
    374       onLeaveStep: leaveStep,
    375       onFinish: saveExperiment
    376     });
    377     makeTree();
    378 
    379     $("#params").dialog({
    380       autoOpen: false,
    381       width: 1024,
    382       height: 768,
    383       /*modal: true,
    384       buttons: {
    385         "Save parameters": function () {
    386          
    387         }
    388         ,
    389         "Cancel": function () {
    390           $(this).dialog("close");
    391         }
    392       },
    393       close: function () {
    394       }*/
    395     });
    396 
    397     $("#status-dialog").dialog({
    398       autoOpen: false,
    399       resizable: false,
    400       height: 100,
    401       modal: true,
    402       buttons: { "OK" : function() { $(this).dialog('close'); $('.buttonFinish').removeAttr('disabled'); } }
    403     });
    404 
    405     $('#runImmediately').change(
    406         function() {
    407             if ($(this).is(':checked')) {
    408                 $('#repititions').removeAttr('disabled');
    409                 $('#group').removeAttr('disabled');
    410             }
    411             else {
    412                 $('#repititions').attr('disabled', 'disabled');
    413                 $('#group').attr('disabled', 'disabled');
    414             }
    415         });
    416   });
    417 </script>
     99</script>
     100<noscript>
     101    <p>You need JavaScript to view this page! Please activate it in your browser settings.</p>
     102</noscript>
    418103
    419104<h2>Experiment</h2>
    420105
    421 <div class="wizard swMain">
     106<div id="stepWizard" class="wizard swMain">
    422107  <ul>
    423108    <li>
     
    450135  </ul>
    451136  <div id="step1">
    452   @using (Html.BeginForm("TreeData", "Tree"))
    453   {
    454137  <fieldset>   
    455138    <div>
    456139    <p>Experiment Tree:</p>
    457140    </div>
    458 
    459     <div id="container" class="treeStyle">
    460       <ul>
    461         <li id="root">Experiment</li>
    462       </ul>
    463     </div>
    464     <input style="margin-top:5px;"  name="RemoveNode" type="button" value="Remove" disabled="disabled" />
    465 
    466    
    467      @if (Model.Scenarios.Count > 0) {
    468         <p>Choose an algorithm:</p>
    469         foreach (var scen in Model.Scenarios) {
    470             <div class="dragables" id="@scen"><p>@scen</p></div>
    471         }       
    472         <div class="clearer"/>   
    473      }
    474    
    475     @if (Model.Scenarios.Count > 0) {
    476         <p>Choose from your stored experiments:</p>
    477         foreach (var scen in Model.Experiments) {
    478             <div class="dragables" id="@scen"><p>@scen</p></div>
    479         }
    480         <div class="clearer"/>
    481     }   
    482    
     141    <div id="container" class="treeStyle"></div>   
     142    <p>Choose an algorithm:</p>
     143    <div id="algorithms"></div>
     144    <div class="clearer"></div>
     145    <p>Choose from your stored experiments:</p>
     146    <div id="experiments"></div>
    483147  </fieldset>
    484   }
    485148  </div>
    486149  <div id="step2">
    487   <h2>Click on a experiment to adjust its parameters:</h2>
    488   <div id="container2" class="treeStyle">
    489       <ul>
    490         <li>Experiment</li>
    491       </ul>
    492     </div>
     150    <h2>Click on a experiment to adjust its parameters:</h2>
     151    <div id="container2" class="treeStyle"></div>
    493152  </div>
    494153  <div id="step3">
     
    524183      <input id="group" name="Group" type="text" value="TESTAZURE" disabled="disabled" />
    525184    </div>
    526   </div> 
    527 </div>
    528 
    529 <div id="status-dialog">
    530     <div>
    531       Experiment has been saved!
    532     </div>           
    533 </div>
    534 
    535 <div id="params" title="Update parameters">
    536     <!-- Note: The content must be loaded asynchronously -->
    537     <div id="parameter-dialog-content">
    538       <img src="@Url.Content("~/Content/ajax-loader.gif")" alt="Loading animation" class="loader" />
    539       Loading ...     
    540     </div>
    541            
    542   </div>
     185  </div>   
     186</div>
     187
     188<div id="parameterDialog">
     189  <div id="parameterDialog-content">
     190  </div>
     191</div>
     192
     193<div id="loadingDialog">
     194</div>
     195
     196@section submenu {
     197    <ul>
     198        <li class="selected">@Html.ActionLink("Build", "New")</li>   
     199        <li>@Html.ActionLink("Edit", "NewEdit")</li>
     200        <li>@Html.ActionLink("Status", "Index", "Status")</li>
     201    </ul>
     202}
Note: See TracChangeset for help on using the changeset viewer.