Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.view.js @ 9395

Last change on this file since 9395 was 9395, checked in by fschoepp, 11 years ago

#1888:

  • Added visual extensions (dynamic JavaScript) which will be used to render additional result parameters specific to scenarios (e. g. create a graphical representation of a TSP).
  • Added relationship between jobs and experiments (otherwise, it's not possible to get the job's experiment).
  • Updated Admin page to allow removal/addition of visual extensions.
  • Added back-end logic to store/retrieve/delete visual extensions.
  • Added visual extension functionality to the JavaScript views/controllers (job.*.js).
  • Added tsp.js which is a visual extension for the "Genetic Algorithm - TSP" scenario. It adds a graphical representation of the TSP (just like the C# version does) to the results.
File size: 9.5 KB
Line 
1var OAAS_VIEW = (function (my, Backbone, _, $) {
2    // ================= VIEWS ===================
3    my.LoadingView = Backbone.View.extend({
4        render: function () {
5            this.$el.empty();
6            this.template = _.template($('#loadingTemplate').html());
7            $(this.template({ text: this.model })).appendTo(this.$el);
8        }
9    });
10
11    my.JobOverView = Backbone.View.extend({
12        events: {
13            'click tr': 'rowClicked',
14            'click button[data-name="DeleteButton"]': 'deleteClicked'
15        },
16        initialize: function () {
17            this.collection.bind('remove', this.render, this);
18        },
19        render: function () {
20            var prevSettings = null;
21            if (this.table) {
22                prevSettings = this.table.fnSettings();
23            }
24            this.$el.empty();
25            // create header
26            var table = $('<table />');
27            this.template = _.template($('#jobHeaderTemplate').html());
28            $(this.template({})).appendTo(table);
29
30            // create content
31            var tbody = $('<tbody />');
32            this.collection.each(function (model) {
33                var row = new my.JobOverViewRow({ model: model });
34                row.render();
35                row.$el.appendTo(tbody);
36            });
37            tbody.appendTo(table);
38            table.appendTo(this.$el);
39            if (prevSettings != null) {
40                this.table = table.dataTable({
41                    'aaSorting': prevSettings.aaSorting,
42                    'iDisplayLength' : prevSettings._iDisplayLength,
43                    'iDisplayStart' : prevSettings._iDisplayStart,
44                });
45                this.table.fnFilter(prevSettings.oPreviousSearch.sSearch);
46            } else {
47                this.table = table.dataTable();
48            }
49            this.highlightSelectedJob();
50        },
51        highlightSelectedJob: function () {
52            $('tr', this.table).removeClass('selectedRow');
53            if (this.selectedJob) {
54                $('tr[data-jobId="' + this.selectedJob + '"]', this.table).addClass('selectedRow');
55            }
56        },
57        rowClicked: function (row) {
58            var jobId = $(row.target).parent("tr").attr("data-jobId");
59            if (jobId) {
60                this.selectedJob = jobId;
61                this.highlightSelectedJob();
62                this.trigger('jobSelected', jobId);
63            }
64        },
65        deleteClicked: function (evt) {
66            var target = $(evt.target);
67            var id = target.attr('data-id');
68            var jobs = this.collection.where({ Id: id });
69            if (jobs.length == 1) {
70                jobs[0].destroy(); // triggers a remove event on this.collection -> DELETE /Job/1 will be called
71            }
72        }
73    });
74
75    my.JobOverViewRow = Backbone.View.extend({
76        render: function () {
77            this.template = _.template($('#jobRowTemplate').html());
78            this.setElement($(this.template(this.model.attributes)));
79        }
80    });
81
82    my.ResultView = Backbone.View.extend({
83        render: function () {
84            this.$el.empty();
85            var div = $('<h3/>').text('Compare with charts').appendTo(this.$el);
86            var div = $('<div/>').appendTo(this.$el);
87            var rcv = new my.RunCollectionView({model: this.model, el: div});
88            rcv.render();
89            for (var i = 0; i < this.model.models.length; i++) {
90                $('<h3></h3>').text(this.model.models[i].get('name')).appendTo(this.$el);
91                var rev = new my.ResultEntryView({ model: this.model.models[i], el: this.$el });
92                this.listenTo(rev, 'renderVisualExtension', this.renderVisualExtension);
93                rev.render();                         
94            }           
95        },
96        renderVisualExtension: function(model, element) {
97            // propagate to client listener
98            this.trigger('renderVisualExtension', model, element);
99        }
100    });
101
102    my.AccordionView = Backbone.View.extend({
103        render: function () {
104            this.$el.accordion({
105                heightStyle: 'content',
106                collapsible: true,
107                active: false
108            });
109        },
110        refresh: function () {
111            this.$el.accordtion("refresh");
112        }
113    });
114
115    my.ResizableView = Backbone.View.extend({
116        events: {
117            'resizestop': 'resized'
118        },
119        render: function () {
120            this.$el.resizable();
121        },
122        resized: function (evt) {
123            this.trigger('resized', evt);
124        }
125    });
126
127    my.TabView = Backbone.View.extend({
128        // model structure: [{ name:
129        events: {
130            'tabsactivate': 'tabActivated'
131        },
132        render: function () {
133            this.$el.empty();
134            var header = $('<ul />').appendTo(this.$el);
135            for (var i = 0; i < this.model.length; i++) {
136                var li = $('<li/>').appendTo(header);
137                var id = 'tab_' + my.PlotView.nextId() + '_' + i;
138                $('<a />').attr('href', '#' + id).text(this.model[i].name).appendTo(li);
139
140                var targetDiv = $('<div/>').attr('id', id).appendTo(this.$el);
141                $(this.model[i].content).appendTo(targetDiv);
142            }
143            this.$el.tabs({
144                collapsible: true,
145                active: false
146            });
147        },
148        tabActivated: function (event, ui) {
149            var tabElement = $(ui.newPanel[0]);
150            this.trigger('tab-activated', { name: ui.newTab.text(), element: tabElement });
151        }
152    });
153
154    my.ResultEntryView = Backbone.View.extend({
155        initialize: function () {
156            this.plotted = {};
157            this.plotted['params'] = {};
158            this.plotted['results'] = {};
159        },
160        render: function () {
161            this.template = _.template($('#runTemplate').html());
162            var table = $(this.template(this.model.attributes));
163            var body = $('tbody[class="results"]', table);
164            table.appendTo(this.$el);
165            // render the results of the model
166            var results = this.model.get('results');
167            for (var i = 0; i < results.length; i++) {
168                this.renderModelEntry(results[i], i, body, 'results');               
169            }
170            // get the visual extension, execute it!
171            this.trigger('renderVisualExtension', this.model, body);
172
173            var inputs = this.model.get('params');
174            body = $('tbody[class="inputs"]', table);
175            for (var i = 0; i < inputs.length; i++) {
176                this.renderModelEntry(inputs[i], i, body, 'params');
177            }
178
179            var av = new my.AccordionView({el: $(table)});
180            av.render();
181        },
182        renderModelEntry: function(entry, index, body, attribute) {         
183            var row = $('<tr/>').attr('data-index', index).attr('data-attribute', attribute);
184            $('<td/>').text(entry.Name).appendTo(row);
185            if ($.isArray(entry.Value)) {
186                var col = $('<td/>').appendTo(row);
187                var tevDiv = $('<div/>');
188                var plotDiv = $('<div/>').appendTo($('#tmp'));                               
189                this.plotted[attribute][index] = {};
190                var tv = new my.TabView({
191                    model: [
192                        { name: 'Table', content: tevDiv },
193                        { name: 'Plot', content: plotDiv },
194                    ],
195                    el: col
196                });
197                this.listenTo(tv, 'tab-activated', this.tabActivated);
198                tv.render();
199            }
200            else {
201                $('<td/>').text(entry.Value).appendTo(row);
202            }
203            row.appendTo(body);
204        },
205        tabActivated: function (evt) {
206            var index = parseInt(evt.element.parents('tr').attr('data-index'));
207            var attribute = evt.element.parents('tr').attr('data-attribute');
208            if (evt.name == 'Plot' && !this.plotted[attribute][index].Plot) {
209                this.plotted[attribute][index].Plot = true;
210                var plotDiv = $('<div/>').appendTo($('#tmp'));
211                var pv = new my.PlotView({ model: this.model.get(attribute)[index], el: plotDiv, transpose: true });
212                pv.render();
213                plotDiv.appendTo(evt.element);
214                var rv = new my.ResizableView({ el: evt.element });
215
216                this.listenTo(rv, 'resized', function (evt) {
217                    plotDiv.height($(evt.target).height() * 0.96);
218                    plotDiv.width($(evt.target).width() * 0.96);
219                    pv.refresh();
220                });
221                rv.render();
222                plotDiv.width(rv.$el.width());
223                plotDiv.height(rv.$el.height());
224                pv.refresh();
225            } else if (evt.name == 'Table' && !this.plotted[attribute][index].Table) {
226                this.plotted[attribute][index].Table = true;
227                var tevDiv = $('<div/>').css('overflow', 'scroll');
228                var tev = new my.TableEditView({ model: this.model.get(attribute)[index].Value, rowNames: this.model.get(attribute)[index].RowNames, useDatatable: true, el: tevDiv });
229                tev.render();
230                tevDiv.appendTo(evt.element)
231            }
232        }
233    });
234    return my;
235} (OAAS_VIEW || {}, Backbone, _, $));
Note: See TracBrowser for help on using the repository browser.