1 
  2 
  3 vq.OmicsHeatmap = function() {
  4         vq.Vis.call(this);
  5         //set option variables to useful values before options are set.
  6         this.height(400);     // defaults
  7         this.width(400);     // defaults
  8         this.vertical_padding(0);
  9         this.horizontal_padding(0);
 10 
 11     };
 12 
 13 
 14 vq.OmicsHeatmap.prototype = pv.extend(vq.Vis);
 15 
 16     /**
 17      *      Changes the plot size and re-renders the plot.
 18      *
 19      * @param {Number} height - plot height in units of pixels
 20      * @param {Number} width  - plot width in units of pixels
 21      */
 22 
 23 vq.OmicsHeatmap.prototype.setSize = function(height, width) {
 24         if (height > 1 && width > 1) {
 25             this.width(width);
 26             this.height(height);
 27             this._render();
 28         }
 29     };
 30 
 31 vq.OmicsHeatmap.prototype._setOptionDefaults = function(options) {
 32 
 33             if (options.height != null) { this.height(options.height); }
 34 
 35             if (options.width != null) { this.width(options.width); }
 36 
 37             if (options.container) { this.container(options.container); }
 38 
 39             if (options.vertical_padding != null) { this.vertical_padding(options.vertical_padding); }
 40 
 41             if (options.horizontal_padding != null) { this.horizontal_padding(options.horizontal_padding); }
 42 },
 43     /**
 44      *
 45      *  Constructs the OmicsHeatmap model and adds the SVG tags to the defined DOM element.
 46      *
 47      * @param {JSON Object} circvis_object - the object defined above.
 48      * @param {JSON Object} options - the general options for the visualization.
 49      */
 50 vq.OmicsHeatmap.prototype.draw = function(data) {
 51         var vis_data = new vq.models.OmicsHeatmapData(data);
 52 
 53         if (vis_data.isDataReady()) {
 54             this._setOptionDefaults(vis_data);
 55             this.data = vis_data;
 56             this._render();
 57         } else {
 58             console.warn('Invalid data input.  Check data for missing or improperly formatted values.');
 59         }
 60     };
 61 
 62 vq.OmicsHeatmap.prototype._render = function() {
 63         var     dataObj = this.data,
 64                 w = this.width(),
 65                 h = this.height();
 66 
 67         var div = this.container();
 68         var vertical_padding = this.vertical_padding(), horizontal_padding = this.horizontal_padding();
 69         var color = dataObj.cell_fillStyle;
 70 
 71         var vis = new pv.Panel()
 72                 .left(horizontal_padding)
 73                 .top(vertical_padding)
 74                 .width(w)
 75                 .height(h)
 76                 .fillStyle(null)
 77                 .canvas(div);
 78 
 79         var size = dataObj.datamatrix[0].length * dataObj.item_width;
 80         var heatmap_panel = vis.add(pv.Panel)
 81                             .width(size)
 82                             .height((dataObj.item_height + dataObj.item_row_padding) * dataObj.datamatrix.length)
 83                             .strokeStyle('rgba(40,40,40,1.0)')
 84                             .lineWidth(1);
 85 
 86         var heatmap_container = heatmap_panel.add(pv.Panel)
 87                 .data(pv.range(0,dataObj.datamatrix.length))
 88                 .height(dataObj.item_height)
 89                 .top(function(c) { return c * (dataObj.item_height + dataObj.item_row_padding);})
 90                 .strokeStyle(null)
 91                 .fillStyle(null)
 92                 .lineWidth(dataObj.item_row_padding / 2)
 93                 .width(size);
 94 
 95         heatmap_container.add(pv.Image)
 96                 .width(size)
 97                 .height(dataObj.item_height)
 98                 .image( color.by(function(x,y){
 99             return dataObj.datamatrix[this.parent.index][Math.floor(x/dataObj.item_width)];}));
100 
101         var highlight_panel = heatmap_panel.add(pv.Panel);
102 
103     var highlighter = highlight_panel.add(pv.Panel)
104                   .data(function() { return (dataObj.active == -1 ? [-1] : pv.range(Math.max(0,dataObj.active-3),Math.min(dataObj.active+4,dataObj.datamatrix.length)));})
105                   .visible(function(c) { return c > -1;})
106                   .height((dataObj.item_height) * 4)
107                   .top(function(c) {
108               return c * (dataObj.item_height + dataObj.item_row_padding) - ((dataObj.item_height) * 2);});
109 
110           var highlight_bar = highlighter.add(pv.Panel)
111                   .visible(function(c) { return c > -1 && dataObj.active == c;})
112                   .fillStyle('rgba(255,255,255,1.0)')
113                   .strokeStyle('rgba(40,40,40,1)')
114                   .lineWidth(1)
115                   .width(size);
116 
117           highlight_bar.add(pv.Image)
118                   .image(color.by(function(x,y){
119               return dataObj.datamatrix[dataObj.active][Math.floor(x/dataObj.item_width)];}));
120 
121           highlighter.add(pv.Label)
122                   .right(size+5)
123                   .textBaseline('top')
124                   .textAlign('right')
125                .top(function(c) { return (c - dataObj.active) * (dataObj.item_height + Math.max(8,dataObj.item_row_padding));})
126                   .font(function(c) { return (c != dataObj.active ? '10px bold courier, monospace' : dataObj.row_label_font);})
127                   .text(function(c) { return dataObj.row_label_prefix + dataObj.row_labels[c];});
128 
129         var col_label_panel = highlight_panel.add(pv.Panel)
130                 .data(function() { return [dataObj.column]; })
131                 .visible(function(c) { return c > -1 && dataObj.active > -1;})
132                 .left(function(c) { return (c * dataObj.item_width) + (dataObj.column  < (dataObj.datamatrix.length / 5) ? 0 :
133                                 (dataObj.column  > (dataObj.datamatrix.length * 3 / 5)) ?  ('Column: ' + dataObj.column_labels[c]).length *
134                                         -6 : -50);})
135                 .width(function(c) { return (Math.max(('Column: ' + dataObj.column_labels[c]).length * 6.2,200));})
136                 .fillStyle('rgba(240,240,240,1.0)')
137                 .strokeStyle('rgba(40,40,40,1.0)')
138                 .lineWidth(0.5)
139                 .top(function() { return dataObj.active * (dataObj.item_height + dataObj.item_row_padding) +
140                 ((dataObj.item_height + dataObj.item_row_padding) * (dataObj.active  < (dataObj.datamatrix.length / 2) ? 3 : -9)) ;})
141                 .height(30)
142 
143         col_label_panel.anchor('left').add(pv.Label)
144                 .font('10px bold Courier, monospace')
145                 .top(5)
146                 .text(function(c) { return 'Column: ' + dataObj.column_labels[c];})
147               .add(pv.Label)
148                 .top(15)
149                  .text(function(c) { return 'Value: ' +  dataObj.datamatrix[dataObj.active][dataObj.column];});
150 
151     var drag_panel = heatmap_panel.add(pv.Panel)
152             .events('all')
153             .data([{y:0,dy:0,fix:0}])
154             .cursor('crosshair')
155             .event('mousedown',pv.Behavior.select())
156             .event('select',function() {drag_panel.render();})
157             .event('selectend', function(d) {
158                 var pos = vq.utils.VisUtils.translateToReferenceCoord({x:0,y:d.y},this);
159                 var begin = Math.floor(pos.y/(dataObj.item_height+dataObj.item_row_padding));
160                 var end = Math.floor((pos.y+d.dy)/(dataObj.item_height+dataObj.item_row_padding));
161                 if (end < begin) { return; }
162                 var labels = pv.permute(dataObj.row_labels,pv.range(begin,end+1,1));
163                 dataObj.select_notifier(labels);
164                 d.dy = 0;
165                 drag_panel.render();
166             })
167           .add(pv.Bar)
168             .left(-5)
169             .width(5)
170             .fillStyle('rgba(255,0,0,1)')
171             .top(function(d){ var pos = vq.utils.VisUtils.translateToReferenceCoord({x:0,y:d.y},this.parent);
172                 return pos.y;})
173             .height(function(d){return d.dy;})
174             .strokeStyle(null)
175             .lineWidth(1);
176 
177     var event_panel = drag_panel.add(pv.Panel)
178                .events('all')
179                .data(pv.range(0,dataObj.datamatrix.length))
180                .height(dataObj.item_height)
181                .top(function(c) { return c * (dataObj.item_height + dataObj.item_row_padding);})
182                .fillStyle(null)
183                .width(size)
184                .event('mouseover',function(c){ dataObj.active = c;
185                 var pos = vq.utils.VisUtils.translateToReferenceCoord({x:this.mouse().x,y:0},this);
186                 dataObj.column = Math.floor(pos.x/dataObj.item_width)-1; highlight_panel.render()})
187                .event('mousemove',function(c){dataObj.active = c;
188                 var pos = vq.utils.VisUtils.translateToReferenceCoord({x:this.mouse().x,y:0},this);
189                 dataObj.column = Math.floor(pos.x/dataObj.item_width)-1; highlight_panel.render()})
190                .event('mouseout',function(c) { dataObj.active = -1; highlight_panel.render()})
191                .event('click',function(c) { dataObj.row_click_notifier( dataObj.row_labels[dataObj.active]);});
192 
193         vis.render();
194     };
195 
196 /**
197 
198  */
199 
200 vq.models.OmicsHeatmapData = function(data) {
201     /**
202      * @lends vq.models.OmicsHeatmapData#
203      */
204         vq.models.VisData.call(this,data);
205     this._setDataModel();
206     /**
207      *  @augments vq.models.VisData
208      *  @class The class which models the OmicsHeatmap data.  The JSON Object is parsed and analyzed to create the proper data structure for
209      *  consumption by the OmicsHeatmap class.
210      *
211      * @constructs
212      * @param {Class} $super - the {@link vq.models.VisData} class is passed into the instance on creation.
213      * @param {JSON Object} data - JSON Object defined in {@link vq.OmicsHeatmap}.
214      * @see vq.OmicsHeatmap
215      */
216         if (this.getDataType() == 'vq.models.OmicsHeatmapData') {
217             this._build_data(this.getContents())
218         } else {
219             console.warn('Unrecognized JSON object.  Expected vq.models.OmicsHeatmapData object.');
220         }
221     };
222 
223 vq.models.OmicsHeatmapData.prototype = pv.extend(vq.models.VisData);
224 
225     vq.models.OmicsHeatmapData.prototype._build_data = function(data) {
226         this._processData(data);
227 
228         if (this.row_labels === []) this.row_labels = pv.repeat(['Default'],this.datamatrix.length);
229         this.imagematrix = [];
230           this.setDataReady(true);
231       };
232 
233 
234 vq.models.OmicsHeatmapData.prototype._setDataModel = function() {
235           this._dataModel = [
236               {label: 'width', id: 'PLOT.width', cast : Number, defaultValue: 400},
237               {label: 'height', id: 'PLOT.height', cast : Number, defaultValue: 400},
238               {label : 'container', id:'PLOT.container', optional : true},
239               {label:  'vertical_padding', id: 'PLOT.vertical_padding', cast : Number, defaultValue: 0},
240               {label:  'horizontal_padding', id: 'PLOT.horizontal_padding',cast : Number,  defaultValue: 0},
241               {label : 'datamatrix', id: 'data_matrix', defaultValue : [[]] },
242               {label : 'item_width', id: 'item_width', cast: Number, defaultValue : 8 },
243               {label : 'item_height', id: 'item_height', cast: Number, defaultValue : 8 },
244               {label : 'item_row_padding', id: 'item_row_padding', cast: Number, defaultValue : 1 },
245               {label : 'cell_fillStyle', id:'fill_style', cast : vq.utils.VisUtils.wrapProperty, defaultValue : pv.Scale.linear(-1,1).range('blue','red') },
246               {label : 'item_column_padding', id: 'item_column_padding', cast: Number, defaultValue : 2 },
247               {label : 'row_labels' , id: 'row_labels', defaultValue : []},
248               {label : 'column_labels' , id: 'column_labels', defaultValue : []},
249               {label : 'row_label_prefix' , id: 'row_label_prefix', cast : String, defaultValue : ''},
250               {label : 'row_label_font', id: 'row_label_font', cast: String, defaultValue : '10pt helvetica serif'},
251               {label : 'row_click_notifier', id: 'row_click_notifier', cast: vq.utils.VisUtils.wrapProperty, defaultValue : function(a) {} },
252                   {label : 'select_notifier', id: 'select_notifier', cast: vq.utils.VisUtils.wrapProperty, defaultValue : function(a) {} },
253               {label : 'tooltipItems', id: 'CONFIGURATION.tooltip_items', defaultValue :
254               {X : 'x' , Value : 'y'} }
255           ];
256       };
257