1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/4ec6ff7c4165/ Changeset: 4ec6ff7c4165 User: guerler Date: 2014-03-06 06:48:58 Summary: Ui/Charts: Enable job submission, revise data access, generalize framework, update elements Affected #: 25 files diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/app.js --- a/config/plugins/visualizations/charts/static/app.js +++ b/config/plugins/visualizations/charts/static/app.js @@ -1,10 +1,10 @@ // dependencies -define(['mvc/ui/ui-portlet', 'plugin/library/ui', 'utils/utils', - 'plugin/views/charts', 'plugin/views/viewport', 'plugin/views/chart', - 'plugin/models/config', 'plugin/models/datasets', 'plugin/models/chart', 'plugin/models/charts', 'plugin/models/types'], - function( Portlet, Ui, Utils, - ChartsView, ViewportView, ChartView, - Config, Datasets, Chart, Charts, Types +define(['mvc/ui/ui-portlet', 'plugin/library/ui', 'utils/utils', 'plugin/library/jobs', 'plugin/library/datasets', + 'plugin/views/charts', 'plugin/views/chart', + 'plugin/models/config', 'plugin/models/chart', 'plugin/models/charts', 'plugin/models/types'], + function( Portlet, Ui, Utils, Jobs, Datasets, + ChartsView, ChartView, + Config, Chart, Charts, Types ) { // widget @@ -17,11 +17,14 @@ this.options = options; // link galaxy - this.modal = parent.Galaxy.modal; + this.modal = Galaxy.modal; // create configuration model this.config = new Config(); + // job/data /processor + this.jobs = new Jobs(this); + // create chart models this.types = new Types(); this.chart = new Chart(); @@ -33,11 +36,7 @@ // create views this.charts_view = new ChartsView(this); this.chart_view = new ChartView(this); - this.viewport_view = new ViewportView(this); - // append view port to charts viewer - this.charts_view.append(this.viewport_view.$el); - // create portlet if (!this.options.config.widget) { this.portlet = new Portlet.View({icon : 'fa-bar-chart-o'}); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/bardiagram.js --- a/config/plugins/visualizations/charts/static/charts/bardiagram.js +++ b/config/plugins/visualizations/charts/static/charts/bardiagram.js @@ -11,21 +11,25 @@ }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - self.d3_chart = nv.models.multiBarChart(); + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + self.d3_chart = nv.models.multiBarChart(); - self.d3_chart.xAxis.tickFormat(d3.format('.2f')) - self.d3_chart.yAxis.tickFormat(d3.format('.1f')) - - d3.select(self.options.svg_id) - .datum(data) - .call(self.d3_chart); - - nv.utils.windowResize(self.d3_chart.update); + self.d3_chart.xAxis.tickFormat(d3.format('.2f')) + self.d3_chart.yAxis.tickFormat(d3.format('.1f')) + + self.options.svg.datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/histogram.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/histogram.js @@ -0,0 +1,49 @@ +// dependencies +define([], function() { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + }, + + // plot + plot: function(chart, request_dictionary) { + + // update request dataset id + request_dictionary.id = chart.get('dataset_id_job'); + + // configure request + var index = 0; + for (var i in request_dictionary.groups) { + var group = request_dictionary.groups[i]; + group.columns = { + x: index++, + y: index++ + } + } + + // send request + var self = this; + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + self.d3_chart = nv.models.multiBarChart(); + + self.d3_chart.xAxis.tickFormat(d3.format('.2f')) + self.d3_chart.yAxis.tickFormat(d3.format('.1f')) + + self.options.svg.datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + + chart.set('state', 'ok'); + }); + }); + } +}); + +}); \ No newline at end of file diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/horizontal.js --- a/config/plugins/visualizations/charts/static/charts/horizontal.js +++ b/config/plugins/visualizations/charts/static/charts/horizontal.js @@ -8,24 +8,28 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - self.d3_chart = nv.models.multiBarHorizontalChart(); - - self.d3_chart.xAxis.tickFormat(function() { return ''; }); - - d3.select(self.options.svg_id) - .datum(data) - .call(self.d3_chart); - - nv.utils.windowResize(self.d3_chart.update); + this.app.datasets.request(request_dictionary, function(data) { + // add graph to screen + nv.addGraph(function() { + self.d3_chart = nv.models.multiBarHorizontalChart(); + + self.d3_chart.xAxis.tickFormat(function() { return ''; }); + + self.options.svg.datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/line.js --- a/config/plugins/visualizations/charts/static/charts/line.js +++ b/config/plugins/visualizations/charts/static/charts/line.js @@ -8,30 +8,31 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - self.chart_3d = nv.models.lineChart(); + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + self.chart_3d = nv.models.lineChart(); - self.chart_3d.xAxis - .tickFormat(d3.format(',f')); + self.chart_3d.xAxis + .tickFormat(d3.format(',f')); - self.chart_3d.yAxis - .tickFormat(d3.format(',.2f')); - - d3.select(self.options.svg_id) - .datum(data) - .call(self.chart_3d); + self.chart_3d.yAxis + .tickFormat(d3.format(',.2f')); + + self.options.svg.datum(data) + .call(self.chart_3d); - nv.utils.windowResize(self.chart_3d.update); - - return self.chart_3d; + nv.utils.windowResize(self.chart_3d.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/linewithfocus.js --- a/config/plugins/visualizations/charts/static/charts/linewithfocus.js +++ b/config/plugins/visualizations/charts/static/charts/linewithfocus.js @@ -8,28 +8,31 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - self.chart_3d = nv.models.lineWithFocusChart(); + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + self.chart_3d = nv.models.lineWithFocusChart(); - self.chart_3d.xAxis - .tickFormat(d3.format(',f')); + self.chart_3d.xAxis + .tickFormat(d3.format(',f')); - self.chart_3d.yAxis - .tickFormat(d3.format(',.2f')); - - d3.select(self.options.svg_id) - .datum(data) - .call(self.chart_3d); + self.chart_3d.yAxis + .tickFormat(d3.format(',.2f')); + + self.options.svg.datum(data) + .call(self.chart_3d); - nv.utils.windowResize(self.chart_3d.update); + nv.utils.windowResize(self.chart_3d.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/piechart.js --- a/config/plugins/visualizations/charts/static/charts/piechart.js +++ b/config/plugins/visualizations/charts/static/charts/piechart.js @@ -8,43 +8,46 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // loop through data groups - for (var key in data) { - // get group - var group = data[key]; + // request data + var self = this; + this.app.datasets.request(request_dictionary, function(data) { - // format chart data - var pie_data = []; - for (var key in group.values) { - var value = group.values[key]; - pie_data.push ({ - key : value.x, - y : value.y + // loop through data groups + for (var key in request_dictionary.groups) { + // get group + var group = request_dictionary.groups[key]; + + // format chart data + var pie_data = []; + for (var key in group.values) { + var value = group.values[key]; + pie_data.push ({ + key : value.x, + y : value.y + }); + } + + // add graph to screen + nv.addGraph(function() { + self.chart_3d = nv.models.pieChart() + .donut(true) + .showLegend(false); + + self.options.svg.datum(pie_data) + .call(self.chart_3d); + + nv.utils.windowResize(self.chart_3d.update); + + // set chart state + chart.set('state', 'ok'); }); } - - // add graph to screen - var self = this; - nv.addGraph(function() { - self.chart_3d = nv.models.pieChart() - .donut(true) - .showLegend(false); - - d3.select(self.options.svg_id) - .datum(pie_data) - .call(self.chart_3d); - - nv.utils.windowResize(self.chart_3d.update); - - return self.chart_3d; - }); - } + }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/scatterplot.js --- a/config/plugins/visualizations/charts/static/charts/scatterplot.js +++ b/config/plugins/visualizations/charts/static/charts/scatterplot.js @@ -8,28 +8,31 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - self.d3_chart = nv.models.scatterChart() - .showDistX(true) - .showDistY(true) - .color(d3.scale.category10().range()); + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + self.d3_chart = nv.models.scatterChart() + .showDistX(true) + .showDistY(true) + .color(d3.scale.category10().range()); + + self.d3_chart.xAxis.tickFormat(d3.format('.02f')) + self.d3_chart.yAxis.tickFormat(d3.format('.02f')) - self.d3_chart.xAxis.tickFormat(d3.format('.02f')) - self.d3_chart.yAxis.tickFormat(d3.format('.02f')) - - d3.select(self.options.svg_id) - .datum(data) - .call(self.d3_chart); - - nv.utils.windowResize(self.d3_chart.update); + self.options.svg.datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/charts/stackedarea.js --- a/config/plugins/visualizations/charts/static/charts/stackedarea.js +++ b/config/plugins/visualizations/charts/static/charts/stackedarea.js @@ -8,50 +8,35 @@ initialize: function(app, options) { this.app = app; this.options = options; - this.chart = options.chart; }, // render - refresh : function(data) + plot : function(chart, request_dictionary) { - // add graph to screen + // request data var self = this; - nv.addGraph(function() { - // check data - var valid = true; - var length = 0; - for (var key in data) { - // evalute length - if (length == 0) { - length = data[key].values.length; - } else { - if (length != data[key].values.length) { - valid = false; - break; - } - } - } - if (!valid) { - return; - } - - // make plot - self.d3_chart = nv.models.stackedAreaChart() - .x(function(d) { - return d.x - }) - .y(function(d) { - return d.y - }) - .clipEdge(true); - - self.d3_chart.xAxis.tickFormat(function() { return ''; }); - - d3.select(self.options.svg_id) - .datum(data) - .call(self.d3_chart); - - nv.utils.windowResize(self.d3_chart.update); + this.app.datasets.request(request_dictionary, function(data) { + nv.addGraph(function() { + // make plot + self.d3_chart = nv.models.stackedAreaChart() + .x(function(d) { + return d.x + }) + .y(function(d) { + return d.y + }) + .clipEdge(true); + + self.d3_chart.xAxis.tickFormat(function() { return ''; }); + + self.options.svg.datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + + // set chart state + chart.set('state', 'ok'); + }); }); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/library/datasets.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/datasets.js @@ -0,0 +1,137 @@ +// dependencies +define(['utils/utils'], function(Utils) { + +// widget +return Backbone.Collection.extend( +{ + // initialize + initialize: function(app, options) + { + // link app + this.app = app; + + // configure options + this.options = Utils.merge(options, this.optionsDefault); + }, + + // wait + request: function(options, success, error) { + // link this + var self = this; + + // wait for dataset + Utils.request('GET', config.root + 'api/datasets/' + options.id, {}, function(dataset) { + switch (dataset.state) { + case 'error': + if (error) { + error(dataset); + } + break; + default: + if (options.groups) { + self._fetch(options, success); + } else { + success(dataset); + } + } + }); + }, + + // fetch data columns into dataset object + _fetch: function(options, callback) { + // set offset + var offset = options.start ? options.start : 0; + + // set limit + var limit = Math.abs(options.end - options.start); + var query_limit = this.app.config.get('query_limit'); + if (!limit || limit > query_limit) { + limit = query_limit; + } + + // get column indices + var index_string = ''; + var index_map = {}; + var index_count = 0; + for (var i in options.groups) { + var group = options.groups[i]; + for (var key in group.columns) { + var column = group.columns[key]; + + // add to index string + index_string += column + ','; + + // add to dictionary + index_map[column] = index_count; + + // increase counter + index_count++; + } + } + if (index_count == 0) { + callback({}); + return; + } + index_string = index_string.substring(0, index_string.length - 1); + + // initialize result dictionary + var result = options.groups.slice(0); + for (var i in result) { + result[i].values = []; + } + + // make request + var self = this; + Utils.request('GET', config.root + 'api/datasets/' + options.id, { + data_type : 'raw_data', + provider : 'dataset-column', + limit : limit, + offset : offset, + indeces : index_string + }, function(response) { + + // loop through rows + for (var i in response.data) { + // get row + var row = response.data[i]; + + // collect all data into the defined groups + for (var j in options.groups) { + // get group + var group = options.groups[j]; + + // initialize value + var value = { + x : parseInt(i) + offset + }; + + // fill value + for (var key in group.columns) { + // get column + var column = group.columns[key]; + + // identify column + var index = index_map[column]; + + // read value from row + var v = row[index]; + if(isNaN(v)) { + v = 0; + } + + // add value to dictionary + value[key] = v; + } + + // add to result + result[j].values.push(value); + } + } + + // callback + callback(result); + }); + } +}); + +}); \ No newline at end of file diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/library/jobs.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/jobs.js @@ -0,0 +1,98 @@ +// dependencies +define(['utils/utils'], function(Utils) { + +// widget +return Backbone.Model.extend( +{ + // initialize + initialize: function(app, options) { + // link app + this.app = app; + + // link options + this.options = Utils.merge(options, this.optionsDefault); + }, + + // create job + submit: function(chart, request_string, callback) { + // link this + var self = this; + + // backup chart details + var chart_id = chart.id; + var chart_type = chart.get('type'); + + // get chart settings + var chart_settings = this.app.types.get(chart_type); + + // configure tool + data = { + 'tool_id' : 'rkit', + 'history_id' : chart.history_id, + 'inputs' : { + 'input' : chart.dataset_hid, + 'module' : chart_type, + 'options' : request_string + } + } + + // set chart state + chart.state('submit', 'Sending job request...'); + + // post job + Utils.request('POST', config.root + 'api/tools', data, + // success handler + function(response) { + if (!response.outputs || response.outputs.length == 0) { + chart.state('failed', 'Job submission failed. No response.'); + self.app.log('handle::load()', 'Job submission failed.'); + } else { + // update galaxy history + Galaxy.currHistoryPanel.refreshHdas(); + + // get dataset + var job = response.outputs[0]; + + // check dataset + chart.state('queued', 'Job has been queued...'); + + // backup resulting dataset id + chart.set('dataset_id_job', job.id); + + // wait for job completion + self._loop(job.id, function(job) { + switch (job.state) { + case 'ok': + chart.state('ok', 'Job completed successfully...'); + callback(job); + return true; + case 'error': + chart.state('failed', 'Job has failed. Please check the history for details.'); + return true; + case 'running': + chart.state('running', 'Job is running...'); + return false; + } + }); + } + }, + // error handler + function(response) { + chart.state('failed', 'Job submission failed.'); + self.app.log('handle::load()', 'Job submission failed.'); + } + ); + }, + + // request job details + _loop: function(id, callback) { + var self = this; + Utils.request('GET', config.root + 'api/jobs/' + id, {}, function(job) { + if (!callback(job)) { + setTimeout(function() { self._loop(id, callback); }, self.app.config.get('query_timeout')); + } + }); + } +}); + +}); \ No newline at end of file diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/library/table.js --- a/config/plugins/visualizations/charts/static/library/table.js +++ b/config/plugins/visualizations/charts/static/library/table.js @@ -82,9 +82,12 @@ // remove remove: function(id) { - this.$tbody.find('#' + id).remove(); - this.row_count--; - this._refresh(); + var item = this.$tbody.find('#' + id); + if (item.length > 0) { + item.remove(); + this.row_count--; + this._refresh(); + } }, // remove @@ -129,6 +132,9 @@ // commit _commit: function(id, prepend) { + // remove previous item with same id + this.remove(id); + // add this.row.attr('id', id); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/library/ui.select.js --- a/config/plugins/visualizations/charts/static/library/ui.select.js +++ b/config/plugins/visualizations/charts/static/library/ui.select.js @@ -8,9 +8,14 @@ optionsDefault: { id : '', cls : '', - empty : 'No data available' + empty : 'No data available', + visible : true, + wait : false }, + // value + selected : null, + // initialize initialize : function(options) { // configure options @@ -19,70 +24,102 @@ // create new element this.setElement(this._template(this.options)); + // link elements + this.$select = this.$el.find('#select'); + this.$wait = this.$el.find('#wait'); + // initial value - if (this.options.value) { - this.$el.val(this.options.value); - } + this.selected = this.options.value; // add change event var self = this; if (this.options.onchange) { - this.$el.on('change', function() { self.options.onchange(self.value()); }); + this.$select.on('change', function() { + self.value(self.$select.val()); + }); } // refresh this._refresh(); + + // show/hide + if (!this.options.visible) { + this.hide(); + } + + // wait + if (this.options.wait) { + this.wait(); + } }, // value value : function (new_value) { + // get current id/value - var before = this.$el.val(); + var before = this.selected; // check if new_value is defined if (new_value !== undefined) { - this.$el.val(new_value); + this.selected = new_value; + this.$select.val(new_value); } // get current id/value - var after = this.$el.val(); - if(after === undefined) { - return null; - } else { + var after = this.selected; + if(after) { // fire onchange - if ((after != before && this.options.onchange) || this.$el.find('option').length == 1) { + if ((after != before && this.options.onchange)) { this.options.onchange(after); } - - // return current value - return after; } + + // return + return after; }, // label text : function () { - return this.$el.find('option:selected').text(); + return this.$select.find('option:selected').text(); + }, + + // show + show: function() { + this.$wait.hide(); + this.$select.show(); + this.$el.show(); + }, + + // hide + hide: function() { + this.$el.hide(); + }, + + // wait + wait: function() { + this.$select.hide(); + this.$wait.css('display','inline-block'); }, // disabled disabled: function() { - return this.$el.is(':disabled'); + return this.$select.is(':disabled'); }, // enable enable: function() { - this.$el.prop('disabled', false); + this.$select.prop('disabled', false); }, // disable disable: function() { - this.$el.prop('disabled', true); + this.$select.prop('disabled', true); }, // add add: function(options) { // add options - $(this.el).append(this._templateOption(options)); + this.$select.append(this._templateOption(options)); // refresh this._refresh(); @@ -91,8 +128,8 @@ // remove del: function(value) { // remove option - $(this.el).find('option[value=' + value + ']').remove(); - $(this.el).trigger('change'); + this.$select.find('option[value=' + value + ']').remove(); + this.$select.trigger('change'); // refresh this._refresh(); @@ -100,20 +137,18 @@ // render update: function(options) { - // selected - var selected = this.$el.val(); - // remove all options - $(this.el).find('option').remove(); + this.$select.find('option').remove(); // add new options - for (var key in options.data) { - $(this.el).append(this._templateOption(options.data[key])); + for (var key in options) { + this.$select.append(this._templateOption(options[key])); } - // add selected value - if (this._exists(selected)) - $(this.el).val(selected); + // select first option if nothing else is selected + if (!this.selected && options.length > 0) { + this.value(options[0].value); + } // refresh this._refresh(); @@ -122,23 +157,31 @@ // refresh _refresh: function() { // remove placeholder - $(this.el).find('option[value=null]').remove(); + this.$select.find('option[value=null]').remove(); // count remaining entries - var remaining = $(this.el).find('option').length; + var remaining = this.$select.find('option').length; if (remaining == 0) { // append placeholder - $(this.el).append(this._templateOption({value : 'null', label : this.options.empty})); + this.$select.append(this._templateOption({value : 'null', label : this.options.empty})); this.disable(); } else { + // enable select field this.enable(); + + // update selected value + if (this.selected) { + //if (this._exists(selected)) { + this.$select.val(this.selected); + //} + } } }, // exists _exists: function(value) { // check if selected value exists - return 0 != $(this.el).find('option[value=' + value + ']').length; + return 0 != this.$select.find('option[value=' + value + ']').length; }, // option @@ -148,21 +191,24 @@ // element _template: function(options) { - var tmpl = '<select id="' + options.id + '" class="select ' + options.cls + ' ' + options.id + '">'; + var tmpl = '<div id="' + options.id + '">' + + '<i id="wait" class="fa fa-spinner fa-spin" style="font-size: 1.2em; display: none;"/>' + + '<select id="select" class="select ' + options.cls + ' ' + options.id + '">'; for (key in options.data) { // options var item = options.data[key]; // identify selected value var tag = ''; - if (item.value == options.selected || item.value == '') { + if (item.value == options.value || item.value == '') { tag = 'selected'; } // add template string - tmpl += '<option value="' + item.value + '" ' + tag + '>' + item.label + '</option>'; + tmpl += '<option value="' + item.value + '" ' + tag + '>' + item.label + '</option>'; } - tmpl += '</select>'; + tmpl += '</select>' + + '</div>'; return tmpl; } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/library/utils.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/utils.js @@ -0,0 +1,152 @@ +/** + * Galaxy utilities comprises small functions, which at this point + * do not require their own classes/files +*/ + +// dependencies +define(["libs/underscore"], function(_) { + +// generic function to recieve json from url +function get (url, success, error) { + request('GET', url, {}, success, error); +}; + +// generic function to send json to url +function request (method, url, data, success, error) { + + // encode data into url + if (method == 'GET' || method == 'DELETE') { + if (url.indexOf('?') == -1) { + url += '?'; + } else { + url += '&'; + } + url += $.param(data) + } + + // prepare request + var xhr = new XMLHttpRequest(); + xhr.open(method, url, true); + xhr.setRequestHeader('Accept', 'application/json'); + xhr.setRequestHeader('Cache-Control', 'no-cache'); + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.onloadend = function() { + var status = xhr.status; + if (status == 200) { + try { + response = jQuery.parseJSON(xhr.responseText); + } catch (e) { + response = xhr.responseText; + } + success && success(response); + } else { + error && error(status); + } + }; + + // make request + if (method == 'GET' || method == 'DELETE') { + xhr.send(); + } else { + xhr.send(JSON.stringify(data)); + } +}; + +// get css value +function cssGetAttribute (classname, name) { + // place dummy element + var el = $('<div class="' + classname + '"></div>'); + + // required append + el.appendTo(':eq(0)'); + + // get value + var value = el.css(name); + + // remove element + el.remove(); + + // return css value + return value; +}; + +// load css +function cssLoadFile (url) { + // check if css is already available + if (!$('link[href^="' + url + '"]').length) + $('<link href="' + galaxy_config.root + url + '" rel="stylesheet">').appendTo('head'); +}; + +// merge +function merge (options, optionsDefault) { + if (options) + return _.defaults(options, optionsDefault); + else + return optionsDefault; +}; + +// to string +function bytesToString (size, normal_font) { + // identify unit + var unit = ""; + if (size >= 100000000000) { size = size / 100000000000; unit = 'TB'; } else + if (size >= 100000000) { size = size / 100000000; unit = 'GB'; } else + if (size >= 100000) { size = size / 100000; unit = 'MB'; } else + if (size >= 100) { size = size / 100; unit = 'KB'; } else + if (size > 0) { size = size * 10; unit = 'b'; } else + return '<strong>-</strong>'; + + // return formatted string + var rounded = (Math.round(size) / 10); + if (normal_font) { + return rounded + ' ' + unit; + } else { + return '<strong>' + rounded + '</strong> ' + unit; + } +}; + +// unique ide +function uuid(){ + return (new Date().getTime()).toString(36); +}; + +// wrap +function wrap($el) { + var wrapper = $('<p></p>'); + wrapper.append($el); + return wrapper; +}; + +// time +function time() { + // get date object + var d = new Date(); + + // format items + var hours = (d.getHours() < 10 ? "0" : "") + d.getHours(); + var minutes = (d.getMinutes() < 10 ? "0" : "") + d.getMinutes() + + // format final stamp + var datetime = d.getDate() + "/" + + (d.getMonth() + 1) + "/" + + d.getFullYear() + ", " + + hours + ":" + + minutes; + return datetime; +}; + +// return +return { + cssLoadFile : cssLoadFile, + cssGetAttribute : cssGetAttribute, + get : get, + merge : merge, + bytesToString: bytesToString, + uuid: uuid, + time: time, + wrap: wrap, + request: request +}; + +}); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/models/chart.js --- a/config/plugins/visualizations/charts/static/models/chart.js +++ b/config/plugins/visualizations/charts/static/models/chart.js @@ -7,10 +7,12 @@ { // defaults defaults : { - id : null, - title : '', - type : '', - date : null + id : null, + title : '', + type : '', + date : null, + state : '', + state_info : '' }, // initialize @@ -37,6 +39,11 @@ current.groups.add(group.clone()); }); current.trigger('change', current); + }, + + state: function(value, info) { + this.set('state_info', info); + this.set('state', value); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/models/config.js --- a/config/plugins/visualizations/charts/static/models/config.js +++ b/config/plugins/visualizations/charts/static/models/config.js @@ -1,15 +1,13 @@ // dependencies define([], function() { - // model return Backbone.Model.extend( { // options defaults : { - query_limit : 20, - query_pace : 1000, - query_max : 5, + query_limit : 1000, + query_timeout : 500, title : 'Create a new chart' } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/models/datasets.js --- a/config/plugins/visualizations/charts/static/models/datasets.js +++ /dev/null @@ -1,125 +0,0 @@ -// dependencies -define(['utils/utils'], function(Utils) { - -// widget -return Backbone.Model.extend( -{ - // options - optionsDefault : { - limit : 500, - pace : 1000, - max : 2 - }, - - // list - list: {}, - - // initialize - initialize: function(app, options) - { - // link app - this.app = app; - - // configure options - this.options = Utils.merge(options, this.optionsDefault); - }, - - // get - get: function(options, callback) { - // check if dataset already exists - var dataset = this.list[options.id]; - if (dataset) { - if (dataset.values) { - if (dataset.values[options.column]) { - if (callback) { - callback(dataset); - } - return dataset; - } - } - } else { - this.list[options.id] = dataset = this.app.options.dataset; - } - - // initiate fetch cycle - if (options.column !== undefined) { - this._fetch(options, callback); - } else { - if (callback) { - callback(dataset); - } - return dataset; - } - - // return - return dataset; - }, - - // size - length: function() { - return this.list.length; - }, - - // request data - _fetch : function(options, callback) { - // get dataset - var dataset = this.list[options.id]; - - // initialize values for datasets - if (!dataset.values) { - dataset.values = {}; - } - if (!dataset.values[options.column]) { - dataset.values[options.column] = []; - } - - // initialize page number - if (options.page === undefined) { - options.page = 0; - } else { - options.page++; - } - - // check max page - if (options.page > this.options.max) { - return; - } - - // config limits - var limit = this.options.limit; - var offset = this.options.limit * options.page; - - // make request - var self = this; - Utils.request('GET', config.root + 'api/datasets/' + options.id, { - data_type : 'raw_data', - provider : 'dataset-column', - limit : limit, - offset : offset, - indeces : options.column - }, function(response) { - // verify if all data has been fetched - if (response.data.length > 0) { - // add values to dataset - for (var key in response.data){ - var value = response.data[key][0]; - if (value !== undefined) { - dataset.values[options.column].push(value); - } else { - return dataset; - } - } - - // update charts - if (callback) { - callback(dataset); - } - - // next call - setTimeout(function() { self._fetch(options, callback); }, self.options.pace); - } - }); - } -}); - -}); \ No newline at end of file diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/models/group.js --- a/config/plugins/visualizations/charts/static/models/group.js +++ b/config/plugins/visualizations/charts/static/models/group.js @@ -6,8 +6,8 @@ { // options defaults : { - label : 'Data label', - date : '' + key : 'Data label', + date : '' }, // reset diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/models/types.js --- a/config/plugins/visualizations/charts/static/models/types.js +++ b/config/plugins/visualizations/charts/static/models/types.js @@ -7,48 +7,57 @@ // types defaults: { 'bardiagram' : { - title : 'Bar diagram', - data : { + title : 'Bar diagram', + columns : { y : { title : 'Values for y-axis' } } }, + 'histogram' : { + title : 'Histogram', + mode : 'execute', + columns : { + y : { + title : 'Derive frequencies' + } + } + }, 'horizontal' : { - title : 'Bar diagram (horizontal)', - data : { + title : 'Bar diagram (horizontal)', + columns : { y : { title : 'Values for y-axis' } } }, 'line' : { - title : 'Line chart', - data : { + title : 'Line chart', + columns : { y : { title : 'Values for y-axis' } } }, 'linewithfocus' : { - title : 'Line chart (with focus)', - data : { + title : 'Line chart (with focus)', + columns : { y : { title : 'Values for y-axis' } } }, 'piechart' : { - title : 'Pie chart', - data : { + title : 'Pie chart', + columns : { y : { title : 'Values for y-axis' } } }, 'scatterplot' : { - title : 'Scatter plot', - data : { + title : 'Scatter plot', + columns : { x : { title : 'Values for x-axis' }, @@ -58,8 +67,8 @@ } }, 'stackedarea' : { - title : 'Stacked area', - data : { + title : 'Stacked area', + columns : { y : { title : 'Values for y-axis' } diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/views/chart.js --- a/config/plugins/visualizations/charts/static/views/chart.js +++ b/config/plugins/visualizations/charts/static/views/chart.js @@ -97,7 +97,7 @@ // save chart self._saveChart(); - // show viewport + // show charts self.hide(); self.app.charts_view.$el.show(); } @@ -125,7 +125,6 @@ self.app.config.set('title', self.title.value()); } }); - this.dataset = new Ui.Input({value : app.options.dataset.id, disabled: true, visible: false}); // append element var $settings = $('<div/>'); @@ -183,8 +182,8 @@ this.app.chart.groups.on('reset', function(group) { self._removeAllGroups(); }); - this.app.chart.groups.on('change:label', function(group) { - self._refreshLabels(); + this.app.chart.groups.on('change:key', function(group) { + self._refreshGroupKey(); }); // reset @@ -198,11 +197,11 @@ }, // update - _refreshLabels: function() { + _refreshGroupKey: function() { var self = this; var counter = 0; this.chart.groups.each(function(group) { - var title = group.get('label', ''); + var title = group.get('key', ''); if (title == '') { title = 'Chart data'; } @@ -213,8 +212,7 @@ // new group _addGroupModel: function() { var group = new Group({ - id : Utils.uuid(), - dataset_id : this.chart.get('dataset_id') + id : Utils.uuid() }); this.chart.groups.add(group); return group; @@ -241,7 +239,7 @@ }); // update titles - this._refreshLabels() + this._refreshGroupKey(); }, // remove group @@ -249,7 +247,7 @@ this.tabs.del(group.id); // update titles - this._refreshLabels() + this._refreshGroupKey(); }, // remove group @@ -261,8 +259,10 @@ _resetChart: function() { // reset chart details this.chart.set('id', Utils.uuid()); + this.chart.set('type', 'bardiagram'); this.chart.set('dataset_id', this.app.options.dataset.id); - this.chart.set('type', 'bardiagram'); + this.chart.set('dataset_hid', this.app.options.dataset.hid); + this.chart.set('history_id', this.app.options.dataset.history_id); this.chart.set('title', 'New Chart'); }, @@ -272,7 +272,6 @@ this.chart.set({ type : this.table.value(), title : this.title.value(), - dataset_id : this.dataset.value(), date : Utils.time() }); @@ -280,11 +279,14 @@ var current = this.app.charts.get(this.chart.id); if (!current) { current = this.chart.clone(); + current.copy(this.chart); this.app.charts.add(current); + } else { + current.copy(this.chart); } - - // update chart model - current.copy(this.chart); + + // trigger redraw + current.set('state', 'redraw'); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/views/charts.js --- a/config/plugins/visualizations/charts/static/views/charts.js +++ b/config/plugins/visualizations/charts/static/views/charts.js @@ -1,5 +1,5 @@ // dependencies -define(['mvc/ui/ui-portlet', 'plugin/library/table', 'plugin/library/ui', 'utils/utils', 'plugin/models/group'], function(Portlet, Table, Ui, Utils, Group) { +define(['mvc/ui/ui-portlet', 'plugin/library/table', 'plugin/library/ui', 'utils/utils', 'plugin/models/group', 'plugin/views/viewport',], function(Portlet, Table, Ui, Utils, Group, ViewportView) { // widget return Backbone.View.extend( @@ -10,6 +10,9 @@ // link app this.app = app; + // create viewport + this.viewport_view = new ViewportView(app); + // table this.table = new Table({ content : 'Add charts to this table.', @@ -32,7 +35,7 @@ self.app.config.set('title', chart.get('title')); // show viewport - self.app.viewport_view.show(chart_id); + self.viewport_view.showChart(chart_id); } }); @@ -89,11 +92,15 @@ }); this.portlet.append(this.table.$el); - // append to main + // append portlet with table if (!this.app.options.config.widget) { this.$el.append(this.portlet.$el); } + // append view port + this.$el.append(Utils.wrap('')); + this.$el.append(this.viewport_view.$el); + // events var self = this; this.app.charts.on('add', function(chart) { @@ -106,8 +113,7 @@ }); this.app.charts.on('change', function(chart) { // replace - self._removeChart(chart); - self._addChart(chart); + self._changeChart(chart); }); }, @@ -117,12 +123,6 @@ this.$el.hide(); }, - // append - append : function($el) { - this.$el.append(Utils.wrap('')); - this.$el.append($el); - }, - // add _addChart: function(chart) { // add title to table @@ -146,11 +146,21 @@ // check if table is empty if (this.table.size() == 0) { this.hide(); + this.app.chart.reset(); this.app.chart_view.$el.show(); } else { // select available chart this.table.value(this.app.charts.last().id); } + }, + + // change + _changeChart: function(chart) { + // add chart + this._addChart(chart); + + // select available chart + this.table.value(chart.id); } }); diff -r ff303b254f5a2ae3dfa213d5cde5ed65070b1961 -r 4ec6ff7c4165fff75f0e52735bb189ee2f29cecd config/plugins/visualizations/charts/static/views/group.js --- a/config/plugins/visualizations/charts/static/views/group.js +++ b/config/plugins/visualizations/charts/static/views/group.js @@ -1,6 +1,6 @@ // dependencies -define(['mvc/ui/ui-portlet', 'plugin/library/table', 'plugin/library/ui', 'utils/utils'], - function(Portlet, Table, Ui, Utils) { +define(['plugin/library/table', 'plugin/library/ui', 'utils/utils'], + function(Table, Ui, Utils) { // chart config return Backbone.View.extend( @@ -23,18 +23,18 @@ this.group = options.group; // ui elements - this.label = new Ui.Input({ + this.group_key = new Ui.Input({ placeholder: 'Data label', onchange: function() { - self.group.set('label', self.label.value()); + self.group.set('key', self.group_key.value()); } }); this.table = new Table({content: 'No data column.'}); - // add table to portlet + // create element var $view = $('<div/>'); $view.append(Utils.wrap((new Ui.Label({title: 'Provide a label:'})).$el)); - $view.append(Utils.wrap(this.label.$el)); + $view.append(Utils.wrap(this.group_key.$el)); $view.append(Utils.wrap((new Ui.Label({title: 'Select columns:'})).$el)); $view.append(Utils.wrap(this.table.$el)); @@ -44,101 +44,92 @@ // change var self = this; this.chart.on('change:dataset_id', function() { - self._refreshDataset(); + self._refreshTable(); }); this.chart.on('change:type', function() { - self._refreshType(); + self._refreshTable(); }); - this.group.on('change:label', function() { - self._refreshLabel(); + this.group.on('change:key', function() { + self._refreshGroupKey(); }); this.group.on('change', function() { self._refreshGroup(); }); // refresh - this._refresh(); - }, - - // render - _refresh: function() { - this._refreshDataset(); - this._refreshType(); - this._refreshLabel(); + this._refreshTable(); + this._refreshGroupKey(); this._refreshGroup(); }, // update dataset - _refreshDataset: function() { + _refreshTable: function() { // identify datasets var dataset_id = this.chart.get('dataset_id'); + var chart_type = this.chart.get('type'); // check if dataset is available - if (!dataset_id) { + if (!dataset_id || !chart_type) { return; } + // link this + var self = this; + + // configure chart type + var chart_settings = this.app.types.get(chart_type); + + // reset table + this.table.removeAll(); + + // load list + var list = {}; + for (var id in chart_settings.columns) { + // initialize + var value = this.group.get(id); + if (!value) { + this.group.set(id, 0); + } + + // create select field + var data_def = chart_settings.columns[id]; + var select = new Ui.Select({ + id : 'select_' + id, + gid : id, + onchange : function(value) { + self.group.set(this.gid, value); + }, + value : value, + wait : true + }); + + // add row to table + this.table.add(data_def.title); + this.table.add(select.$el); + this.table.append(id); + + // add select field to list + list[id] = select; + } + // get dataset - var dataset = this.app.datasets.get({id : dataset_id}); - - // check - if (!dataset) { - this.app.log('Group::_refreshDataset()', 'Failed to retrieve dataset.'); - return; - } - - // configure columns - this.columns = []; - var meta = dataset.metadata_column_types; - for (var key in meta){ - this.columns.push({ - 'label' : key + ' [' + meta[key] + ']', - 'value' : key - }); - } - - // update select fields - for (var key in this.list) { - this.list[key].update(this.columns); - } - }, - - // update - _refreshType: function() { - // configure chart type - var self = this; - var chart_type = this.chart.get('type'); - if (chart_type) { - var chart_settings = this.app.types.get(chart_type); - - // table - this.table.removeAll(); - this.list = {}; - for (var id in chart_settings.data) { - // create select field - var data_def = chart_settings.data[id]; - var select = new Ui.Select({ - id : 'select_' + id, - gid : id, - data : this.columns, - onchange : function(value) { - self.group.set(this.gid, value); - }, - value : this.group.get(id) + this.app.datasets.request({id : dataset_id}, function(dataset) { + // configure columns + self.columns = []; + var meta = dataset.metadata_column_types; + for (var key in meta){ + self.columns.push({ + 'label' : key + ' [' + meta[key] + ']', + 'value' : key }); - - // set model value - this.group.set(id, select.value()); - - // add row to table - this.table.add(data_def.title); - this.table.add(select.$el); - this.table.append(id); - - // add select field to list - this.list[id] = select; } - } + + // update select fields + for (var key in list) { + list[key].update(self.columns); + list[key].show(); + } + }); }, // update @@ -146,13 +137,13 @@ this.group.set('date', Utils.time()); }, - // update label - _refreshLabel: function() { - var label_text = this.group.get('label'); - if (label_text === undefined) { - label_text = ''; + // update group key + _refreshGroupKey: function() { + var key_text = this.group.get('key'); + if (key_text === undefined) { + key_text = ''; } - this.label.value(label_text); + this.group_key.value(key_text); } }); This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.