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