Created
February 20, 2019 12:35
-
-
Save bumbeishvili/83c9fe7d26f53afcea94c24a180e28ad to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*DEEP MERGE*/ | |
function isMergeableObject(e){return e&&"object"==typeof e&&"[object RegExp]"!==Object.prototype.toString.call(e)&&"[object Date]"!==Object.prototype.toString.call(e)}function emptyTarget(e){return Array.isArray(e)?[]:{}}function cloneIfNecessary(e,r){return r&&!0===r.clone&&isMergeableObject(e)?deepmerge(emptyTarget(e),e,r):e}function defaultArrayMerge(e,r,t){var a=e.slice();return r.forEach(function(r,c){void 0===a[c]?a[c]=cloneIfNecessary(r,t):isMergeableObject(r)?a[c]=deepmerge(e[c],r,t):-1===e.indexOf(r)&&a.push(cloneIfNecessary(r,t))}),a}function mergeObject(e,r,t){var a={};return isMergeableObject(e)&&Object.keys(e).forEach(function(r){a[r]=cloneIfNecessary(e[r],t)}),Object.keys(r).forEach(function(c){isMergeableObject(r[c])&&e[c]?a[c]=deepmerge(e[c],r[c],t):a[c]=cloneIfNecessary(r[c],t)}),a}function deepmerge(e,r,t){var a=Array.isArray(r),c=(t||{arrayMerge:defaultArrayMerge}).arrayMerge||defaultArrayMerge;return a?Array.isArray(e)?c(e,r,t):cloneIfNecessary(r,t):mergeObject(e,r,t)}deepmerge.all=function(e,r){if(!Array.isArray(e)||e.length<2)throw new Error("first argument should be an array with at least two elements");return e.reduce(function(e,t){return deepmerge(e,t,r)})}; | |
/** | |
* InCHlib is an interactive JavaScript library which facilitates data | |
* visualization and exploration by means of a cluster heatmap. InCHlib | |
* is a versatile tool, and its use is not limited only to chemical or | |
* biological data. Source code, tutorial, documentation, and example | |
* data are freely available from InCHlib website <a | |
* href="http://openscreen.cz/software/inchlib" | |
* target=blank>http://openscreen.cz/software/inchlib</a>. At the | |
* website, you can also find a Python script <a | |
* href="http://openscreen.cz/software/inchlib/inchlib_clust" | |
* target=blank>inchlib_clust</a> which performs data clustering and | |
* prepares <a href="http://openscreen.cz/software/inchlib/input_format" | |
* target=blank>input data for InCHlib</a>. | |
* | |
* @author <a href="mailto:[email protected]">Ctibor Škuta</a> | |
* @author <a href="mailto:[email protected]">Petr Bartůněk</a> | |
* @author <a href="mailto:[email protected]">Daniel Svozil</a> | |
* @version dev | |
* @category 1 | |
* @license InCHlib - Interactive Cluster Heatmap Library http://openscreen.cz/software/inchlib Copyright 2014, Ctibor Škuta, Petr Bartůněk, Daniel Svozil Licensed under the MIT license. | |
* | |
* Permission is hereby granted, free of charge, to any person | |
* obtaining a copy of this software and associated documentation | |
* files (the "Software"), to deal in the Software without | |
* restriction, including without limitation the rights to use, | |
* copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the | |
* Software is furnished to do so, subject to the following | |
* conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
* OTHER DEALINGS IN THE SOFTWARE. | |
* | |
* @requires <a href='http://code.jquery.com/jquery-2.0.3.min.js'>jQuery Core 2.0.3</a> | |
* @dependency <script language="JavaScript" type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script> | |
* | |
* @requires <a href='https://cdn.rawgit.com/konvajs/konva/0.9.5/konva.min.js'>KonvaJS 0.9.5</a> | |
* @dependency <script language="JavaScript" type="text/javascript" src="https://cdn.rawgit.com/konvajs/konva/0.9.5/konva.min.js"></script> | |
* | |
* @param {Object} options An object with the options for the InCHlib component. | |
* | |
* @option {string} target | |
* identifier of the DIV tag where the component should be displayed | |
* @option {boolean} [column_dendrogram=false] | |
* turn on/off the column dendrogram | |
* @option {boolean} [count_column=false] | |
* turn on/off the count column | |
* @option {boolean} [dendrogram=true] | |
* turn on/off the row dendrogram | |
* @option {string} [font="Trebuchet MS"] | |
* font family | |
* @option {string} [heatmap_colors="Greens"] | |
* the heatmap color scale | |
* @option {number} [heatmap_part_width=0.7] | |
* define the heatmap part width from the width of the whole graph | |
* @option {string} [highlight_colors="Reds"] | |
* color scale for highlighted rows | |
* @option {obejct} [highlighted_rows=[]] | |
* array of row IDs to highlight | |
* @option {boolean} [independent_columns=true] | |
* determines whether the color scale is based on the values from all columns together or for each column separately | |
* @option {string} [label_color=grey] | |
* color of column label | |
* @option {number} [max_column_width=100] | |
* maximum column width in pixels | |
* @option {number} [max_height=800] | |
* maximum graph height in pixels | |
* @option {number} [max_row_height=25] | |
* maximum row height in pixels | |
* @option {boolean} [metadata=false] | |
* turn on/off the metadata | |
* @option {string} [metadata_colors="Oranges"] | |
* the metadata color scale | |
* @option {number} [min_row_height=false] | |
* minimum row height in pixels | |
* @option {number} [width="the width of target DIV"] | |
* width of the graph in pixels | |
* @option {boolean} [heatmap=true] | |
* turn on/off the heatmap | |
* @option {string} [heatmap_font_color="black"] | |
* the color of the text values in the heatmap | |
* @option {string} [count_column_colors="Reds"] | |
* the color scale of count column | |
* @option {boolean} [draw_row_ids=false] | |
* draws the row IDs next to the heatmap when there is enough space to visualize them | |
* @option {boolean} [fixed_row_id_size=false] | |
* fixes the row id size on given number and extends the right margin of the visualization accordingly | |
* @option {number} [max_percentile=100] | |
* the value percentile above which the color will be equal to the terminal color of the color scale | |
* @option {number} [min_percentile=0] | |
* the value percentile below which the color will be equal to the beginning color of the color scale | |
* @option {number} [middle_percentile=50] | |
* the value percentile which defines where the middle color of the color scale will be used | |
* @option {array} [columns_order=[]] | |
* the order of columns defined by their indexes startin from 0, when not provided the columns are sorted in common order 0, 1, 2... etc. | |
* @option {boolean} [alternative_data=false] | |
* use original data to compute heatmap but show the alternative values (alternative_data section must be present in input data) | |
* @option {boolean} [images_as_alternative_data=false] | |
* alternative data values can be used to identify image files (.png, .jpg) and draw them insted of the heatmap values | |
* @option {object} [images_path=false] | |
* when using images_as_alternative_data option - set dir path of the image files and the image files extension to generate the whole file path ({"dir": "", "ext": ""}) | |
* @option {object} [navigation_toggle={"distance_scale": false, "filter_button": false, "export_button": false, "color_scale": false, "hint_button": false}] | |
* toggle "navigation" features - true/false | |
* | |
* @example | |
* window.instance = new InCHlib({ | |
* target : "YourOwnDivId", | |
* metadata: true, | |
* max_height: 800, | |
* width: 700, | |
* metadata_colors: "RdLrBu" | |
* }); | |
* instance.read_data_from_file("../biojs/data/chembl_gr.json"); | |
* instance.draw(); | |
*/ | |
var InCHlib; | |
(function($){ | |
InCHlib = function(settings){ | |
var self = this; | |
self.user_settings = settings; | |
self.target_element = $("#" + settings.target); | |
self.target_element.css({"position": "relative"}); | |
/** | |
* Default values for the settings | |
* @name InCHlib#settings | |
*/ | |
self.settings = { | |
"target" : "YourOwnDivId", | |
"heatmap_header": { | |
"draw": true, | |
"settings":{ | |
"fontFamily": "Helvetica", | |
"fontSize": undefined, | |
"rotation": -90, | |
"fill": "#000000" | |
} | |
}, | |
"heatmap": { | |
"draw": true, | |
"colors": { | |
"scale": "Greens", | |
"value_type": "percentile", | |
"independent_columns" : true, | |
"params": {"min": 0, "middle": 50, "max": 100} | |
}, | |
"columns_order": [], | |
"row_height": {"min": 1, "max": 25}, | |
"column_width": {"max": 150}, | |
"relative_width": 0.7, | |
"font": { | |
"fontFamily": "Helvetica", | |
"fill": "#000000" | |
} | |
}, | |
"dendrogram": { | |
"draw": true, | |
"unified_distance": false | |
}, | |
"metadata": { | |
"draw": false, | |
"colors": { | |
"independent_columns" : true, | |
"value_type": "percentile", | |
"scale": "Reds", | |
"params": {"min": 0, "middle": 50, "max": 100}, | |
"value2color": {}, | |
"default": "#F5F5F5" | |
} | |
}, | |
"column_metadata": { | |
"draw": false, | |
"row_height": 8, | |
"feature_names": { | |
"draw": true, | |
"settings": { | |
"fontFamily": "Helvetica", | |
"fontSize": undefined, | |
"fill": "#000000" | |
} | |
}, | |
"colors": { | |
"independent_columns" : true, | |
"value_type": "percentile", | |
"scale": "Reds", | |
"params": {"min": 0, "middle": 50, "max": 100}, | |
"value2color": {}, | |
"default": "#F5F5F5" | |
} | |
}, | |
"row_ids": { | |
"draw": true, | |
"fixed_size": false, | |
"tooltip": false | |
}, | |
"column_dendrogram": { | |
"draw": false | |
}, | |
"count_column": { | |
"draw": false, | |
"colors": "Reds" | |
}, | |
"max_height" : 800, | |
"width" : "dynamic", | |
"highlight_colors" : "Oranges", | |
"highlighted_rows" : [], | |
"label_color": "#9E9E9E", | |
"alternative_data": false, | |
"images": { | |
"draw": false, | |
"path": {"dir": "", "ext": ""} | |
}, | |
"navigation_toggle": {"color_scale": true, "distance_scale": true, "export_button": true, "filter_button": true, "hint_button": true}, | |
}; | |
self.update_settings(settings); | |
self.settings.width = (settings.max_width && settings.max_width < target_width)?settings.max_width:self.settings.width; | |
self.settings.heatmap.relative_width = (self.settings.heatmap.relative_width>0.9)?0.9:self.settings.heatmap.relative_width; | |
self.header_height = 150; | |
self.footer_height = 70; | |
self.dendrogram_heatmap_distance = 5; | |
/** | |
* Default function definitions for the InCHlib events | |
* @name InCHlib#events | |
*/ | |
self.events = { | |
/** | |
* @name InCHlib#row_onclick | |
* @event | |
* @param {function} function() callback function for click on the heatmap row event | |
* @eventData {array} array array of object IDs represented by row | |
* @eventData {object} event event object | |
* @example | |
* instance.events.row_onclick = ( | |
* function(object_ids, evt) { | |
* alert(object_ids); | |
* } | |
* ); | |
* | |
*/ | |
"row_click": function(object_ids, evt){ | |
return; | |
}, | |
"row_onclick": function(object_ids, evt){ | |
self.events.row_click(object_ids, evt); | |
}, | |
/** | |
* @name InCHlib#row_onmouseover | |
* @event | |
* @param {function} function() callback function for mouse cursor over the heatmap row event | |
* @eventData {array} array array of object IDs represented by row | |
* @eventData {object} event event object | |
* @example | |
* instance.events.row_onmouseover = ( | |
* function(object_ids, evt) { | |
* alert(object_ids); | |
* } | |
* ); | |
* | |
*/ | |
"row_mouseover": function(object_ids, evt){ | |
return; | |
}, | |
"row_onmouseover": function(object_ids, evt){ | |
self.events.row_mouseover(object_ids, evt); | |
}, | |
/** | |
* @name InCHlib#row_onmouseout | |
* @event | |
* @param {function} function() callback function for mouse cursor out of the heatmap row event | |
* @eventData {object} event event object | |
* @example | |
* instance.events.row_onmouseout = ( | |
* function(evt) { | |
* alert("now"); | |
* } | |
* ); | |
* | |
*/ | |
"row_mouseout": function(evt){ | |
return; | |
}, | |
"row_onmouseout": function(evt){ | |
self.events.row_mouseout(evt); | |
}, | |
/** | |
* @name InCHlib#dendrogram_node_onclick | |
* @event | |
* @param {function} function() callback function for dendrogram node click event | |
* @eventData {array} array array of object IDs represented by the node | |
* @eventData {string} node_id Id of the dendrogram node | |
* @eventData {object} event event object | |
* @example | |
* instance.events.dendrogram_node_onclick = ( | |
* function(object_ids, node_id, evt) { | |
* alert(node_id + ": " + object_ids.length+" rows"); | |
* } | |
* ); | |
* | |
*/ | |
"dendrogram_node_click": function(object_ids, node_id, evt){ | |
return; | |
}, | |
"dendrogram_node_onclick": function(object_ids, node_id, evt){ | |
self.events.dendrogram_node_click(object_ids, node_id, evt); | |
}, | |
/** | |
* @name InCHlib#column_dendrogram_node_onclick | |
* @event | |
* @param {function} function() callback function for column dendrogram click event | |
* @eventData {array} array array of column indexes | |
* @eventData {string} node_id Id of the dendrogram node | |
* @eventData {object} event event object | |
* @example | |
* instance.events.column_dendrogram_node_onclick = ( | |
* function(column_ids, node_id, evt) { | |
* alert(node_id + ": " + column_ids.length+" columns"); | |
* } | |
* ); | |
* | |
*/ | |
"column_dendrogram_node_click": function(column_indexes, node_id, evt){ | |
return; | |
}, | |
"column_dendrogram_node_onclick": function(column_indexes, node_id, evt){ | |
self.events.column_dendrogram_node_click(column_indexes, node_id, evt); | |
}, | |
/** | |
* @name InCHlib#dendrogram_node_highlight | |
* @event | |
* @param {function} function() callback function for the dendrogram node highlight event | |
* @eventData {array} array array of object IDs represented by row | |
* @eventData {string} node_id Id of the dendrogram node | |
* @eventData {object} event event object | |
* @example | |
* instance.events.dendrogram_node_highlight = ( | |
* function(object_ids, node_id, evt) { | |
* alert(node_id + ": " + object_ids.length+" rows"); | |
* } | |
* ); | |
* | |
*/ | |
"dendrogram_node_highlight": function(object_ids, node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#column_dendrogram_node_highlight | |
* @event | |
* @param {function} function() callback function for the column dendrogram node highlight event | |
* @eventData {array} array array of column indexes | |
* @eventData {string} node_id Id of the dendrogram node | |
* @eventData {object} event event object | |
* @example | |
* instance.events.column_dendrogram_node_highlight = ( | |
* function(object_ids, node_id, evt) { | |
* alert(node_id + ": " + object_ids.length+" columns"); | |
* } | |
* ); | |
* | |
*/ | |
"column_dendrogram_node_highlight": function(column_indexes, node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#dendrogram_node_unhighlight | |
* @event | |
* @param {function} function() callback function for the dendrogram node unhighlight event | |
* @eventData {string} node_id Id of the dendrogram node | |
* @example | |
* instance.events.dendrogram_node_unhighlight = ( | |
* function(node_id) { | |
* alert(node_id); | |
* } | |
* ); | |
* | |
*/ | |
"dendrogram_node_unhighlight": function(node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#column_dendrogram_node_unhighlight | |
* @event | |
* @param {function} function() callback function for the column dendrogram node unhighlight event | |
* @eventData {string} node_id Id of the column dendrogram node | |
* @example | |
* instance.events.column_dendrogram_node_unhighlight = ( | |
* function(node_id) { | |
* alert(node_id); | |
* } | |
* ); | |
* | |
*/ | |
"column_dendrogram_node_unhighlight": function(node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#heatmap_onmouseout | |
* @event | |
* @param {function} function() callback function for mouse cursor out of hte heatmap area | |
* @eventData {object} event event object | |
* @example | |
* instance.events.heatmap_onmouseout = ( | |
* function(evt) { | |
* alert("now"); | |
* } | |
* ); | |
* | |
*/ | |
"heatmap_onmouseout": function(evt){ | |
return; | |
}, | |
/** | |
* @name InCHlib#on_zoom | |
* @event | |
* @param {function} function() callback function for zoom event | |
* @eventData {string} node_id Id of the dendrogram node | |
* @example | |
* instance.events.on_zoom = ( | |
* function(node_id) { | |
* alert(node_id); | |
* } | |
* ); | |
* | |
*/ | |
"on_zoom": function(object_ids, node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#on_unzoom | |
* @event | |
* @param {function} function() callback function for unzoom event | |
* @eventData {string} node_id Id of the dendrogram node | |
* @example | |
* instance.events.on_unzoom = ( | |
* function(node_id) { | |
* alert(node_id); | |
* } | |
* ); | |
* | |
*/ | |
"on_unzoom": function(node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#on_columns_zoom | |
* @event | |
* @param {function} function() callback function for columns zoom event | |
* @eventData {array} array array of column indexes | |
* @eventData {string} node_id Id of the column dendrogram node | |
* @example | |
* instance.events.on_columns_zoom = ( | |
* function(column_indexes, node_id) { | |
* alert(column_indexes, node_id); | |
* } | |
* ); | |
* | |
*/ | |
"on_columns_zoom": function(column_indexes, node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#on_columns_unzoom | |
* @event | |
* @param {function} function() callback function for columns unzoom event | |
* @eventData {string} node_id Id of the column dendrogram node | |
* @example | |
* instance.events.on_columns_unzoom = ( | |
* function(node_id) { | |
* alert(node_id); | |
* } | |
* ); | |
* | |
*/ | |
"on_columns_unzoom": function(node_id){ | |
return; | |
}, | |
/** | |
* @name InCHlib#on_refresh | |
* @event | |
* @param {function} function() callback function for refresh icon click event | |
* @eventData {object} event event object | |
* @example | |
* instance.events.on_refresh = ( | |
* function() { | |
* alert("now"); | |
* } | |
* ); | |
* | |
*/ | |
"on_refresh": function(){ | |
return; | |
}, | |
/** | |
* @name InCHlib#empty_space_onclick | |
* @event | |
* @param {function} function() callback function for click on empty(inactive) space in the visualization (e.g., around the heatmap) | |
* @eventData {object} event event object | |
* @example | |
* instance.events.empty_space_onclick = ( | |
* function(evt) { | |
* alert("now"); | |
* } | |
* ); | |
* | |
*/ | |
"empty_space_click": function(evt){ | |
return; | |
}, | |
"empty_space_onclick": function(evt){ | |
self.events.empty_space_click(evt); | |
}, | |
/** | |
* @name InCHlib#cell_click | |
* @event | |
* @param {function} function() callback function for click on a cell in a heatmap row | |
* @eventData {object} object containing value and header attributes | |
* @eventData {object} event event object | |
* @example | |
* instance.events.cell_click = ( | |
* function(obj, evt) { | |
* alert(obj); | |
* } | |
* ); | |
* | |
*/ | |
"cell_click" : function(obj, evt){ | |
return; | |
}, | |
/** | |
* @name InCHlib#cell_mouseover | |
* @event | |
* @param {function} function() callback function for the mouseover event of a cell in a heatmap row | |
* @eventData {object} object containing value and header attributes | |
* @eventData {object} event event object | |
* @example | |
* instance.events.cell_mouseover = ( | |
* function(obj, evt) { | |
* alert(obj); | |
* } | |
* ); | |
* | |
*/ | |
"cell_mouseover" : function(obj, evt){ | |
return; | |
} | |
} | |
/** | |
* Default color scales | |
* @name InCHlib#colors | |
*/ | |
self.colors = { | |
"YlGn": {"start": {"r":255, "g": 255, "b": 204}, "end": {"r": 35, "g": 132, "b": 67}}, | |
"GnBu": {"start": {"r":240, "g": 249, "b": 232}, "end": {"r": 43, "g": 140, "b": 190}}, | |
"BuGn": {"start": {"r":237, "g": 248, "b": 251}, "end": {"r": 35, "g": 139, "b": 69}}, | |
"PuBu": {"start": {"r":241, "g": 238, "b": 246}, "end": {"r": 5, "g": 112, "b": 176}}, | |
"BuPu": {"start": {"r":237, "g": 248, "b": 251}, "end": {"r": 136, "g": 65, "b": 157}}, | |
"RdPu": {"start": {"r":254, "g": 235, "b": 226}, "end": {"r": 174, "g": 1, "b": 126}}, | |
"PuRd": {"start": {"r":241, "g": 238, "b": 246}, "end": {"r": 206, "g": 18, "b": 86}}, | |
"OrRd": {"start": {"r":254, "g": 240, "b": 217}, "end": {"r": 215, "g": 48, "b": 31}}, | |
"Purples2": {"start": {"r":242, "g": 240, "b": 247}, "end": {"r": 106, "g": 81, "b": 163}}, | |
"Blues": {"start": {"r":239, "g": 243, "b": 255}, "end": {"r": 33, "g": 113, "b": 181}}, | |
"Greens": {"start": {"r":237, "g": 248, "b": 233}, "end": {"r": 35, "g": 139, "b": 69}}, | |
"Oranges": {"start": {"r":254, "g": 237, "b": 222}, "end": {"r": 217, "g": 71, "b": 1}}, | |
"Reds": {"start": {"r":254, "g": 229, "b": 217}, "end": {"r": 203, "g": 24, "b": 29}}, | |
"Greys": {"start": {"r":247, "g": 247, "b": 247}, "end": {"r": 82, "g": 82, "b": 82}}, | |
"PuOr": {"start": {"r":230, "g": 97, "b": 1}, "end": {"r": 94, "g": 60, "b": 153}}, | |
"BrBG": {"start": {"r":166, "g": 97, "b": 26}, "end": {"r": 1, "g": 133, "b": 113}}, | |
"RdBu": {"start": {"r":202, "g": 0, "b": 32}, "end": {"r": 5, "g": 113, "b": 176}}, | |
"RdGy": {"start": {"r":202, "g": 0, "b": 32}, "end": {"r": 64, "g": 64, "b": 64}}, | |
"BuYl": {"start": {"r": 5, "g": 113, "b": 176}, "end": {"r": 250, "g": 233, "b": 42}}, | |
"YlOrR": {"start": {"r":255, "g": 255, "b": 178}, "end": {"r": 227, "g": 26, "b": 28}, "middle": {"r": 204, "g": 76, "b": 2}}, | |
"YlOrB": {"start": {"r":255, "g": 255, "b": 212}, "end": {"r": 5, "g": 112, "b": 176}, "middle": {"r": 204, "g": 76, "b": 2}}, | |
"PRGn2": {"start": {"r":123, "g": 50, "b": 148}, "end": {"r": 0, "g": 136, "b": 55}, "middle": {"r":202, "g": 0, "b": 32}}, | |
"PiYG2": {"start": {"r":208, "g": 28, "b": 139}, "end": {"r": 77, "g": 172, "b": 38}, "middle": {"r":255, "g": 255, "b": 178},}, | |
"YlGnBu": {"start": {"r":255, "g": 255, "b": 204}, "end": {"r": 34, "g": 94, "b": 168}, "middle": {"r": 35, "g": 132, "b": 67}}, | |
"RdYlBu": {"start": {"r":215, "g": 25, "b": 28}, "end": {"r": 44, "g": 123, "b": 182}, "middle": {"r":255, "g": 255, "b": 178}}, | |
"RdYlGn": {"start": {"r":215, "g": 25, "b": 28}, "end": {"r": 26, "g": 150, "b": 65}, "middle": {"r":255, "g": 255, "b": 178}}, | |
"BuWhRd": {"start": {"r": 33, "g": 113, "b": 181}, "middle": {"r": 255, "g": 255, "b": 255}, "end": {"r":215, "g": 25, "b": 28}}, | |
"RdLrBu": {"start": {"r":215, "g": 25, "b": 28}, "middle": {"r":254, "g": 229, "b": 217}, "end": {"r": 44, "g": 123, "b": 182}}, | |
"RdBkGr": {"start": {"r":215, "g": 25, "b": 28}, "middle": {"r": 0, "g": 0, "b": 0}, "end": {"r": 35, "g": 139, "b": 69}}, | |
"RdLrGr": {"start": {"r":215, "g": 25, "b": 28}, "middle": {"r":254, "g": 229, "b": 217}, "end": {"r": 35, "g": 139, "b": 69}}, | |
}; | |
/** | |
* Default konvajs objects references | |
* @name InCHlib#objects_ref | |
*/ | |
self.objects_ref = { | |
"tooltip_label": new Konva.Label({ | |
opacity: 1, | |
listening: false, | |
preventDefault: false | |
}), | |
"tooltip_tag": new Konva.Tag({ | |
fill: self.settings.label_color, | |
pointerWidth: 10, | |
pointerHeight: 10, | |
lineJoin: 'round', | |
listening: false, | |
preventDefault: false | |
}), | |
"tooltip_text": new Konva.Text({ | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fontSize: 12, | |
padding: 8, | |
fill: 'white', | |
fontStyle: "bold", | |
listening: false, | |
align: "center", | |
lineHeight: 1.2, | |
preventDefault: false | |
}), | |
"node": new Konva.Line({ | |
stroke: "grey", | |
strokeWidth: 2, | |
lineCap: 'sqare', | |
lineJoin: 'round', | |
listening: false, | |
preventDefault: false | |
}), | |
"node_rect" : new Konva.Rect({ | |
fill: "white", | |
opacity: 0, | |
preventDefault: false | |
}), | |
"icon_overlay": new Konva.Rect({ | |
width: 32, | |
height: 32, | |
opacity: 0, | |
preventDefault: false | |
}), | |
"heatmap_value": new Konva.Text({ | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fill: self.settings.heatmap.font.fill, | |
fontStyle: "bold", | |
listening: false, | |
preventDefault: false | |
}), | |
"heatmap_line": new Konva.Line({ | |
lineCap: 'butt', | |
value: false, | |
preventDefault: false | |
}), | |
"column_header": new Konva.Text({ | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fontStyle: "bold", | |
fill: 'black', | |
preventDefault: false | |
}), | |
"count": new Konva.Text({ | |
fontSize: 10, | |
fill: "#6d6b6a", | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fontStyle: 'bold', | |
listening: false, | |
preventDefault: false | |
}), | |
"cluster_overlay": new Konva.Rect({ | |
fill: "white", | |
opacity: 0.5, | |
preventDefault: false | |
}), | |
"cluster_border": new Konva.Line({ | |
stroke: "black", | |
strokeWidth: 1, | |
dash: [6,2], | |
preventDefault: false | |
}), | |
"icon": new Konva.Path({ | |
fill: "grey", | |
preventDefault: false | |
}), | |
"rect_gradient": new Konva.Rect({ | |
x: 0, | |
y: 80, | |
width: 80, | |
height: 20, | |
fillLinearGradientStartPoint: {x: 0, y: 80}, | |
fillLinearGradientEndPoint: {x: 100, y: 80}, | |
stroke: "#D2D2D2", | |
strokeWidth: "1px", | |
preventDefault: false | |
}), | |
"image": new Konva.Image({ | |
stroke: "#D2D2D2", | |
strokeWidth: 1, | |
preventDefault: false | |
}), | |
}; | |
self.paths_ref = { | |
"zoom_icon": "M22.646,19.307c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127l3.535-3.537L22.646,19.307zM13.688,20.369c-3.582-0.008-6.478-2.904-6.484-6.484c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486C20.165,17.465,17.267,20.361,13.688,20.369zM15.687,9.051h-4v2.833H8.854v4.001h2.833v2.833h4v-2.834h2.832v-3.999h-2.833V9.051z", | |
"unzoom_icon": "M22.646,19.307c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127l3.535-3.537L22.646,19.307zM13.688,20.369c-3.582-0.008-6.478-2.904-6.484-6.484c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486C20.165,17.465,17.267,20.361,13.688,20.369zM8.854,11.884v4.001l9.665-0.001v-3.999L8.854,11.884z", | |
"lightbulb": "M15.5,2.833c-3.866,0-7,3.134-7,7c0,3.859,3.945,4.937,4.223,9.499h5.553c0.278-4.562,4.224-5.639,4.224-9.499C22.5,5.968,19.366,2.833,15.5,2.833zM15.5,28.166c1.894,0,2.483-1.027,2.667-1.666h-5.334C13.017,27.139,13.606,28.166,15.5,28.166zM12.75,25.498h5.5v-5.164h-5.5V25.498z" | |
}; | |
} | |
InCHlib.prototype._update_user_settings = function(settings){ | |
var self = this; | |
self.update_settings(settings); | |
} | |
/** | |
* Read data from JSON variable. | |
* | |
* @param {object} [variable] Clustering in proper JSON format. | |
*/ | |
InCHlib.prototype.read_data = function(json){ | |
var self = this; | |
self.json = json; | |
self.data = self.json.data; | |
var settings = {"metadata": {}, "column_dendrogram": {}, "column_metadata": {}}; | |
if(json["metadata"] !== undefined && self.settings.metadata.draw){ | |
self.metadata = json.metadata; | |
settings.metadata.draw = true; | |
} | |
else{ | |
settings.metadata.draw = false; | |
} | |
if(json["column_dendrogram"] !== undefined && self.settings.column_dendrogram.draw){ | |
self.column_dendrogram = json.column_dendrogram; | |
settings.column_dendrogram.draw = true; | |
settings.heatmap_header = {"settings": {"rotation": -1*self.settings.heatmap_header.settings.rotation}}; | |
} | |
else{ | |
settings.column_dendrogram.draw = false; | |
} | |
if(json["column_metadata"] !== undefined && self.settings.column_metadata.draw){ | |
self.column_metadata = json.column_metadata; | |
settings.column_metadata.draw = true; | |
} | |
else{ | |
settings.column_metadata.draw = false; | |
} | |
if(self.json["alternative_data"] !== undefined && self.settings.alternative_data){ | |
self.alternative_data = self.json.alternative_data.nodes; | |
} | |
else{ | |
settings.alternative_data = false; | |
} | |
if((self.data.feature_names !== undefined && self.data.feature_names.length > 0)||(self.metadata !== undefined && self.metadata.feature_names !== undefined && self.metadata.feature_names.length > 0)){ | |
self.settings.heatmap_header.draw = true; | |
} | |
else{ | |
self.settings.heatmap_header.draw = false; | |
} | |
self._update_user_settings(settings); | |
self._add_prefix(); | |
self.node_ids = Object.keys(self.data.nodes); | |
self.leaf_ids = self.node_ids.filter(x => self.data.nodes[x].count === 1); | |
} | |
/** | |
* Read data from JSON file. | |
* | |
* @param {string} [filename] Path to the JSON data file. | |
* | |
*/ | |
InCHlib.prototype.read_data_from_file = function(json){ | |
var self = this; | |
$.ajax({ | |
type: 'GET', | |
url: json, | |
dataType: 'json', | |
success: function(json_file){ | |
self.read_data(json_file); | |
}, | |
async: false | |
}); | |
} | |
InCHlib.prototype._add_prefix = function(){ | |
var self = this; | |
self.data.nodes = self._add_prefix_to_data(self.data.nodes); | |
if(self.settings.metadata.draw){ | |
var metadata = {}; | |
for(var i = 0, keys = Object.keys(self.metadata.nodes), len = keys.length; i < len; i++){ | |
id = [self.settings.target, keys[i]].join("#"); | |
metadata[id] = self.metadata.nodes[keys[i]]; | |
} | |
self.metadata.nodes = metadata; | |
} | |
if(self.settings.alternative_data){ | |
var alternative_data = {}; | |
for(var i = 0, keys = Object.keys(self.alternative_data), len = keys.length; i < len; i++){ | |
id = [self.settings.target, keys[i]].join("#"); | |
alternative_data[id] = self.alternative_data[keys[i]]; | |
} | |
self.alternative_data = alternative_data; | |
} | |
if(self.column_dendrogram){ | |
self.column_dendrogram.nodes = self._add_prefix_to_data(self.column_dendrogram.nodes); | |
} | |
} | |
InCHlib.prototype._add_prefix_to_data = function(data){ | |
var self = this; | |
var id, prefixed_data = {}; | |
for(var i = 0, keys = Object.keys(data), len = keys.length; i < len; i++){ | |
id = [self.settings.target, keys[i]].join("#"); | |
prefixed_data[id] = data[keys[i]]; | |
if(prefixed_data[id]["parent"] !== undefined){ | |
prefixed_data[id].parent = [self.settings.target, prefixed_data[id].parent].join("#"); | |
} | |
if(prefixed_data[id]["count"] != 1){ | |
prefixed_data[id].left_child = [self.settings.target, prefixed_data[id].left_child].join("#"); | |
prefixed_data[id].right_child = [self.settings.target, prefixed_data[id].right_child].join("#"); | |
} | |
} | |
return prefixed_data; | |
} | |
InCHlib.prototype._get_root_id = function(nodes){ | |
var self = this; | |
var root_id; | |
for(var i = 0, keys = Object.keys(nodes), len = keys.length; i < len; i++){ | |
if(nodes[keys[i]]["parent"] === undefined){ | |
root_id = keys[i]; | |
break; | |
} | |
} | |
return root_id; | |
} | |
InCHlib.prototype._get_dimensions = function(){ | |
var self = this; | |
var dimensions = {"data": 0, "metadata": 0, "overall": 0}, key, keys, i; | |
if(self.settings.images.draw){ | |
dimensions["data"] = self.alternative_data[self.leaf_ids[0]].length; | |
} | |
else{ | |
dimensions["data"] = self.data.nodes[self.leaf_ids[0]].features.length; | |
} | |
if(self.settings.metadata.draw){ | |
dimensions["metadata"] = self.metadata.nodes[self.leaf_ids[0]].length; | |
} | |
dimensions["overall"] = dimensions["data"] + dimensions["metadata"]; | |
return dimensions; | |
} | |
InCHlib.prototype._get_min_max_middle = function(data){ | |
var self = this; | |
var all = []; | |
for(var i = 0, len = data.length; i<len; i++){ | |
all = all.concat(data[i].filter(function(x){return x !== null})); | |
} | |
var len = all.length; | |
all.sort(function(a,b){return a - b}); | |
var min = (self.settings.heatmap.colors.params.min > 0)?all[self._hack_round(len*self.settings.heatmap.colors.params.min/100)]:Math.min.apply(null, all); | |
var max = (self.settings.heatmap.colors.params.max < 100)?all[self._hack_round(len*self.settings.heatmap.colors.params.max/100)]:Math.max.apply(null, all) | |
var middle = (self.settings.heatmap.colors.params.middle != 50)?all[self._hack_round(len*self.settings.heatmap.colors.params.middle/100)]:all[self._hack_round((len-1)/2)] | |
return [min, max, middle]; | |
} | |
InCHlib.prototype._get_data_min_max_middle = function(data, axis, section){ | |
var self = this; | |
if(axis === undefined){ | |
axis = "column"; | |
} | |
if(section === undefined){ | |
var section = "heatmap"; | |
} | |
var data2descs = {} | |
var i, j, value, len, columns; | |
var data_length = data[0].length; | |
if(axis == "column"){ | |
columns = []; | |
for(i = 0; i<data_length; i++){ | |
columns.push([]); | |
} | |
for(i = 0; i<data.length; i++){ | |
for(j = 0; j < data_length; j++){ | |
value = data[i][j]; | |
if(value !== null && value !== undefined){ | |
columns[j].push(value); | |
} | |
} | |
} | |
} | |
else{ | |
columns = data.slice(0); | |
} | |
var data_min_max_middle = [], min, max, middle; | |
if(self.settings[section].value_type === "value"){ | |
for(i = 0; i<columns.length; i++){ | |
data2descs[i] = $.extend({}, self.settings[section].colors.params); | |
} | |
} | |
else{ | |
for(i = 0; i<columns.length; i++){ | |
if(self._is_number(columns[i][0])){ | |
columns[i] = columns[i].map(parseFloat); | |
columns[i].sort(function(a,b){return a - b}); | |
len = columns[i].length; | |
max = (self.settings[section].colors.params.max < 100)?columns[i][self._hack_round(len*self.settings[section].colors.params.max/100) - 1]:Math.max.apply(null, columns[i]); | |
min = (self.settings[section].colors.params.min > 0)?columns[i][self._hack_round(len*self.settings[section].colors.params.min/100)]:Math.min.apply(null, columns[i]); | |
middle = (self.settings[section].colors.params.middle != 50)?columns[i][self._hack_round(len*self.settings[section].colors.params.middle/100)]:columns[i][self._hack_round((len-1)/2)]; | |
data2descs[i] = {"min": min, "max": max, "middle": middle}; | |
} | |
else{ | |
var hash_object = self._get_hash_object(columns[i]); | |
min = 0; | |
max = self._hack_size(hash_object)-1; | |
middle = max/2; | |
data2descs[i] = {"min": min, "max": max, "middle": middle, "str2num": hash_object}; | |
} | |
} | |
} | |
return data2descs; | |
} | |
InCHlib.prototype._get_hash_object = function(array){ | |
var self = this; | |
var i, count=0, hash_object = {}; | |
for(i = 0; i<array.length; i++){ | |
if(hash_object[array[i]] === undefined){ | |
hash_object[array[i]] = count; | |
count++; | |
} | |
} | |
return hash_object; | |
} | |
InCHlib.prototype._get_max_length = function(items){ | |
var self = this; | |
var lengths = items.map(function(x){return (""+x).length}); | |
var max = Math.max.apply(Math, lengths); | |
return max; | |
} | |
InCHlib.prototype._get_max_value_length = function(){ | |
var self = this; | |
var max_length = 0; | |
var node_data, key; | |
if(self.settings.images.draw){ | |
max_length = 0; | |
} | |
else{ | |
if(self.settings.alternative_data){ | |
var values = self.current_leaf_ids.map(v => self.alternative_data[v]); | |
} | |
else{ | |
var values = self.current_leaf_ids.map(v => self.data.nodes[v].features); | |
} | |
if(self.settings.metadata.draw){ | |
values = values.concat(self.current_leaf_ids.map(v => self.metadata.nodes[v])); | |
} | |
for(var i = 0, len = values.length; i < len; i++){ | |
/*value = values[i];*/ | |
node_data = values[i]; | |
for(var j = 0, len_2 = node_data.length; j < len_2; j++){ | |
if((""+node_data[j]).length > max_length){ | |
max_length = (""+node_data[j]).length; | |
} | |
} | |
} | |
} | |
return max_length; | |
} | |
InCHlib.prototype._preprocess_heatmap_data = function(){ | |
var self = this; | |
var heatmap_array = [], i, j = 0, keys, key, len, data, node; | |
for(i = 0, len = self.node_ids.length; i < len; i++){ | |
key = self.node_ids[i]; | |
node = self.data.nodes[key]; | |
if(node.count == 1){ | |
data = node.features; | |
heatmap_array.push([key]); | |
heatmap_array[j].push.apply(heatmap_array[j], data); | |
if(self.settings.metadata.draw){ | |
heatmap_array[j].push.apply(heatmap_array[j], self.metadata.nodes[key]); | |
} | |
j++; | |
} | |
} | |
return heatmap_array; | |
} | |
InCHlib.prototype._reorder_heatmap = function(column_index){ | |
var self = this; | |
self.leaves_y_coordinates = {}; | |
column_index++; | |
if(self.ordered_by_index == column_index){ | |
self.heatmap_array.reverse(); | |
} | |
else{ | |
if(self._is_number(self.heatmap_array[0][column_index])){ | |
self.heatmap_array.sort(function(a,b){return (a[column_index] == null)?-1:(b[column_index] == null)?1:a[column_index] - b[column_index]}); | |
} | |
else{ | |
self.heatmap_array.sort(function(a,b){return (a[column_index] == null)?-1:(b[column_index] == null)?1:(a[column_index] > b[column_index])?1:(a[column_index] < b[column_index])?-1:0}); | |
} | |
} | |
var y = self.top_heatmap_distance; | |
for(var i = 0, len = self.heatmap_array.length; i<len; i++){ | |
self.leaves_y_coordinates[self.heatmap_array[i][0]] = y; | |
y += self.pixels_for_leaf; | |
} | |
self.ordered_by_index = column_index; | |
} | |
/** | |
* Draw already read data (from file/JSON variable). | |
*/ | |
InCHlib.prototype.draw = function(){ | |
console.time("DRAW"); | |
var self = this; | |
self.zoomed_clusters = {"row": [], "column": []}; | |
self.last_highlighted_cluster = null; | |
self.current_object_ids = []; | |
self.current_column_ids = []; | |
self.highlighted_rows_y = []; | |
self.heatmap_array = self._preprocess_heatmap_data(); | |
self.on_features = {"data":[], "metadata":[], "count_column": []}; | |
self.column_metadata_rows = (self.settings.column_metadata.draw)?self.column_metadata.features.length:0; | |
self.column_metadata_height = self.column_metadata_rows * self.settings.column_metadata.row_height; | |
if(self.settings.heatmap.draw){ | |
self.last_column = null; | |
self.dimensions = self._get_dimensions(); | |
self._set_heatmap_settings(); | |
} | |
else{ | |
self.dimensions = {"data": 0, "metadata": 0, "overall": 0}; | |
self.settings.heatmap_header.draw = false; | |
self.settings.column_dendrogram.draw = false; | |
} | |
self._adjust_leaf_size(self.heatmap_array.length); | |
if(self.settings.row_ids.draw){ | |
self._get_row_id_size(); | |
} | |
else{ | |
self.right_margin = 100; | |
} | |
self._adjust_horizontal_sizes(); | |
self.top_heatmap_distance = self.header_height + self.column_metadata_height + self.settings.column_metadata.row_height/2; | |
if(self.settings.column_dendrogram.draw && self.heatmap_header){ | |
self.footer_height = 150; | |
} | |
self.stage = new Konva.Stage({ | |
container: self.settings.target, | |
}); | |
self.settings.height = self.heatmap_array.length*self.pixels_for_leaf+self.header_height+self.footer_height; | |
self.stage.setWidth(self.settings.width); | |
self.stage.setHeight(self.settings.height); | |
self._draw_stage_layer(); | |
if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw){ | |
self.timer = 0; | |
self._draw_dendrogram_layers(); | |
} | |
if(self.settings.dendrogram.draw){ | |
console.time("DENDROGRAM") | |
self.root_id = self._get_root_id(self.data.nodes); | |
self._draw_row_dendrogram(self.root_id); | |
console.timeEnd("DENDROGRAM") | |
} | |
else{ | |
self._reorder_heatmap(0); | |
self.ordered_by_index = 0; | |
} | |
if(self.settings.column_dendrogram.draw){ | |
self.column_root_id = self._get_root_id(self.column_dendrogram.nodes); | |
self.nodes2columns = false; | |
self.columns_start_index = 0; | |
self._draw_column_dendrogram(self.column_root_id); | |
} | |
if(self.settings.images.draw){ | |
self.path2image = {}; | |
self.path2image_obj = {}; | |
self.image_counter = 0; | |
} | |
self._draw_heatmap(); | |
self._draw_heatmap_header(); | |
self._draw_navigation(); | |
self.highlight_rows(self.settings.highlighted_rows); | |
console.timeEnd("DRAW"); | |
} | |
InCHlib.prototype._draw_dendrogram_layers = function(){ | |
var self = this; | |
self.cluster_layer = new Konva.Layer(); | |
self.dendrogram_hover_layer = new Konva.Layer(); | |
self.stage.add(self.cluster_layer, self.dendrogram_hover_layer); | |
self.cluster_layer.on("click", function(evt){ | |
self.unhighlight_cluster(); | |
self.unhighlight_column_cluster(); | |
self.events.empty_space_onclick(evt); | |
}); | |
}; | |
InCHlib.prototype._get_node_levels = function(nodes){ | |
var self = this; | |
for(var i = 0, keys=Object.keys(nodes), len=keys.length; i<len; i++){ | |
var key = keys[i]; | |
var level = 1 | |
if(nodes[key].count == 1){ | |
nodes[key].level = level; | |
level++; | |
var node = nodes[key]; | |
while("parent" in node){ | |
var parent_id = node.parent; | |
if(nodes[parent_id].level == undefined || nodes[parent_id].level < level){ | |
nodes[parent_id].level = level; | |
} | |
level++; | |
node = nodes[parent_id]; | |
} | |
} | |
} | |
} | |
InCHlib.prototype._draw_row_dendrogram = function(node_id){ | |
var self = this; | |
self.dendrogram_layer = new Konva.Layer(); | |
var node = self.data.nodes[node_id]; | |
var count = node.count; | |
self.distance_step = self.distance/node.distance; | |
self.leaves_y_coordinates = {}; | |
self.objects2leaves = {}; | |
self._adjust_leaf_size(count); | |
self.settings.height = count*self.pixels_for_leaf+self.header_height+self.footer_height+self.column_metadata_height; | |
self.stage.setWidth(self.settings.width); | |
self.stage.setHeight(self.settings.height); | |
var current_left_count = 0; | |
var current_right_count = 0; | |
var y = self.header_height + self.column_metadata_height + self.pixels_for_leaf/2; | |
if(node.count > 1){ | |
current_left_count = self.data.nodes[node.left_child].count; | |
current_right_count = self.data.nodes[node.right_child].count; | |
} | |
if(self.settings.dendrogram.unified_distance){ | |
self._get_node_levels(self.data.nodes); | |
self.unified_distance_step = self.data.nodes[node_id].distance/self.data.nodes[node_id].level; | |
} | |
var node_options = {node_id: node_id, current_left_count: current_left_count, current_right_count: current_right_count, x: 0, y: y}; | |
var nodes = [[node, node_options]]; | |
while(nodes.length > 0){ | |
var to_draw = []; | |
for(var i = 0, len=nodes.length; i<len; i++){ | |
to_draw = to_draw.concat(self._draw_row_dendrogram_node(nodes[i][0], nodes[i][1])); | |
} | |
nodes = to_draw.map(function(x, i){return x}); | |
} | |
self.middle_item_count = (self.min_item_count+self.max_item_count)/2; | |
self._draw_distance_scale(node.distance); | |
self.stage.add(self.dendrogram_layer); | |
self.current_leaf_ids = Object.keys(self.leaves_y_coordinates); | |
self._bind_dendrogram_hover_events(self.dendrogram_layer); | |
self.dendrogram_layer.on("click", function(evt){ | |
self._dendrogram_layers_click(this, evt); | |
}); | |
self.dendrogram_layer.on("mousedown", function(evt){ | |
self._dendrogram_layers_mousedown(this, evt); | |
}); | |
self.dendrogram_layer.on("mouseup", function(evt){ | |
self._dendrogram_layers_mouseup(this, evt); | |
}); | |
} | |
InCHlib.prototype._draw_row_dendrogram_node = function(node, node_options){ | |
var self = this; | |
var to_draw = []; | |
if(node.color !== undefined){ | |
node_options.color = node.color; | |
} | |
else if(node_options.color !== undefined){ | |
node.color = node_options.color; | |
} | |
if(node.count > 1){ | |
var node_neighbourhood = self._get_node_neighbourhood(node, self.data.nodes); | |
var right_child = self.data.nodes[node.right_child]; | |
var left_child = self.data.nodes[node.left_child]; | |
var y1 = self._get_y1(node_neighbourhood, node_options.current_left_count, node_options.current_right_count); | |
var y2 = self._get_y2(node_neighbourhood, node_options.current_left_count, node_options.current_right_count); | |
var left_distance = self.distance; | |
var right_distance = self.distance; | |
if(self.settings.dendrogram.unified_distance){ | |
var x1 = self._hack_round(self.distance - node.level*self.distance_step*self.unified_distance_step); | |
if(self.data.nodes[node.left_child].count > 1){ | |
left_distance = self.distance - self.data.nodes[node.left_child].level*self.distance_step*self.unified_distance_step; | |
} | |
if(self.data.nodes[node.right_child].count > 1){ | |
right_distance = self.distance - self.data.nodes[node.right_child].level*self.distance_step*self.unified_distance_step; | |
} | |
} | |
else{ | |
var x1 = self._hack_round(self.distance - self.distance_step*node.distance); | |
left_distance = self.distance - self.distance_step*self.data.nodes[node.left_child].distance; | |
right_distance = self.distance - self.distance_step*self.data.nodes[node.right_child].distance; | |
} | |
x1 = (x1 == 0)? 2: x1; | |
var x2 = x1; | |
if(right_child.count == 1){ | |
y2 = y2 + self.pixels_for_leaf/2; | |
} | |
self.dendrogram_layer.add(self._draw_horizontal_path(node_options.node_id, x1, y1, x2, y2, left_distance, right_distance, node_options.color)); | |
to_draw.push([left_child, {node_id: node.left_child, current_left_count: node_options.current_left_count - node_neighbourhood.left_node.right_count, current_right_count: node_options.current_right_count + node_neighbourhood.left_node.right_count, x: left_distance, y: y1, color: node_options.color}]); | |
to_draw.push([right_child, {node_id: node.right_child, current_left_count: node_options.current_left_count + node_neighbourhood.right_node.left_count, current_right_count: node_options.current_right_count - node_neighbourhood.right_node.left_count, x: right_distance, y: y2, color: node_options.color}]); | |
} | |
else{ | |
var objects = node.objects; | |
self.leaves_y_coordinates[node_options.node_id] = node_options.y; | |
for(var i = 0, len = objects.length; i<len; i++){ | |
self.objects2leaves[objects[i]] = node_options.node_id; | |
} | |
var count = node.objects.length; | |
if(count<self.min_item_count){ | |
self.min_item_count = count; | |
} | |
if(count>self.max_item_count){ | |
self.max_item_count = count; | |
} | |
} | |
return to_draw; | |
} | |
InCHlib.prototype._draw_stage_layer = function(){ | |
var self = this; | |
self.stage_layer = new Konva.Layer(); | |
var stage_rect = new Konva.Rect({ | |
x: 0, | |
y: 0, | |
width: self.settings.width, | |
height: self.settings.height, | |
opacity: 0, | |
preventDefault: false | |
}); | |
self.stage_layer.add(stage_rect); | |
stage_rect.moveToBottom(); | |
self.stage.add(self.stage_layer); | |
self.stage_layer.on("click", function(evt){ | |
self.unhighlight_cluster(); | |
self.unhighlight_column_cluster(); | |
self.events.empty_space_onclick(evt); | |
}); | |
} | |
InCHlib.prototype._draw_column_dendrogram = function(node_id){ | |
var self = this; | |
self.column_dendrogram_layer = new Konva.Layer(); | |
self.column_x_coordinates = {}; | |
var node = self.column_dendrogram.nodes[node_id]; | |
self.current_column_count = node.count; | |
self.vertical_distance = self.header_height; | |
self.vertical_distance_step = self.vertical_distance/node.distance; | |
self.last_highlighted_column_cluster = null; | |
var current_left_count = self.column_dendrogram.nodes[node.left_child].count; | |
var current_right_count = self.column_dendrogram.nodes[node.right_child].count; | |
self._draw_column_dendrogram_node(node_id, node, current_left_count, current_right_count, 0, 0); | |
self.stage.add(self.column_dendrogram_layer); | |
if(!self.nodes2columns){ | |
self.nodes2columns = self._get_nodes2columns(); | |
}; | |
self._bind_dendrogram_hover_events(self.column_dendrogram_layer); | |
self.column_dendrogram_layer.on("click", function(evt){ | |
self._column_dendrogram_layers_click(this, evt); | |
}); | |
self.column_dendrogram_layer.on("mousedown", function(evt){ | |
self._column_dendrogram_layers_mousedown(this, evt); | |
}); | |
self.column_dendrogram_layer.on("mouseup", function(evt){ | |
self._dendrogram_layers_mouseup(this, evt); | |
}); | |
} | |
InCHlib.prototype._get_nodes2columns = function(){ | |
var self = this; | |
var coordinates = []; | |
var coordinates2nodes = {}; | |
var nodes2columns = {}; | |
var key, value, i; | |
for(i = 0, keys = Object.keys(self.column_x_coordinates), len = keys.length; i < len; i++){ | |
key = keys[i]; | |
value = self.column_x_coordinates[key]; | |
coordinates2nodes[value] = key; | |
coordinates.push(value); | |
} | |
coordinates.sort(function(a,b){return a - b}); | |
for(i = 0, len = coordinates.length; i<len; i++){ | |
nodes2columns[coordinates2nodes[coordinates[i]]] = i; | |
} | |
return nodes2columns; | |
} | |
InCHlib.prototype._bind_dendrogram_hover_events = function(layer){ | |
var self = this; | |
layer.on("mouseover", function(evt){ | |
self._dendrogram_layers_mouseover(this, evt); | |
}); | |
layer.on("mouseout", function(evt){ | |
self._dendrogram_layers_mouseout(this, evt); | |
}); | |
} | |
InCHlib.prototype._delete_layers = function(to_destroy, to_remove_children){ | |
var self = this; | |
for(var i = 0, len = to_destroy.length; i < len; i++){ | |
if(to_destroy[i] !== undefined){ | |
to_destroy[i].destroy(); | |
} | |
} | |
if(to_remove_children !== undefined){ | |
for(var i = 0, len = to_remove_children.length; i < len; i++){ | |
to_remove_children[i].removeChildren(); | |
to_remove_children[i].draw(); | |
} | |
} | |
} | |
InCHlib.prototype._delete_all_layers = function(){ | |
var self = this; | |
self.stage.destroyChildren(); | |
} | |
InCHlib.prototype._adjust_leaf_size = function(leaves){ | |
var self = this; | |
self.pixels_for_leaf = (self.settings.max_height-self.header_height-self.footer_height-self.column_metadata_height-5)/leaves; | |
if(self.settings.row_ids.draw && self.settings.row_ids.fixed_size){ | |
self.settings.heatmap.row_height.min = self.settings.row_ids.fixed_size + 2; | |
} | |
if(self.pixels_for_leaf > self.settings.heatmap.row_height.max){ | |
self.pixels_for_leaf = self.settings.heatmap.row_height.max; | |
} | |
if(self.settings.heatmap.row_height.min > self.pixels_for_leaf){ | |
self.pixels_for_leaf = self.settings.heatmap.row_height.min; | |
} | |
} | |
InCHlib.prototype._adjust_horizontal_sizes = function(dimensions){ | |
var self = this; | |
if(self.right_margin === undefined){ | |
self.right_margin = 100; | |
} | |
if(dimensions === undefined){ | |
dimensions = self._get_visible_count(); | |
} | |
if(self.settings.dendrogram.draw){ | |
if(self.settings.heatmap.draw){ | |
self.heatmap_width = (self.settings.width - self.right_margin - self.dendrogram_heatmap_distance)*self.settings.heatmap.relative_width; | |
} | |
else{ | |
self.heatmap_width = 0; | |
} | |
self.pixels_for_dimension = (dimensions > 0 && self.heatmap_width > 0)?self.heatmap_width/dimensions:0; | |
if(self.pixels_for_dimension === 0){ | |
self.heatmap_width = 0; | |
} | |
self.distance = self.settings.width - self.heatmap_width - self.right_margin; | |
self.heatmap_distance = self.distance + self.dendrogram_heatmap_distance; | |
} | |
else{ | |
self.heatmap_width = self.settings.width - self.right_margin*2; | |
self.distance = self.right_margin; | |
self.heatmap_distance = self.distance; | |
self.pixels_for_dimension = dimensions?self.heatmap_width/dimensions:0; | |
} | |
if(self.settings.heatmap.column_width.max && self.settings.heatmap.column_width.max < self.pixels_for_dimension){ | |
self.pixels_for_dimension = self.settings.heatmap.column_width.max; | |
self.heatmap_width = dimensions*self.pixels_for_dimension; | |
if(self.settings.dendrogram.draw){ | |
self.distance = self.settings.width - self.heatmap_width - self.right_margin - self.dendrogram_heatmap_distance; | |
self.heatmap_distance = self.distance + self.dendrogram_heatmap_distance; | |
} | |
else{ | |
self.distance = self._hack_round((self.settings.width - self.heatmap_width)/2); | |
self.right_margin = self.distance; | |
self.heatmap_distance = self.distance; | |
} | |
} | |
} | |
InCHlib.prototype._set_color_settings = function(){ | |
var self = this; | |
var data = []; | |
for(i = 0, len = self.leaf_ids.length; i < len; i++){ | |
data.push(self.data.nodes[self.leaf_ids[i]].features); | |
} | |
self.data_descs = {}; | |
if(self.settings.heatmap.colors.independent_columns){ | |
self.data_descs = self._get_data_min_max_middle(data, "column", "heatmap"); | |
} | |
else{ | |
var min_max_middle = self._get_min_max_middle(data); | |
for(i = 0; i < self.dimensions["data"]; i++){ | |
self.data_descs[i] = {"min": min_max_middle[0], "max": min_max_middle[1], "middle": min_max_middle[2]}; | |
} | |
} | |
if(self.settings.metadata.draw){ | |
var metadata = []; | |
for(i = 0, len = self.leaf_ids.length; i < len; i++){ | |
metadata.push(self.metadata.nodes[self.leaf_ids[i]]); | |
} | |
self.metadata_descs = self._get_data_min_max_middle(metadata, "column", "metadata"); | |
} | |
} | |
InCHlib.prototype._set_heatmap_settings = function(){ | |
var self = this; | |
var i, keys, key, len, node; | |
self.header = []; | |
for(i = 0; i<self.dimensions["overall"]; i++){ | |
self.header.push(""); | |
} | |
if(self.settings.heatmap.columns_order.length === 0 || self.settings.heatmap.columns_order.length !== self.dimensions["data"]){ | |
self.settings.heatmap.columns_order = []; | |
for(i = 0; i < self.dimensions["data"]; i++){ | |
self.settings.heatmap.columns_order.push(i); | |
} | |
} | |
if(self.settings.metadata.draw){ | |
for(i = self.dimensions["data"]; i < self.dimensions["data"] + self.dimensions["metadata"]; i++){ | |
self.settings.heatmap.columns_order.push(i); | |
} | |
} | |
if(self.settings.count_column.draw){ | |
self.settings.heatmap.columns_order.push(self.settings.heatmap.columns_order.length); | |
} | |
self.features = {}; | |
for(i=0; i<self.settings.heatmap.columns_order.length; i++){ | |
self.features[i] = true; | |
} | |
self._set_on_features(); | |
self.heatmap_header = false; | |
self.metadata_header = false; | |
self.current_label = null; | |
self._set_color_settings(); | |
if(self.settings.alternative_data && self.json.alternative_data.feature_names !== undefined){ | |
self.heatmap_header = self.json.alternative_data.feature_names; | |
} | |
else if(self.data.feature_names !== undefined){ | |
self.heatmap_header = self.data.feature_names; | |
} | |
if(self.heatmap_header){ | |
for(i=0; i<self.dimensions["data"]; i++){ | |
self.header[i] = self.heatmap_header[self.on_features["data"][i]].trim(" "); | |
} | |
} | |
if(self.settings.metadata.draw){ | |
if(self.metadata.feature_names){ | |
self.metadata_header = self.metadata.feature_names; | |
for(i=0; i<self.dimensions["metadata"]; i++){ | |
self.header[self.dimensions["data"]+i] = self.metadata_header[i].trim(" "); | |
} | |
} | |
} | |
if(self.settings.column_metadata.draw){ | |
if(self.column_metadata.feature_names !== undefined){ | |
self.column_metadata_header = self.column_metadata.feature_names; | |
} | |
} | |
if(self.settings.count_column.draw){ | |
self.max_item_count = 1; | |
self.min_item_count = 1; | |
self.dimensions["overall"]++; | |
self.header.push("Count"); | |
} | |
self._adjust_horizontal_sizes(); | |
self.top_heatmap_distance = self.header_height + self.column_metadata_height + self.settings.column_metadata.row_height/2; | |
} | |
InCHlib.prototype._set_on_features = function(features){ | |
var self = this; | |
var key; | |
if(features === undefined){ | |
var features = []; | |
for(var i = 0, keys = Object.keys(self.features), len = keys.length; i < len; i++){ | |
key = keys[i]; | |
if(self.features[key]){ | |
features.push(self.settings.heatmap.columns_order[i]); | |
} | |
} | |
} | |
self.on_features = {"data":[], "metadata":[], "count_column":[]} | |
for(var i = 0, len = features.length; i < len; i++){ | |
key = features[i]; | |
if(key < self.dimensions["data"]){ | |
self.on_features["data"].push(key); | |
} | |
else if(key <= self.dimensions["data"] + self.dimensions["metadata"] - 1){ | |
self.on_features["metadata"].push(key-self.dimensions["data"]); | |
} | |
else{ | |
self.on_features["count_column"].push(0); | |
} | |
} | |
} | |
InCHlib.prototype._draw_heatmap = function(){ | |
var self = this; | |
console.time("HEATMAP"); | |
if(!self.settings.heatmap.draw){ | |
return; | |
} | |
var heatmap_row, row_id, col_number, col_label, row_values, y; | |
self.heatmap_layer = new Konva.Layer(); | |
self.heatmap_overlay = new Konva.Layer(); | |
self.current_draw_values = true; | |
self.max_value_length = self._get_max_value_length(); | |
self.value_font_size = self._get_font_size(self.max_value_length, self.pixels_for_dimension, self.pixels_for_leaf, 12); | |
if(self.value_font_size < 4){ | |
self.current_draw_values = false; | |
} | |
var x1 = self.heatmap_distance; | |
for(var i = 0, len = self.current_leaf_ids.length; i < len; i++){ | |
key = self.current_leaf_ids[i]; | |
y = self.leaves_y_coordinates[key]; | |
heatmap_row = self._draw_heatmap_row(key, x1, y); | |
self.heatmap_layer.add(heatmap_row); | |
self._bind_row_events(heatmap_row); | |
} | |
if(self.settings.column_metadata.draw){ | |
self.column_metadata_descs = self._get_data_min_max_middle(self.column_metadata.features, "row"); | |
y1 = self.header_height + 0.5*self.settings.column_metadata.row_height; | |
for(var i = 0, len = self.column_metadata.features.length; i < len; i++){ | |
heatmap_row = self._draw_column_metadata_row(self.column_metadata.features[i], i, x1, y1); | |
self.heatmap_layer.add(heatmap_row); | |
self._bind_row_events(heatmap_row); | |
y1 = y1 + self.settings.column_metadata.row_height; | |
} | |
} | |
if(self.settings.row_ids.draw){ | |
self._draw_row_ids(); | |
} | |
self.highlighted_rows_layer = new Konva.Layer(); | |
self.stage.add(self.heatmap_layer, self.heatmap_overlay, self.highlighted_rows_layer); | |
self.highlighted_rows_layer.moveToTop(); | |
self.row_overlay = self.objects_ref.heatmap_line.clone(); | |
self.column_overlay = self.objects_ref.heatmap_line.clone(); | |
self.heatmap_layer.on("mouseout", function(evt){ | |
self.last_header = null; | |
self.heatmap_overlay.destroyChildren(); | |
self.heatmap_overlay.draw(); | |
self.events.heatmap_onmouseout(evt); | |
}); | |
console.timeEnd("HEATMAP"); | |
} | |
InCHlib.prototype._draw_heatmap_row = function(node_id, x1, y1){ | |
var self = this; | |
var node = self.data.nodes[node_id]; | |
var row = new Konva.Group({id:node_id}); | |
var x2, y2, color, line, value, text, text_value, col_index; | |
for (var i = 0, len = self.on_features["data"].length; i < len; i++){ | |
col_index = self.on_features["data"][i]; | |
x2 = x1 + self.pixels_for_dimension; | |
y2 = y1; | |
value = node.features[col_index]; | |
text_value = value; | |
if(self.settings.alternative_data){ | |
text_value = self.alternative_data[node_id][col_index]; | |
} | |
if(self.settings.images.draw && ![undefined, null, ""].includes(text_value)){ | |
value = null; | |
var filepath = self.settings.images.path.dir + text_value + self.settings.images.path.ext; | |
filepath = escape(filepath); | |
if(self.path2image[text_value] === undefined){ | |
var image_obj = new Image(); | |
image_obj.src = filepath; | |
image_obj.onload = function(){ | |
self.image_counter++; | |
if(self.image_counter === Object.keys(self.path2image).length){ | |
self.heatmap_layer.draw(); | |
} | |
}; | |
self.path2image_obj[text_value] = image_obj; | |
self.path2image[text_value] = self.objects_ref.image.clone({image: self.path2image_obj[text_value]}); | |
} | |
var image = self.path2image[text_value].clone({width: self.pixels_for_dimension, | |
height: self.pixels_for_leaf, | |
x:x1, | |
y:y1 - self._hack_round(0.5*self.pixels_for_leaf), | |
points:[x1, y1, x1 + self.pixels_for_dimension, null], | |
column: ["d", col_index].join("_"), | |
value: text_value | |
}); | |
row.add(image); | |
} | |
else if(value !== null){ | |
color = self._get_color_for_value(value, self.data_descs[col_index]["min"], self.data_descs[col_index]["max"], self.data_descs[col_index]["middle"], self.settings.heatmap.colors.scale); | |
text_value = text_value.toString(); | |
line = self.objects_ref.heatmap_line.clone({ | |
stroke: color, | |
points: [x1, y1, x2, y2], | |
value: text_value, | |
column: ["d", col_index].join("_"), | |
strokeWidth: self.pixels_for_leaf, | |
}); | |
row.add(line); | |
if(self.current_draw_values){ | |
text = self.objects_ref.heatmap_value.clone({ | |
x: self._hack_round((x1 + x2)/2-(text_value).length*(self.value_font_size/4)), | |
y: self._hack_round(y1-self.value_font_size/2), | |
fontSize: self.value_font_size, | |
text: text_value, | |
}); | |
row.add(text); | |
} | |
} | |
x1 = x2; | |
} | |
if(self.settings.metadata.draw){ | |
var metadata = self.metadata.nodes[node_id]; | |
if(metadata !== undefined){ | |
var colors_predefined = Object.keys(self.settings.metadata.colors.value2color).length > 0; | |
for (var i = 0, len = self.on_features["metadata"].length; i < len; i++){ | |
col_index = self.on_features["metadata"][i]; | |
value = metadata[col_index]; | |
x2 = x1 + self.pixels_for_dimension; | |
y2 = y1; | |
if(value !== null && value !== undefined){ | |
text_value = value; | |
if(self.metadata_descs[col_index]["str2num"] !== undefined){ | |
value = self.metadata_descs[col_index]["str2num"][value]; | |
} | |
if(colors_predefined){ | |
color = self.settings.metadata.colors.value2color[text_value]; | |
if(color === undefined){ | |
color = self.settings.metadata.colors.default; | |
} | |
} | |
else{ | |
color = self._get_color_for_value(value, self.metadata_descs[col_index]["min"], self.metadata_descs[col_index]["max"], self.metadata_descs[col_index]["middle"], self.settings.metadata.colors.scale); | |
} | |
line = self.objects_ref.heatmap_line.clone({ | |
stroke: color, | |
points: [x1, y1, x2, y2], | |
value: text_value, | |
column: ["m", col_index].join("_"), | |
strokeWidth: self.pixels_for_leaf, | |
}); | |
row.add(line); | |
if(self.current_draw_values){ | |
text = self.objects_ref.heatmap_value.clone({ | |
text: text_value, | |
fontSize: self.value_font_size, | |
}); | |
width = text.getWidth(); | |
x = self._hack_round((x1+x2)/2-width/2); | |
y = self._hack_round(y1-self.value_font_size/2); | |
text.position({x:x, y:y}); | |
row.add(text); | |
} | |
} | |
x1 = x2; | |
} | |
} | |
} | |
if(self.settings.count_column.draw && self.features[self.dimensions["overall"]-1]){ | |
x2 = x1 + self.pixels_for_dimension; | |
var count = node.objects.length; | |
color = self._get_color_for_value(count, self.min_item_count, self.max_item_count, self.middle_item_count, self.settings.count_column.colors); | |
line = self.objects_ref.heatmap_line.clone({ | |
stroke: color, | |
points: [x1, y1, x2, y2], | |
value: count, | |
column: "Count", | |
strokeWidth: self.pixels_for_leaf, | |
}); | |
row.add(line); | |
if(self.current_draw_values){ | |
text = self.objects_ref.heatmap_value.clone({ | |
text: count, | |
}); | |
width = text.getWidth(); | |
x = self._hack_round((x1+x2)/2-width/2); | |
y = self._hack_round(y1-self.value_font_size/2); | |
text.position({x:x, y:y}); | |
row.add(text); | |
} | |
} | |
return row; | |
} | |
InCHlib.prototype._draw_column_metadata_row = function(data, row_index, x1, y1){ | |
var self = this; | |
var row = new Konva.Group({"class": "column_metadata"}); | |
var x2, y2, color, line, value, text, text_value, width, col_index; | |
var str2num = (self.column_metadata_descs[row_index]["str2num"] === undefined)?false:true; | |
var colors_predefined = Object.keys(self.settings.column_metadata.colors.value2color).length > 0; | |
for (var i = 0, len = self.on_features["data"].length; i < len; i++){ | |
col_index = self.on_features["data"][i]; | |
value = data[col_index]; | |
text_value = value; | |
if(str2num){ | |
value = self.column_metadata_descs[row_index]["str2num"][value]; | |
} | |
if(colors_predefined){ | |
color = self.settings.column_metadata.colors.value2color[text_value]; | |
if(color === undefined){ | |
color = self.settings.column_metadata.colors.default; | |
} | |
} | |
else{ | |
color = self._get_color_for_value(value, self.column_metadata_descs[row_index]["min"], self.column_metadata_descs[row_index]["max"], self.column_metadata_descs[row_index]["middle"], self.settings.column_metadata.colors.scale); | |
} | |
x2 = x1 + self.pixels_for_dimension; | |
y2 = y1; | |
line = self.objects_ref.heatmap_line.clone({ | |
strokeWidth: self.settings.column_metadata.row_height, | |
stroke: color, | |
value: text_value, | |
points: [x1, y1, x2, y2], | |
column: ["cm", row_index].join("_"), | |
}); | |
row.add(line); | |
x1 = x2; | |
} | |
if(self.settings.column_metadata.feature_names.draw){ | |
var text = self.objects_ref.heatmap_value.clone({ | |
x: x2 + 10, | |
y: self._hack_round(y2 - self.settings.column_metadata.row_height/2), | |
fontSize: self.settings.column_metadata.row_height, | |
text: self.column_metadata.feature_names[row_index].toString(), | |
fill: "#000000", | |
fontWeight: "bold" | |
}); | |
self.heatmap_layer.add(text); | |
} | |
return row; | |
} | |
InCHlib.prototype._bind_row_events = function(row){ | |
var self = this; | |
row.on("mouseenter", function(evt){ | |
self._row_mouseenter(evt); | |
}); | |
row.on("mouseleave", function(evt){ | |
self._row_mouseleave(evt); | |
}); | |
row.on("mouseover", function(evt){ | |
self._draw_col_label(evt); | |
}); | |
row.on("mouseout", function(evt){ | |
self.heatmap_overlay.find("#col_label")[0].destroy(); | |
}); | |
row.on("click", function(evt){ | |
var row_id = evt.target.parent.attrs.id; | |
if(evt.target.parent.attrs.class !== "column_metadata"){ | |
var items = self.data.nodes[row_id].objects; | |
var item_ids = []; | |
for(i = 0; i < items.length; i++){ | |
item_ids.push(items[i]); | |
} | |
self.events.row_onclick(item_ids, evt); | |
var cell = self._get_cell_data(evt); | |
self.events.cell_click(cell, evt); | |
} | |
}); | |
} | |
InCHlib.prototype._draw_row_ids = function(){ | |
var self = this; | |
if(self.pixels_for_leaf < 6 || self.row_id_size < 5){ | |
return; | |
} | |
var i, objects, object_y = [], leaf, values = [], text; | |
for(i = 0, len = self.current_leaf_ids.length; i < len; i++){ | |
leaf_id = self.current_leaf_ids[i]; | |
objects = self.data.nodes[leaf_id].objects; | |
if(objects.length > 1){ | |
return; | |
} | |
object_y.push([objects[0], self.leaves_y_coordinates[leaf_id]]); | |
} | |
var x = self.distance + self._get_visible_count()*self.pixels_for_dimension + 15; | |
for(i = 0; i < object_y.length; i++){ | |
/*self.target_element.append($("<div>" + object_y[i][0].toString() + "</div>") | |
.css({ | |
"position": "absolute", "top": self._hack_round(object_y[i][1] - self.row_id_size/2), | |
"left": x, | |
"font-style": "italic", | |
"font-size": self.row_id_size, | |
"color": "gray" | |
}));*/ | |
text = self.objects_ref.heatmap_value.clone({ | |
x: x, | |
y: self._hack_round(object_y[i][1] - self.row_id_size/2), | |
fontSize: self.row_id_size, | |
text: object_y[i][0].toString(), | |
fontStyle: 'italic', | |
fill: "gray" | |
}); | |
self.heatmap_layer.add(text); | |
} | |
} | |
InCHlib.prototype._get_row_id_size = function(){ | |
var self = this; | |
var objects, object_y = [], leaf_id, values = [], text; | |
for(var i = 0, len = self.heatmap_array.length; i < len; i++){ | |
leaf_id = self.heatmap_array[i][0]; | |
objects = self.data.nodes[leaf_id].objects; | |
if(objects.length > 1){ | |
/*self.settings.row_ids.draw = false; | |
self.right_margin = 100; | |
return;*/ | |
values.push(objects[0] + " +" + (objects.length-1)); | |
} | |
else{ | |
values = values.concat(objects); | |
} | |
} | |
var max_length = self._get_max_length(values); | |
var test_string = ""; | |
for(var i = 0; i < max_length; i++){ | |
test_string += "E"; | |
} | |
if(self.settings.row_ids.fixed_size){ | |
var test = new Konva.Text({ | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fontSize: self.settings.row_ids.fixed_size, | |
fontStyle: "italic", | |
listening: false, | |
text: test_string, | |
preventDefault: false | |
}); | |
self.row_id_size = self.settings.row_ids.fixed_size; | |
self.right_margin = 20 + test.width(); | |
// if(this.right_margin < 100){ | |
// self.right_margin = 100; | |
// } | |
} | |
else{ | |
self.row_id_size = self._get_font_size(max_length, 85, self.pixels_for_leaf, 10); | |
self.right_margin = 100; | |
} | |
} | |
InCHlib.prototype._draw_heatmap_header = function(){ | |
var self = this; | |
if(self.settings.heatmap_header.draw && self.header.length > 0){ | |
self.header_layer = new Konva.Layer(); | |
var count = self.current_leaf_ids.length; | |
var distance_step = 0; | |
var x, i, column_header, key; | |
var current_headers = []; | |
var header_settings = self.settings.heatmap_header.settings; | |
for(i = 0, len = self.on_features["data"].length; i < len; i++){ | |
current_headers.push({"label": self.header[self.on_features["data"][i]], "min": self.data_descs[i].min, "max": self.data_descs[i].max}); | |
} | |
for(i = 0, len = self.on_features["metadata"].length; i < len; i++){ | |
var index = self.on_features["metadata"][i] + self.dimensions["data"]; | |
// current_headers.push({"label": self.header[index], "min": self.data_descs[index].min, "max": self.data_descs[index].max}); | |
current_headers.push({"label": self.header[index]}); | |
} | |
if(self.settings.count_column.draw && self.features[self.dimensions["overall"] - 1]){ | |
current_headers.push({"label": self.header[self.dimensions["overall"] - 1], "min": self.data_descs[self.dimensions["overall"] - 1].min, "max": self.data_descs[self.dimensions["overall"] - 1].max}); | |
} | |
var max_text_length = self._get_max_length(current_headers.map(x => x.label)); | |
if(header_settings.fontSize === undefined){ | |
var font_size = self._get_font_size(max_text_length, self.header_height, self.pixels_for_dimension, 16); | |
if(font_size < 6){ | |
return; | |
} | |
header_settings.fontSize = font_size; | |
} | |
var y = self.header_height - header_settings.fontSize/2; | |
var header_shift = self.pixels_for_dimension/2-header_settings.fontSize/2; | |
if(self.settings.column_dendrogram.draw && self.heatmap_header){ | |
y = self.header_height+(self.pixels_for_leaf*count) + 10 + self.column_metadata_height; | |
header_shift = header_settings.fontSize/2 + self.pixels_for_dimension/2; | |
}; | |
for(i = 0, len = current_headers.length; i<len; i++){ | |
x = self.heatmap_distance + distance_step*self.pixels_for_dimension + header_shift; | |
header_settings.x = x; | |
header_settings.y = y; | |
/*header_settings.text = current_headers[i].label + "\n" + current_headers[i].min + " - " + current_headers[i].max;*/ | |
header_settings.text = current_headers[i].label; | |
header_settings.position_index = i; | |
column_header = self.objects_ref.column_header.clone(header_settings); | |
self.header_layer.add(column_header); | |
distance_step++; | |
} | |
self.stage.add(self.header_layer); | |
if(!(self.settings.dendrogram.draw)){ | |
self.header_layer.on("click", function(evt){ | |
var column = evt.target; | |
var position_index = column.attrs.position_index; | |
for(i = 0; i<self.header_layer.getChildren().length; i++){ | |
self.header_layer.getChildren()[i].setFill("black"); | |
} | |
evt.target.setAttrs({"fill": "red"}); | |
self._delete_layers([self.heatmap_layer, self.heatmap_overlay, self.highlighted_rows_layer]); | |
self._reorder_heatmap(self._translate_column_to_feature_index(position_index)); | |
self._draw_heatmap(); | |
self.header_layer.draw(); | |
}); | |
self.header_layer.on("mouseover", function(evt){ | |
var label = evt.target; | |
label.setOpacity(0.7); | |
this.draw(); | |
}); | |
self.header_layer.on("mouseout", function(evt){ | |
var label = evt.target; | |
label.setOpacity(1); | |
this.draw(); | |
}); | |
} | |
} | |
} | |
InCHlib.prototype._translate_column_to_feature_index = function(column_index){ | |
var self = this; | |
var key; | |
var index = -1; | |
for(var i = 0, keys=Object.keys(self.features), len=keys.length; i<len; i++){ | |
key = keys[i]; | |
if(self.features[key]){ | |
index++; | |
if(column_index === index){ | |
return key; | |
} | |
} | |
} | |
} | |
InCHlib.prototype._draw_distance_scale = function(distance){ | |
var self = this; | |
if(!self.settings.navigation_toggle.distance_scale){ | |
return; | |
} | |
var y1 = self.header_height + self.column_metadata_height + self.settings.column_metadata.row_height/2 -10; | |
var y2 = y1; | |
var x1 = 0; | |
var x2 = self.distance; | |
var path = new Konva.Line({ | |
points: [x1, y1, x2, y2], | |
stroke: "black", | |
listening: false, | |
preventDefault: false | |
}); | |
var circle = new Konva.Circle({ | |
x: x2, | |
y: y2, | |
radius: 3, | |
fill: "black", | |
listening: false, | |
preventDefault: false | |
}); | |
var number = 0; | |
var marker_tail = 3; | |
var marker_distance = x2; | |
var marker_number_distance = self._hack_round(30/self.distance_step*10)/10; | |
var distance = Math.round(100*self.distance/self.distance_step)/100; | |
var marker_distance_step = self._hack_round(self.distance_step*marker_number_distance); | |
var marker_counter = 0; | |
var distance_number = new Konva.Text({ | |
x: 0, | |
y: y1-20, | |
text: distance, | |
fontSize: 12, | |
fontFamily: self.settings.heatmap.font.fontFamily, | |
fontStyle: 'bold', | |
fill: 'black', | |
align: 'right', | |
listening: false, | |
preventDefault: false | |
}); | |
self.dendrogram_layer.add(path, circle, distance_number); | |
if(marker_distance_step==0){ | |
marker_distance_step=0.5; | |
} | |
var path; | |
if(marker_number_distance > 0.1){ | |
while(marker_distance > 0){ | |
path = new Konva.Line({ | |
points: [marker_distance, (y1-marker_tail), marker_distance, (y2+marker_tail)], | |
stroke: "black", | |
listening: false, | |
preventDefault: false | |
}) | |
self.dendrogram_layer.add(path); | |
number = self._hack_round((number + marker_number_distance)*10)/10; | |
if(number>10){ | |
number = self._hack_round(number); | |
} | |
marker_distance = marker_distance - marker_distance_step; | |
marker_counter++; | |
} | |
} | |
} | |
InCHlib.prototype._draw_navigation = function(){ | |
var self = this; | |
self.navigation_layer = new Konva.Layer(); | |
var x = 0; | |
var y = 10; | |
if(self.settings.heatmap.draw){ | |
self._draw_color_scale(); | |
} | |
self._draw_help(); | |
if(!self.settings.column_dendrogram.draw && self.settings.heatmap.draw && self.settings.navigation_toggle.filter_button){ | |
var filter_icon = self.objects_ref.icon.clone({ | |
data: "M26.834,6.958c0-2.094-4.852-3.791-10.834-3.791c-5.983,0-10.833,1.697-10.833,3.791c0,0.429,0.213,0.84,0.588,1.224l8.662,15.002v4.899c0,0.414,0.709,0.75,1.583,0.75c0.875,0,1.584-0.336,1.584-0.75v-4.816l8.715-15.093h-0.045C26.625,7.792,26.834,7.384,26.834,6.958zM16,9.75c-6.363,0-9.833-1.845-9.833-2.792S9.637,4.167,16,4.167c6.363,0,9.834,1.844,9.834,2.791S22.363,9.75,16,9.75z", | |
x: x, | |
y: y, | |
label: "Filter\ncolumns" | |
}); | |
var filter_overlay = self._draw_icon_overlay(x, y); | |
self.navigation_layer.add(filter_icon, filter_overlay); | |
x = x + 40; | |
filter_overlay.on("click", function(){ | |
self._filter_icon_click(this); | |
}); | |
filter_overlay.on("mouseover", function(){ | |
self._icon_mouseover(filter_icon, filter_overlay, self.navigation_layer); | |
}); | |
filter_overlay.on("mouseout", function(){ | |
self._icon_mouseout(filter_icon, filter_overlay, self.navigation_layer); | |
}); | |
} | |
if(self.zoomed_clusters["row"].length > 0 || self.zoomed_clusters["column"].length > 0){ | |
var refresh_icon = self.objects_ref.icon.clone({ | |
data: "M24.083,15.5c-0.009,4.739-3.844,8.574-8.583,8.583c-4.741-0.009-8.577-3.844-8.585-8.583c0.008-4.741,3.844-8.577,8.585-8.585c1.913,0,3.665,0.629,5.09,1.686l-1.782,1.783l8.429,2.256l-2.26-8.427l-1.89,1.89c-2.072-1.677-4.717-2.688-7.587-2.688C8.826,3.418,3.418,8.826,3.416,15.5C3.418,22.175,8.826,27.583,15.5,27.583S27.583,22.175,27.583,15.5H24.083z", | |
x: x, | |
y: y, | |
id: "refresh_icon", | |
label: "Refresh" | |
}); | |
var refresh_overlay = self._draw_icon_overlay(x, y); | |
self.navigation_layer.add(refresh_icon, refresh_overlay); | |
refresh_overlay.on("click", function(){ | |
self._refresh_icon_click(); | |
self.events.on_refresh(); | |
}); | |
refresh_overlay.on("mouseover", function(){ | |
self._icon_mouseover(refresh_icon, refresh_overlay, self.navigation_layer); | |
}); | |
refresh_overlay.on("mouseout", function(){ | |
self._icon_mouseout(refresh_icon, refresh_overlay, self.navigation_layer); | |
}); | |
} | |
if(self.zoomed_clusters["row"].length > 0){ | |
x = self.distance - 55; | |
y = self.header_height + self.column_metadata_height - 40; | |
var unzoom_icon = self.objects_ref.icon.clone({ | |
data: self.paths_ref["unzoom_icon"], | |
x: x, | |
y: y, | |
scale: {x: 0.7, y: 0.7}, | |
label: "Unzoom\nrows" | |
}); | |
var unzoom_overlay = self._draw_icon_overlay(x, y); | |
self.navigation_layer.add(unzoom_icon, unzoom_overlay); | |
unzoom_overlay.on("click", function(){ | |
self._unzoom_icon_click(); | |
}); | |
unzoom_overlay.on("mouseover", function(){ | |
self._icon_mouseover(unzoom_icon, unzoom_overlay, self.navigation_layer); | |
}); | |
unzoom_overlay.on("mouseout", function(){ | |
self._icon_mouseout(unzoom_icon, unzoom_overlay, self.navigation_layer); | |
}); | |
} | |
if(self.zoomed_clusters["column"].length > 0){ | |
x = self.settings.width - self.right_margin + 10; | |
y = self.header_height - 50; | |
var column_unzoom_icon = self.objects_ref.icon.clone({ | |
data: self.paths_ref["unzoom_icon"], | |
x: x, | |
y: y-5, | |
scale: {x: 0.7, y: 0.7}, | |
label: "Unzoom\ncolumns" | |
}); | |
var column_unzoom_overlay = self._draw_icon_overlay(x, y); | |
self.navigation_layer.add(column_unzoom_icon, column_unzoom_overlay); | |
column_unzoom_overlay.on("click", function(){ | |
self._column_unzoom_icon_click(this); | |
}); | |
column_unzoom_overlay.on("mouseover", function(){ | |
self._icon_mouseover(column_unzoom_icon, column_unzoom_overlay, self.navigation_layer); | |
}); | |
column_unzoom_overlay.on("mouseout", function(){ | |
self._icon_mouseout(column_unzoom_icon, column_unzoom_overlay, self.navigation_layer); | |
}); | |
} | |
if(self.settings.navigation_toggle.export_button){ | |
var export_icon = self.objects_ref.icon.clone({ | |
data: "M24.25,10.25H20.5v-1.5h-9.375v1.5h-3.75c-1.104,0-2,0.896-2,2v10.375c0,1.104,0.896,2,2,2H24.25c1.104,0,2-0.896,2-2V12.25C26.25,11.146,25.354,10.25,24.25,10.25zM15.812,23.499c-3.342,0-6.06-2.719-6.06-6.061c0-3.342,2.718-6.062,6.06-6.062s6.062,2.72,6.062,6.062C21.874,20.78,19.153,23.499,15.812,23.499zM15.812,13.375c-2.244,0-4.062,1.819-4.062,4.062c0,2.244,1.819,4.062,4.062,4.062c2.244,0,4.062-1.818,4.062-4.062C19.875,15.194,18.057,13.375,15.812,13.375z", | |
x: self.settings.width - 30, | |
y: 10, | |
scale: {x: 0.7, y: 0.7}, | |
id: "export_icon", | |
label: "Export\nin png format" | |
}); | |
var export_overlay = self._draw_icon_overlay(self.settings.width - 30, 10); | |
self.navigation_layer.add(export_icon, export_overlay); | |
export_overlay.on("click", function(){ | |
self._export_icon_click(this); | |
}); | |
export_overlay.on("mouseover", function(){ | |
self._icon_mouseover(export_icon, export_overlay, self.navigation_layer); | |
}); | |
export_overlay.on("mouseout", function(){ | |
self._icon_mouseout(export_icon, export_overlay, self.navigation_layer); | |
}); | |
} | |
self.stage.add(self.navigation_layer); | |
}; | |
InCHlib.prototype._draw_help = function(){ | |
var self = this; | |
if(!self.settings.navigation_toggle.hint_button){ | |
return; | |
} | |
var help_icon = self.objects_ref.icon.clone({ | |
data: self.paths_ref["lightbulb"], | |
x: self.settings.width - 30, | |
y: 40, | |
scale: {x: 0.8, y: 0.8}, | |
id: "help_icon", | |
label: "Tip" | |
}); | |
var help_overlay = self._draw_icon_overlay(self.settings.width - 30, 40); | |
self.navigation_layer.add(help_icon, help_overlay); | |
help_overlay.on("mouseover", function(){ | |
self._icon_mouseover(help_icon, help_overlay, self.navigation_layer); | |
self._help_mouseover(); | |
}); | |
help_overlay.on("mouseout", function(){ | |
self._help_mouseout(); | |
self._icon_mouseout(help_icon, help_overlay, self.navigation_layer); | |
}); | |
} | |
InCHlib.prototype._draw_color_scale = function(){ | |
var self = this; | |
if(!self.settings.navigation_toggle.color_scale){ | |
return; | |
} | |
var color_steps = [self.settings.heatmap.colors.params.min/100*0.8, self._get_color_for_value(0, 0, 1, 0.5, self.settings.heatmap.colors.scale), self.settings.heatmap.colors.params.middle/100*0.8, self._get_color_for_value(0.5, 0, 1, 0.5, self.settings.heatmap.colors.scale), self.settings.heatmap.colors.params.max/100*0.8, self._get_color_for_value(1, 0, 1, 0.5, self.settings.heatmap.colors.scale)]; | |
var color_scale = self.objects_ref.rect_gradient.clone({"label": "Color settings", | |
"fillLinearGradientColorStops": color_steps, | |
"id": self.settings.target + "_color_scale"}); | |
color_scale.on("mouseover", function(){ | |
self._color_scale_mouseover(color_scale, self.navigation_layer); | |
}); | |
color_scale.on("mouseout", function(){ | |
self._color_scale_mouseout(color_scale, self.navigation_layer); | |
}); | |
color_scale.on("click", function(){ | |
self._color_scale_click(color_scale, self.navigation_layer); | |
}); | |
self.navigation_layer.add(color_scale); | |
} | |
InCHlib.prototype._update_color_scale = function(){ | |
var self = this; | |
var color_scale = self.navigation_layer.find("#" + self.settings.target + "_color_scale"); | |
color_scale.fillLinearGradientColorStops([self.settings.heatmap.colors.params.min/100*0.8, self._get_color_for_value(0, 0, 1, 0.5, self.settings.heatmap.colors.scale), self.settings.heatmap.colors.params.middle/100*0.8, self._get_color_for_value(0.5, 0, 1, 0.5, self.settings.heatmap.colors.scale), self.settings.heatmap.colors.params.max/100*0.8, self._get_color_for_value(1, 0, 1, 0.5, self.settings.heatmap.colors.scale)]); | |
self.navigation_layer.draw(); | |
} | |
InCHlib.prototype._draw_icon_overlay = function(x, y){ | |
var self = this; | |
return self.objects_ref.icon_overlay.clone({x: x, y: y}); | |
} | |
InCHlib.prototype._highlight_path = function(path_id, color){ | |
var self = this; | |
var node = self.data.nodes[path_id]; | |
if(color === undefined && node.color !== undefined){ | |
color = node.color; | |
} | |
else if(color === undefined && node.color === undefined){ | |
color = "gray"; | |
} | |
else if(color !== undefined && node.color !== undefined && color !== node.color){ | |
color = node.color; | |
} | |
if(node.count != 1){ | |
self.dendrogram_layer.get("#"+path_id)[0].stroke(color); | |
self._highlight_path(node.left_child, color); | |
self._highlight_path(node.right_child, color); | |
} | |
else{ | |
self.highlighted_rows_y.push(self.leaves_y_coordinates[path_id]); | |
self.current_object_ids.push.apply(self.current_object_ids, node["objects"]) | |
} | |
} | |
InCHlib.prototype._highlight_column_path = function(path_id, color){ | |
var self = this; | |
var node = self.column_dendrogram.nodes[path_id]; | |
if(node.count != 1){ | |
self.column_dendrogram_layer.get("#col"+path_id)[0].stroke(color); | |
self._highlight_column_path(node.left_child, color); | |
self._highlight_column_path(node.right_child, color); | |
} | |
else{ | |
self.current_column_ids.push(self.nodes2columns[path_id]); | |
} | |
} | |
/** | |
* Unhighlight highlighted heatmap rows. | |
* | |
* @example | |
* instance.unhighlight_rows(); | |
*/ | |
InCHlib.prototype.unhighlight_rows = function(){ | |
var self = this; | |
self.highlight_rows([]); | |
} | |
/** | |
* Highlight heatmap rows with color defined in instance.settings.highlight_colors. | |
* When the empty array is passed it unhighlights all highlighted rows. | |
* | |
* @param {object} [row_ids] The array of heatmap row (object) IDs. | |
* | |
* @example | |
* instance.highlight_rows(["CHEMBL7781", "CHEMBL273658", "CHEMBL415309", "CHEMBL267231", "CHEMBL8007", "CHEMBL7987", "CHEMBL7988", "CHEMBL266282", "CHEMBL7655", "CHEMBL7817", "CHEMBL8637", "CHEMBL8639", "CHEMBL8055", "CHEMBL7843", "CHEMBL266488", "CHEMBL8329"]); | |
*/ | |
InCHlib.prototype.highlight_rows = function(row_ids){ | |
var self = this; | |
var i, row, row_id; | |
if(!self.settings.heatmap.draw){ | |
return; | |
} | |
self.settings.highlighted_rows = row_ids; | |
self.highlighted_rows_layer.destroyChildren(); | |
var original_colors = self.settings.heatmap.colors.scale; | |
var original_metadata_colors = self.settings.metadata.colors.scale; | |
self.settings.heatmap.colors.scale = self.settings.highlight_colors; | |
self.settings.metadata.colors.scale = self.settings.highlight_colors; | |
var done_rows = {}; | |
var unique_row_ids = []; | |
for(i = 0; i<row_ids.length; i++){ | |
if(self.objects2leaves[row_ids[i]] !== undefined){ | |
row_id = self.objects2leaves[row_ids[i]]; | |
if(done_rows[row_id] === undefined){ | |
unique_row_ids.push(row_id); | |
done_rows[row_id] = null; | |
} | |
} | |
} | |
for(i = 0; i<unique_row_ids.length; i++){ | |
row = self._draw_heatmap_row(unique_row_ids[i], self.heatmap_distance, self.leaves_y_coordinates[unique_row_ids[i]]); | |
self.highlighted_rows_layer.add(row); | |
row.setAttr("listening", false); | |
} | |
self.highlighted_rows_layer.draw(); | |
self.heatmap_overlay.moveToTop(); | |
self.settings.heatmap.colors.scale = original_colors; | |
self.settings.metadata.colors.scale = original_metadata_colors; | |
self.highlighted_rows_layer.on("click", function(evt){ | |
self.heatmap_layer.fire("click"); | |
}); | |
} | |
InCHlib.prototype._highlight_cluster = function(path_id){ | |
var self = this; | |
var previous_cluster = self.last_highlighted_cluster; | |
if(previous_cluster){ | |
self.unhighlight_cluster(); | |
} | |
if(previous_cluster !== path_id){ | |
self.last_highlighted_cluster = path_id; | |
self._highlight_path(path_id, "#F5273C"); | |
self._draw_cluster_layer(path_id); | |
self.events.dendrogram_node_highlight(self.current_object_ids, self._unprefix(path_id)); | |
} | |
self.dendrogram_layer.draw(); | |
} | |
InCHlib.prototype._highlight_column_cluster = function(path_id){ | |
var self = this; | |
var previous_cluster = self.last_highlighted_column_cluster; | |
if(previous_cluster){ | |
self.unhighlight_column_cluster() | |
} | |
if(previous_cluster !== path_id){ | |
self.last_highlighted_column_cluster = path_id; | |
self._highlight_column_path(path_id, "#F5273C"); | |
self.current_column_ids.sort(function(a,b){return a - b}); | |
self._draw_column_cluster_layer(path_id); | |
self.events.column_dendrogram_node_highlight(self.current_column_ids, self._unprefix(path_id)); | |
} | |
self.column_dendrogram_layer.draw(); | |
} | |
InCHlib.prototype.unhighlight_column_cluster = function(){ | |
var self = this; | |
if(self.last_highlighted_column_cluster){ | |
self._highlight_column_path(self.last_highlighted_column_cluster, "grey"); | |
self.column_dendrogram_layer.draw(); | |
self.column_cluster_group.destroy(); | |
self.cluster_layer.draw(); | |
self.current_column_ids = []; | |
self.events.column_dendrogram_node_unhighlight(self._unprefix(self.last_highlighted_column_cluster)); | |
self.last_highlighted_column_cluster = null; | |
} | |
} | |
/** | |
* Highlight cluster defined by the dendrogram node ID. | |
* | |
* @param {string} node_id The ID of particular node in dendrogram. | |
* | |
* @example | |
* instance.highlight_cluster("node@715"); | |
*/ | |
InCHlib.prototype.highlight_cluster = function(node_id){ | |
var self = this; | |
return self._highlight_cluster(self._prefix(node_id)); | |
} | |
/** | |
* Highlight column cluster defined by the dendrogram node ID. | |
* | |
* @param {string} node_id The ID of particular node in dendrogram. | |
* | |
* @example | |
* instance.highlight_column_cluster("node@715"); | |
*/ | |
InCHlib.prototype.highlight_column_cluster = function(node_id){ | |
var self = this; | |
return self._highlight_column_cluster(self._prefix(node_id)); | |
} | |
/** | |
* Unhighlight highlighted dendrogram node (cluster). | |
* | |
* @example | |
* instance.unhighlight_cluster(); | |
*/ | |
InCHlib.prototype.unhighlight_cluster = function(){ | |
var self = this; | |
if(self.last_highlighted_cluster){ | |
self._highlight_path(self.last_highlighted_cluster); | |
self.dendrogram_layer.draw(); | |
self.row_cluster_group.destroy(); | |
self.cluster_layer.draw(); | |
self.events.dendrogram_node_unhighlight(self._unprefix(self.last_highlighted_cluster)); | |
self.highlighted_rows_y = []; | |
self.current_object_ids = []; | |
self.last_highlighted_cluster = null; | |
} | |
} | |
InCHlib.prototype._neutralize_path = function(path_id){ | |
var self = this; | |
var node = self.data.nodes[path_id]; | |
if(node.count != 1){ | |
var path = self.dendrogram_layer.get("#"+path_id)[0]; | |
if(path){ | |
path.setStroke("grey"); | |
self._neutralize_path(node.right_child); | |
self._neutralize_path(node.left_child); | |
} | |
} | |
} | |
InCHlib.prototype._draw_cluster_layer = function(path_id){ | |
var self = this; | |
self.row_cluster_group = new Konva.Group(); | |
var visible = self._get_visible_count(); | |
var count = self.data.nodes[path_id].count; | |
var x = self.distance - 30; | |
var y = self.header_height + self.column_metadata_height - 40; | |
var rows_desc = self.objects_ref.count.clone({x: x + 10, | |
y: y - 10, | |
text: count, | |
}); | |
var zoom_icon = self.objects_ref.icon.clone({ | |
data: self.paths_ref["zoom_icon"], | |
x: x, | |
y: y, | |
scale: {x: 0.7, y: 0.7}, | |
label: "Zoom\nrows", | |
}); | |
var zoom_overlay = self._draw_icon_overlay(x, y); | |
x = self.distance + self.dendrogram_heatmap_distance; | |
var width = visible*self.pixels_for_dimension+self.heatmap_distance; | |
var upper_y = self.highlighted_rows_y[0]-self.pixels_for_leaf/2; | |
var lower_y = self.highlighted_rows_y[self.highlighted_rows_y.length-1]+self.pixels_for_leaf/2; | |
var cluster_overlay_1 = self.objects_ref.cluster_overlay.clone({ | |
x: x, | |
y: self.header_height + self.column_metadata_height + 5, | |
width: width, | |
height: self._hack_round(upper_y -self.header_height - self.column_metadata_height - 5), | |
}); | |
var cluster_border_1 = self.objects_ref.cluster_border.clone({ | |
points: [0, upper_y, width, upper_y], | |
}); | |
var cluster_overlay_2 = self.objects_ref.cluster_overlay.clone({ | |
x: x, | |
y: lower_y, | |
width: width, | |
height: self.settings.height-lower_y-self.footer_height + 5, | |
}); | |
var cluster_border_2 = self.objects_ref.cluster_border.clone({ | |
points: [0, lower_y, width, lower_y], | |
}); | |
self.row_cluster_group.add(rows_desc, cluster_overlay_1, cluster_overlay_2, zoom_icon, zoom_overlay, cluster_border_1, cluster_border_2); | |
self.cluster_layer.add(self.row_cluster_group); | |
self.stage.add(self.cluster_layer); | |
rows_desc.moveToTop(); | |
self.cluster_layer.draw(); | |
self.cluster_layer.moveToTop(); | |
self.navigation_layer.moveToTop(); | |
zoom_overlay.on("mouseover", function(){ | |
self._icon_mouseover(zoom_icon, zoom_overlay, self.cluster_layer); | |
}); | |
zoom_overlay.on("mouseout", function(){ | |
self._icon_mouseout(zoom_icon, zoom_overlay, self.cluster_layer); | |
}); | |
zoom_overlay.on("click", function(){ | |
self._zoom_cluster(self.last_highlighted_cluster); | |
}); | |
} | |
InCHlib.prototype._draw_column_cluster_layer = function(path_id){ | |
var self = this; | |
self.column_cluster_group = new Konva.Group(); | |
var count = self.column_dendrogram.nodes[path_id].count; | |
var x = self.settings.width - self.right_margin + 10; | |
var y = self.header_height - 25; | |
var cols_desc = self.objects_ref.count.clone({x: x + 15, | |
y: y - 5, | |
text: count, | |
}); | |
var zoom_icon = self.objects_ref.icon.clone({ | |
data: self.paths_ref["zoom_icon"], | |
x: x, | |
y: y, | |
scale: {x: 0.7, y: 0.7}, | |
label: "Zoom\ncolumns", | |
}); | |
var zoom_overlay = self._draw_icon_overlay(x, y); | |
var x1 = self._hack_round((self.current_column_ids[0] - self.columns_start_index)*self.pixels_for_dimension); | |
var x2 = self._hack_round((self.current_column_ids[0] + self.current_column_ids.length - self.columns_start_index)*self.pixels_for_dimension); | |
var y1 = 0; | |
var height = self.settings.height-self.footer_height-self.header_height+self.settings.column_metadata.row_height+self.column_metadata_height; | |
var y2 = height+self.header_height; | |
var cluster_border_1 = self.objects_ref.cluster_border.clone({ | |
points: [self.heatmap_distance + x1, y1, self.heatmap_distance + x1, y2], | |
}); | |
var cluster_overlay_1 = self.objects_ref.cluster_overlay.clone({ | |
x: self.heatmap_distance, | |
y: self.header_height, | |
width: x1, | |
height: height, | |
}); | |
var cluster_border_2 = self.objects_ref.cluster_border.clone({ | |
points: [self.heatmap_distance + x2, y1, self.heatmap_distance + x2, y2], | |
}); | |
var cluster_overlay_2 = self.objects_ref.cluster_overlay.clone({ | |
x: x2+self.heatmap_distance, | |
y: self.header_height, | |
width: self.heatmap_width - x2 - (self.on_features["metadata"].length + self.on_features["count_column"].length)*self.pixels_for_dimension, | |
height: height, | |
}); | |
self.column_cluster_group.add(cluster_overlay_1, cluster_overlay_2, zoom_icon, zoom_overlay, cols_desc, cluster_border_1, cluster_border_2); | |
self.cluster_layer.add(self.column_cluster_group); | |
self.stage.add(self.cluster_layer); | |
self.cluster_layer.draw(); | |
self.cluster_layer.moveToTop(); | |
self.navigation_layer.moveToTop(); | |
zoom_overlay.on("mouseover", function(){ | |
self._icon_mouseover(zoom_icon, zoom_overlay, self.cluster_layer); | |
}); | |
zoom_overlay.on("mouseout", function(){ | |
self._icon_mouseout(zoom_icon, zoom_overlay, self.cluster_layer); | |
}); | |
zoom_overlay.on("click", function(){ | |
self._zoom_column_cluster(self.last_highlighted_column_cluster); | |
}); | |
} | |
InCHlib.prototype._draw_column_cluster = function(node_id){ | |
var self = this; | |
self.columns_start_index = self.current_column_ids[0]; | |
self.on_features["data"] = self.current_column_ids; | |
var distance = self.distance; | |
self._adjust_horizontal_sizes(); | |
self._delete_layers([self.column_dendrogram_layer, self.heatmap_layer, self.heatmap_overlay, self.column_cluster_group, self.navigation_layer, self.highlighted_rows_layer], [self.dendrogram_hover_layer]); | |
if(self.settings.heatmap_header.draw){ | |
self._delete_layers([self.header_layer]); | |
} | |
self._draw_column_dendrogram(node_id); | |
self._draw_heatmap(); | |
self._draw_heatmap_header(); | |
self._draw_navigation(); | |
if(self.settings.dendrogram.draw){ | |
if(distance !== self.distance){ | |
self._delete_layers([self.dendrogram_layer, self.cluster_layer]); | |
var row_node = (self.zoomed_clusters["row"].length > 0)?self.zoomed_clusters["row"][self.zoomed_clusters["row"].length - 1]:self.root_id; | |
self._draw_row_dendrogram(row_node); | |
if(self.last_highlighted_cluster !== null){ | |
self._highlight_path(self.last_highlighted_cluster, "#F5273C"); | |
self.dendrogram_layer.draw(); | |
self._draw_cluster_layer(self.last_highlighted_cluster); | |
} | |
} | |
else{ | |
self.cluster_layer.moveToTop(); | |
self.cluster_layer.draw(); | |
} | |
} | |
} | |
InCHlib.prototype._zoom_column_cluster = function(node_id){ | |
var self = this; | |
if(node_id != self.column_root_id){ | |
self.zoomed_clusters["column"].push(node_id); | |
self._draw_column_cluster(node_id); | |
self.highlight_rows(self.settings.highlighted_rows); | |
self.events.on_columns_zoom(self.current_column_ids, self._unprefix(node_id)); | |
self.current_column_ids = []; | |
self.last_highlighted_column_cluster = null; | |
} | |
} | |
InCHlib.prototype._unzoom_column_cluster = function(){ | |
var self = this; | |
var unzoomed = self.zoomed_clusters["column"].pop(); | |
var zoomed_count = self.zoomed_clusters["column"].length; | |
var node_id = (zoomed_count > 0)?self.zoomed_clusters["column"][zoomed_count-1]:self.column_root_id; | |
self._get_column_ids(node_id); | |
self._draw_column_cluster(node_id); | |
self.events.on_columns_unzoom(self._unprefix(unzoomed)); | |
self.current_column_ids = []; | |
self._highlight_column_cluster(unzoomed); | |
} | |
InCHlib.prototype._draw_cluster = function(node_id){ | |
var self = this; | |
self._delete_layers([self.dendrogram_layer, self.heatmap_layer, self.heatmap_overlay, self.cluster_layer, self.navigation_layer, self.header_layer, self.highlighted_rows_layer], [self.dendrogram_hover_layer]); | |
self._draw_row_dendrogram(node_id); | |
self._get_row_id_size(); | |
self._draw_heatmap(); | |
self._draw_heatmap_header(); | |
self._draw_navigation(); | |
if(self.settings.column_dendrogram.draw && self.last_highlighted_column_cluster !== null){ | |
self._draw_column_cluster_layer(self.last_highlighted_column_cluster); | |
} | |
} | |
InCHlib.prototype._zoom_cluster = function(node_id){ | |
var self = this; | |
if(node_id !== self.root_id){ | |
self.zoomed_clusters["row"].push(node_id); | |
self._draw_cluster(node_id); | |
self.highlight_rows(self.settings.highlighted_rows); | |
self.events.on_zoom(self.current_object_ids, self._unprefix(node_id)); | |
self.highlighted_rows_y = []; | |
self.current_object_ids = []; | |
self.last_highlighted_cluster = null; | |
} | |
} | |
InCHlib.prototype._unzoom_cluster = function(){ | |
var self = this; | |
var unzoomed = self.zoomed_clusters["row"].pop(); | |
var zoomed_count = self.zoomed_clusters["row"].length; | |
var node_id = (zoomed_count > 0)?self.zoomed_clusters["row"][zoomed_count-1]:self.root_id; | |
self._draw_cluster(node_id); | |
self.events.on_unzoom(self._unprefix(unzoomed)); | |
self._highlight_cluster(unzoomed); | |
} | |
InCHlib.prototype._get_node_neighbourhood = function(node, nodes){ | |
var self = this; | |
var node_neighbourhood = {"left_node": {"left_node": {"left_count" : 0, | |
"right_count": 0}, | |
"right_node": {"left_count" : 0, | |
"right_count": 0}, | |
"left_count" : 0.5, | |
"right_count": 0.5 | |
}, | |
"right_node": {"left_node": {"left_count" : 0, | |
"right_count": 0}, | |
"right_node": {"left_count" : 0, | |
"right_count": 0}, | |
"left_count" : 0.5, | |
"right_count": 0.5 | |
}, | |
"left_count": nodes[node.left_child].count, | |
"right_count": nodes[node.right_child].count, | |
}; | |
var left_child = nodes[node.left_child]; | |
var right_child = nodes[node.right_child]; | |
var left_child_left_child = nodes[left_child.left_child]; | |
var left_child_right_child = nodes[left_child.right_child]; | |
var right_child_left_child = nodes[right_child.left_child]; | |
var right_child_right_child = nodes[right_child.right_child]; | |
if(left_child.count != 1){ | |
node_neighbourhood.left_node.left_count = nodes[left_child.left_child].count; | |
node_neighbourhood.left_node.right_count = nodes[left_child.right_child].count; | |
if(left_child_left_child.count != 1){ | |
node_neighbourhood.left_node.left_node.left_count = nodes[left_child_left_child.left_child].count; | |
node_neighbourhood.left_node.left_node.right_count = nodes[left_child_left_child.right_child].count; | |
} | |
else{ | |
node_neighbourhood.left_node.left_node.left_count = 0.5; | |
node_neighbourhood.left_node.left_node.right_count = 0.5; | |
} | |
if(left_child_right_child.count != 1){ | |
node_neighbourhood.left_node.right_node.left_count = nodes[left_child_right_child.left_child].count; | |
node_neighbourhood.left_node.right_node.right_count = nodes[left_child_right_child.right_child].count; | |
} | |
else{ | |
node_neighbourhood.left_node.right_node.left_count = 0.5; | |
node_neighbourhood.left_node.right_node.right_count = 0.5; | |
} | |
} | |
if(right_child.count != 1){ | |
node_neighbourhood.right_node.left_count = nodes[right_child.left_child].count; | |
node_neighbourhood.right_node.right_count = nodes[right_child.right_child].count; | |
if(right_child_left_child.count != 1){ | |
node_neighbourhood.right_node.left_node.left_count = nodes[right_child_left_child.left_child].count; | |
node_neighbourhood.right_node.left_node.right_count = nodes[right_child_left_child.right_child].count; | |
} | |
else{ | |
node_neighbourhood.right_node.left_node.left_count = 0.5; | |
node_neighbourhood.right_node.left_node.right_count = 0.5; | |
} | |
if(right_child_right_child.count != 1){ | |
node_neighbourhood.right_node.right_node.left_count = nodes[right_child_right_child.left_child].count; | |
node_neighbourhood.right_node.right_node.right_count = nodes[right_child_right_child.right_child].count; | |
} | |
else{ | |
node_neighbourhood.right_node.right_node.left_count = 0.5; | |
node_neighbourhood.right_node.right_node.right_count = 0.5; | |
} | |
} | |
return node_neighbourhood; | |
} | |
InCHlib.prototype._draw_column_dendrogram_node = function(node_id, node, current_left_count, current_right_count, x, y){ | |
var self = this; | |
if(node.count > 1){ | |
var node_neighbourhood = self._get_node_neighbourhood(node, self.column_dendrogram.nodes); | |
var right_child = self.column_dendrogram.nodes[node.right_child]; | |
var left_child = self.column_dendrogram.nodes[node.left_child]; | |
var x1 = self._get_x1(node_neighbourhood, current_left_count, current_right_count); | |
var x2 = self._get_x2(node_neighbourhood, current_left_count, current_right_count); | |
var y1 = self._hack_round(self.vertical_distance - self.vertical_distance_step*node.distance); | |
y1 = (y1 == 0)? 2: y1; | |
var y2 = y1; | |
if(right_child.count == 1){ | |
x2 = x2 - self.pixels_for_dimension/2; | |
} | |
var left_distance = self.vertical_distance - self.vertical_distance_step*self.column_dendrogram.nodes[node.left_child].distance; | |
var right_distance = self.vertical_distance - self.vertical_distance_step*self.column_dendrogram.nodes[node.right_child].distance; | |
self.column_dendrogram_layer.add(self._draw_vertical_path(node_id, x1, y1, x2, y2, left_distance, right_distance)); | |
self._draw_column_dendrogram_node(node.left_child, left_child, current_left_count - node_neighbourhood.left_node.right_count, current_right_count + node_neighbourhood.left_node.right_count, left_distance, y1); | |
self._draw_column_dendrogram_node(node.right_child, right_child, current_left_count + node_neighbourhood.right_node.left_count, current_right_count - node_neighbourhood.right_node.left_count, right_distance, y2); | |
} | |
else{ | |
self.column_x_coordinates[node_id] = current_right_count*self.pixels_for_dimension; | |
} | |
} | |
InCHlib.prototype._get_y1 = function(node_neighbourhood, current_left_count, current_right_count){ | |
var self = this; | |
current_left_count = current_left_count-node_neighbourhood.left_node.right_count-node_neighbourhood.left_node.left_node.right_count; | |
var y = (current_left_count+(node_neighbourhood.left_node.left_node.right_count+node_neighbourhood.left_node.right_node.left_count)/2)*self.pixels_for_leaf; | |
return y + self.top_heatmap_distance; | |
} | |
InCHlib.prototype._get_y2 = function(node_neighbourhood, current_left_count, current_right_count){ | |
var self = this; | |
current_left_count = current_left_count+node_neighbourhood.right_node.left_node.left_count; | |
var y = (current_left_count+(node_neighbourhood.right_node.left_node.right_count+node_neighbourhood.right_node.right_node.left_count)/2)*self.pixels_for_leaf; | |
return y + self.top_heatmap_distance; | |
} | |
InCHlib.prototype._get_x1 = function(node_neighbourhood, current_left_count, current_right_count){ | |
var self = this; | |
current_left_count = current_left_count-node_neighbourhood.left_node.right_count-node_neighbourhood.left_node.left_node.right_count; | |
var x = (current_left_count+(node_neighbourhood.left_node.left_node.right_count+node_neighbourhood.left_node.right_node.left_count)/2)*self.pixels_for_dimension; | |
return (self.heatmap_distance+self.on_features["data"].length * self.pixels_for_dimension)-x; | |
} | |
InCHlib.prototype._get_x2 = function(node_neighbourhood, current_left_count, current_right_count){ | |
var self = this; | |
current_left_count = current_left_count+node_neighbourhood.right_node.left_node.left_count; | |
var x = (current_left_count+(node_neighbourhood.right_node.left_node.right_count+node_neighbourhood.right_node.right_node.left_count)/2)*self.pixels_for_dimension;; | |
return (self.heatmap_distance+self.on_features["data"].length * self.pixels_for_dimension)-x; | |
} | |
InCHlib.prototype._draw_vertical_path = function(path_id, x1, y1, x2, y2, left_distance, right_distance){ | |
var self = this; | |
var path_group = new Konva.Group({}); | |
var path = self.objects_ref.node.clone({points: [x1, left_distance, x1, y1, x2, y2, x2, right_distance], id: "col" + path_id,}) | |
var path_rect = self.objects_ref.node_rect.clone({x: x2-1, | |
y: y1-1, | |
width: x1 - x2 + 2, | |
height: self.header_height - y1, | |
id: "col_rect" + path_id, | |
path: path, | |
path_id: path_id, | |
}); | |
path_group.add(path, path_rect); | |
return path_group; | |
} | |
InCHlib.prototype._draw_horizontal_path = function(path_id, x1, y1, x2, y2, left_distance, right_distance, path_color){ | |
var self = this; | |
if(path_color === undefined){ | |
path_color = "gray"; | |
} | |
var path_group = new Konva.Group({}); | |
var path = self.objects_ref.node.clone({points: [left_distance, y1, x1, y1, x2, y2, right_distance, y2], | |
id: path_id, stroke: path_color}); | |
var path_rect = self.objects_ref.node_rect.clone({x: x1-1, | |
y: y1-1, | |
width: self.distance - x1, | |
height: y2 - y1, | |
id: [path_id, "rect"].join("_"), | |
path: path, | |
path_id: path_id, | |
}); | |
path_group.add(path, path_rect); | |
return path_group; | |
} | |
InCHlib.prototype._filter_icon_click = function(filter_button){ | |
var self = this; | |
var filter_features_element = self.target_element.find(".filter_features"); | |
var symbol = "✖"; | |
if(filter_features_element.length){ | |
filter_features_element.fadeIn("fast"); | |
var overlay = self._draw_target_overlay(); | |
} | |
else{ | |
filter_list = ""; | |
for(var attr in self.header){ | |
if(self.features[attr]){ | |
symbol = "✔"; | |
} | |
if(attr < self.dimensions){ | |
var text = self.header[attr]; | |
if(text == ""){ | |
text = parseInt(attr) + 1 + ". column"; | |
} | |
filter_list = filter_list + "<li class='feature_switch' data-num='" + attr + "'><span class='symbol'>" + symbol + "</span> " + text +"</li>"; | |
} | |
} | |
self.target_element.append("<div class='filter_features'><ul>" + filter_list + "</ul><hr /><div><span class='cancel_filter_list'>Cancel</span> <span class='update_filter_list'>Update</span></div></div>"); | |
filter_features_element = self.target_element.find(".filter_features"); | |
filter_features_element.css({"display":"none", | |
"top": 45, | |
"left": 0, | |
"border-radius":"5px", | |
"text-align":"center", | |
"position":"absolute", | |
"background-color":"#ffffff", | |
"border":"solid 2px #DEDEDE", | |
"padding-top":"5px", | |
"padding-left":"15px", | |
"padding-bottom":"10px", | |
"padding-right":"15px", | |
"font-weight":"bold", | |
"font-size": "14px", | |
"z-index": 1000, | |
"font-family": self.settings.heatmap.font.fontFamily | |
}); | |
filter_features_element.find("ul").css({ | |
"list-style-type":"none", | |
"margin-left":"0", | |
"padding-left":"0", | |
"text-align":"left", | |
}); | |
filter_features_element.find("li").css({ | |
"color":"green", | |
"margin-top":"5px", | |
}); | |
filter_features_element.find("div").css({ | |
"cursor":"pointer", | |
"opacity":"0.7", | |
}); | |
var overlay = self._draw_target_overlay(); | |
filter_features_element.fadeIn("fast"); | |
self.target_element.find(".feature_switch").click(function(){ | |
var num = parseInt($(this).attr("data-num")); | |
var symbol_element = $(this).find("span"); | |
self.features[num] = !self.features[num]; | |
if(self.features[num]){ | |
symbol_element.text("✔"); | |
$(this).css("color", "green"); | |
} | |
else{ | |
symbol_element.text("✖"); | |
$(this).css("color", "red"); | |
} | |
self._set_on_features(); | |
}); | |
$(function(){ | |
filter_features_element.click(function(){ | |
return false; | |
}); | |
filter_features_element.mousedown(function(){ | |
return false; | |
}); | |
$("#" + self.settings.target + " .filter_features ul li," + "#" + self.settings.target + " .filter_features div span").hover( | |
function(){ | |
$(this).css({ | |
"cursor": "pointer", | |
"opacity": "0.7", | |
}); | |
}, | |
function(){ | |
$(this).css({ | |
"cursor": "default", | |
"opacity": "1", | |
}); | |
}); | |
}); | |
self.target_element.find(".cancel_filter_list").click(function(){ | |
filter_features_element.fadeOut("fast"); | |
overlay.fadeOut("fast"); | |
}); | |
overlay.click(function(){ | |
filter_features_element.fadeOut("fast"); | |
overlay.fadeOut("fast"); | |
}); | |
self.target_element.find(".update_filter_list").click(function(){ | |
filter_features_element.fadeOut("slow"); | |
overlay.fadeOut("slow"); | |
var node_id = (self.zoomed_clusters["row"].length > 0)?self.zoomed_clusters["row"][self.zoomed_clusters["row"].length-1]:self.root_id; | |
var highlighted_cluster = self.last_highlighted_cluster; | |
self.last_highlighted_cluster = null; | |
self._adjust_horizontal_sizes(); | |
self._delete_all_layers(); | |
self._draw_stage_layer(); | |
if(self.settings.dendrogram.draw){ | |
self._draw_dendrogram_layers(); | |
self._draw_row_dendrogram(node_id); | |
self._draw_dendrogram_layers(); | |
if(self.settings.column_dendrogram.draw && self._visible_features_equal_column_dendrogram_count()){ | |
self._draw_column_dendrogram(self.column_root_id); | |
} | |
} | |
self._draw_navigation(); | |
self._draw_heatmap(); | |
self._draw_heatmap_header(); | |
if(highlighted_cluster != null){ | |
self._highlight_cluster(highlighted_cluster); | |
} | |
}); | |
} | |
} | |
InCHlib.prototype._draw_target_overlay = function(){ | |
var self = this; | |
var overlay = self.target_element.find(".target_overlay"); | |
if(overlay.length){ | |
overlay.fadeIn("fast"); | |
} | |
else{ | |
overlay = $("<div class='target_overlay'></div>"); | |
overlay.css({"background-color": "white", | |
"position": "absolute", | |
"top": 0, | |
"left": 0, | |
"right": 0, | |
"bottom": 0, | |
"opacity": 0.5 | |
}); | |
self.target_element.append(overlay); | |
} | |
return overlay; | |
} | |
InCHlib.prototype._refresh_icon_click = function(){ | |
var self = this; | |
self.redraw(); | |
} | |
InCHlib.prototype._export_icon_click = function(){ | |
var self = this; | |
var export_menu = self.target_element.find(".export_menu"); | |
var overlay = self._draw_target_overlay(); | |
if(export_menu.length){ | |
export_menu.fadeIn("fast"); | |
} | |
else{ | |
export_menu = $("<div class='export_menu'><div><button type='submit' data-action='open'>Show image</button></div><div><button type='submit' data-action='save'>Save image</button></div></div>"); | |
self.target_element.append(export_menu); | |
export_menu.css({"position": "absolute", | |
"top": 45, | |
"left": self.settings.width - 125, | |
"font-size": "12px", | |
"border": "solid #D2D2D2 1px", | |
"border-radius": "5px", | |
"padding": "2px", | |
"background-color": "white"}); | |
var buttons = export_menu.find("button"); | |
buttons.css({"padding-top": "7px", "padding-bottom": "5px", "padding-right": "8px", "padding-left": "8px", "color": "white", "border": "solid #D2D2D2 1px", "width": "100%", "background-color": "#2171b5", "font-weight": "bold"}); | |
buttons.hover( | |
function(){$(this).css({"cursor": "pointer", "opacity": 0.7})}, | |
function(){$(this).css({"opacity": 1})} | |
); | |
overlay.click(function(){ | |
export_menu.fadeOut("fast"); | |
overlay.fadeOut("fast"); | |
}); | |
buttons.click(function(){ | |
var action = $(this).attr("data-action"); | |
var zoom = 3; | |
var width = self.stage.width(); | |
var height = self.stage.height(); | |
var loading_div = $("<h3 style='margin-top: 100px; margin-left: 100px; width: " + width + "px; height: " + height + "px;'>Loading...</h3>"); | |
self.target_element.after(loading_div); | |
self.target_element.hide(); | |
self.stage.width(width*zoom); | |
self.stage.height(height*zoom); | |
self.stage.scale({x: zoom, y:zoom}); | |
self.stage.draw(); | |
self.navigation_layer.hide(); | |
self.stage.toDataURL({ | |
quality: 1, | |
callback: function(dataUrl){ | |
if(action === "open"){ | |
open_image(dataUrl); | |
} | |
else{ | |
download_image(dataUrl); | |
} | |
self.stage.width(width); | |
self.stage.height(height); | |
self.stage.scale({x: 1, y:1}); | |
self.stage.draw(); | |
loading_div.remove(); | |
self.target_element.show(); | |
self.navigation_layer.show(); | |
self.navigation_layer.draw(); | |
overlay.trigger("click"); | |
} | |
}); | |
}); | |
} | |
function download_image(dataUrl){ | |
var fileName = 'inchlib.png'; | |
if ('msToBlob' in self.stage) { // IE10+ | |
var blob = self.stage.msToBlob(); | |
navigator.msSaveBlob(blob, fileName); | |
} else { | |
var a = document.createElement('a'); | |
a.setAttribute('href', dataUrl); | |
a.setAttribute('target', '_blank'); | |
a.setAttribute('download', fileName); | |
a.style.display = 'none'; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
} | |
}; | |
function open_image(dataUrl){ | |
window.open(dataUrl, "_blank"); | |
}; | |
}; | |
InCHlib.prototype._color_scale_click = function(icon, evt){ | |
var self = this; | |
var i, option, key, value; | |
var color_options = {"heatmap": "Heatmap data colors"}; | |
var value_options = ["min", "middle", "max"]; | |
if(self.settings.metadata.draw){ | |
color_options["metadata"] = "Metadata colors"; | |
} | |
if(self.settings.column_metadata.draw){ | |
color_options["column_metadata"] = "Column metadata colors"; | |
} | |
var settings_form = self.target_element.find(".inchlib-settings_form"); | |
var overlay = self._draw_target_overlay(); | |
if(settings_form.length){ | |
settings_form.fadeIn("fast"); | |
} | |
else{ | |
settings_form = $("<form class='inchlib-settings_form'></form>"); | |
var options = "", color_1, color_2, color_3; | |
for(i = 0, keys = Object.keys(color_options), len = keys.length; i < len; i++){ | |
key = keys[i]; | |
var section = $("<div class='inchlib-section' data-name='" + key + "' ></div>").css({"margin-bottom": 5, "padding-bottom": 5, "border-bottom": "solid #D2D2D2 1px"}); | |
color_1 = self._get_color_for_value(0,0,1,0.5,self.settings[key].colors.scale); | |
color_2 = self._get_color_for_value(0.5,0,1,0.5,self.settings[key].colors.scale); | |
color_3 = self._get_color_for_value(1,0,1,0.5,self.settings[key].colors.scale); | |
section.append($("<div class='form_label'>" + color_options[key] + "</div>")); | |
section.append($("<div><input class='inchlib-color_input' type='text' name='colors.scale' value='"+ self.settings[key].colors.scale + "'/> <div class='color_button' style='background: linear-gradient(to right, " + color_1 + "," + color_2 + "," + color_3 + ")'></div></div>") | |
.css({"display": "flex", "align-items": "center"})); | |
var params = $("<div class='inchlib-params'></div>").css({"display": "flex", "justify-content": "space-between"}); | |
for(i2 = 0, len2 = value_options.length; i2 < len2; i2++){ | |
key2 = value_options[i2]; | |
params.append($("<div><div class='form_label'>" + key2 + "</div><input type='text' name='colors.params." + key2 +"' value='"+ self.settings[key].colors.params[key2] + "'/></div>")); | |
} | |
section.append(params); | |
section.append($("<div><div class='form_label'>Value type</div>\ | |
<select name='value_type'>\ | |
<option value='percentile' selected>Percentile</option>\ | |
<option value='value'>Value</option>\ | |
</select></div>\ | |
<div><div class='form_label'>Color by</div>\ | |
<select name='independent_columns'>\ | |
<option value='true' selected>By columns</option>\ | |
<option value='false'>Entire heatmap</option>\ | |
</select></div>")); | |
settings_form.append(section); | |
} | |
settings_form.append($("<button type='submit'>Redraw</button>")); | |
self.target_element.append(settings_form); | |
settings_form.css({"width": 150, "z-index": 1000, "position": "absolute", "top": 110, "left": 0, "padding": "10px", "border": "solid #D2D2D2 2px", "border-radius": "5px", "background-color": "white", "font-size": "small"}); | |
self.target_element.find(".inchlib-settings_form .color_button").css({"border": "solid #D2D2D2 1px", "height": "15px", "width": "30px", "display": "inline-block"}); | |
self.target_element.find(".inchlib-settings_form input[type='text']").css({"width": 40}); | |
self.target_element.find(".inchlib-settings_form .inchlib-color_input").css({"width": 80, "margin-right": 3}); | |
self.target_element.find(".inchlib-settings_form .inchlib-section > *").css({"margin-bottom": 5}); | |
self.target_element.find(".inchlib-settings_form .form_label").css({"color": "gray", "margin-bottom": 5, "font-style": "italic"}); | |
self.target_element.find(".inchlib-settings_form button").css({"padding": 5, "color": "white", "border": "none", "width": "100%", "background-color": "#2171b5", "font-weight": "bold"}); | |
overlay.click(function(){ | |
settings_form.fadeOut("fast"); | |
overlay.fadeOut("fast"); | |
}); | |
var color_buttons = settings_form.find(".color_button"); | |
color_buttons.hover( | |
function(){$(this).css({"cursor": "pointer", "opacity": 0.7})}, | |
function(){$(this).css({"opacity": 1})} | |
); | |
color_buttons.click(function(evt){ | |
self._draw_color_scales_select(this, evt); | |
}); | |
settings_form.submit(function(evt){ | |
var settings_fieldset = $(this).find("input, select"); | |
evt.preventDefault(); | |
evt.stopPropagation(); | |
settings_fieldset.each(function(){ | |
var settings_section = $(this).parents(".inchlib-section").attr("data-name"); | |
option = $(this); | |
key = option.attr("name"); | |
var path = key.split("."); | |
value = option.val(); | |
if(value_options.indexOf(path[path.length - 1]) !== -1){ | |
value = parseFloat(value); | |
} | |
if(path.length == 1){ | |
self.settings[settings_section][path[0]] = value; | |
} | |
else if(path.length == 2){ | |
self.settings[settings_section][path[0]][path[1]] = value; | |
} | |
else{ | |
self.settings[settings_section][path[0]][path[1]][path[2]] = value; | |
} | |
}); | |
self.redraw_heatmap(); | |
self._update_color_scale(); | |
overlay.trigger('click'); | |
}) | |
} | |
} | |
InCHlib.prototype._draw_color_scales_select = function(element, evt){ | |
var self = this; | |
var scales_div = self.target_element.find(".color_scales"); | |
var scale_divs; | |
if(scales_div.length){ | |
scales_div.fadeIn("fast"); | |
scale_divs = scales_div.find(".color_scale"); | |
} | |
else{ | |
scales_div = $("<div class='color_scales'></div>").css({"z-index": 10}); | |
var scale, color_1, color_2, color_3, key; | |
for(var i = 0, keys = Object.keys(self.colors), len = keys.length; i < len; i++){ | |
key = keys[i]; | |
color_1 = self._get_color_for_value(0,0,1,0.5,key); | |
color_2 = self._get_color_for_value(0.5,0,1,0.5,key); | |
color_3 = self._get_color_for_value(1,0,1,0.5,key); | |
scale = "<div class='color_scale' data-scale_acronym='" + key + "' style='background: linear-gradient(to right, " + color_1 + "," + color_2 + "," + color_3 + ")'></div>"; | |
scales_div.append(scale); | |
} | |
self.target_element.append(scales_div); | |
scales_div.css({"border": "solid #D2D2D2 2px", | |
"border-radius": "5px", | |
"padding": "5px", | |
"position": "absolute", | |
"top": 110, | |
"left": 170, | |
"background-color": "white"}); | |
scale_divs = self.target_element.find(".color_scale"); | |
scale_divs.css({"margin-top":"3px", | |
"width": "80px", | |
"height": "20px", | |
"border": "solid #D2D2D2 1px",}); | |
scale_divs.hover( | |
function(){$(this).css({"cursor": "pointer", "opacity": 0.7})}, | |
function(){$(this).css({"opacity": 1})} | |
); | |
self.target_element.find(".target_overlay").click(function(){ | |
scales_div.fadeOut("fast"); | |
}); | |
} | |
scale_divs.on("click", function(){ | |
var color = $(this).attr("data-scale_acronym"); | |
var input = $(element).prev("input:first").val(color); | |
$(element).css({"background": "linear-gradient(to right, " + self._get_color_for_value(0,0,1,0.5,color) + "," + self._get_color_for_value(0.5,0,1,0.5,color) + "," + self._get_color_for_value(1,0,1,0.5,color) + ")"}) | |
scales_div.fadeOut("fast"); | |
scale_divs.off("click"); | |
}); | |
}; | |
InCHlib.prototype._color_scale_mouseover = function(color_scale, layer){ | |
var self = this; | |
var label = color_scale.getAttr("label"); | |
var x = color_scale.getAttr("x"); | |
var y = color_scale.getAttr("y"); | |
self.icon_tooltip = self.objects_ref.tooltip_label.clone({x: x, | |
y: y + 25 | |
}); | |
self.icon_tooltip.add(self.objects_ref.tooltip_tag.clone()); | |
self.icon_tooltip.add(self.objects_ref.tooltip_text.clone({text: label})); | |
layer.add(self.icon_tooltip); | |
self.icon_tooltip.moveToTop(); | |
color_scale.setOpacity(0.7); | |
layer.draw(); | |
} | |
InCHlib.prototype._color_scale_mouseout = function(color_scale, layer){ | |
var self = this; | |
self.icon_tooltip.destroy(); | |
color_scale.setOpacity(1); | |
layer.draw(); | |
} | |
InCHlib.prototype._unzoom_icon_click = function(){ | |
var self = this; | |
self._unzoom_cluster(); | |
}; | |
InCHlib.prototype._column_unzoom_icon_click = function(){ | |
var self = this; | |
self._unzoom_column_cluster(); | |
}; | |
InCHlib.prototype._icon_mouseover = function(icon, icon_overlay, layer){ | |
var self = this; | |
if(icon.getAttr("id") !== "help_icon"){ | |
var label = icon.getAttr("label"); | |
var x = icon_overlay.getAttr("x"); | |
var y = icon_overlay.getAttr("y"); | |
var width = icon_overlay.getWidth(); | |
var height = icon_overlay.getHeight(); | |
var icon_id = icon.getAttr("id"); | |
if(icon_id === "export_icon"){ | |
x = x - 100; | |
y = y - 50; | |
} | |
self.icon_tooltip = self.objects_ref.tooltip_label.clone({x: x, | |
y: y+1.2*height | |
}); | |
self.icon_tooltip.add(self.objects_ref.tooltip_tag.clone()); | |
self.icon_tooltip.add(self.objects_ref.tooltip_text.clone({text: label})); | |
layer.add(self.icon_tooltip); | |
} | |
icon.setFill("black"); | |
layer.draw(); | |
} | |
InCHlib.prototype._icon_mouseout = function(icon, icon_overlay, layer){ | |
var self = this; | |
if(icon.getAttr("id") !== "help_icon"){ | |
self.icon_tooltip.destroy(); | |
} | |
icon.setFill("grey"); | |
layer.draw(); | |
} | |
InCHlib.prototype._help_mouseover = function(){ | |
var self = this; | |
var help_element = self.target_element.find(".inchlib_help"); | |
if(help_element.length){ | |
help_element.show(); | |
} | |
else{ | |
help_element = $("<div class='inchlib_help'><ul><li>Zoom clusters by a long click on a dendrogram node.</li></ul></div>"); | |
help_element.css({"position": "absolute", | |
"top": 70, | |
"left": self.settings.width - 200, | |
"font-size": 12, | |
"padding-right": 15, | |
"width": 200, | |
"background-color": "white", | |
"border-radius": 5, | |
"border": "solid #DEDEDE 2px", | |
"z-index": 1000 | |
}); | |
self.target_element.append(help_element); | |
} | |
} | |
InCHlib.prototype._help_mouseout = function(){ | |
var self = this; | |
self.target_element.find(".inchlib_help").hide(); | |
} | |
InCHlib.prototype._dendrogram_layers_click=function(layer, evt){ | |
var self = this; | |
var path_id = evt.target.attrs.path_id; | |
layer.fire("mouseout", layer, evt); | |
self._highlight_cluster(path_id); | |
self.events.dendrogram_node_onclick(self.current_object_ids, self._unprefix(path_id), evt); | |
} | |
InCHlib.prototype._column_dendrogram_layers_click=function(layer, evt){ | |
var self = this; | |
var path_id = evt.target.attrs.path_id; | |
layer.fire("mouseout", layer, evt); | |
self._highlight_column_cluster(path_id); | |
self.events.column_dendrogram_node_onclick(self.current_column_ids, self._unprefix(path_id), evt); | |
} | |
InCHlib.prototype._dendrogram_layers_mousedown = function(layer, evt){ | |
// if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw) | |
var self = this; | |
// if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw) | |
var node_id = evt.target.attrs.path_id; | |
clearTimeout(self.timer); | |
self.timer = setTimeout(function() { | |
self._get_object_ids(node_id); | |
self._zoom_cluster(node_id); | |
}, 500); | |
} | |
InCHlib.prototype._column_dendrogram_layers_mousedown = function(layer, evt){ | |
// if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw) | |
var self = this; | |
// if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw) | |
var node_id = evt.target.attrs.path_id; | |
clearTimeout(self.timer); | |
self.timer = setTimeout(function() { | |
self._get_column_ids(node_id); | |
self._zoom_column_cluster(node_id); | |
}, 500); | |
} | |
// if(self.settings.dendrogram.draw || self.settings.column_dendrogram.draw) | |
InCHlib.prototype._dendrogram_layers_mouseup = function(layer, evt){ | |
var self = this; | |
clearTimeout(self.timer); | |
} | |
InCHlib.prototype._dendrogram_layers_mouseout = function(layer, evt){ | |
var self = this; | |
if(self.path_overlay !== undefined){ | |
self.path_overlay.destroy(); | |
} | |
self.dendrogram_hover_layer.draw(); | |
} | |
InCHlib.prototype._dendrogram_layers_mouseover = function(layer, evt){ | |
var self = this; | |
self.path_overlay = evt.target.attrs.path.clone({"strokeWidth": 4}); | |
self.dendrogram_hover_layer.add(self.path_overlay); | |
self.dendrogram_hover_layer.draw(); | |
} | |
InCHlib.prototype._visible_features_equal_column_dendrogram_count = function(){ | |
var self = this; | |
if((self.on_features["data"].length + self.on_features["metadata"].length) == self.current_column_count){ | |
return true; | |
} | |
return false; | |
} | |
InCHlib.prototype._get_color_for_value = function(value, min, max, middle, color_scale){ | |
var self = this; | |
var color = self.colors[color_scale]; | |
var c1 = color["start"]; | |
var c2 = color["end"]; | |
if(value > max){ | |
return 'rgb('+c2.r+','+c2.g+','+c2.b+')'; | |
} | |
if(min == max || value < min){ | |
return 'rgb('+c1.r+','+c1.g+','+c1.b+')'; | |
} | |
if(color["middle"] !== undefined){ | |
if(value >= middle){ | |
if(middle == max){ | |
return 'rgb('+c2.r+','+c2.g+','+c2.b+')'; | |
} | |
min = middle; | |
c1 = color["middle"]; | |
c2 = color["end"]; | |
} | |
else{ | |
if(middle == min){ | |
return 'rgb('+c1.r+','+c1.g+','+c1.b+')'; | |
} | |
max = middle; | |
c1 = color["start"]; | |
c2 = color["middle"]; | |
} | |
} | |
var position = (value-min)/(max-min); | |
var r = self._hack_round(c1.r+(position*(c2.r-c1.r))); | |
var g = self._hack_round(c1.g+(position*(c2.g-c1.g))); | |
var b = self._hack_round(c1.b+(position*(c2.b-c1.b))); | |
return 'rgb('+r+','+g+','+b+')'; | |
} | |
InCHlib.prototype._get_font_size = function(text_length, width, height, max_font_size){ | |
var self = this; | |
var max_possible_size = height - 2; | |
var font_size = max_possible_size; | |
if(font_size/2*text_length > width-10){ | |
font_size = font_size/(font_size/2*text_length/(width-10)); | |
}; | |
font_size = (font_size > max_possible_size)?max_possible_size:font_size; | |
font_size = (font_size > max_font_size)?max_font_size:font_size; | |
return font_size; | |
} | |
InCHlib.prototype._get_object_ids = function(node_id){ | |
var self = this; | |
self.current_object_ids = []; | |
self._collect_object_ids(node_id); | |
} | |
InCHlib.prototype._collect_object_ids = function(node_id){ | |
var self = this; | |
if(self.data.nodes[node_id]["left_child"] !== undefined){ | |
self._collect_object_ids(self.data.nodes[node_id]["left_child"]); | |
self._collect_object_ids(self.data.nodes[node_id]["right_child"]); | |
} | |
else{ | |
self.current_object_ids.push.apply(self.current_object_ids, self.data.nodes[node_id]["objects"]) | |
} | |
} | |
InCHlib.prototype._get_column_ids = function(node_id){ | |
var self = this; | |
self.current_column_ids = []; | |
self._collect_column_ids(node_id); | |
self.current_column_ids.sort(function(a,b){return a - b}); | |
} | |
InCHlib.prototype._collect_column_ids = function(node_id){ | |
var self = this; | |
if(self.column_dendrogram.nodes[node_id]["left_child"] !== undefined){ | |
self._collect_column_ids(self.column_dendrogram.nodes[node_id]["left_child"]); | |
self._collect_column_ids(self.column_dendrogram.nodes[node_id]["right_child"]); | |
} | |
else{ | |
self.current_column_ids.push(self.nodes2columns[node_id]); | |
} | |
} | |
InCHlib.prototype._hack_size = function(obj) { | |
var self = this; | |
return Object.keys(obj).length; | |
}; | |
InCHlib.prototype._hack_round = function(value){ | |
var self = this; | |
return (0.5 + value) >> 0; | |
} | |
InCHlib.prototype._is_number = function(n){ | |
var self = this; | |
return !isNaN(parseFloat(n)) && isFinite(n); | |
} | |
InCHlib.prototype._row_mouseenter = function(evt){ | |
var self = this; | |
var row_id = evt.target.parent.getAttr("id"); | |
var visible = self._get_visible_count(); | |
if(evt.target.parent.attrs.class !== "column_metadata"){ | |
self.highlighted_row = row_id; | |
var y = self.leaves_y_coordinates[row_id]; | |
var x = self.heatmap_distance; | |
self.row_overlay = self.objects_ref.heatmap_line.clone({points: [x, y, x + self.heatmap_width, y], | |
strokeWidth: self.pixels_for_leaf, | |
stroke: "#FFFFFF", | |
opacity: 0.3, | |
listening: false}); | |
self.heatmap_overlay.add(self.row_overlay); | |
self.heatmap_overlay.draw(); | |
self.events.row_onmouseover(self.data.nodes[row_id].objects, evt); | |
} | |
} | |
InCHlib.prototype._row_mouseleave = function(evt){ | |
var self = this; | |
self.row_overlay.destroy(); | |
self.events.row_onmouseout(evt); | |
}; | |
InCHlib.prototype._get_cell_data = function(evt){ | |
var self = this; | |
var attrs = evt.target.attrs; | |
var column = attrs.column.split("_"); | |
var header_type2value = {"d": self.heatmap_header[column[1]], | |
"m": self.metadata_header[column[1]], | |
"Count": "Count"}; | |
if(self.column_metadata_header !== undefined){ | |
header_type2value["cm"] = self.column_metadata_header[column[1]]; | |
} | |
return {"value": attrs.value, "header": header_type2value[column[0]]}; | |
} | |
InCHlib.prototype._draw_col_label = function(evt){ | |
var self = this; | |
var parent = evt.target.parent; | |
var i, line; | |
var attrs = evt.target.attrs; | |
var points = attrs.points; | |
var x = self._hack_round((points[0] + points[2])/2); | |
var y = points[1]-0.5*self.pixels_for_leaf; | |
var column = attrs.column.split("_"); | |
var header_type2value = {"d": self.heatmap_header[column[1]], | |
"m": self.metadata_header[column[1]], | |
"Count": "Count"}; | |
if(self.column_metadata_header !== undefined){ | |
header_type2value["cm"] = self.column_metadata_header[column[1]]; | |
} | |
var header = header_type2value[column[0]]; | |
if(header !== self.last_column){ | |
self.column_overlay.destroy(); | |
self.last_column = attrs.column; | |
self.column_overlay = self.objects_ref.heatmap_line.clone({points: [x, self.header_height, x, self.header_height + self.column_metadata_height + (self.heatmap_array.length+0.5)*self.pixels_for_leaf], | |
strokeWidth: self.pixels_for_dimension, | |
stroke: "#FFFFFF", | |
opacity: 0.3, | |
listening: false}); | |
self.heatmap_overlay.add(self.column_overlay); | |
} | |
self.events.cell_mouseover({"value": value, "header": header}, evt); | |
var values = []; | |
if(self.settings.row_ids.tooltip && parent.getAttr("class") !== "column_metadata"){ | |
values.push(self.data.nodes[parent.getAttr("id")].objects.join(", ")); | |
} | |
if(header !== undefined){ | |
values.push(header); | |
} | |
values.push(attrs.value); | |
var value = values.join("\n"); | |
var tooltip = self.objects_ref.tooltip_label.clone({x: x, y:y, id: "col_label",}); | |
tooltip.add(self.objects_ref.tooltip_tag.clone({pointerDirection: 'down'}), self.objects_ref.tooltip_text.clone({text: value})); | |
self.heatmap_overlay.add(tooltip); | |
self.heatmap_overlay.moveToTop(); | |
self.heatmap_overlay.draw(); | |
} | |
InCHlib.prototype._unprefix = function(prefixed){ | |
var self = this; | |
return prefixed.split(self.settings.target+"#")[1]; | |
} | |
InCHlib.prototype._prefix = function(nonprefixed){ | |
var self = this; | |
return self.settings.target + "#" + nonprefixed; | |
} | |
/** | |
* Returns array of features for object by its ID. When sent object ID is not present, false is returned | |
*/ | |
InCHlib.prototype.get_features_for_object = function(object_id){ | |
var self = this; | |
if(self.objects2leaves[object_id] !== undefined){ | |
var row_id = self.objects2leaves[object_id]; | |
return self.data.nodes[row_id].features; | |
} | |
return false; | |
} | |
/** | |
* Adds a user defined color scale defined by its name start color, end color and optionaly middle color | |
*/ | |
InCHlib.prototype.add_color_scale = function(color_scale_name, color_scale){ | |
var self = this; | |
self.colors[color_scale_name] = color_scale; | |
self.target_element.find(".color_scales").remove(); | |
} | |
InCHlib.prototype._get_visible_count = function(){ | |
var self = this; | |
return self.on_features["data"].length + self.on_features["metadata"].length + self.on_features["count_column"].length; | |
} | |
/** | |
* Update cluster heatmap settings | |
*/ | |
InCHlib.prototype.update_settings = function(settings_object){ | |
var self = this; | |
var navigation_toggle = self.settings.navigation_toggle; | |
self.settings = deepmerge(self.settings, settings_object); | |
self.dynamic_width = false; | |
if(self.settings.width === "dynamic"){ | |
self.dynamic_width = true; | |
if(self.target_element.width() === 0){ | |
self.target_element.css({"width": "100%"}); | |
} | |
self.settings.width = self.target_element.width(); | |
} | |
} | |
/** | |
* Redraw cluster heatmap | |
*/ | |
InCHlib.prototype.redraw = function(){ | |
var self = this; | |
if(self.dynamic_width){ | |
self.settings.width = self.target_element.width(); | |
} | |
self._delete_all_layers(); | |
self.draw(); | |
} | |
/** | |
* Redraw heatmap only | |
*/ | |
InCHlib.prototype.redraw_heatmap = function(){ | |
var self = this; | |
self._delete_layers([self.heatmap_layer, self.heatmap_overlay, self.highlighted_rows_layer, self.header_layer]); | |
self._set_color_settings(); | |
self._draw_heatmap(); | |
self._draw_heatmap_header(); | |
self.heatmap_layer.moveToBottom(); | |
self.heatmap_layer.moveUp(); | |
} | |
/** | |
* Add metadata column | |
* @name [String] name of the column | |
* @data [Object] data object in format {leaf_id: value} | |
*/ | |
InCHlib.prototype.add_metadata_column = function(name, data){ | |
var self = this; | |
if(self.metadata == undefined){ | |
self.metadata = { | |
"feature_names": [name], | |
"nodes": {} | |
} | |
} | |
else{ | |
self.metadata.feature_names.push(name); | |
} | |
for(var i = 0, len=self.point_ids.length; i<len; i++){ | |
var key = self.point_ids[i]; | |
if(self.data.nodes[key].objects !== undefined){ | |
var row_id = self.data.nodes[key].objects[0]; | |
var value = data[row_id]; | |
if(value === undefined){ | |
value = null; | |
} | |
if(self.metadata.nodes[key] === undefined){ | |
self.metadata.nodes[key] = [value]; | |
} | |
else{ | |
self.metadata.nodes[key].push(value); | |
} | |
} | |
} | |
} | |
}(jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment