diff --git a/config/plugins/visualizations/scatterplot/Gruntfile.js b/config/plugins/visualizations/scatterplot/Gruntfile.js
index 55b9a3b7a8d..019b676499f 100644
--- a/config/plugins/visualizations/scatterplot/Gruntfile.js
+++ b/config/plugins/visualizations/scatterplot/Gruntfile.js
@@ -6,6 +6,7 @@ module.exports = function(grunt) {
pkg: grunt.file.readJSON( 'package.json' ),
handlebars: {
+ // compile all hb templates into a single file in the build dir
compile: {
options: {
namespace: 'Templates',
@@ -20,6 +21,7 @@ module.exports = function(grunt) {
},
concat: {
+ // concat the template file and any js files in the src dir into a single file in the build dir
options: {
separator: ';\n'
},
@@ -31,16 +33,19 @@ module.exports = function(grunt) {
},
uglify: {
+ // uglify the concat single file directly into the static dir
options: {
+ //mangle : false,
+ //beautify : true
},
dist: {
src : 'build/scatterplot-concat.js',
- // uglify directly into static dir
- dest: 'static/scatterplot.js'
+ dest: 'static/scatterplot-edit.js'
}
},
watch: {
+ // watch for changes in the src dir
files: [ 'src/**.js', 'src/handlebars/*.handlebars' ],
tasks: [ 'default' ]
}
@@ -52,5 +57,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.registerTask( 'default', [ 'handlebars', 'concat', 'uglify' ]);
- grunt.registerTask( 'watch', [ 'handlebars', 'concat', 'uglify', 'watch' ]);
+ // you can run grunt watch directly:
+ // grunt watch
};
diff --git a/config/plugins/visualizations/scatterplot/package.json b/config/plugins/visualizations/scatterplot/package.json
index d0c81baafb2..84909ef83bf 100644
--- a/config/plugins/visualizations/scatterplot/package.json
+++ b/config/plugins/visualizations/scatterplot/package.json
@@ -19,6 +19,6 @@
"grunt-contrib-handlebars": "~0.5.10",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-uglify": "~0.2.2",
- "grunt-contrib-watch": "~0.5.1"
+ "grunt-contrib-watch": "~0.5.3"
}
}
diff --git a/config/plugins/visualizations/scatterplot/src/handlebars/chartControl.handlebars b/config/plugins/visualizations/scatterplot/src/handlebars/chartControl.handlebars
deleted file mode 100644
index b08521fbc8d..00000000000
--- a/config/plugins/visualizations/scatterplot/src/handlebars/chartControl.handlebars
+++ /dev/null
@@ -1,56 +0,0 @@
-
- Use the following controls to how the chart is displayed.
- The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.
- Move the focus between controls by using the tab or shift+tab keys on your keyboard.
- Use the 'Draw' button to render (or re-render) the chart with the current settings.
-
-
-
-
-
{{datapointSize}}
-
-
- Size of the graphic representation of each data point
-
-
-
-
-
-
-
- Uncheck this to disable the animations used on the chart
-
-
-
-
-
-
{{width}}
-
-
- (not including chart margins and axes)
-
-
-
-
-
-
{{height}}
-
-
- (not including chart margins and axes)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/plugins/visualizations/scatterplot/src/handlebars/chartDisplay.handlebars b/config/plugins/visualizations/scatterplot/src/handlebars/chartDisplay.handlebars
deleted file mode 100644
index f1c54ebc2f0..00000000000
--- a/config/plugins/visualizations/scatterplot/src/handlebars/chartDisplay.handlebars
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/config/plugins/visualizations/scatterplot/src/handlebars/chartcontrol.handlebars b/config/plugins/visualizations/scatterplot/src/handlebars/chartcontrol.handlebars
new file mode 100644
index 00000000000..8ac966fa7d0
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/chartcontrol.handlebars
@@ -0,0 +1,47 @@
+
+ Use the following controls to how the chart is displayed.
+ The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.
+ Move the focus between controls by using the tab or shift+tab keys on your keyboard.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+
+
+
+
+
{{datapointSize}}
+
+
+ Size of the graphic representation of each data point
+
- Use the following controls to change the data used by the chart.
- Use the 'Draw' button to render (or re-render) the chart with the current settings.
-
-
- {{! column selector containers }}
-
-
-
-
-
-
-
-
-
- {{! optional id column }}
-
-
-
-
- These will be displayed (along with the x and y values) when you hover over
- a data point.
-
-
-
-
-
-
-
- {{! if we're using generic column selection names ('column 1') - allow the user to use the first line }}
-
-
Possible headers: {{ possibleHeaders }}
-
-
-
-
- It looks like Galaxy couldn't get proper column headers for this data.
- Would you like to use the column headers above as column names to select columns?
-
-
-
-
-
\ No newline at end of file
diff --git a/config/plugins/visualizations/scatterplot/src/handlebars/datacontrol.handlebars b/config/plugins/visualizations/scatterplot/src/handlebars/datacontrol.handlebars
new file mode 100644
index 00000000000..2e7eb35dc8f
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/datacontrol.handlebars
@@ -0,0 +1,55 @@
+
+ Use the following controls to change the data used by the chart.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+
+
+{{! column selector containers }}
+
+
+
+
+
+
+
+
+
+{{! optional id column }}
+
+
+
+
+ These will be displayed (along with the x and y values) when you hover over
+ a data point.
+
+
+
+
+
+
+
+{{! if we're using generic column selection names ('column 1') - allow the user to use the first line }}
+
+
Possible headers: {{ possibleHeaders }}
+
+
+
+
+ It looks like Galaxy couldn't get proper column headers for this data.
+ Would you like to use the column headers above as column names to select columns?
+
-
- {{! data form, chart config form, stats, and chart all get their own tab }}
-
- {{! ---------------------------- tab for data settings form }}
-
- {{! rendered separately }}
-
-
- {{! ---------------------------- tab for chart graphics control form }}
-
- {{! rendered separately }}
-
-
- {{! ---------------------------- tab for data statistics }}
-
- {{! rendered separately }}
-
-
- {{! ---------------------------- tab for actual chart }}
-
- {{! chart rendered separately }}
-
-
-
{{! end .tab-content }}
-
{{! end .chart-control }}
\ No newline at end of file
diff --git a/config/plugins/visualizations/scatterplot/src/handlebars/statsDisplay.handlebars b/config/plugins/visualizations/scatterplot/src/handlebars/statsDisplay.handlebars
deleted file mode 100644
index 038b4ea7b71..00000000000
--- a/config/plugins/visualizations/scatterplot/src/handlebars/statsDisplay.handlebars
+++ /dev/null
@@ -1,8 +0,0 @@
-
By column:
-
-
X
Y
- {{#each stats}}
-
{{name}}
{{xval}}
{{yval}}
-
- {{/each}}
-
\ No newline at end of file
diff --git a/config/plugins/visualizations/scatterplot/src/scatterplot-config-editor.js b/config/plugins/visualizations/scatterplot/src/scatterplot-config-editor.js
new file mode 100644
index 00000000000..5dc81d982b4
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/scatterplot-config-editor.js
@@ -0,0 +1,237 @@
+/* =============================================================================
+todo:
+ Remove 'chart' names
+ Make this (the config control/editor) and the ScatterplotView (in scatterplot.js) both
+ views onto a visualization/revision model
+ Move margins into wid/hi calcs (so final svg dims are w/h)
+ Better separation of AJAX in scatterplot.js (maybe pass in function?)
+ Labels should auto fill in chart control when dataset has column_names
+ Allow column selection/config using the peek output as a base for UI
+ Allow setting perPage of config
+ Auto render if given data and/or config
+ Allow option to auto set width/height based on screen real estate avail.
+ Use d3.nest to allow grouping, pagination/filtration by group (e.g. chromCol)
+ Semantic HTML (figure, caption)
+ Save as visualization, load from visualization
+ Save as SVG/png
+ Does it work w/ Galaxy.Frame?
+ Embedding
+ Small multiples
+ Drag & Drop other splots onto current (redraw with new axis and differentiate the datasets)
+
+ Subclass on specific datatypes? (vcf, cuffdiff, etc.)
+ What can be common/useful to other visualizations?
+
+============================================================================= */
+/**
+ * Scatterplot config control UI as a backbone view
+ * handles:
+ * configuring which data will be used
+ * configuring the plot display
+ */
+var ScatterplotConfigEditor = BaseView.extend( LoggableMixin ).extend({
+ //TODO: !should be a view on a visualization model
+ //logger : console,
+ className : 'scatterplot-control-form',
+
+ /** initialize requires a configuration Object containing a dataset Object */
+ initialize : function( attributes ){
+ //console.log( this + '.initialize, attributes:', attributes );
+ if( !attributes || !attributes.config || !attributes.config.dataset ){
+ throw new Error( "ScatterplotView requires a configuration and dataset" );
+ }
+ this.dataset = attributes.config.dataset;
+ //console.log( 'dataset:', this.dataset );
+
+ this.plotView = new ScatterplotView({
+ config : attributes.config
+ });
+ },
+
+ // ------------------------------------------------------------------------- CONTROLS RENDERING
+ render : function(){
+ //console.log( this + '.render' );
+
+ // render the tab controls, areas and loading indicator
+ this.$el.append( ScatterplotConfigEditor.templates.mainLayout({
+ }));
+
+ // render the tab content
+ this.$el.find( '#data-control' ).append( this._render_dataControl() );
+ this._render_chartControls( this.$el.find( '#chart-control' ) );
+ //this.$statsDisplay = this.$el.find( '.tab-pane#stats-display' );
+ this._render_chartDisplay();
+
+ //TODO: auto render if given both x, y column choices in query for page
+
+ // set up behaviours
+ this.$el.find( '[title]' ).tooltip();
+
+ // uncomment any of the following to have that tab show on initial load (for testing)
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#data-control"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#chart-control"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#stats-display"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
+ return this;
+ },
+
+ _render_dataControl : function(){
+ // controls for which columns are used to plot datapoints (and ids/additional info to attach if desired)
+ var dataset = this.dataset;
+ //console.log( 'metadata_column_types:', this.dataset.metadata_column_types );
+ //console.log( 'metadata_column_names:', this.dataset.metadata_column_names );
+
+ var allColumns = _.map( dataset.metadata_column_types, function( type, i ){
+ var column = { index: i, type: type, name: ( 'column ' + ( i + 1 ) ) };
+ if( dataset.metadata_column_names && dataset.metadata_column_names[ i ] ){
+ column.name = dataset.metadata_column_names[ i ];
+ }
+ return column;
+ });
+ var numericColumns = _.filter( allColumns, function( column, i ){
+ return ( ( column.type === 'int' ) || ( column.type === 'float' ) );
+ });
+ if( numericColumns < 2 ){
+ numericColumns = allColumns;
+ }
+ //console.log( 'allColumns:', allColumns );
+ //console.log( 'numericColumns:', numericColumns );
+
+ // render the html
+ var $dataControl = this.$el.find( '.tab-pane#data-control' );
+ $dataControl.html( ScatterplotConfigEditor.templates.dataControl({
+ allColumns : allColumns,
+ numericColumns : numericColumns
+ }));
+
+ // preset to column selectors if they were passed in the config in the query string
+ $dataControl.find( '[name="xColumn"]' ).val( this.plotView.config.xColumn || numericColumns[0].index );
+ $dataControl.find( '[name="yColumn"]' ).val( this.plotView.config.yColumn || numericColumns[1].index );
+ if( this.plotView.config.idColumn !== undefined ){
+ $dataControl.find( '#include-id-checkbox' ).prop( 'checked', true ).trigger( 'change' );
+ $dataControl.find( 'select[name="idColumn"]' ).val( this.plotView.config.idColumn );
+ }
+
+ return $dataControl;
+ },
+
+ _render_chartControls : function( $chartControls ){
+ // tab content to control how the chart is rendered (data glyph size, chart size, etc.)
+ $chartControls.html( ScatterplotConfigEditor.templates.chartControl( this.plotView.config ) );
+ //console.debug( '$chartControl:', $chartControls );
+
+ // set up behaviours, js on sliders
+ //console.debug( 'numeric sliders:', $chartControls.find( '.numeric-slider-input' ) );
+ // what to do when the slider changes: update display and update chartConfig
+ var view = this,
+ // limits for controls (by control/chartConfig id)
+ //TODO: move into TwoVarScatterplot
+ controlRanges = {
+ 'datapointSize' : { min: 2, max: 10, step: 1 },
+ 'width' : { min: 200, max: 800, step: 20 },
+ 'height' : { min: 200, max: 800, step: 20 }
+ };
+
+ function onSliderChange(){
+ var $this = $( this );
+ $this.siblings( '.slider-output' ).text( $this.slider( 'value' ) );
+ }
+ $chartControls.find( '.numeric-slider-input' ).each( function(){
+ var $this = $( this ),
+ configKey = $this.attr( 'data-config-key' ),
+ sliderSettings = _.extend( controlRanges[ configKey ], {
+ value : view.plotView.config[ configKey ],
+ change : onSliderChange,
+ slide : onSliderChange
+ });
+ //console.debug( configKey + ' slider settings:', sliderSettings );
+ $this.find( '.slider' ).slider( sliderSettings );
+ });
+//TODO: to more common area (like render)?
+ // set label inputs to current x, y metadata_column_names (if any)
+ if( this.dataset.metadata_column_names ){
+ //var colNames = this.dataset.metadata_column_names;
+ //$chartControls.find( 'input[name="X-axis-label"]' ).val( colNames );
+ //$chartControls.find( 'input[name="Y-axis-label"]' ).val( colNames );
+//TODO: on change of x, y data controls
+ }
+
+ //console.debug( '$chartControls:', $chartControls );
+ return $chartControls;
+ },
+
+ _render_chartDisplay : function(){
+ // render the tab content where the chart is displayed (but not the chart itself)
+ var $chartDisplay = this.$el.find( '.tab-pane#chart-display' );
+ this.plotView.setElement( $chartDisplay );
+ this.plotView.render();
+ return $chartDisplay;
+ },
+
+ // ------------------------------------------------------------------------- EVENTS
+ events : {
+ 'change #include-id-checkbox' : 'toggleThirdColumnSelector',
+ 'click #data-control .render-button' : 'renderChart',
+ 'click #chart-control .render-button' : 'renderChart'
+ },
+
+ toggleThirdColumnSelector : function(){
+ // show/hide the id selector on the data settings panel
+ this.$el.find( 'select[name="idColumn"]' ).parent().toggle();
+ },
+
+ // ------------------------------------------------------------------------- CHART/STATS RENDERING
+ renderChart : function(){
+ //console.log( this + '.renderChart' );
+ // fetch the data, (re-)render the chart
+ this.$el.find( '.nav li.disabled' ).removeClass( 'disabled' );
+ this.updateConfigWithDataSettings();
+ this.updateConfigWithChartSettings();
+ this.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
+ this.plotView.fetchData();
+ //console.debug( this.plotView.$el );
+ },
+
+ // ------------------------------------------------------------------------- GET DATA/CHART SETTINGS
+ updateConfigWithDataSettings : function(){
+ // parse the column values for both indeces (for the data fetch) and names (for the chart)
+ var $dataControls = this.$el.find( '#data-control' );
+ var settings = {
+ xColumn : $dataControls.find( '[name="xColumn"]' ).val(),
+ yColumn : $dataControls.find( '[name="yColumn"]' ).val()
+ };
+ if( $dataControls.find( '#include-id-checkbox' ).prop( 'checked' ) ){
+ settings.idColumn = $dataControls.find( '[name="idColumn"]' ).val();
+ }
+ //console.log( '\t data settings:', settings );
+ return _.extend( this.plotView.config, settings );
+ },
+
+ updateConfigWithChartSettings : function(){
+ // gets the user-selected chartConfig from the chart settings panel
+ var plotView = this.plotView,
+ $chartControls = this.$el.find( '#chart-control' );
+ // use a loop of config keys to get the form values for these sliders
+ [ 'datapointSize', 'width', 'height' ].forEach( function( v, i ){
+ plotView.config[ v ] = $chartControls.find( '.numeric-slider-input[data-config-key="' + v + '"]' )
+ .find( '.slider' ).slider( 'value' );
+ });
+ // update axes labels using chartSettings inputs (if not at defaults), otherwise the selects' colName
+ plotView.config.x.label = $chartControls.find( 'input[name="X-axis-label"]' ).val();
+ plotView.config.y.label = $chartControls.find( 'input[name="Y-axis-label"]' ).val();
+ //console.log( '\t chartSettings:', settings );
+ return plotView.config;
+ },
+
+ toString : function(){
+ return 'ScatterplotConfigEditor(' + (( this.dataset )?( this.dataset.id ):( '' )) + ')';
+ }
+});
+
+ScatterplotConfigEditor.templates = {
+ mainLayout : Templates.editor,
+ dataControl : Templates.datacontrol,
+ chartControl : Templates.chartcontrol
+};
+
+//==============================================================================
diff --git a/config/plugins/visualizations/scatterplot/src/scatterplot-display.js b/config/plugins/visualizations/scatterplot/src/scatterplot-display.js
new file mode 100644
index 00000000000..dd0258369b8
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/scatterplot-display.js
@@ -0,0 +1,288 @@
+// =============================================================================
+/**
+ * Scatterplot display control UI as a backbone view
+ * handles:
+ * fetching the data (if needed)
+ * computing and displaying data stats
+ * controls for pagination of data (if needed)
+ */
+var ScatterplotView = Backbone.View.extend({
+ //TODO: should be a view on visualization(revision) model
+
+ defaults : {
+ dataset : {
+ },
+ metadata : {
+ dataLines : undefined
+ },
+
+ ajaxFn : null,
+
+ pagination : {
+ currPage : 0,
+ perPage : 3000
+ },
+
+ width : 400,
+ height : 400,
+
+ margin : {
+ top : 16,
+ right : 16,
+ bottom : 40,
+ left : 54
+ },
+
+ x : {
+ ticks : 10,
+ label : 'X'
+ },
+ y : {
+ ticks : 10,
+ label : 'Y'
+ },
+
+ datapointSize : 4,
+ animDuration : 500
+ },
+
+ initialize : function( attributes ){
+ this.config = _.extend( _.clone( this.defaults ), attributes.config || {});
+ //console.debug( this + '.config:', this.config );
+ },
+
+ updateConfig : function( newConfig ){
+ //console.log( this + '.updateConfig:', newConfig );
+ this.config = this.config || {};
+ //TODO: validate here
+ _.extend( this.config, newConfig );
+ //TODO: implement rerender flag
+ },
+
+ fetchData : function(){
+//TODO: doesn't work bc it's rendered in render()...
+ this.showLoadingIndicator( 'getting data' );
+ //console.debug( 'currPage', this.config.pagination.currPage );
+ var view = this;
+//TODO: very tied to datasets - should be generalized eventually
+ xhr = jQuery.getJSON( '/api/datasets/' + this.config.dataset.id, {
+ data_type : 'raw_data',
+ provider : 'dataset-column',
+ limit : this.config.pagination.perPage,
+ offset : ( this.config.pagination.currPage * this.config.pagination.perPage )
+ });
+ xhr.done( function( data ){
+ view.renderData( data.data );
+ });
+ xhr.fail( function( xhr, status, message ){
+ alert( 'Error loading data:\n' + xhr.responseText );
+ console.error( xhr, status, message );
+ });
+ xhr.always( function(){
+ view.hideLoadingIndicator();
+ });
+ return xhr;
+ },
+
+ render : function( data ){
+ this.$el.addClass( 'scatterplot-display' ).html([
+ '',
+ '
"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var b=this;var a=function(c){c.one("click.close_popup",function(){b.remove()})};a($(window.document));a($(window.top.document));_.each(window.top.frames,function(c){a($(c.document))})},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a','',""].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};
\ No newline at end of file