Mercurial > repos > pimarin > abromics_extractor_summarize
comparison test-data/recentrifuge/rcf_report.html @ 0:35704a6837a7 draft
planemo upload commit bb69b191fe3ce756655bf90af4d69e4472f94ba9-dirty
| author | pimarin |
|---|---|
| date | Sun, 04 Jun 2023 17:15:36 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:35704a6837a7 |
|---|---|
| 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
| 2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta charset="utf-8"><link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAMAEBAAAAEAIABoBAAANgAAABgYAAABACAAiAkAAJ4EAAAgIAAAAQAgAKgQAAAmDgAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wCAgIAC////AP///wC0tKJHlZWSqI6OmuRxcXn9koaK9J2Ym8uNm5V73PPoFv///wAAAAAD////AP///wCAgIAC////AP//7xCHh4OodHSi/2xqw/9nZ9H/XVuU/9eFqv/njb7/yYiq/5GAiOifqKJV////AAAAAAL///8A////AO3t2w56eoHPdHLH/3Vz3vx4dtz7dXTb/mVimv/XhKn/8ZPG/fSVx/vvlcT/kG+E/32Himb///8AAAAAA////wB0dHageHbO/3585fl5d9r/dnTX/3V02/5mYpz80X2i/eaIuv/ukcD/wXak/I6Maf+OkXD9iIKjL////wCEhFo+c3Kv/4F+6P18etz/e3nd/3l33P57eeT/aWag/9F5oP/sib3+tmuZ/3uEXf/P1YX7zdKG/3x9dbX///8Ac3J9nYKA4f+CgOb7fnzf/3174P58et//bm2v8Vtgc7SdbIHNqWmM/4aLZP/L0YT/0dWH/tfdiP+go3P6YlyWJ3BvmduGg+n/g4Hk/oF+4/6AfuX/bm2k7pCUUUX///8Ajv/jCVBmXqPBxoH/1NmI/c7Uhf/b4Yn9wMWB/2BdcGBraqX6iYbs/4SB5P+Eguj7hYPm/2Vlcov///8AACRtB////wAAAIAWrLB29uHojv/X3on+3eSK+9PYh/9XWVN7bWum+ouI7/+Gg+f/hoTq+4iF6f9lZXKL////ACQAbQf///8AAABoFoF+Xva0snL/y818/uDmiPvZ34n/WVlTe3Jxm9uMiu//iofr/oiG6f6Jhu3/cnGo7oyQQ0X///8A/znjCXF8dKNotpL/Za2O/WuVe/+FkGv9mJ5w/2pqaGBzc3+djYrr/42K8fuKh+v/i4js/oqH6/93dbfxYmJztGaTec1yxJr/gOGu/4nptf+K6Lf+i+q8/2eXhfqDNG8ngIBKPnt6uP+Rjvf9jInr/4yJ7f+Miu3+jor0/25xoP920pz/gOGw/oHerv+H4rL/kPC9+5Ttvf98ioC1////AP///wB0dHSgioff/5SR+/mOi+7/jYvt/4+L8P5scJ78etKe/YXis/+H47P/kO+8/JLxv/92m4f9nXKNL////wD///8A7e3bDnt7hM+Ihdv/ko/4/JSS+PuUkPb+bnKg/4Lapv+Q7739kfO/+43puf9/qJH/mYeUZv///wAAAAADgICAAv///wD//+8QhoaBqIB/sf+Iht7/jYjw/2tvnf+D3Kf/ieS1/4bIpP+AkYfoqJOfVf///wAAAAAC////AP///wCAgIAC////AP///wCwsJdHlZWQqJORn+RzdHv9hZOK9Jecmcuej5l7/+jzFv///wAAAAAD////AP///wD4PwAA4A8AAMAHAACAAwAAgAEAAAABAAADgQAAA8EAAAPBAAADgQAAAAEAAIABAACAAwAAwAcAAOAPAAD4PwAAKAAAABgAAAAwAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wEAAAAB////AP///wi6urdDubmxj6ennsuQkIzvc3Nz/YSIh/WWoZzWrrezoLe6t1X///8T////AP///wCAgIAC////AP///wD///8A////AP///wD///8A////Af///wD///8Ax8fDQJeYkLV4eH39WlmM/19dpP9dX6b/WFRr/611j/+/fJ//om2I/4N3ff+Jko7Ntri2Xv///wD///8AgICAAv///wD///8A////AP///wD///8B////AP///wOfn5t9c3N29GRjn/9oZ8P/c3LU/XVy3P9rbdH/YVt8/9eIrv/5mcz/75bE/t+Mt/67epz/fnN5/4uTkKP///8W////AAAAAAL///8A////AP///wH///8A////A5iYkZJoaH3/bWvB/3h23Px4dt3+dHPX/3Rx1v9sbcv/YFp6/82ApP/rj8D/65DA//KVxv/1mcn83424/5t1iP98gX7A////F////wCAgIAC////AAAAAAL///8AkJCHdWZlf/9zcs7/fHrj/Hh32/92ddn/dXTX/3Zz2P9vcM//YFt7/8t9of/pi73/54u7/+eNvf/vk8P/7ZbE/pxsh/xLVU7/iomJqP///wD///8A////Af///wCfn5Y4ZmV07XZ0zv9+fOX8enjc/3p43P94dtv/dnXZ/3d12f9xcdD/YFp6/8h5nf/mh7r/44e3/+qMvf/ljrv/jV59/3F+V/68wH3/gYNp/4uIlWf///8AAAAAAv///wJ3d22pc3G6/4KA5/t9e9//fHre/3t53f96eNz/eHbZ/3l23P50dNb9Ylx+/ch2m/3jg7b+44W2/+CItv+NXXz/bnpW/8XIgv/Y3Yv8ur57/3Fxbtni4uIa////AHl5XTdoZ4b4f3zb/4F+5P5+fN//fXvf/3x63v96edz/ennf/nt54P9xccb/Xlxy/7Rvj//gf7P/3IKw/olZeP9te1b/xsqD/9DVh//P1IX/09iG/pWYcf9nZ3Nt////AISEb35ycLb/hYPr/YB+4f9/feH/fnzh/3173/99e+L+enjX/2dmmfhlZXiwYGBiknJkaqGVZ37pg11x/3eBXP7GyoP/0NWH/87Uhf/R1ob/2eCK+8HFff9tbXWv////BG9vdb16eMn/hYPq/4F/4/+BfuP/gH7i/4B94v59e93/Y2KO+ISEbX7y8uQT////AP///weAjo5aT1tP5L7Cf//T2Ij+ztOF/9HWhv/S14b/2d+K/s3Sgv+BgnLcg4OSI11deeaBf9r/hYPo/4OB5P+DgeX/gX/i/4OB6v10c77/cXFjmv///wL///8A////AP///wD///8AeHN9apuecP/U2Yf/0teG/tPZhv/V24f/2uCJ/tTahv+KjGj6AABINV9egfuGg+P/hoTp/4WC5v+EgeX/goDk/4WD6/1wbq//WFgAQ////wAzMzMFAAAAAVVVVQP///8AAABjEoiLZ/Df5Y7/2d+J/dfch//W3If/2d+H/9vhif6ZnW3/AAA5P19egvuHheX/iIXq/4eE6P+Gg+f/hILl/4eE7P1xb7D/WFgAQ////wAzMzMFAAAAAVVVVQP///8AAABVEnd1WvDEx37/y9GD/dnfif/g54z/4OeL/97kiv6anWz/AAA1P15eeuaFg93/ioft/4iF6f+Hhen/hoPn/4mG7/14d8L/cXFimv///wP///8A////AP///wD///8AenV3a1dyZf9QY1//bGVW/pORY/+trnD/xch7/tTZhP+Pkmn6AABINXBwdb1/fc7/jYry/4mH6v+Jhur/iIbp/4iG6/6Gg+X/Z2aT+IKEaX7y8uQT////AP///wiXgY9bXndp5HXLnv95z6P+dsif/2Wrjv9RcWv/Z3Rk/nyBYv9xcWbbfHyDI4SEa354d73/kI31/YuI6/+LiOz/iofr/4mG6v+Lh+3+hoPi/21soPhnZ3qwYGBikmNza6JhinXpcsWa/3vdq/6C4a//iOi1/4zpt/+O6Lf/kOu8+3O1l/9jVmKv////BHl5WDdraor4iofn/4+M8v6Miez/i4nt/4uI7P+LiOv/i4jt/ouJ8P9+e83/XGBt/223jv952aj/e9uq/n3aqv+D36//huKy/4rntv+Q7r3/lvTC/nupj/9zYmxt////AP///wJ3d2qpfXvF/5KP9vyNiu7/jYru/4yJ7f+Miu7/i4jr/46L8P6FgN79XmZ5/XTMm/1+3q7+f9ys/4Lgr/+G5LP/iue2/4zot/+V9cL8iNWs/3BxcNni4uIa////AP///wCfn5I4aGd17YeE3v+Ukfj8jovu/46L7/+Oi+//jYru/46M8f+FgNv/XmV3/3jMnf+D4rH/g+Cw/4fks/+K57b/jem4/5TywP6Q57n/bYh5/5KIjWf///8AAAAAAgAAAAL///8AkJCFdWtqhf+IheL/lZL5/JCN8P+PjO//j4zv/5GO8/+Hgt3/X2Z4/33Rof+I5rb/h+Sz/4nmtf+N6rn/lPPB/pHruvxxm4T/h3yDqP///wD///8A////Af///wH///8A////A5aWj5JtbIP/g4DW/5SR9vyVkvj+kY7y/5KP9P+Ig97/X2d4/4DUpf+N6rn/jeq4/5Lwvv+U88D8h9qu/3KVgv+Lgoe/////F////wCAgIAC////AP///wD///8B////AP///wOfn5l9dHR39HVzsf+Fg97/k4/x/ZiW/v+Nh+f/YWl7/4ngrv+W+MX/kuy8/onesP52uZb/dH54/5aOk6P///8W////AAAAAAL///8A////AP///wD///8A////Af///wD///8Ax8fDQJWVjbV5eX79amic/3h2vv93crf/WV9r/3W1kP95vZn/aZ2C/3eCfP+Ui5DNu7i7Xv///wD///8AgICAAv///wD///8A////AP///wD///8A////AP///wEAAAAB////AP///wi6urdDuLitj6WmmcuPj4rvc3Nz/YiEh/Whlp3Wt66zoLq3ulX///8T////AP///wD///8C////AP///wD///8A////AP8B/wD8AH8A+AAfAOAADwDgAAcAwAAHAIAAAwCAAAMAgAABAAB8AQAAfgEAAP4BAAD+AQAAfgEAAHwBAIAAAQCAAAMAgAADAMAABwDgAAcA4AAPAPgAHwD8AH8A/wH/ACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KO3t7XXFxcWwqqqq25eXl/RwcHD9mJiY9Kurq9vHx8ew8PDwdf///yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A9/f3TLS0tLpvb3H/UVFR/1VVWf9bW27/WVlz/1FRUf96ZG//c2Nr/1lWV/9RUVH/d3V2/7m5ubr5+flM////AP///wD///8A////AP///wD///8A////AP///wAAAAAA////AP///wD///8A////AP///wD///8A/f39HLW1tatbW13/V1de/2FgkP9rabv/cG7S/29u0/9paL7/UVFR/9GIrv/wlcX/75bE/8+Irf+ZcYb/XVhb/2FfYP+8vLyr/v7+HP///wD///8A////AP///wD///8A////AAAAAAD///8A////AP///wD///8A////AOvr60l2dnnpVVVZ/2ZlnP9ycdL/c3LW/3Jx1f9xcNT/cG/T/2ppvv9RUVH/zoSs/+yRwf/uk8L/7pPC/++UxP/pk8D/pXaP/1hVV/9/fn/p7+/vSf///wD///8A////AP///wD///8AAAAAAP///wD///8A////AP///wDg4OBWX19h/11dcv9zccr/d3XZ/3Z02P91c9f/dHLX/3Nx1v9xcNT/a2q//1FRUf/Ngqn/6o6+/+uQwP/tksH/7pPD/++Vxf/xl8b/3I64/3Jiav9lY2T/2dnZVv///wD///8A////AP///wAAAAAA////AP///wD///8A5OTkQ1tbXf9hYIH/eHfY/3l32/94dtr/d3ba/3Z12f90c9f/c3LW/3Nx1f9tbMH/UVFR/8l/pf/mirr/6Iy8/+mOvv/qj7//7JHB/++VxP/xl8b/04qx/1RUUv9ZWVj/6+vrQ////wD///8A////AAAAAAD///8A////APX19Q9mZmjfYF98/3t53P97ed3/enjc/3l32/93dtr/dnXZ/3Z02P91c9f/dXTY/25tw/9RUVH/yHyj/+WIuf/libn/54q7/+mNvf/rj7//7JHB/9WJsf9XVlX/Z2hb/3BxX/9vb23f+fn5D////wD///8AAAAAAP///wD///8AkZCSnFpaZ/97edn/fHre/3t53v97ed3/enjc/3l33P94dtv/dnXZ/3V02P92dNj/cG7D/1FRUf/FeaH/4oW2/+OGt//liLj/54q6/+mOvv/Sha3/V1VV/2doW//FyYL/xcqC/19fWf+fn5+c////AP///wAAAAAA////ANjY2DhRUVL/dXPA/3994f9+fOD/fXvf/3x63v97ed3/enjc/3l32/94dtr/eHba/3d12f9xb8T/UVFR/8J1nf/fgLH/4IOz/+KEtf/liLn/zoCq/1dVVf9naFr/w8eA/83Shf/P1Yb/q652/1JSUf/h4eE4////AAAAAAD///8Afn6ApWNigv+BfuL/gH3h/3584P99e9//fHre/3x63v97ed3/eXjc/3l32/95d9v/d3ba/3Fwxf9RUVH/wXSc/9x9r//fgbL/4YO0/8t9pv9XVVT/Z2ha/8LHgf/N0oX/ztOF/8/Uhv/S14b/c3Vh/42Ni6X///8AAAAAAOfn5xJRUVH/eXbG/4F/4/+AfuL/f33h/3584P99e+D/fHrf/3x63v97ed3/e3ne/3p43f9ycMH/Y2OR/1FRUf+NY3j/w3Sd/9x9rv/IeaL/V1VU/2doWv/DyIH/zNGF/87Thf/Q1Yb/0daG/9TZh/+ytnj/UlJS/+/v7xIAAAAAq6urYF1cav+DgeX/goDk/4F/4/+AfuL/f33h/3994f9+fOD/fXvf/3x63v95d9X/YF99/1FRUb9sbG+AZmVmgG1qa4BRUVG/fWBv/1dVVP9naFr/xMiB/83Shv/O04b/z9WG/9HWhv/S14b/1NqH/9TZhv9fYFn/t7e3YAAAAAB6enyeaGeV/4SC5v+DgeX/goDk/4F+4/+BfuP/f33h/3584P9+fOD/fHrb/1xcbv9sbG6g39/fQP///wD///8A////ANra2kBbWlugVVVT/8LHgf/O04X/ztOF/8/Uhf/Q1Yb/0teG/9PZh//V24f/2N6I/4aIZv+IiIeeAAAAAFpaXMx0crX/hYLm/4SC5v+DgeX/goDk/4KA5P+Bf+P/gH7i/3994f9oZ5v/X19hv/Hx8SD///8A////AP///wD///8A////AOfn5yBcXFq/m55w/9DVhv/R1ob/0teG/9LXhv/T2Yb/1dqH/9jdiP/Z34j/o6Zy/2VlY8wAAAAAUVFR7Hx7zP+GhOj/hYLm/4SB5f+Egub/g4Hl/4KA5P+Bf+P/gX/j/1paZP+xsbFA////AP///wD///8A////AP///wD///8A////AKampkBqa17/0teG/9LXhv/T2Yf/1dqH/9bciP/Y3oj/2N6H/9rgiP+5vXr/UlJS7AAAAABRUVH7gX7W/4eE6P+GhOj/hYPn/4WC5v+EgeX/g4Hl/4OB5f9/fNv/UVFR/9zc3AD///8A////AP///wD///8A////AP///wD///8A0NDQAFRUU//R14b/1dqH/9Xbh//W3If/192H/9jeh//a4Ij/3OKI/8PJfv9RUVH7AAAAAFFRUfuCgNj/iIbq/4eE6P+HhOj/hoPn/4WC5v+Egub/hILm/4B+3f9RUVH/3NzcAP///wD///8A////AP///wD///8A////AP///wDLy8sAUlJR/87ThP/W3Ij/192H/9nfiP/Z34j/2uCI/9vhiP/d44j/xMh+/1FRUfsAAAAAUVFR7H99zv+Jh+v/iIXq/4iF6v+Hhen/hoTo/4aD5/+Fgub/hYLm/1taZP+xsbFA////AP///wD///8A////AP///wD///8A////AJWVlUBSUlH/UlJR/25vXf+Ul2z/ur97/9jeh//c44j/3uWJ/97lif+8wXr/UVFR7AAAAABaWlzMd3W4/4qH6/+Kh+v/iYbq/4iF6f+HhOj/iIXp/4aE6P+GhOj/a2qe/19fYr/x8fEg////AP///wD///8A////AP///wDp6ekgW1xcv2SWe/9nm4D/Wm9k/1daVv9RUVH/VlZT/3p8Yf+ipnH/ys+A/6ircv9lZmPMAAAAAHp6fJ5rapf/i4js/4uJ7f+KiOz/iYbq/4mG6v+Ihur/iIbq/4eE6P+FguP/Xl5w/2xsb6Df399A////AP///wD///8A2traQGVnZqBccGX/d9Sk/3vZqf+B367/g+Gw/33No/9qk33/W2lh/1ZXVP9RUVH/U1NR/3d3dZ4AAAAAq6urYF5ea/+Ni+//jInt/4uI7P+LiOz/iofr/4mG6v+Jhur/iIXp/4iF6f+EguD/ZGSB/1FRUb9ra2+AZWdmgGpubIBRUVG/Xn1u/3TOn/9516f/ftyr/4Herf+G47L/iOa1/4vot/+Q7bz/k+++/4PHo/9SVFP/oaGhYAAAAADn5+cSUVFR/4F/z/+Niu7/jInt/4yJ7f+LiOz/i4nt/4qI7P+LiOz/iofr/4mG6v+Jhur/fnzN/2ZljP9RUVH/YpB5/2++lf921KT/edem/3vZqf+A3q3/hOGw/4bjs/+J5rX/juu6/5Dsu/+U8cD/g8Wi/1JTUv/t7e0SAAAAAP///wB+foClZ2aG/46L8P+Oi/D/jYru/4yJ7f+Mie3/i4js/4uI7P+LiOz/iofr/4qH6/+KiOz/eXjA/1FRUf9zyJz/eden/3zaqf982qn/ftys/4Hfrv+G47L/iOW0/4rntv+N6rn/ku++/5XxwP9le2//iYqKpf///wAAAAAA////ANjY2DhRUVL/gH7L/4+M8P+Oi+//jovv/42K7v+Niu7/jIru/4yK7v+Mie3/jInt/4uI7P96eMD/UVFR/3bLoP972an/ftyr/4Herv+D4K//heOy/4jmtf+L6Lf/juu5/5DtvP+V8cD/gcGf/1NUU//l5eU4////AAAAAAD///8A////AJGRkpxdXGn/jYrp/5CN8f+PjPD/j4zw/46L7/+Oi+//jYru/42K7v+Niu7/jYru/3x5wv9RUVH/ec6i/4Herv+B367/hOGw/4bjsv+I5bT/i+i3/43quf+Q7bz/k+++/4/jtv9bY17/nZ6enP///wD///8AAAAAAP///wD///8A9vb2D2Zmad9mZYL/kI3w/5CN8f+QjfH/j4zw/4+M8P+PjPD/j4zw/46L7/+Oi+//fHrD/1FRUf9/0qb/hOGw/4Xjsv+F47L/iOa1/4vot/+O67r/kO28/5Lvvf+S7b3/ZHht/3N1dN/6+voP////AP///wAAAAAA////AP///wD///8A5OTkQ1xcXv9oZ4j/kI3v/5GN8f+RjfH/kI3x/5CN8f+QjfH/kI3x/5CN8f99e8P/UVFR/3/UqP+I5bT/iOW0/4vot/+L6Lf/juu5/4/su/+S773/kem6/2Z9cf9gYmH/6+vrQ////wD///8A////AAAAAAD///8A////AP///wD///8A4ODgVl9fYf9iYnf/iojh/5KP8/+Sj/P/kY7y/5GO8v+RjvL/kY7y/358xf9RUVH/hdmt/4vot/+O67n/juu5/5Dtu/+Q7bv/ku++/4rXrv9hcGj/aGpp/+np6Vb///8A////AP///wD///8AAAAAAP///wD///8A////AP///wD///8A7OzsSXd3eelWVlr/dXOr/5CO7v+TkPT/k5D0/5KP8/+Sj/P/f33F/1FRUf+I267/kO28/5Dsu/+Q7Lv/ku+9/5Douv9zoon/U1VU/4GDgunx8fFJ////AP///wD///8A////AP///wAAAAAA////AP///wD///8A////AP///wD///8A/f39HLW1tatbW13/WVlg/3Bunv+Gg9T/k4/y/5SR9f+Bfsf/UVFR/4vfsv+S773/kOu7/4TKpf9ul4H/VlpY/19hYP/AwMCr////HP///wD///8A////AP///wD///8A////AAAAAAD///8A////AP///wD///8A////AP///wD///8A////APf390y0tLS6cG9y/1FRUf9WVlr/Y2J2/2Fgdv9RUVH/ZYBx/2N1a/9VV1b/UVFR/3R2df+/v7+6+vr6TP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o7e3tdcXFxbCqqqrbl5eX9HBwcP2YmJj0q6ur28fHx7Dv7+91////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAA//Af//+AA//+AAD//AAAf/gAAD/wAAAf4AAAD8AAAAfAAAAHgAAAA4AAAAOAAAADAAfAAQAP4AEAH/ABAB/wAQAf8AEAH/ABAA/gAQAHwAGAAAADgAAAA4AAAAPAAAAHwAAAB+AAAA/wAAAf+AAAP/wAAH/+AAD//4AD///wH/8="><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu"><script id="notfound">window.onload=function(){document.body.innerHTML=""}</script><script language="javascript" type="text/javascript">{//---------------------------------------------------------------------------- | |
| 3 // | |
| 4 // PURPOSE | |
| 5 // | |
| 6 // Krona is a flexible tool for exploring the relative proportions of | |
| 7 // hierarchical data, such as metagenomic classifications, using a | |
| 8 // radial, space-filling display. It is implemented using HTML5 and | |
| 9 // JavaScript, allowing charts to be explored locally or served over the | |
| 10 // Internet, requiring only a current version of any major web | |
| 11 // browser. Krona charts can be created using an Excel template or from | |
| 12 // common bioinformatic formats using the provided conversion scripts. | |
| 13 // | |
| 14 // | |
| 15 // COPYRIGHT LICENSE | |
| 16 // | |
| 17 // Copyright (c) 2011, Battelle National Biodefense Institute (BNBI); | |
| 18 // all rights reserved. Authored by: Brian Ondov, Nicholas Bergman, and | |
| 19 // Adam Phillippy | |
| 20 // | |
| 21 // This Software was prepared for the Department of Homeland Security | |
| 22 // (DHS) by the Battelle National Biodefense Institute, LLC (BNBI) as | |
| 23 // part of contract HSHQDC-07-C-00020 to manage and operate the National | |
| 24 // Biodefense Analysis and Countermeasures Center (NBACC), a Federally | |
| 25 // Funded Research and Development Center. | |
| 26 // | |
| 27 // Redistribution and use in source and binary forms, with or without | |
| 28 // modification, are permitted provided that the following conditions are | |
| 29 // met: | |
| 30 // | |
| 31 // * Redistributions of source code must retain the above copyright | |
| 32 // notice, this list of conditions and the following disclaimer. | |
| 33 // | |
| 34 // * Redistributions in binary form must reproduce the above copyright | |
| 35 // notice, this list of conditions and the following disclaimer in the | |
| 36 // documentation and/or other materials provided with the distribution. | |
| 37 // | |
| 38 // * Neither the name of the Battelle National Biodefense Institute nor | |
| 39 // the names of its contributors may be used to endorse or promote | |
| 40 // products derived from this software without specific prior written | |
| 41 // permission. | |
| 42 // | |
| 43 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 44 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 45 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 46 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 47 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 48 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 49 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 50 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 51 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 52 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 53 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 54 // | |
| 55 // | |
| 56 // TRADEMARK LICENSE | |
| 57 // | |
| 58 // KRONA(TM) is a trademark of the Department of Homeland Security, and use | |
| 59 // of the trademark is subject to the following conditions: | |
| 60 // | |
| 61 // * Distribution of the unchanged, official code/software using the | |
| 62 // KRONA(TM) mark is hereby permitted by the Department of Homeland | |
| 63 // Security, provided that the software is distributed without charge | |
| 64 // and modification. | |
| 65 // | |
| 66 // * Distribution of altered source code/software using the KRONA(TM) mark | |
| 67 // is not permitted unless written permission has been granted by the | |
| 68 // Department of Homeland Security. | |
| 69 // | |
| 70 // | |
| 71 // FOR MORE INFORMATION VISIT | |
| 72 // | |
| 73 // https://github.com/marbl/Krona/wiki/ | |
| 74 // | |
| 75 //---------------------------------------------------------------------------- | |
| 76 // | |
| 77 // Copyright (C) 2017-2022 Jose Manuel Martà MartÃnez, for the changes in | |
| 78 // this file from the Krona Javascript 2.0 release. | |
| 79 // | |
| 80 // Redistribution and use in source and binary forms, with or without | |
| 81 // modification, are permitted provided that the above copyright notice is | |
| 82 // reproduced and all the above conditions are met. | |
| 83 // | |
| 84 // The KRONA(TM) mark has been substituted in the generated charts by | |
| 85 // another logo in compliance with the above-stated conditions. | |
| 86 // | |
| 87 // FOR MORE INFORMATION VISIT | |
| 88 // | |
| 89 // https://github.com/khyox/recentrifuge/wiki/ | |
| 90 // | |
| 91 //---------------------------------------------------------------------------- | |
| 92 } | |
| 93 | |
| 94 /////////////// | |
| 95 // Variables // | |
| 96 /////////////// | |
| 97 | |
| 98 var canvas; | |
| 99 var canvasButtons = []; // Keep trace of CanvasButton objects | |
| 100 var ChartEnum = Object.freeze({ | |
| 101 TAXOMIC: 'taxonomic', | |
| 102 GENOMIC: 'genomic' | |
| 103 }) | |
| 104 var chart = ChartEnum.TAXOMIC | |
| 105 var context; | |
| 106 var svg; // for snapshot mode | |
| 107 var collapse = true; | |
| 108 var collapseCheckBox; | |
| 109 var collapseLast; | |
| 110 var compress; | |
| 111 var compressCheckBox; | |
| 112 var maxAbsoluteDepthText; | |
| 113 var maxAbsoluteDepthButtonDecrease; | |
| 114 var maxAbsoluteDepthButtonIncrease; | |
| 115 var fontSize = 12; | |
| 116 var fontSizeText; | |
| 117 var fontSizeButtonDecrease; | |
| 118 var fontSizeButtonIncrease; | |
| 119 var fontSizeLast; | |
| 120 var bkgBright = "eeeeee"; | |
| 121 var bkgBrightButtonDecrease; | |
| 122 var bkgBrightButtonIncrease; | |
| 123 var radiusButtonDecrease; | |
| 124 var radiusButtonIncrease; | |
| 125 var shorten; | |
| 126 var shortenCheckBox; | |
| 127 var maxAbsoluteDepth; | |
| 128 var backButton; | |
| 129 var upButton; | |
| 130 var forwardButton; | |
| 131 var snapshotButton; | |
| 132 var snapshotMode = false; | |
| 133 var details; | |
| 134 var detailsName; | |
| 135 var search; | |
| 136 var searchResults; | |
| 137 var nSearchResults; | |
| 138 var useHueCheckBox; | |
| 139 var useHueDiv; | |
| 140 var sortByScoreCheckBox; | |
| 141 var datasetDropDown; | |
| 142 var datasetButtonLast; | |
| 143 var datasetButtonPrev; | |
| 144 var datasetButtonNext; | |
| 145 var rankDropDown; | |
| 146 var keyControl; | |
| 147 var showKeys = true; | |
| 148 var linkButton; | |
| 149 var linkText; | |
| 150 var frame; | |
| 151 | |
| 152 // Node references. Note that the meanings of 'selected' and 'focused' are | |
| 153 // swapped in the docs. | |
| 154 // | |
| 155 var head; // the root of the entire tree | |
| 156 var selectedNode = 0; // the root of the current view | |
| 157 var focusNode = 0; // a node chosen for more info (single-click) | |
| 158 var highlightedNode = 0; // mouse hover node | |
| 159 var highlightingHidden = false; | |
| 160 var nodes = new Array(); // Array with all the nodes | |
| 161 var nodesIndex; // Index of nodes, points last using hue(score) buttons | |
| 162 var currentNodeID = 0; // to iterate while loading | |
| 163 | |
| 164 var nodeHistory = new Array(); | |
| 165 var nodeHistoryPosition = 0; | |
| 166 | |
| 167 var dataEnabled = false; // true when supplemental files are present | |
| 168 | |
| 169 // store non-Krona GET variables so they can be passed on to links | |
| 170 // | |
| 171 var getVariables = new Array(); | |
| 172 | |
| 173 // selectedNodeLast is separate from the history, since we need to check | |
| 174 // properties of the last node viewed when browsing through the history | |
| 175 // | |
| 176 var selectedNodeLast = 0; | |
| 177 var zoomOut = false; | |
| 178 | |
| 179 // temporary zoom-in while holding the mouse button on a wedge | |
| 180 // | |
| 181 var quickLook = false; // true when in quick look state | |
| 182 var mouseDown = false; | |
| 183 var mouseDownTime; // to detect mouse button hold | |
| 184 var quickLookHoldLength = 200; | |
| 185 | |
| 186 var imageWidth; | |
| 187 var imageHeight; | |
| 188 var centerX; | |
| 189 var centerY; | |
| 190 var gRadius; | |
| 191 var updateViewNeeded = false; | |
| 192 | |
| 193 // Determines the angle that the pie chart starts at. 90 degrees makes the | |
| 194 // center label consistent with the children. | |
| 195 // | |
| 196 var rotationOffset = Math.PI / 2; | |
| 197 | |
| 198 var buffer; | |
| 199 var bufferFactor = .1; | |
| 200 | |
| 201 // The maps are the small pie charts showing the current slice being viewed. | |
| 202 // | |
| 203 var mapBuffer = 10; | |
| 204 var mapRadius = 0; | |
| 205 var maxMapRadius = 25; | |
| 206 var mapWidth = 150; | |
| 207 var maxLabelOverhang = Math.PI * 4.18; | |
| 208 | |
| 209 // Keys are the labeled boxes for slices in the highest level that are too thin | |
| 210 // to label. | |
| 211 // | |
| 212 var maxKeySizeFactor = 2; // will be multiplied by font size | |
| 213 var keySize; | |
| 214 var keys; | |
| 215 var keyBuffer = 10; | |
| 216 var currentKey; | |
| 217 var keyMinTextLeft; | |
| 218 var keyMinAngle; | |
| 219 | |
| 220 var minRingWidthFactor = 5; // will be multiplied by font size | |
| 221 var maxPossibleDepth; // the theoretical max that can be displayed | |
| 222 var maxDisplayDepth; // the actual depth that will be displayed | |
| 223 var headerHeight = 0;//document.getElementById('options').clientHeight; | |
| 224 var historySpacingFactor = 1.6; // will be multiplied by font size | |
| 225 var historyAlphaDelta = .25; | |
| 226 | |
| 227 // appearance | |
| 228 // | |
| 229 var lineOpacity = 0.3; | |
| 230 var saturation = 0.5; | |
| 231 var lightnessBase = 0.6; | |
| 232 var lightnessMax = .8; | |
| 233 var thinLineWidth = .3; | |
| 234 var highlightLineWidth = 1.5; | |
| 235 var labelBoxBuffer = 6; | |
| 236 var labelBoxRounding = 15; | |
| 237 var labelWidthFudge = 1.05; // The width of unshortened labels are set slightly | |
| 238 // longer than the name width so the animation | |
| 239 // finishes faster. | |
| 240 var fontNormal; | |
| 241 var fontBold; | |
| 242 var fontFamily = 'sans-serif'; | |
| 243 //var fontFaceBold = 'bold Arial'; | |
| 244 var nodeRadius; | |
| 245 var angleFactor; | |
| 246 var tickLength; | |
| 247 var compressedRadii; | |
| 248 | |
| 249 // colors | |
| 250 // | |
| 251 var highlightFill = 'rgba(255, 255, 255, .3)'; | |
| 252 var colorUnclassified = 'rgb(220,220,220)'; | |
| 253 | |
| 254 // label staggering | |
| 255 // | |
| 256 var labelOffsets; // will store the current offset at each depth | |
| 257 // | |
| 258 // This will store pointers to the last node that had a label in each offset | |
| 259 // (or "track") of each depth. These will be used to shorten neighboring | |
| 260 // labels that would overlap. The [nLabelNodes] index will store the last node | |
| 261 // with a radial label. labelFirstNodes is the same, but to check for going all | |
| 262 // the way around and overlapping the first labels. | |
| 263 // | |
| 264 var labelLastNodes; | |
| 265 var labelFirstNodes; | |
| 266 // | |
| 267 var nLabelOffsets = 3; // the number of offsets to use | |
| 268 | |
| 269 var mouseX = -1; | |
| 270 var mouseY = -1; | |
| 271 var mouseXRel = -1; | |
| 272 var mouseYRel = -1; | |
| 273 | |
| 274 // tweening | |
| 275 // | |
| 276 var progress = 0; // for tweening; goes from 0 to 1. | |
| 277 var progressLast = 0; | |
| 278 var tweenFactor = 0; // progress converted by a curve for a smoother effect. | |
| 279 var tweenLength = 850; // in ms | |
| 280 var tweenCurvature = 13; | |
| 281 // | |
| 282 // tweenMax is used to scale the sigmoid function so its range is [0,1] for the | |
| 283 // domain [0,1] | |
| 284 // | |
| 285 var tweenMax = 1 / (1 + Math.exp(-tweenCurvature / 2)); | |
| 286 // | |
| 287 var tweenStartTime; | |
| 288 | |
| 289 // for framerate debug | |
| 290 // | |
| 291 var tweenFrames = 0; | |
| 292 var fpsDisplay = document.getElementById('frameRate'); | |
| 293 | |
| 294 // Arrays to translate xml attribute names into displayable attribute names | |
| 295 // | |
| 296 var attributes = []; | |
| 297 // | |
| 298 var magnitudeIndex; // the index of attribute arrays used for magnitude | |
| 299 var membersAssignedIndex; | |
| 300 var membersSummaryIndex; | |
| 301 | |
| 302 // For defining gradients | |
| 303 // | |
| 304 var hueDisplayName; | |
| 305 var hueStopPositions; | |
| 306 var hueStopHues; | |
| 307 var hueStopText; | |
| 308 | |
| 309 // multiple datasets | |
| 310 // | |
| 311 const DEFAULT_RANK = 'SUMMARY'; | |
| 312 const NO_RANK = 'NONE'; | |
| 313 var currentRank = DEFAULT_RANK; | |
| 314 var currentDataset = 0; | |
| 315 var lastDataset = 0; | |
| 316 var datasets = 1; | |
| 317 var datasetNames; | |
| 318 const DATASET_MAX_SIZE = 20; // Max size in rows of the dataset selection list | |
| 319 var datasetsVisible = 1; // Number of datasets not hidden | |
| 320 var datasetAlpha = new Tween(0, 0); | |
| 321 var datasetWidths = []; | |
| 322 var datasetChanged; | |
| 323 var datasetSelectWidth = 50; | |
| 324 var numRawSamples; | |
| 325 var stats; | |
| 326 | |
| 327 window.onload = load; | |
| 328 | |
| 329 var image; | |
| 330 var hiddenPattern; | |
| 331 var loadingImage; | |
| 332 var logoImage; | |
| 333 | |
| 334 // Setup CSS-like style of tooltips for attributes | |
| 335 // | |
| 336 var csstring = '.CellWithTooltip{ position:relative; }\n' + | |
| 337 '.Tooltip{ display:none;position:absolute;z-index:100;border:2px;' + | |
| 338 'background-color:white;border-style:solid;border-width:2px;' + | |
| 339 'border-color:red;padding:3px;color:red;top:20px;left:0px; }' + | |
| 340 '.CellWithTooltip:hover span.Tooltip{ display:block; }'; | |
| 341 var style = document.createElement('style'); | |
| 342 if (style.styleSheet) { | |
| 343 style.styleSheet.cssText = csstring; | |
| 344 } else { | |
| 345 style.appendChild(document.createTextNode(csstring)); | |
| 346 } | |
| 347 document.getElementsByTagName('head')[0].appendChild(style); | |
| 348 | |
| 349 /////////////// | |
| 350 // Functions // | |
| 351 /////////////// | |
| 352 | |
| 353 function backingScale() { | |
| 354 if ('devicePixelRatio' in window) { | |
| 355 if (window.devicePixelRatio > 1) { | |
| 356 return window.devicePixelRatio; | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 return 1; | |
| 361 } | |
| 362 | |
| 363 function resize() { | |
| 364 imageWidth = window.innerWidth; | |
| 365 imageHeight = window.innerHeight; | |
| 366 | |
| 367 if (!snapshotMode) { | |
| 368 context.canvas.width = imageWidth * backingScale(); | |
| 369 context.canvas.height = imageHeight * backingScale(); | |
| 370 context.canvas.style.width = imageWidth + "px" | |
| 371 context.canvas.style.height = imageHeight + "px" | |
| 372 context.scale(backingScale(), backingScale()); | |
| 373 } | |
| 374 | |
| 375 if (datasetDropDown) { | |
| 376 var ratio = | |
| 377 (datasetDropDown.offsetTop + datasetDropDown.clientHeight) * 2 / | |
| 378 imageHeight; | |
| 379 | |
| 380 if (ratio > 1) { | |
| 381 ratio = 1; | |
| 382 } | |
| 383 | |
| 384 ratio = Math.sqrt(ratio); | |
| 385 | |
| 386 datasetSelectWidth = | |
| 387 (datasetDropDown.offsetLeft + datasetDropDown.clientWidth) * ratio; | |
| 388 } | |
| 389 var leftMargin = datasets > 1 ? datasetSelectWidth + 30 : 0; | |
| 390 var minDimension = imageWidth - mapWidth - leftMargin > imageHeight ? | |
| 391 imageHeight : | |
| 392 imageWidth - mapWidth - leftMargin; | |
| 393 | |
| 394 maxMapRadius = minDimension * .03; | |
| 395 buffer = minDimension * bufferFactor; | |
| 396 margin = minDimension * .015; | |
| 397 centerX = (imageWidth - mapWidth - leftMargin) / 2 + leftMargin; | |
| 398 centerY = imageHeight / 2; | |
| 399 gRadius = minDimension / 2 - buffer; | |
| 400 //context.font = '11px sans-serif'; | |
| 401 } | |
| 402 | |
| 403 function handleResize() { | |
| 404 updateViewNeeded = true; | |
| 405 } | |
| 406 | |
| 407 function Attribute() { | |
| 408 } | |
| 409 | |
| 410 function SampleStats(sample, ictrl, sread, sclas, sfilt, scmin, scavg, scmax, | |
| 411 lnmin, lnavg, lnmax, tclas, tfilt, tfold) { | |
| 412 // Class to store the statistics of a sample | |
| 413 this.sample = sample; | |
| 414 this.is_ctrl = (ictrl === 'True'); | |
| 415 this.sread = sread; | |
| 416 this.sclas = sclas; | |
| 417 this.sfilt = sfilt; | |
| 418 this.scmin = scmin; | |
| 419 this.scavg = scavg; | |
| 420 this.scmax = scmax; | |
| 421 this.lnmin = lnmin; | |
| 422 this.lnavg = lnavg; | |
| 423 this.lnmax = lnmax; | |
| 424 this.tclas = tclas; | |
| 425 this.tfilt = tfilt; | |
| 426 this.tfold = tfold; | |
| 427 } | |
| 428 | |
| 429 function CanvasButton(name, x, y, w, h, fill) { | |
| 430 // Constructor for a button in the canvas | |
| 431 this.name = name; | |
| 432 this.x = x || 0; | |
| 433 this.y = y || 0; | |
| 434 this.w = w || 1; | |
| 435 this.h = h || 1; | |
| 436 this.fill = fill || '#000000'; | |
| 437 | |
| 438 // Draws the button to a given context | |
| 439 this.draw = function (ctx) { | |
| 440 var oldAlpha = ctx.globalAlpha | |
| 441 ctx.globalAlpha = 1; | |
| 442 ctx.strokeStyle = '#' + bkgBright; | |
| 443 ctx.lineWidth = 3; | |
| 444 ctx.strokeRect(this.x, this.y, this.w, this.h); | |
| 445 ctx.fillStyle = this.fill; | |
| 446 ctx.fillRect(this.x, this.y, this.w, this.h); | |
| 447 ctx.strokeStyle = '#000000'; | |
| 448 ctx.lineWidth = 0.5; | |
| 449 ctx.strokeRect(this.x, this.y, this.w, this.h); | |
| 450 // Draws symbols in buttons | |
| 451 ctx.fillStyle = '#000000'; | |
| 452 ctx.globalAlpha = 0.7; | |
| 453 switch (this.name) { | |
| 454 case 'mostScore': | |
| 455 ctx.beginPath(); | |
| 456 ctx.moveTo(this.x + 1 * this.w / 2, this.y + this.h / 8); | |
| 457 ctx.lineTo(this.x + 1 * this.w / 6, this.y + this.h / 2); | |
| 458 ctx.lineTo(this.x + 5 * this.w / 6, this.y + this.h / 2); | |
| 459 ctx.fill(); | |
| 460 case 'moreScore': | |
| 461 ctx.beginPath(); | |
| 462 ctx.moveTo(this.x + 1 * this.w / 2, this.y + 1 * this.h / 4); | |
| 463 ctx.lineTo(this.x + 1 * this.w / 6, this.y + 3 * this.h / 4); | |
| 464 ctx.lineTo(this.x + 5 * this.w / 6, this.y + 3 * this.h / 4); | |
| 465 ctx.fill(); | |
| 466 break; | |
| 467 case 'lestScore': | |
| 468 ctx.beginPath(); | |
| 469 ctx.moveTo(this.x + 1 * this.w / 2, this.y + 7 * this.h / 8); | |
| 470 ctx.lineTo(this.x + 1 * this.w / 6, this.y + 1 * this.h / 2); | |
| 471 ctx.lineTo(this.x + 5 * this.w / 6, this.y + 1 * this.h / 2); | |
| 472 ctx.fill(); | |
| 473 case 'lessScore': | |
| 474 ctx.beginPath(); | |
| 475 ctx.moveTo(this.x + 1 * this.w / 2, this.y + 3 * this.h / 4); | |
| 476 ctx.lineTo(this.x + 1 * this.w / 6, this.y + 1 * this.h / 4); | |
| 477 ctx.lineTo(this.x + 5 * this.w / 6, this.y + 1 * this.h / 4); | |
| 478 ctx.fill(); | |
| 479 break; | |
| 480 } | |
| 481 ctx.globalAlpha = oldAlpha | |
| 482 }; | |
| 483 | |
| 484 // Determine if a point is inside the button's bounds | |
| 485 this.is_inside = function (mx, my) { | |
| 486 // Check the Mouse X,Y fall in the button's area | |
| 487 return (this.x <= mx) && (this.x + this.w >= mx) && | |
| 488 (this.y <= my) && (this.y + this.h >= my); | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 function Tween(start, end) { | |
| 493 this.start = start; | |
| 494 this.end = end; | |
| 495 this.current = this.start; | |
| 496 | |
| 497 this.current = function () { | |
| 498 if (progress == 1 || this.start == this.end) { | |
| 499 return this.end; | |
| 500 } | |
| 501 else { | |
| 502 return this.start + tweenFactor * (this.end - this.start); | |
| 503 } | |
| 504 }; | |
| 505 | |
| 506 this.setTarget = function (target) { | |
| 507 this.start = this.current(); | |
| 508 this.end = target; | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 function Node() { | |
| 513 this.id = currentNodeID; | |
| 514 currentNodeID++; | |
| 515 nodes[this.id] = this; | |
| 516 | |
| 517 this.angleStart = new Tween(Math.PI, 0); | |
| 518 this.angleEnd = new Tween(Math.PI, 0); | |
| 519 this.radiusInner = new Tween(1, 1); | |
| 520 this.labelRadius = new Tween(1, 1); | |
| 521 this.labelWidth = new Tween(0, 0); | |
| 522 this.scale = new Tween(1, 1); // TEMP | |
| 523 this.radiusOuter = new Tween(1, 1); | |
| 524 | |
| 525 this.r = new Tween(255, 255); | |
| 526 this.g = new Tween(255, 255); | |
| 527 this.b = new Tween(255, 255); | |
| 528 | |
| 529 this.alphaLabel = new Tween(0, 1); | |
| 530 this.alphaLine = new Tween(0, 1); | |
| 531 this.alphaArc = new Tween(0, 0); | |
| 532 this.alphaWedge = new Tween(0, 1); | |
| 533 this.alphaOther = new Tween(0, 1); | |
| 534 this.alphaPattern = new Tween(0, 0); | |
| 535 this.children = Array(); | |
| 536 this.parent = 0; | |
| 537 | |
| 538 this.attributes = new Array(attributes.length); | |
| 539 | |
| 540 this.addChild = function (child) { | |
| 541 this.children.push(child); | |
| 542 }; | |
| 543 | |
| 544 this.addLabelNode = function (depth, labelOffset) { | |
| 545 if (labelHeadNodes[depth][labelOffset] == 0) { | |
| 546 // this will become the head node for this list | |
| 547 | |
| 548 labelHeadNodes[depth][labelOffset] = this; | |
| 549 this.labelPrev = this; | |
| 550 } | |
| 551 | |
| 552 var head = labelHeadNodes[depth][labelOffset]; | |
| 553 | |
| 554 this.labelNext = head; | |
| 555 this.labelPrev = head.labelPrev; | |
| 556 head.labelPrev.labelNext = this; | |
| 557 head.labelPrev = this; | |
| 558 } | |
| 559 | |
| 560 this.canDisplayDepth = function () { | |
| 561 // whether this node is at a depth that can be displayed, according | |
| 562 // to the max absolute depth | |
| 563 | |
| 564 return this.depth <= maxAbsoluteDepth; | |
| 565 } | |
| 566 | |
| 567 this.canDisplayHistory = function () { | |
| 568 var radiusInner; | |
| 569 | |
| 570 if (compress) { | |
| 571 radiusInner = compressedRadii[0]; | |
| 572 } | |
| 573 else { | |
| 574 radiusInner = nodeRadius; | |
| 575 } | |
| 576 | |
| 577 return ( | |
| 578 -this.labelRadius.end * gRadius + | |
| 579 historySpacingFactor * fontSize / 2 < | |
| 580 radiusInner * gRadius | |
| 581 ); | |
| 582 } | |
| 583 | |
| 584 this.canDisplayLabelCurrent = function () { | |
| 585 return ( | |
| 586 (this.angleEnd.current() - this.angleStart.current()) * | |
| 587 (this.radiusInner.current() * gRadius + gRadius) >= | |
| 588 minWidth()); | |
| 589 } | |
| 590 | |
| 591 this.checkHighlight = function () { | |
| 592 if (this.children.length == 0 && this == focusNode) { | |
| 593 //return false; | |
| 594 } | |
| 595 | |
| 596 if (this.hide) { | |
| 597 return false; | |
| 598 } | |
| 599 | |
| 600 if (this.radiusInner.end == 1) { | |
| 601 // compressed to the outside; don't check | |
| 602 | |
| 603 return false; | |
| 604 } | |
| 605 | |
| 606 var highlighted = false; | |
| 607 | |
| 608 var angleStartCurrent = this.angleStart.current() + rotationOffset; | |
| 609 var angleEndCurrent = this.angleEnd.current() + rotationOffset; | |
| 610 var radiusInner = this.radiusInner.current() * gRadius; | |
| 611 | |
| 612 for (var i = 0; i < this.children.length; i++) { | |
| 613 highlighted = this.children[i].checkHighlight(); | |
| 614 | |
| 615 if (highlighted) { | |
| 616 return true; | |
| 617 } | |
| 618 } | |
| 619 | |
| 620 if (this.radial) { | |
| 621 var angleText = (angleStartCurrent + angleEndCurrent) / 2; | |
| 622 var radiusText = (gRadius + radiusInner) / 2; | |
| 623 | |
| 624 context.rotate(angleText); | |
| 625 context.beginPath(); | |
| 626 context.moveTo(radiusText, -fontSize); | |
| 627 context.lineTo(radiusText, fontSize); | |
| 628 context.lineTo(radiusText + centerX, fontSize); | |
| 629 context.lineTo(radiusText + centerX, -fontSize); | |
| 630 context.closePath(); | |
| 631 context.rotate(-angleText); | |
| 632 | |
| 633 if (context.isPointInPath(mouseXRel, mouseYRel)) { | |
| 634 var label = String(this.getPercentage()) + '%' + ' ' | |
| 635 + this.name; | |
| 636 | |
| 637 if (this.searchResultChildren()) { | |
| 638 label += searchResultString(this.searchResultChildren()); | |
| 639 } | |
| 640 | |
| 641 if | |
| 642 ( | |
| 643 Math.sqrt((mouseXRel) * (mouseXRel) | |
| 644 + (mouseYRel) * (mouseYRel)) / backingScale() < | |
| 645 radiusText + measureText(label) | |
| 646 ) { | |
| 647 highlighted = true; | |
| 648 } | |
| 649 } | |
| 650 } | |
| 651 else { | |
| 652 for (var i = 0; i < this.hiddenLabels.length; i++) { | |
| 653 var hiddenLabel = this.hiddenLabels[i]; | |
| 654 | |
| 655 context.rotate(hiddenLabel.angle); | |
| 656 context.beginPath(); | |
| 657 context.moveTo(gRadius, -fontSize); | |
| 658 context.lineTo(gRadius, fontSize); | |
| 659 context.lineTo(gRadius + centerX, fontSize); | |
| 660 context.lineTo(gRadius + centerX, -fontSize); | |
| 661 context.closePath(); | |
| 662 context.rotate(-hiddenLabel.angle); | |
| 663 | |
| 664 if (context.isPointInPath(mouseXRel, mouseYRel)) { | |
| 665 var label = String(hiddenLabel.value) + ' more'; | |
| 666 | |
| 667 if (hiddenLabel.search) { | |
| 668 label += searchResultString(hiddenLabel.search); | |
| 669 } | |
| 670 | |
| 671 if | |
| 672 ( | |
| 673 Math.sqrt((mouseXRel) * (mouseXRel) | |
| 674 + (mouseYRel) * (mouseYRel)) / backingScale() < | |
| 675 gRadius + fontSize + measureText(label) | |
| 676 ) { | |
| 677 highlighted = true; | |
| 678 break; | |
| 679 } | |
| 680 } | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 if (!highlighted && this != selectedNode && !this.getCollapse()) { | |
| 685 context.beginPath(); | |
| 686 context.arc(0, 0, radiusInner, angleStartCurrent, angleEndCurrent, | |
| 687 false); | |
| 688 context.arc(0, 0, gRadius, angleEndCurrent, angleStartCurrent, | |
| 689 true); | |
| 690 context.closePath(); | |
| 691 | |
| 692 if (context.isPointInPath(mouseXRel, mouseYRel)) { | |
| 693 highlighted = true; | |
| 694 } | |
| 695 | |
| 696 if | |
| 697 ( | |
| 698 !highlighted && | |
| 699 (angleEndCurrent - angleStartCurrent) * | |
| 700 (radiusInner + gRadius) < | |
| 701 minWidth() && | |
| 702 this.getDepth() == selectedNode.getDepth() + 1 | |
| 703 ) { | |
| 704 if (showKeys && this.checkHighlightKey()) { | |
| 705 highlighted = true; | |
| 706 } | |
| 707 } | |
| 708 } | |
| 709 | |
| 710 if (highlighted) { | |
| 711 if (this != highlightedNode) { | |
| 712 // document.body.style.cursor='pointer'; | |
| 713 } | |
| 714 | |
| 715 highlightedNode = this; | |
| 716 } | |
| 717 | |
| 718 return highlighted; | |
| 719 } | |
| 720 | |
| 721 this.checkHighlightCenter = function () { | |
| 722 if (!this.canDisplayHistory()) { | |
| 723 return; | |
| 724 } | |
| 725 | |
| 726 var cx = centerX; | |
| 727 var cy = centerY - this.labelRadius.end * gRadius; | |
| 728 //var dim = context.measureText(this.name); | |
| 729 | |
| 730 var width = this.nameWidth; | |
| 731 | |
| 732 if (this.searchResultChildren()) { | |
| 733 var results = searchResultString(this.searchResultChildren()); | |
| 734 var dim = context.measureText(results); | |
| 735 width += dim.width; | |
| 736 } | |
| 737 | |
| 738 if | |
| 739 ( | |
| 740 mouseX > cx - width / 2 && | |
| 741 mouseX < cx + width / 2 && | |
| 742 mouseY > cy - historySpacingFactor * fontSize / 2 && | |
| 743 mouseY < cy + historySpacingFactor * fontSize / 2 | |
| 744 ) { | |
| 745 highlightedNode = this; | |
| 746 return; | |
| 747 } | |
| 748 | |
| 749 if (this.getParent()) { | |
| 750 this.getParent().checkHighlightCenter(); | |
| 751 } | |
| 752 } | |
| 753 | |
| 754 this.checkHighlightKey = function () { | |
| 755 var offset = keyOffset(); | |
| 756 | |
| 757 var xMin = imageWidth - keySize - margin - this.keyNameWidth | |
| 758 - keyBuffer; | |
| 759 var xMax = imageWidth - margin; | |
| 760 var yMin = offset; | |
| 761 var yMax = offset + keySize; | |
| 762 | |
| 763 currentKey++; | |
| 764 | |
| 765 return ( | |
| 766 mouseX > xMin && | |
| 767 mouseX < xMax && | |
| 768 mouseY > yMin && | |
| 769 mouseY < yMax); | |
| 770 } | |
| 771 | |
| 772 this.checkHighlightMap = function () { | |
| 773 if (this.parent) { | |
| 774 this.parent.checkHighlightMap(); | |
| 775 } | |
| 776 | |
| 777 if (this.getCollapse() || this == focusNode) { | |
| 778 return; | |
| 779 } | |
| 780 | |
| 781 var box = this.getMapPosition(); | |
| 782 | |
| 783 if | |
| 784 ( | |
| 785 mouseX > box.x - mapRadius && | |
| 786 mouseX < box.x + mapRadius && | |
| 787 mouseY > box.y - mapRadius && | |
| 788 mouseY < box.y + mapRadius | |
| 789 ) { | |
| 790 highlightedNode = this; | |
| 791 } | |
| 792 } | |
| 793 | |
| 794 /* this.collapse = function() | |
| 795 { | |
| 796 for (var i = 0; i < this.children.length; i++ ) | |
| 797 { | |
| 798 this.children[i] = this.children[i].collapse(); | |
| 799 } | |
| 800 | |
| 801 if | |
| 802 ( | |
| 803 this.children.length == 1 && | |
| 804 this.children[0].magnitude == this.magnitude | |
| 805 ) | |
| 806 { | |
| 807 this.children[0].parent = this.parent; | |
| 808 this.children[0].getDepth() = this.parent.getDepth() + 1; | |
| 809 return this.children[0]; | |
| 810 } | |
| 811 else | |
| 812 { | |
| 813 return this; | |
| 814 } | |
| 815 } | |
| 816 */ | |
| 817 this.draw = function (labelMode, selected, searchHighlighted) { | |
| 818 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 819 // var hidden = false; | |
| 820 | |
| 821 if (selectedNode == this) { | |
| 822 selected = true; | |
| 823 } | |
| 824 | |
| 825 var angleStartCurrent = this.angleStart.current() + rotationOffset; | |
| 826 var angleEndCurrent = this.angleEnd.current() + rotationOffset; | |
| 827 var radiusInner = this.radiusInner.current() * gRadius; | |
| 828 var canDisplayLabelCurrent = this.canDisplayLabelCurrent(); | |
| 829 var hiddenSearchResults = false; | |
| 830 | |
| 831 /* if ( ! this.hide ) | |
| 832 { | |
| 833 for ( var i = 0; i < this.children.length; i++ ) | |
| 834 { | |
| 835 if ( this.children[i].hide && this.children[i].searchResults ) | |
| 836 { | |
| 837 hiddenSearchResults = true; | |
| 838 } | |
| 839 } | |
| 840 } | |
| 841 */ | |
| 842 var drawChildren = | |
| 843 (!this.hide || !this.hidePrev && progress < 1) && | |
| 844 (!this.hideAlone || !this.hideAlonePrev && progress < 1); | |
| 845 | |
| 846 // if ( this.alphaWedge.current() > 0 || this.alphaLabel.current() > 0 ) | |
| 847 { | |
| 848 var lastChildAngleEnd = angleStartCurrent; | |
| 849 | |
| 850 if (this.hasChildren())//canDisplayChildren ) | |
| 851 { | |
| 852 lastChildAngleEnd = | |
| 853 this.children[this.children.length - 1].angleEnd.current() | |
| 854 + rotationOffset; | |
| 855 } | |
| 856 | |
| 857 if (labelMode) { | |
| 858 var drawRadial = | |
| 859 !( | |
| 860 this.parent && | |
| 861 this.parent != selectedNode && | |
| 862 angleEndCurrent == this.parent.angleEnd.current() | |
| 863 + rotationOffset | |
| 864 ); | |
| 865 | |
| 866 //if ( angleStartCurrent != angleEndCurrent ) | |
| 867 { | |
| 868 this.drawLines(angleStartCurrent, angleEndCurrent, | |
| 869 radiusInner, drawRadial, selected); | |
| 870 } | |
| 871 | |
| 872 var alphaOtherCurrent = this.alphaOther.current(); | |
| 873 var childRadiusInner; | |
| 874 | |
| 875 if (this == selectedNode || alphaOtherCurrent) { | |
| 876 childRadiusInner = | |
| 877 this.children.length ? | |
| 878 this.children[this.children.length | |
| 879 - 1].radiusInner.current() * gRadius | |
| 880 : radiusInner | |
| 881 } | |
| 882 | |
| 883 if (this == selectedNode) { | |
| 884 this.drawReferenceRings(childRadiusInner); | |
| 885 } | |
| 886 | |
| 887 if | |
| 888 ( | |
| 889 selected && | |
| 890 !searchHighlighted && | |
| 891 this != selectedNode && | |
| 892 ( | |
| 893 this.isSearchResult || | |
| 894 this.hideAlone && this.searchResultChildren() || | |
| 895 false | |
| 896 // this.hide && | |
| 897 // this.containsSearchResult | |
| 898 ) | |
| 899 ) { | |
| 900 context.globalAlpha = this.alphaWedge.current(); | |
| 901 | |
| 902 drawWedge | |
| 903 ( | |
| 904 angleStartCurrent, | |
| 905 angleEndCurrent, | |
| 906 radiusInner, | |
| 907 gRadius, | |
| 908 highlightFill, | |
| 909 0, | |
| 910 true | |
| 911 ); | |
| 912 | |
| 913 if | |
| 914 ( | |
| 915 this.keyed && | |
| 916 !showKeys && | |
| 917 this.searchResults && | |
| 918 !searchHighlighted && | |
| 919 this != highlightedNode && | |
| 920 this != focusNode | |
| 921 ) { | |
| 922 var angle = (angleEndCurrent + angleStartCurrent) / 2; | |
| 923 this.drawLabel(angle, true, false, true, true); | |
| 924 } | |
| 925 | |
| 926 //this.drawHighlight(false); | |
| 927 searchHighlighted = true; | |
| 928 } | |
| 929 | |
| 930 if | |
| 931 ( | |
| 932 this == selectedNode || | |
| 933 // true | |
| 934 //(canDisplayLabelCurrent) && | |
| 935 this != highlightedNode && | |
| 936 this != focusNode | |
| 937 ) { | |
| 938 if (this.radial != this.radialPrev | |
| 939 && this.alphaLabel.end == 1) { | |
| 940 context.globalAlpha = tweenFactor; | |
| 941 } | |
| 942 else { | |
| 943 context.globalAlpha = this.alphaLabel.current(); | |
| 944 } | |
| 945 | |
| 946 this.drawLabel | |
| 947 ( | |
| 948 (angleStartCurrent + angleEndCurrent) / 2, | |
| 949 this.hideAlone && this.searchResultChildren() || | |
| 950 (this.isSearchResult || hiddenSearchResults) && selected, | |
| 951 this == selectedNode && !this.radial, | |
| 952 selected, | |
| 953 this.radial | |
| 954 ); | |
| 955 | |
| 956 if (this.radial != this.radialPrev | |
| 957 && this.alphaLabel.start == 1 && progress < 1) { | |
| 958 context.globalAlpha = 1 - tweenFactor; | |
| 959 | |
| 960 this.drawLabel | |
| 961 ( | |
| 962 (angleStartCurrent + angleEndCurrent) / 2, | |
| 963 (this.isSearchResult || hiddenSearchResults) | |
| 964 && selected, | |
| 965 this == selectedNodeLast && !this.radialPrev, | |
| 966 selected, | |
| 967 this.radialPrev | |
| 968 ); | |
| 969 } | |
| 970 } | |
| 971 | |
| 972 if | |
| 973 ( | |
| 974 alphaOtherCurrent && | |
| 975 lastChildAngleEnd != null | |
| 976 ) { | |
| 977 if | |
| 978 ( | |
| 979 (angleEndCurrent - lastChildAngleEnd) * | |
| 980 (childRadiusInner + gRadius) >= | |
| 981 minWidth() | |
| 982 ) { | |
| 983 //context.font = fontNormal; | |
| 984 context.globalAlpha = this.alphaOther.current(); | |
| 985 | |
| 986 drawTextPolar | |
| 987 ( | |
| 988 this.getUnclassifiedText(), | |
| 989 this.getUnclassifiedPercentage(), | |
| 990 (lastChildAngleEnd + angleEndCurrent) / 2, | |
| 991 (childRadiusInner + gRadius) / 2, | |
| 992 true, | |
| 993 false, | |
| 994 false, | |
| 995 0, | |
| 996 0 | |
| 997 ); | |
| 998 } | |
| 999 } | |
| 1000 | |
| 1001 if (this == selectedNode && this.keyUnclassified && showKeys) { | |
| 1002 this.drawKey | |
| 1003 ( | |
| 1004 (lastChildAngleEnd + angleEndCurrent) / 2, | |
| 1005 false, | |
| 1006 false | |
| 1007 ); | |
| 1008 } | |
| 1009 } | |
| 1010 else { | |
| 1011 var alphaWedgeCurrent = this.alphaWedge.current(); | |
| 1012 | |
| 1013 if (alphaWedgeCurrent || this.alphaOther.current()) { | |
| 1014 var currentR = this.r.current(); | |
| 1015 var currentG = this.g.current(); | |
| 1016 var currentB = this.b.current(); | |
| 1017 | |
| 1018 var fill = rgbText(currentR, currentG, currentB); | |
| 1019 | |
| 1020 var radiusOuter; | |
| 1021 var lastChildAngle; | |
| 1022 var truncateWedge = | |
| 1023 ( | |
| 1024 (this.hasChildren() || this == selectedNode) && | |
| 1025 !this.keyed && | |
| 1026 (compress || depth < maxDisplayDepth) && | |
| 1027 drawChildren | |
| 1028 ); | |
| 1029 | |
| 1030 if (truncateWedge) { | |
| 1031 radiusOuter = this.children.length | |
| 1032 ? this.children[0].radiusInner.current() | |
| 1033 * gRadius : radiusInner; | |
| 1034 } | |
| 1035 else { | |
| 1036 radiusOuter = gRadius; | |
| 1037 } | |
| 1038 /* | |
| 1039 if ( this.hasChildren() ) | |
| 1040 { | |
| 1041 radiusOuter = this.children[0].getUncollapsed().radiusInner.current() * gRadius + 1; | |
| 1042 } | |
| 1043 else | |
| 1044 { // TEMP | |
| 1045 radiusOuter = radiusInner + nodeRadius * gRadius; | |
| 1046 | |
| 1047 if ( radiusOuter > gRadius ) | |
| 1048 { | |
| 1049 radiusOuter = gRadius; | |
| 1050 } | |
| 1051 } | |
| 1052 */ | |
| 1053 context.globalAlpha = alphaWedgeCurrent; | |
| 1054 | |
| 1055 if (radiusInner != radiusOuter || truncateWedge) { | |
| 1056 drawWedge | |
| 1057 ( | |
| 1058 angleStartCurrent, | |
| 1059 angleEndCurrent, | |
| 1060 radiusInner, | |
| 1061 radiusOuter,//this.radiusOuter.current() * gRadius, | |
| 1062 //'rgba(0, 200, 0, .1)', | |
| 1063 fill, | |
| 1064 this.alphaPattern.current() | |
| 1065 ); | |
| 1066 | |
| 1067 if (truncateWedge) { | |
| 1068 // fill in the extra space if the sum of our | |
| 1069 // childrens' magnitudes is less than ours | |
| 1070 | |
| 1071 if (lastChildAngleEnd < angleEndCurrent) | |
| 1072 //&& false) // TEMP | |
| 1073 { | |
| 1074 if (radiusOuter > 1) { | |
| 1075 // overlap slightly to hide the seam | |
| 1076 | |
| 1077 // radiusOuter -= 1; | |
| 1078 } | |
| 1079 | |
| 1080 if (alphaWedgeCurrent < 1) { | |
| 1081 context.globalAlpha | |
| 1082 = this.alphaOther.current(); | |
| 1083 drawWedge | |
| 1084 ( | |
| 1085 lastChildAngleEnd, | |
| 1086 angleEndCurrent, | |
| 1087 radiusOuter, | |
| 1088 gRadius, | |
| 1089 colorUnclassified, | |
| 1090 0 | |
| 1091 ); | |
| 1092 context.globalAlpha = alphaWedgeCurrent; | |
| 1093 } | |
| 1094 | |
| 1095 drawWedge | |
| 1096 ( | |
| 1097 lastChildAngleEnd, | |
| 1098 angleEndCurrent, | |
| 1099 radiusOuter, | |
| 1100 gRadius, | |
| 1101 //this.radiusOuter.current() * gRadius, | |
| 1102 //'rgba(200, 0, 0, .1)', | |
| 1103 fill, | |
| 1104 this.alphaPattern.current() | |
| 1105 ); | |
| 1106 } | |
| 1107 } | |
| 1108 | |
| 1109 if (radiusOuter < gRadius) { | |
| 1110 // patch up the seam | |
| 1111 // | |
| 1112 context.beginPath(); | |
| 1113 context.arc(0, 0, radiusOuter, | |
| 1114 angleStartCurrent/*lastChildAngleEnd*/, | |
| 1115 angleEndCurrent, false); | |
| 1116 context.strokeStyle = fill; | |
| 1117 context.lineWidth = 1; | |
| 1118 context.stroke(); | |
| 1119 } | |
| 1120 } | |
| 1121 | |
| 1122 if (this.keyed && selected && showKeys) | |
| 1123 //&& progress == 1 ) | |
| 1124 { | |
| 1125 this.drawKey | |
| 1126 ( | |
| 1127 (angleStartCurrent + angleEndCurrent) / 2, | |
| 1128 ( | |
| 1129 this == highlightedNode || | |
| 1130 this == focusNode || | |
| 1131 this.searchResults | |
| 1132 ), | |
| 1133 this == highlightedNode || this == focusNode | |
| 1134 ); | |
| 1135 } | |
| 1136 } | |
| 1137 } | |
| 1138 } | |
| 1139 | |
| 1140 this.hiddenLabels = Array(); | |
| 1141 | |
| 1142 if (drawChildren) { | |
| 1143 // draw children | |
| 1144 // | |
| 1145 for (var i = 0; i < this.children.length; i++) { | |
| 1146 if (this.drawHiddenChildren(i, selected, labelMode, | |
| 1147 searchHighlighted)) { | |
| 1148 var childHiddenEnd = this.children[i].hiddenEnd; | |
| 1149 if (childHiddenEnd > i) { // Avoid infinite loop | |
| 1150 i = childHiddenEnd; | |
| 1151 } | |
| 1152 } | |
| 1153 else { | |
| 1154 this.children[i].draw(labelMode, selected, | |
| 1155 searchHighlighted); | |
| 1156 } | |
| 1157 } | |
| 1158 } | |
| 1159 }; | |
| 1160 | |
| 1161 this.drawHiddenChildren = function | |
| 1162 (firstHiddenChild, | |
| 1163 selected, | |
| 1164 labelMode, | |
| 1165 searchHighlighted) { | |
| 1166 var firstChild = this.children[firstHiddenChild]; | |
| 1167 | |
| 1168 if (firstChild.hiddenEnd == null | |
| 1169 || firstChild.radiusInner.current() == 1) { | |
| 1170 return false; | |
| 1171 } | |
| 1172 | |
| 1173 for (var i = firstHiddenChild; i < firstChild.hiddenEnd; i++) { | |
| 1174 if (!this.children[i].hide | |
| 1175 || !this.children[i].hidePrev && progress < 1) { | |
| 1176 return false; | |
| 1177 } | |
| 1178 } | |
| 1179 | |
| 1180 var angleStart = firstChild.angleStart.current() + rotationOffset; | |
| 1181 var lastChild = this.children[firstChild.hiddenEnd]; | |
| 1182 var angleEnd = lastChild.angleEnd.current() + rotationOffset; | |
| 1183 var radiusInner = gRadius * firstChild.radiusInner.current(); | |
| 1184 var hiddenChildren = firstChild.hiddenEnd - firstHiddenChild + 1; | |
| 1185 | |
| 1186 if (labelMode) { | |
| 1187 var hiddenSearchResults = 0; | |
| 1188 | |
| 1189 for (var i = firstHiddenChild; i <= firstChild.hiddenEnd; i++) { | |
| 1190 hiddenSearchResults += this.children[i].searchResults; | |
| 1191 | |
| 1192 if (this.children[i].magnitude == 0) { | |
| 1193 hiddenChildren--; | |
| 1194 } | |
| 1195 } | |
| 1196 | |
| 1197 if | |
| 1198 ( | |
| 1199 selected && | |
| 1200 (angleEnd - angleStart) * | |
| 1201 (gRadius + gRadius) >= | |
| 1202 minWidth() || | |
| 1203 this == highlightedNode && | |
| 1204 hiddenChildren || | |
| 1205 hiddenSearchResults | |
| 1206 ) { | |
| 1207 context.globalAlpha = this.alphaWedge.current(); | |
| 1208 | |
| 1209 this.drawHiddenLabel | |
| 1210 ( | |
| 1211 angleStart, | |
| 1212 angleEnd, | |
| 1213 hiddenChildren, | |
| 1214 hiddenSearchResults | |
| 1215 ); | |
| 1216 } | |
| 1217 } | |
| 1218 | |
| 1219 var drawWedges = true; | |
| 1220 | |
| 1221 for (var i = firstHiddenChild; i <= firstChild.hiddenEnd; i++) { | |
| 1222 // all hidden children must be completely hidden to draw together | |
| 1223 | |
| 1224 if (this.children[i].alphaPattern.current() | |
| 1225 != this.children[i].alphaWedge.current()) { | |
| 1226 drawWedges = false; | |
| 1227 break; | |
| 1228 } | |
| 1229 } | |
| 1230 | |
| 1231 if (labelMode) { | |
| 1232 if (drawWedges) { | |
| 1233 var drawRadial = (angleEnd | |
| 1234 < this.angleEnd.current() + rotationOffset); | |
| 1235 this.drawLines(angleStart, angleEnd, radiusInner, drawRadial); | |
| 1236 } | |
| 1237 | |
| 1238 if (hiddenSearchResults && !searchHighlighted) { | |
| 1239 drawWedge | |
| 1240 ( | |
| 1241 angleStart, | |
| 1242 angleEnd, | |
| 1243 radiusInner, | |
| 1244 gRadius,//this.radiusOuter.current() * gRadius, | |
| 1245 highlightFill, | |
| 1246 0, | |
| 1247 true | |
| 1248 ); | |
| 1249 } | |
| 1250 } | |
| 1251 else if (drawWedges) { | |
| 1252 context.globalAlpha = this.alphaWedge.current(); | |
| 1253 | |
| 1254 var fill = rgbText | |
| 1255 ( | |
| 1256 firstChild.r.current(), | |
| 1257 firstChild.g.current(), | |
| 1258 firstChild.b.current() | |
| 1259 ); | |
| 1260 | |
| 1261 drawWedge | |
| 1262 ( | |
| 1263 angleStart, | |
| 1264 angleEnd, | |
| 1265 radiusInner, | |
| 1266 gRadius,//this.radiusOuter.current() * gRadius, | |
| 1267 fill, | |
| 1268 context.globalAlpha, | |
| 1269 false | |
| 1270 ); | |
| 1271 } | |
| 1272 | |
| 1273 return drawWedges; | |
| 1274 } | |
| 1275 | |
| 1276 this.drawHiddenLabel = function (angleStart, angleEnd, value, | |
| 1277 hiddenSearchResults) { | |
| 1278 var textAngle = (angleStart + angleEnd) / 2; | |
| 1279 var labelRadius = gRadius + fontSize;//(radiusInner + radius) / 2; | |
| 1280 | |
| 1281 var hiddenLabel = Array(); | |
| 1282 | |
| 1283 hiddenLabel.value = value; | |
| 1284 hiddenLabel.angle = textAngle; | |
| 1285 hiddenLabel.search = hiddenSearchResults; | |
| 1286 | |
| 1287 this.hiddenLabels.push(hiddenLabel); | |
| 1288 | |
| 1289 drawTick(gRadius - fontSize * .75, fontSize * 1.5, textAngle); | |
| 1290 drawTextPolar | |
| 1291 ( | |
| 1292 value.toString() + ' more', | |
| 1293 0, // inner text | |
| 1294 textAngle, | |
| 1295 labelRadius, | |
| 1296 true, // radial | |
| 1297 hiddenSearchResults, // bubble | |
| 1298 this == highlightedNode || this == focusNode, // bold | |
| 1299 false, | |
| 1300 hiddenSearchResults | |
| 1301 ); | |
| 1302 } | |
| 1303 | |
| 1304 this.drawHighlight = function (bold) { | |
| 1305 var angleStartCurrent = this.angleStart.current() + rotationOffset; | |
| 1306 var angleEndCurrent = this.angleEnd.current() + rotationOffset; | |
| 1307 var radiusInner = this.radiusInner.current() * gRadius; | |
| 1308 | |
| 1309 //this.setHighlightStyle(); | |
| 1310 | |
| 1311 if (this == focusNode && this | |
| 1312 == highlightedNode && this.hasChildren()) { | |
| 1313 // context.fillStyle = "rgba(255, 255, 255, .3)"; | |
| 1314 arrow | |
| 1315 ( | |
| 1316 angleStartCurrent, | |
| 1317 angleEndCurrent, | |
| 1318 radiusInner | |
| 1319 ); | |
| 1320 } | |
| 1321 else { | |
| 1322 drawWedge | |
| 1323 ( | |
| 1324 angleStartCurrent, | |
| 1325 angleEndCurrent, | |
| 1326 radiusInner, | |
| 1327 gRadius, | |
| 1328 highlightFill, | |
| 1329 0, | |
| 1330 true | |
| 1331 ); | |
| 1332 } | |
| 1333 | |
| 1334 // check if hidden children should be highlighted | |
| 1335 // | |
| 1336 for (var i = 0; i < this.children.length; i++) { | |
| 1337 if | |
| 1338 ( | |
| 1339 this.children[i].getDepth() - selectedNode.getDepth() + 1 <= | |
| 1340 maxDisplayDepth && | |
| 1341 this.children[i].hiddenEnd != null | |
| 1342 ) { | |
| 1343 var firstChild = this.children[i]; | |
| 1344 var lastChild = this.children[firstChild.hiddenEnd]; | |
| 1345 var hiddenAngleStart = firstChild.angleStart.current() | |
| 1346 + rotationOffset; | |
| 1347 var hiddenAngleEnd = lastChild.angleEnd.current() | |
| 1348 + rotationOffset; | |
| 1349 var hiddenRadiusInner = gRadius | |
| 1350 * firstChild.radiusInner.current(); | |
| 1351 | |
| 1352 drawWedge | |
| 1353 ( | |
| 1354 hiddenAngleStart, | |
| 1355 hiddenAngleEnd, | |
| 1356 hiddenRadiusInner, | |
| 1357 gRadius, | |
| 1358 'rgba(255, 255, 255, .3)', | |
| 1359 0, | |
| 1360 true | |
| 1361 ); | |
| 1362 | |
| 1363 if (false && !this.searchResults) { | |
| 1364 this.drawHiddenLabel | |
| 1365 ( | |
| 1366 hiddenAngleStart, | |
| 1367 hiddenAngleEnd, | |
| 1368 firstChild.hiddenEnd - i + 1 | |
| 1369 ); | |
| 1370 } | |
| 1371 | |
| 1372 i = firstChild.hiddenEnd; | |
| 1373 } | |
| 1374 } | |
| 1375 | |
| 1376 // context.strokeStyle = 'black'; | |
| 1377 context.fillStyle = 'black'; | |
| 1378 | |
| 1379 var highlight = !(progress < 1 && zoomOut | |
| 1380 && this == selectedNodeLast); | |
| 1381 | |
| 1382 var angle = (angleEndCurrent + angleStartCurrent) / 2; | |
| 1383 | |
| 1384 if (!(this.keyed && showKeys)) { | |
| 1385 this.drawLabel(angle, true, bold, true, this.radial); | |
| 1386 } | |
| 1387 } | |
| 1388 | |
| 1389 this.drawHighlightCenter = function () { | |
| 1390 if (!this.canDisplayHistory()) { | |
| 1391 return; | |
| 1392 } | |
| 1393 | |
| 1394 context.lineWidth = highlightLineWidth; | |
| 1395 context.strokeStyle = 'black'; | |
| 1396 context.fillStyle = "rgba(255, 255, 255, .6)"; | |
| 1397 | |
| 1398 context.fillStyle = 'black'; | |
| 1399 this.drawLabel(3 * Math.PI / 2, true, true, false); | |
| 1400 context.font = fontNormal; | |
| 1401 } | |
| 1402 | |
| 1403 this.drawKey = function (angle, highlight, bold) { | |
| 1404 var offset = keyOffset(); | |
| 1405 var color; | |
| 1406 var colorText = this.magnitude == 0 ? 'gray' : 'black'; | |
| 1407 var patternAlpha = this.alphaPattern.end; | |
| 1408 var boxLeft = imageWidth - keySize - margin; | |
| 1409 var textY = offset + keySize / 2; | |
| 1410 | |
| 1411 var label; | |
| 1412 var keyNameWidth; | |
| 1413 | |
| 1414 if (this == selectedNode) { | |
| 1415 color = colorUnclassified; | |
| 1416 label = | |
| 1417 this.getUnclassifiedText() + | |
| 1418 ' ' + | |
| 1419 this.getUnclassifiedPercentage(); | |
| 1420 keyNameWidth = measureText(label, false); | |
| 1421 } | |
| 1422 else { | |
| 1423 label = this.keyLabel; | |
| 1424 color = rgbText(this.r.end, this.g.end, this.b.end); | |
| 1425 | |
| 1426 if (highlight) { | |
| 1427 if (this.searchResultChildren()) { | |
| 1428 label = label | |
| 1429 + searchResultString(this.searchResultChildren()); | |
| 1430 } | |
| 1431 | |
| 1432 keyNameWidth = measureText(label, bold); | |
| 1433 } | |
| 1434 else { | |
| 1435 keyNameWidth = this.keyNameWidth; | |
| 1436 } | |
| 1437 } | |
| 1438 | |
| 1439 var textLeft = boxLeft - keyBuffer - keyNameWidth - fontSize / 2; | |
| 1440 var labelLeft = textLeft; | |
| 1441 | |
| 1442 if (labelLeft > keyMinTextLeft - fontSize / 2) { | |
| 1443 keyMinTextLeft -= fontSize / 2; | |
| 1444 | |
| 1445 if (keyMinTextLeft < centerX - gRadius + fontSize / 2) { | |
| 1446 keyMinTextLeft = centerX - gRadius + fontSize / 2; | |
| 1447 } | |
| 1448 | |
| 1449 labelLeft = keyMinTextLeft; | |
| 1450 } | |
| 1451 | |
| 1452 var lineX = new Array(); | |
| 1453 var lineY = new Array(); | |
| 1454 | |
| 1455 var bendRadius; | |
| 1456 var keyAngle = Math.atan((textY - centerY) / (labelLeft - centerX)); | |
| 1457 var arcAngle; | |
| 1458 | |
| 1459 if (keyAngle < 0) { | |
| 1460 keyAngle += Math.PI; | |
| 1461 } | |
| 1462 | |
| 1463 if (keyMinAngle == 0 || angle < keyMinAngle) { | |
| 1464 keyMinAngle = angle; | |
| 1465 } | |
| 1466 | |
| 1467 if (angle > Math.PI && keyMinAngle > Math.PI) { | |
| 1468 // allow lines to come underneath the chart | |
| 1469 | |
| 1470 angle -= Math.PI * 2; | |
| 1471 } | |
| 1472 | |
| 1473 lineX.push(Math.cos(angle) * gRadius); | |
| 1474 lineY.push(Math.sin(angle) * gRadius); | |
| 1475 | |
| 1476 if (angle < keyAngle | |
| 1477 && textY > centerY | |
| 1478 + Math.sin(angle) * (gRadius + buffer * (currentKey - 1) | |
| 1479 / (keys + 1) / 2 + buffer / 2)) { | |
| 1480 bendRadius = gRadius + buffer - buffer * currentKey | |
| 1481 / (keys + 1) / 2; | |
| 1482 } | |
| 1483 else { | |
| 1484 bendRadius = gRadius + buffer * currentKey | |
| 1485 / (keys + 1) / 2 + buffer / 2; | |
| 1486 } | |
| 1487 | |
| 1488 var outside = | |
| 1489 Math.sqrt | |
| 1490 ( | |
| 1491 Math.pow(labelLeft - centerX, 2) + | |
| 1492 Math.pow(textY - centerY, 2) | |
| 1493 ) > bendRadius; | |
| 1494 | |
| 1495 if (!outside) { | |
| 1496 arcAngle = Math.asin((textY - centerY) / bendRadius); | |
| 1497 | |
| 1498 keyMinTextLeft = min(keyMinTextLeft, centerX | |
| 1499 + bendRadius * Math.cos(arcAngle) - fontSize / 2); | |
| 1500 | |
| 1501 if (labelLeft < textLeft && textLeft > centerX | |
| 1502 + bendRadius * Math.cos(arcAngle)) { | |
| 1503 lineX.push(textLeft - centerX); | |
| 1504 lineY.push(textY - centerY); | |
| 1505 } | |
| 1506 } | |
| 1507 else { | |
| 1508 keyMinTextLeft = min(keyMinTextLeft, labelLeft - fontSize / 2); | |
| 1509 | |
| 1510 if (angle < keyAngle) { | |
| 1511 // flip everything over y = x | |
| 1512 // | |
| 1513 arcAngle = Math.PI / 2 - keyLineAngle | |
| 1514 ( | |
| 1515 Math.PI / 2 - angle, | |
| 1516 Math.PI / 2 - keyAngle, | |
| 1517 bendRadius, | |
| 1518 textY - centerY, | |
| 1519 labelLeft - centerX, | |
| 1520 lineY, | |
| 1521 lineX | |
| 1522 ); | |
| 1523 | |
| 1524 } | |
| 1525 else { | |
| 1526 arcAngle = keyLineAngle | |
| 1527 ( | |
| 1528 angle, | |
| 1529 keyAngle, | |
| 1530 bendRadius, | |
| 1531 labelLeft - centerX, | |
| 1532 textY - centerY, | |
| 1533 lineX, | |
| 1534 lineY | |
| 1535 ); | |
| 1536 } | |
| 1537 } | |
| 1538 | |
| 1539 if (labelLeft > centerX + bendRadius * Math.cos(arcAngle) || | |
| 1540 textY > centerY + bendRadius * Math.sin(arcAngle) + .01) | |
| 1541 // if ( outside || ) | |
| 1542 { | |
| 1543 lineX.push(labelLeft - centerX); | |
| 1544 lineY.push(textY - centerY); | |
| 1545 | |
| 1546 if (textLeft != labelLeft) { | |
| 1547 lineX.push(textLeft - centerX); | |
| 1548 lineY.push(textY - centerY); | |
| 1549 } | |
| 1550 } | |
| 1551 | |
| 1552 context.globalAlpha = this.alphaWedge.current(); | |
| 1553 | |
| 1554 if (snapshotMode) { | |
| 1555 var labelSVG; | |
| 1556 | |
| 1557 if (this == selectedNode) { | |
| 1558 labelSVG = | |
| 1559 this.getUnclassifiedText() + | |
| 1560 spacer() + | |
| 1561 this.getUnclassifiedPercentage(); | |
| 1562 } | |
| 1563 else { | |
| 1564 labelSVG = this.name + spacer() + this.getPercentage() + '%'; | |
| 1565 } | |
| 1566 | |
| 1567 svg += | |
| 1568 '<rect fill="' + color + '" ' + | |
| 1569 'x="' + boxLeft + '" y="' + offset + | |
| 1570 '" width="' + keySize + '" height="' + keySize + '"/>'; | |
| 1571 | |
| 1572 if (patternAlpha) { | |
| 1573 svg += | |
| 1574 '<rect fill="url(#hiddenPattern)" style="stroke:none" ' + | |
| 1575 'x="' + boxLeft + '" y="' + offset + | |
| 1576 '" width="' + keySize + '" height="' + keySize + '"/>'; | |
| 1577 } | |
| 1578 | |
| 1579 svg += | |
| 1580 '<path class="line' + | |
| 1581 (highlight ? ' highlight' : '') + | |
| 1582 '" d="M ' + (lineX[0] + centerX) + ',' + | |
| 1583 (lineY[0] + centerY); | |
| 1584 | |
| 1585 if (angle != arcAngle) { | |
| 1586 svg += | |
| 1587 ' L ' + (centerX + bendRadius * Math.cos(angle)) + ',' + | |
| 1588 (centerY + bendRadius * Math.sin(angle)) + | |
| 1589 ' A ' + bendRadius + ',' + bendRadius + ' 0 ' + | |
| 1590 '0,' + (angle > arcAngle ? '0' : '1') + ' ' + | |
| 1591 (centerX + bendRadius * Math.cos(arcAngle)) + ',' + | |
| 1592 (centerY + bendRadius * Math.sin(arcAngle)); | |
| 1593 } | |
| 1594 | |
| 1595 for (var i = 1; i < lineX.length; i++) { | |
| 1596 svg += | |
| 1597 ' L ' + (centerX + lineX[i]) + ',' + | |
| 1598 (centerY + lineY[i]); | |
| 1599 } | |
| 1600 | |
| 1601 svg += '"/>'; | |
| 1602 | |
| 1603 if (highlight) { | |
| 1604 if (this.searchResultChildren()) { | |
| 1605 labelSVG = labelSVG | |
| 1606 + searchResultString(this.searchResultChildren()); | |
| 1607 } | |
| 1608 | |
| 1609 drawBubbleSVG | |
| 1610 ( | |
| 1611 boxLeft - keyBuffer - keyNameWidth - fontSize / 2, | |
| 1612 textY - fontSize, | |
| 1613 keyNameWidth + fontSize, | |
| 1614 fontSize * 2, | |
| 1615 fontSize, | |
| 1616 0 | |
| 1617 ); | |
| 1618 | |
| 1619 if (this.isSearchResult) { | |
| 1620 drawSearchHighlights | |
| 1621 ( | |
| 1622 label, | |
| 1623 boxLeft - keyBuffer - keyNameWidth, | |
| 1624 textY, | |
| 1625 0 | |
| 1626 ) | |
| 1627 } | |
| 1628 } | |
| 1629 | |
| 1630 svg += svgText(labelSVG, boxLeft - keyBuffer, textY, 'end', bold, | |
| 1631 colorText); | |
| 1632 } | |
| 1633 else { | |
| 1634 context.fillStyle = color; | |
| 1635 context.translate(-centerX, -centerY); | |
| 1636 context.strokeStyle = 'black'; | |
| 1637 context.globalAlpha = 1;//this.alphaWedge.current(); | |
| 1638 | |
| 1639 context.fillRect(boxLeft, offset, keySize, keySize); | |
| 1640 | |
| 1641 if (patternAlpha) { | |
| 1642 context.globalAlpha = patternAlpha; | |
| 1643 context.fillStyle = hiddenPattern; | |
| 1644 | |
| 1645 // make clipping box for Firefox performance | |
| 1646 context.beginPath(); | |
| 1647 context.moveTo(boxLeft, offset); | |
| 1648 context.lineTo(boxLeft + keySize, offset); | |
| 1649 context.lineTo(boxLeft + keySize, offset + keySize); | |
| 1650 context.lineTo(boxLeft, offset + keySize); | |
| 1651 context.closePath(); | |
| 1652 context.save(); | |
| 1653 context.clip(); | |
| 1654 | |
| 1655 context.fillRect(boxLeft, offset, keySize, keySize); | |
| 1656 context.fillRect(boxLeft, offset, keySize, keySize); | |
| 1657 | |
| 1658 context.restore(); // remove clipping region | |
| 1659 } | |
| 1660 | |
| 1661 if (highlight) { | |
| 1662 this.setHighlightStyle(); | |
| 1663 context.fillRect(boxLeft, offset, keySize, keySize); | |
| 1664 } | |
| 1665 else { | |
| 1666 context.lineWidth = thinLineWidth; | |
| 1667 } | |
| 1668 | |
| 1669 context.strokeRect(boxLeft, offset, keySize, keySize); | |
| 1670 | |
| 1671 if (lineX.length) { | |
| 1672 context.beginPath(); | |
| 1673 context.moveTo(lineX[0] + centerX, lineY[0] + centerY); | |
| 1674 | |
| 1675 context.arc(centerX, centerY, bendRadius, angle, arcAngle, | |
| 1676 angle > arcAngle); | |
| 1677 | |
| 1678 for (var i = 1; i < lineX.length; i++) { | |
| 1679 context.lineTo(lineX[i] + centerX, lineY[i] + centerY); | |
| 1680 } | |
| 1681 | |
| 1682 context.globalAlpha = this == selectedNode ? | |
| 1683 this.children[0].alphaWedge.current() : | |
| 1684 this.alphaWedge.current(); | |
| 1685 context.lineWidth = highlight | |
| 1686 ? highlightLineWidth : thinLineWidth; | |
| 1687 context.stroke(); | |
| 1688 context.globalAlpha = 1; | |
| 1689 } | |
| 1690 | |
| 1691 if (highlight) { | |
| 1692 drawBubbleCanvas | |
| 1693 ( | |
| 1694 boxLeft - keyBuffer - keyNameWidth - fontSize / 2, | |
| 1695 textY - fontSize, | |
| 1696 keyNameWidth + fontSize, | |
| 1697 fontSize * 2, | |
| 1698 fontSize, | |
| 1699 0 | |
| 1700 ); | |
| 1701 | |
| 1702 if (this.isSearchResult) { | |
| 1703 drawSearchHighlights | |
| 1704 ( | |
| 1705 label, | |
| 1706 boxLeft - keyBuffer - keyNameWidth, | |
| 1707 textY, | |
| 1708 0 | |
| 1709 ) | |
| 1710 } | |
| 1711 } | |
| 1712 | |
| 1713 drawText(label, boxLeft - keyBuffer, offset + keySize / 2, 0, | |
| 1714 'end', bold, colorText); | |
| 1715 | |
| 1716 context.translate(centerX, centerY); | |
| 1717 } | |
| 1718 | |
| 1719 currentKey++; | |
| 1720 } | |
| 1721 | |
| 1722 this.drawLabel = function (angle, bubble, bold, selected, radial) { | |
| 1723 if (context.globalAlpha == 0) { | |
| 1724 return; | |
| 1725 } | |
| 1726 | |
| 1727 var innerText; | |
| 1728 var label; | |
| 1729 var radius; | |
| 1730 | |
| 1731 if (radial) { | |
| 1732 radius = (this.radiusInner.current() + 1) * gRadius / 2; | |
| 1733 } | |
| 1734 else { | |
| 1735 radius = this.labelRadius.current() * gRadius; | |
| 1736 } | |
| 1737 | |
| 1738 if (radial && (selected || bubble)) { | |
| 1739 var percentage = this.getPercentage(); | |
| 1740 innerText = percentage + '%'; | |
| 1741 } | |
| 1742 | |
| 1743 if | |
| 1744 ( | |
| 1745 !radial && | |
| 1746 this != selectedNode && | |
| 1747 !bubble && | |
| 1748 (!zoomOut || this != selectedNodeLast) | |
| 1749 ) { | |
| 1750 label = this.shortenLabel(); | |
| 1751 } | |
| 1752 else { | |
| 1753 label = this.name; | |
| 1754 } | |
| 1755 | |
| 1756 var flipped = drawTextPolar | |
| 1757 ( | |
| 1758 label, | |
| 1759 innerText, | |
| 1760 angle, | |
| 1761 radius, | |
| 1762 radial, | |
| 1763 bubble, | |
| 1764 bold, | |
| 1765 // this.isSearchResult && this.shouldAddSearchResultsString() && (!selected || this == selectedNode || highlight), | |
| 1766 this.isSearchResult | |
| 1767 && (!selected || this == selectedNode || bubble), | |
| 1768 (this.hideAlone || !selected || this == selectedNode) | |
| 1769 ? this.searchResultChildren() : 0 | |
| 1770 ); | |
| 1771 | |
| 1772 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 1773 | |
| 1774 if | |
| 1775 ( | |
| 1776 !radial && | |
| 1777 !bubble && | |
| 1778 this != selectedNode && | |
| 1779 this.angleEnd.end != this.angleStart.end && | |
| 1780 nLabelOffsets[depth - 2] > 2 && | |
| 1781 this.labelWidth.current() | |
| 1782 > (this.angleEnd.end - this.angleStart.end) * Math.abs(radius) && | |
| 1783 !(zoomOut && this == selectedNodeLast) && | |
| 1784 this.labelRadius.end > 0 | |
| 1785 ) { | |
| 1786 // name extends beyond wedge; draw tick mark towards the central | |
| 1787 // radius for easier identification | |
| 1788 | |
| 1789 var radiusCenter = compress ? | |
| 1790 (compressedRadii[depth - 1] + compressedRadii[depth - 2]) / 2 : | |
| 1791 (depth - .5) * nodeRadius; | |
| 1792 | |
| 1793 if (this.labelRadius.end > radiusCenter) { | |
| 1794 if (flipped) { | |
| 1795 drawTick(radius - tickLength * 1.4, tickLength, angle); | |
| 1796 } | |
| 1797 else { | |
| 1798 drawTick(radius - tickLength * 1.7, tickLength, angle); | |
| 1799 } | |
| 1800 } | |
| 1801 else { | |
| 1802 if (flipped) { | |
| 1803 drawTick(radius + tickLength * .7, tickLength, angle); | |
| 1804 } | |
| 1805 else { | |
| 1806 drawTick(radius + tickLength * .4, tickLength, angle); | |
| 1807 } | |
| 1808 } | |
| 1809 } | |
| 1810 } | |
| 1811 | |
| 1812 this.drawLines = function (angleStart, angleEnd, radiusInner, drawRadial, | |
| 1813 selected) { | |
| 1814 if (snapshotMode) { | |
| 1815 if (this != selectedNode) { | |
| 1816 if (angleEnd == angleStart + Math.PI * 2) { | |
| 1817 // fudge to prevent overlap, which causes arc ambiguity | |
| 1818 // | |
| 1819 angleEnd -= .1 / gRadius; | |
| 1820 } | |
| 1821 | |
| 1822 var longArc = angleEnd - angleStart > Math.PI ? 1 : 0; | |
| 1823 | |
| 1824 var x1 = centerX + radiusInner * Math.cos(angleStart); | |
| 1825 var y1 = centerY + radiusInner * Math.sin(angleStart); | |
| 1826 | |
| 1827 var x2 = centerX + gRadius * Math.cos(angleStart); | |
| 1828 var y2 = centerY + gRadius * Math.sin(angleStart); | |
| 1829 | |
| 1830 var x3 = centerX + gRadius * Math.cos(angleEnd); | |
| 1831 var y3 = centerY + gRadius * Math.sin(angleEnd); | |
| 1832 | |
| 1833 var x4 = centerX + radiusInner * Math.cos(angleEnd); | |
| 1834 var y4 = centerY + radiusInner * Math.sin(angleEnd); | |
| 1835 | |
| 1836 if (this.alphaArc.end) { | |
| 1837 var dArray = | |
| 1838 [ | |
| 1839 " M ", x4, ",", y4, | |
| 1840 " A ", radiusInner, ",", radiusInner, " 0 ", | |
| 1841 longArc, | |
| 1842 " 0 ", x1, ",", y1 | |
| 1843 ]; | |
| 1844 | |
| 1845 svg += '<path class="line" d="' + dArray.join('') + '"/>'; | |
| 1846 } | |
| 1847 | |
| 1848 if (drawRadial && this.alphaLine.end) { | |
| 1849 svg += '<line x1="' + x3 + '" y1="' + y3 + '" x2="' + x4 | |
| 1850 + '" y2="' + y4 + '"/>'; | |
| 1851 } | |
| 1852 } | |
| 1853 } | |
| 1854 else { | |
| 1855 context.lineWidth = thinLineWidth; | |
| 1856 context.strokeStyle = 'black'; | |
| 1857 context.beginPath(); | |
| 1858 context.arc(0, 0, radiusInner, angleStart, angleEnd, false); | |
| 1859 context.globalAlpha = this.alphaArc.current(); | |
| 1860 context.stroke(); | |
| 1861 | |
| 1862 if (drawRadial) { | |
| 1863 var x1 = radiusInner * Math.cos(angleEnd); | |
| 1864 var y1 = radiusInner * Math.sin(angleEnd); | |
| 1865 var x2 = gRadius * Math.cos(angleEnd); | |
| 1866 var y2 = gRadius * Math.sin(angleEnd); | |
| 1867 | |
| 1868 context.beginPath(); | |
| 1869 context.moveTo(x1, y1); | |
| 1870 context.lineTo(x2, y2); | |
| 1871 | |
| 1872 // if ( this.getCollapse() )//( selected && this != selectedNode ) | |
| 1873 { | |
| 1874 context.globalAlpha = this.alphaLine.current(); | |
| 1875 } | |
| 1876 | |
| 1877 context.stroke(); | |
| 1878 } | |
| 1879 } | |
| 1880 } | |
| 1881 | |
| 1882 this.drawMap = function (child) { | |
| 1883 if (this.parent) { | |
| 1884 this.parent.drawMap(child); | |
| 1885 } | |
| 1886 | |
| 1887 if (this.getCollapse() && this != child || this == focusNode) { | |
| 1888 return; | |
| 1889 } | |
| 1890 | |
| 1891 var angleStart = | |
| 1892 (child.baseMagnitude - this.baseMagnitude) / this.magnitude | |
| 1893 * Math.PI * 2 + rotationOffset; | |
| 1894 var angleEnd = | |
| 1895 (child.baseMagnitude - this.baseMagnitude + child.magnitude) / | |
| 1896 this.magnitude * Math.PI * 2 + | |
| 1897 rotationOffset; | |
| 1898 | |
| 1899 var box = this.getMapPosition(); | |
| 1900 | |
| 1901 context.save(); | |
| 1902 context.fillStyle = 'black'; | |
| 1903 context.textAlign = 'end'; | |
| 1904 context.textBaseline = 'middle'; | |
| 1905 | |
| 1906 var textX = box.x - mapRadius - mapBuffer; | |
| 1907 var percentage = getPercentage(child.magnitude / this.magnitude); | |
| 1908 | |
| 1909 var highlight = this == selectedNode || this == highlightedNode; | |
| 1910 | |
| 1911 if (highlight) { | |
| 1912 context.font = fontBold; | |
| 1913 } | |
| 1914 else { | |
| 1915 context.font = fontNormal; | |
| 1916 } | |
| 1917 | |
| 1918 context.fillText(percentage + '% of', textX, box.y - mapRadius / 3); | |
| 1919 context.fillText(this.name, textX, box.y + mapRadius / 3); | |
| 1920 | |
| 1921 if (highlight) { | |
| 1922 context.font = fontNormal; | |
| 1923 } | |
| 1924 | |
| 1925 if (this == highlightedNode && this != selectedNode) { | |
| 1926 context.fillStyle = 'rgb(245, 245, 245)'; | |
| 1927 // context.fillStyle = 'rgb(200, 200, 200)'; | |
| 1928 } | |
| 1929 else { | |
| 1930 context.fillStyle = 'rgb(255, 255, 255)'; | |
| 1931 } | |
| 1932 | |
| 1933 context.beginPath(); | |
| 1934 context.arc(box.x, box.y, mapRadius, 0, Math.PI * 2, true); | |
| 1935 context.closePath(); | |
| 1936 context.fill(); | |
| 1937 | |
| 1938 if (this == selectedNode) { | |
| 1939 context.lineWidth = 1; | |
| 1940 context.fillStyle = 'rgb(100, 100, 100)'; | |
| 1941 } | |
| 1942 else { | |
| 1943 if (this == highlightedNode) { | |
| 1944 context.lineWidth = .2; | |
| 1945 context.fillStyle = 'rgb(190, 190, 190)'; | |
| 1946 } | |
| 1947 else { | |
| 1948 context.lineWidth = .2; | |
| 1949 context.fillStyle = 'rgb(200, 200, 200)'; | |
| 1950 } | |
| 1951 } | |
| 1952 | |
| 1953 var maxDepth = this.getMaxDepth(); | |
| 1954 | |
| 1955 if (!compress && maxDepth > maxPossibleDepth + this.getDepth() - 1) { | |
| 1956 maxDepth = maxPossibleDepth + this.getDepth() - 1; | |
| 1957 } | |
| 1958 | |
| 1959 if (this.getDepth() < selectedNode.getDepth()) { | |
| 1960 if (child.getDepth() - 1 >= maxDepth) { | |
| 1961 maxDepth = child.getDepth(); | |
| 1962 } | |
| 1963 } | |
| 1964 | |
| 1965 var radiusInner; | |
| 1966 | |
| 1967 if (compress) { | |
| 1968 radiusInner = 0; | |
| 1969 // Math.atan(child.getDepth() - this.getDepth()) / | |
| 1970 // Math.PI * 2 * .9; | |
| 1971 } | |
| 1972 else { | |
| 1973 radiusInner = | |
| 1974 (child.getDepth() - this.getDepth()) / | |
| 1975 (maxDepth - this.getDepth() + 1); | |
| 1976 } | |
| 1977 | |
| 1978 context.stroke(); | |
| 1979 context.beginPath(); | |
| 1980 | |
| 1981 if (radiusInner == 0) { | |
| 1982 context.moveTo(box.x, box.y); | |
| 1983 } | |
| 1984 else { | |
| 1985 context.arc(box.x, box.y, mapRadius * radiusInner, angleEnd, | |
| 1986 angleStart, true); | |
| 1987 } | |
| 1988 | |
| 1989 context.arc(box.x, box.y, mapRadius, angleStart, angleEnd, false); | |
| 1990 context.closePath(); | |
| 1991 context.fill(); | |
| 1992 | |
| 1993 if (this == highlightedNode && this != selectedNode) { | |
| 1994 context.lineWidth = 1; | |
| 1995 context.stroke(); | |
| 1996 } | |
| 1997 | |
| 1998 context.restore(); | |
| 1999 } | |
| 2000 | |
| 2001 this.drawReferenceRings = function (childRadiusInner) { | |
| 2002 if (snapshotMode) { | |
| 2003 svg += | |
| 2004 '<circle cx="' + centerX + '" cy="' + centerY + | |
| 2005 '" r="' + childRadiusInner + '"/>'; | |
| 2006 svg += | |
| 2007 '<circle cx="' + centerX + '" cy="' + centerY + | |
| 2008 '" r="' + gRadius + '"/>'; | |
| 2009 } | |
| 2010 else { | |
| 2011 context.globalAlpha = 1 - this.alphaLine.current();//this.getUncollapsed().alphaLine.current(); | |
| 2012 context.beginPath(); | |
| 2013 context.arc(0, 0, childRadiusInner, 0, Math.PI * 2, false); | |
| 2014 context.stroke(); | |
| 2015 context.beginPath(); | |
| 2016 context.arc(0, 0, gRadius, 0, Math.PI * 2, false); | |
| 2017 context.stroke(); | |
| 2018 } | |
| 2019 } | |
| 2020 | |
| 2021 this.getCollapse = function () { | |
| 2022 return ( | |
| 2023 collapse && | |
| 2024 this.collapse && | |
| 2025 this.depth != maxAbsoluteDepth | |
| 2026 ); | |
| 2027 } | |
| 2028 | |
| 2029 this.getDepth = function () { | |
| 2030 if (collapse) { | |
| 2031 return this.depthCollapsed; | |
| 2032 } | |
| 2033 else { | |
| 2034 return this.depth; | |
| 2035 } | |
| 2036 }; | |
| 2037 | |
| 2038 this.getHue = function () { | |
| 2039 return this.hues[currentDataset]; | |
| 2040 }; | |
| 2041 | |
| 2042 this.getMagnitude = function () { | |
| 2043 return this.attributes[magnitudeIndex][currentDataset]; | |
| 2044 }; | |
| 2045 | |
| 2046 this.getMapPosition = function () { | |
| 2047 return { | |
| 2048 x: (details.offsetLeft + details.clientWidth - mapRadius), | |
| 2049 y: ((focusNode.getDepth() - this.getDepth()) * | |
| 2050 (mapBuffer + mapRadius * 2) - mapRadius) + | |
| 2051 details.clientHeight + details.offsetTop | |
| 2052 }; | |
| 2053 } | |
| 2054 | |
| 2055 this.getMaxDepth = function (limit) { | |
| 2056 var max; | |
| 2057 | |
| 2058 if (collapse) { | |
| 2059 return this.maxDepthCollapsed; | |
| 2060 } | |
| 2061 else { | |
| 2062 if (this.maxDepth > maxAbsoluteDepth) { | |
| 2063 return maxAbsoluteDepth; | |
| 2064 } | |
| 2065 else { | |
| 2066 return this.maxDepth; | |
| 2067 } | |
| 2068 } | |
| 2069 } | |
| 2070 | |
| 2071 this.getData = function (index, summary) { | |
| 2072 var files = new Array(); | |
| 2073 | |
| 2074 if | |
| 2075 ( | |
| 2076 this.attributes[index] != null && | |
| 2077 this.attributes[index][currentDataset] != null && | |
| 2078 this.attributes[index][currentDataset] != '' | |
| 2079 ) { | |
| 2080 files.push | |
| 2081 ( | |
| 2082 document.location + | |
| 2083 '.files/' + | |
| 2084 this.attributes[index][currentDataset] | |
| 2085 ); | |
| 2086 } | |
| 2087 | |
| 2088 if (summary) { | |
| 2089 for (var i = 0; i < this.children.length; i++) { | |
| 2090 files = files.concat(this.children[i].getData(index, true)); | |
| 2091 } | |
| 2092 } | |
| 2093 | |
| 2094 return files; | |
| 2095 } | |
| 2096 | |
| 2097 this.getList = function (index, summary) { | |
| 2098 var list; | |
| 2099 | |
| 2100 if | |
| 2101 ( | |
| 2102 this.attributes[index] != null && | |
| 2103 this.attributes[index][currentDataset] != null | |
| 2104 ) { | |
| 2105 list = this.attributes[index][currentDataset]; | |
| 2106 } | |
| 2107 else { | |
| 2108 list = new Array(); | |
| 2109 } | |
| 2110 | |
| 2111 if (summary) { | |
| 2112 for (var i = 0; i < this.children.length; i++) { | |
| 2113 list = list.concat(this.children[i].getList(index, true)); | |
| 2114 } | |
| 2115 } | |
| 2116 | |
| 2117 return list; | |
| 2118 } | |
| 2119 | |
| 2120 this.getParent = function () { | |
| 2121 // returns parent, accounting for collapsing or 0 if doesn't exist | |
| 2122 | |
| 2123 var parent = this.parent; | |
| 2124 | |
| 2125 while (parent != 0 && parent.getCollapse()) { | |
| 2126 parent = parent.parent; | |
| 2127 } | |
| 2128 | |
| 2129 return parent; | |
| 2130 } | |
| 2131 | |
| 2132 this.getPercentage = function () { | |
| 2133 return getPercentage(this.magnitude / selectedNode.magnitude); | |
| 2134 } | |
| 2135 | |
| 2136 this.getUnclassifiedPercentage = function () { | |
| 2137 if (this.children.length) { | |
| 2138 var lastChild = this.children[this.children.length - 1]; | |
| 2139 | |
| 2140 return getPercentage | |
| 2141 ( | |
| 2142 ( | |
| 2143 this.baseMagnitude + | |
| 2144 this.magnitude - | |
| 2145 lastChild.magnitude - | |
| 2146 lastChild.baseMagnitude | |
| 2147 ) / this.magnitude | |
| 2148 ) + '%'; | |
| 2149 } | |
| 2150 else { | |
| 2151 return '100%'; | |
| 2152 } | |
| 2153 } | |
| 2154 | |
| 2155 this.getUnclassifiedText = function () { | |
| 2156 return '[other ' + this.name + ']'; | |
| 2157 } | |
| 2158 | |
| 2159 this.getUncollapsed = function () { | |
| 2160 // recurse through collapsed children until uncollapsed node is found | |
| 2161 | |
| 2162 if (this.getCollapse()) { | |
| 2163 return this.children[0].getUncollapsed(); | |
| 2164 } | |
| 2165 else { | |
| 2166 return this; | |
| 2167 } | |
| 2168 }; | |
| 2169 | |
| 2170 this.hasChildren = function () { | |
| 2171 return this.depth < maxAbsoluteDepth && this.magnitude | |
| 2172 && this.children.length; | |
| 2173 }; | |
| 2174 | |
| 2175 this.hasParent = function (parent) { | |
| 2176 if (this.parent) { | |
| 2177 if (this.parent === parent) { | |
| 2178 return true; | |
| 2179 } | |
| 2180 else { | |
| 2181 return this.parent.hasParent(parent); | |
| 2182 } | |
| 2183 } | |
| 2184 else { | |
| 2185 return false; | |
| 2186 } | |
| 2187 }; | |
| 2188 | |
| 2189 this.isLeaf = function (_recursing) { | |
| 2190 // Returns true/1 for a real leave, false/0 otherwise, counting the | |
| 2191 // non-empty leaves downstream and checking for positive counts. | |
| 2192 // Param _recursing is an internal auxiliar variable not to be used | |
| 2193 var leaves = 0; | |
| 2194 if (this.children.length) { // Node has children -> recurse | |
| 2195 for (var i = 0; i < this.children.length; i++) { | |
| 2196 leaves += this.children[i].isLeaf(true); | |
| 2197 } | |
| 2198 if (_recursing) { | |
| 2199 return leaves ? leaves : +!!this.magnitude; | |
| 2200 // If this has no leaves but has magnitude, this is a leaf. | |
| 2201 // NOTE: +!!num is 0 for num=0 and is 1 otherwise | |
| 2202 } else { | |
| 2203 return !!this.magnitude && !leaves; | |
| 2204 } | |
| 2205 } else { // Node has not children | |
| 2206 if (!this.magnitude) { | |
| 2207 return 0; // Fake leaf (empty) | |
| 2208 } else { | |
| 2209 return 1; // This is true leaf | |
| 2210 } | |
| 2211 } | |
| 2212 }; | |
| 2213 | |
| 2214 this.maxVisibleDepth = function (maxDepth) { | |
| 2215 var childInnerRadius; | |
| 2216 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 2217 var currentMaxDepth = depth; | |
| 2218 | |
| 2219 if (this.hasChildren() && depth < maxDepth) { | |
| 2220 var lastChild = this.children[this.children.length - 1]; | |
| 2221 | |
| 2222 if (lastChild.baseMagnitude + lastChild.magnitude < | |
| 2223 this.baseMagnitude + this.magnitude) { | |
| 2224 currentMaxDepth++; | |
| 2225 } | |
| 2226 | |
| 2227 if (compress) { | |
| 2228 childInnerRadius = compressedRadii[depth - 1]; | |
| 2229 } | |
| 2230 else { | |
| 2231 childInnerRadius = (depth) / maxDepth; | |
| 2232 } | |
| 2233 | |
| 2234 for (var i = 0; i < this.children.length; i++) { | |
| 2235 if | |
| 2236 (//true || | |
| 2237 this.children[i].magnitude * | |
| 2238 angleFactor * | |
| 2239 (childInnerRadius + 1) * | |
| 2240 gRadius >= | |
| 2241 minWidth() | |
| 2242 ) { | |
| 2243 var childMaxDepth | |
| 2244 = this.children[i].maxVisibleDepth(maxDepth); | |
| 2245 | |
| 2246 if (childMaxDepth > currentMaxDepth) { | |
| 2247 currentMaxDepth = childMaxDepth; | |
| 2248 } | |
| 2249 } | |
| 2250 } | |
| 2251 } | |
| 2252 | |
| 2253 return currentMaxDepth; | |
| 2254 } | |
| 2255 | |
| 2256 this.resetLabelWidth = function () { | |
| 2257 var nameWidthOld = this.nameWidth; | |
| 2258 | |
| 2259 if (true || !this.radial)//&& fontSize != fontSizeLast ) | |
| 2260 { | |
| 2261 var dim = context.measureText(this.name); | |
| 2262 this.nameWidth = dim.width; | |
| 2263 } | |
| 2264 | |
| 2265 if (fontSize != fontSizeLast | |
| 2266 && this.labelWidth.end == nameWidthOld * labelWidthFudge) { | |
| 2267 // font size changed; adjust start of tween to match | |
| 2268 | |
| 2269 this.labelWidth.start = this.nameWidth * labelWidthFudge; | |
| 2270 } | |
| 2271 else { | |
| 2272 this.labelWidth.start = this.labelWidth.current(); | |
| 2273 } | |
| 2274 | |
| 2275 this.labelWidth.end = this.nameWidth * labelWidthFudge; | |
| 2276 } | |
| 2277 | |
| 2278 this.restrictLabelWidth = function (width) { | |
| 2279 if (width < this.labelWidth.end) { | |
| 2280 this.labelWidth.end = width; | |
| 2281 } | |
| 2282 } | |
| 2283 | |
| 2284 this.search = function () { | |
| 2285 this.isSearchResult = false; | |
| 2286 this.searchResults = 0; | |
| 2287 | |
| 2288 if | |
| 2289 ( | |
| 2290 !this.getCollapse() && | |
| 2291 search.value !== '' && | |
| 2292 this.name.toLowerCase().indexOf(search.value.toLowerCase()) !== -1 | |
| 2293 ) { | |
| 2294 this.isSearchResult = true; | |
| 2295 this.searchResults = 1; | |
| 2296 nSearchResults++; | |
| 2297 } | |
| 2298 | |
| 2299 for (var i = 0; i < this.children.length; i++) { | |
| 2300 this.searchResults += this.children[i].search(); | |
| 2301 } | |
| 2302 | |
| 2303 return this.searchResults; | |
| 2304 } | |
| 2305 | |
| 2306 this.searchResultChildren = function () { | |
| 2307 if (this.isSearchResult) { | |
| 2308 return this.searchResults - 1; | |
| 2309 } | |
| 2310 else { | |
| 2311 return this.searchResults; | |
| 2312 } | |
| 2313 } | |
| 2314 | |
| 2315 this.setDepth = function (depth, depthCollapsed) { | |
| 2316 this.depth = depth; | |
| 2317 this.depthCollapsed = depthCollapsed; | |
| 2318 | |
| 2319 if | |
| 2320 ( | |
| 2321 this.children.length === 1 && | |
| 2322 // this.magnitude > 0 && | |
| 2323 this.children[0].magnitude === this.magnitude && | |
| 2324 (head.children.length > 1 || this.children[0].children.length) | |
| 2325 ) { | |
| 2326 this.collapse = true; | |
| 2327 } | |
| 2328 else { | |
| 2329 this.collapse = false; | |
| 2330 depthCollapsed++; | |
| 2331 } | |
| 2332 | |
| 2333 for (var i = 0; i < this.children.length; i++) { | |
| 2334 this.children[i].setDepth(depth + 1, depthCollapsed); | |
| 2335 } | |
| 2336 } | |
| 2337 | |
| 2338 this.setHighlightStyle = function () { | |
| 2339 context.lineWidth = highlightLineWidth; | |
| 2340 | |
| 2341 if (this.hasChildren() || this !== focusNode | |
| 2342 || this !== highlightedNode) { | |
| 2343 context.strokeStyle = 'black'; | |
| 2344 context.fillStyle = "rgba(255, 255, 255, .3)"; | |
| 2345 } | |
| 2346 else { | |
| 2347 context.strokeStyle = 'rgb(90,90,90)'; | |
| 2348 context.fillStyle = "rgba(155, 155, 155, .3)"; | |
| 2349 } | |
| 2350 } | |
| 2351 | |
| 2352 this.setLabelWidth = function (node) { | |
| 2353 if (!shorten || this.radial) { | |
| 2354 return; // don't need to set width | |
| 2355 } | |
| 2356 | |
| 2357 if (node.hide) { | |
| 2358 alert('wtf'); | |
| 2359 return; | |
| 2360 } | |
| 2361 | |
| 2362 var angle = (this.angleStart.end + this.angleEnd.end) / 2; | |
| 2363 var a; // angle difference | |
| 2364 | |
| 2365 if (node == selectedNode) { | |
| 2366 a = Math.abs(angle - node.angleOther); | |
| 2367 } | |
| 2368 else { | |
| 2369 a = Math.abs(angle | |
| 2370 - (node.angleStart.end + node.angleEnd.end) / 2); | |
| 2371 } | |
| 2372 | |
| 2373 if (a == 0) { | |
| 2374 return; | |
| 2375 } | |
| 2376 | |
| 2377 if (a > Math.PI) { | |
| 2378 a = 2 * Math.PI - a; | |
| 2379 } | |
| 2380 | |
| 2381 if (node.radial || node == selectedNode) { | |
| 2382 var nodeLabelRadius; | |
| 2383 | |
| 2384 if (node == selectedNode) { | |
| 2385 // radial 'other' label | |
| 2386 | |
| 2387 nodeLabelRadius = (node.children[0].radiusInner.end + 1) / 2; | |
| 2388 } | |
| 2389 else { | |
| 2390 nodeLabelRadius = (node.radiusInner.end + 1) / 2; | |
| 2391 } | |
| 2392 | |
| 2393 if (a < Math.PI / 2) { | |
| 2394 var r = this.labelRadius.end * gRadius + .5 * fontSize | |
| 2395 var hypotenuse = r / Math.cos(a); | |
| 2396 var opposite = r * Math.tan(a); | |
| 2397 var fontRadius = .8 * fontSize; | |
| 2398 | |
| 2399 if | |
| 2400 ( | |
| 2401 nodeLabelRadius * gRadius < hypotenuse && | |
| 2402 this.labelWidth.end / 2 + fontRadius > opposite | |
| 2403 ) { | |
| 2404 this.labelWidth.end = 2 * (opposite - fontRadius); | |
| 2405 } | |
| 2406 } | |
| 2407 } | |
| 2408 else if | |
| 2409 ( | |
| 2410 this.labelRadius.end == node.labelRadius.end && | |
| 2411 a < Math.PI / 4 | |
| 2412 ) { | |
| 2413 // same radius with small angle; use circumferential approximation | |
| 2414 | |
| 2415 var dist = a * this.labelRadius.end * gRadius - fontSize | |
| 2416 * (1 - a * 4 / Math.PI) * 1.3; | |
| 2417 | |
| 2418 if (this.labelWidth.end < dist) { | |
| 2419 node.restrictLabelWidth((dist - this.labelWidth.end / 2) * 2); | |
| 2420 } | |
| 2421 else if (node.labelWidth.end < dist) { | |
| 2422 this.restrictLabelWidth((dist - node.labelWidth.end / 2) * 2); | |
| 2423 } | |
| 2424 else { | |
| 2425 // both labels reach halfway point; restrict both | |
| 2426 | |
| 2427 this.labelWidth.end = dist; | |
| 2428 node.labelWidth.end = dist | |
| 2429 } | |
| 2430 } | |
| 2431 else { | |
| 2432 var r1 = this.labelRadius.end * gRadius; | |
| 2433 var r2 = node.labelRadius.end * gRadius; | |
| 2434 | |
| 2435 // first adjust the radii to account for the height of the font | |
| 2436 // by shifting them toward each other | |
| 2437 // | |
| 2438 var fontFudge = .35 * fontSize; | |
| 2439 // | |
| 2440 if (this.labelRadius.end < node.labelRadius.end) { | |
| 2441 r1 += fontFudge; | |
| 2442 r2 -= fontFudge; | |
| 2443 } | |
| 2444 else if (this.labelRadius.end > node.labelRadius.end) { | |
| 2445 r1 -= fontFudge; | |
| 2446 r2 += fontFudge; | |
| 2447 } | |
| 2448 else { | |
| 2449 r1 -= fontFudge; | |
| 2450 r2 -= fontFudge; | |
| 2451 } | |
| 2452 | |
| 2453 var r1s = r1 * r1; | |
| 2454 var r2s = r2 * r2; | |
| 2455 | |
| 2456 // distance between the centers of the two labels | |
| 2457 // | |
| 2458 var dist = Math.sqrt(r1s + r2s - 2 * r1 * r2 * Math.cos(a)); | |
| 2459 | |
| 2460 // angle at our label center between our radius and the line to the | |
| 2461 // other label center | |
| 2462 // | |
| 2463 var b = Math.acos((r1s + dist * dist - r2s) / (2 * r1 * dist)); | |
| 2464 | |
| 2465 // distance from our label center to the intersection of the | |
| 2466 // two tangents | |
| 2467 // | |
| 2468 var l1 = Math.sin(a + b - Math.PI / 2) * dist / Math.sin(Math.PI - a); | |
| 2469 | |
| 2470 // distance from other label center the the intersection of the | |
| 2471 // two tangents | |
| 2472 // | |
| 2473 var l2 = Math.sin(Math.PI / 2 - b) * dist / Math.sin(Math.PI - a); | |
| 2474 | |
| 2475 l1 = Math.abs(l1) - .4 * fontSize; | |
| 2476 l2 = Math.abs(l2) - .4 * fontSize; | |
| 2477 /* | |
| 2478 // amount to shorten the distances because of height of the font | |
| 2479 // | |
| 2480 var l3 = 0; | |
| 2481 var fontRadius = fontSize * .55; | |
| 2482 // | |
| 2483 if ( l1 < 0 || l2 < 0 ) | |
| 2484 { | |
| 2485 var l4 = fontRadius / Math.tan(a); | |
| 2486 l1 = Math.abs(l1); | |
| 2487 l2 = Math.abs(l2); | |
| 2488 | |
| 2489 l1 -= l4; | |
| 2490 l2 -= l4; | |
| 2491 } | |
| 2492 else | |
| 2493 { | |
| 2494 var c = Math.PI - a; | |
| 2495 | |
| 2496 l3 = fontRadius * Math.tan(c / 2); | |
| 2497 } | |
| 2498 */ | |
| 2499 if (this.labelWidth.end / 2 > l1 && node.labelWidth.end / 2 > l2) { | |
| 2500 // shorten the farthest one from the intersection | |
| 2501 | |
| 2502 if (l1 > l2) { | |
| 2503 this.restrictLabelWidth(2 * (l1));// - l3 - fontRadius)); | |
| 2504 } | |
| 2505 else { | |
| 2506 node.restrictLabelWidth(2 * (l2));// - l3 - fontRadius)); | |
| 2507 } | |
| 2508 } | |
| 2509 /* | |
| 2510 else if ( this.labelWidth.end / 2 > l1 + l3 && node.labelWidth.end | |
| 2511 / 2 > l2 - l3 ) | |
| 2512 { | |
| 2513 node.restrictLabelWidth(2 * (l2 - l3)); | |
| 2514 } | |
| 2515 else if ( this.labelWidth.end / 2 > l1 - l3 && node.labelWidth.end | |
| 2516 / 2 > l2 + l3 ) | |
| 2517 { | |
| 2518 this.restrictLabelWidth(2 * (l1 - l3)); | |
| 2519 }*/ | |
| 2520 } | |
| 2521 } | |
| 2522 | |
| 2523 this.setMagnitudes = function (baseMagnitude) { | |
| 2524 this.magnitude = this.getMagnitude(); | |
| 2525 this.baseMagnitude = baseMagnitude; | |
| 2526 | |
| 2527 for (var i = 0; i < this.children.length; i++) { | |
| 2528 this.children[i].setMagnitudes(baseMagnitude); | |
| 2529 baseMagnitude += this.children[i].magnitude; | |
| 2530 } | |
| 2531 | |
| 2532 this.maxChildMagnitude = baseMagnitude; | |
| 2533 } | |
| 2534 | |
| 2535 this.setMaxDepths = function () { | |
| 2536 this.maxDepth = this.depth; | |
| 2537 this.maxDepthCollapsed = this.depthCollapsed; | |
| 2538 | |
| 2539 for (i in this.children) { | |
| 2540 var child = this.children[i]; | |
| 2541 | |
| 2542 child.setMaxDepths(); | |
| 2543 | |
| 2544 if (child.maxDepth > this.maxDepth) { | |
| 2545 this.maxDepth = child.maxDepth; | |
| 2546 } | |
| 2547 | |
| 2548 if | |
| 2549 ( | |
| 2550 child.maxDepthCollapsed > this.maxDepthCollapsed && | |
| 2551 (child.depth <= maxAbsoluteDepth || maxAbsoluteDepth == 0) | |
| 2552 ) { | |
| 2553 this.maxDepthCollapsed = child.maxDepthCollapsed; | |
| 2554 } | |
| 2555 } | |
| 2556 } | |
| 2557 | |
| 2558 this.setTargetLabelRadius = function () { | |
| 2559 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 2560 var index = depth - 2; | |
| 2561 var labelOffset = labelOffsets[index]; | |
| 2562 | |
| 2563 if (this.radial) { | |
| 2564 //this.labelRadius.setTarget((this.radiusInner.end + 1) / 2); | |
| 2565 var max = | |
| 2566 depth == maxDisplayDepth ? | |
| 2567 1 : | |
| 2568 compressedRadii[index + 1]; | |
| 2569 | |
| 2570 this.labelRadius.setTarget((compressedRadii[index] + max) / 2); | |
| 2571 } | |
| 2572 else { | |
| 2573 var radiusCenter; | |
| 2574 var width; | |
| 2575 | |
| 2576 if (compress) { | |
| 2577 if (nLabelOffsets[index] > 1) { | |
| 2578 this.labelRadius.setTarget | |
| 2579 ( | |
| 2580 lerp | |
| 2581 ( | |
| 2582 labelOffset + .75, | |
| 2583 0, | |
| 2584 nLabelOffsets[index] + .5, | |
| 2585 compressedRadii[index], | |
| 2586 compressedRadii[index + 1] | |
| 2587 ) | |
| 2588 ); | |
| 2589 } | |
| 2590 else { | |
| 2591 this.labelRadius.setTarget((compressedRadii[index] | |
| 2592 + compressedRadii[index + 1]) / 2); | |
| 2593 } | |
| 2594 } | |
| 2595 else { | |
| 2596 radiusCenter = | |
| 2597 nodeRadius * (depth - 1) + | |
| 2598 nodeRadius / 2; | |
| 2599 width = nodeRadius; | |
| 2600 | |
| 2601 this.labelRadius.setTarget | |
| 2602 ( | |
| 2603 radiusCenter + width | |
| 2604 * ((labelOffset + 1) / (nLabelOffsets[index] + 1) - .5) | |
| 2605 ); | |
| 2606 } | |
| 2607 } | |
| 2608 | |
| 2609 if (!this.hide && !this.keyed && nLabelOffsets[index]) { | |
| 2610 // check last and first labels in each track for overlap | |
| 2611 | |
| 2612 for (var i = 0; i < maxDisplayDepth - 1; i++) { | |
| 2613 for (var j = 0; j <= nLabelOffsets[i]; j++) { | |
| 2614 var last = labelLastNodes[i][j]; | |
| 2615 var first = labelFirstNodes[i][j]; | |
| 2616 | |
| 2617 if (last) { | |
| 2618 if (j == nLabelOffsets[i]) { | |
| 2619 // last is radial | |
| 2620 this.setLabelWidth(last); | |
| 2621 } | |
| 2622 else { | |
| 2623 last.setLabelWidth(this); | |
| 2624 } | |
| 2625 } | |
| 2626 | |
| 2627 if (first) { | |
| 2628 if (j == nLabelOffsets[i]) { | |
| 2629 this.setLabelWidth(first); | |
| 2630 } | |
| 2631 else { | |
| 2632 first.setLabelWidth(this); | |
| 2633 } | |
| 2634 } | |
| 2635 } | |
| 2636 } | |
| 2637 | |
| 2638 if (selectedNode.canDisplayLabelOther) { | |
| 2639 // in case there is an 'other' label | |
| 2640 this.setLabelWidth(selectedNode); | |
| 2641 } | |
| 2642 | |
| 2643 if (this.radial) { | |
| 2644 // use the last 'track' of this depth for radial | |
| 2645 | |
| 2646 labelLastNodes[index][nLabelOffsets[index]] = this; | |
| 2647 | |
| 2648 if (labelFirstNodes[index][nLabelOffsets[index]] == 0) { | |
| 2649 labelFirstNodes[index][nLabelOffsets[index]] = this; | |
| 2650 } | |
| 2651 } | |
| 2652 else { | |
| 2653 labelLastNodes[index][labelOffset] = this; | |
| 2654 | |
| 2655 // update offset | |
| 2656 | |
| 2657 labelOffsets[index] += 1; | |
| 2658 | |
| 2659 if (labelOffsets[index] > nLabelOffsets[index]) { | |
| 2660 labelOffsets[index] -= nLabelOffsets[index]; | |
| 2661 | |
| 2662 if (!(nLabelOffsets[index] & 1)) { | |
| 2663 labelOffsets[index]--; | |
| 2664 } | |
| 2665 } | |
| 2666 else if (labelOffsets[index] == nLabelOffsets[index]) { | |
| 2667 labelOffsets[index] -= nLabelOffsets[index]; | |
| 2668 | |
| 2669 if (false && !(nLabelOffsets[index] & 1)) { | |
| 2670 labelOffsets[index]++; | |
| 2671 } | |
| 2672 } | |
| 2673 | |
| 2674 if (labelFirstNodes[index][labelOffset] == 0) { | |
| 2675 labelFirstNodes[index][labelOffset] = this; | |
| 2676 } | |
| 2677 } | |
| 2678 } | |
| 2679 else if (this.hide) { | |
| 2680 this.labelWidth.end = 0; | |
| 2681 } | |
| 2682 } | |
| 2683 | |
| 2684 this.setTargets = function () { | |
| 2685 if (this == selectedNode) { | |
| 2686 this.setTargetsSelected | |
| 2687 ( | |
| 2688 0, | |
| 2689 1, | |
| 2690 lightnessBase, | |
| 2691 false, | |
| 2692 false | |
| 2693 ); | |
| 2694 return; | |
| 2695 } | |
| 2696 | |
| 2697 var depthRelative = this.getDepth() - selectedNode.getDepth(); | |
| 2698 | |
| 2699 var parentOfSelected = selectedNode.hasParent(this); | |
| 2700 /* ( | |
| 2701 // ! this.getCollapse() && | |
| 2702 this.baseMagnitude <= selectedNode.baseMagnitude && | |
| 2703 this.baseMagnitude + this.magnitude >= | |
| 2704 selectedNode.baseMagnitude + selectedNode.magnitude | |
| 2705 ); | |
| 2706 */ | |
| 2707 if (parentOfSelected) { | |
| 2708 this.resetLabelWidth(); | |
| 2709 } | |
| 2710 else { | |
| 2711 //context.font = fontNormal; | |
| 2712 var dim = context.measureText(this.name); | |
| 2713 this.nameWidth = dim.width; | |
| 2714 //this.labelWidth.setTarget(this.labelWidth.end); | |
| 2715 this.labelWidth.setTarget(0); | |
| 2716 } | |
| 2717 | |
| 2718 // set angles | |
| 2719 // | |
| 2720 if (this.baseMagnitude <= selectedNode.baseMagnitude) { | |
| 2721 this.angleStart.setTarget(0); | |
| 2722 } | |
| 2723 else { | |
| 2724 this.angleStart.setTarget(Math.PI * 2); | |
| 2725 } | |
| 2726 // | |
| 2727 if | |
| 2728 ( | |
| 2729 parentOfSelected || | |
| 2730 this.baseMagnitude + this.magnitude >= | |
| 2731 selectedNode.baseMagnitude + selectedNode.magnitude | |
| 2732 ) { | |
| 2733 this.angleEnd.setTarget(Math.PI * 2); | |
| 2734 } | |
| 2735 else { | |
| 2736 this.angleEnd.setTarget(0); | |
| 2737 } | |
| 2738 | |
| 2739 // children | |
| 2740 // | |
| 2741 for (var i = 0; i < this.children.length; i++) { | |
| 2742 this.children[i].setTargets(); | |
| 2743 } | |
| 2744 | |
| 2745 if (this.getDepth() <= selectedNode.getDepth()) { | |
| 2746 // collapse in | |
| 2747 | |
| 2748 this.radiusInner.setTarget(0); | |
| 2749 | |
| 2750 if (parentOfSelected) { | |
| 2751 this.labelRadius.setTarget | |
| 2752 ( | |
| 2753 (depthRelative) * | |
| 2754 historySpacingFactor * fontSize / gRadius | |
| 2755 ); | |
| 2756 //this.scale.setTarget(1 - (selectedNode.getDepth() | |
| 2757 // - this.getDepth()) / 18); // TEMP | |
| 2758 } | |
| 2759 else { | |
| 2760 this.labelRadius.setTarget(0); | |
| 2761 //this.scale.setTarget(1); // TEMP | |
| 2762 } | |
| 2763 } | |
| 2764 else if (depthRelative + 1 > maxDisplayDepth) { | |
| 2765 // collapse out | |
| 2766 | |
| 2767 this.radiusInner.setTarget(1); | |
| 2768 this.labelRadius.setTarget(1); | |
| 2769 //this.scale.setTarget(1); // TEMP | |
| 2770 } | |
| 2771 else { | |
| 2772 // don't collapse | |
| 2773 | |
| 2774 if (compress) { | |
| 2775 this.radiusInner.setTarget(compressedRadii[depthRelative - 1]); | |
| 2776 } | |
| 2777 else { | |
| 2778 this.radiusInner.setTarget(nodeRadius * (depthRelative)); | |
| 2779 } | |
| 2780 | |
| 2781 //this.scale.setTarget(1); // TEMP | |
| 2782 | |
| 2783 if (this == selectedNode) { | |
| 2784 this.labelRadius.setTarget(0); | |
| 2785 } | |
| 2786 else { | |
| 2787 if (compress) { | |
| 2788 this.labelRadius.setTarget | |
| 2789 ( | |
| 2790 (compressedRadii[depthRelative - 1] | |
| 2791 + compressedRadii[depthRelative]) / 2 | |
| 2792 ); | |
| 2793 } | |
| 2794 else { | |
| 2795 this.labelRadius.setTarget(nodeRadius * (depthRelative) | |
| 2796 + nodeRadius / 2); | |
| 2797 } | |
| 2798 } | |
| 2799 } | |
| 2800 | |
| 2801 // this.r.start = this.r.end; | |
| 2802 // this.g.start = this.g.end; | |
| 2803 // this.b.start = this.b.end; | |
| 2804 | |
| 2805 this.r.setTarget(255); | |
| 2806 this.g.setTarget(255); | |
| 2807 this.b.setTarget(255); | |
| 2808 | |
| 2809 this.alphaLine.setTarget(0); | |
| 2810 this.alphaArc.setTarget(0); | |
| 2811 this.alphaWedge.setTarget(0); | |
| 2812 this.alphaPattern.setTarget(0); | |
| 2813 this.alphaOther.setTarget(0); | |
| 2814 | |
| 2815 if (parentOfSelected && !this.getCollapse()) { | |
| 2816 var alpha = | |
| 2817 ( | |
| 2818 1 - | |
| 2819 (selectedNode.getDepth() - this.getDepth()) / | |
| 2820 (Math.floor((compress ? compressedRadii[0] : nodeRadius) | |
| 2821 * gRadius / (historySpacingFactor * fontSize) - .5) + 1) | |
| 2822 ); | |
| 2823 | |
| 2824 if (alpha < 0) { | |
| 2825 alpha = 0; | |
| 2826 } | |
| 2827 | |
| 2828 this.alphaLabel.setTarget(alpha); | |
| 2829 this.radial = false; | |
| 2830 } | |
| 2831 else { | |
| 2832 this.alphaLabel.setTarget(0); | |
| 2833 } | |
| 2834 | |
| 2835 this.hideAlonePrev = this.hideAlone; | |
| 2836 this.hidePrev = this.hide; | |
| 2837 | |
| 2838 if (parentOfSelected) { | |
| 2839 this.hideAlone = false; | |
| 2840 this.hide = false; | |
| 2841 } | |
| 2842 | |
| 2843 if (this.getParent() == selectedNode.getParent()) { | |
| 2844 this.hiddenEnd = null; | |
| 2845 } | |
| 2846 | |
| 2847 this.radialPrev = this.radial; | |
| 2848 } | |
| 2849 | |
| 2850 this.setTargetsSelected = function (hueMin, hueMax, lightness, hide, | |
| 2851 nextSiblingHidden) { | |
| 2852 var collapse = this.getCollapse(); | |
| 2853 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 2854 var canDisplayChildLabels = false; | |
| 2855 var lastChild; | |
| 2856 | |
| 2857 if (this.hasChildren())//&& ! hide ) | |
| 2858 { | |
| 2859 lastChild = this.children[this.children.length - 1]; | |
| 2860 this.hideAlone = true; | |
| 2861 } | |
| 2862 else { | |
| 2863 this.hideAlone = false; | |
| 2864 } | |
| 2865 | |
| 2866 // set child wedges | |
| 2867 // | |
| 2868 for (var i = 0; i < this.children.length; i++) { | |
| 2869 this.children[i].setTargetWedge(); | |
| 2870 | |
| 2871 if | |
| 2872 ( | |
| 2873 !this.children[i].hide && | |
| 2874 (collapse || depth < maxDisplayDepth) && | |
| 2875 this.depth < maxAbsoluteDepth | |
| 2876 ) { | |
| 2877 canDisplayChildLabels = true; | |
| 2878 this.hideAlone = false; | |
| 2879 } | |
| 2880 } | |
| 2881 | |
| 2882 if (this == selectedNode || lastChild && lastChild.angleEnd.end | |
| 2883 < this.angleEnd.end - .01) { | |
| 2884 this.hideAlone = false; | |
| 2885 } | |
| 2886 | |
| 2887 if (this.hideAlonePrev == undefined) { | |
| 2888 this.hideAlonePrev = this.hideAlone; | |
| 2889 } | |
| 2890 | |
| 2891 if (this == selectedNode) { | |
| 2892 var otherArc = | |
| 2893 this.children.length ? | |
| 2894 angleFactor * | |
| 2895 ( | |
| 2896 this.baseMagnitude + this.magnitude - | |
| 2897 lastChild.baseMagnitude - lastChild.magnitude | |
| 2898 ) | |
| 2899 : this.baseMagnitude + this.magnitude; | |
| 2900 this.canDisplayLabelOther = | |
| 2901 this.children.length ? | |
| 2902 otherArc * | |
| 2903 (this.children[0].radiusInner.end + 1) * gRadius >= | |
| 2904 minWidth() | |
| 2905 : true; | |
| 2906 | |
| 2907 this.keyUnclassified = false; | |
| 2908 | |
| 2909 if (this.canDisplayLabelOther) { | |
| 2910 this.angleOther = Math.PI * 2 - otherArc / 2; | |
| 2911 } | |
| 2912 else if (otherArc > 0.0000000001) { | |
| 2913 this.keyUnclassified = true; | |
| 2914 keys++; | |
| 2915 } | |
| 2916 | |
| 2917 this.angleStart.setTarget(0); | |
| 2918 this.angleEnd.setTarget(Math.PI * 2); | |
| 2919 | |
| 2920 if (this.children.length) { | |
| 2921 this.radiusInner.setTarget(0); | |
| 2922 } | |
| 2923 else { | |
| 2924 this.radiusInner.setTarget(compressedRadii[0]); | |
| 2925 } | |
| 2926 | |
| 2927 this.hidePrev = this.hide; | |
| 2928 this.hide = false; | |
| 2929 this.hideAlonePrev = this.hideAlone; | |
| 2930 this.hideAlone = false; | |
| 2931 this.keyed = false; | |
| 2932 } | |
| 2933 | |
| 2934 if (hueMax - hueMin > 1 / 12) { | |
| 2935 hueMax = hueMin + 1 / 12; | |
| 2936 } | |
| 2937 | |
| 2938 // set lightness | |
| 2939 // | |
| 2940 if (!(hide || this.hideAlone)) { | |
| 2941 if (useHue()) { | |
| 2942 lightness = (lightnessBase + lightnessMax) / 2; | |
| 2943 } | |
| 2944 else { | |
| 2945 lightness = lightnessBase + (depth - 1) * lightnessFactor; | |
| 2946 | |
| 2947 if (lightness > lightnessMax) { | |
| 2948 lightness = lightnessMax; | |
| 2949 } | |
| 2950 } | |
| 2951 } | |
| 2952 | |
| 2953 if (hide) { | |
| 2954 this.hide = true; | |
| 2955 } | |
| 2956 | |
| 2957 if (this.hidePrev == undefined) { | |
| 2958 this.hidePrev = this.hide; | |
| 2959 } | |
| 2960 | |
| 2961 var hiddenStart = -1; | |
| 2962 var hiddenHueNumer = 0; | |
| 2963 var hiddenHueDenom = 0; | |
| 2964 | |
| 2965 | |
| 2966 if (!this.hide) { | |
| 2967 this.hiddenEnd = null; | |
| 2968 } | |
| 2969 | |
| 2970 for (var i = 0; true; i++) { | |
| 2971 if (!this.hideAlone && !hide && (i == this.children.length | |
| 2972 || !this.children[i].hide)) { | |
| 2973 // reached a non-hidden child or the end; set targets for | |
| 2974 // previous group of hidden children (if any) using their | |
| 2975 // average hue | |
| 2976 | |
| 2977 if (hiddenStart != -1) { | |
| 2978 var hiddenHue = hiddenHueDenom ? hiddenHueNumer | |
| 2979 / hiddenHueDenom : hueMin; | |
| 2980 | |
| 2981 for (var j = hiddenStart; j < i; j++) { | |
| 2982 this.children[j].setTargetsSelected | |
| 2983 ( | |
| 2984 hiddenHue, | |
| 2985 null, | |
| 2986 lightness, | |
| 2987 false, | |
| 2988 j < i - 1 | |
| 2989 ); | |
| 2990 | |
| 2991 this.children[j].hiddenEnd = null; | |
| 2992 } | |
| 2993 | |
| 2994 this.children[hiddenStart].hiddenEnd = i - 1; | |
| 2995 } | |
| 2996 } | |
| 2997 | |
| 2998 if (i == this.children.length) { | |
| 2999 break; | |
| 3000 } | |
| 3001 | |
| 3002 var child = this.children[i]; | |
| 3003 var childHueMin; | |
| 3004 var childHueMax; | |
| 3005 | |
| 3006 if (this.magnitude > 0 && !this.hide && !this.hideAlone) { | |
| 3007 if (useHue()) { | |
| 3008 childHueMin = child.hues[currentDataset]; | |
| 3009 } | |
| 3010 else if (this == selectedNode) { | |
| 3011 var min = 0.0; | |
| 3012 var max = 1.0; | |
| 3013 | |
| 3014 if (this.children.length > 6) { | |
| 3015 childHueMin = lerp((1 - Math.pow( | |
| 3016 1 - i / this.children.length, 1.4)) * .95, | |
| 3017 0, 1, min, max); | |
| 3018 childHueMax = lerp((1 - Math.pow( | |
| 3019 1 - (i + .55) / this.children.length, 1.4)) * .95, | |
| 3020 0, 1, min, max); | |
| 3021 } | |
| 3022 else { | |
| 3023 childHueMin = lerp(i / this.children.length, 0, 1, | |
| 3024 min, max); | |
| 3025 childHueMax = lerp((i + .55) / this.children.length, | |
| 3026 0, 1, min, max); | |
| 3027 } | |
| 3028 } | |
| 3029 else { | |
| 3030 childHueMin = lerp | |
| 3031 ( | |
| 3032 child.baseMagnitude, | |
| 3033 this.baseMagnitude, | |
| 3034 this.baseMagnitude + this.magnitude, | |
| 3035 hueMin, | |
| 3036 hueMax | |
| 3037 ); | |
| 3038 childHueMax = lerp | |
| 3039 ( | |
| 3040 child.baseMagnitude + child.magnitude * .99, | |
| 3041 this.baseMagnitude, | |
| 3042 this.baseMagnitude + this.magnitude, | |
| 3043 hueMin, | |
| 3044 hueMax | |
| 3045 ); | |
| 3046 } | |
| 3047 } | |
| 3048 else { | |
| 3049 childHueMin = hueMin; | |
| 3050 childHueMax = hueMax; | |
| 3051 } | |
| 3052 | |
| 3053 if (!this.hideAlone && !hide && !this.hide && child.hide) { | |
| 3054 if (hiddenStart == -1) { | |
| 3055 hiddenStart = i; | |
| 3056 } | |
| 3057 | |
| 3058 if (useHue()) { | |
| 3059 hiddenHueNumer += childHueMin * child.magnitude; | |
| 3060 hiddenHueDenom += child.magnitude; | |
| 3061 } | |
| 3062 else { | |
| 3063 hiddenHueNumer += childHueMin; | |
| 3064 hiddenHueDenom++; | |
| 3065 } | |
| 3066 } | |
| 3067 else { | |
| 3068 hiddenStart = -1; | |
| 3069 | |
| 3070 this.children[i].setTargetsSelected | |
| 3071 ( | |
| 3072 childHueMin, | |
| 3073 childHueMax, | |
| 3074 lightness, | |
| 3075 hide || this.keyed || this.hideAlone | |
| 3076 || this.hide && !collapse, | |
| 3077 false | |
| 3078 ); | |
| 3079 } | |
| 3080 } | |
| 3081 | |
| 3082 if (this.hue && this.magnitude) { | |
| 3083 this.hue.setTarget(this.hues[currentDataset]); | |
| 3084 | |
| 3085 if (this.attributes[magnitudeIndex][lastDataset] == 0) { | |
| 3086 this.hue.start = this.hue.end; | |
| 3087 } | |
| 3088 } | |
| 3089 | |
| 3090 this.radialPrev = this.radial; | |
| 3091 | |
| 3092 if (this == selectedNode) { | |
| 3093 this.resetLabelWidth(); | |
| 3094 this.labelWidth.setTarget(this.nameWidth * labelWidthFudge); | |
| 3095 this.alphaWedge.setTarget(0); | |
| 3096 this.alphaLabel.setTarget(1); | |
| 3097 this.alphaOther.setTarget(1); | |
| 3098 this.alphaArc.setTarget(0); | |
| 3099 this.alphaLine.setTarget(0); | |
| 3100 this.alphaPattern.setTarget(0); | |
| 3101 this.r.setTarget(255); | |
| 3102 this.g.setTarget(255); | |
| 3103 this.b.setTarget(255); | |
| 3104 this.radial = false; | |
| 3105 this.labelRadius.setTarget(0); | |
| 3106 } | |
| 3107 else { | |
| 3108 var rgb = hslToRgb | |
| 3109 ( | |
| 3110 hueMin, | |
| 3111 saturation, | |
| 3112 lightness | |
| 3113 ); | |
| 3114 | |
| 3115 this.r.setTarget(rgb.r); | |
| 3116 this.g.setTarget(rgb.g); | |
| 3117 this.b.setTarget(rgb.b); | |
| 3118 this.alphaOther.setTarget(0); | |
| 3119 | |
| 3120 this.alphaWedge.setTarget(1); | |
| 3121 | |
| 3122 if (this.hide || this.hideAlone) { | |
| 3123 this.alphaPattern.setTarget(1); | |
| 3124 } | |
| 3125 else { | |
| 3126 this.alphaPattern.setTarget(0); | |
| 3127 } | |
| 3128 | |
| 3129 // set radial | |
| 3130 // | |
| 3131 if (!(hide || this.hide))//&& ! this.keyed ) | |
| 3132 { | |
| 3133 if (this.hideAlone) { | |
| 3134 this.radial = true; | |
| 3135 } | |
| 3136 else if (false && canDisplayChildLabels) { | |
| 3137 this.radial = false; | |
| 3138 } | |
| 3139 else { | |
| 3140 this.radial = true; | |
| 3141 | |
| 3142 if (this.hasChildren() && depth < maxDisplayDepth) { | |
| 3143 var lastChild = this.children[this.children.length - 1]; | |
| 3144 | |
| 3145 if | |
| 3146 ( | |
| 3147 lastChild.angleEnd.end == this.angleEnd.end || | |
| 3148 ( | |
| 3149 (this.angleStart.end + this.angleEnd.end) / 2 - | |
| 3150 lastChild.angleEnd.end | |
| 3151 ) * (this.radiusInner.end + 1) * gRadius * 2 < | |
| 3152 minWidth() | |
| 3153 ) { | |
| 3154 this.radial = false; | |
| 3155 } | |
| 3156 } | |
| 3157 } | |
| 3158 } | |
| 3159 | |
| 3160 // set alphaLabel | |
| 3161 // | |
| 3162 if | |
| 3163 ( | |
| 3164 collapse || | |
| 3165 hide || | |
| 3166 this.hide || | |
| 3167 this.keyed || | |
| 3168 depth > maxDisplayDepth || | |
| 3169 !this.canDisplayDepth() | |
| 3170 ) { | |
| 3171 this.alphaLabel.setTarget(0); | |
| 3172 } | |
| 3173 else { | |
| 3174 if | |
| 3175 ( | |
| 3176 (this.radial || nLabelOffsets[depth - 2]) | |
| 3177 ) { | |
| 3178 this.alphaLabel.setTarget(1); | |
| 3179 } | |
| 3180 else { | |
| 3181 this.alphaLabel.setTarget(0); | |
| 3182 | |
| 3183 if (this.radialPrev) { | |
| 3184 this.alphaLabel.start = 0; | |
| 3185 } | |
| 3186 } | |
| 3187 } | |
| 3188 | |
| 3189 // set alphaArc | |
| 3190 // | |
| 3191 if | |
| 3192 ( | |
| 3193 collapse || | |
| 3194 hide || | |
| 3195 depth > maxDisplayDepth || | |
| 3196 !this.canDisplayDepth() | |
| 3197 ) { | |
| 3198 this.alphaArc.setTarget(0); | |
| 3199 } | |
| 3200 else { | |
| 3201 this.alphaArc.setTarget(1); | |
| 3202 } | |
| 3203 | |
| 3204 // set alphaLine | |
| 3205 // | |
| 3206 if | |
| 3207 ( | |
| 3208 hide || | |
| 3209 this.hide && nextSiblingHidden || | |
| 3210 depth > maxDisplayDepth || | |
| 3211 !this.canDisplayDepth() | |
| 3212 ) { | |
| 3213 this.alphaLine.setTarget(0); | |
| 3214 } | |
| 3215 else { | |
| 3216 this.alphaLine.setTarget(1); | |
| 3217 } | |
| 3218 | |
| 3219 //if ( ! this.radial ) | |
| 3220 { | |
| 3221 this.resetLabelWidth(); | |
| 3222 } | |
| 3223 | |
| 3224 // set labelRadius target | |
| 3225 // | |
| 3226 if (collapse) { | |
| 3227 this.labelRadius.setTarget(this.radiusInner.end); | |
| 3228 } | |
| 3229 else { | |
| 3230 if (depth > maxDisplayDepth || !this.canDisplayDepth()) { | |
| 3231 this.labelRadius.setTarget(1); | |
| 3232 } | |
| 3233 else { | |
| 3234 this.setTargetLabelRadius(); | |
| 3235 } | |
| 3236 } | |
| 3237 } | |
| 3238 } | |
| 3239 | |
| 3240 this.setTargetWedge = function () { | |
| 3241 var depth = this.getDepth() - selectedNode.getDepth() + 1; | |
| 3242 | |
| 3243 // set angles | |
| 3244 // | |
| 3245 var baseMagnitudeRelative = this.baseMagnitude | |
| 3246 - selectedNode.baseMagnitude; | |
| 3247 // | |
| 3248 this.angleStart.setTarget(baseMagnitudeRelative * angleFactor); | |
| 3249 this.angleEnd.setTarget((baseMagnitudeRelative + this.magnitude) | |
| 3250 * angleFactor); | |
| 3251 | |
| 3252 // set radiusInner | |
| 3253 // | |
| 3254 if (depth > maxDisplayDepth || !this.canDisplayDepth()) { | |
| 3255 this.radiusInner.setTarget(1); | |
| 3256 } | |
| 3257 else { | |
| 3258 if (compress) { | |
| 3259 this.radiusInner.setTarget(compressedRadii[depth - 2]); | |
| 3260 } | |
| 3261 else { | |
| 3262 this.radiusInner.setTarget(nodeRadius * (depth - 1)); | |
| 3263 } | |
| 3264 } | |
| 3265 | |
| 3266 if (this.hide != undefined) { | |
| 3267 this.hidePrev = this.hide; | |
| 3268 } | |
| 3269 | |
| 3270 if (this.hideAlone != undefined) { | |
| 3271 this.hideAlonePrev = this.hideAlone; | |
| 3272 } | |
| 3273 | |
| 3274 // set hide | |
| 3275 // | |
| 3276 if | |
| 3277 ( | |
| 3278 (this.angleEnd.end - this.angleStart.end) * | |
| 3279 (this.radiusInner.end * gRadius + gRadius) < | |
| 3280 minWidth() | |
| 3281 ) { | |
| 3282 if (depth == 2 && !this.getCollapse() && this.depth | |
| 3283 <= maxAbsoluteDepth) { | |
| 3284 this.keyed = true; | |
| 3285 keys++; | |
| 3286 this.hide = false; | |
| 3287 | |
| 3288 var percentage = this.getPercentage(); | |
| 3289 this.keyLabel = this.name + ' ' + percentage + '%'; | |
| 3290 var dim = context.measureText(this.keyLabel); | |
| 3291 this.keyNameWidth = dim.width; | |
| 3292 } | |
| 3293 else { | |
| 3294 this.keyed = false; | |
| 3295 this.hide = depth > 2; | |
| 3296 } | |
| 3297 } | |
| 3298 else { | |
| 3299 this.keyed = false; | |
| 3300 this.hide = false; | |
| 3301 } | |
| 3302 } | |
| 3303 | |
| 3304 this.shortenLabel = function () { | |
| 3305 var label = this.name; | |
| 3306 | |
| 3307 var labelWidth = this.nameWidth; | |
| 3308 var maxWidth = this.labelWidth.current(); | |
| 3309 var minEndLength = 0; | |
| 3310 | |
| 3311 if (labelWidth > maxWidth && label.length > minEndLength * 2) { | |
| 3312 var endLength = | |
| 3313 Math.floor((label.length - 1) * maxWidth / labelWidth / 2); | |
| 3314 | |
| 3315 if (endLength < minEndLength) { | |
| 3316 endLength = minEndLength; | |
| 3317 } | |
| 3318 | |
| 3319 return ( | |
| 3320 label.substring(0, endLength) + | |
| 3321 '...' + | |
| 3322 label.substring(label.length - endLength)); | |
| 3323 } | |
| 3324 else { | |
| 3325 return label; | |
| 3326 } | |
| 3327 } | |
| 3328 | |
| 3329 /* this.shouldAddSearchResultsString = function() | |
| 3330 { | |
| 3331 if ( this.isSearchResult ) | |
| 3332 { | |
| 3333 return this.searchResults > 1; | |
| 3334 } | |
| 3335 else | |
| 3336 { | |
| 3337 return this.searchResults > 0; | |
| 3338 } | |
| 3339 } | |
| 3340 */ | |
| 3341 this.sort = function () { | |
| 3342 this.children.sort(function (a, b) { | |
| 3343 if (sortByScoreCheckBox.checked) { | |
| 3344 return b.getHue() - a.getHue() | |
| 3345 } else { | |
| 3346 return b.getMagnitude() - a.getMagnitude() | |
| 3347 } | |
| 3348 }); | |
| 3349 | |
| 3350 for (var i = 0; i < this.children.length; i++) { | |
| 3351 this.children[i].sort(); | |
| 3352 } | |
| 3353 } | |
| 3354 } | |
| 3355 | |
| 3356 var options; | |
| 3357 | |
| 3358 function addOptionElement(position, innerHTML, title, padding) { | |
| 3359 var div = document.createElement("div"); | |
| 3360 // div.style.position = 'absolute'; | |
| 3361 // div.style.top = position + 'px'; | |
| 3362 div.innerHTML = innerHTML; | |
| 3363 // div.style.display = 'block'; | |
| 3364 div.style.padding = padding || '2px'; | |
| 3365 | |
| 3366 if (title) { | |
| 3367 div.title = title; | |
| 3368 } | |
| 3369 | |
| 3370 options.appendChild(div); | |
| 3371 var height = 0;//div.clientHeight; | |
| 3372 return position + height; | |
| 3373 } | |
| 3374 | |
| 3375 function addOptionElements(hueName, hueDefault) { | |
| 3376 options = document.createElement('div'); | |
| 3377 options.style.position = 'absolute'; | |
| 3378 options.style.top = '0px'; | |
| 3379 options.addEventListener('mousedown', function (e) { | |
| 3380 mouseClick(e) | |
| 3381 }, false); | |
| 3382 // options.onmouseup = function(e) {mouseUp(e)} | |
| 3383 document.body.appendChild(options); | |
| 3384 | |
| 3385 if (chart === ChartEnum.TAXOMIC) { | |
| 3386 document.body.style.font = '11px Ubuntu'; | |
| 3387 } else { | |
| 3388 document.body.style.font = '12px Saira Semi Condensed'; | |
| 3389 } | |
| 3390 var position = 5; | |
| 3391 | |
| 3392 function logLoaded(fontFace) { | |
| 3393 console.log(fontFace.family, 'loaded successfully.'); | |
| 3394 } | |
| 3395 | |
| 3396 // Loading FontFaces via JavaScript is alternative to using CSS's @font-face rule. | |
| 3397 // var ubuntuMonoFontFace = new FontFace('Ubuntu Mono', 'url(https://fonts.gstatic.com/s/ubuntumono/v7/KFOjCneDtsqEr0keqCMhbCc6CsTYl4BO.woff2)'); | |
| 3398 // document.fonts.add(ubuntuMonoFontFace); | |
| 3399 // ubuntuMonoFontFace.loaded.then(logLoaded); | |
| 3400 // var oxygenFontFace = new FontFace('Oxygen', 'url(https://fonts.gstatic.com/s/oxygen/v5/qBSyz106i5ud7wkBU-FrPevvDin1pK8aKteLpeZ5c0A.woff2)'); | |
| 3401 // document.fonts.add(oxygenFontFace); | |
| 3402 // oxygenFontFace.loaded.then(logLoaded); | |
| 3403 var oxygenMonoFontFace = new FontFace('Oxygen Mono', 'url(https://fonts.gstatic.com/s/oxygenmono/v5/h0GsssGg9FxgDgCjLeAd7hjYx-6tPUUv.woff2)'); | |
| 3404 document.fonts.add(oxygenMonoFontFace); | |
| 3405 oxygenMonoFontFace.loaded.then(logLoaded); | |
| 3406 var sairaCondensedFontFace = new FontFace('Saira Condensed', 'url(https://fonts.gstatic.com/s/sairacondensed/v3/EJROQgErUN8XuHNEtX81i9TmEkrvoutF2o-Srg.woff2)'); | |
| 3407 document.fonts.add(sairaCondensedFontFace); | |
| 3408 sairaCondensedFontFace.loaded.then(logLoaded); | |
| 3409 var sairaSemiCondensedFontFace = new FontFace('Saira Semi Condensed', 'url(https://fonts.gstatic.com/s/sairasemicondensed/v3/U9MD6c-2-nnJkHxyCjRcnMHcWVWV1cWRRX8MaOY8q3T_.woff2)'); | |
| 3410 document.fonts.add(sairaSemiCondensedFontFace); | |
| 3411 sairaSemiCondensedFontFace.loaded.then(logLoaded); | |
| 3412 | |
| 3413 // The .ready promise resolves when all fonts that have been previously requested | |
| 3414 // are loaded and layout operations are complete. | |
| 3415 document.fonts.ready.then(function () { | |
| 3416 console.log('There are', document.fonts.size, 'FontFaces loaded.\n'); | |
| 3417 | |
| 3418 // document.fonts has a Set-like interface. Here, we're iterating over its values. | |
| 3419 for (var fontFace of document.fonts.values()) { | |
| 3420 console.log('FontFace:'); | |
| 3421 for (var property in fontFace) { | |
| 3422 console.log(' ' + property + ': ' + fontFace[property]); | |
| 3423 } | |
| 3424 console.log('\n'); | |
| 3425 } | |
| 3426 }); | |
| 3427 | |
| 3428 details = document.createElement('div'); | |
| 3429 details.style.position = 'absolute'; | |
| 3430 details.style.top = '1%'; | |
| 3431 details.style.right = '2%'; | |
| 3432 details.style.textAlign = 'right'; | |
| 3433 document.body.insertBefore(details, canvas); | |
| 3434 //<div id="details" style="position:absolute;top:1%;right:2%;text-align:right;"> | |
| 3435 | |
| 3436 details.innerHTML = '\ | |
| 3437 <span id="detailsName" style="font-weight:bold"></span> \ | |
| 3438 <input type="button" id="detailsExpand" onclick="expand(focusNode);"\ | |
| 3439 value="↔" title="Expand this wedge to become the new focus of the chart"/><br/>\ | |
| 3440 <div id="detailsInfo" style="float:right"></div>'; | |
| 3441 | |
| 3442 keyControl = document.createElement('input'); | |
| 3443 keyControl.type = 'button'; | |
| 3444 keyControl.value = showKeys ? 'x' : '…'; | |
| 3445 keyControl.style.position = ''; | |
| 3446 keyControl.style.position = 'fixed'; | |
| 3447 keyControl.style.visibility = 'hidden'; | |
| 3448 | |
| 3449 document.body.insertBefore(keyControl, canvas); | |
| 3450 | |
| 3451 var logoElement = document.getElementById('logo'); | |
| 3452 | |
| 3453 if (logoElement) { | |
| 3454 logoImage = logoElement.src; | |
| 3455 } | |
| 3456 else { | |
| 3457 logoImage = 'https://raw.githubusercontent.com/khyox/recentrifuge/master/recentrifuge/img/logo-rcf-mini.uri'; | |
| 3458 } | |
| 3459 var placeholderTit; | |
| 3460 if (chart === ChartEnum.GENOMIC) { | |
| 3461 placeholderTit = "Complete or partial function, process, component..."; | |
| 3462 } else { | |
| 3463 placeholderTit = "Taxon scientific name, complete or partial name..."; | |
| 3464 } | |
| 3465 position = addOptionElement | |
| 3466 ( | |
| 3467 position, | |
| 3468 '<a style="margin:2px" target="_blank" href="http://www.recentrifuge.org"><img style="vertical-align:middle;width:136px;height:32px;padding:8px 10px 6px 10px" src="' + logoImage + '"/></a><input type="button" id="back" value="←" title="Go back (Shortcut: ←)"/>\ | |
| 3469 <input type="button" id="forward" value="→" title="Go forward (Shortcut: →)"/> \ | |
| 3470 Search: <input type="text" placeholder="' + placeholderTit + '" size="45" id="search"/>\ | |
| 3471 <input id="searchClear" type="button" value="x" onclick="clearSearch()"/> \ | |
| 3472 <span id="searchResults"></span>' | |
| 3473 ); | |
| 3474 | |
| 3475 if (datasets > 1) { | |
| 3476 var size = datasets < DATASET_MAX_SIZE ? datasets : DATASET_MAX_SIZE; | |
| 3477 | |
| 3478 var select = | |
| 3479 '<table style="border-collapse:collapse;margin-left:10px"><tr><td style="padding:0px">' + | |
| 3480 '<select id="datasets" style="min-width:100px" size="' + size + '" onchange="onDatasetChange()">'; | |
| 3481 | |
| 3482 for (var i = 0; i < datasetNames.length; i++) { | |
| 3483 select += '<option>' + datasetNames[i] + '</option>'; | |
| 3484 } | |
| 3485 select += | |
| 3486 '</select></td><td style="vertical-align:top;padding:2px;">' + | |
| 3487 '<input style="display:block" title="Previous dataset ' + | |
| 3488 '(Shortcut: ↑)" id="prevDataset" type="button"' + | |
| 3489 ' value="↑" onclick="prevDataset()" disabled="true"/>' + | |
| 3490 '<input title="Next dataset (Shortcut: ↓)" ' + | |
| 3491 'id="nextDataset" type="button" value="↓" ' + | |
| 3492 'onclick="nextDataset()"/><br/></td>' + | |
| 3493 '<td style="vertical-align:top;padding:2px;">' + | |
| 3494 '<input style="display:block" ' + | |
| 3495 'title="Switch to the prior dataset that was viewed ' + | |
| 3496 '(Shortcut: TAB)" id="lastDataset" type="button" ' + | |
| 3497 'style="font:11px Ubuntu" value="prior" ' + | |
| 3498 'onclick="selectLastDataset()"/>' + | |
| 3499 '<select id="ranks" onchange="onRankChange()" ' + | |
| 3500 'title="Filter samples by taxonomic rank">' + | |
| 3501 '<option value="SUMMARY">SUMMARY</option>' + | |
| 3502 '<option value="strain">strain</option>' + | |
| 3503 '<option value="species">species</option>' + | |
| 3504 '<option value="genus">genus</option>' + | |
| 3505 '<option value="family">family</option>' + | |
| 3506 '<option value="order">order</option>' + | |
| 3507 '<option value="class">class</option>' + | |
| 3508 '<option value="phylum">phylum</option>' + | |
| 3509 '<option value="kingdom">kingdom</option>' + | |
| 3510 '<option value="domain">domain</option>' + | |
| 3511 '<option value="ALL">ALL</option>' + | |
| 3512 '<option value="NONE">NONE</option>' + | |
| 3513 '</select></td></tr></table>'; | |
| 3514 | |
| 3515 position = addOptionElement(position + 5, select); | |
| 3516 | |
| 3517 datasetDropDown = document.getElementById('datasets'); | |
| 3518 datasetButtonLast = document.getElementById('lastDataset'); | |
| 3519 datasetButtonPrev = document.getElementById('prevDataset'); | |
| 3520 datasetButtonNext = document.getElementById('nextDataset'); | |
| 3521 rankDropDown = document.getElementById('ranks'); | |
| 3522 if (chart === ChartEnum.GENOMIC) { | |
| 3523 for (i = 1; i < 10; i++) { | |
| 3524 rankDropDown.remove(1); // Remove taxonomic ranks from options | |
| 3525 } | |
| 3526 datasetDropDown.style.color='#FFFFFF' | |
| 3527 datasetDropDown.style.backgroundColor='#555555' // #B20DFF22' | |
| 3528 } | |
| 3529 position += datasetDropDown.clientHeight; | |
| 3530 } | |
| 3531 | |
| 3532 position = addOptionElement | |
| 3533 ( | |
| 3534 position + 5, | |
| 3535 '<input type="button" id="maxAbsoluteDepthDecrease" style="margin:1px 4px 0 10px" value="-"/>\ | |
| 3536 <span id="maxAbsoluteDepth"></span>\ | |
| 3537 <input type="button" id="maxAbsoluteDepthIncrease" style="margin:2px 1px 0 2px" value="+"/> Max depth', | |
| 3538 'Maximum depth to display, counted from the top level \ | |
| 3539 and including collapsed wedges.' | |
| 3540 ); | |
| 3541 | |
| 3542 position = addOptionElement | |
| 3543 ( | |
| 3544 position, | |
| 3545 '<input type="button" id="fontSizeDecrease" style="margin:0 4px 0 10px" value="-"/>\ | |
| 3546 <span id="fontSize"></span>\ | |
| 3547 <input type="button" id="fontSizeIncrease" style="margin:0 2px 0 2px" value="+"/> Font size' | |
| 3548 ); | |
| 3549 | |
| 3550 position = addOptionElement | |
| 3551 ( | |
| 3552 position, | |
| 3553 '<input type="button" id="radiusDecrease" style="margin:0 4px 0 10px" value="-"/>\ | |
| 3554 <input type="button" id="radiusIncrease" style="margin:0 2px 0 1px" value="+"/> Chart size' | |
| 3555 ); | |
| 3556 | |
| 3557 position = addOptionElement | |
| 3558 ( | |
| 3559 position, | |
| 3560 '<input type="button" id="bkgBrightDecrease" style="margin:0 4px 5px 10px" value="-"/>\ | |
| 3561 <input type="button" id="bkgBrightIncrease" style="margin:0 2px 5px 1px" value="+"/> Bkg bright' | |
| 3562 ); | |
| 3563 | |
| 3564 if (hueName) { | |
| 3565 hueDisplayName = attributes[attributeIndex(hueName)].displayName; | |
| 3566 | |
| 3567 position = addOptionElement | |
| 3568 ( | |
| 3569 position + 5, | |
| 3570 '<input type="checkbox" id="useHue" style="float:left; ' + | |
| 3571 'margin:1px 4px 0 12px"/><div>Color by ' + hueDisplayName + | |
| 3572 '</div>' | |
| 3573 ); | |
| 3574 | |
| 3575 useHueCheckBox = document.getElementById('useHue'); | |
| 3576 useHueCheckBox.checked = hueDefault; | |
| 3577 useHueCheckBox.onclick = handleResize; | |
| 3578 useHueCheckBox.onmousedown = suppressEvent; | |
| 3579 | |
| 3580 position = addOptionElement | |
| 3581 ( | |
| 3582 position, | |
| 3583 '<input type="checkbox" id="sortByScore"/> Use to sort', | |
| 3584 'Activates sorting the taxa by this magnitude', | |
| 3585 '0px 2px 2px 25px' | |
| 3586 ); | |
| 3587 | |
| 3588 sortByScoreCheckBox = document.getElementById('sortByScore'); | |
| 3589 sortByScoreCheckBox.onclick = onSortChange; | |
| 3590 sortByScoreCheckBox.onmousedown = suppressEvent; | |
| 3591 } | |
| 3592 | |
| 3593 position = addOptionElement | |
| 3594 ( | |
| 3595 position, | |
| 3596 '<input type="checkbox" id="collapse" style="margin:4px 4px 0 12px" ' + | |
| 3597 'checked="checked"/>Collapse', | |
| 3598 'Collapse wedges that are redundant (entirely composed of another ' + | |
| 3599 'wedge). Also affects score navigation, restricting to lowest level.' | |
| 3600 ); | |
| 3601 | |
| 3602 /* | |
| 3603 position = addOptionElement | |
| 3604 ( | |
| 3605 position, | |
| 3606 ' <input type="checkbox" id="shorten" checked="checked" />Shorten labels</div>', | |
| 3607 'Prevent labels from overlapping by shortening them' | |
| 3608 ); | |
| 3609 | |
| 3610 position = addOptionElement | |
| 3611 ( | |
| 3612 position, | |
| 3613 ' <input type="checkbox" id="compress" checked="checked" />Compress', | |
| 3614 'Compress wedges if needed to show the entire depth' | |
| 3615 ); | |
| 3616 */ | |
| 3617 | |
| 3618 position = addOptionElement | |
| 3619 ( | |
| 3620 position, | |
| 3621 '<input type="button" id="snapshot" style="margin:5px 2px 0 10px"\ | |
| 3622 value="Snapshot" title="Render the current view as SVG (Scalable \ | |
| 3623 Vector Graphics), a vectorial publication-quality format that can be saved or \ | |
| 3624 printed as PDF"/> <input type="button" id="help" value="?"\ | |
| 3625 onclick="window.open(\'https://github.com/khyox/recentrifuge/wiki\',\ | |
| 3626 \'help\')" title="Help"/>'); | |
| 3627 | |
| 3628 position = addOptionElement | |
| 3629 ( | |
| 3630 position + 5, | |
| 3631 '<input type="button" id="linkButton" style="margin:5px 2px 0 10px" value="Link"/>\ | |
| 3632 <input type="text" size="30" id="linkText"/>', | |
| 3633 'Show a link to this view that can be copied for bookmarking or sharing' | |
| 3634 ); | |
| 3635 } | |
| 3636 | |
| 3637 function arrow(angleStart, angleEnd, radiusInner) { | |
| 3638 if (context.globalAlpha == 0) { | |
| 3639 return; | |
| 3640 } | |
| 3641 | |
| 3642 var angleCenter = (angleStart + angleEnd) / 2; | |
| 3643 var radiusArrowInner = radiusInner - gRadius / 10;//nodeRadius * gRadius; | |
| 3644 var radiusArrowOuter = gRadius * 1.1;//(1 + nodeRadius); | |
| 3645 var radiusArrowCenter = (radiusArrowInner + radiusArrowOuter) / 2; | |
| 3646 var pointLength = (radiusArrowOuter - radiusArrowInner) / 5; | |
| 3647 | |
| 3648 context.fillStyle = highlightFill; | |
| 3649 context.lineWidth = highlightLineWidth; | |
| 3650 | |
| 3651 // First, mask out the first half of the arrow. This will prevent the tips | |
| 3652 // from superimposing if the arrow goes most of the way around the circle. | |
| 3653 // Masking is done by setting the clipping region to the inverse of the | |
| 3654 // half-arrow, which is defined by cutting the half-arrow out of a large | |
| 3655 // rectangle | |
| 3656 // | |
| 3657 context.beginPath(); | |
| 3658 context.arc(0, 0, radiusInner, angleCenter, angleEnd, false); | |
| 3659 context.lineTo | |
| 3660 ( | |
| 3661 radiusArrowInner * Math.cos(angleEnd), | |
| 3662 radiusArrowInner * Math.sin(angleEnd) | |
| 3663 ); | |
| 3664 context.lineTo | |
| 3665 ( | |
| 3666 radiusArrowCenter * Math.cos(angleEnd) | |
| 3667 - pointLength * Math.sin(angleEnd), | |
| 3668 radiusArrowCenter * Math.sin(angleEnd) | |
| 3669 + pointLength * Math.cos(angleEnd) | |
| 3670 ); | |
| 3671 context.lineTo | |
| 3672 ( | |
| 3673 radiusArrowOuter * Math.cos(angleEnd), | |
| 3674 radiusArrowOuter * Math.sin(angleEnd) | |
| 3675 ); | |
| 3676 context.arc(0, 0, gRadius, angleEnd, angleCenter, true); | |
| 3677 context.closePath(); | |
| 3678 context.moveTo(-imageWidth, -imageHeight); | |
| 3679 context.lineTo(imageWidth, -imageHeight); | |
| 3680 context.lineTo(imageWidth, imageHeight); | |
| 3681 context.lineTo(-imageWidth, imageHeight); | |
| 3682 context.closePath(); | |
| 3683 context.save(); | |
| 3684 context.clip(); | |
| 3685 | |
| 3686 // Next, draw the other half-arrow with the first half masked out | |
| 3687 // | |
| 3688 context.beginPath(); | |
| 3689 context.arc(0, 0, radiusInner, angleCenter, angleStart, true); | |
| 3690 context.lineTo | |
| 3691 ( | |
| 3692 radiusArrowInner * Math.cos(angleStart), | |
| 3693 radiusArrowInner * Math.sin(angleStart) | |
| 3694 ); | |
| 3695 context.lineTo | |
| 3696 ( | |
| 3697 radiusArrowCenter * Math.cos(angleStart) | |
| 3698 + pointLength * Math.sin(angleStart), | |
| 3699 radiusArrowCenter * Math.sin(angleStart) | |
| 3700 - pointLength * Math.cos(angleStart) | |
| 3701 ); | |
| 3702 context.lineTo | |
| 3703 ( | |
| 3704 radiusArrowOuter * Math.cos(angleStart), | |
| 3705 radiusArrowOuter * Math.sin(angleStart) | |
| 3706 ); | |
| 3707 context.arc(0, 0, gRadius, angleStart, angleCenter, false); | |
| 3708 context.fill(); | |
| 3709 context.stroke(); | |
| 3710 | |
| 3711 // Finally, remove the clipping region and draw the first half-arrow. This | |
| 3712 // half is extended slightly to fill the seam. | |
| 3713 // | |
| 3714 context.restore(); | |
| 3715 context.beginPath(); | |
| 3716 context.arc(0, 0, radiusInner, angleCenter | |
| 3717 - 2 / (2 * Math.PI * radiusInner), angleEnd, false); | |
| 3718 context.lineTo | |
| 3719 ( | |
| 3720 radiusArrowInner * Math.cos(angleEnd), | |
| 3721 radiusArrowInner * Math.sin(angleEnd) | |
| 3722 ); | |
| 3723 context.lineTo | |
| 3724 ( | |
| 3725 radiusArrowCenter * Math.cos(angleEnd) | |
| 3726 - pointLength * Math.sin(angleEnd), | |
| 3727 radiusArrowCenter * Math.sin(angleEnd) | |
| 3728 + pointLength * Math.cos(angleEnd) | |
| 3729 ); | |
| 3730 context.lineTo | |
| 3731 ( | |
| 3732 radiusArrowOuter * Math.cos(angleEnd), | |
| 3733 radiusArrowOuter * Math.sin(angleEnd) | |
| 3734 ); | |
| 3735 context.arc(0, 0, gRadius, angleEnd, angleCenter - 2 | |
| 3736 / (2 * Math.PI * gRadius), true); | |
| 3737 context.fill(); | |
| 3738 context.stroke(); | |
| 3739 } | |
| 3740 | |
| 3741 function attributeIndex(aname) { | |
| 3742 for (var i = 0; i < attributes.length; i++) { | |
| 3743 if (aname == attributes[i].name) { | |
| 3744 return i; | |
| 3745 } | |
| 3746 } | |
| 3747 | |
| 3748 return null; | |
| 3749 } | |
| 3750 | |
| 3751 function bkgBrightDecrease() { | |
| 3752 var bkgBrightInt = parseInt(bkgBright, 16) | |
| 3753 if (bkgBrightInt > parseInt('555555', 16)) { | |
| 3754 bkgBright = (bkgBrightInt - 0x111111).toString(16) | |
| 3755 document.body.style.backgroundColor = '#' + bkgBright | |
| 3756 updateViewNeeded = true; | |
| 3757 } | |
| 3758 } | |
| 3759 | |
| 3760 function bkgBrightIncrease() { | |
| 3761 var bkgBrightInt = parseInt(bkgBright, 16) | |
| 3762 if (bkgBrightInt < parseInt('ffffff', 16)) { | |
| 3763 bkgBright = (bkgBrightInt + 0x111111).toString(16) | |
| 3764 document.body.style.backgroundColor = '#' + bkgBright | |
| 3765 updateViewNeeded = true; | |
| 3766 } | |
| 3767 } | |
| 3768 | |
| 3769 function checkHighlight() { | |
| 3770 var lastHighlightedNode = highlightedNode; | |
| 3771 var lastHighlightingHidden = highlightingHidden; | |
| 3772 | |
| 3773 highlightedNode = selectedNode; | |
| 3774 resetKeyOffset(); | |
| 3775 | |
| 3776 if (progress == 1) { | |
| 3777 selectedNode.checkHighlight(); | |
| 3778 if (selectedNode.getParent()) { | |
| 3779 selectedNode.getParent().checkHighlightCenter(); | |
| 3780 } | |
| 3781 | |
| 3782 focusNode.checkHighlightMap(); | |
| 3783 } | |
| 3784 | |
| 3785 if (highlightedNode != selectedNode) { | |
| 3786 if (highlightedNode == focusNode) { | |
| 3787 // canvas.style.display='none'; | |
| 3788 // window.resizeBy(1,0); | |
| 3789 // canvas.style.cursor='ew-resize'; | |
| 3790 // window.resizeBy(-1,0); | |
| 3791 // canvas.style.display='inline'; | |
| 3792 } | |
| 3793 else { | |
| 3794 // canvas.style.cursor='pointer'; | |
| 3795 } | |
| 3796 } | |
| 3797 else { | |
| 3798 // canvas.style.cursor='auto'; | |
| 3799 } | |
| 3800 | |
| 3801 if | |
| 3802 ( | |
| 3803 ( | |
| 3804 true || | |
| 3805 highlightedNode != lastHighlightedNode || | |
| 3806 highlightingHidden != highlightingHiddenLast | |
| 3807 ) && | |
| 3808 progress == 1 | |
| 3809 ) { | |
| 3810 draw(); // TODO: handle in update() | |
| 3811 } | |
| 3812 } | |
| 3813 | |
| 3814 function checkSelectedCollapse() { | |
| 3815 var newNode = selectedNode; | |
| 3816 | |
| 3817 while (newNode.getCollapse()) { | |
| 3818 newNode = newNode.children[0]; | |
| 3819 } | |
| 3820 | |
| 3821 if (newNode.children.length == 0 && newNode.getParent()) { | |
| 3822 newNode = newNode.getParent(); | |
| 3823 } | |
| 3824 | |
| 3825 if (newNode != selectedNode) { | |
| 3826 selectNode(newNode); | |
| 3827 } | |
| 3828 } | |
| 3829 | |
| 3830 function clearSearch() { | |
| 3831 if (search.value != '') { | |
| 3832 search.value = ''; | |
| 3833 nodesIndex = undefined; | |
| 3834 onSearchChange(); | |
| 3835 } | |
| 3836 } | |
| 3837 | |
| 3838 function createSVG() { | |
| 3839 svgNS = "http://www.w3.org/2000/svg"; | |
| 3840 var SVG = {}; | |
| 3841 SVG.xlinkns = "http://www.w3.org/1999/xlink"; | |
| 3842 | |
| 3843 var newSVG = document.createElementNS(svgNS, "svg:svg"); | |
| 3844 | |
| 3845 newSVG.setAttribute("id", "canvas"); | |
| 3846 // How big is the canvas in pixels | |
| 3847 newSVG.setAttribute("width", '100%'); | |
| 3848 newSVG.setAttribute("height", '100%'); | |
| 3849 // Set the coordinates used by drawings in the canvas | |
| 3850 // newSVG.setAttribute("viewBox", "0 0 " + imageWidth + " " + imageHeight); | |
| 3851 // Define the XLink namespace that SVG uses | |
| 3852 newSVG.setAttributeNS | |
| 3853 ( | |
| 3854 "http://www.w3.org/2000/xmlns/", | |
| 3855 "xmlns:xlink", | |
| 3856 SVG.xlinkns | |
| 3857 ); | |
| 3858 | |
| 3859 return newSVG; | |
| 3860 } | |
| 3861 | |
| 3862 function degrees(radians) { | |
| 3863 return radians * 180 / Math.PI; | |
| 3864 } | |
| 3865 | |
| 3866 function draw() { | |
| 3867 tweenFrames++; | |
| 3868 //resize(); | |
| 3869 // context.fillRect(0, 0, imageWidth, imageHeight); | |
| 3870 context.clearRect(0, 0, imageWidth, imageHeight); | |
| 3871 | |
| 3872 context.font = fontNormal; | |
| 3873 context.textBaseline = 'middle'; | |
| 3874 | |
| 3875 //context.strokeStyle = 'rgba(0, 0, 0, 0.3)'; | |
| 3876 context.translate(centerX, centerY); | |
| 3877 | |
| 3878 resetKeyOffset(); | |
| 3879 | |
| 3880 head.draw(false, false); // draw pie slices | |
| 3881 head.draw(true, false); // draw labels | |
| 3882 | |
| 3883 var pathRoot = selectedNode; | |
| 3884 | |
| 3885 if (focusNode != 0 && focusNode != selectedNode) { | |
| 3886 context.globalAlpha = 1; | |
| 3887 focusNode.drawHighlight(true); | |
| 3888 pathRoot = focusNode; | |
| 3889 } | |
| 3890 | |
| 3891 if | |
| 3892 ( | |
| 3893 highlightedNode && | |
| 3894 highlightedNode.getDepth() >= selectedNode.getDepth() && | |
| 3895 highlightedNode != focusNode | |
| 3896 ) { | |
| 3897 if | |
| 3898 ( | |
| 3899 progress == 1 && | |
| 3900 highlightedNode != selectedNode && | |
| 3901 ( | |
| 3902 highlightedNode != focusNode || | |
| 3903 focusNode.children.length > 0 | |
| 3904 ) | |
| 3905 ) { | |
| 3906 context.globalAlpha = 1; | |
| 3907 highlightedNode.drawHighlight(true); | |
| 3908 } | |
| 3909 | |
| 3910 //pathRoot = highlightedNode; | |
| 3911 } | |
| 3912 else if | |
| 3913 ( | |
| 3914 progress == 1 && | |
| 3915 highlightedNode.getDepth() < selectedNode.getDepth() | |
| 3916 ) { | |
| 3917 context.globalAlpha = 1; | |
| 3918 highlightedNode.drawHighlightCenter(); | |
| 3919 } | |
| 3920 | |
| 3921 if (quickLook && false) // TEMP | |
| 3922 { | |
| 3923 context.globalAlpha = 1 - progress / 2; | |
| 3924 selectedNode.drawHighlight(true); | |
| 3925 } | |
| 3926 else if (progress < 1)//&& zoomOut() ) | |
| 3927 { | |
| 3928 if (!zoomOut)//() ) | |
| 3929 { | |
| 3930 context.globalAlpha = selectedNode.alphaLine.current(); | |
| 3931 selectedNode.drawHighlight(true); | |
| 3932 } | |
| 3933 else if (selectedNodeLast) { | |
| 3934 context.globalAlpha = 1 - 4 * Math.pow(progress - .5, 2); | |
| 3935 selectedNodeLast.drawHighlight(false); | |
| 3936 } | |
| 3937 } | |
| 3938 | |
| 3939 drawDatasetName(); | |
| 3940 | |
| 3941 //drawHistory(); | |
| 3942 | |
| 3943 context.translate(-centerX, -centerY); | |
| 3944 context.globalAlpha = 1; | |
| 3945 | |
| 3946 mapRadius = | |
| 3947 (imageHeight / 2 - details.clientHeight - details.offsetTop) / | |
| 3948 (pathRoot.getDepth() - 1) * 3 / 4 / 2; | |
| 3949 | |
| 3950 if (mapRadius > maxMapRadius) { | |
| 3951 mapRadius = maxMapRadius; | |
| 3952 } | |
| 3953 | |
| 3954 mapBuffer = mapRadius / 2; | |
| 3955 | |
| 3956 //context.font = fontNormal; | |
| 3957 pathRoot.drawMap(pathRoot); | |
| 3958 | |
| 3959 if (hueDisplayName && useHue()) { | |
| 3960 drawLegend(); | |
| 3961 } | |
| 3962 } | |
| 3963 | |
| 3964 function drawBubble(angle, radius, width, radial, flip) { | |
| 3965 var height = fontSize * 2; | |
| 3966 var x; | |
| 3967 var y; | |
| 3968 | |
| 3969 width = width + fontSize; | |
| 3970 | |
| 3971 if (radial) { | |
| 3972 y = -fontSize; | |
| 3973 | |
| 3974 if (flip) { | |
| 3975 x = radius - width + fontSize / 2; | |
| 3976 } | |
| 3977 else { | |
| 3978 x = radius - fontSize / 2; | |
| 3979 } | |
| 3980 } | |
| 3981 else { | |
| 3982 x = -width / 2; | |
| 3983 y = -radius - fontSize; | |
| 3984 } | |
| 3985 | |
| 3986 if (snapshotMode) { | |
| 3987 drawBubbleSVG(x + centerX, y + centerY, width, height, fontSize, angle); | |
| 3988 } | |
| 3989 else { | |
| 3990 drawBubbleCanvas(x, y, width, height, fontSize, angle); | |
| 3991 } | |
| 3992 } | |
| 3993 | |
| 3994 function drawBubbleCanvas(x, y, width, height, radius, rotation) { | |
| 3995 context.strokeStyle = 'black'; | |
| 3996 context.lineWidth = highlightLineWidth; | |
| 3997 context.fillStyle = 'rgba(255, 255, 255, .75)'; | |
| 3998 context.rotate(rotation); | |
| 3999 roundedRectangle(x, y, width, fontSize * 2, fontSize); | |
| 4000 context.fill(); | |
| 4001 context.stroke(); | |
| 4002 context.rotate(-rotation); | |
| 4003 } | |
| 4004 | |
| 4005 function drawBubbleSVG(x, y, width, height, radius, rotation) { | |
| 4006 svg += | |
| 4007 '<rect x="' + x + '" y="' + y + | |
| 4008 '" width="' + width + | |
| 4009 '" height="' + height + | |
| 4010 '" rx="' + radius + | |
| 4011 '" ry="' + radius + | |
| 4012 '" fill="rgba(255, 255, 255, .75)' + | |
| 4013 '" class="highlight" ' + | |
| 4014 'transform="rotate(' + | |
| 4015 degrees(rotation) + ',' + centerX + ',' + centerY + | |
| 4016 ')"/>'; | |
| 4017 } | |
| 4018 | |
| 4019 function drawDatasetName() { | |
| 4020 var alpha = datasetAlpha.current(); | |
| 4021 | |
| 4022 if (alpha > 0) { | |
| 4023 var radius = gRadius * compressedRadii[0] / -2; | |
| 4024 | |
| 4025 if (alpha > 1) { | |
| 4026 alpha = 1; | |
| 4027 } | |
| 4028 | |
| 4029 context.globalAlpha = alpha; | |
| 4030 | |
| 4031 drawBubble(0, -radius, datasetWidths[currentDataset], false, false); | |
| 4032 drawText(datasetNames[currentDataset], 0, radius, 0, 'center', true); | |
| 4033 } | |
| 4034 } | |
| 4035 | |
| 4036 function drawHistory() { | |
| 4037 var alpha = 1; | |
| 4038 context.textAlign = 'center'; | |
| 4039 | |
| 4040 for (var i = 0; i < nodeHistoryPosition && alpha > 0; i++) { | |
| 4041 | |
| 4042 context.globalAlpha = alpha - historyAlphaDelta * tweenFactor; | |
| 4043 context.fillText | |
| 4044 ( | |
| 4045 nodeHistory[nodeHistoryPosition - i - 1].name, | |
| 4046 0, | |
| 4047 (i + tweenFactor) * historySpacingFactor * fontSize - 1 | |
| 4048 ); | |
| 4049 | |
| 4050 if (alpha > 0) { | |
| 4051 alpha -= historyAlphaDelta; | |
| 4052 } | |
| 4053 } | |
| 4054 | |
| 4055 context.globalAlpha = 1; | |
| 4056 } | |
| 4057 | |
| 4058 function drawLegend() { | |
| 4059 var width = imageHeight * .0265; | |
| 4060 var side = width * 0.9 | |
| 4061 var left_buttons = imageWidth * .008; | |
| 4062 var left = left_buttons + side + fontSize; | |
| 4063 var height = imageHeight * .15; | |
| 4064 var top = imageHeight - fontSize * 3.5 - height; | |
| 4065 var textLeft = left + width + fontSize / 2; | |
| 4066 var delta = (height - side) / 3; | |
| 4067 | |
| 4068 canvasButtons = [] // Delete previous buttons | |
| 4069 var buttonMost = new CanvasButton('mostScore', left_buttons, | |
| 4070 top, side, side, '#c87cca'); | |
| 4071 var buttonLest = new CanvasButton('lestScore', left_buttons, | |
| 4072 top + 3 * delta, side, side, '#d38381'); | |
| 4073 canvasButtons.push(buttonMost, buttonLest); | |
| 4074 if (nodesIndex !== undefined) { | |
| 4075 var buttonMore = new CanvasButton('moreScore', left_buttons, | |
| 4076 top + delta, side, side, '#81c8d3'); | |
| 4077 var buttonLess = new CanvasButton('lessScore', left_buttons, | |
| 4078 top + 2 * delta, side, side, '#96d281'); | |
| 4079 canvasButtons.push(buttonMore, buttonLess) | |
| 4080 } | |
| 4081 canvasButtons.forEach(function (element) { | |
| 4082 element.draw(context); | |
| 4083 }); | |
| 4084 context.fillStyle = 'black'; | |
| 4085 context.textAlign = 'start'; | |
| 4086 context.font = fontNormal; | |
| 4087 context.fillText(hueDisplayName, left_buttons, imageHeight - fontSize * 1.5); | |
| 4088 | |
| 4089 var gradient = context.createLinearGradient(0, top + height, 0, top); | |
| 4090 | |
| 4091 for (var i = 0; i < hueStopPositions.length; i++) { | |
| 4092 gradient.addColorStop(hueStopPositions[i], hueStopHsl[i]); | |
| 4093 | |
| 4094 var textY = top + (1 - hueStopPositions[i]) * height; | |
| 4095 | |
| 4096 if | |
| 4097 ( | |
| 4098 i === 0 || | |
| 4099 i === hueStopPositions.length - 1 || | |
| 4100 textY > top + fontSize && textY < top + height - fontSize | |
| 4101 ) { | |
| 4102 context.fillText(hueStopText[i], textLeft, textY); | |
| 4103 } | |
| 4104 } | |
| 4105 | |
| 4106 context.fillStyle = gradient; | |
| 4107 context.fillRect(left, top, width, height); | |
| 4108 context.lineWidth = thinLineWidth; | |
| 4109 context.strokeRect(left, top, width, height); | |
| 4110 | |
| 4111 // Sample statistics | |
| 4112 if (currentDataset < numRawSamples) { | |
| 4113 var stat = stats[currentDataset]; | |
| 4114 // Define aux position variables | |
| 4115 var statsX = textLeft + 2 * width; | |
| 4116 var statsY = top; | |
| 4117 var rad = width; | |
| 4118 context.font = "Bold 11px Ubuntu"; | |
| 4119 var statLabelText; | |
| 4120 if (chart === ChartEnum.GENOMIC) { | |
| 4121 context.fillStyle = 'rgba(170, 20, 255, 1)'; | |
| 4122 statLabelText = 'Functional sample statistics'; | |
| 4123 } else if (stat.is_ctrl) { | |
| 4124 context.fillStyle = 'rgba(50, 50, 200, 1)'; | |
| 4125 statLabelText = 'Control statistics'; | |
| 4126 } else { | |
| 4127 context.fillStyle = 'rgba(200, 50, 50, 1)'; | |
| 4128 statLabelText = 'Sample statistics'; | |
| 4129 } | |
| 4130 context.fillText(statLabelText, statsX + width, | |
| 4131 imageHeight - fontSize * 1.5); | |
| 4132 // Get the set of strings | |
| 4133 var oldFont = context.font; | |
| 4134 context.font = "10.5px monospace"; // In case the next line fails | |
| 4135 context.font = "10.5px Oxygen Mono"; | |
| 4136 var readTit; | |
| 4137 var nodeTit; | |
| 4138 if (chart === ChartEnum.GENOMIC) { | |
| 4139 readTit = 'Annotations read: ' | |
| 4140 nodeTit = 'GOs' | |
| 4141 } else { | |
| 4142 readTit = 'Sequences read: ' | |
| 4143 nodeTit = 'TaxIDs' | |
| 4144 } | |
| 4145 var statsStrs = [ | |
| 4146 readTit + stat.sread, | |
| 4147 ' those classified: ' + ( | |
| 4148 stat.sclas / stat.sread * 100).toPrecision(3) + '%', | |
| 4149 ' those accepted: ' | |
| 4150 + (stat.sfilt / stat.sclas * 100).toPrecision(3) + '%', | |
| 4151 'Score average: ' + parseFloat(stat.scavg).toFixed(1), | |
| 4152 ' min: ' + parseFloat(stat.scmin).toFixed(1) + | |
| 4153 ' max: ' + parseFloat(stat.scmax).toFixed(1), | |
| 4154 'Length average: ' + stat.lnavg, | |
| 4155 ' min: ' + stat.lnmin + ' max: ' + stat.lnmax, | |
| 4156 nodeTit + ' by classifier: ' + stat.tclas, | |
| 4157 ' those accepted: ' + | |
| 4158 (stat.tfilt / stat.tclas * 100).toPrecision(3) + '%', | |
| 4159 ' final: ' + | |
| 4160 (stat.tfold / stat.tfilt * 100).toPrecision(3) + '% [' | |
| 4161 + stat.tfold + ']' | |
| 4162 ]; | |
| 4163 var maxTextWidth = Math.max.apply(null, statsStrs.map(function (text) { | |
| 4164 return context.measureText(text).width | |
| 4165 })); | |
| 4166 // Draw the rounded rectangle | |
| 4167 context.lineWidth = 3; | |
| 4168 if (chart === ChartEnum.GENOMIC) { | |
| 4169 context.strokeStyle = '#B20DFF'; | |
| 4170 context.fillStyle = 'rgba(180, 100, 255, 0.2)'; | |
| 4171 } else if (stat.is_ctrl) { | |
| 4172 context.strokeStyle = '#3333CC'; | |
| 4173 context.fillStyle = 'rgba(0, 255, 255, 0.2)'; | |
| 4174 } else { | |
| 4175 context.strokeStyle = '#CC3333'; | |
| 4176 context.fillStyle = 'rgba(255, 255, 0, 0.2)'; | |
| 4177 } | |
| 4178 var box = new roundedRectangle( | |
| 4179 statsX, statsY, 1.2 * maxTextWidth, height, {tr: rad, bl: rad}); | |
| 4180 context.stroke(); | |
| 4181 context.fill(); | |
| 4182 context.fillStyle = context.strokeStyle = '#222222'; | |
| 4183 // Write the stats inside | |
| 4184 var statsNum = statsStrs.length; | |
| 4185 var statsLeft = statsX + maxTextWidth * 0.1; | |
| 4186 var statsDelta = height / (statsNum + 1); | |
| 4187 for (i = 0; i < statsNum; i++) { | |
| 4188 context.fillText(statsStrs[i], | |
| 4189 statsLeft, top + i * statsDelta + fontSize); | |
| 4190 } | |
| 4191 // Restore font | |
| 4192 context.font = oldFont; | |
| 4193 } | |
| 4194 } | |
| 4195 | |
| 4196 function drawLegendSVG() { | |
| 4197 var left = imageWidth * .01; | |
| 4198 var width = imageHeight * .0265; | |
| 4199 var height = imageHeight * .15; | |
| 4200 var top = imageHeight - fontSize * 3.5 - height; | |
| 4201 var textLeft = left + width + fontSize / 2; | |
| 4202 | |
| 4203 var text = ''; | |
| 4204 | |
| 4205 text += svgText(hueDisplayName, left, imageHeight - fontSize * 1.5); | |
| 4206 | |
| 4207 var svgtest = | |
| 4208 '<linearGradient id="gradient" x1="0%" y1="100%" x2="0%" y2="0%">'; | |
| 4209 | |
| 4210 for (var i = 0; i < hueStopPositions.length; i++) { | |
| 4211 svgtest += | |
| 4212 '<stop offset="' + round(hueStopPositions[i] * 100) + | |
| 4213 '%" style="stop-color:' + hueStopHsl[i] + '"/>'; | |
| 4214 | |
| 4215 var textY = top + (1 - hueStopPositions[i]) * height; | |
| 4216 | |
| 4217 if | |
| 4218 ( | |
| 4219 i == 0 || | |
| 4220 i == hueStopPositions.length - 1 || | |
| 4221 textY > top + fontSize && textY < top + height - fontSize | |
| 4222 ) { | |
| 4223 text += svgText(hueStopText[i], textLeft, textY); | |
| 4224 } | |
| 4225 } | |
| 4226 | |
| 4227 svgtest += '</linearGradient>'; | |
| 4228 //alert(svgtest); | |
| 4229 svg += svgtest; | |
| 4230 svg += | |
| 4231 '<rect style="fill:url(#gradient)" x="' + left + '" y="' + top + | |
| 4232 '" width="' + width + '" height="' + height + '"/>'; | |
| 4233 | |
| 4234 svg += text; | |
| 4235 } | |
| 4236 | |
| 4237 function drawSearchHighlights(label, bubbleX, bubbleY, rotation, center) { | |
| 4238 var index = -1; | |
| 4239 var labelLength = label.length; | |
| 4240 | |
| 4241 bubbleX -= fontSize / 4; | |
| 4242 | |
| 4243 do { | |
| 4244 index = label.toLowerCase().indexOf(search.value.toLowerCase(), | |
| 4245 index + 1); | |
| 4246 | |
| 4247 if (index != -1 && index < labelLength) { | |
| 4248 var dim = context.measureText(label.substr(0, index)); | |
| 4249 var x = bubbleX + dim.width; | |
| 4250 | |
| 4251 dim = context.measureText(label.substr(index, search.value.length)); | |
| 4252 | |
| 4253 var y = bubbleY - fontSize * 3 / 4; | |
| 4254 var width = dim.width + fontSize / 2; | |
| 4255 var height = fontSize * 3 / 2; | |
| 4256 var radius = fontSize / 2; | |
| 4257 | |
| 4258 if (snapshotMode) { | |
| 4259 if (center) { | |
| 4260 x += centerX; | |
| 4261 y += centerY; | |
| 4262 } | |
| 4263 | |
| 4264 svg += | |
| 4265 '<rect x="' + x + '" y="' + y + | |
| 4266 '" width="' + width + | |
| 4267 '" height="' + height + | |
| 4268 '" rx="' + radius + | |
| 4269 '" ry="' + radius + | |
| 4270 '" class="searchHighlight' + | |
| 4271 '" transform="rotate(' + | |
| 4272 degrees(rotation) + ',' + centerX + ',' + centerY + | |
| 4273 ')"/>'; | |
| 4274 } | |
| 4275 else { | |
| 4276 context.fillStyle = 'rgb(255, 255, 100)'; | |
| 4277 context.rotate(rotation); | |
| 4278 roundedRectangle(x, y, width, height, radius); | |
| 4279 context.fill(); | |
| 4280 context.rotate(-rotation); | |
| 4281 } | |
| 4282 } | |
| 4283 } | |
| 4284 while (index != -1 && index < labelLength); | |
| 4285 } | |
| 4286 | |
| 4287 function drawText(text, x, y, angle, anchor, bold, color) { | |
| 4288 if (color == undefined) { | |
| 4289 color = 'black'; | |
| 4290 } | |
| 4291 | |
| 4292 if (snapshotMode) { | |
| 4293 svg += | |
| 4294 '<text x="' + (centerX + x) + '" y="' + (centerY + y) + | |
| 4295 '" text-anchor="' + anchor + '" style="font-color:' + color | |
| 4296 + ';font-weight:' + (bold ? 'bold' : 'normal') + | |
| 4297 '" transform="rotate(' + degrees(angle) + ',' + centerX | |
| 4298 + ',' + centerY + ')">' + | |
| 4299 text + '</text>'; | |
| 4300 } | |
| 4301 else { | |
| 4302 context.fillStyle = color; | |
| 4303 context.textAlign = anchor; | |
| 4304 context.font = bold ? fontBold : fontNormal; | |
| 4305 context.rotate(angle); | |
| 4306 context.fillText(text, x, y); | |
| 4307 context.rotate(-angle); | |
| 4308 } | |
| 4309 } | |
| 4310 | |
| 4311 function drawTextPolar | |
| 4312 (text, | |
| 4313 innerText, | |
| 4314 angle, | |
| 4315 radius, | |
| 4316 radial, | |
| 4317 bubble, | |
| 4318 bold, | |
| 4319 searchResult, | |
| 4320 searchResults) { | |
| 4321 var anchor; | |
| 4322 var textX; | |
| 4323 var textY; | |
| 4324 var spacer; | |
| 4325 var totalText = text; | |
| 4326 var flip; | |
| 4327 | |
| 4328 if (snapshotMode) { | |
| 4329 spacer = '   '; | |
| 4330 } | |
| 4331 else { | |
| 4332 spacer = ' '; | |
| 4333 } | |
| 4334 | |
| 4335 if (radial) { | |
| 4336 flip = angle < 3 * Math.PI / 2; | |
| 4337 | |
| 4338 if (flip) { | |
| 4339 angle -= Math.PI; | |
| 4340 radius = -radius; | |
| 4341 anchor = 'end'; | |
| 4342 | |
| 4343 if (innerText) { | |
| 4344 totalText = text + spacer + innerText; | |
| 4345 } | |
| 4346 } | |
| 4347 else { | |
| 4348 anchor = 'start'; | |
| 4349 | |
| 4350 if (innerText) { | |
| 4351 totalText = innerText + spacer + text; | |
| 4352 } | |
| 4353 } | |
| 4354 | |
| 4355 textX = radius; | |
| 4356 textY = 0; | |
| 4357 } | |
| 4358 else { | |
| 4359 flip = angle < Math.PI || angle > 2 * Math.PI; | |
| 4360 var label; | |
| 4361 | |
| 4362 anchor = snapshotMode ? 'middle' : 'center'; | |
| 4363 | |
| 4364 if (flip) { | |
| 4365 angle -= Math.PI; | |
| 4366 radius = -radius; | |
| 4367 } | |
| 4368 | |
| 4369 angle += Math.PI / 2; | |
| 4370 textX = 0; | |
| 4371 textY = -radius; | |
| 4372 } | |
| 4373 | |
| 4374 if (bubble) { | |
| 4375 var textActual = totalText; | |
| 4376 | |
| 4377 if (innerText && snapshotMode) { | |
| 4378 if (flip) { | |
| 4379 textActual = text + ' ' + innerText; | |
| 4380 } | |
| 4381 else { | |
| 4382 textActual = innerText + ' ' + text; | |
| 4383 } | |
| 4384 } | |
| 4385 | |
| 4386 if (searchResults) { | |
| 4387 textActual = textActual + searchResultString(searchResults); | |
| 4388 } | |
| 4389 | |
| 4390 var textWidth = measureText(textActual, bold); | |
| 4391 | |
| 4392 var x = textX; | |
| 4393 | |
| 4394 if (anchor == 'end') { | |
| 4395 x -= textWidth; | |
| 4396 } | |
| 4397 else if (anchor != 'start') { | |
| 4398 // centered | |
| 4399 x -= textWidth / 2; | |
| 4400 } | |
| 4401 | |
| 4402 drawBubble(angle, radius, textWidth, radial, flip); | |
| 4403 | |
| 4404 if (searchResult) { | |
| 4405 drawSearchHighlights | |
| 4406 ( | |
| 4407 textActual, | |
| 4408 x, | |
| 4409 textY, | |
| 4410 angle, | |
| 4411 true | |
| 4412 ) | |
| 4413 } | |
| 4414 } | |
| 4415 | |
| 4416 if (searchResults) { | |
| 4417 totalText = totalText + searchResultString(searchResults); | |
| 4418 } | |
| 4419 | |
| 4420 drawText(totalText, textX, textY, angle, anchor, bold); | |
| 4421 | |
| 4422 return flip; | |
| 4423 } | |
| 4424 | |
| 4425 function drawTick(start, length, angle) { | |
| 4426 if (snapshotMode) { | |
| 4427 svg += | |
| 4428 '<line x1="' + (centerX + start) + | |
| 4429 '" y1="' + centerY + | |
| 4430 '" x2="' + (centerX + start + length) + | |
| 4431 '" y2="' + centerY + | |
| 4432 '" class="tick" transform="rotate(' + | |
| 4433 degrees(angle) + ',' + centerX + ',' + centerY + | |
| 4434 ')"/>'; | |
| 4435 } | |
| 4436 else { | |
| 4437 context.rotate(angle); | |
| 4438 context.beginPath(); | |
| 4439 context.moveTo(start, 0); | |
| 4440 context.lineTo(start + length, 0); | |
| 4441 context.lineWidth = thinLineWidth * 2; | |
| 4442 context.stroke(); | |
| 4443 context.rotate(-angle); | |
| 4444 } | |
| 4445 } | |
| 4446 | |
| 4447 function drawWedge | |
| 4448 (angleStart, | |
| 4449 angleEnd, | |
| 4450 radiusInner, | |
| 4451 radiusOuter, | |
| 4452 color, | |
| 4453 patternAlpha, | |
| 4454 highlight) { | |
| 4455 if (context.globalAlpha == 0) { | |
| 4456 return; | |
| 4457 } | |
| 4458 | |
| 4459 if (snapshotMode) { | |
| 4460 if (angleEnd == angleStart + Math.PI * 2) { | |
| 4461 // fudge to prevent overlap, which causes arc ambiguity | |
| 4462 // | |
| 4463 angleEnd -= .1 / gRadius; | |
| 4464 } | |
| 4465 | |
| 4466 var longArc = angleEnd - angleStart > Math.PI ? 1 : 0; | |
| 4467 | |
| 4468 var x1 = centerX + radiusInner * Math.cos(angleStart); | |
| 4469 var y1 = centerY + radiusInner * Math.sin(angleStart); | |
| 4470 | |
| 4471 var x2 = centerX + gRadius * Math.cos(angleStart); | |
| 4472 var y2 = centerY + gRadius * Math.sin(angleStart); | |
| 4473 | |
| 4474 var x3 = centerX + gRadius * Math.cos(angleEnd); | |
| 4475 var y3 = centerY + gRadius * Math.sin(angleEnd); | |
| 4476 | |
| 4477 var x4 = centerX + radiusInner * Math.cos(angleEnd); | |
| 4478 var y4 = centerY + radiusInner * Math.sin(angleEnd); | |
| 4479 | |
| 4480 var dArray = | |
| 4481 [ | |
| 4482 " M ", x1, ",", y1, | |
| 4483 " L ", x2, ",", y2, | |
| 4484 " A ", gRadius, ",", gRadius, " 0 ", longArc, ",1 ", x3 | |
| 4485 , ",", y3, | |
| 4486 " L ", x4, ",", y4, | |
| 4487 " A ", radiusInner, ",", radiusInner, " 0 ", longArc, | |
| 4488 " 0 ", x1, ",", y1, | |
| 4489 " Z " | |
| 4490 ]; | |
| 4491 | |
| 4492 svg += | |
| 4493 '<path class="' + (highlight ? 'highlight' : 'wedge') | |
| 4494 + '" fill="' + color + | |
| 4495 '" d="' + dArray.join('') + '"/>'; | |
| 4496 | |
| 4497 if (patternAlpha > 0) { | |
| 4498 svg += | |
| 4499 '<path class="wedge" fill="url(#hiddenPattern)" d="' + | |
| 4500 dArray.join('') + '"/>'; | |
| 4501 } | |
| 4502 } | |
| 4503 else { | |
| 4504 // fudge to prevent seams during animation | |
| 4505 // | |
| 4506 angleEnd += 1 / gRadius; | |
| 4507 | |
| 4508 context.fillStyle = color; | |
| 4509 context.beginPath(); | |
| 4510 context.arc(0, 0, radiusInner, angleStart, angleEnd, false); | |
| 4511 context.arc(0, 0, radiusOuter, angleEnd, angleStart, true); | |
| 4512 context.closePath(); | |
| 4513 context.fill(); | |
| 4514 | |
| 4515 if (patternAlpha > 0) { | |
| 4516 context.save(); | |
| 4517 context.clip(); | |
| 4518 context.globalAlpha = patternAlpha; | |
| 4519 context.fillStyle = hiddenPattern; | |
| 4520 context.fill(); | |
| 4521 context.restore(); | |
| 4522 } | |
| 4523 | |
| 4524 if (highlight) { | |
| 4525 context.lineWidth = highlight ? highlightLineWidth : thinLineWidth; | |
| 4526 context.strokeStyle = 'black'; | |
| 4527 context.stroke(); | |
| 4528 } | |
| 4529 } | |
| 4530 } | |
| 4531 | |
| 4532 function expand(node) { | |
| 4533 selectNode(node); | |
| 4534 updateView(); | |
| 4535 } | |
| 4536 | |
| 4537 function focusLost() { | |
| 4538 mouseX = -1; | |
| 4539 mouseY = -1; | |
| 4540 checkHighlight(); | |
| 4541 document.body.style.cursor = 'auto'; | |
| 4542 } | |
| 4543 | |
| 4544 function fontSizeDecrease() { | |
| 4545 if (fontSize > 1) { | |
| 4546 fontSize--; | |
| 4547 updateViewNeeded = true; | |
| 4548 } | |
| 4549 } | |
| 4550 | |
| 4551 function fontSizeIncrease() { | |
| 4552 fontSize++; | |
| 4553 updateViewNeeded = true; | |
| 4554 } | |
| 4555 | |
| 4556 function getGetString(name, value, bool) { | |
| 4557 return name + '=' + (bool ? value ? 'true' : 'false' : value); | |
| 4558 } | |
| 4559 | |
| 4560 function hideLink() { | |
| 4561 hide(linkText); | |
| 4562 show(linkButton); | |
| 4563 } | |
| 4564 | |
| 4565 function show(object) { | |
| 4566 object.style.display = 'inline'; | |
| 4567 } | |
| 4568 | |
| 4569 function hide(object) { | |
| 4570 object.style.display = 'none'; | |
| 4571 } | |
| 4572 | |
| 4573 function showLink() { | |
| 4574 var urlHalves = String(document.location).split('?'); | |
| 4575 var newGetVariables = new Array(); | |
| 4576 | |
| 4577 newGetVariables.push | |
| 4578 ( | |
| 4579 getGetString('dataset', currentDataset, false), | |
| 4580 getGetString('node', selectedNode.id, false), | |
| 4581 getGetString('collapse', collapse, true), | |
| 4582 getGetString('color', useHue(), true), | |
| 4583 getGetString('depth', maxAbsoluteDepth - 1, false), | |
| 4584 getGetString('font', fontSize, false), | |
| 4585 getGetString('key', showKeys, true) | |
| 4586 ); | |
| 4587 | |
| 4588 hide(linkButton); | |
| 4589 show(linkText); | |
| 4590 linkText.value = urlHalves[0] + '?' | |
| 4591 + getVariables.concat(newGetVariables).join('&'); | |
| 4592 //linkText.disabled = false; | |
| 4593 linkText.focus(); | |
| 4594 linkText.select(); | |
| 4595 //linkText.disabled = true; | |
| 4596 // document.location = urlHalves[0] + '?' + getVariables.join('&'); | |
| 4597 } | |
| 4598 | |
| 4599 function getFirstChild(element) { | |
| 4600 element = element.firstChild; | |
| 4601 | |
| 4602 if (element && element.nodeType != 1) { | |
| 4603 element = getNextSibling(element); | |
| 4604 } | |
| 4605 | |
| 4606 return element; | |
| 4607 } | |
| 4608 | |
| 4609 function getNextSibling(element) { | |
| 4610 do { | |
| 4611 element = element.nextSibling; | |
| 4612 } | |
| 4613 while (element && element.nodeType != 1); | |
| 4614 | |
| 4615 return element; | |
| 4616 } | |
| 4617 | |
| 4618 function getPercentage(fraction) { | |
| 4619 return round(fraction * 100); | |
| 4620 } | |
| 4621 | |
| 4622 function hslText(hue) { | |
| 4623 if (1 || snapshotMode) { | |
| 4624 // Safari doesn't seem to allow hsl() in SVG | |
| 4625 | |
| 4626 var rgb = hslToRgb(hue, saturation, (lightnessBase + lightnessMax) / 2); | |
| 4627 | |
| 4628 return rgbText(rgb.r, rgb.g, rgb.b); | |
| 4629 } | |
| 4630 else { | |
| 4631 var hslArray = | |
| 4632 [ | |
| 4633 'hsl(', | |
| 4634 Math.floor(hue * 360), | |
| 4635 ',', | |
| 4636 Math.floor(saturation * 100), | |
| 4637 '%,', | |
| 4638 Math.floor((lightnessBase + lightnessMax) * 50), | |
| 4639 '%)' | |
| 4640 ]; | |
| 4641 | |
| 4642 return hslArray.join(''); | |
| 4643 } | |
| 4644 } | |
| 4645 | |
| 4646 function hslToRgb(h, s, l) { | |
| 4647 var m1, m2; | |
| 4648 var r, g, b; | |
| 4649 | |
| 4650 if (s == 0) { | |
| 4651 r = g = b = Math.floor((l * 255)); | |
| 4652 } | |
| 4653 else { | |
| 4654 if (l <= 0.5) { | |
| 4655 m2 = l * (s + 1); | |
| 4656 } | |
| 4657 else { | |
| 4658 m2 = l + s - l * s; | |
| 4659 } | |
| 4660 | |
| 4661 m1 = l * 2 - m2; | |
| 4662 | |
| 4663 r = Math.floor(hueToRgb(m1, m2, h + 1 / 3)); | |
| 4664 g = Math.floor(hueToRgb(m1, m2, h)); | |
| 4665 b = Math.floor(hueToRgb(m1, m2, h - 1 / 3)); | |
| 4666 } | |
| 4667 | |
| 4668 return {r: r, g: g, b: b}; | |
| 4669 } | |
| 4670 | |
| 4671 function hueToRgb(m1, m2, hue) { | |
| 4672 var v; | |
| 4673 | |
| 4674 while (hue < 0) { | |
| 4675 hue += 1; | |
| 4676 } | |
| 4677 | |
| 4678 while (hue > 1) { | |
| 4679 hue -= 1; | |
| 4680 } | |
| 4681 | |
| 4682 if (6 * hue < 1) | |
| 4683 v = m1 + (m2 - m1) * hue * 6; | |
| 4684 else if (2 * hue < 1) | |
| 4685 v = m2; | |
| 4686 else if (3 * hue < 2) | |
| 4687 v = m1 + (m2 - m1) * (2 / 3 - hue) * 6; | |
| 4688 else | |
| 4689 v = m1; | |
| 4690 | |
| 4691 return 255 * v; | |
| 4692 } | |
| 4693 | |
| 4694 function interpolateHue(hueStart, hueEnd, valueStart, valueEnd) { | |
| 4695 // since the gradient will be RGB based, we need to add stops to hit all the | |
| 4696 // colors in the hue spectrum | |
| 4697 | |
| 4698 function selective_round(value){ | |
| 4699 // Selective round depending on the hue scale width | |
| 4700 if(valueEnd - valueStart < 10){ | |
| 4701 return(value.toFixed(1)) | |
| 4702 } else { | |
| 4703 return(round(value)) | |
| 4704 } | |
| 4705 } | |
| 4706 | |
| 4707 hueStopPositions = new Array(); | |
| 4708 hueStopHsl = new Array(); | |
| 4709 hueStopText = new Array(); | |
| 4710 | |
| 4711 hueStopPositions.push(0); | |
| 4712 hueStopHsl.push(hslText(hueStart)); | |
| 4713 hueStopText.push(selective_round(valueStart)); | |
| 4714 | |
| 4715 for | |
| 4716 ( | |
| 4717 var i = (hueStart > hueEnd ? 5 / 6 : 1 / 6); | |
| 4718 (hueStart > hueEnd ? i > 0 : i < 1); | |
| 4719 i += (hueStart > hueEnd ? -1 : 1) / 6 | |
| 4720 ) { | |
| 4721 if | |
| 4722 ( | |
| 4723 hueStart > hueEnd ? | |
| 4724 i > hueEnd && i < hueStart : | |
| 4725 i > hueStart && i < hueEnd | |
| 4726 ) { | |
| 4727 hueStopPositions.push(lerp(i, hueStart, hueEnd, 0, 1)); | |
| 4728 hueStopHsl.push(hslText(i)); | |
| 4729 hueStopText.push(selective_round(lerp( | |
| 4730 i, hueStart, hueEnd, valueStart, valueEnd))); | |
| 4731 } | |
| 4732 } | |
| 4733 | |
| 4734 hueStopPositions.push(1); | |
| 4735 hueStopHsl.push(hslText(hueEnd)); | |
| 4736 hueStopText.push(selective_round(valueEnd)); | |
| 4737 } | |
| 4738 | |
| 4739 function keyLineAngle(angle, keyAngle, bendRadius, keyX, keyY, pointsX, | |
| 4740 pointsY) { | |
| 4741 if (angle < Math.PI / 2 && keyY < bendRadius * Math.sin(angle) | |
| 4742 || angle > Math.PI / 2 && keyY < bendRadius) { | |
| 4743 return Math.asin(keyY / bendRadius); | |
| 4744 } | |
| 4745 else { | |
| 4746 // find the angle of the normal to a tangent line that goes to | |
| 4747 // the label | |
| 4748 | |
| 4749 var textDist = Math.sqrt | |
| 4750 ( | |
| 4751 Math.pow(keyX, 2) + | |
| 4752 Math.pow(keyY, 2) | |
| 4753 ); | |
| 4754 | |
| 4755 var tanAngle = Math.acos(bendRadius / textDist) + keyAngle; | |
| 4756 | |
| 4757 if (angle < tanAngle || angle < Math.PI / 2)//|| labelLeft < centerX ) | |
| 4758 { | |
| 4759 // angle doesn't reach far enough for tangent; collapse and | |
| 4760 // connect directly to label | |
| 4761 | |
| 4762 if (keyY / Math.tan(angle) > 0) { | |
| 4763 pointsX.push(keyY / Math.tan(angle)); | |
| 4764 pointsY.push(keyY); | |
| 4765 } | |
| 4766 else { | |
| 4767 pointsX.push(bendRadius * Math.cos(angle)); | |
| 4768 pointsY.push(bendRadius * Math.sin(angle)); | |
| 4769 } | |
| 4770 | |
| 4771 return angle; | |
| 4772 } | |
| 4773 else { | |
| 4774 return tanAngle; | |
| 4775 } | |
| 4776 } | |
| 4777 } | |
| 4778 | |
| 4779 function keyOffset() { | |
| 4780 return imageHeight - (keys - currentKey + 1) * (keySize + keyBuffer) + | |
| 4781 keyBuffer - margin; | |
| 4782 } | |
| 4783 | |
| 4784 function lerp(value, fromStart, fromEnd, toStart, toEnd) { | |
| 4785 // Rescale value from source scale [fromStart, fromEnd] | |
| 4786 // to target scale [toStart, toEnd] | |
| 4787 return (value - fromStart) * | |
| 4788 (toEnd - toStart) / | |
| 4789 (fromEnd - fromStart) + | |
| 4790 toStart; | |
| 4791 } | |
| 4792 | |
| 4793 function createCanvas() { | |
| 4794 canvas = document.createElement('canvas'); | |
| 4795 document.body.appendChild(canvas); | |
| 4796 context = canvas.getContext('2d'); | |
| 4797 } | |
| 4798 | |
| 4799 function load() { | |
| 4800 document.body.style.overflow = "hidden"; | |
| 4801 document.body.style.margin = 0; | |
| 4802 document.body.style.backgroundColor = '#' + bkgBright; | |
| 4803 createCanvas(); | |
| 4804 | |
| 4805 if (context == undefined) { | |
| 4806 document.body.innerHTML = '\ | |
| 4807 <br/>Recentrifuge: Sorry, this browser does not support HTML5 (please see \ | |
| 4808 <a href="https://github.com/khyox/recentrifuge/wiki/Browser-support">Browser support</a>).\ | |
| 4809 '; | |
| 4810 return; | |
| 4811 } | |
| 4812 | |
| 4813 if (typeof context.fillText != 'function') { | |
| 4814 document.body.innerHTML = '\ | |
| 4815 <br/>Recentrifuge: Sorry, this browser does not support HTML5 canvas text (please see \ | |
| 4816 <a href="https://github.com/khyox/recentrifuge/wiki/Browser-support">Browser support</a>).\ | |
| 4817 '; | |
| 4818 return; | |
| 4819 } | |
| 4820 | |
| 4821 resize(); | |
| 4822 | |
| 4823 var kronaElement = document.getElementsByTagName('krona')[0]; | |
| 4824 | |
| 4825 var magnitudeName; | |
| 4826 var hueName; | |
| 4827 var hueDefault; | |
| 4828 var hueStart; | |
| 4829 var hueEnd; | |
| 4830 var valueStart; | |
| 4831 var valueEnd; | |
| 4832 | |
| 4833 if (kronaElement.getAttribute('collapse') !== undefined) { | |
| 4834 collapse = kronaElement.getAttribute('collapse') === 'true'; | |
| 4835 } | |
| 4836 | |
| 4837 if (kronaElement.getAttribute('key') !== undefined) { | |
| 4838 showKeys = kronaElement.getAttribute('key') === 'true'; | |
| 4839 } | |
| 4840 | |
| 4841 if (kronaElement.getAttribute('chart') !== undefined) { | |
| 4842 switch (kronaElement.getAttribute('chart')) { | |
| 4843 case 'TAXOMIC': | |
| 4844 chart = ChartEnum.TAXOMIC; | |
| 4845 fontFamily = 'Ubuntu' | |
| 4846 fontSize = 11 | |
| 4847 break; | |
| 4848 case 'GENOMIC': | |
| 4849 chart = ChartEnum.GENOMIC; | |
| 4850 fontFamily = 'Saira Condensed' | |
| 4851 fontSize = 12 | |
| 4852 break; | |
| 4853 } | |
| 4854 } | |
| 4855 | |
| 4856 for | |
| 4857 ( | |
| 4858 var element = getFirstChild(kronaElement); | |
| 4859 element; | |
| 4860 element = getNextSibling(element) | |
| 4861 ) { | |
| 4862 switch (element.tagName.toLowerCase()) { | |
| 4863 case 'attributes': | |
| 4864 magnitudeName = element.getAttribute('magnitude'); | |
| 4865 // | |
| 4866 for | |
| 4867 ( | |
| 4868 var attributeElement = getFirstChild(element); | |
| 4869 attributeElement; | |
| 4870 attributeElement = getNextSibling(attributeElement) | |
| 4871 ) { | |
| 4872 var tag = attributeElement.tagName.toLowerCase(); | |
| 4873 | |
| 4874 if (tag == 'attribute') { | |
| 4875 var attribute = new Attribute(); | |
| 4876 attribute.name = | |
| 4877 attributeElement.firstChild.nodeValue.toLowerCase(); | |
| 4878 attribute.displayName = | |
| 4879 attributeElement.getAttribute('display'); | |
| 4880 | |
| 4881 if (attributeElement.getAttribute('tip')) { | |
| 4882 attribute.tip = | |
| 4883 attributeElement.getAttribute('tip'); | |
| 4884 } | |
| 4885 | |
| 4886 if (attributeElement.getAttribute('hrefBase')) { | |
| 4887 attribute.hrefBase = | |
| 4888 attributeElement.getAttribute('hrefBase'); | |
| 4889 } | |
| 4890 | |
| 4891 if (attributeElement.getAttribute('target')) { | |
| 4892 attribute.target = | |
| 4893 attributeElement.getAttribute('target'); | |
| 4894 } | |
| 4895 | |
| 4896 if (attribute.name === magnitudeName) { | |
| 4897 magnitudeIndex = attributes.length; | |
| 4898 } | |
| 4899 | |
| 4900 if (attributeElement.getAttribute('listAll')) { | |
| 4901 attribute.listAll = | |
| 4902 attributeElement.getAttribute('listAll').toLowerCase(); | |
| 4903 } | |
| 4904 else if (attributeElement.getAttribute('listNode')) { | |
| 4905 attribute.listNode = | |
| 4906 attributeElement.getAttribute('listNode').toLowerCase(); | |
| 4907 } | |
| 4908 else if (attributeElement.getAttribute('dataAll')) { | |
| 4909 attribute.dataAll = | |
| 4910 attributeElement.getAttribute('dataAll').toLowerCase(); | |
| 4911 } | |
| 4912 else if (attributeElement.getAttribute('dataNode')) { | |
| 4913 attribute.dataNode = | |
| 4914 attributeElement.getAttribute('dataNode').toLowerCase(); | |
| 4915 } | |
| 4916 | |
| 4917 if (attributeElement.getAttribute('postUrl')) { | |
| 4918 attribute.postUrl = | |
| 4919 attributeElement.getAttribute('postUrl'); | |
| 4920 } | |
| 4921 | |
| 4922 if (attributeElement.getAttribute('postVar')) { | |
| 4923 attribute.postVar = | |
| 4924 attributeElement.getAttribute('postVar'); | |
| 4925 } | |
| 4926 | |
| 4927 if (attributeElement.getAttribute('mono')) { | |
| 4928 attribute.mono = true; | |
| 4929 } | |
| 4930 | |
| 4931 attributes.push(attribute); | |
| 4932 } | |
| 4933 else if (tag == 'list') { | |
| 4934 var attribute = new Attribute(); | |
| 4935 | |
| 4936 attribute.name = attributeElement.firstChild.nodeValue; | |
| 4937 attribute.list = true; | |
| 4938 attributes.push(attribute); | |
| 4939 } | |
| 4940 else if (tag == 'data') { | |
| 4941 var attribute = new Attribute(); | |
| 4942 | |
| 4943 attribute.name = attributeElement.firstChild.nodeValue; | |
| 4944 attribute.data = true; | |
| 4945 attributes.push(attribute); | |
| 4946 | |
| 4947 var enableScript = document.createElement('script'); | |
| 4948 var date = new Date(); | |
| 4949 enableScript.src = | |
| 4950 attributeElement.getAttribute('enable') + '?' + | |
| 4951 date.getTime(); | |
| 4952 document.body.appendChild(enableScript); | |
| 4953 } | |
| 4954 } | |
| 4955 break; | |
| 4956 | |
| 4957 case 'color': | |
| 4958 hueName = element.getAttribute('attribute'); | |
| 4959 hueStart = Number(element.getAttribute('hueStart')) / 360; | |
| 4960 hueEnd = Number(element.getAttribute('hueEnd')) / 360; | |
| 4961 valueStart = Number(element.getAttribute('valueStart')); | |
| 4962 valueEnd = Number(element.getAttribute('valueEnd')); | |
| 4963 // | |
| 4964 interpolateHue(hueStart, hueEnd, valueStart, valueEnd); | |
| 4965 // | |
| 4966 if (element.getAttribute('default') == 'true') { | |
| 4967 hueDefault = true; | |
| 4968 } | |
| 4969 break; | |
| 4970 | |
| 4971 case 'datasets': | |
| 4972 datasetNames = []; | |
| 4973 stats = []; | |
| 4974 numRawSamples = element.getAttribute('rawSamples'); | |
| 4975 var i = 0; | |
| 4976 for (var j = getFirstChild(element); j; j = getNextSibling(j)) { | |
| 4977 var datasetName = j.firstChild.nodeValue; | |
| 4978 datasetNames.push(datasetName); | |
| 4979 if (i < numRawSamples) { // Get stats of raw samples | |
| 4980 var stat = new SampleStats( | |
| 4981 datasetName, | |
| 4982 j.getAttribute('isctr'), | |
| 4983 j.getAttribute('sread'), | |
| 4984 j.getAttribute('sclas'), | |
| 4985 j.getAttribute('sfilt'), | |
| 4986 j.getAttribute('scmin'), | |
| 4987 j.getAttribute('scavg'), | |
| 4988 j.getAttribute('scmax'), | |
| 4989 j.getAttribute('lnmin'), | |
| 4990 j.getAttribute('lnavg'), | |
| 4991 j.getAttribute('lnmax'), | |
| 4992 j.getAttribute('tclas'), | |
| 4993 j.getAttribute('tfilt'), | |
| 4994 j.getAttribute('tfold') | |
| 4995 ); | |
| 4996 stats.push(stat) | |
| 4997 } | |
| 4998 } | |
| 4999 datasets = datasetNames.length; | |
| 5000 break; | |
| 5001 | |
| 5002 case 'node': | |
| 5003 head = loadTreeDOM | |
| 5004 ( | |
| 5005 element, | |
| 5006 magnitudeName, | |
| 5007 hueName, | |
| 5008 hueStart, | |
| 5009 hueEnd, | |
| 5010 valueStart, | |
| 5011 valueEnd | |
| 5012 ); | |
| 5013 break; | |
| 5014 } | |
| 5015 } | |
| 5016 | |
| 5017 // get GET options | |
| 5018 // | |
| 5019 var urlHalves = String(document.location).split('?'); | |
| 5020 var datasetDefault = 0; | |
| 5021 var maxDepthDefault; | |
| 5022 var nodeDefault = 0; | |
| 5023 // | |
| 5024 if (urlHalves[1]) { | |
| 5025 var vars = urlHalves[1].split('&'); | |
| 5026 | |
| 5027 for (i = 0; i < vars.length; i++) { | |
| 5028 var pair = vars[i].split('='); | |
| 5029 | |
| 5030 switch (pair[0]) { | |
| 5031 case 'collapse': | |
| 5032 collapse = pair[1] == 'true'; | |
| 5033 break; | |
| 5034 | |
| 5035 case 'color': | |
| 5036 hueDefault = pair[1] == 'true'; | |
| 5037 break; | |
| 5038 | |
| 5039 case 'dataset': | |
| 5040 datasetDefault = Number(pair[1]); | |
| 5041 break; | |
| 5042 | |
| 5043 case 'depth': | |
| 5044 maxDepthDefault = Number(pair[1]) + 1; | |
| 5045 break; | |
| 5046 | |
| 5047 case 'key': | |
| 5048 showKeys = pair[1] == 'true'; | |
| 5049 break; | |
| 5050 | |
| 5051 case 'font': | |
| 5052 fontSize = Number(pair[1]); | |
| 5053 break; | |
| 5054 | |
| 5055 case 'node': | |
| 5056 nodeDefault = Number(pair[1]); | |
| 5057 break; | |
| 5058 | |
| 5059 default: | |
| 5060 getVariables.push(pair[0] + '=' + pair[1]); | |
| 5061 break; | |
| 5062 } | |
| 5063 } | |
| 5064 } | |
| 5065 | |
| 5066 addOptionElements(hueName, hueDefault); | |
| 5067 if (datasets > 1) { | |
| 5068 if (datasets > numRawSamples) { // Check for cross-analysis samples | |
| 5069 selectRank(DEFAULT_RANK); | |
| 5070 } else { | |
| 5071 selectRank(NO_RANK); | |
| 5072 } | |
| 5073 } | |
| 5074 setCallBacks(); | |
| 5075 | |
| 5076 head.sort(); | |
| 5077 maxAbsoluteDepth = 0; | |
| 5078 selectDataset(datasetDefault); | |
| 5079 | |
| 5080 if (maxDepthDefault && maxDepthDefault < head.maxDepth) { | |
| 5081 maxAbsoluteDepth = maxDepthDefault; | |
| 5082 } | |
| 5083 else { | |
| 5084 maxAbsoluteDepth = head.maxDepth; | |
| 5085 } | |
| 5086 | |
| 5087 selectNode(nodes[nodeDefault]); | |
| 5088 | |
| 5089 setInterval(update, 20); | |
| 5090 | |
| 5091 window.onresize = handleResize; | |
| 5092 updateMaxAbsoluteDepth(); | |
| 5093 updateViewNeeded = true; | |
| 5094 } | |
| 5095 | |
| 5096 function loadTreeDOM | |
| 5097 (domNode, | |
| 5098 magnitudeName, | |
| 5099 hueName, | |
| 5100 hueStart, | |
| 5101 hueEnd, | |
| 5102 valueStart, | |
| 5103 valueEnd) { | |
| 5104 var newNode = new Node(); | |
| 5105 | |
| 5106 newNode.name = domNode.getAttribute('name'); | |
| 5107 | |
| 5108 if (domNode.getAttribute('href')) { | |
| 5109 newNode.href = domNode.getAttribute('href'); | |
| 5110 } | |
| 5111 | |
| 5112 if (hueName) { | |
| 5113 newNode.hues = new Array(); | |
| 5114 } | |
| 5115 | |
| 5116 for (var i = getFirstChild(domNode); i; i = getNextSibling(i)) { | |
| 5117 switch (i.tagName.toLowerCase()) { | |
| 5118 case 'node': | |
| 5119 var newChild = loadTreeDOM | |
| 5120 ( | |
| 5121 i, | |
| 5122 magnitudeName, | |
| 5123 hueName, | |
| 5124 hueStart, | |
| 5125 hueEnd, | |
| 5126 valueStart, | |
| 5127 valueEnd | |
| 5128 ); | |
| 5129 newChild.parent = newNode; | |
| 5130 newNode.children.push(newChild); | |
| 5131 break; | |
| 5132 | |
| 5133 default: | |
| 5134 var attributeName = i.tagName.toLowerCase(); | |
| 5135 var index = attributeIndex(attributeName); | |
| 5136 // | |
| 5137 newNode.attributes[index] = new Array(); | |
| 5138 // | |
| 5139 for (var j = getFirstChild(i); j; j = getNextSibling(j)) { | |
| 5140 if (attributes[index] == undefined) { | |
| 5141 var x = 5; | |
| 5142 } | |
| 5143 if (attributes[index].list) { | |
| 5144 newNode.attributes[index].push(new Array()); | |
| 5145 | |
| 5146 for (var k = getFirstChild(j); k; k = getNextSibling(k)) { | |
| 5147 newNode.attributes[index][ | |
| 5148 newNode.attributes[ | |
| 5149 index].length - 1].push( | |
| 5150 k.firstChild.nodeValue); | |
| 5151 } | |
| 5152 } | |
| 5153 else { | |
| 5154 var value = j.firstChild ? j.firstChild.nodeValue : ''; | |
| 5155 | |
| 5156 if (j.getAttribute('href')) { | |
| 5157 var target; | |
| 5158 | |
| 5159 if (attributes[index].target) { | |
| 5160 target = ' target="' | |
| 5161 + attributes[index].target + '"'; | |
| 5162 } | |
| 5163 | |
| 5164 value = '<a href="' + attributes[index].hrefBase | |
| 5165 + j.getAttribute('href') + '"' | |
| 5166 + target + '>' + value + '</a>'; | |
| 5167 } | |
| 5168 | |
| 5169 newNode.attributes[index].push(value); | |
| 5170 } | |
| 5171 } | |
| 5172 // | |
| 5173 if (attributeName == magnitudeName | |
| 5174 || attributeName == hueName) { | |
| 5175 for (j = 0; j < datasets; j++) { | |
| 5176 // j is the dataset index (goes from 0 to datasets-1) | |
| 5177 var value = newNode.attributes[index][j] | |
| 5178 == undefined ? 0 : Number(newNode.attributes[index][j]); | |
| 5179 | |
| 5180 newNode.attributes[index][j] = value; | |
| 5181 | |
| 5182 if (attributeName == hueName) { | |
| 5183 var hue = lerp | |
| 5184 ( | |
| 5185 value, | |
| 5186 valueStart, | |
| 5187 valueEnd, | |
| 5188 hueStart, | |
| 5189 hueEnd | |
| 5190 ); | |
| 5191 | |
| 5192 if (hue < hueStart == hueStart < hueEnd) { | |
| 5193 hue = hueStart; | |
| 5194 } | |
| 5195 else if (hue > hueEnd == hueStart < hueEnd) { | |
| 5196 hue = hueEnd; | |
| 5197 } | |
| 5198 | |
| 5199 newNode.hues[j] = hue; | |
| 5200 } | |
| 5201 } | |
| 5202 | |
| 5203 if (attributeName == hueName) { | |
| 5204 newNode.hue = new Tween(newNode.hues[0], | |
| 5205 newNode.hues[0]); | |
| 5206 } | |
| 5207 } | |
| 5208 break; | |
| 5209 } | |
| 5210 } | |
| 5211 | |
| 5212 return newNode; | |
| 5213 } | |
| 5214 | |
| 5215 function maxAbsoluteDepthDecrease() { | |
| 5216 if (maxAbsoluteDepth > 2) { | |
| 5217 maxAbsoluteDepth--; | |
| 5218 head.setMaxDepths(); | |
| 5219 handleResize(); | |
| 5220 } | |
| 5221 } | |
| 5222 | |
| 5223 function maxAbsoluteDepthIncrease() { | |
| 5224 if (maxAbsoluteDepth < head.maxDepth) { | |
| 5225 maxAbsoluteDepth++; | |
| 5226 head.setMaxDepths(); | |
| 5227 handleResize(); | |
| 5228 } | |
| 5229 } | |
| 5230 | |
| 5231 function measureText(text, bold) { | |
| 5232 context.font = bold ? fontBold : fontNormal; | |
| 5233 var dim = context.measureText(text); | |
| 5234 return dim.width; | |
| 5235 } | |
| 5236 | |
| 5237 function min(a, b) { | |
| 5238 return a < b ? a : b; | |
| 5239 } | |
| 5240 | |
| 5241 function minWidth() { | |
| 5242 // Min wedge width (at center) for displaying a node (or for displaying a | |
| 5243 // label if it's at the highest level being viewed, multiplied by 2 to make | |
| 5244 // further calculations simpler | |
| 5245 | |
| 5246 return (fontSize * 2.3); | |
| 5247 } | |
| 5248 | |
| 5249 function mouseMove(e) { | |
| 5250 mouseX = e.pageX; | |
| 5251 mouseY = e.pageY - headerHeight; | |
| 5252 mouseXRel = (mouseX - centerX) * backingScale() | |
| 5253 mouseYRel = (mouseY - centerY) * backingScale() | |
| 5254 | |
| 5255 if (head && !quickLook) { | |
| 5256 checkHighlight(); | |
| 5257 } | |
| 5258 } | |
| 5259 | |
| 5260 function mouseClick(e) { | |
| 5261 // Event listener function for mouse click on CANVAS | |
| 5262 if (highlightedNode == focusNode && focusNode != selectedNode | |
| 5263 || selectedNode.hasParent(highlightedNode)) { | |
| 5264 if (highlightedNode.hasChildren()) { | |
| 5265 expand(highlightedNode); | |
| 5266 } | |
| 5267 } | |
| 5268 else if (progress == 1)//( highlightedNode != selectedNode ) | |
| 5269 { | |
| 5270 setFocus(highlightedNode); | |
| 5271 // document.body.style.cursor='ew-resize'; | |
| 5272 draw(); | |
| 5273 checkHighlight(); | |
| 5274 var date = new Date(); | |
| 5275 mouseDownTime = date.getTime(); | |
| 5276 mouseDown = true; | |
| 5277 var button = undefined; | |
| 5278 for (var i = 0; i < canvasButtons.length; i++) { | |
| 5279 if (canvasButtons[i].is_inside(e.pageX, e.pageY)) { | |
| 5280 context.strokeStyle = '#CC0000'; | |
| 5281 context.lineWidth = 2; | |
| 5282 button = canvasButtons[i]; | |
| 5283 context.strokeRect(button.x, button.y, button.w, button.h); | |
| 5284 } | |
| 5285 } | |
| 5286 if (button) { | |
| 5287 // Reorder the array of nodes only when needed | |
| 5288 if (nodesIndex === undefined || !nodes.reduce( | |
| 5289 function (acc, current, index) { | |
| 5290 // Calculate deviation from id == index for every node | |
| 5291 return acc + Math.abs(current.id - index) | |
| 5292 }, 0)) { | |
| 5293 nodes.sort(function (a, b) { | |
| 5294 return b.getHue() - a.getHue() | |
| 5295 }); | |
| 5296 } | |
| 5297 | |
| 5298 function lookForLeaf(testIndex, reverse) { | |
| 5299 // Look for nodes without children but with counts | |
| 5300 for (; testIndex >= 0 && testIndex <= nodes.length - 1 | |
| 5301 && !nodes[testIndex].isLeaf(); | |
| 5302 reverse ? testIndex-- : testIndex++) { | |
| 5303 } | |
| 5304 if (testIndex >= 0 && testIndex <= nodes.length - 1 | |
| 5305 && nodes[testIndex].isLeaf()) nodesIndex = testIndex; | |
| 5306 } | |
| 5307 | |
| 5308 function lookForNode(testIndex, reverse) { | |
| 5309 // Look for nodes with counts | |
| 5310 for (; testIndex >= 0 && testIndex <= nodes.length - 1 | |
| 5311 && nodes[testIndex].getHue() <= 0; | |
| 5312 reverse ? testIndex-- : testIndex++) { | |
| 5313 } | |
| 5314 if (testIndex >= 0 && testIndex <= nodes.length - 1 | |
| 5315 && nodes[testIndex].getHue() > 0) | |
| 5316 nodesIndex = testIndex; | |
| 5317 } | |
| 5318 | |
| 5319 switch (button.name) { | |
| 5320 case 'mostScore': | |
| 5321 nodesIndex = 0; | |
| 5322 if (collapseCheckBox.checked) { | |
| 5323 lookForLeaf(nodesIndex, false); | |
| 5324 } else { | |
| 5325 lookForNode(nodesIndex, false); | |
| 5326 } | |
| 5327 break; | |
| 5328 case 'moreScore': | |
| 5329 if (collapseCheckBox.checked) { | |
| 5330 lookForLeaf(nodesIndex - 1, true); | |
| 5331 } else { | |
| 5332 lookForNode(nodesIndex - 1, true); | |
| 5333 } | |
| 5334 break; | |
| 5335 case 'lessScore': | |
| 5336 if (collapseCheckBox.checked) { | |
| 5337 lookForLeaf(nodesIndex + 1, false); | |
| 5338 } else { | |
| 5339 lookForNode(nodesIndex + 1, false); | |
| 5340 } | |
| 5341 break; | |
| 5342 case 'lestScore': | |
| 5343 nodesIndex = nodes.length - 1; | |
| 5344 if (collapseCheckBox.checked) { | |
| 5345 lookForLeaf(nodesIndex, true); | |
| 5346 } else { | |
| 5347 lookForNode(nodesIndex, true); | |
| 5348 } | |
| 5349 break; | |
| 5350 default: | |
| 5351 alert('ERROR! Unknown button in canvas. Ignoring!') | |
| 5352 } | |
| 5353 search.value = nodes[nodesIndex].name; | |
| 5354 onSearchChange(); | |
| 5355 context.strokeStyle = '#CC0000'; | |
| 5356 context.lineWidth = 2; | |
| 5357 context.strokeRect(button.x, button.y, button.w, button.h); | |
| 5358 setTimeout(function () { | |
| 5359 drawLegend() | |
| 5360 }, 700) | |
| 5361 } | |
| 5362 } | |
| 5363 } | |
| 5364 | |
| 5365 function mouseUp(e) { | |
| 5366 if (quickLook) { | |
| 5367 navigateBack(); | |
| 5368 quickLook = false; | |
| 5369 } | |
| 5370 | |
| 5371 mouseDown = false; | |
| 5372 } | |
| 5373 | |
| 5374 function navigateBack() { | |
| 5375 if (nodeHistoryPosition > 0) { | |
| 5376 nodeHistory[nodeHistoryPosition] = selectedNode; | |
| 5377 nodeHistoryPosition--; | |
| 5378 | |
| 5379 if (nodeHistory[nodeHistoryPosition].collapse) { | |
| 5380 collapseCheckBox.checked = collapse = false; | |
| 5381 } | |
| 5382 | |
| 5383 setSelectedNode(nodeHistory[nodeHistoryPosition]); | |
| 5384 updateDatasetButtons(); | |
| 5385 updateView(); | |
| 5386 } | |
| 5387 } | |
| 5388 | |
| 5389 function navigateUp() { | |
| 5390 if (selectedNode.getParent()) { | |
| 5391 selectNode(selectedNode.getParent()); | |
| 5392 updateView(); | |
| 5393 } | |
| 5394 } | |
| 5395 | |
| 5396 function navigateForward() { | |
| 5397 if (nodeHistoryPosition < nodeHistory.length - 1) { | |
| 5398 nodeHistoryPosition++; | |
| 5399 var newNode = nodeHistory[nodeHistoryPosition]; | |
| 5400 | |
| 5401 if (newNode.collapse) { | |
| 5402 collapseCheckBox.checked = collapse = false; | |
| 5403 } | |
| 5404 | |
| 5405 if (nodeHistoryPosition == nodeHistory.length - 1) { | |
| 5406 // this will ensure the forward button is disabled | |
| 5407 | |
| 5408 nodeHistory.length = nodeHistoryPosition; | |
| 5409 } | |
| 5410 | |
| 5411 setSelectedNode(newNode); | |
| 5412 updateDatasetButtons(); | |
| 5413 updateView(); | |
| 5414 } | |
| 5415 } | |
| 5416 | |
| 5417 function nextDataset() { | |
| 5418 var newDataset = currentDataset; | |
| 5419 | |
| 5420 do { | |
| 5421 if (newDataset === datasets - 1) { | |
| 5422 newDataset = 0; | |
| 5423 } | |
| 5424 else { | |
| 5425 newDataset++; | |
| 5426 } | |
| 5427 } | |
| 5428 while (datasetDropDown.options[newDataset].disabled | |
| 5429 || datasetDropDown.options[newDataset].hidden) | |
| 5430 | |
| 5431 selectDataset(newDataset); | |
| 5432 } | |
| 5433 | |
| 5434 function onDatasetChange() { | |
| 5435 selectDataset(datasetDropDown.selectedIndex); | |
| 5436 nodesIndex = undefined; | |
| 5437 } | |
| 5438 | |
| 5439 function onKeyDown(event) { | |
| 5440 if | |
| 5441 ( | |
| 5442 event.keyCode == 37 && | |
| 5443 document.activeElement.id != 'search' && | |
| 5444 document.activeElement.id != 'linkText' | |
| 5445 ) { | |
| 5446 navigateBack(); | |
| 5447 event.preventDefault(); | |
| 5448 } | |
| 5449 else if | |
| 5450 ( | |
| 5451 event.keyCode == 39 && | |
| 5452 document.activeElement.id != 'search' && | |
| 5453 document.activeElement.id != 'linkText' | |
| 5454 ) { | |
| 5455 navigateForward(); | |
| 5456 event.preventDefault(); | |
| 5457 } | |
| 5458 else if (event.keyCode == 38 && datasets > 1) { | |
| 5459 prevDataset(); | |
| 5460 | |
| 5461 //if ( document.activeElement.id == 'datasets' ) | |
| 5462 { | |
| 5463 event.preventDefault(); | |
| 5464 } | |
| 5465 } | |
| 5466 else if (event.keyCode == 40 && datasets > 1) { | |
| 5467 nextDataset(); | |
| 5468 | |
| 5469 //if ( document.activeElement.id == 'datasets' ) | |
| 5470 { | |
| 5471 event.preventDefault(); | |
| 5472 } | |
| 5473 } | |
| 5474 else if (event.keyCode == 9 && datasets > 1) { | |
| 5475 selectLastDataset(); | |
| 5476 event.preventDefault(); | |
| 5477 } | |
| 5478 else if (event.keyCode == 83) { | |
| 5479 progress += .2; | |
| 5480 } | |
| 5481 else if (event.keyCode == 66) { | |
| 5482 progress -= .2; | |
| 5483 } | |
| 5484 else if (event.keyCode == 70) { | |
| 5485 progress = 1; | |
| 5486 } | |
| 5487 } | |
| 5488 | |
| 5489 function onKeyPress(event) { | |
| 5490 if (event.keyCode == 38 && datasets > 1) { | |
| 5491 // prevDataset(); | |
| 5492 | |
| 5493 //if ( document.activeElement.id == 'datasets' ) | |
| 5494 { | |
| 5495 event.preventDefault(); | |
| 5496 } | |
| 5497 } | |
| 5498 else if (event.keyCode == 40 && datasets > 1) { | |
| 5499 // nextDataset(); | |
| 5500 | |
| 5501 //if ( document.activeElement.id == 'datasets' ) | |
| 5502 { | |
| 5503 event.preventDefault(); | |
| 5504 } | |
| 5505 } | |
| 5506 } | |
| 5507 | |
| 5508 function onKeyUp(event) { | |
| 5509 if (event.keyCode == 27 && document.activeElement.id == 'search') { | |
| 5510 search.value = ''; | |
| 5511 onSearchChange(); | |
| 5512 } | |
| 5513 else if (event.keyCode == 38 && datasets > 1) { | |
| 5514 // prevDataset(); | |
| 5515 | |
| 5516 //if ( document.activeElement.id == 'datasets' ) | |
| 5517 { | |
| 5518 event.preventDefault(); | |
| 5519 } | |
| 5520 } | |
| 5521 else if (event.keyCode == 40 && datasets > 1) { | |
| 5522 // nextDataset(); | |
| 5523 | |
| 5524 //if ( document.activeElement.id == 'datasets' ) | |
| 5525 { | |
| 5526 event.preventDefault(); | |
| 5527 } | |
| 5528 } | |
| 5529 } | |
| 5530 | |
| 5531 function onRankChange() { | |
| 5532 selectRank(rankDropDown.value); | |
| 5533 } | |
| 5534 | |
| 5535 function onSearchChange() { | |
| 5536 nSearchResults = 0; | |
| 5537 head.search(); | |
| 5538 | |
| 5539 if (search.value == '') { | |
| 5540 searchResults.innerHTML = ''; | |
| 5541 } | |
| 5542 else { | |
| 5543 searchResults.innerHTML = nSearchResults + ' results'; | |
| 5544 } | |
| 5545 | |
| 5546 setFocus(selectedNode); | |
| 5547 draw(); | |
| 5548 } | |
| 5549 | |
| 5550 function onSortChange() { | |
| 5551 head.sort(); | |
| 5552 head.setMagnitudes(0); | |
| 5553 handleResize(); | |
| 5554 } | |
| 5555 | |
| 5556 function post(url, variable, value, postWindow) { | |
| 5557 var form = document.createElement('form'); | |
| 5558 var input = document.createElement('input'); | |
| 5559 var inputDataset = document.createElement('input'); | |
| 5560 | |
| 5561 form.appendChild(input); | |
| 5562 form.appendChild(inputDataset); | |
| 5563 | |
| 5564 form.method = "POST"; | |
| 5565 form.action = url; | |
| 5566 | |
| 5567 if (postWindow == undefined) { | |
| 5568 form.target = '_blank'; | |
| 5569 postWindow = window; | |
| 5570 } | |
| 5571 | |
| 5572 input.type = 'hidden'; | |
| 5573 input.name = variable; | |
| 5574 input.value = value; | |
| 5575 | |
| 5576 inputDataset.type = 'hidden'; | |
| 5577 inputDataset.name = 'dataset'; | |
| 5578 inputDataset.value = currentDataset; | |
| 5579 | |
| 5580 postWindow.document.body.appendChild(form); | |
| 5581 form.submit(); | |
| 5582 } | |
| 5583 | |
| 5584 function prevDataset() { | |
| 5585 var newDataset = currentDataset; | |
| 5586 | |
| 5587 do { | |
| 5588 if (newDataset == 0) { | |
| 5589 newDataset = datasets - 1; | |
| 5590 } | |
| 5591 else { | |
| 5592 newDataset--; | |
| 5593 } | |
| 5594 } | |
| 5595 while (datasetDropDown.options[newDataset].disabled | |
| 5596 || datasetDropDown.options[newDataset].hidden); | |
| 5597 | |
| 5598 selectDataset(newDataset); | |
| 5599 } | |
| 5600 | |
| 5601 function radiusDecrease() { | |
| 5602 if (bufferFactor < .309) { | |
| 5603 bufferFactor += .03; | |
| 5604 updateViewNeeded = true; | |
| 5605 } | |
| 5606 } | |
| 5607 | |
| 5608 function radiusIncrease() { | |
| 5609 if (bufferFactor > .041) { | |
| 5610 bufferFactor -= .03; | |
| 5611 updateViewNeeded = true; | |
| 5612 } | |
| 5613 } | |
| 5614 | |
| 5615 function resetKeyOffset() { | |
| 5616 currentKey = 1; | |
| 5617 keyMinTextLeft = centerX + gRadius + buffer - buffer / (keys + 1) / | |
| 5618 2 + fontSize / 2; | |
| 5619 keyMinAngle = 0; | |
| 5620 } | |
| 5621 | |
| 5622 function rgbText(r, g, b) { | |
| 5623 var rgbArray = | |
| 5624 [ | |
| 5625 "rgb(", | |
| 5626 Math.floor(r), | |
| 5627 ",", | |
| 5628 Math.floor(g), | |
| 5629 ",", | |
| 5630 Math.floor(b), | |
| 5631 ")" | |
| 5632 ]; | |
| 5633 | |
| 5634 return rgbArray.join(''); | |
| 5635 } | |
| 5636 | |
| 5637 function round(number) { | |
| 5638 if (number >= 1 || number <= -1) { | |
| 5639 return number.toFixed(0); | |
| 5640 } | |
| 5641 else { | |
| 5642 return number.toPrecision(1); | |
| 5643 } | |
| 5644 } | |
| 5645 | |
| 5646 function roundedRectangle(x, y, width, height, radius, fill, stroke) { | |
| 5647 // Optionals: radius, stroke, fill | |
| 5648 if (typeof stroke === 'undefined') { | |
| 5649 stroke = true; | |
| 5650 } | |
| 5651 if (typeof radius === 'undefined') { | |
| 5652 radius = 5; | |
| 5653 } else if (typeof radius === 'number') { | |
| 5654 if (radius * 2 > width) { | |
| 5655 radius = width / 2; | |
| 5656 } | |
| 5657 if (radius * 2 > height) { | |
| 5658 radius = height / 2; | |
| 5659 } | |
| 5660 radius = {tl: radius, tr: radius, br: radius, bl: radius}; | |
| 5661 } else { | |
| 5662 var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; | |
| 5663 for (var side in defaultRadius) { | |
| 5664 radius[side] = radius[side] || defaultRadius[side]; | |
| 5665 } | |
| 5666 } | |
| 5667 | |
| 5668 context.beginPath(); | |
| 5669 context.arc(x + radius.tl, y + radius.tl, radius.tl, | |
| 5670 Math.PI, Math.PI * 3 / 2, false); | |
| 5671 context.lineTo(x + width - radius.tr, y); | |
| 5672 context.arc(x + width - radius.tr, y + radius.tr, radius.tr, | |
| 5673 Math.PI * 3 / 2, Math.PI * 2, false); | |
| 5674 context.lineTo(x + width, y + height - radius.br); | |
| 5675 context.arc(x + width - radius.br, y + height - radius.br, radius.br, | |
| 5676 0, Math.PI / 2, false); | |
| 5677 context.lineTo(x + radius.bl, y + height); | |
| 5678 context.arc(x + radius.bl, y + height - radius.bl, radius.bl, | |
| 5679 Math.PI / 2, Math.PI, false); | |
| 5680 context.lineTo(x, y + radius.tl); | |
| 5681 | |
| 5682 if (fill) { | |
| 5683 context.fill(); | |
| 5684 } | |
| 5685 if (stroke) { | |
| 5686 context.stroke(); | |
| 5687 } | |
| 5688 } | |
| 5689 | |
| 5690 function passClick(e) { | |
| 5691 mouseClick(e); | |
| 5692 } | |
| 5693 | |
| 5694 function searchResultString(results) { | |
| 5695 var searchResults = this.searchResults; | |
| 5696 | |
| 5697 if (this.isSearchResult) { | |
| 5698 // don't count ourselves | |
| 5699 searchResults--; | |
| 5700 } | |
| 5701 | |
| 5702 return ' - ' + results + (results > 1 ? ' results' : ' result'); | |
| 5703 } | |
| 5704 | |
| 5705 function setCallBacks() { | |
| 5706 canvas.onselectstart = function () { | |
| 5707 return false; | |
| 5708 } // prevent unwanted highlighting | |
| 5709 options.onselectstart = function () { | |
| 5710 return false; | |
| 5711 } // prevent unwanted highlighting | |
| 5712 document.onmousemove = mouseMove; | |
| 5713 window.onblur = focusLost; | |
| 5714 window.onmouseout = focusLost; | |
| 5715 document.onkeyup = onKeyUp; | |
| 5716 document.onkeydown = onKeyDown; | |
| 5717 canvas.onmousedown = mouseClick; | |
| 5718 document.onmouseup = mouseUp; | |
| 5719 keyControl.onclick = toggleKeys; | |
| 5720 collapseCheckBox = document.getElementById('collapse'); | |
| 5721 collapseCheckBox.checked = collapse; | |
| 5722 collapseCheckBox.onclick = handleResize; | |
| 5723 collapseCheckBox.onmousedown = suppressEvent; | |
| 5724 maxAbsoluteDepthText = document.getElementById('maxAbsoluteDepth'); | |
| 5725 maxAbsoluteDepthButtonDecrease = | |
| 5726 document.getElementById('maxAbsoluteDepthDecrease'); | |
| 5727 maxAbsoluteDepthButtonIncrease = | |
| 5728 document.getElementById('maxAbsoluteDepthIncrease'); | |
| 5729 maxAbsoluteDepthButtonDecrease.onclick = maxAbsoluteDepthDecrease; | |
| 5730 maxAbsoluteDepthButtonIncrease.onclick = maxAbsoluteDepthIncrease; | |
| 5731 maxAbsoluteDepthButtonDecrease.onmousedown = suppressEvent; | |
| 5732 maxAbsoluteDepthButtonIncrease.onmousedown = suppressEvent; | |
| 5733 fontSizeText = document.getElementById('fontSize'); | |
| 5734 fontSizeButtonDecrease = document.getElementById('fontSizeDecrease'); | |
| 5735 fontSizeButtonIncrease = document.getElementById('fontSizeIncrease'); | |
| 5736 fontSizeButtonDecrease.onclick = fontSizeDecrease; | |
| 5737 fontSizeButtonIncrease.onclick = fontSizeIncrease; | |
| 5738 fontSizeButtonDecrease.onmousedown = suppressEvent; | |
| 5739 fontSizeButtonIncrease.onmousedown = suppressEvent; | |
| 5740 bkgBrightButtonDecrease = document.getElementById('bkgBrightDecrease'); | |
| 5741 bkgBrightButtonIncrease = document.getElementById('bkgBrightIncrease'); | |
| 5742 bkgBrightButtonDecrease.onclick = bkgBrightDecrease; | |
| 5743 bkgBrightButtonIncrease.onclick = bkgBrightIncrease; | |
| 5744 bkgBrightButtonDecrease.onmousedown = suppressEvent; | |
| 5745 bkgBrightButtonIncrease.onmousedown = suppressEvent; | |
| 5746 radiusButtonDecrease = document.getElementById('radiusDecrease'); | |
| 5747 radiusButtonIncrease = document.getElementById('radiusIncrease'); | |
| 5748 radiusButtonDecrease.onclick = radiusDecrease; | |
| 5749 radiusButtonIncrease.onclick = radiusIncrease; | |
| 5750 radiusButtonDecrease.onmousedown = suppressEvent; | |
| 5751 radiusButtonIncrease.onmousedown = suppressEvent; | |
| 5752 maxAbsoluteDepth = 0; | |
| 5753 backButton = document.getElementById('back'); | |
| 5754 backButton.onclick = navigateBack; | |
| 5755 backButton.onmousedown = suppressEvent; | |
| 5756 forwardButton = document.getElementById('forward'); | |
| 5757 forwardButton.onclick = navigateForward; | |
| 5758 forwardButton.onmousedown = suppressEvent; | |
| 5759 snapshotButton = document.getElementById('snapshot'); | |
| 5760 snapshotButton.onclick = snapshot; | |
| 5761 snapshotButton.onmousedown = suppressEvent; | |
| 5762 detailsName = document.getElementById('detailsName'); | |
| 5763 detailsExpand = document.getElementById('detailsExpand'); | |
| 5764 detailsInfo = document.getElementById('detailsInfo'); | |
| 5765 search = document.getElementById('search'); | |
| 5766 search.onkeyup = onSearchChange; | |
| 5767 search.onmousedown = suppressEvent; | |
| 5768 searchResults = document.getElementById('searchResults'); | |
| 5769 useHueDiv = document.getElementById('useHueDiv'); | |
| 5770 linkButton = document.getElementById('linkButton'); | |
| 5771 linkButton.onclick = showLink; | |
| 5772 linkButton.onmousedown = suppressEvent; | |
| 5773 linkText = document.getElementById('linkText'); | |
| 5774 linkText.onblur = hideLink; | |
| 5775 linkText.onmousedown = suppressEvent; | |
| 5776 hide(linkText); | |
| 5777 var helpButton = document.getElementById('help'); | |
| 5778 helpButton.onmousedown = suppressEvent; | |
| 5779 var searchClear = document.getElementById('searchClear'); | |
| 5780 searchClear.onmousedown = suppressEvent; | |
| 5781 if (datasets > 1) { | |
| 5782 datasetDropDown.onmousedown = suppressEvent; | |
| 5783 var prevDatasetButton = document.getElementById('prevDataset'); | |
| 5784 prevDatasetButton.onmousedown = suppressEvent; | |
| 5785 var nextDatasetButton = document.getElementById('nextDataset'); | |
| 5786 nextDatasetButton.onmousedown = suppressEvent; | |
| 5787 var lastDatasetButton = document.getElementById('lastDataset'); | |
| 5788 lastDatasetButton.onmousedown = suppressEvent; | |
| 5789 } | |
| 5790 | |
| 5791 image = document.getElementById('hiddenImage'); | |
| 5792 | |
| 5793 if (image.complete) { | |
| 5794 hiddenPattern = context.createPattern(image, 'repeat'); | |
| 5795 } | |
| 5796 else { | |
| 5797 image.onload = function () { | |
| 5798 hiddenPattern = context.createPattern(image, 'repeat'); | |
| 5799 } | |
| 5800 } | |
| 5801 | |
| 5802 var loadingImageElement = document.getElementById('loadingImage'); | |
| 5803 | |
| 5804 if (loadingImageElement) { | |
| 5805 loadingImage = loadingImageElement.src; | |
| 5806 } | |
| 5807 } | |
| 5808 | |
| 5809 function selectDataset(newDataset) { | |
| 5810 lastDataset = currentDataset; | |
| 5811 currentDataset = newDataset | |
| 5812 if (datasets > 1) { | |
| 5813 datasetDropDown.selectedIndex = currentDataset; | |
| 5814 updateDatasetButtons(); | |
| 5815 datasetAlpha.start = 1.5; | |
| 5816 datasetChanged = true; | |
| 5817 } | |
| 5818 head.setMagnitudes(0); | |
| 5819 head.setDepth(1, 1); | |
| 5820 head.setMaxDepths(); | |
| 5821 handleResize(); | |
| 5822 } | |
| 5823 | |
| 5824 function selectLastDataset() { | |
| 5825 selectDataset(lastDataset); | |
| 5826 } | |
| 5827 | |
| 5828 function selectNode(newNode) { | |
| 5829 if (selectedNode != newNode) { | |
| 5830 // truncate history at current location to create a new branch | |
| 5831 // | |
| 5832 nodeHistory.length = nodeHistoryPosition; | |
| 5833 | |
| 5834 if (selectedNode != 0) { | |
| 5835 nodeHistory.push(selectedNode); | |
| 5836 nodeHistoryPosition++; | |
| 5837 } | |
| 5838 | |
| 5839 setSelectedNode(newNode); | |
| 5840 //updateView(); | |
| 5841 } | |
| 5842 | |
| 5843 updateDatasetButtons(); | |
| 5844 } | |
| 5845 | |
| 5846 function selectRank(rank) { | |
| 5847 rankDropDown.value = rank; | |
| 5848 currentRank = rank; | |
| 5849 datasetsVisible = 0; | |
| 5850 for (var i = 0; i < datasets; i++) { | |
| 5851 if (currentRank === 'ALL' | |
| 5852 || i < numRawSamples | |
| 5853 || (currentRank !== NO_RANK && ( | |
| 5854 datasetNames[i].endsWith('EXCLUSIVE_' + currentRank) || | |
| 5855 datasetNames[i].endsWith('SHARED_' + currentRank) || | |
| 5856 datasetNames[i].endsWith('CONTROL_SHARED' + currentRank) || | |
| 5857 datasetNames[i].endsWith('CTRL_' + currentRank)))) { | |
| 5858 datasetDropDown.options[i].hidden = false; | |
| 5859 datasetsVisible++; | |
| 5860 } else { | |
| 5861 datasetDropDown.options[i].hidden = true; | |
| 5862 } | |
| 5863 } | |
| 5864 if (datasetDropDown.options[currentDataset].hidden === true) { | |
| 5865 selectDataset(0); | |
| 5866 } else { | |
| 5867 selectDataset(currentDataset); | |
| 5868 } | |
| 5869 datasetDropDown.size = (datasetsVisible < DATASET_MAX_SIZE ? | |
| 5870 datasetsVisible : DATASET_MAX_SIZE); | |
| 5871 } | |
| 5872 | |
| 5873 function setFocus(node) { | |
| 5874 if (node == focusNode) { | |
| 5875 // return; | |
| 5876 } | |
| 5877 | |
| 5878 focusNode = node; | |
| 5879 | |
| 5880 if (node.href) { | |
| 5881 detailsName.innerHTML = | |
| 5882 '<a target="_blank" href="' + node.href + '">' + node.name + '</a>'; | |
| 5883 } | |
| 5884 else { | |
| 5885 detailsName.innerHTML = node.name; | |
| 5886 } | |
| 5887 | |
| 5888 var table = '<table>'; | |
| 5889 | |
| 5890 table += '<tr><td></td></tr>'; | |
| 5891 | |
| 5892 for (var i = 0; i < node.attributes.length; i++) { | |
| 5893 if (attributes[i].displayName && node.attributes[i] != undefined) { | |
| 5894 var index = node.attributes[i].length == 1 | |
| 5895 && attributes[i].mono ? 0 : currentDataset; | |
| 5896 | |
| 5897 if (typeof node.attributes[i][currentDataset] == 'number' | |
| 5898 || node.attributes[i][index] != undefined | |
| 5899 && node.attributes[i][currentDataset] != '') { | |
| 5900 var value = node.attributes[i][index]; | |
| 5901 | |
| 5902 if (attributes[i].listNode != undefined) { | |
| 5903 value = | |
| 5904 '<a href="" onclick="showList(' + | |
| 5905 attributeIndex(attributes[i].listNode) + ',' + i + | |
| 5906 ',false);return false;" title="Show list">' + | |
| 5907 value + '</a>'; | |
| 5908 } | |
| 5909 else if (attributes[i].listAll != undefined) { | |
| 5910 value = | |
| 5911 '<a href="" onclick="showList(' + | |
| 5912 attributeIndex(attributes[i].listAll) + ',' + i + | |
| 5913 ',true);return false;" title="Show list">' + | |
| 5914 value + '</a>'; | |
| 5915 } | |
| 5916 else if (attributes[i].dataNode != undefined && dataEnabled) { | |
| 5917 value = | |
| 5918 '<a href="" onclick="showData(' + | |
| 5919 attributeIndex(attributes[i].dataNode) + ',' + i + | |
| 5920 ',false);return false;" title="Show data">' + | |
| 5921 value + '</a>'; | |
| 5922 } | |
| 5923 else if (attributes[i].dataAll != undefined && dataEnabled) { | |
| 5924 value = | |
| 5925 '<a href="" onclick="showData(' + | |
| 5926 attributeIndex(attributes[i].dataAll) + ',' + i + | |
| 5927 ',true);return false;" title="Show data">' + | |
| 5928 value + '</a>'; | |
| 5929 } | |
| 5930 | |
| 5931 table += | |
| 5932 '<tr><td class="CellWithTooltip">' + | |
| 5933 '<strong>' + attributes[i].displayName + ':</strong>' + | |
| 5934 '<span class="Tooltip">' + | |
| 5935 attributes[i].tip + '</span>' + | |
| 5936 '</td><td>' + value + '</td></tr>'; | |
| 5937 } | |
| 5938 } | |
| 5939 } | |
| 5940 | |
| 5941 table += '</table>'; | |
| 5942 detailsInfo.innerHTML = table; | |
| 5943 | |
| 5944 detailsExpand.disabled = !focusNode.hasChildren() | |
| 5945 || focusNode == selectedNode; | |
| 5946 } | |
| 5947 | |
| 5948 function setSelectedNode(newNode) { | |
| 5949 if (selectedNode && selectedNode.hasParent(newNode)) { | |
| 5950 zoomOut = true; | |
| 5951 } | |
| 5952 else { | |
| 5953 zoomOut = false; | |
| 5954 } | |
| 5955 | |
| 5956 selectedNodeLast = selectedNode; | |
| 5957 selectedNode = newNode; | |
| 5958 | |
| 5959 //if ( focusNode != selectedNode ) | |
| 5960 { | |
| 5961 setFocus(selectedNode); | |
| 5962 } | |
| 5963 } | |
| 5964 | |
| 5965 function waitForData(dataWindow, target, title, time, postUrl, postVar) { | |
| 5966 if (nodeData.length == target) { | |
| 5967 if (postUrl != undefined) { | |
| 5968 for (var i = 0; i < nodeData.length; i++) { | |
| 5969 nodeData[i] = nodeData[i].replace(/\n/g, ','); | |
| 5970 } | |
| 5971 | |
| 5972 var postString = nodeData.join(''); | |
| 5973 postString = postString.slice(0, -1); | |
| 5974 | |
| 5975 dataWindow.document.body.removeChild(dataWindow.document.getElementById('loading')); | |
| 5976 document.body.removeChild(document.getElementById('data')); | |
| 5977 | |
| 5978 post(postUrl, postVar, postString, dataWindow); | |
| 5979 } | |
| 5980 else { | |
| 5981 //dataWindow.document.body.removeChild(dataWindow.document.getElementById('loading')); | |
| 5982 //document.body.removeChild(document.getElementById('data')); | |
| 5983 | |
| 5984 dataWindow.document.open(); | |
| 5985 dataWindow.document.write('<pre>' + nodeData.join('') + '</pre>'); | |
| 5986 dataWindow.document.close(); | |
| 5987 } | |
| 5988 | |
| 5989 dataWindow.document.title = title; // replace after document.write() | |
| 5990 } | |
| 5991 else { | |
| 5992 var date = new Date(); | |
| 5993 | |
| 5994 if (date.getTime() - time > 10000) { | |
| 5995 dataWindow.document.body.removeChild(dataWindow.document.getElementById('loading')); | |
| 5996 document.body.removeChild(document.getElementById('data')); | |
| 5997 dataWindow.document.body.innerHTML = | |
| 5998 'Timed out loading supplemental files for:<br/>' + document.location; | |
| 5999 } | |
| 6000 else { | |
| 6001 setTimeout(function () { | |
| 6002 waitForData(dataWindow, target, title, time, postUrl, postVar); | |
| 6003 }, 100); | |
| 6004 } | |
| 6005 } | |
| 6006 } | |
| 6007 | |
| 6008 function data(newData) { | |
| 6009 nodeData.push(newData); | |
| 6010 } | |
| 6011 | |
| 6012 function enableData() { | |
| 6013 dataEnabled = true; | |
| 6014 } | |
| 6015 | |
| 6016 function showData(indexData, indexAttribute, summary) { | |
| 6017 var dataWindow = window.open('', '_blank'); | |
| 6018 var title = 'Re@ - ' + attributes[indexAttribute].displayName | |
| 6019 + ' - ' + focusNode.name; | |
| 6020 dataWindow.document.title = title; | |
| 6021 | |
| 6022 nodeData = new Array(); | |
| 6023 | |
| 6024 if (dataWindow && dataWindow.document && dataWindow.document.body != null) { | |
| 6025 //var loadImage = document.createElement('img'); | |
| 6026 //loadImage.src = "file://localhost/Users/ondovb/Krona/KronaTools/img/loading.gif"; | |
| 6027 //loadImage.id = "loading"; | |
| 6028 //loadImage.alt = "Loading..."; | |
| 6029 //dataWindow.document.body.appendChild(loadImage); | |
| 6030 dataWindow.document.body.innerHTML = | |
| 6031 '<img id="loading" src="' + loadingImage + '" alt="Loading..."></img>'; | |
| 6032 } | |
| 6033 | |
| 6034 var scripts = document.createElement('div'); | |
| 6035 scripts.id = 'data'; | |
| 6036 document.body.appendChild(scripts); | |
| 6037 | |
| 6038 var files = focusNode.getData(indexData, summary); | |
| 6039 | |
| 6040 var date = new Date(); | |
| 6041 var time = date.getTime(); | |
| 6042 | |
| 6043 for (var i = 0; i < files.length; i++) { | |
| 6044 var script = document.createElement('script'); | |
| 6045 script.src = files[i] + '?' + time; | |
| 6046 scripts.appendChild(script); | |
| 6047 } | |
| 6048 | |
| 6049 waitForData(dataWindow, files.length, title, time, | |
| 6050 attributes[indexAttribute].postUrl, attributes[indexAttribute].postVar); | |
| 6051 | |
| 6052 return false; | |
| 6053 } | |
| 6054 | |
| 6055 function showList(indexList, indexAttribute, summary) { | |
| 6056 var list = focusNode.getList(indexList, summary); | |
| 6057 | |
| 6058 if (attributes[indexAttribute].postUrl != undefined) { | |
| 6059 post(attributes[indexAttribute].postUrl, | |
| 6060 attributes[indexAttribute].postVar, list.join(',')); | |
| 6061 } | |
| 6062 else { | |
| 6063 var dataWindow = window.open('', '_blank'); | |
| 6064 | |
| 6065 if (true || navigator.appName == 'Microsoft Internet Explorer') // :( | |
| 6066 { | |
| 6067 dataWindow.document.open(); | |
| 6068 dataWindow.document.write('<pre>' + list.join('\n') + '</pre>'); | |
| 6069 dataWindow.document.close(); | |
| 6070 } | |
| 6071 else { | |
| 6072 var pre = document.createElement('pre'); | |
| 6073 dataWindow.document.body.appendChild(pre); | |
| 6074 pre.innerHTML = list; | |
| 6075 } | |
| 6076 | |
| 6077 dataWindow.document.title = 'Re@ - ' + | |
| 6078 attributes[indexAttribute].displayName + ' - ' + focusNode.name; | |
| 6079 } | |
| 6080 } | |
| 6081 | |
| 6082 function snapshot() { | |
| 6083 svg = svgHeader(); | |
| 6084 | |
| 6085 resetKeyOffset(); | |
| 6086 | |
| 6087 snapshotMode = true; | |
| 6088 | |
| 6089 selectedNode.draw(false, true); | |
| 6090 selectedNode.draw(true, true); | |
| 6091 | |
| 6092 if (focusNode != 0 && focusNode != selectedNode) { | |
| 6093 context.globalAlpha = 1; | |
| 6094 focusNode.drawHighlight(true); | |
| 6095 } | |
| 6096 | |
| 6097 if (hueDisplayName && useHue()) { | |
| 6098 drawLegendSVG(); | |
| 6099 } | |
| 6100 | |
| 6101 snapshotMode = false; | |
| 6102 | |
| 6103 svg += svgFooter(); | |
| 6104 | |
| 6105 var snapshotWindow = window.open('', '_blank', '', 'replace=false'); | |
| 6106 snapshotWindow.document.write('<html><body>' + | |
| 6107 '<button title="Download Rec@ntrifuge snapshot as SVG file" ' + | |
| 6108 'onclick="document.getElementById(\'link\').click()">' + | |
| 6109 'Download</button><a id="link" href="data:image/svg+xml,' + | |
| 6110 encodeURIComponent(svg) + '" download="Recfg_snapshot.svg" hidden>' + | |
| 6111 'Download</a><br></html></body>'); | |
| 6112 snapshotWindow.document.title = 'Re@ [snapshot] ' + | |
| 6113 location.href.split("/").slice(-1)[0].split(".html")[0]; | |
| 6114 snapshotWindow.document.write(svg); | |
| 6115 } | |
| 6116 | |
| 6117 function save() { | |
| 6118 alert(document.body.innerHTML); | |
| 6119 } | |
| 6120 | |
| 6121 function spacer() { | |
| 6122 if (snapshotMode) { | |
| 6123 return '   '; | |
| 6124 } | |
| 6125 else { | |
| 6126 return ' '; | |
| 6127 } | |
| 6128 } | |
| 6129 | |
| 6130 function suppressEvent(e) { | |
| 6131 e.cancelBubble = true; | |
| 6132 if (e.stopPropagation) e.stopPropagation(); | |
| 6133 } | |
| 6134 | |
| 6135 function svgFooter() { | |
| 6136 return '</svg>'; | |
| 6137 } | |
| 6138 | |
| 6139 function svgHeader() { | |
| 6140 var patternWidth = fontSize * .6;//radius / 50; | |
| 6141 | |
| 6142 return '\ | |
| 6143 <?xml version="1.0" standalone="no"?>\ | |
| 6144 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" \ | |
| 6145 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\ | |
| 6146 <svg width="' + imageWidth + '" height="' + imageHeight + '" version="1.1"\ | |
| 6147 xmlns="http://www.w3.org/2000/svg">\ | |
| 6148 <title>Rec@ntrifuge (snapshot) - ' + | |
| 6149 (datasets > 1 ? datasetNames[currentDataset] + ' - ' : '') | |
| 6150 + selectedNode.name + | |
| 6151 '</title>\ | |
| 6152 <defs>\ | |
| 6153 <style type="text/css">\ | |
| 6154 @import url("https://fonts.googleapis.com/css?family=' + fontFamily + '");\ | |
| 6155 text {font-size: ' + fontSize + 'px; font-family: ' + fontFamily | |
| 6156 + '; dominant-baseline:central}\ | |
| 6157 path {stroke-width:' + thinLineWidth * fontSize / 12 + ';}\ | |
| 6158 path.wedge {stroke:none}\ | |
| 6159 path.line {fill:none;stroke:black;}\ | |
| 6160 line {stroke:black;stroke-width:' + thinLineWidth * fontSize / 12 + ';}\ | |
| 6161 line.tick {stroke-width:' + thinLineWidth * fontSize / 6 + ';}\ | |
| 6162 line.pattern {stroke-width:' + thinLineWidth * fontSize / 18 + ';}\ | |
| 6163 circle {fill:none;stroke:black;stroke-width:' + thinLineWidth | |
| 6164 * fontSize / 12 + ';}\ | |
| 6165 rect {stroke:black;stroke-width:' + thinLineWidth * fontSize / 12 + ';}\ | |
| 6166 .highlight {stroke:black;stroke-width:' + highlightLineWidth | |
| 6167 * fontSize / 12 + ';}\ | |
| 6168 .searchHighlight {fill:rgb(255, 255, 100);stroke:none;}\ | |
| 6169 </style>\ | |
| 6170 <pattern id="hiddenPattern" patternUnits="userSpaceOnUse" \ | |
| 6171 x="0" y="0" width="' + patternWidth + '" height="' + patternWidth + '">\ | |
| 6172 <line class="pattern" x1="0" y1="0" x2="' + patternWidth / 2 + '" y2="' | |
| 6173 + patternWidth / 2 + '"/>\ | |
| 6174 <line class="pattern" x1="' + patternWidth / 2 + '" y1="' + patternWidth + | |
| 6175 '" x2="' + patternWidth + '" y2="' + patternWidth / 2 + '"/>\ | |
| 6176 </pattern>\ | |
| 6177 </defs>\ | |
| 6178 '; | |
| 6179 } | |
| 6180 | |
| 6181 function svgText(text, x, y, anchor, bold, color) { | |
| 6182 if (typeof(anchor) == 'undefined') { | |
| 6183 anchor = 'start'; | |
| 6184 } | |
| 6185 | |
| 6186 if (color == undefined) { | |
| 6187 color = 'black'; | |
| 6188 } | |
| 6189 | |
| 6190 return '<text x="' + x + '" y="' + y + | |
| 6191 '" style="font-color:' + color + ';font-weight:' | |
| 6192 + (bold ? 'bold' : 'normal') + | |
| 6193 '" text-anchor="' + anchor + '">' + text + '</text>'; | |
| 6194 } | |
| 6195 | |
| 6196 function toggleKeys() { | |
| 6197 if (showKeys) { | |
| 6198 keyControl.value = '…'; | |
| 6199 showKeys = false; | |
| 6200 } | |
| 6201 else { | |
| 6202 keyControl.value = 'x'; | |
| 6203 showKeys = true; | |
| 6204 } | |
| 6205 | |
| 6206 updateKeyControl(); | |
| 6207 | |
| 6208 if (progress == 1) { | |
| 6209 draw(); | |
| 6210 } | |
| 6211 } | |
| 6212 | |
| 6213 function update() { | |
| 6214 if (!head) { | |
| 6215 return; | |
| 6216 } | |
| 6217 | |
| 6218 if (mouseDown && focusNode != selectedNode) { | |
| 6219 var date = new Date(); | |
| 6220 | |
| 6221 if (date.getTime() - mouseDownTime > quickLookHoldLength) { | |
| 6222 if (focusNode.hasChildren()) { | |
| 6223 expand(focusNode); | |
| 6224 quickLook = true; | |
| 6225 } | |
| 6226 } | |
| 6227 } | |
| 6228 | |
| 6229 if (updateViewNeeded) { | |
| 6230 resize(); | |
| 6231 mouseX = -1; | |
| 6232 mouseY = -1; | |
| 6233 | |
| 6234 collapse = collapseCheckBox.checked; | |
| 6235 compress = true;//compressCheckBox.checked; | |
| 6236 shorten = true;//shortenCheckBox.checked; | |
| 6237 | |
| 6238 checkSelectedCollapse(); | |
| 6239 updateMaxAbsoluteDepth(); | |
| 6240 | |
| 6241 if (focusNode.getCollapse() || focusNode.depth > maxAbsoluteDepth) { | |
| 6242 setFocus(selectedNode); | |
| 6243 } | |
| 6244 else { | |
| 6245 setFocus(focusNode); | |
| 6246 } | |
| 6247 | |
| 6248 updateView(); | |
| 6249 | |
| 6250 updateViewNeeded = false; | |
| 6251 } | |
| 6252 | |
| 6253 var date = new Date(); | |
| 6254 progress = (date.getTime() - tweenStartTime) / tweenLength; | |
| 6255 // progress += .01; | |
| 6256 | |
| 6257 if (progress >= 1) { | |
| 6258 progress = 1; | |
| 6259 } | |
| 6260 | |
| 6261 if (progress != progressLast) { | |
| 6262 tweenFactor =// progress; | |
| 6263 (1 / (1 + Math.exp(-tweenCurvature * (progress - .5))) - .5) / | |
| 6264 (tweenMax - .5) / 2 + .5; | |
| 6265 | |
| 6266 if (progress == 1) { | |
| 6267 snapshotButton.disabled = false; | |
| 6268 zoomOut = false; | |
| 6269 | |
| 6270 //updateKeyControl(); | |
| 6271 | |
| 6272 if (!quickLook) { | |
| 6273 //checkHighlight(); | |
| 6274 } | |
| 6275 | |
| 6276 | |
| 6277 if (fpsDisplay) { | |
| 6278 fpsDisplay.innerHTML = 'fps: ' | |
| 6279 + Math.round(tweenFrames * 1000 / tweenLength); | |
| 6280 } | |
| 6281 } | |
| 6282 | |
| 6283 draw(); | |
| 6284 } | |
| 6285 | |
| 6286 progressLast = progress; | |
| 6287 } | |
| 6288 | |
| 6289 function updateDatasetButtons() { | |
| 6290 if (datasets == 1) { | |
| 6291 return; | |
| 6292 } | |
| 6293 | |
| 6294 var node = selectedNode ? selectedNode : head; | |
| 6295 | |
| 6296 datasetButtonLast.disabled = | |
| 6297 node.attributes[magnitudeIndex][lastDataset] == 0; | |
| 6298 | |
| 6299 datasetButtonPrev.disabled = true; | |
| 6300 datasetButtonNext.disabled = true; | |
| 6301 | |
| 6302 for (var i = 0; i < datasets; i++) { | |
| 6303 var disable = node.attributes[magnitudeIndex][i] == 0; | |
| 6304 | |
| 6305 datasetDropDown.options[i].disabled = disable; | |
| 6306 | |
| 6307 if (!disable) { | |
| 6308 if (i != currentDataset) { | |
| 6309 datasetButtonPrev.disabled = false; | |
| 6310 datasetButtonNext.disabled = false; | |
| 6311 } | |
| 6312 } | |
| 6313 } | |
| 6314 } | |
| 6315 | |
| 6316 function updateDatasetWidths() { | |
| 6317 if (datasets > 1) { | |
| 6318 for (var i = 0; i < datasets; i++) { | |
| 6319 context.font = fontBold; | |
| 6320 var dim = context.measureText(datasetNames[i]); | |
| 6321 datasetWidths[i] = dim.width; | |
| 6322 } | |
| 6323 } | |
| 6324 } | |
| 6325 | |
| 6326 function updateKeyControl() { | |
| 6327 if (keys == 0)//|| progress != 1 ) | |
| 6328 { | |
| 6329 keyControl.style.visibility = 'hidden'; | |
| 6330 } | |
| 6331 else { | |
| 6332 keyControl.style.visibility = 'visible'; | |
| 6333 keyControl.style.right = margin + 'px'; | |
| 6334 | |
| 6335 if (showKeys) { | |
| 6336 keyControl.style.top = | |
| 6337 imageHeight - | |
| 6338 ( | |
| 6339 keys * (keySize + keyBuffer) - | |
| 6340 keyBuffer + | |
| 6341 margin + | |
| 6342 keyControl.clientHeight * 1.5 | |
| 6343 ) + 'px'; | |
| 6344 } | |
| 6345 else { | |
| 6346 keyControl.style.top = | |
| 6347 (imageHeight - margin - keyControl.clientHeight) + 'px'; | |
| 6348 } | |
| 6349 } | |
| 6350 } | |
| 6351 | |
| 6352 function updateView() { | |
| 6353 if (selectedNode.depth > maxAbsoluteDepth - 1) { | |
| 6354 maxAbsoluteDepth = selectedNode.depth + 1; | |
| 6355 } | |
| 6356 | |
| 6357 highlightedNode = selectedNode; | |
| 6358 | |
| 6359 angleFactor = 2 * Math.PI / (selectedNode.magnitude); | |
| 6360 | |
| 6361 maxPossibleDepth = Math.floor(gRadius / (fontSize * minRingWidthFactor)); | |
| 6362 | |
| 6363 if (maxPossibleDepth < 4) { | |
| 6364 maxPossibleDepth = 4; | |
| 6365 } | |
| 6366 | |
| 6367 var minRadiusInner = fontSize * 8 / gRadius; | |
| 6368 var minRadiusFirst = fontSize * 6 / gRadius; | |
| 6369 var minRadiusOuter = fontSize * 5 / gRadius; | |
| 6370 | |
| 6371 if (.25 < minRadiusInner) { | |
| 6372 minRadiusInner = .25; | |
| 6373 } | |
| 6374 | |
| 6375 if (.15 < minRadiusFirst) { | |
| 6376 minRadiusFirst = .15; | |
| 6377 } | |
| 6378 | |
| 6379 if (.15 < minRadiusOuter) { | |
| 6380 minRadiusOuter = .15; | |
| 6381 } | |
| 6382 | |
| 6383 // visibility of nodes depends on the depth they are displayed at, | |
| 6384 // so we need to set the max depth assuming they can all be displayed | |
| 6385 // and iterate it down based on the deepest child node we can display | |
| 6386 // | |
| 6387 var maxDepth; | |
| 6388 var newMaxDepth = selectedNode.getMaxDepth() - selectedNode.getDepth() + 1; | |
| 6389 // | |
| 6390 do { | |
| 6391 maxDepth = newMaxDepth; | |
| 6392 | |
| 6393 if (!compress && maxDepth > maxPossibleDepth) { | |
| 6394 maxDepth = maxPossibleDepth; | |
| 6395 } | |
| 6396 | |
| 6397 if (compress) { | |
| 6398 compressedRadii = new Array(maxDepth); | |
| 6399 | |
| 6400 compressedRadii[0] = minRadiusInner; | |
| 6401 | |
| 6402 var offset = 0; | |
| 6403 | |
| 6404 while | |
| 6405 ( | |
| 6406 lerp | |
| 6407 ( | |
| 6408 Math.atan(offset + 2), | |
| 6409 Math.atan(offset + 1), | |
| 6410 Math.atan(maxDepth + offset - 1), | |
| 6411 minRadiusInner, | |
| 6412 1 - minRadiusOuter | |
| 6413 ) - minRadiusInner > minRadiusFirst && | |
| 6414 offset < 10 | |
| 6415 ) { | |
| 6416 offset++; | |
| 6417 } | |
| 6418 | |
| 6419 offset--; | |
| 6420 | |
| 6421 for (var i = 1; i < maxDepth; i++) { | |
| 6422 compressedRadii[i] = lerp | |
| 6423 ( | |
| 6424 Math.atan(i + offset), | |
| 6425 Math.atan(offset), | |
| 6426 Math.atan(maxDepth + offset - 1), | |
| 6427 minRadiusInner, | |
| 6428 1 - minRadiusOuter | |
| 6429 ) | |
| 6430 } | |
| 6431 } | |
| 6432 else { | |
| 6433 nodeRadius = 1 / maxDepth; | |
| 6434 } | |
| 6435 | |
| 6436 newMaxDepth = selectedNode.maxVisibleDepth(maxDepth); | |
| 6437 | |
| 6438 if (compress) { | |
| 6439 if (newMaxDepth <= maxPossibleDepth) { | |
| 6440 // compress | |
| 6441 } | |
| 6442 } | |
| 6443 else { | |
| 6444 if (newMaxDepth > maxPossibleDepth) { | |
| 6445 newMaxDepth = maxPossibleDepth; | |
| 6446 } | |
| 6447 } | |
| 6448 } | |
| 6449 while (newMaxDepth < maxDepth); | |
| 6450 | |
| 6451 maxDisplayDepth = maxDepth; | |
| 6452 | |
| 6453 lightnessFactor = (lightnessMax - lightnessBase) | |
| 6454 / (maxDepth > 8 ? 8 : maxDepth); | |
| 6455 keys = 0; | |
| 6456 | |
| 6457 nLabelOffsets = new Array(maxDisplayDepth - 1); | |
| 6458 labelOffsets = new Array(maxDisplayDepth - 1); | |
| 6459 labelLastNodes = new Array(maxDisplayDepth - 1); | |
| 6460 labelFirstNodes = new Array(maxDisplayDepth - 1); | |
| 6461 | |
| 6462 for (var i = 0; i < maxDisplayDepth - 1; i++) { | |
| 6463 if (compress) { | |
| 6464 if (i == maxDisplayDepth - 1) { | |
| 6465 nLabelOffsets[i] = 0; | |
| 6466 } | |
| 6467 else { | |
| 6468 var width = | |
| 6469 (compressedRadii[i + 1] - compressedRadii[i]) * | |
| 6470 gRadius; | |
| 6471 | |
| 6472 nLabelOffsets[i] = Math.floor(width / fontSize / 1.2); | |
| 6473 | |
| 6474 if (nLabelOffsets[i] > 2) { | |
| 6475 nLabelOffsets[i] = min | |
| 6476 ( | |
| 6477 Math.floor(width / fontSize / 1.75), | |
| 6478 5 | |
| 6479 ); | |
| 6480 } | |
| 6481 } | |
| 6482 } | |
| 6483 else { | |
| 6484 nLabelOffsets[i] = Math.max | |
| 6485 ( | |
| 6486 Math.floor(Math.sqrt((nodeRadius * gRadius / fontSize)) * 1.5), | |
| 6487 3 | |
| 6488 ); | |
| 6489 } | |
| 6490 | |
| 6491 labelOffsets[i] = Math.floor((nLabelOffsets[i] - 1) / 2); | |
| 6492 labelLastNodes[i] = new Array(nLabelOffsets[i] + 1); | |
| 6493 labelFirstNodes[i] = new Array(nLabelOffsets[i] + 1); | |
| 6494 | |
| 6495 for (var j = 0; j <= nLabelOffsets[i]; j++) { | |
| 6496 // these arrays will allow nodes with neighboring labels to link to | |
| 6497 // each other to determine max label length | |
| 6498 | |
| 6499 labelLastNodes[i][j] = 0; | |
| 6500 labelFirstNodes[i][j] = 0; | |
| 6501 } | |
| 6502 } | |
| 6503 | |
| 6504 fontSizeText.innerHTML = fontSize; | |
| 6505 fontNormal = fontSize + 'px ' + fontFamily; | |
| 6506 context.font = fontNormal; | |
| 6507 fontBold = 'bold ' + fontSize + 'px ' + fontFamily; | |
| 6508 tickLength = fontSize * .7; | |
| 6509 | |
| 6510 head.setTargets(0); | |
| 6511 | |
| 6512 keySize = ((imageHeight - margin * 3) * 1 / 2) / keys * 3 / 4; | |
| 6513 | |
| 6514 if (keySize > fontSize * maxKeySizeFactor) { | |
| 6515 keySize = fontSize * maxKeySizeFactor; | |
| 6516 } | |
| 6517 | |
| 6518 keyBuffer = keySize / 3; | |
| 6519 | |
| 6520 fontSizeLast = fontSize; | |
| 6521 | |
| 6522 if (datasetChanged) { | |
| 6523 datasetChanged = false; | |
| 6524 } | |
| 6525 else { | |
| 6526 datasetAlpha.start = 0; | |
| 6527 } | |
| 6528 | |
| 6529 var date = new Date(); | |
| 6530 tweenStartTime = date.getTime(); | |
| 6531 progress = 0; | |
| 6532 tweenFrames = 0; | |
| 6533 | |
| 6534 updateKeyControl(); | |
| 6535 updateDatasetWidths(); | |
| 6536 | |
| 6537 document.title = ('Re@ - ' + | |
| 6538 location.href.split("/").slice(-1)[0].split(".html")[0]); | |
| 6539 updateNavigationButtons(); | |
| 6540 snapshotButton.disabled = true; | |
| 6541 | |
| 6542 maxAbsoluteDepthText.innerHTML = maxAbsoluteDepth - 1; | |
| 6543 | |
| 6544 maxAbsoluteDepthButtonDecrease.disabled = (maxAbsoluteDepth == 2); | |
| 6545 maxAbsoluteDepthButtonIncrease.disabled = | |
| 6546 (maxAbsoluteDepth == head.maxDepth); | |
| 6547 | |
| 6548 bkgBrightButtonDecrease.disabled = (bkgBright == '555555'); | |
| 6549 bkgBrightButtonIncrease.disabled = (bkgBright == 'ffffff'); | |
| 6550 | |
| 6551 if (collapse != collapseLast && search.value != '') { | |
| 6552 onSearchChange(); | |
| 6553 collapseLast = collapse; | |
| 6554 } | |
| 6555 } | |
| 6556 | |
| 6557 function updateMaxAbsoluteDepth() { | |
| 6558 while (maxAbsoluteDepth > 1 && selectedNode.depth > maxAbsoluteDepth - 1) { | |
| 6559 selectedNode = selectedNode.getParent(); | |
| 6560 } | |
| 6561 } | |
| 6562 | |
| 6563 function updateNavigationButtons() { | |
| 6564 backButton.disabled = (nodeHistoryPosition == 0); | |
| 6565 // upButton.disabled = (selectedNode.getParent() == 0); | |
| 6566 forwardButton.disabled = (nodeHistoryPosition == nodeHistory.length); | |
| 6567 } | |
| 6568 | |
| 6569 function useHue() { | |
| 6570 return useHueCheckBox && useHueCheckBox.checked; | |
| 6571 } | |
| 6572 | |
| 6573 /* | |
| 6574 function zoomOut() | |
| 6575 { | |
| 6576 return ( | |
| 6577 selectedNodeLast != 0 && | |
| 6578 selectedNodeLast.getDepth() < selectedNode.getDepth()); | |
| 6579 } | |
| 6580 */</script></head><body><img id="hiddenImage" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oLCBQhNQwWVnsAAAAidEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAABE0lEQVQYGQEIAff+AwAAABkAAAAAAAAA+gAAAAAAAAAAAAAAAAAAAAAAAAAMAwAAAAAAAAANAAAAAAAAAPoAAAAAAAAADAAAAAYAAAD0AwAAAPoAAAAAAAAAAAAAAPoAAAAMAAAADQAAAPoAAAD6AAAAAAAAAAAAAAAAAAAAAAwAAAAZAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAABkAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAGQAAAAwAAAAAAAAADAAAAAwAAAAABAAAAAAAAAAAAAAA8wAAAPQAAAAAAAAAAAAAAA0AAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAZRssKC5OpXwYAAAAASUVORK5CYII=" style="display:none"><img id="loadingImage" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" style="display:none"><img id="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAakAAABkCAYAAAA8Lc+FAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4gYZFgwotKLFqAAAIABJREFUeNrtnXmYVMXVh9/q7umZnhl2RBbZQUEFUVkVcQFxBTUK4kJiEgU1UWQgavw0kmiCIouKEbckYhAV3EBUNIgbKG4RIyC7CAqyD9t0z0x31/dHXXToube7bs/tmWGm3ufpR+ypvl1dt2796lSdOgcMBoPBYDAYDAaDwWAwGAwGg8FgMBgMBoPBYDAYDAaDwWAwGAwGg8Fg0EIA7Ty4jgR2AXtMkxoMBoPBS5GSHl6vCFgHfAEsAuYC200zGww1nvrWc6/DyUBhBb/PB5wInA70AZoCjYFgQrnpwF/M7Tm8kRl8RYE5wGmmmQ2GGk1DF+NCowp8Tx7we2CV5nc9ZG6NESnd14tAc9PcBoMRqTS/43jga5fjjhEpI1KuXluAU02TGwxGpFxyKRBJY8wxInWY46vk72sKvA2caZreYDBo0gt4Bsg2TVH7CFTBd+YCrwDdgbXmFhgMP/Ey0Eqj3C0ox6TaQB3Uvnau6R5GpCqTesDz1gwpZm7D4Ym8lTrEcjsh48cgfB2Jx5siRB0kdQEQFIE4AHIHiPUIsR5/fLmYEP7etJ4txwFHaz4/tYWxwJGmaxiRqgpOBkYCj5rbcJiI0hD8HJVzJkIMAM4kyskg/SBAShACS5zKfurn/0oJUZAFoU3KEhDvIvyviEn7dpjWNdjQECgwzWBEqiq5G/gnakPUUF3FaWz+8cjYNUiuBJp5cMmWwBUgr0BGp8kxue8i4/+mNPKCmEqxaXGDxVAg3zSDESld7gK2JbznAxpYrxNQ56FCLq7ZBBgGPG1uRTUUp4JQbyR3Eo+dn2gfeYgfKQeAGEBW6H45Wk6D4CNiyt5d5g7Ues52UXYfsBT4MeH9paYZD2/cRJw4GliTokwOcLMlaLozoHeAAeZWVCfLKa8rUk5S4lEl7AbupW74ETGOklrU9KvQ25O6EHi9mtU9CxX9QYf3gVKNchstqzsVXwHnoY64GIxIadEHWGiJVipiKNd0sy9R1eI0glzyQnchGGMNOq7YWwKFxZK9xZK4hPygIMcPzfJFumbYOqT8rZgSed+IVLUXKa/JRoVZ0zkmcz7wpnmCayaZ2pP6GLgNvYN0fqAfyv3WUFUCNSa3B1I+j2bA4a1Fknc3xXl/U5z/7YizapdkZ8R+vpPth7b1BMc28nFqcx99W/jofqQPX2rlao8QC2VBaDKl4TvNflWtogH65zi/MM1lLCm3lhSoQI8rgbYaZScDY8ztqCKBKsi9DuRUUhyWLCyWzFoV45kVMT7aHK9QZOJmeYJLO/oZfqyfnk21xqLPiIuLxINFNXlJx1hSP9MG+NbFZNscZamhZDLiRIkL6+h4cyuqQJyG4Jejcx4H+UQygdpaJLntw1JaPhFh5IJSFldQoAC2HJA8sjRKr5nF9HmumNmrY6mu2QOf/ESOzetq7pwZmwymI3jFB5rlOptbUckCNY4ArUIzEGKEU5lwFO5cXEq7pyJM+CzK/tLM1GXJljhD55XQa2YxH3wfT1a0JXH5oRyT28PcQYPBiJQX6C4PNjG3olIFKsie0AtIhjmVWbAxTtdnIvz1kyhF0cqp12c/xjljVjEjF5QmEURZFynnG4vKYDAi5QU/aJbLRs8T0OAFe3MfR/ALuz/FJdy1uJSBLxaztlBWetUk8MT/onT7d4SvtjtaVQ2Jx9+WY3Jam5tpMBiRqtBwCMQ1y9Yxt6MSRKAgdBvIa+z+tqdYcv4rJdz7SdT1npNAOUP0buZjQCv1Ov0oH10a+8jLcl/PdYWSvs8XM2+94374kUjxohxnJjcGQ02mMsIiFaMXhaI+3qSar4Pa46qPCsQpUWewNgLfUXVeQEGrXkdYdRPAHqte6yHzh1bl6NxBIP9m97ddEck5L5Xw+da49vXa11ceev1b+enZVFA/WzhaR9/ukXzwfZy3NsR4bX2MAxr7W/tL4eI5JTxzXpArO/ntinRnb87DEBlRhc9PCBXtoLZR15qEGiqXeqiM5weqeT1zrGdjjwtDxXECnCkX9IMUohe1+WTgv2n+jl7A5SjX3A44h/ApRDlzPI/yPMz0uZuOwBXARUDXJJOCCLAEeAmYCXgeEkiOyjsSf/xrSyQPYWdEMmB2CUu3p+5LPgGD2/sZdWKAM1qmZ4jvL4XnV0Z54PMoq3en7n4BH8y6MMglHfxOlbpQTCzSdcnui17izeXAPJsB4mpgMCrVTMMy928dKlfaC8AnGte/2WbyNhZorPHZp1HHOxL5DHWI/iCD0XNKWgQsTiLE/YFzgR5AJ1TSwu0cupecA4zSvAcPA+GEieWNCWUaArdqXu+OJAPhF8AC699tUfEAU7EbeEKj3MFU9jpMSWMiGkSFjbsIOAloXWZsi1p9dCEwHRV1oyw9gLM0vmOtNe5UhLbAL6znqisq3UzZ9ZMdqOMVH1nP1IcudKdSRKpI05LqAixLQ5zGk14SxS3WZx/NgHXVBrjX6mB+t2M4MA24x8sZuiwIvWp19kMoicHAl4p5//vUAnX6UT4ePDOLbkd4s0ock/CvZVH+uCjKjnDybpgTgA8vz6b7kbbfvYH94ePEExRpfO04VGDjVMwAhpf5/6uABzVF5APgBmBFkjLbNa/lhikcGjV8pjVJSsXdwF8S3vNbv2GsNTja1b9Jgqjs1Kxn44SyLYBMpW95uIx4noteZIq11gQzFU3RD8VUx3q2delhTXh0zplKYJYlmAcj94xGnT9NxWvWZCYdTgX+BAx0+bm1wAOo4OIp3bIyvScl0HeIcGO+ZgETrNlfull+m1kd+GOHhzBdrgX+Zw1q/jQ+nw/8wZolneKJQI0OXWknUADXLyhJKVC5AXjy7CzeG5rtmUAB+AVc2yXAN9dkc2G75E0VicJlr5U4RbVoQ17orgz1YR9wvyVauqLSz7KMBx2mS0onWdbgVI+fDYMeV1gTnbaa5YW1kvSFprhWlHrAPywLfGAan+8APA58blleVSpS9dCPnq07y8hHZer8Q5oiYDdj+ZSKHygWwCTgSbxxAmkJvAtcXCGBGkcOgvF2f5u+Isa/lic3IjvUF3x+dQ7Xdsnc9mXjkGDuxUH+ckpyD4vv9kpuXFDq1Po3y7H5mTjK8JSLZafEmfMLwImH0eDot1YXPkUtvxsqn36o5bt0HIJaWWNGuwzWr63VP37jwbVOQC0BDqpKkdLNPVSEXoDZAPAiKuKxlzRBrVu3qcA1xuN9gragNdCdlfYV9oZGYZOSfNM+yah3k3svnNTEx6Jh2XRumHKeEQE5HynvRnIFUp6NlGeDuADECDUjl8tSKfxdvQNMG5CVdFYza3WM+RtshTWXWHyUx+0/Cvh1BT4fAmaTItxUNaEBKtTS7R5N/gzuaWT1l6wKXKOFNZa1yED9WlvW09EeXjPPGtPPSTboZxJd0/Nb9PbGxif7MRXkSGCuZVm5dai4HBVQNxMErZt4ArDJlRV1W4N6lEZut/vbDe+UsqfYucmPa+RjwWVBGuQkkwzxDfAQgaKZYkLq/TM5JtiJuH8EgutwSOVyfdcAO8LqrJYTNy0s5Ztr/AQSp1hC/k7exP1iqideZ6eC82FnF7QHfoXeRnxVcQxqea8jhqrkerwJbNA2AxPmPJTTQ/MMjXGzgN7AN5VtSfXVLLdSo8zJqM3ATNIFlQvLDQ1Re1uZnuU+6vpTpZFfo9zdD+GdjXFedz5/RPN8wZu/SCJQgp0IMZJNRV3E5KLHdQQKQEwqWSmmhAuI+Tqg9nhsubNXgMuOdp7Mry2UPLfStv71yMq5zMNlDa8mcbeSuaSRXnClEahqwXUeXsvr/jaOzMZYrQs8Y/fMZVKkAoDugLFIs5EqYxmiwOVsYRSVE9bpQlTmYz0rahw+bNxj4xL+8IGzleITMOO8IC3rOPbxD/HTTUwqekLMTs8rUjx0YKuYHB4OcriT1fr4gCya5zs/Z/d9Vupgeosrq+Hg0x441ozBhiQ0pfo6qbQBbqmE7+lurTqUE5JM8Wv0vVNSBaLtiEpsVhmEgJHouSlnW2Uri1tQZwxSszf3XJDtE9+evyHGl9ucvfnGnBzgTOfzTy9RGr5KTPbmfJmYHJkhx+ZsJi7mkXBMoWGO4G99s7hmvv3RkhU7JYt+iHNai3J1PVOOyjtSPHRgazV70M9CeWwe5B4yc07qcGQvai8scYXCq3NShwPV2cHm91RO4AesfvBPymz/ZOqLu6HObOiwAfgyRZmhaVh9e1BnL3KtGYqbzw/XFKkzUXtZbgijIl8IS8SDLj47COUxuSe1KSWH2Rn8D3/pbPy0yBf8qU+W0/Xe5EDkCvEEnsZCFxMjC2VB6FeoNelDb0JnPxM/97Fsh/348+w3MTuR8uGPn4FyOKlOnJR4K2zK/EZTpF6kZuWT2ody8y9LOxciNYHDP59U82paLx8Vcx5ySwfgdOC9shXwklzgd9ZsP0/zMzNI7TRxqos6rLMG80aoNdR2wFHAYy6u0Ra9NXo39dpjWV2NUVEAOln/vhX9k+hZwBkp9WkcQUR5t841uyVvb3B+lu89NYt8O40SrKI4MtSNQMmx2vcfMTk8G+ST5Z4OATd1c17hnbPOIQeVkGd42Kd3WTP17qhjAZ1RZ+FWu7xOo8Nw4CxCRWcZgXIoamX123NIZ4/UkIwGaVif/2dZYK1QgQ0m4n14teP5ObKKDkuBX6KccVqi/BKmoXFotwyHeG+7saRGUN5N3Gf9gIaWtXIq7vz7S1CHwlLRS/N6G1EHYLclvL8FdXp+O/qOEQNJHWFDt14Ra7nnvzYzyAf4OTSJzmZnf9Q5sSTdN3cAyHIOEy8kSSzYqo7gqs62ghAFcZV4NPk5NnlrbnNi8WuQ4jygD3H8soAw8CWSV4mGH0/qdSey7kBGh5IQQuuqzgFuea+UsE0X//GAZNUuSadEF3kp+nj0gO4AelI+Q+xKa/Cej75z0OEkUmFUBIrHUKHEElmFCgFl8A43QrAH6MOhnnCbUOeX5lr9MtejerkJKDAbFcSg7GT2e1TQhfnWGKejOQMp4y3txpIaC9yX8Pqb9f5vrMHT7QG0R1HLfcmo6+IG/tFGoMoyzsUMuKemxaX7O5PFJXwF/SzGGtab7G/37kurna2o358YIMu+NzwmJhU5ruur7L6hPxCVK5Hir9agfVDtQsApCCaQFVonR+de5KhRk/btQJR3087Lgl7NnLvpR5ttlwI7Sm+8m+7FOYX5AVQcP92Za93DZLBca83O73MQKENmcCMqd2Pjqm3xIeX39yqC7pmorahlQafVlrmoYAc6nFDWsqzKFM3fW4NAKlpqXi+a0sJQm6u6exWp9poE+gfmdAI4Pqd5rdQHpAXlLIlN+6RjAFmfwCnKeISYz/Ee/ZzdlwmkjrLRGCFflgU5v3S+O/7pdm/3a+HcTVftjts/8AWhoyrYP+Oo2HfJ+I6atTe02ZrFrjKaUenormpFUI4FyXg8xWTdDbrP0QukDm33d81rCcrs0VWVSEWAS9ELSKnr3v0devH/vta8XqrvrYNe4FxIHmj0IF9pXqsxSawEeRPZyHKb9Cze7OzRd1oLHy1s3b3Fs0m95PbmPp4su6+dHoKYJguy7WdnU/avwCZdS98Wyc9MOUhMqwr20TXopY5ZXIMGymuTWI6G6iFSn5A68HQJP0d+ryi6Dh2fa5TZhH4i3CZuG8ZrgboKtX6qg64Q6EYM113CaORRvUAv784O9N1l83CKdejPPQ5kuTA8HyURqbNbO4iAjE93FMOxuRcQl+nE78oF3w3YHMwWIKV6CC88xHRM4oLhGD1d+CoaP3G9Zrkt1AzmoRch3FC1IrVSs9xqj+ql6wClGwF/G3orUEdUlUjtQgVM/dDFZ3T3uWIelxMe1UvN6/XEs3uFW9gv29l5RyQ7G3X6UbYG9XamRGwPWUsQxOVEu7+VxuGlNTGW7YjTu5mPC9r57RpyEI7RQ8SuRGfP/KDzrdjntCMk4hUVKd1JT7iGDJL3G52oUnQDFRR63H+9Gn91PX/deDJXukjNRSU2+8Hl54LVtFNVz3rFaWunCt/ucfby72qffuMD4XQ0oCDnLJQr8qGqFlbZfcsK4lmtfORnCW48wc85bX56DpM4wshyS7b5ScJtxp1+lqyw40QJtYet1Kxly8MR4XG/lB7Vq8qDI1fWntR0VD6jH0xfzHhXLxdaJRKFLQfs+2zzfEFdO7mVcmmSL7FNH3LjO6XlLLaFG+Ns3CuJy0POSexM8miVyxycLNW8o4AJsd90Bm3+6+GgZqid4pkxKsuS6m3udSUhqZvYrXaEpaPF0TzPqQ+KZGva3e0stUQX9xOO8PGXUwKxQe39fnFIX5MzkjwS5UI5rSt0Hj/rOwbBjRuR0udH0wSG6oobkZqIfc6na7BZ+kngGFSE8a9Nk2d83lNuDTmc5Kx3PUdjXu5K8i3lzoct+iF+yFR8+rlBhh/rR5Rfa9+KFE/ZfuPt9RpQUnJc4vvr9zjvp7Wt6yBSPrnFdAZttpkmMNQEkXoC+wgMEr1N18szLFLtsIn/ZkOTGn1HBTmJCzeRmLMlku13GuRFJMm3lJO23Qm5qeauizH82HJ7wbvBd46YcsB+2be4eDBClFt8/HKbc/071Letf5Q9xRvM461NkWkCQwU5H73gBq7HXy+W+17RFKlhwJ0ZbKQGwJBa31Vk+b0FX5JVZUcBkzI7xaB2SNilxHNWL62Jcfz0CNd3DdA8XyCl+PCyTlmXiYn7t9lXGwHihsT34xJeWevskNnTPhrFRq8D4RoMhqRkLJWHFyK1BhWio3OKcu1R4Va+NPczo6ZUYeIeeP1sZ5Xa7+grJJJF4/6GhEN+A1r5CAUOXVpcsVNy888p6nszr7g5TktLY0LDkOVjIS7eHHd0+ggF4OQmPjtr8lPTDwyGmoFX3n2vapYbapo846ZUuTQe9ZKI1MZ9jj7c7ZII4Ud23zGia9I5TxbwL8qcf/jpm8bmtEXyoN2Hnl7uvKE2oJWfoN3pEikWmX5gMBiRKssczXKXU73TaNcAQ0rsTnwrPwvHVPBbD0h7F28pnA8Wy/jT2Lgs/61vFt2OSNqlupEQ/FKOqdOYuO91bNaqv94RZ/py56W+IU4p5n2+901HMBiMSJXlU1TA2FS0xYuoCoYkxNfavdu5ob1ISeDzrTbec4K+coj9KXgxJbIeWJj4fm4A3h0aZGDrpN3qTpSnJ/KWUB9k9BOQtkvFY98vxWnLrF624OIOfrt6rxIT9y8z/cBgMCKVONa9plnWLPllVKN8tiH8OzV0NmAd4vo1oXXOaUksttuwCYVSP1vw1qXZvDgoyFmtfOWcNvyC4MDWvlmx0aHn8LEI5ZVZjqeXx3j7O2fX8+u6+KljG/NDzDadwGAwImWHWfKrDmQVrcJmKa53kpxMb3wbcxI8x7TRKseUvMfp75d29PPOZdkU/i7Ep1dm85/Lslk8LJvC34d469LsTj7BMKf+9+6mOCMXOEd/yQ3ALSfZ7n/FkbF/m05gMNQcvIw48S4qY2S9FOVaoiJQfOzxb1mPt8m+DsuzI2IC+2SBWJm4hHZWSz9OMSA/2hznh/3SJl2HHCZHh+4QU8L255rqRsazN9SFJK7/dYLQo6n+XGjZjjiXvlZCSZIwwGO7BxxSizBPTC5ebR5rg6HSeR1vw96tyYRIlaBC/evkFxqaAZHajUpfbEC+Q8KRgPb1BW3qCjbsLb/JE5cwfXmMO3qV6w5BhLwbGGEriOOIyiHhK2iZswvEyIrWev6GGMNeL2VPsfPh3fb1Bbf2cAjYJ+Qkc+8NhirhIeA/mbiw1wFm3Sz5+cx9zZRGlXdqABh6jHM2gEeWRim2tV7Eb+XoUE9Hy202MTE5cj3I4aSZW2lPseSmhaWc/3JJUoEK+ODf5wXJs9MoKd8UkyIfmJtvMNQsvBaK14FijXLNgFNM82eI7OB72IT0/9WxzobzlgOSZ1ZEnfrIDHkTdZN9pZgcmUFpuBPIcehnd91SEhfjO/6zePUjS6Mpw3CP75tFH/u9tSgE/mBuvMFgRCoV+1B7U7rWlCEDiPv27LYmDIdwbCNBryQOFHctjtpbMoKOZIWednJJ/6nYVPaKyZE/Mzncnjh9EdwG4mkEHwMfIMQCBM8DY5CyH3XDrbIfLLpje1j+lhSJIUd0DTC2u4PICh4SU/YvN3feYKh5ZCJVxxzgXI1yl6HiPaXKlFtdk89V76R4UkxHyEsS3769R4BL5tpXfWuR5E8fRXnoTNs9n0tomTNNEhkpUuQeEiB5MLwY/UR6i4BHgJvt/vjb4/082t8x8+HXlIT/zzzKhhowya+OxGpiI7+CXrr0psBpGuUi1fTmRap11zpQ9AY2cfIu6uDnhCRRIR5ZGmXBRqfbJ66jIDRD3pSRbJ13AOsSxI7bewZ4cmAQh2DtB5C+q8RUrSVmg8HrcTFUQwyLZIRrokhtBe0AnzoHe3VdwYMuvnOXxusTD2+eTt2O1qzXLiA/1cVUFHD5sI2Vw919nPt5XMLVb5Q4BnUFriQYeleOzWnrcb85AFyLZaXVzxa8PDjI+L5ZTofq4khxlZhyoDbmKDPnDDNLXc1yR1aBxdJMs1xeJU/GdbXkIVRKpVSv3plW5TnoZeO9FLXEkyQtn3ZCtubWw5tq//0sVFqPVKSane+1BDRX41otSO1M0E+zXkWAXtbZ0shUskJjEq97SQc/57X186bDId6tRZILXylh4ZCgfXBaSR+kb6kcE7qTfeHHPEyL8R4w7YpO/hsnnZ5FszyRbJguEJOL5lA7ycWQSRqjYkmmGnuO8/A7dbcPWmuW6+RRvXZplmukUaY+8HtNQZuWSUsK9KOiNwHOSFFmk4tGSiWMddE7x3XQIkyF7uG1CzTKjNC8lnYWVTGVvUhpG118Wv8s8rOcP/vfbXEGzymhyHH6IOsieZj83K/kmJzhcgRZFekwEoQcnTuodHSo+8zzg8kESgKjxKTwQ7V4ED3K6EjGuUijzHkefp/ukvWppE4cWBeVhNALvtcsp7N1M8SF5mzNtEittF46pFry2wfs1LzWZCifPr0MY0kdEaPsb0iFrqv1HSTkX7J5IHp4WK8yQ3rOw3aC27quYEK/5Lrywfdx+s8uZns4mXEqOyPFM+SHNsiC0CR5S6iPHKdvocvR+cfJgpy7KAitQMi5AUHP5LNN+RsxOfxwDR0YdWfT52NIBzcW//8BdVJYKoOqQKSCqGXxZNyvuSqjg66RcHUKKy8L0D0mEisrjpnchJujaXL+Avhdig60RNMa6Y3yKLsd5Qp/0A44ArjBEgtd3tIoswQYqFGuGWqf7jaUY8nBfbY8S6Qnu6jXfDc3QTxYWChHh25B8Fzi3244IcCSLXGeWeG8HL5kS5xTnivm5cFBujROOqdpDhTgo4C9of1yjFiClKsQrEHKfSD2IWUuiDoIWqP24HpDrInmFssm4lwuHox8TM1Fd2mlv9XHJ5J8qdyQXvtiDbhvAlcB3yX8rSsquo2X4+d2F2XvtsQjMU5lPjAeuN7Den2hWS4fFXFiOOX383OBR4GOmtf6DLWdknGRetUalFPRyHrokg2+izRFCuAk4G1LCH60LKumLq3GQkuAUrHYxTVbADMsMf4B8KM2XoMu23W+2xshpoSflwU5w0GUm4E/NiDIsh3F/Hebs0Pm2kJJz5nF3Nc3i5tPCuhISj5SDgAGqB1C6xMizf1+yctE/deLqfu3U7PZ6KLseGCUNYjssGbibwEvGy3yRKRALa2tssaf1dZY0hnomYFVqM0uygaBZ4C/AB+hYqY2QX+/3Q0foZbYdR7ejta4+aX1iliT19Nd1uuQMS6TIvUpKkyOjjfK0BSD7yzgXmtg1yUXhzQQGryoOUN9z8VvLGv2tkmzXl9aD417BDci+YqE5c5QAOZdEuSMWcWs3u28rBeJwi3vlfLCqhgPnplFz6aZPyKyeb8sal7Hd5mYXPRmLRlEP7OWTXRpmjB5O2BEKinbrEmim/3TbGsS3T/DdduUxmfaVGAs0WWnJVSnuvjMidarIgbOT2RypIkDczXLXpzColgPzKukjhxHuUnqUEIZL5RKYEq6HxSTIt+B+CU23o/N8gQLh2TTvn7qydLHW+L0nlnM0Hkl9skSPWD1bsm1b5fQ9h+RXDGp6EhqD+8YHckoYeDzalq3pVSDg7MOTK3E71oMfFVZIgX6AWcbAGenKHM3lbP+/jSwzOUN3FIJ9foSeLYiFxCTi+YihG0OqBb5gneHZCc96HsQCcxeHaPHs8X0e6GYJ/4XZWdEVujHFUVh1uoYF80pofPTEf6xLHYwXceD1B5vtuXohxUzpMfCalqvfUB1PfP3Mumu4LinXPQYXyV0iL2aZVPF8vsK5bWSSTYAY1x+phDl+CEzWK8w8Ev0Inkkp07Rn50s3JZ1BIuGZXNRe/1V1Q9/iDNyQSnNHovQ9/li7lhUyrz1MdYWSqJxZ5HbtE+ycGOcv30S5fxXSmgyLczl80qYuy5G/NCWrAc8VosG0Xsy3JdqO89WY4uluqYaKgVGVkK/fBJ432nM0Hl1TPOLn9e8fiGkDLfjtwZYmYHXLip2OG9chuoVBS7xsifIceTIgty3ZEFI2r1io0PynlOzZJavYnXP8iGb5gnZsYGQJx/pk8c0ELJ1XSFzAmld7yqPfr7ufdLN8HuJ5vXczJL/nmabJ3qJztT83J88aNeGLuqpc/CznYvr+V3WdaZHz+Y9Lsrma9SrKcrZoKL1iluDvU7ZuS7a7fYMjXESlV/Q9pB6ZQRI1F3yq0fqwLQx1IGwWR7X8Vugr7Xcki5/tl5esh+1X/eKlxcV44ggiy52yjvlE3BnrwBfXJ1NtyPS7yKlcfjxgGTNbskXW+Os2i35bq8kkt6i7UPWQ1wbGIveEQhDetyOO5dvOx6zJhNe8iMwwYPrjEc/oIIb7gMykVj0fZQDUFFVidQb6B9S1InlVwxcaQmCF+F4FgK9gBWbkJGGAAAFR0lEQVQVNVCsWfrVllVYUVajcm5lxGFETCGMPzwY5BtOZbo09rHkymwe6JdFg5yqDReX5aPRmO6BuW4OCh/GhFEHvJ8zepIRNqIiz6SbyeAlHCL2e8A9VGzf7DHgzgxPoG7GuwDb01FnTR2PB1SGSO1BuWrrMAi9yMIxSxB6WiKYDquspZr+HsyqyvIscDzwjzRFdIfVCY4nwxupYiIH2BQZTJLDxNl+GNs9wNrfZDO2e4A6wcodTQI++NWxflb+OoeJ/bJ6zF0afKqWDKQHJ2MXAGuNrnjOQuvZ3+ryc/dZk+nSDNWrFBichiVUYgnIDWR+72gq0B2H/SNNvrF+5zWpJgsBYIHmRYsqUKGnXAjicei7iS61HuIu1szoQtRhO6dzEFtR3lMvoJICZqqj/YAKXfJnlEPIxahDxk4CvA/40Jqhzbb+v1IQs4lBeIwsyFkO4u84hJVqmCN4oF8Wd/XO4l/Lovz9qyhrdmfuWWgcElzZyc/vugU4usHPVtzpLXy/nDUo589DX4t8S+3gDdQZwv6oWHHdUIfAG6MiqZiI6OmzCDgBFXRgJMkD934G3EXlLMMesCbQl6OWJrulELVXrbGmMhN/LkfFXT0dFXf0AlKHnIujXMz/iQpsoLXwXxM7eBAVcqcRKtBisXXT16HWfKsKP2ozuIlVL2HV6zvUQb4q9ziStwQ74/NPRzOO4Bdb47y8Nsara2Os2FlxwWqaJxjQyselHf2c39ZP0HE7XD4lJkeuM2OswUPyUMv+J6L2PnNQnsmrUYdZ11Rh3Tqilv47WEIQQx2yXY5apdpt85nR6IVbe82yaLwYd7ugQka1tMa4XKsNf0StXC1xqGutEylDRYRqHAH25vwRxJ24CNm0rUiyZEucJVvirNipHCQ27JUU2qSjzw1Aw5DgmAaCzg19HNtIcFoLH8c31l59jiNFLzGl6HNzxwwGWypbpDJGwNxLwyGzlnFEIXKPHJ3zLD7xVySX60xmmuQKBrf3M9jmjNVu66BvVELdoCDbX9FK8glS+szdMhhqPuZBN9jrwJTIejEpfAVC9AL5FhXYjG2QI2iQIzgiVGGB+gLEBWJS+BQxJfypuUsGQ83HWFKG5GI1qegz4Fw5JtgJ6b8ZFYo/vxKrEEPKtxG+x5hc9Jow0RgMBiNSBkN5sSpZCdwob2vwR0rDg0D8AjiHzKQyl8D/gOcIiH+LCeHN5g4YajhHkDzJ4kEK0Us54q8pDWNEyuBOrO7fvQflPjpDjiCX/NyzgN4gT0F5BaZjZUWBtQjxMcTfwed/Rzxw4EfT2oZaxFjgVo1yT6JcvlPRSPN7i6t7wxiRMqQvWE9QBEXzsKJiyCH4aZHTkgBtiNMGfG1A5iBkPeL4ED4/yH1IuRshChFsJu7/hnr714hxaZ/+NxhqArou7gOtcTvVGaPumtfbZpreYDAYDKk4Gf1grAUprtUWdchX51p3maY3GAwGQyoCqIDSOsKyD+jncJ1sVFQdXcE71zS9wWAwGHR42YW4lAL/QgUi7oqKY3odKt6n7jWKUZE2DAaDwWBIyRVkLl+T3esd0+QGg8Fg0CUIbK5Ekfq1aXKDwWAwuGFEJQnUJlJnQjcYDAaD4RAEKjVLpkVqiGlqg8FgMKRDG1RKi0wJ1D9NExsMBoOhIvRCZTX3WqDmY5b5DAaDweABfVDJDb0SqJk4ZN42GAwGgyEdmgFzKihOu4FrMUluDQaDwZAhBgFvoFLH64rTNuCvQMPD+YcbZTUYDIbDh9aoILP9gBNRKT4ao0Iq7UMFqv0KWAD8h8Mgynkq/h885rfKXRQafwAAAABJRU5ErkJggg== | |
| 6581 " style="display:none"><noscript>Javascript must be enabled to view this page.</noscript><div style="display:none"><krona collapse="true" key="true" chart="TAXOMIC"><attributes magnitude="count"><attribute display="Count" dataAll="members" tip="Number of reads assigned to this and child taxa">count</attribute><attribute display="Unassigned" dataNode="members" tip="Number of reads assigned specifically to this taxon">unassigned</attribute><attribute display="TaxID" mono="true" hrefBase="https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=" tip="Taxonomic identifier">tid</attribute><attribute display="Rank" mono="true" tip="Taxonomic rank/level">rank</attribute><attribute display="Kmer coverage (%)" tip="Averaged score of reads assigned to this and child taxa">score</attribute></attributes><datasets rawSamples="17"><dataset isctr="False" sread="99" sclas="99" sfilt="99" scmin="36" scavg="1861.2323232323233" scmax="28395" lnmin="128 nt" lnavg="26.18 knt" lnmax="252.90 knt" tclas="16" tfilt="16" tfold="13" sclim="None" totnt="2.59 Mnt">../kraken_assembly/taxonomy_10_Enterococcus_faecalis_S17_L001</dataset><dataset isctr="False" sread="98" sclas="98" sfilt="98" scmin="36" scavg="630.8469387755102" scmax="7011" lnmin="140 nt" lnavg="45.36 knt" lnmax="373.24 knt" tclas="17" tfilt="17" tfold="10" sclim="None" totnt="4.45 Mnt">../kraken_assembly/taxonomy_11_Enterobacter_kobei_S19</dataset><dataset isctr="False" sread="83" sclas="83" sfilt="83" scmin="36" scavg="157.13253012048193" scmax="4990" lnmin="131 nt" lnavg="52.70 knt" lnmax="476.98 knt" tclas="15" tfilt="15" tfold="10" sclim="None" totnt="4.37 Mnt">../kraken_assembly/taxonomy_12_Enterobacter_hormaechei_S1_L001</dataset><dataset isctr="False" sread="315" sclas="315" sfilt="315" scmin="36" scavg="295.8984126984127" scmax="3212" lnmin="114 nt" lnavg="16.63 knt" lnmax="168.27 knt" tclas="22" tfilt="22" tfold="16" sclim="None" totnt="5.24 Mnt">../kraken_assembly/taxonomy_13_citrobacter_freundii_S55</dataset><dataset isctr="False" sread="327" sclas="322" sfilt="322" scmin="36" scavg="1341.9192546583852" scmax="11569" lnmin="118 nt" lnavg="16.63 knt" lnmax="136.00 knt" tclas="33" tfilt="33" tfold="16" sclim="None" totnt="5.36 Mnt">../kraken_assembly/taxonomy_14_citrobacter_telavivensis_S188</dataset><dataset isctr="False" sread="689" sclas="687" sfilt="687" scmin="35" scavg="1183.4264919941777" scmax="14756" lnmin="112 nt" lnavg="15.21 knt" lnmax="139.92 knt" tclas="26" tfilt="26" tfold="19" sclim="None" totnt="10.45 Mnt">../kraken_assembly/taxonomy_1_contaminant_S198</dataset><dataset isctr="False" sread="214" sclas="214" sfilt="214" scmin="36" scavg="445.7429906542056" scmax="15273" lnmin="147 nt" lnavg="23.33 knt" lnmax="441.96 knt" tclas="24" tfilt="24" tfold="14" sclim="None" totnt="4.99 Mnt">../kraken_assembly/taxonomy_2_Escherichia_coli_S8_L001</dataset><dataset isctr="False" sread="1053" sclas="1052" sfilt="1052" scmin="35" scavg="774.2480988593156" scmax="9077" lnmin="113 nt" lnavg="8.42 knt" lnmax="334.92 knt" tclas="33" tfilt="32" tfold="21" sclim="None" totnt="8.86 Mnt">../kraken_assembly/taxonomy_2_contaminant_S50</dataset><dataset isctr="False" sread="792" sclas="765" sfilt="765" scmin="35" scavg="154.0718954248366" scmax="4919" lnmin="112 nt" lnavg="15.11 knt" lnmax="165.48 knt" tclas="43" tfilt="43" tfold="27" sclim="None" totnt="11.56 Mnt">../kraken_assembly/taxonomy_3_contaminant_S169</dataset><dataset isctr="False" sread="159" sclas="159" sfilt="159" scmin="36" scavg="4295.377358490566" scmax="72684" lnmin="128 nt" lnavg="34.51 knt" lnmax="448.65 knt" tclas="13" tfilt="13" tfold="11" sclim="None" totnt="5.49 Mnt">../kraken_assembly/taxonomy_4_Klebsiella_oxytoca_S13_L001</dataset><dataset isctr="False" sread="1706" sclas="1624" sfilt="1624" scmin="35" scavg="267.61268472906403" scmax="8717" lnmin="112 nt" lnavg="6.05 knt" lnmax="138.88 knt" tclas="73" tfilt="73" tfold="31" sclim="None" totnt="9.84 Mnt">../kraken_assembly/taxonomy_4_contaminant_S103</dataset><dataset isctr="False" sread="181" sclas="181" sfilt="181" scmin="36" scavg="397.24309392265195" scmax="7723" lnmin="112 nt" lnavg="34.92 knt" lnmax="235.36 knt" tclas="17" tfilt="17" tfold="9" sclim="None" totnt="6.32 Mnt">../kraken_assembly/taxonomy_5_Pseudomonas_aeruginosa_S14</dataset><dataset isctr="False" sread="1762" sclas="1745" sfilt="1745" scmin="35" scavg="208.61489971346705" scmax="6081" lnmin="112 nt" lnavg="5.12 knt" lnmax="139.52 knt" tclas="45" tfilt="44" tfold="28" sclim="None" totnt="8.95 Mnt">../kraken_assembly/taxonomy_5_contaminant_S105</dataset><dataset isctr="False" sread="350" sclas="347" sfilt="347" scmin="36" scavg="319.2680115273775" scmax="12084" lnmin="86 nt" lnavg="19.41 knt" lnmax="588.10 knt" tclas="18" tfilt="18" tfold="10" sclim="None" totnt="6.74 Mnt">../kraken_assembly/taxonomy_6_Pseudomonas_aeruginosa_S1</dataset><dataset isctr="False" sread="162" sclas="160" sfilt="160" scmin="36" scavg="616.25" scmax="6221" lnmin="112 nt" lnavg="23.39 knt" lnmax="207.32 knt" tclas="20" tfilt="20" tfold="13" sclim="None" totnt="3.74 Mnt">../kraken_assembly/taxonomy_7_Acinetobacter_baumannii_S78</dataset><dataset isctr="False" sread="162" sclas="161" sfilt="161" scmin="35" scavg="76.30434782608695" scmax="1557" lnmin="104 nt" lnavg="19.23 knt" lnmax="603.00 knt" tclas="8" tfilt="8" tfold="6" sclim="None" totnt="3.10 Mnt">../kraken_assembly/taxonomy_8_Acinetobacter_pittii_S378</dataset><dataset isctr="False" sread="9" sclas="9" sfilt="9" scmin="46" scavg="277" scmax="799" lnmin="778 nt" lnavg="3.05 knt" lnmax="6.53 knt" tclas="4" tfilt="4" tfold="4" sclim="None" totnt="27.46 knt">../kraken_assembly/taxonomy_9_Enterococcus_faecium_S20_L001</dataset></datasets><color attribute="score" hueStart="0" hueEnd="300" valueStart="0.0" valueEnd="24.2" default="true"> </color><node name="root" href="https://www.google.com/search?q=root"><count><val>99</val><val>98</val><val>83</val><val>315</val><val>322</val><val>687</val><val>214</val><val>1052</val><val>765</val><val>159</val><val>1624</val><val>181</val><val>1745</val><val>347</val><val>160</val><val>161</val><val>9</val></count><unassigned><val></val><val></val><val>1</val><val>2</val><val>2</val><val>4</val><val>6</val><val>6</val><val></val><val></val><val>21</val><val></val><val>6</val><val>3</val><val></val><val></val><val></val></unassigned><tid><val href="1">1</val></tid><rank><val>no_rank</val></rank><score><val>11.2</val><val>4.0</val><val>5.4</val><val>6.5</val><val>9.3</val><val>10.5</val><val>9.7</val><val>18.3</val><val>5.0</val><val>10.6</val><val>9.4</val><val>9.9</val><val>15.1</val><val>12.2</val><val>7.9</val><val>9.7</val><val>8.6</val></score><node name="Bacteria" href="https://www.google.com/search?q=Bacteria"><count><val>99</val><val>98</val><val>82</val><val>313</val><val>320</val><val>683</val><val>208</val><val>1046</val><val>765</val><val>159</val><val>1603</val><val>181</val><val>1723</val><val>344</val><val>160</val><val>161</val><val>9</val></count><unassigned><val>3</val><val></val><val></val><val>4</val><val></val><val>4</val><val>2</val><val>9</val><val>3</val><val></val><val>21</val><val></val><val>2</val><val>4</val><val></val><val></val><val>1</val></unassigned><tid><val href="2">2</val></tid><rank><val>superkingdom</val></rank><score><val>11.2</val><val>4.0</val><val>5.1</val><val>6.4</val><val>9.2</val><val>10.4</val><val>9.2</val><val>18.3</val><val>5.0</val><val>10.6</val><val>9.2</val><val>9.9</val><val>15.0</val><val>12.1</val><val>7.9</val><val>9.7</val><val>8.6</val></score><node name="Proteobacteria" href="https://www.google.com/search?q=Proteobacteria"><count><val></val><val>98</val><val>82</val><val>309</val><val>320</val><val>679</val><val>206</val><val>1037</val><val>762</val><val>159</val><val>1582</val><val>181</val><val>1721</val><val>340</val><val>160</val><val>161</val><val></val></count><unassigned><val></val><val></val><val></val><val>7</val><val></val><val>9</val><val>3</val><val>2</val><val>25</val><val>4</val><val>32</val><val></val><val></val><val>7</val><val></val><val></val><val></val></unassigned><tid><val href="1224">1224</val></tid><rank><val>phylum</val></rank><score><val>0</val><val>4.0</val><val>5.1</val><val>6.2</val><val>9.2</val><val>10.3</val><val>9.1</val><val>18.3</val><val>4.9</val><val>10.6</val><val>9.0</val><val>9.9</val><val>15.1</val><val>11.9</val><val>7.9</val><val>9.7</val><val>0</val></score><node name="Gammaproteobacteria" href="https://www.google.com/search?q=Gammaproteobacteria"><count><val></val><val>98</val><val>82</val><val>302</val><val>320</val><val>670</val><val>203</val><val>1035</val><val>737</val><val>155</val><val>1550</val><val>181</val><val>1721</val><val>333</val><val>160</val><val>161</val><val></val></count><unassigned><val></val><val>1</val><val>5</val><val>13</val><val>7</val><val>28</val><val>13</val><val>9</val><val>4</val><val>1</val><val>70</val><val></val><val>156</val><val>2</val><val>7</val><val></val><val></val></unassigned><tid><val href="1236">1236</val></tid><rank><val>class</val></rank><score><val>0</val><val>4.0</val><val>5.1</val><val>5.8</val><val>9.2</val><val>10.3</val><val>9.1</val><val>18.3</val><val>4.2</val><val>10.4</val><val>8.8</val><val>9.9</val><val>15.1</val><val>11.7</val><val>7.9</val><val>9.7</val><val>0</val></score><node name="Pseudomonadales" href="https://www.google.com/search?q=Pseudomonadales"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>18</val><val>733</val><val></val><val></val><val>181</val><val></val><val>331</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="72274">72274</val></tid><rank><val>order</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.1</val><val>4.2</val><val>0</val><val>0</val><val>9.9</val><val>0</val><val>11.7</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonadaceae" href="https://www.google.com/search?q=Pseudomonadaceae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>18</val><val>733</val><val></val><val></val><val>181</val><val></val><val>331</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val><val>1</val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val></unassigned><tid><val href="135621">135621</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.1</val><val>4.2</val><val>0</val><val>0</val><val>9.9</val><val>0</val><val>11.7</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas" href="https://www.google.com/search?q=Pseudomonas"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>17</val><val>732</val><val></val><val></val><val>181</val><val></val><val>329</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val>131</val><val></val><val></val><val>65</val><val></val><val>70</val><val></val><val></val><val></val></unassigned><tid><val href="286">286</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.2</val><val>4.1</val><val>0</val><val>0</val><val>9.9</val><val>0</val><val>11.8</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas aeruginosa group" href="https://www.google.com/search?q=Pseudomonas aeruginosa group"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val>6</val><val></val><val></val><val>116</val><val></val><val>259</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val>1</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="136841">136841</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.9</val><val>1.9</val><val>0</val><val>0</val><val>1.5</val><val>0</val><val>7.9</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas aeruginosa" href="https://www.google.com/search?q=Pseudomonas aeruginosa"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val>116</val><val></val><val>259</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val>87</val><val></val><val>239</val><val></val><val></val><val></val></unassigned><tid><val href="287">287</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.2</val><val>0</val><val>0</val><val>1.5</val><val>0</val><val>7.9</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas aeruginosa PA7" href="https://www.google.com/search?q=Pseudomonas aeruginosa PA7"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val>3</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val>3</val><val></val><val></val><val></val></unassigned><tid><val href="381754">381754</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa 39016" href="https://www.google.com/search?q=Pseudomonas aeruginosa 39016"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val>11</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val>11</val><val></val><val></val><val></val></unassigned><tid><val href="798130">798130</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa PAK" href="https://www.google.com/search?q=Pseudomonas aeruginosa PAK"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val>6</val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val>6</val><val></val><val></val><val></val></unassigned><tid><val href="1009714">1009714</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa B136-33" href="https://www.google.com/search?q=Pseudomonas aeruginosa B136-33"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1280938">1280938</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa PAO581" href="https://www.google.com/search?q=Pseudomonas aeruginosa PAO581"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1352354">1352354</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa c7447m" href="https://www.google.com/search?q=Pseudomonas aeruginosa c7447m"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1352355">1352355</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas aeruginosa PA96" href="https://www.google.com/search?q=Pseudomonas aeruginosa PA96"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1457392">1457392</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Pseudomonas mendocina" href="https://www.google.com/search?q=Pseudomonas mendocina"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>10</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>10</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="300">300</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Pseudomonas putida group" href="https://www.google.com/search?q=Pseudomonas putida group"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>541</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>26</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="136845">136845</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas putida" href="https://www.google.com/search?q=Pseudomonas putida"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>484</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>191</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="303">303</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas putida GB-1" href="https://www.google.com/search?q=Pseudomonas putida GB-1"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="76869">76869</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida S16" href="https://www.google.com/search?q=Pseudomonas putida S16"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>42</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>42</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1042876">1042876</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida B6-2" href="https://www.google.com/search?q=Pseudomonas putida B6-2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1081940">1081940</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida JB" href="https://www.google.com/search?q=Pseudomonas putida JB"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1150601">1150601</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida DOT-T1E" href="https://www.google.com/search?q=Pseudomonas putida DOT-T1E"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1196325">1196325</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida NBRC 14164" href="https://www.google.com/search?q=Pseudomonas putida NBRC 14164"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>51</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>51</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1211579">1211579</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida S12" href="https://www.google.com/search?q=Pseudomonas putida S12"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1215087">1215087</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida HB3267" href="https://www.google.com/search?q=Pseudomonas putida HB3267"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>87</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>87</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1215088">1215088</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.3</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida H8234" href="https://www.google.com/search?q=Pseudomonas putida H8234"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1331671">1331671</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas putida S13.1.2" href="https://www.google.com/search?q=Pseudomonas putida S13.1.2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>74</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>74</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1384061">1384061</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Pseudomonas plecoglossicida" href="https://www.google.com/search?q=Pseudomonas plecoglossicida"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>17</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>17</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="70775">70775</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas monteilii" href="https://www.google.com/search?q=Pseudomonas monteilii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>14</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>14</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="76759">76759</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Pseudomonas syringae group" href="https://www.google.com/search?q=Pseudomonas syringae group"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="136849">136849</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas syringae group genomosp. 2" href="https://www.google.com/search?q=Pseudomonas syringae group genomosp. 2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="251698">251698</val></tid><rank><val>species_subgroup</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas savastanoi" href="https://www.google.com/search?q=Pseudomonas savastanoi"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="29438">29438</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas savastanoi pv. savastanoi" href="https://www.google.com/search?q=Pseudomonas savastanoi pv. savastanoi"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="360920">360920</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas savastanoi pv. savastanoi NCPPB 3335" href="https://www.google.com/search?q=Pseudomonas savastanoi pv. savastanoi NCPPB 3335"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="693985">693985</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node></node><node name="unclassified Pseudomonas" href="https://www.google.com/search?q=unclassified Pseudomonas"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>23</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="196821">196821</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pseudomonas sp. FGI182" href="https://www.google.com/search?q=Pseudomonas sp. FGI182"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1259844">1259844</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Pseudomonas sp. 13159349" href="https://www.google.com/search?q=Pseudomonas sp. 13159349"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2662034">2662034</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Pseudomonas asiatica" href="https://www.google.com/search?q=Pseudomonas asiatica"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>25</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>25</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2219225">2219225</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node><node name="Enterobacterales" href="https://www.google.com/search?q=Enterobacterales"><count><val></val><val>97</val><val>77</val><val>289</val><val>313</val><val>642</val><val>190</val><val>1008</val><val></val><val>154</val><val>1480</val><val></val><val>342</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>8</val><val>6</val><val>24</val><val>24</val><val>33</val><val>13</val><val>29</val><val></val><val>8</val><val>271</val><val></val><val>2</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="91347">91347</val></tid><rank><val>order</val></rank><score><val>0</val><val>4.0</val><val>4.7</val><val>5.8</val><val>9.0</val><val>10.3</val><val>9.0</val><val>18.6</val><val>0</val><val>10.3</val><val>8.6</val><val>0</val><val>6.3</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacteriaceae" href="https://www.google.com/search?q=Enterobacteriaceae"><count><val></val><val>89</val><val>71</val><val>265</val><val>289</val><val>609</val><val>177</val><val>191</val><val></val><val>146</val><val>1199</val><val></val><val>3</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>24</val><val>11</val><val>43</val><val>69</val><val>49</val><val>25</val><val>30</val><val></val><val>19</val><val>208</val><val></val><val>3</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="543">543</val></tid><rank><val>family</val></rank><score><val>0</val><val>3.7</val><val>4.1</val><val>5.6</val><val>8.7</val><val>10.5</val><val>9.0</val><val>5.9</val><val>0</val><val>10.4</val><val>6.5</val><val>0</val><val>2.3</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Citrobacter" href="https://www.google.com/search?q=Citrobacter"><count><val></val><val></val><val></val><val>211</val><val>190</val><val></val><val></val><val></val><val></val><val>2</val><val>84</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>20</val><val>14</val><val></val><val></val><val></val><val></val><val>2</val><val>56</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="544">544</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>4.9</val><val>7.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>12.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Citrobacter amalonaticus" href="https://www.google.com/search?q=Citrobacter amalonaticus"><count><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="35703">35703</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Citrobacter farmeri" href="https://www.google.com/search?q=Citrobacter farmeri"><count><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="67824">67824</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>1.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Citrobacter freundii complex" href="https://www.google.com/search?q=Citrobacter freundii complex"><count><val></val><val></val><val></val><val>186</val><val>5</val><val></val><val></val><val></val><val></val><val></val><val>23</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>6</val><val>1</val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1344959">1344959</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>0</val><val>0</val><val>4.7</val><val>1.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Citrobacter freundii" href="https://www.google.com/search?q=Citrobacter freundii"><count><val></val><val></val><val></val><val>180</val><val>4</val><val></val><val></val><val></val><val></val><val></val><val>13</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>177</val><val>4</val><val></val><val></val><val></val><val></val><val></val><val>13</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="546">546</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>4.2</val><val>1.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Citrobacter freundii ATCC 8090 = MTCC 1658 = NBRC 12681" href="https://www.google.com/search?q=Citrobacter freundii ATCC 8090 = MTCC 1658 = NBRC 12681"><count><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1006003">1006003</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Citrobacter werkmanii" href="https://www.google.com/search?q=Citrobacter werkmanii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="67827">67827</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="unclassified Citrobacter" href="https://www.google.com/search?q=unclassified Citrobacter"><count><val></val><val></val><val></val><val>5</val><val>4</val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>3</val><val>4</val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2644389">2644389</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>1.9</val><val>1.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Citrobacter sp. RHBSTW-00127" href="https://www.google.com/search?q=Citrobacter sp. RHBSTW-00127"><count><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2742636">2742636</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Citrobacter telavivensis" href="https://www.google.com/search?q=Citrobacter telavivensis"><count><val></val><val></val><val></val><val></val><val>159</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val>159</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2653932">2653932</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>8.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Enterobacter" href="https://www.google.com/search?q=Enterobacter"><count><val></val><val>65</val><val>60</val><val></val><val>6</val><val>183</val><val>3</val><val></val><val></val><val>4</val><val>827</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>8</val><val>13</val><val></val><val>1</val><val>21</val><val></val><val></val><val></val><val></val><val>55</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="547">547</val></tid><rank><val>genus</val></rank><score><val>0</val><val>3.1</val><val>3.4</val><val>0</val><val>0.2</val><val>2.5</val><val>0.1</val><val>0</val><val>0</val><val>1.6</val><val>5.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter cloacae complex" href="https://www.google.com/search?q=Enterobacter cloacae complex"><count><val></val><val>57</val><val>47</val><val></val><val>5</val><val>159</val><val>3</val><val></val><val></val><val>4</val><val>494</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>3</val><val>17</val><val></val><val>5</val><val>4</val><val>1</val><val></val><val></val><val></val><val>30</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="354276">354276</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>2.0</val><val>3.0</val><val>0</val><val>0.2</val><val>1.4</val><val>0.1</val><val>0</val><val>0</val><val>1.6</val><val>4.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter cloacae" href="https://www.google.com/search?q=Enterobacter cloacae"><count><val></val><val>4</val><val>3</val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>2</val><val>3</val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="550">550</val></tid><rank><val>species</val></rank><score><val>0</val><val>1.1</val><val>0.8</val><val>0</val><val>0</val><val>1.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter cloacae subsp. dissolvens" href="https://www.google.com/search?q=Enterobacter cloacae subsp. dissolvens"><count><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="69219">69219</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter cloacae subsp. dissolvens SDM" href="https://www.google.com/search?q=Enterobacter cloacae subsp. dissolvens SDM"><count><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1104326">1104326</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node><node name="Enterobacter asburiae" href="https://www.google.com/search?q=Enterobacter asburiae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="61645">61645</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterobacter cancerogenus" href="https://www.google.com/search?q=Enterobacter cancerogenus"><count><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="69218">69218</val></tid><rank><val>species</val></rank><score><val>0</val><val>12.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterobacter hormaechei" href="https://www.google.com/search?q=Enterobacter hormaechei"><count><val></val><val>3</val><val>27</val><val></val><val></val><val>152</val><val>2</val><val></val><val></val><val>4</val><val>457</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>3</val><val>16</val><val></val><val></val><val>90</val><val>2</val><val></val><val></val><val>4</val><val>441</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="158836">158836</val></tid><rank><val>species</val></rank><score><val>0</val><val>0.7</val><val>1.9</val><val>0</val><val>0</val><val>1.4</val><val>0.1</val><val>0</val><val>0</val><val>1.6</val><val>4.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter hormaechei subsp. steigerwaltii" href="https://www.google.com/search?q=Enterobacter hormaechei subsp. steigerwaltii"><count><val></val><val></val><val></val><val></val><val></val><val>58</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val>58</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="299766">299766</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterobacter hormaechei subsp. xiangfangensis" href="https://www.google.com/search?q=Enterobacter hormaechei subsp. xiangfangensis"><count><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>9</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>9</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1296536">1296536</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterobacter hormaechei subsp. hoffmannii" href="https://www.google.com/search?q=Enterobacter hormaechei subsp. hoffmannii"><count><val></val><val></val><val>9</val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val>9</val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1812934">1812934</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0</val><val>4.3</val><val>0</val><val>0</val><val>0.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter hormaechei subsp. hoffmannii ECNIH3" href="https://www.google.com/search?q=Enterobacter hormaechei subsp. hoffmannii ECNIH3"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1333851">1333851</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node><node name="Enterobacter kobei" href="https://www.google.com/search?q=Enterobacter kobei"><count><val></val><val>45</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val>45</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="208224">208224</val></tid><rank><val>species</val></rank><score><val>0</val><val>1.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterobacter roggenkampii" href="https://www.google.com/search?q=Enterobacter roggenkampii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1812935">1812935</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="unclassified Enterobacter" href="https://www.google.com/search?q=unclassified Enterobacter"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val>278</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val>1</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2608935">2608935</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.3</val><val>0</val><val>0</val><val>0</val><val>0</val><val>5.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterobacter sp. E76" href="https://www.google.com/search?q=Enterobacter sp. E76"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>277</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>277</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2596949">2596949</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>5.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node><node name="Escherichia" href="https://www.google.com/search?q=Escherichia"><count><val></val><val></val><val></val><val>2</val><val>13</val><val></val><val>147</val><val>6</val><val></val><val></val><val>25</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="561">561</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.6</val><val>0.5</val><val>0</val><val>8.3</val><val>0.5</val><val>0</val><val>0</val><val>1.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Escherichia coli" href="https://www.google.com/search?q=Escherichia coli"><count><val></val><val></val><val></val><val>2</val><val>13</val><val></val><val>138</val><val>6</val><val></val><val></val><val>25</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val>13</val><val></val><val>133</val><val>6</val><val></val><val></val><val>25</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="562">562</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.6</val><val>0.5</val><val>0</val><val>8.5</val><val>0.5</val><val>0</val><val>0</val><val>1.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Escherichia coli ATCC 8739" href="https://www.google.com/search?q=Escherichia coli ATCC 8739"><count><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="481805">481805</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Escherichia coli UM146" href="https://www.google.com/search?q=Escherichia coli UM146"><count><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="869729">869729</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Escherichia coli O19:H7" href="https://www.google.com/search?q=Escherichia coli O19:H7"><count><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2773707">2773707</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Escherichia fergusonii" href="https://www.google.com/search?q=Escherichia fergusonii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="564">564</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Salmonella" href="https://www.google.com/search?q=Salmonella"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="590">590</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Salmonella enterica" href="https://www.google.com/search?q=Salmonella enterica"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="28901">28901</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Salmonella enterica subsp. diarizonae" href="https://www.google.com/search?q=Salmonella enterica subsp. diarizonae"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="59204">59204</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Salmonella enterica subsp. diarizonae serovar 48:i:z" href="https://www.google.com/search?q=Salmonella enterica subsp. diarizonae serovar 48:i:z"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1192842">1192842</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node><node name="Leclercia" href="https://www.google.com/search?q=Leclercia"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="83654">83654</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Atlantibacter" href="https://www.google.com/search?q=Atlantibacter"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1903434">1903434</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Atlantibacter hermannii" href="https://www.google.com/search?q=Atlantibacter hermannii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>12</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="565">565</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.6</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Klebsiella/Raoultella group" href="https://www.google.com/search?q=Klebsiella/Raoultella group"><count><val></val><val></val><val></val><val>9</val><val>11</val><val>374</val><val>2</val><val>155</val><val></val><val>121</val><val>34</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2890311">2890311</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>3.3</val><val>0.8</val><val>14.3</val><val>0.1</val><val>5.1</val><val>0</val><val>10.5</val><val>1.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Klebsiella" href="https://www.google.com/search?q=Klebsiella"><count><val></val><val></val><val></val><val>9</val><val>11</val><val>374</val><val>2</val><val>155</val><val></val><val>121</val><val>34</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>1</val><val>6</val><val>23</val><val></val><val>29</val><val></val><val>21</val><val>15</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="570">570</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>3.3</val><val>0.8</val><val>14.3</val><val>0.1</val><val>5.1</val><val>0</val><val>10.5</val><val>1.9</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Klebsiella aerogenes" href="https://www.google.com/search?q=Klebsiella aerogenes"><count><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="548">548</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Klebsiella oxytoca" href="https://www.google.com/search?q=Klebsiella oxytoca"><count><val></val><val></val><val></val><val>2</val><val></val><val>334</val><val></val><val></val><val></val><val>77</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>2</val><val></val><val>334</val><val></val><val></val><val></val><val>77</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="571">571</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>14.4</val><val>0</val><val>15.3</val><val>0</val><val>0</val><val>0</val><val>11.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Klebsiella pneumoniae" href="https://www.google.com/search?q=Klebsiella pneumoniae"><count><val></val><val></val><val></val><val>6</val><val>5</val><val>8</val><val>2</val><val>126</val><val></val><val>9</val><val>19</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val>6</val><val>5</val><val>8</val><val>2</val><val>96</val><val></val><val>9</val><val>19</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="573">573</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0.3</val><val>2.3</val><val>0.1</val><val>5.2</val><val>0</val><val>3.8</val><val>2.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Klebsiella pneumoniae subsp. pneumoniae" href="https://www.google.com/search?q=Klebsiella pneumoniae subsp. pneumoniae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>30</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="72407">72407</val></tid><rank><val>subspecies</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Klebsiella pneumoniae subsp. pneumoniae 1084" href="https://www.google.com/search?q=Klebsiella pneumoniae subsp. pneumoniae 1084"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>22</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>22</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1193292">1193292</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node><node name="Klebsiella michiganensis" href="https://www.google.com/search?q=Klebsiella michiganensis"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1134687">1134687</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Klebsiella quasipneumoniae" href="https://www.google.com/search?q=Klebsiella quasipneumoniae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>11</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>11</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1463165">1463165</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>12.3</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Klebsiella grimontii" href="https://www.google.com/search?q=Klebsiella grimontii"><count><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2058152">2058152</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.8</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node><node name="Erwiniaceae" href="https://www.google.com/search?q=Erwiniaceae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1903409">1903409</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Yersiniaceae" href="https://www.google.com/search?q=Yersiniaceae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val>6</val><val></val><val>337</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1903411">1903411</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>8.6</val><val>0</val><val>0</val><val>1.6</val><val>0</val><val>6.3</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Serratia" href="https://www.google.com/search?q=Serratia"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val>4</val><val></val><val>337</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val><val></val><val>6</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="613">613</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>8.6</val><val>0</val><val>0</val><val>1.9</val><val>0</val><val>6.3</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Serratia marcescens" href="https://www.google.com/search?q=Serratia marcescens"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val>3</val><val></val><val>328</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val><val></val><val></val><val>3</val><val></val><val>241</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="615">615</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>8.6</val><val>0</val><val>0</val><val>1.3</val><val>0</val><val>6.3</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Serratia marcescens WW4" href="https://www.google.com/search?q=Serratia marcescens WW4"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>9</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>9</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="435998">435998</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Serratia marcescens subsp. marcescens ATCC 13880" href="https://www.google.com/search?q=Serratia marcescens subsp. marcescens ATCC 13880"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>10</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>10</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="911022">911022</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.4</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Serratia marcescens SM39" href="https://www.google.com/search?q=Serratia marcescens SM39"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>62</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>62</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1334564">1334564</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Serratia marcescens SMB2099" href="https://www.google.com/search?q=Serratia marcescens SMB2099"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1401254">1401254</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="unclassified Serratia" href="https://www.google.com/search?q=unclassified Serratia"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2647522">2647522</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>7.5</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Serratia sp. P2ACOL2" href="https://www.google.com/search?q=Serratia sp. P2ACOL2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2482769">2482769</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>7.5</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node><node name="Morganellaceae" href="https://www.google.com/search?q=Morganellaceae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>780</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1903414">1903414</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>22.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Proteus" href="https://www.google.com/search?q=Proteus"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>777</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="583">583</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>22.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Proteus mirabilis" href="https://www.google.com/search?q=Proteus mirabilis"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>776</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>765</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="584">584</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>22.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Proteus mirabilis HI4320" href="https://www.google.com/search?q=Proteus mirabilis HI4320"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="529507">529507</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Proteus mirabilis BB2000" href="https://www.google.com/search?q=Proteus mirabilis BB2000"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1266738">1266738</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.3</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node></node><node name="Moraxellales" href="https://www.google.com/search?q=Moraxellales"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1223</val><val></val><val>153</val><val>161</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2887326">2887326</val></tid><rank><val>order</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.1</val><val>0</val><val>7.2</val><val>9.7</val><val>0</val></score><node name="Moraxellaceae" href="https://www.google.com/search?q=Moraxellaceae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1223</val><val></val><val>153</val><val>161</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val><val></val><val></val></unassigned><tid><val href="468">468</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.1</val><val>0</val><val>7.2</val><val>9.7</val><val>0</val></score><node name="Acinetobacter" href="https://www.google.com/search?q=Acinetobacter"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1223</val><val></val><val>152</val><val>161</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>689</val><val></val><val>26</val><val>35</val><val></val></unassigned><tid><val href="469">469</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>16.1</val><val>0</val><val>7.2</val><val>9.7</val><val>0</val></score><node name="Acinetobacter lwoffii" href="https://www.google.com/search?q=Acinetobacter lwoffii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>30</val><val></val><val>2</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>30</val><val></val><val>2</val><val></val><val></val></unassigned><tid><val href="28090">28090</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>2.4</val><val>0</val><val>0.4</val><val>0</val><val>0</val></score></node><node name="Acinetobacter johnsonii" href="https://www.google.com/search?q=Acinetobacter johnsonii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="40214">40214</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.6</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Acinetobacter johnsonii XBB1" href="https://www.google.com/search?q=Acinetobacter johnsonii XBB1"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>5</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1242245">1242245</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>3.6</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Acinetobacter radioresistens" href="https://www.google.com/search?q=Acinetobacter radioresistens"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="40216">40216</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.7</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="unclassified Acinetobacter" href="https://www.google.com/search?q=unclassified Acinetobacter"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val>2</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val>2</val><val></val><val></val></unassigned><tid><val href="196816">196816</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>5.5</val><val>0</val><val>1.5</val><val>0</val><val>0</val></score><node name="Acinetobacter sp. NEB 394" href="https://www.google.com/search?q=Acinetobacter sp. NEB 394"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2743575">2743575</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>7.0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Acinetobacter calcoaceticus/baumannii complex" href="https://www.google.com/search?q=Acinetobacter calcoaceticus/baumannii complex"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>489</val><val></val><val>122</val><val>126</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>37</val><val></val><val>6</val><val>31</val><val></val></unassigned><tid><val href="909768">909768</val></tid><rank><val>species_group</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>5.6</val><val>0</val><val>5.1</val><val>5.3</val><val>0</val></score><node name="Acinetobacter baumannii" href="https://www.google.com/search?q=Acinetobacter baumannii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>435</val><val></val><val>116</val><val>10</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>418</val><val></val><val>99</val><val>10</val><val></val></unassigned><tid><val href="470">470</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>5.1</val><val>0</val><val>5.2</val><val>6.2</val><val>0</val></score><node name="Acinetobacter baumannii ATCC 17978" href="https://www.google.com/search?q=Acinetobacter baumannii ATCC 17978"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val></unassigned><tid><val href="400667">400667</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter baumannii ACICU" href="https://www.google.com/search?q=Acinetobacter baumannii ACICU"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val>4</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val>4</val><val></val><val></val></unassigned><tid><val href="405416">405416</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter baumannii 1656-2" href="https://www.google.com/search?q=Acinetobacter baumannii 1656-2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val>2</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val>2</val><val></val><val></val></unassigned><tid><val href="696749">696749</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter baumannii BJAB0868" href="https://www.google.com/search?q=Acinetobacter baumannii BJAB0868"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>2</val><val></val><val></val></unassigned><tid><val href="1096997">1096997</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter baumannii DU202" href="https://www.google.com/search?q=Acinetobacter baumannii DU202"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val>3</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>3</val><val></val><val>3</val><val></val><val></val></unassigned><tid><val href="1370126">1370126</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter baumannii ZW85-1" href="https://www.google.com/search?q=Acinetobacter baumannii ZW85-1"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val>4</val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val>4</val><val></val><val></val></unassigned><tid><val href="1400867">1400867</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.0</val><val>0</val><val>0.0</val><val>0</val><val>0</val></score></node></node><node name="Acinetobacter calcoaceticus" href="https://www.google.com/search?q=Acinetobacter calcoaceticus"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>4</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="471">471</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.4</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter pittii" href="https://www.google.com/search?q=Acinetobacter pittii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val>70</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val><val></val><val></val><val>26</val><val></val></unassigned><tid><val href="48296">48296</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>1.2</val><val>0</val><val>0</val><val>4.2</val><val>0</val></score><node name="Acinetobacter pittii PHEA-2" href="https://www.google.com/search?q=Acinetobacter pittii PHEA-2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>44</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>44</val><val></val></unassigned><tid><val href="871585">871585</val></tid><rank><val>strain</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>4.1</val><val>0</val></score></node></node><node name="Acinetobacter seifertii" href="https://www.google.com/search?q=Acinetobacter seifertii"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1530123">1530123</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Acinetobacter lactucae" href="https://www.google.com/search?q=Acinetobacter lactucae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>15</val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>15</val><val></val></unassigned><tid><val href="1785128">1785128</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>15.2</val><val>0</val></score></node></node></node></node></node></node></node><node name="Terrabacteria group" href="https://www.google.com/search?q=Terrabacteria group"><count><val>96</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1783272">1783272</val></tid><rank><val>no_rank</val></rank><score><val>10.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>9.6</val></score><node name="Firmicutes" href="https://www.google.com/search?q=Firmicutes"><count><val>96</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1239">1239</val></tid><rank><val>phylum</val></rank><score><val>10.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>9.6</val></score><node name="Bacilli" href="https://www.google.com/search?q=Bacilli"><count><val>96</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>8</val></count><unassigned><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val></unassigned><tid><val href="91061">91061</val></tid><rank><val>class</val></rank><score><val>10.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>9.6</val></score><node name="Bacillales" href="https://www.google.com/search?q=Bacillales"><count><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1385">1385</val></tid><rank><val>order</val></rank><score><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Lactobacillales" href="https://www.google.com/search?q=Lactobacillales"><count><val>90</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val></count><unassigned><val>8</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="186826">186826</val></tid><rank><val>order</val></rank><score><val>10.5</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>10.7</val></score><node name="Streptococcaceae" href="https://www.google.com/search?q=Streptococcaceae"><count><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1300">1300</val></tid><rank><val>family</val></rank><score><val>0.2</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterococcaceae" href="https://www.google.com/search?q=Enterococcaceae"><count><val>80</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="81852">81852</val></tid><rank><val>family</val></rank><score><val>11.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>10.7</val></score><node name="Enterococcus" href="https://www.google.com/search?q=Enterococcus"><count><val>80</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>7</val></count><unassigned><val>8</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>1</val></unassigned><tid><val href="1350">1350</val></tid><rank><val>genus</val></rank><score><val>11.4</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>10.7</val></score><node name="Enterococcus faecalis" href="https://www.google.com/search?q=Enterococcus faecalis"><count><val>68</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>46</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1351">1351</val></tid><rank><val>species</val></rank><score><val>12.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Enterococcus faecalis ARO1/DG" href="https://www.google.com/search?q=Enterococcus faecalis ARO1/DG"><count><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="565651">565651</val></tid><rank><val>strain</val></rank><score><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterococcus faecalis R712" href="https://www.google.com/search?q=Enterococcus faecalis R712"><count><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>6</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="699186">699186</val></tid><rank><val>strain</val></rank><score><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterococcus faecalis ATCC 29212" href="https://www.google.com/search?q=Enterococcus faecalis ATCC 29212"><count><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>7</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1201292">1201292</val></tid><rank><val>strain</val></rank><score><val>5.7</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterococcus faecalis D32" href="https://www.google.com/search?q=Enterococcus faecalis D32"><count><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>2</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1206105">1206105</val></tid><rank><val>strain</val></rank><score><val>0.0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node><node name="Enterococcus faecalis DENG1" href="https://www.google.com/search?q=Enterococcus faecalis DENG1"><count><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></count><unassigned><val>5</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="1287066">1287066</val></tid><rank><val>strain</val></rank><score><val>0.1</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node><node name="Enterococcus faecium" href="https://www.google.com/search?q=Enterococcus faecium"><count><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val></count><unassigned><val>4</val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>6</val></unassigned><tid><val href="1352">1352</val></tid><rank><val>species</val></rank><score><val>0.3</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>8.0</val></score></node></node></node></node></node></node></node></node><node name="Viruses" href="https://www.google.com/search?q=Viruses"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="10239">10239</val></tid><rank><val>superkingdom</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Riboviria" href="https://www.google.com/search?q=Riboviria"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2559587">2559587</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Orthornavirae" href="https://www.google.com/search?q=Orthornavirae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2732396">2732396</val></tid><rank><val>kingdom</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pisuviricota" href="https://www.google.com/search?q=Pisuviricota"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2732408">2732408</val></tid><rank><val>phylum</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Pisoniviricetes" href="https://www.google.com/search?q=Pisoniviricetes"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2732506">2732506</val></tid><rank><val>class</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Nidovirales" href="https://www.google.com/search?q=Nidovirales"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="76804">76804</val></tid><rank><val>order</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Cornidovirineae" href="https://www.google.com/search?q=Cornidovirineae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2499399">2499399</val></tid><rank><val>suborder</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Coronaviridae" href="https://www.google.com/search?q=Coronaviridae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="11118">11118</val></tid><rank><val>family</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Orthocoronavirinae" href="https://www.google.com/search?q=Orthocoronavirinae"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2501931">2501931</val></tid><rank><val>subfamily</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Betacoronavirus" href="https://www.google.com/search?q=Betacoronavirus"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="694002">694002</val></tid><rank><val>genus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Sarbecovirus" href="https://www.google.com/search?q=Sarbecovirus"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2509511">2509511</val></tid><rank><val>subgenus</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Severe acute respiratory syndrome-related coronavirus" href="https://www.google.com/search?q=Severe acute respiratory syndrome-related coronavirus"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val></unassigned><tid><val href="694009">694009</val></tid><rank><val>species</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score><node name="Severe acute respiratory syndrome coronavirus 2" href="https://www.google.com/search?q=Severe acute respiratory syndrome coronavirus 2"><count><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></count><unassigned><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val></val><val>16</val><val></val><val></val><val></val><val></val></unassigned><tid><val href="2697049">2697049</val></tid><rank><val>no_rank</val></rank><score><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>0</val><val>24.2</val><val>0</val><val>0</val><val>0</val><val>0</val></score></node></node></node></node></node></node></node></node></node></node></node></node></node></node></krona></div></body></html> |
