phyloio 2.1.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ /*
2
+ * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
3
+ * This devtool is neither made for production nor for readable output files.
4
+ * It uses "eval()" calls to create a separate source file in the browser devtools.
5
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
6
+ * or disable the default devtool with "devtool: false".
7
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
8
+ */
9
+ (self["webpackChunkPhyloIO"] = self["webpackChunkPhyloIO"] || []).push([["src_utils_js"],{
10
+
11
+ /***/ "./src/utils.js":
12
+ /*!**********************!*\
13
+ !*** ./src/utils.js ***!
14
+ \**********************/
15
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
16
+
17
+ eval("const fs = __webpack_require__(/*! file-saver */ \"./node_modules/file-saver/dist/FileSaver.min.js\")\nconst d3 = __webpack_require__(/*! d3 */ \"./node_modules/d3/index.js\");\n\nfunction traverse(o,func_pre, func_post) {\n\n if (func_pre){\n func_pre.apply(this,[o,o[\"children\"]])\n }\n\n if(o[\"children\"]){\n\n for (var c in o[\"children\"] ) {\n\n var child = o[\"children\"][c]\n\n child = traverse(child, func_pre, func_post)\n\n if (func_post) {\n func_post.apply(this,[child,o])\n }\n\n\n }\n\n\n }\n\n return o\n\n}\n\nfunction build_table(hierarchy){\n\n traverse(hierarchy, function(node,children){\n delete node.left_\n delete node.right_\n delete node.weight_\n }, null)\n\n var n = hierarchy.leaves().length\n var X = Array.from(new Array(n), _ => Array(3).fill(null));\n var S2I = {} //Array(n).fill(0)\n var I2S = Array(n).fill(null)\n var n_edges = 0\n\n var nzl = []\n traverse(hierarchy, null, function(node,children){nzl.push(node)})\n nzl.push(hierarchy)\n var nz = nzl.entries()\n\n var n1 = nz.next()\n var n2 = nz.next()\n var i = 0\n\n while (true) {\n\n var node = n1.value[1]\n var node2 = n2.value[1]\n var p = node.parent\n var ii;\n\n // Do work\n if (!(node.hasOwnProperty('children'))) {\n I2S[i] = node.data.name\n S2I[I2S[i]] = i\n node.weight_ = 0\n node.left_ = i\n node.right_ = i\n i += 1\n }\n\n // propagate up\n if (typeof p != \"undefined\"){\n p.left_ = p.hasOwnProperty('left_') ? Math.min(p.left_, node.left_) : node.left_\n p.right_ = p.hasOwnProperty('right_') ? Math.max(p.right_, node.right_) : node.right_\n if (p.hasOwnProperty('weight_')){ p.weight_ = p.weight_ + node.weight_ + 1} else {p.weight_ = node.weight_ +=1}\n }\n\n if (node.hasOwnProperty('children')) {\n\n if( node2.hasOwnProperty('weight_') && node2.weight_ > 0 ){ii = node.left_} else { ii = node.right_}\n X[ii][0] = node.left_\n X[ii][1] = node.right_\n if (node.data.hasOwnProperty('branch_length')){\n X[ii][2] = node.data.branch_length\n }\n else {\n X[ii][2] = 1\n }\n\n\n n_edges += 1\n\n }\n\n n1 = n2\n n2 = nz.next()\n\n if (n2.done){\n\n\n // process seed node, w=0\n ii = hierarchy.leaves().length-1\n X[ii][0] = n1.value[1].left_\n X[ii][1] = n1.value[1].right_\n X[ii][2] = n1.value[1].data.branch_length\n n_edges += 1\n\n break\n }\n\n }\n\n\n\n if (X[0][0] !== null){\n X[0] = Array(3).fill(null)\n\n }\n\n n_edges = 0\n for (const n2Key in X) {\n if (X[n2Key][0] !== null){\n n_edges++\n }\n\n }\n\n var leaf_to_dist = {}\n\n hierarchy.leaves().forEach( e=> { leaf_to_dist[e.data.name] = e.data.branch_length })\n\n\n return {'table': X, 'n_edges': n_edges, 'I2S': I2S, 'S2I': S2I, 'leaf_dict': leaf_to_dist}\n\n\n}\n\nfunction reverse_order(child,parent){\n\n child.children.push(parent)\n parent.parent =child\n\n const b = parent.children.indexOf(child);\n if (b > -1) {\n parent.children.splice(b, 1);\n }\n}\n\nfunction reroot_hierarchy(hierarchy, leaf_name){\n\n\n let leaf = hierarchy.leaves().find(element => element.data.name == leaf_name );\n\n // INVERT PATH TO ROOT\n var ancestors = leaf.ancestors()\n leaf.children = []\n leaf.root = true\n\n\n //leaf.branch_length_before_reverse = leaf.data.branch_length\n\n/*\n for (var j = 0; j < leaf.parent.children.length; j++) {\n\n if (leaf.parent.children[j] != leaf){\n\n leaf.data.branch_length = leaf.parent.children[j].data.branch_length\n break\n\n }\n\n }\n\n */\n\n\n var index\n for (index = 0; index < ancestors.length; index++) {\n\n let child = (index === 0) ? leaf : ancestors[index-1]\n let parent = ancestors[index]\n\n\n /*\n parent.branch_length_before_reverse = parent.data.branch_length\n if (child.branch_length_before_reverse){\n parent.data.branch_length = child.branch_length_before_reverse\n }\n else{\n parent.data.branch_length = child.data.branch_length\n }\n */\n\n\n reverse_order(child,parent)\n }\n\n //DESTROY ROOT\n var old_root_children = ancestors[ancestors.length-1].children\n\n var c = ancestors[ancestors.length-2].children.indexOf(ancestors[ancestors.length-1]);\n if (c > -1) {\n ancestors[ancestors.length-2].children.splice(c, 1);\n }\n for (var j = 0; j < old_root_children.length; j++) {\n\n let parent = old_root_children[j]\n let child = ancestors[ancestors.length-2]\n\n child.children.push(parent)\n parent.parent =child\n }\n\n leaf.parent = null\n leaf.data.branch_length = leaf.children[0].data.branch_length\n\n return leaf\n}\n\nfunction addLogo(svg) {\n // TODO load with ajax\n var logo_xml = '<svg id=\"exportLogo\" x=\"0\" y=\"0\"><g id=\"g4169\"> <path d=\"m 29.606259,23.679171 1.905511,0 c 0.193778,0.617882 0.290669,1.188505 0.290672,1.711869 0.466506,-0.545171 1.022728,-0.99222 1.668668,-1.341146 0.653108,-0.348904 1.295455,-0.523362 1.927043,-0.523373 0.976073,1.1e-5 1.86603,0.261698 2.669869,0.78506 0.810999,0.523383 1.442581,1.221215 1.894747,2.093495 0.459321,0.865028 0.688986,1.802739 0.688998,2.813134 -1.2e-5,1.010407 -0.229677,1.951752 -0.688998,2.824038 -0.452166,0.865023 -1.083748,1.559219 -1.894747,2.082592 -0.803839,0.516105 -1.693796,0.774156 -2.669869,0.774157 -0.638765,-1e-6 -1.284701,-0.163554 -1.937809,-0.490663 -0.653117,-0.334377 -1.20575,-0.770521 -1.657902,-1.308434 l 0,6.542172 -1.711731,0 0,-12.713622 c -2e-6,-0.552441 -0.04665,-1.170313 -0.139953,-1.853616 -0.08613,-0.683283 -0.20096,-1.148504 -0.344499,-1.395663 m 2.196183,5.539039 c -3e-6,1.133981 0.355261,2.093499 1.065795,2.878557 0.717702,0.777793 1.561006,1.166688 2.529916,1.166687 0.954543,10e-7 1.79067,-0.392528 2.508385,-1.177592 0.717697,-0.785056 1.07655,-1.740939 1.076561,-2.867652 -1.1e-5,-1.1267 -0.358864,-2.082583 -1.076561,-2.867652 -0.717715,-0.79232 -1.553842,-1.188485 -2.508385,-1.188495 -0.96891,10e-6 -1.812214,0.396175 -2.529916,1.188495 -0.710534,0.785069 -1.065798,1.740952 -1.065795,2.867652\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee Bold\" id=\"path4145\" /> <path d=\"m 43.224746,34.75725 0,-16.279106 1.711731,0 0,7.152775 c 0.437798,-0.610593 0.94378,-1.112159 1.517951,-1.504699 0.581337,-0.399789 1.151913,-0.599688 1.71173,-0.599699 0.602867,1.1e-5 1.141147,0.123585 1.614841,0.370723 0.473678,0.23989 0.854062,0.570633 1.141153,0.99223 0.287074,0.421615 0.502386,0.897739 0.645937,1.428373 0.143531,0.523382 0.215302,1.083101 0.215312,1.679158 l 0,6.760245 -1.6902,0 0,-6.760245 c -8e-6,-0.33437 -0.0323,-0.65421 -0.09689,-0.959518 -0.05742,-0.305294 -0.154315,-0.603326 -0.290672,-0.894097 -0.136371,-0.298024 -0.337329,-0.534268 -0.602873,-0.708736 -0.265559,-0.181718 -0.584938,-0.272581 -0.958139,-0.272591 -0.473692,10e-6 -0.96891,0.243524 -1.485653,0.730544 -0.509576,0.487036 -0.925846,1.05039 -1.24881,1.69006 -0.315795,0.632417 -0.47369,1.177598 -0.473687,1.635543 l 0,5.53904 -1.711731,0\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee Bold\" id=\"path4147\" /> <path d=\"m 53.581256,23.679171 1.776325,0 3.423461,8.472114 3.337338,-8.472114 1.797856,0 -6.4163,16.388142 -1.819387,0 2.22848,-5.658979 -4.327773,-10.729163\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee Bold\" id=\"path4149\" /> <path d=\"m 67.415055,34.75725 -1.71173,0 0,-16.279106 1.71173,0 0,16.279106\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee Bold\" id=\"path4151\" /> <path d=\"m 80.882824,26.361462 c 0.523914,0.872297 0.785877,1.824546 0.785889,2.856748 -1.2e-5,1.032215 -0.261975,1.984463 -0.785889,2.856749 -0.523937,0.872291 -1.234467,1.562854 -2.131589,2.071689 -0.897143,0.501566 -1.873223,0.752348 -2.928244,0.752349 -1.062213,-1e-6 -2.04547,-0.250783 -2.949776,-0.752349 -0.897136,-0.508835 -1.607665,-1.199398 -2.131589,-2.071689 -0.523928,-0.872286 -0.78589,-1.824534 -0.785889,-2.856749 -10e-7,-1.032202 0.261961,-1.984451 0.785889,-2.856748 0.523924,-0.87955 1.234453,-1.570111 2.131589,-2.071688 0.904306,-0.508825 1.887563,-0.763242 2.949776,-0.763253 1.055021,1.1e-5 2.031101,0.254428 2.928244,0.763253 0.897122,0.501577 1.607652,1.192138 2.131589,2.071688 m -9.20459,2.856748 c -3e-6,1.126713 0.405501,2.082596 1.216513,2.867652 0.811004,0.785064 1.794261,1.177593 2.949775,1.177592 1.1555,10e-7 2.142346,-0.392528 2.960541,-1.177592 0.818175,-0.792325 1.227268,-1.748208 1.227279,-2.867652 -1.1e-5,-1.112162 -0.409104,-2.060776 -1.227279,-2.845844 -0.818195,-0.792321 -1.805041,-1.188485 -2.960541,-1.188495 -1.155514,10e-6 -2.138771,0.396174 -2.949775,1.188495 -0.811012,0.785068 -1.216516,1.733682 -1.216513,2.845844\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee Bold\" id=\"path4153\" /> <path d=\"m 84.532366,34.0049 c -2e-6,-0.247148 0.08612,-0.457951 0.258374,-0.63241 0.172247,-0.181725 0.380382,-0.272588 0.624405,-0.27259 0.244018,2e-6 0.452152,0.09087 0.624405,0.27259 0.179424,0.174459 0.269137,0.385262 0.269141,0.63241 -4e-6,0.239881 -0.08972,0.454318 -0.269141,0.643314 -0.17943,0.181727 -0.387564,0.27259 -0.624405,0.27259 -0.236846,0 -0.444981,-0.09087 -0.624405,-0.27259 -0.172252,-0.188996 -0.258376,-0.403433 -0.258374,-0.643314\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee\" id=\"path4155\" /> <path d=\"m 89.527608,21.08411 c -10e-7,-0.239866 0.08253,-0.447035 0.247608,-0.621507 0.172248,-0.174444 0.380383,-0.261673 0.624406,-0.261687 0.23684,1.4e-5 0.437798,0.08724 0.602874,0.261687 0.172246,0.174472 0.258371,0.381641 0.258374,0.621507 -3e-6,0.247162 -0.08254,0.457964 -0.247609,0.632409 -0.165075,0.167203 -0.369621,0.250796 -0.613639,0.250783 -0.244023,1.3e-5 -0.452158,-0.08358 -0.624406,-0.250783 -0.165074,-0.174445 -0.247609,-0.385247 -0.247608,-0.632409 m 1.356465,13.67314 -0.968904,0 0,-11.056271 0.968904,0 0,11.056271\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee\" id=\"path4157\" /> <path d=\"m 99.593447,23.526521 c 0.753583,1.1e-5 1.474873,0.149027 2.163883,0.447048 0.68899,0.298043 1.28468,0.701476 1.78709,1.210302 0.50238,0.508844 0.90072,1.115812 1.19499,1.820905 0.29424,0.705108 0.44137,1.442918 0.44139,2.213434 -2e-5,0.777797 -0.14715,1.519242 -0.44139,2.224339 -0.29427,0.705104 -0.69261,1.312071 -1.19499,1.820905 -0.50241,0.501568 -1.0981,0.905001 -1.78709,1.210301 -0.68901,0.298033 -1.4103,0.447049 -2.163883,0.447049 -1.543077,0 -2.860068,-0.556084 -3.950979,-1.668254 -1.090916,-1.112166 -1.636373,-2.456945 -1.636372,-4.03434 -10e-7,-1.032202 0.247608,-1.984451 0.742827,-2.856748 0.502393,-0.87955 1.180625,-1.570111 2.0347,-2.071688 0.861243,-0.508825 1.797849,-0.763242 2.809824,-0.763253 m -4.629212,5.691689 c -2e-6,1.301171 0.452153,2.416973 1.356467,3.347412 0.911483,0.923175 2.009573,1.38476 3.294277,1.384759 1.284681,10e-7 2.379191,-0.461584 3.283511,-1.384759 0.91147,-0.930439 1.36721,-2.046241 1.36722,-3.347412 -1e-5,-1.293889 -0.45575,-2.402423 -1.36722,-3.325603 -0.90432,-0.923164 -1.99883,-1.38475 -3.283511,-1.38476 -1.284704,10e-6 -2.382794,0.461596 -3.294277,1.38476 -0.904314,0.92318 -1.356469,2.031714 -1.356467,3.325603\" style=\"font-size:22.18883514px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sawasdee;-inkscape-font-specification:Sawasdee\" id=\"path4159\" /> </g> <g id=\"g4014\" transform=\"translate(12.84,20.592727)\"> <g transform=\"translate(0,-0.065)\" id=\"g3992\"> <polygon style=\"fill:#939598\" id=\"polygon461\" points=\"5.7,0.23 11.86,0.23 11.86,1.65 7.12,1.65 7.12,6.04 11.86,6.04 11.86,7.46 11.86,7.46 5.7,7.46 \" class=\"cls-2\" /> <polygon style=\"fill:#939598\" id=\"polygon463\" points=\"0,7.08 3.51,7.08 3.51,8.49 1.43,8.49 1.45,15.84 12.68,15.84 12.68,17.26 12.68,17.26 0.04,17.26 \" class=\"cls-2\" /> <polygon style=\"fill:#939598\" id=\"polygon465\" points=\"10.49,11.02 10.49,12.44 10.49,12.44 2.84,12.44 2.84,7.79 4.26,7.79 4.26,11.02 \" class=\"cls-2\" transform=\"translate(0,-0.15225398)\" /> <polygon style=\"fill:#bcbec0\" id=\"polygon467\" points=\"4.26,4.55 4.26,7.79 4.26,7.79 2.84,7.79 2.84,3.13 6.41,3.13 6.41,4.55 \" class=\"cls-3\" transform=\"matrix(1,0,0,0.85463687,0,0.4549866)\" /> <rect style=\"fill:#939598;fill-opacity:1\" id=\"rect3926-3\" width=\"1.4240631\" height=\"1.7319686\" x=\"2.8396611\" y=\"7.0799503\" /> <rect style=\"fill:#939598;fill-opacity:1\" id=\"rect3926-6\" width=\"1.3864813\" height=\"1.6934805\" x=\"5.7012329\" y=\"2.9206221\" /> </g> <g id=\"g4005\"> <g id=\"g3984\"> <polygon class=\"cls-2\" points=\"94.93,12.33 94.93,10.91 99.87,10.91 99.87,6.46 94.93,6.46 94.93,5.04 101.29,5.04 101.29,12.33 101.29,12.33 \" id=\"polygon453\" style=\"fill:#939598\" /> <polygon class=\"cls-2\" points=\"94.72,17.36 94.72,15.94 104.87,15.94 104.9,5.41 102.74,5.41 102.74,3.99 106.32,3.99 106.29,17.36 106.29,17.36 \" id=\"polygon455\" style=\"fill:#939598\" /> <polygon class=\"cls-2\" points=\"95.51,1.42 95.51,0 103.45,0 103.45,4.7 103.45,4.7 102.03,4.7 102.03,1.42 \" id=\"polygon457\" style=\"fill:#939598\" /> <polygon class=\"cls-3\" points=\"102.03,7.97 102.03,4.7 103.45,4.7 103.45,9.39 103.45,9.39 100.65,9.39 100.65,7.97 \" id=\"polygon459\" style=\"fill:#bcbec0\" /> <rect y=\"3.9876499\" x=\"102.02941\" height=\"1.4238259\" width=\"1.4579451\" id=\"rect3926\" style=\"fill:#939598;fill-opacity:1\" /> <rect y=\"7.884686\" x=\"99.887817\" height=\"1.6934805\" width=\"1.397205\" id=\"rect3926-7\" style=\"fill:#939598;fill-opacity:1\" /> </g> </g> </g> </g> </svg>';\n\n svg.append(\"g\").html(logo_xml);\n\n}\n\nfunction getSVGString( svgNode ) {\n svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');\n var cssStyleText = getCSSStyles(svgNode);\n cssStyleText += \"* {font-family:Helvetica}\"\n appendCSS( cssStyleText, svgNode );\n\n var serializer = new XMLSerializer();\n var svgString = serializer.serializeToString(svgNode);\n svgString = svgString.replace(/(\\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace\n svgString = svgString.replace(/NS\\d+:href/g, 'xlink:href'); // Safari NS namespace fix\n\n return svgString;\n\n function getCSSStyles( parentElement ) {\n var selectorTextArr = [];\n\n // Add Parent element Id and Classes to the list\n selectorTextArr.push( '#'+parentElement.id );\n for (var c = 0; c < parentElement.classList.length; c++)\n if ( !contains('.'+parentElement.classList[c], selectorTextArr) )\n selectorTextArr.push( '.'+parentElement.classList[c] );\n\n // Add Children element Ids and Classes to the list\n var nodes = parentElement.getElementsByTagName(\"*\");\n for (var i = 0; i < nodes.length; i++) {\n var id = nodes[i].id;\n if ( !contains('#'+id, selectorTextArr) )\n selectorTextArr.push( '#'+id );\n\n var classes = nodes[i].classList;\n for (var c = 0; c < classes.length; c++)\n if ( !contains('.'+classes[c], selectorTextArr) )\n selectorTextArr.push( '.'+classes[c] );\n }\n\n // Extract CSS Rules\n var extractedCSSText = \"\";\n for (var i = 0; i < document.styleSheets.length; i++) {\n var s = document.styleSheets[i];\n\n try {\n if(!s.cssRules) continue;\n } catch( e ) {\n if(e.name !== 'SecurityError') throw e; // for Firefox\n continue;\n }\n\n var cssRules = s.cssRules;\n for (var r = 0; r < cssRules.length; r++) {\n if ( contains( cssRules[r].selectorText, selectorTextArr ) )\n extractedCSSText += cssRules[r].cssText;\n }\n }\n\n\n return extractedCSSText;\n\n function contains(str,arr) {\n return arr.indexOf( str ) === -1 ? false : true;\n }\n\n }\n\n function appendCSS( cssText, element ) {\n var styleElement = document.createElement(\"style\");\n styleElement.setAttribute(\"type\",\"text/css\");\n styleElement.innerHTML = cssText;\n var refNode = element.hasChildNodes() ? element.children[0] : null;\n element.insertBefore( styleElement, refNode );\n }\n}\n\nfunction svgString2Image( svgString, width, height, format, callback ) {\n var format = format ? format : 'png';\n\n var imgsrc = 'data:image/svg+xml;base64,'+ btoa( unescape( encodeURIComponent( svgString ) ) ); // Convert SVG string to dataurl\n\n var canvas = document.createElement(\"canvas\");\n var context = canvas.getContext(\"2d\");\n\n canvas.width = width;\n canvas.height = height;\n\n var image = new Image;\n image.onload = function() {\n\n context.clearRect ( 0, 0, width, height );\n context.fillStyle = \"#ffffff\";\n context.fillRect(0, 0, width, height);\n context.drawImage(image, 0, 0, width, height);\n\n canvas.toBlob( function(blob) {\n var filesize = Math.round( blob.length/1024 ) + ' KB';\n if ( callback ) callback( blob, filesize );\n });\n };\n image.src = imgsrc;\n}\n\nfunction screen_shot({ svg1, svg2, format } = {}){\n\n addLogo(svg1);\n var name1 = svg1.attr(\"id\");\n var svgString1 = getSVGString(svg1.node());\n\n var t = \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" version=\\\"1.1\\\">\\n\" +\n \"\\n\" +\n \" <g transform=\\\"translate(0,0)\\\">\\n\" +\n svgString1 +\n \" </g>\\n\"\n\n if(svg2){\n\n addLogo(svg2);\n var name2 = svg2.attr(\"id\");\n var svgString2 = getSVGString(svg2.node());\n\n var w = svg2.node().getBoundingClientRect().width\n var h = svg2.node().getBoundingClientRect().height\n\n t += '<line x1=\"' + (w + 5) +'\" y1=\"0\" x2=\"' + (w + 5) +'\" y2=\"' + h+'\" stroke=\"black\" />'\n\n t += \" <g transform=\\\"translate(\" + (w + 10) +\",0)\\\">\\n\" +\n svgString2 +\n \" </g>\\n\"\n\n }\n\n t += \"</svg> \"\n\n if(format === 'svg') {\n\n var blob = new Blob([t], {\"type\": \"image/svg+xml;base64,\"+ btoa(t)});\n fs.saveAs(blob, name1+\".svg\");\n svg1.select(\"#exportLogo\").remove();\n if(svg2){svg2.select(\"#exportLogo\").remove();}\n\n }\n\n else if (format === 'png'){\n\n\n\n var wi = svg1.node().getBoundingClientRect().width\n var he = svg1.node().getBoundingClientRect().height\n\n if(svg2){\n wi = wi*2;\n }\n\n svgString2Image(t, wi, he, 'png', save);\n\n svg1.select(\"#exportLogo\").remove();\n if(svg2){svg2.select(\"#exportLogo\").remove();}\n\n function save(dataBlob, filesize) {\n var filename = (name) ? name+\".\" : \"\";\n fs.saveAs(dataBlob, filename+'phylo.io.png'); // FileSaver.js function\n }\n\n }\n}\n\n//Adapted from Extended Newick format parser in JavaScript.\n//Copyright (c) Miguel Pignatelli 2014 based on Jason Davies\nfunction parse_nhx(s) {\n var ancestors = [];\n var tree = {'data_nhx' : {}};\n // var tokens = s.split(/\\s*(;|\\(|\\)|,|:)\\s*/);\n //[&&NHX:D=N:G=ENSG00000139618:T=9606]\n var tokens = s.split( /\\s*(;|\\(|\\)|\\[|\\]|,|:|=)\\s*/ );\n for (var i=0; i<tokens.length; i++) {\n var token = tokens[i];\n switch (token) {\n case '(': // new children\n var subtree = {'data_nhx' : {}};\n tree.children = [subtree];\n ancestors.push(tree);\n tree = subtree;\n break;\n case ',': // another branch\n var subtree = {'data_nhx' : {}};\n ancestors[ancestors.length-1].children.push(subtree);\n tree = subtree;\n break;\n case ')': // optional name next\n tree = ancestors.pop();\n break;\n case ':': // optional length next\n break;\n default:\n var x = tokens[i-1];\n // var x2 = tokens[i-2];\n if (x == ')' || x == '(' || x == ',') {\n tree.name = token;\n }\n else if (x == ':') {\n var test_type = typeof token;\n if(!isNaN(token)){\n tree.branch_length = parseFloat(token);\n }\n // tree.length = parseFloat(token);\n }\n else if (x == '='){\n tree['data_nhx'][tokens[i-2]] = token\n }\n else {\n var test;\n }\n }\n }\n return tree;\n};\n\nfunction save_file_as(filename, data) {\n const blob = new Blob([data], {type: 'text/csv'});\n if(window.navigator.msSaveOrOpenBlob) {\n window.navigator.msSaveBlob(blob, filename);\n }\n else{\n const elem = window.document.createElement('a');\n elem.href = window.URL.createObjectURL(blob);\n elem.download = filename;\n document.body.appendChild(elem);\n elem.click();\n document.body.removeChild(elem);\n }\n}\n\nfunction compute_RF_Euc(X1,X2){\n\n var n_good = 0\n var euclidian = 0.00\n\n var x2_processed = []\n\n for (var i = 0; i < X1.table.length; i++) {\n var s1 = X1.table[i][0]\n var e1 = X1.table[i][1]\n var w1 = Math.abs(e1-s1)\n\n if (w1 > 0){\n\n var species = X1.I2S.slice(s1,e1+1)\n var index = []\n\n for (const [name, idx] of Object.entries(X2.S2I)) {\n if (species.includes(name)) {index.push(idx)}\n }\n\n if (index.length <= 0) {\n continue\n }\n\n var s2 = Math.min.apply(null,index)\n var e2 = Math.max.apply(null,index)\n var w2 = Math.abs(e2-s2)\n\n if (w1 == w2) {\n\n\n if (X2.table[e2][0] == s2 && X2.table[e2][1] == e2) {\n n_good += 1\n euclidian += Math.abs(parseFloat(X1.table[i][2]) - parseFloat(X2.table[e2][2]) )\n x2_processed.push(e2)\n }\n else if (X2.table[s2][0] == s2 && X2.table[s2][1] == e2){\n\n n_good += 1\n euclidian += Math.abs(parseFloat(X1.table[i][2]) - parseFloat(X2.table[s2][2]) )\n x2_processed.push(s2)\n\n }\n else{\n euclidian += parseFloat(X1.table[i][2])\n\n }\n\n }\n\n\n else{\n euclidian += parseFloat(X1.table[i][2])\n }\n\n\n\n\n\n\n }\n\n }\n\n\n for (var k = 1; k < X2.table.length; k++) {\n if (!x2_processed.includes(k)){\n\n var d = parseFloat(X2.table[k][2])\n\n if(!isNaN(d)) {\n euclidian += d\n x2_processed.push(k)\n }\n\n }\n }\n\n var leaf_dist = 0.00\n for (var key of Object.keys(X1.leaf_dict)) {\n\n leaf_dist += Math.abs(X1.leaf_dict[key] - X2.leaf_dict[key])\n }\n\n var euc = euclidian + leaf_dist\n\n\n return {\n 'E':euc.toFixed(2),\n 'RF': (X1.n_edges + X2.n_edges -2*n_good),\n 'good':n_good,\n 'L':X1.n_edges,\n 'R':X2.n_edges,\n\n }\n}\n\nfunction get_intersection_leaves(h1, h2){\n\n var leaves1 = h1.leaves().map(x => x.data.name);\n var leaves2 = h2.leaves().map(x => x.data.name);\n return Array.from(new Set(leaves1.filter(value => leaves2.includes(value))))\n}\n\nfunction r_child(parent,child){\n let index = parent.children.indexOf(child);\n if (index > -1) {\n parent.children.splice(index, 1);\n }\n}\n\nfunction get_duplicated(array){\n return array.filter((e, i, a) => a.indexOf(e) !== i)\n}\n\nfunction remove_from_array(array, to_remove){\n\n return array.filter(element => !to_remove.includes(element));\n\n}\n\nfunction remove_duplicated_and_unnamed_leaves_hierarchy(h){\n\n var leaf_space = []\n\n h.eachAfter(d => {\n\n if (d.parent && !d.children){\n\n if (d.data.name.length === 0){\n r_child(d.parent,d)\n d= null;\n }\n else {\n leaf_space.push(d.data.name)\n }\n }\n\n\n });\n\n var dup = get_duplicated(leaf_space)\n\n\n var to_keep = remove_from_array(leaf_space, dup)\n\n return filter_leaves_hierarchy(h, to_keep)\n}\n\nfunction filter_leaves_hierarchy(h, leaves_to_keep){\n\n\n h.eachAfter(d => {\n\n if (d.children && d.parent){\n\n if (d.children.length === 0){\n r_child(d.parent, d)\n d = null\n }\n\n else if (d.children.length === 1){\n r_child(d.parent, d)\n d.parent.children.push(d.children[0])\n d.children[0].parent = d.parent\n d = null\n\n }\n }\n\n else if (d.parent){\n\n if (!leaves_to_keep.includes(d.data.name)){\n r_child(d.parent,d)\n d= null;\n }\n }\n\n\n });\n\n if (Array.from(new Set(h.leaves().map(x => x.data.name))).length == leaves_to_keep.length){\n return h\n }\n\n return false\n}\n\nfunction check_whole_hierarchy_labelled(hierarchy ){\n\n\n traverse(hierarchy, function(node,children){\n\n if (typeof node.data['duplication'] === 'undefined' ){\n node.data['duplication'] = false\n }\n\n\n }, null)\n\n return\n}\n\nfunction buildX(hierarchy){\n\n/*\n Define the table X according to (Day 1985) to have contiguous integers for\n each clade, and define a clade by the left-most and right-most identifiers,\n such as [4,7] for the clade [4,5,6,7].\n\n Note we extend the table to contain the following fields,\n which will be populated later in the algorithm:\n 3: node defining the clade in T1\n 4: node defining the clade in T2\n 5: size of the island rooted in the clade in T1\n 6: size of the island rooted in the clade in T2\n 7: labels in the island rooted in the clade in T1\n 8: labels in the island rooted in the clade in T2\n\n */\n\n var X = []\n var n = hierarchy.leaves().length\n var tax2id = {}\n var n2bip = new Map();\n\n function buildX_r(T){\n if (T.children == null && T._children == null){\n // left right id2taxon nodeT1 nodeT2 sizeIsland1 sizeIsland2 labels1 labels2\n X.push([0,0,T.data.name,0,0,0,0,new Set(),new Set()])\n i = X.length -1\n tax2id[T.data.name] = i\n return [i,i]\n }\n\n else{\n let min_l = n\n let max_r = 0\n\n for (var j = 0; j < T.children.length; j++) {\n var c = T.children[j]\n\n var [l,r] = buildX_r(c)\n min_l = Math.min(l,min_l)\n max_r = Math.max(r,max_r)\n\n }\n\n X[min_l][0]=X[max_r][0]=min_l\n X[min_l][1]=X[max_r][1]=max_r\n X[min_l][3]=X[max_r][3]=T\n n2bip.set(T, [min_l,max_r]);\n\n\n return [min_l,max_r]\n }\n\n }\n\n buildX_r(hierarchy)\n\n return [X, tax2id, n2bip]\n}\n\nfunction findgood(hierarchy,X,tax2id){\n\n\n function findgood_r(T){\n\n if (T.children == null && T._children == null){\n var i = tax2id[T.data.name]\n\n return [i,i,1]\n }\n else {\n var min_l = n\n var max_r=0\n var tot_w=0\n\n for (var j = 0; j < T.children.length; j++) {\n\n var c = T.children[j]\n\n var [l, r, w] = findgood_r(c)\n\n min_l = Math.min(l, min_l)\n max_r = Math.max(r, max_r)\n tot_w += w\n }\n\n if (max_r-min_l+1 == tot_w){\n\n if (X[min_l][0]==min_l && X[min_l][1]==max_r){\n X[min_l][4]= T\n n2bip.set(T, [min_l,max_r]);\n }\n else if (X[max_r][0]==min_l && X[max_r][1]==max_r) {\n X[max_r][4]=T\n n2bip.set(T, [min_l,max_r]);\n }\n }\n\n return [min_l,max_r,tot_w]\n\n\n }\n }\n\n var n2bip = new Map();\n var n = hierarchy.leaves().length\n\n findgood_r(hierarchy)\n\n return(n2bip)\n}\n\nfunction getIslandsDay(t,X,n2bip,isT1){\n\n /*\n An island is separated from the rest of the tree\n by good edges. In the traversal below, we do a preorder\n traversal and create a new island whenever we meet a clade\n defined in X\n ____\n /\n **** x6\n * \\___\n **** x3 ......\n * \\___ ______x7\n ----x1 / ...\n * **** x4 ____\n **** x2 ``-- /\n *********** x5\n \\_____\n\n */\n\n function mytraversal(t,parentIslandId=0){\n\n if (t.children == null && t._children == null){\n return\n }\n\n if (n2bip.has(t)){\n var [l,r] = n2bip.get(t)\n }\n else {\n var l = 0;\n var r = 0;\n }\n\n var row = -1\n\n if (X[l][0]===l && X[l][1]===r && X[l][4]!==0){\n row = l\n }\n\n else if (X[r][0]===l && X[r][1]===r && X[r][4]!==0){\n row = r\n }\n\n // CLADE IS COMMON\n if (row > -1){\n\n // end of previous island, so new island.\n islandId = row\n X[row][off+2].add(t.data.duplication)\n\n\n for (var j = 0; j < t.children.length; j++) {\n var c = t.children[j]\n mytraversal(c,islandId)\n\n }\n\n }\n else {\n // continue previous island\n var islandId = parentIslandId\n\n X[islandId][off+2].add(t.data.duplication)\n X[islandId][off] += 1\n\n for (var j = 0; j < t.children.length; j++) {\n var c = t.children[j]\n\n mytraversal(c,islandId)\n\n }\n\n }\n\n }\n\n\n var off;\n\n if (isT1){\n off = 5\n }\n else{\n off = 6\n }\n\n mytraversal(t)\n\n return\n\n}\n\n// ADAPTED FROM https://github.com/DessimozLab/pylabeledrf\nfunction compute_LRF(t1, t2){\n\n var [ X, tax2id, n12bip ] = buildX(t1)\n\n var n22bip = findgood(t2,X,tax2id)\n\n getIslandsDay(t1,X,n12bip,true)\n getIslandsDay(t2,X,n22bip,false)\n\n\n var rf = 0;\n var subs = 0;\n\n for (var i = 0; i < X.length; i++) {\n\n if (X[i][4] != 0){\n\n rf += X[i][5]+X[i][6]\n\n let intersection = new Set( [...X[i][7]].filter(x => X[i][8].has(x)));\n\n if ( intersection.size == 0){\n subs +=1\n }\n }\n }\n\n return rf+subs\n\n}\n\nfunction prepare_and_run_distance(m1,m2){\n\n var distance = {\n 'no_distance_message': true,\n 'clade': false,\n 'Cl_good': false,\n 'Cl_left': false,\n 'Cl_right': false,\n 'RF': false,\n 'RF_good': false,\n 'RF_left': false,\n 'RF_right': false,\n 'Euc': false,\n 'LRF':false\n }\n\n // CHECK INTERSECTING LEAVES\n var h1_raw = d3.hierarchy(m1.data, d => d.children );\n var h2_raw = d3.hierarchy(m2.data, d => d.children );\n\n var h1 = remove_duplicated_and_unnamed_leaves_hierarchy(h1_raw)\n var h2 = remove_duplicated_and_unnamed_leaves_hierarchy(h2_raw)\n\n var intersection = get_intersection_leaves(h1,h2)\n\n if (intersection.length == 0){\n distance.no_distance_message = 'No leaves in common to compute distance.'\n return distance\n }\n\n // FILTER TREE TO KEEP ONLY INTERSECTING LEAVES\n var hierachy1 = filter_leaves_hierarchy(h1, intersection )\n var table1 = build_table(hierachy1 )\n\n var hierachy2 = filter_leaves_hierarchy(h2, intersection )\n var table2 = build_table(hierachy2 )\n\n // CLADISTIC DISTANCE & EUCLIDIAN\n var r = compute_RF_Euc(table1,table2)\n distance.clade = r.RF\n distance.Cl_good = r.good\n distance.Cl_left = r.L\n distance.Cl_right = r.R\n distance.Euc = r.E\n\n // RF\n var hierarchy_mockup_rerooted1 = reroot_hierarchy(hierachy1, intersection[0])\n var hierarchy_mockup_rerooted2 = reroot_hierarchy(hierachy2, intersection[0])\n\n // build tables\n var X1 = build_table(hierarchy_mockup_rerooted1)\n var X2 = build_table(hierarchy_mockup_rerooted2)\n\n var r2 = compute_RF_Euc(X1,X2)\n distance.RF = r2.RF\n distance.RF_good = r2.good\n distance.RF_left = r2.L\n distance.RF_right = r2.R\n\n\n // LRF\n if ( m1.settings.has_duplications && m2.settings.has_duplications) {\n check_whole_hierarchy_labelled(hierarchy_mockup_rerooted1)\n check_whole_hierarchy_labelled(hierarchy_mockup_rerooted2)\n\n distance.LRF = compute_LRF(hierarchy_mockup_rerooted1, hierarchy_mockup_rerooted2,'duplication' )\n }\n\n return distance\n}\n\nfunction check_if_color(query){\n var accepted_spelling = ['color', 'colour'];\n\n if (accepted_spelling.includes(query.toLowerCase())){\n return true;\n }\n else {\n return false;\n }\n}\n\nfunction hexToRgb(hex){\n if (typeof hex === 'object' && hex.r !== undefined) {\n return hex;\n }\n if (typeof hex === 'string' && hex.startsWith('rgb')) {\n const values = hex.match(/\\d+/g).map(Number);\n return { r: values[0], g: values[1], b: values[2] };\n }\n const bigint = parseInt(hex.slice(1), 16);\n const r = (bigint >> 16) & 255;\n const g = (bigint >> 8) & 255;\n const b = bigint & 255;\n return { r, g, b };\n}\n\nfunction colorDifference(hex1, hex2) {\n const color1 = hexToRgb(hex1);\n const color2 = hexToRgb(hex2);\n const rDiff = color1.r - color2.r;\n const gDiff = color1.g - color2.g;\n const bDiff = color1.b - color2.b;\n const distance = Math.sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);\n const maxDistance = Math.sqrt(255 * 255 * 3);\n return (distance / maxDistance);\n}\n\nmodule.exports = {colorDifference, check_if_color, prepare_and_run_distance, build_table, reroot_hierarchy, screen_shot, parse_nhx, save_file_as, compute_RF_Euc, get_intersection_leaves, filter_leaves_hierarchy, remove_duplicated_and_unnamed_leaves_hierarchy};\n\n\n\n\n//# sourceURL=webpack://PhyloIO/./src/utils.js?");
18
+
19
+ /***/ })
20
+
21
+ }]);