galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
April 2011
- 1 participants
- 112 discussions
commit/galaxy-central: natefoo: Disable eagerloading of a job's datasets. This results in more queries but does away with a join that was returning a far bigger result than it should've.
by Bitbucket 06 Apr '11
by Bitbucket 06 Apr '11
06 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/d44244ed570a/
changeset: r5353:d44244ed570a
user: natefoo
date: 2011-04-06 18:44:58
summary: Disable eagerloading of a job's datasets. This results in more queries but does away with a join that was returning a far bigger result than it should've.
affected #: 1 file (36 bytes)
--- a/lib/galaxy/model/mapping.py Wed Apr 06 12:40:20 2011 -0400
+++ b/lib/galaxy/model/mapping.py Wed Apr 06 12:44:58 2011 -0400
@@ -1392,10 +1392,10 @@
history=relation( History ),
library_folder=relation( LibraryFolder ),
parameters=relation( JobParameter, lazy=False ),
- input_datasets=relation( JobToInputDatasetAssociation, lazy=False ),
- output_datasets=relation( JobToOutputDatasetAssociation, lazy=False ),
+ input_datasets=relation( JobToInputDatasetAssociation ),
+ output_datasets=relation( JobToOutputDatasetAssociation ),
post_job_actions=relation( PostJobActionAssociation, lazy=False ),
- output_library_datasets=relation( JobToOutputLibraryDatasetAssociation, lazy=False ),
+ output_library_datasets=relation( JobToOutputLibraryDatasetAssociation ),
external_output_metadata = relation( JobExternalOutputMetadata, lazy = False ) ) )
assign_mapper( context, Task, Task.table,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new changesets in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/73d12ac49c2a/
changeset: r5351:73d12ac49c2a
user: kanwei
date: 2011-04-06 18:38:00
summary: More BLAST tests
affected #: 20 files (155.6 KB)
Diff too large to display.
http://bitbucket.org/galaxy/galaxy-central/changeset/420ddcb0be8c/
changeset: r5352:420ddcb0be8c
user: kanwei
date: 2011-04-06 18:40:20
summary: Delete unused BLAST tests
affected #: 2 files (0 bytes)
--- a/test-data/blastp_four_human_vs_rhodopsin_22c.tabular Wed Apr 06 12:38:00 2011 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-sp|P08100|OPSD_HUMAN gi|57163783|ref|NP_001009242.1| 96.55 348 12 0 1 348 1 348 0.0 660 gi|57163783|ref|NP_001009242.1| 1704 336 343 0 98.56 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA MNGTEGPNFYVPFSNKTGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVFGGFTTTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLVGWSRYIPEGMQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTLPAFFAKSSSIYNPVIYIMMNKQFRNCMLTTLCCGKNPLGDDEASTTGSKTETSQVAPA
-sp|P08100|OPSD_HUMAN gi|3024260|sp|P56514.1|OPSD_BUFBU 84.80 342 51 1 1 341 1 342 8e-170 578 gi|3024260|sp|P56514.1|OPSD_BUFBU 1489 290 322 1 94.15 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEA-SATVSKTE MNGTEGPNFYIPMSNKTGVVRSPFEYPQYYLAEPWQYSILCAYMFLLILLGFPINFMTLYVTIQHKKLRTPLNYILLNLAFANHFMVLCGFTVTMYSSMNGYFILGATGCYVEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFSENHAVMGVAFTWIMALSCAVPPLLGWSRYIPEGMQCSCGVDYYTLKPEVNNESFVIYMFVVHFTIPLIIIFFCYGRLVCTVKEAAAQQQESATTQKAEKEVTRMVIIMVVFFLICWVPYASVAFFIFSNQGSEFGPIFMTVPAFFAKSSSIYNPVIYIMLNKQFRNCMITTLCCGKNPFGEDDASSAATSKTE
-sp|P08100|OPSD_HUMAN gi|283855846|gb|ADB45242.1| 94.82 328 17 0 11 338 1 328 4e-180 612 gi|283855846|gb|ADB45242.1| 1578 311 321 0 97.87 1 1 VPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVS VPFSNKTGVVRSPFEHPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVFGGFTTTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGLALTWVMALACAAPPLVGWSRYIPEGMQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWLPYAGVAFYIFTHQGSNFGPIFMTLPAFFAKSSSIYNPVIYIMMNKQFRNCMLTTLCCGKNPLGDDEASTTAS
-sp|P08100|OPSD_HUMAN gi|283855823|gb|ADB45229.1| 94.82 328 17 0 11 338 1 328 1e-173 591 gi|283855823|gb|ADB45229.1| 1523 311 323 0 98.48 1 1 VPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVS VPFSNKTGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVANLFMVFGGFTTTLYTSMHGYFVFGATGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGLAFTWVMALACAAPPLAGWSRYIPEGMQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVVAFLICWLPYASVAFYIFTHQGSNFGPVFMTIPAFFAKSSSIYNPVIYIMMNKQFRNCMLTTLCCGKNPLGDDEASTTAS
-sp|P08100|OPSD_HUMAN gi|223523|prf||0811197A 93.10 348 23 1 1 348 1 347 0.0 634 gi|223523|prf||0811197A 1634 324 336 1 96.55 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA MNGTEGPNFYVPFSNKTGVVRSPFEAPQYYLAEPWQFSMLAAYMFLLIMLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVFGGFTTTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLVGWSRYIPEGMQCSCGID-YTPHEETNNESFVIYMFVVHFIIPLIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWLPYAGVAFYIFTHQGSDFGPIFMTIPAFFAKTSAVYNPVIYIMMNKQFRNCMVTTLCCGKNPLGDDEASTTVSKTETSQVAPA
-sp|P08100|OPSD_HUMAN gi|12583665|dbj|BAB21486.1| 82.16 342 60 1 1 341 1 342 2e-165 563 gi|12583665|dbj|BAB21486.1| 1451 281 314 1 91.81 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPL-GDDEASATVSKTE MNGTEGPNFYIPMSNATGVVRSPFEYPQYYLAEPWAFSALSAYMFFLIIAGFPINFLTLYVTIEHKKLRTPLNYILLNLAVADLFMVFGGFTTTMYTSMHGYFVFGPTGCNIEGFFATLGGEIALWCLVVLAIERWMVVCKPVTNFRFGESHAIMGVMVTWTMALACALPPLFGWSRYIPEGLQCSCGIDYYTRAPGINNESFVIYMFTCHFSIPLAVISFCYGRLVCTVKEAAAQQQESETTQRAEREVTRMVVIMVISFLVCWVPYASVAWYIFTHQGSTFGPIFMTIPSFFAKSSALYNPMIYICMNKQFRHCMITTLCCGKNPFEEEDGASATSSKTE
--- a/test-data/blastp_human_vs_pdb_seg_no_converted_x22.tabular Wed Apr 06 12:38:00 2011 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-sp|Q9BS26|ERP44_HUMAN gi|193885198|pdb|2R2J|A 97.11 381 11 0 26 406 2 382 0.0 768 gi|193885198|pdb|2R2J|A 1982 370 372 0 97.64 1 1 PVTTEITSLDTENIDEILNNADVALVNFYADWCRFSQMLHPIFEEASDVIKEEFPNENQVVFARVDCDQHSDIAQRYRISKYPTLKLFRNGMMMKREYRGQRSVKALADYIRQQKSDPIQEIRDLAEITTLDRSKRNIIGYFEQKDSDNYRVFERVANILHDDCAFLSAFGDVSKPERYSGDNIIYKPPGHSAPDMVYLGAMTNFDVTYNWIQDKCVPLVREITFENGEELTEEGLPFLILFHMKEDTESLEIFQNEVARQLISEKGTINFLHADCDKFRHPLLHIQKTPADCPVIAIDSFRHMYVFGDFKDVLIPGKLKQFVFDLHSGKLHREFHHGPDPTDTAPGEQAQDVASSPPESSFQKLAPSEYRYTLLRDRDEL PLGSEITSLDTENIDEILNNADVALVNFYADWCRFSQXLHPIFEEASDVIKEEFPNENQVVFARVDCDQHSDIAQRYRISKYPTLKLFRNGXXXKREYRGQRSVKALADYIRQQKSDPIQEIRDLAEITTLDRSKRNIIGYFEQKDSDNYRVFERVANILHDDCAFLSAFGDVSKPERYSGDNIIYKPPGHSAPDXVYLGAXTNFDVTYNWIQDKCVPLVREITFENGEELTEEGLPFLILFHXKEDTESLEIFQNEVARQLISEKGTINFLHADCDKFRHPLLHIQKTPADCPVIAIDSFRHXYVFGDFKDVLIPGKLKQFVFDLHSGKLHREFHHGPDPTDTAPGEQAQDVASSPPESSFQKLAPSEYRYTLLRDRDEL
-sp|Q9BS26|ERP44_HUMAN gi|88192228|pdb|2B5E|A 25.17 290 193 8 25 306 10 283 4e-20 95.1 gi|88192228|pdb|2B5E|A;gi|206581884|pdb|3BOA|A 235 73 133 24 45.86 1 1 TPVTTEITSLDTENIDEILNNADVALVNFYADWCRFSQMLHPIFEEASDVIKEEFPNENQVVFARVDCDQHSDIAQRYRISKYPTLKLFRNGMMMKR-EYRGQRSVKALADYIRQQKSDPIQEIRDLAEITTLDRSKRNIIGYFEQKDSDNYRVFERVANILHDDCAFLSAFGDVSKPERYSGDNI---IYKPPGHSAPDMVYLGA---MTNFDVTYNWIQDKCVPLVREITFENGEELTEEGLPFLILFHMKEDTESLEIFQNEVARQLISEKGTINFLHADCDKF-RH APEDSAVVKLATDSFNEYIQSHDLVLAEFFAPWCGHCKNMAPEYVKAAETLVEK-----NITLAQIDCTENQDLCMEHNIPGFPSLKIFKNSDVNNSIDYEGPRTAEAIVQFMIKQSQPAVAVVADLPAYLANETFVTPVIVQSGKIDADFNATFYSMANKHFNDYDFVSA--------ENADDDFKLSIYLPSAMDEP-VVYNGKKADIADADVFEKWLQVEALPYFGEIDGSVFAQYVESGLPLGYLFY--NDEEELEEYKPLFTELAKKNRGLMNFVSIDARKFGRH
-sp|Q9NSY1|BMP2K_HUMAN gi|73536291|pdb|2BUJ|A 29.39 279 182 8 40 308 21 294 1e-22 105 gi|73536291|pdb|2BUJ|A;gi|73536292|pdb|2BUJ|B 262 82 130 15 46.59 1 1 GVRVFAVGRHQVTLEESLAEGGFSTVFLVR-THGGIRCALKRMYVNNMPDLNVCKREITIMKELSGHKNIVGYLDCAVNSISDNVWEVLILMEYCRAGQVVNQMNKKLQTG--FTEPEVLQIFCDTCEAVARLHQCKTPIIHRDLKVENILLNDGGNYVLCDFGSATNKFLNPQKDG-VNVVEEEIKKYTTLSYRAPEMINLYGGKPITTKADIWALGCLLYKLCFFTLPF------GESQVAICDGNFTIPDNSRYSRNIHCLIRFMLEPDPEHRPDI GHMVIIDNKHYLFIQK-LGEGGFSYVDLVEGLHDGHFYALKRILCHEQQDREEAQREAD-MHRLFNHPNILRLVAYCLRERGAKH-EAWLLLPFFKRGTLWNEIERLKDKGNFLTEDQILWLLLGICRGLEAIH--AKGYAHRDLKPTNILLGDEGQPVLMDLGSMNQACIHVEGSRQALTLQDWAAQRCTISYRAPELFSVQSHCVIDERTDVWSLGCVLYAMMFGEGPYDMVFQKGDSVALAVQNQLSIPQSPRHSSALWQLLNSMMTVDPHQRPHI
-sp|Q9NSY1|BMP2K_HUMAN gi|270346335|pdb|2WQM|A 27.21 272 166 12 53 311 36 288 6e-17 86.3 gi|270346335|pdb|2WQM|A;gi|270346336|pdb|2WQN|A 212 74 129 32 47.43 1 1 LEESLAEGGFSTVFLVRTH-GGIRCALKRMYVNNMPDLNV---CKREITIMKELSGHKNIVGYLDCAVNSISDNVWEVLILMEYCRAGQVVNQMN--KKLQTGFTEPEVLQIFCDTCEAVARLHQCKTPIIHRDLKVENILLNDGGNYVLCDFGSATNKFLNPQKDGVNVVEEEIKKYTTLSYRAPEMINLYGGKPITTKADIWALGCLLYKLCFFTLPFGESQV---AICD----GNFTIPDNSRYSRNIHCLIRFMLEPDPEHRPDIFQV IEKKIGRGQFSEVYRAACLLDGVPVALKKVQIFDLMDAKARADCIKEIDLLKQLN-HPNVIKYY---ASFIEDN--ELNIVLELADAGDLSRMIKHFKKQKRLIPERTVWKYFVQLCSALEHMHSRR--VMHRDIKPANVFITATGVVKLGDLG--LGRFFSSKTTAAHSL------VGTPYYMSPERIHENG---YNFKSDIWSLGCLLYEMAALQSPFYGDKMNLYSLCKKIEQCDYPPLPSDHYSEELRQLVNMCINPDPEKRPDVTYV
-sp|P06213|INSR_HUMAN gi|116667097|pdb|2DTG|E 95.91 928 7 2 28 955 1 897 0.0 1846 gi|116667097|pdb|2DTG|E 4781 890 893 31 96.23 1 1 HLYPGEVCPGMDIRNNLTRLHELENCSVIEGHLQILLMFKTRPEDFRDLSFPKLIMITDYLLLFRVYGLESLKDLFPNLTVIRGSRLFFNYALVIFEMVHLKELGLYNLMNITRGSVRIEKNNELCYLATIDWSRILDSVEDNYIVLNKDDNEECGDICPGTAKGKTNCPATVINGQFVERCWTHSHCQKVCPTICKSHGCTAEGLCCHSECLGNCSQPDDPTKCVACRNFYLDGRCVETCPPPYYHFQDWRCVNFSFCQDLHHKCKNSRRQGCHQYVIHNNKCIPECPSGYTMNSSNLLCTPCLGPCPKVCHLLEGEKTIDSVTSAQELRGCTVINGSLIINIRGGNNLAAELEANLGLIEEISGYLKIRRSYALVSLSFFRKLRLIRGETLEIGNYSFYALDNQNLRQLWDWSKHNLTITQGKLFFHYNPKLCLSEIHKMEEVSGTKGRQERNDIALKTNGDQASCENELLKFSYIRTSFDKILLRWEPYWPPDFRDLLGFMLFYKEAPYQNVTEFDGQDACGSNSWTVVDIDPPLRSNDPKSQNHPGWLMRGLKPWTQYAIFVKTLVTFSDERRTYGAKSDIIYVQTDATNPSVPLDPISVSNSSSQIILKWKPPSDPNGNITHYLVFWERQAEDSELFELDYCLKGLKLPSRTWSPPFESEDSQKHNQSEYEDSAGECCSCPKTDSQILKELEESSFRKTFEDYLHNVVFVPRKTSSGTGAEDPRPSRKRRSLGDVGNVTVAVPTVAAFPNTSSTSVPTSPEEHRPFEKVVNKESLVISGLRHFTGYRIELQACNQDTPEERCSVAAYVSARTMPEAKADDIVGPVTHEIFENNVVHLMWQEPKEPNGLIVLYEVSYRRYGDEELHLCVSRKHFALERGCRLRGLSPGNYSVRIRATSLAGNGSWTEPTYFYVTDYLDVPSNIA HLYPGEVCPGMDIRNNLTRLHELENCSVIEGHLQILLMFKTRPEDFRDLSFPKLIMITDYLLLFRVYGLESLKDLFPNLTVIRGSRLFFNYALVIFEMVHLKELGLYNLMNITRGSVRIEKNNELCYLATIDWSRILDSVEDNHIVLNKDDNEECGDICPGTAKGKTNCPATVINGQFVERCWTHSHCQKVCPTICKSHGCTAEGLCCHSECLGNCSQPDDPTKCVACRNFYLDGRCVETCPPPYYHFQDWRCVNFSFCQDLHHKCKNSRRQGCHQYVIHNNKCIPECPSGYTMNSSNLLCTPCLGPCPKVCHLLEGEKTIDSVTSAQELRGCTVINGSLIINIRGGNNLAAELEANLGLIEEISGYLKIRRSYALVSLSFFRKLRLIRGETLEIGNYSFYALDNQNLRQLWDWSKHNLTITQGKLFFHYNPKLCLSEIHKMEEVSGTKGRQERNDIALKTNGDQASCENELLKFSYIRTSFDKILLRWEPYWPPDFRDLLGFMLFYKEAPYQNVTEFDGQDACGSNSWTVVDIDPPLRSNDPKSQNHPGWLMRGLKPWTQYAIFVKTLVTFSDERRTYGAKSDIIYVQTDATNPSVPLDPISVSNSSSQIILKWKPPSDPNGNITHYLVFWERQAEDSELFELDYCLKGLKLPSRTWSPPFESEDSQKHNQSEYEDSAGECCSCPKTDSQILKELEESSFRKTFEDYLHNVVFV------------PRPSRKRRSLGDVGNA-------------------GNNEEHRPFEKVVNKESLVISGLRHFTGYRIELQACNQDTPEERCSVAAYVSARTMPEAKADDIVGPVTHEIFENNVVHLMWQEPKEPNGLIVLYEVSYRRYGDEELHLCDTRKHFALERGCRLRGLSPGNYSVRIRATSLAGNGSWTEPTYFYVTDYLDVPSNIA
-sp|P06213|INSR_HUMAN gi|114794482|pdb|2HR7|A 99.59 485 2 0 28 512 1 485 0.0 1016 gi|114794482|pdb|2HR7|A;gi|114794483|pdb|2HR7|B 2628 483 485 0 100.00 1 1 HLYPGEVCPGMDIRNNLTRLHELENCSVIEGHLQILLMFKTRPEDFRDLSFPKLIMITDYLLLFRVYGLESLKDLFPNLTVIRGSRLFFNYALVIFEMVHLKELGLYNLMNITRGSVRIEKNNELCYLATIDWSRILDSVEDNYIVLNKDDNEECGDICPGTAKGKTNCPATVINGQFVERCWTHSHCQKVCPTICKSHGCTAEGLCCHSECLGNCSQPDDPTKCVACRNFYLDGRCVETCPPPYYHFQDWRCVNFSFCQDLHHKCKNSRRQGCHQYVIHNNKCIPECPSGYTMNSSNLLCTPCLGPCPKVCHLLEGEKTIDSVTSAQELRGCTVINGSLIINIRGGNNLAAELEANLGLIEEISGYLKIRRSYALVSLSFFRKLRLIRGETLEIGNYSFYALDNQNLRQLWDWSKHNLTITQGKLFFHYNPKLCLSEIHKMEEVSGTKGRQERNDIALKTNGDQASCENELLKFSYIRTSFDKI HLYPGEVCPGMDIRNNLTRLHELENCSVIEGHLQILLMFKTRPEDFRDLSFPKLIMITDYLLLFRVYGLESLKDLFPNLTVIRGSRLFFNYALVIFEMVHLKELGLYNLMNITRGSVRIEKNNELCYLATIDWSRILDSVEDNHIVLNKDDNEECGDICPGTAKGKTNCPATVINGQFVERCWTHSHCQKVCPTICKSHGCTAEGLCCHSECLGNCSQPDDPTKCVACRNFYLDGRCVETCPPPYYHFQDWRCVNFSFCQDLHHKCKNSRRQGCHQYVIHNNKCIPECPSGYTMNSSNLLCTPCLGPCPKVCHLLEGEKTIDSVTSAQELRGCTVINGSLIINIRGGNNLAAELEANLGLIEEISGYLKIRRSYALVSLSFFRKLRLIRGETLEIGNYSFYALDNQNLRQLWDWSKHNLTITQGKLFFHYNPKLCLSEIHKMEEVSGTKGRQERNDIALKTNGDKASCENELLKFSYIRTSFDKI
-sp|P08100|OPSD_HUMAN gi|16975387|pdb|1JFP|A 93.39 348 23 0 1 348 1 348 0.0 681 gi|16975387|pdb|1JFP|A;gi|22219255|pdb|1LN6|A;gi|157878065|pdb|1GZM|A;gi|157878066|pdb|1GZM|B;gi|157878298|pdb|1HZX|A;gi|157878299|pdb|1HZX|B;gi|157878979|pdb|1L9H|A;gi|157878980|pdb|1L9H|B;gi|157880263|pdb|1U19|A;gi|157880264|pdb|1U19|B;gi|157883606|pdb|2G87|A;gi|157883607|pdb|2G87|B;gi|157883830|pdb|2HPY|A;gi|157883831|pdb|2HPY|B;gi|157883860|pdb|2I35|A;gi|157883861|pdb|2I36|A;gi|157883862|pdb|2I36|B;gi|157883863|pdb|2I36|C;gi|157883864|pdb|2I37|A;gi|157883865|pdb|2I37|B;gi|157883866|pdb|2I37|C;gi|159795066|pdb|2PED|A;gi|159795067|pdb|2PED|B;gi|192988480|pdb|3CAP|A;gi|192988481|pdb|3CAP|B;gi|195927457|pdb|3C9L|A;gi|197107530|pdb|1F88|A;gi|197107531|pdb|1F88|B;gi|206582030|pdb|3DQB|A 1756 325 337 0 96.84 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA MNGTEGPNFYVPFSNKTGVVRSPFEAPQYYLAEPWQFSMLAAYMFLLIMLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVFGGFTTTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLVGWSRYIPEGMQCSCGIDYYTPHEETNNESFVIYMFVVHFIIPLIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWLPYAGVAFYIFTHQGSDFGPIFMTIPAFFAKTSAVYNPVIYIMMNKQFRNCMVTTLCCGKNPLGDDEASTTVSKTETSQVAPA
-sp|P08100|OPSD_HUMAN gi|195927458|pdb|3C9M|A 93.10 348 24 0 1 348 1 348 0.0 674 gi|195927458|pdb|3C9M|A 1738 324 335 0 96.26 1 1 MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA MCGTEGPNFYVPFSNKTGVVRSPFEAPQYYLAEPWQFSMLAAYMFLLIMLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVFGGFTTTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLVGWSRYIPEGMQCSCGIDYYTPHEETNNESFVIYMFVVHFIIPLIVIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWLPYAGVAFYIFTHQGSCFGPIFMTIPAFFAKTSAVYNPVIYIMMNKQFRNCMVTTLCCGKNPLGDDEASTTVSKTETSQVAPA
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
06 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/cd2aff5b117c/
changeset: r5350:cd2aff5b117c
user: kellyv
date: 2011-04-06 16:16:30
summary: Corrected typo in manual build name
affected #: 1 file (0 bytes)
--- a/tool-data/shared/ucsc/manual_builds.txt Tue Apr 05 17:59:43 2011 -0400
+++ b/tool-data/shared/ucsc/manual_builds.txt Wed Apr 06 10:16:30 2011 -0400
@@ -692,7 +692,7 @@
eschColi_TW14359 Escherichia coli TW14359 chr=5528136,plasmid_pO157=94601
pUC18 pUC18 Plasmid plasmid=2686
nomLeu1 Gibbon chr1=245538060,chr10=135320619,chr10_random=51011,chr11=134551115,chr12=132397767,chr12_random=336702,chr13=114140689,chr14=106383727,chr15=100373758,chr15_random=814500,chr16=88836341,chr16_random=121782,chr17=78641643,chr17_random=2617017,chr18=76124575,chr19=63791437,chr19_random=297341,chr1_random=3502083,chr2=242756806,chr20=62432189,chr21=47019833,chr22=49520868,chr22_random=31530,chr2_random=335351,chr3=199337376,chr3_random=950829,chr4=191633586,chr4_random=923474,chr5=180612635,chr5_random=150620,chr6=170839170,chr6_random=1837487,chr7=158619002,chr7_random=805938,chr8=146283503,chr8_random=649034,chr9=138402467,chr9_random=1315712,chrUn=217400297,chrX=154793867,chrX_random=1690203,chrY=57470892
-Saccharomcyes_cerevisiae_S288C_SGD2010 S. cerevisae str. S288C chr1=230218,chr2=813184,chr3=316620,chr4=1531933,chr5=576874,chr6=270161,chr7=1090940,chr8=562643,chr9=439888,chr10=745751,chr11=666816,chr12=1078177,chr13=924431,chr14=784333,chr15=1091291,chr16=948066,chrM=85779
+Saccharomyces_cerevisiae_S288C_SGD2010 S. cerevisae str. S288C chr1=230218,chr2=813184,chr3=316620,chr4=1531933,chr5=576874,chr6=270161,chr7=1090940,chr8=562643,chr9=439888,chr10=745751,chr11=666816,chr12=1078177,chr13=924431,chr14=784333,chr15=1091291,chr16=948066,chrM=85779
Spur_v2.6 Purple Sea Urchin (Strongylocentrotus purpuratus) v2.6
Ptrichocarpa_156 Poplar (Populus trichocarpa)
Hydra_JCVI Hydra magnipapillata str. 105
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Trackster: ensure that reads are drawn in squish and pack modes even when view area is large by setting a minimum width of 1px.
by Bitbucket 05 Apr '11
by Bitbucket 05 Apr '11
05 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/dd604de40ac4/
changeset: r5349:dd604de40ac4
user: jgoecks
date: 2011-04-05 23:59:43
summary: Trackster: ensure that reads are drawn in squish and pack modes even when view area is large by setting a minimum width of 1px.
affected #: 1 file (317 bytes)
--- a/static/scripts/trackster.js Tue Apr 05 14:16:26 2011 -0400
+++ b/static/scripts/trackster.js Tue Apr 05 17:59:43 2011 -0400
@@ -1126,10 +1126,9 @@
/**
* Tiles for TiledTracks.
*/
-var Tile = function(track, canvas, histo_max) {
+var Tile = function(track, canvas) {
this.track = track;
this.canvas = canvas;
- this.histo_max = histo_max;
};
/**
@@ -2192,7 +2191,7 @@
// Start dealing with row-by-row tracks
- // If working with a mode where slotting is neccesary, update the incremental slotting
+ // If working with a mode where slotting is necessary, update the incremental slotting
var slots, slots_required = 1;
if ( mode === "no_detail" || mode === "Squish" || mode === "Pack" ) {
slots_required = this.incremental_slots(w_scale, result.data, mode);
@@ -3164,6 +3163,14 @@
var seq_start = feature_start + base_offset,
s_start = Math.floor( Math.max(0, (seq_start - tile_low) * w_scale) ),
s_end = Math.floor( Math.max(0, (seq_start + cig_len - tile_low) * w_scale) );
+
+ // Make sure that read is drawn even if it too small to be rendered officially; in this case,
+ // read is drawn at 1px.
+ // TODO: need to ensure that s_start, s_end are calcuated the same for both slotting
+ // and drawing.
+ if (s_start === s_end) {
+ s_end += 1;
+ }
switch (cig_op) {
case "H": // Hard clipping.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new changesets in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/63e0cc9ca457/
changeset: r5346:63e0cc9ca457
user: jgoecks
date: 2011-04-05 20:12:39
summary: Trackster: mode is not reduced if in auto mode.
affected #: 1 file (22 bytes)
--- a/static/scripts/trackster.js Tue Apr 05 12:08:42 2011 -0400
+++ b/static/scripts/trackster.js Tue Apr 05 14:12:39 2011 -0400
@@ -2092,9 +2092,9 @@
update_auto_mode: function( mode ) {
if ( this.mode == "Auto" ) {
if ( mode == "no_detail" ) {
- mode = "reduced to feature spans";
+ mode = "feature spans";
} else if ( mode == "summary_tree" ) {
- mode = "reduced to coverage histogram";
+ mode = "coverage histogram";
}
this.mode_div.text( "Auto (" + mode + ")" );
}
http://bitbucket.org/galaxy/galaxy-central/changeset/6131f91bad52/
changeset: r5347:6131f91bad52
user: jgoecks
date: 2011-04-05 20:14:32
summary: Merge.
affected #: 3 files (740 bytes)
--- a/tool_conf.xml.main Tue Apr 05 14:12:39 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 14:14:32 2011 -0400
@@ -169,12 +169,6 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
- <section name="Motif Tools" id="motifs">
- <tool file="rgenetics/rgWebLogo3.xml" />
- </section>
- <section name="Multiple Alignments" id="clustal">
- <tool file="rgenetics/rgClustalw.xml" />
- </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
--- a/tools/rgenetics/rgCaCo.py Tue Apr 05 14:12:39 2011 -0400
+++ b/tools/rgenetics/rgCaCo.py Tue Apr 05 14:14:32 2011 -0400
@@ -53,28 +53,26 @@
resfl = resfl[1:]
headl = [x.strip().upper() for x in headl]
headIndex = dict(zip(headl,range(0,len(headl))))
- chrpos = headIndex.get('CHR',None)
- rspos = headIndex.get('RS',None)
- offspos = headIndex.get('OFFSET',None)
- ppos = headIndex.get('LOG10ARMITAGEP',None)
- wewant = [chrpos,rspos,offspos,ppos]
+ whatwewant = ['CHR','RS','OFFSET','LOG10ARMITAGEP']
+ wewant = [headIndex.get(x,None) for x in whatwewant]
if None in wewant: # missing something
- logf.write('### Error missing a required header in makeGFF - headIndex=%s\n' % headIndex)
+ logf.write('### Error missing a required header from %s in makeGFF - headIndex=%s\n' % (whatwewant,headIndex))
return
- resfl = [x for x in resfl if x[ppos] > '']
+ ppos = wewant[3] # last in list
+ resfl = [x for x in resfl if x[ppos] > '' and x[ppos] <> 'NA']
resfl = [(float(x[ppos]),x) for x in resfl] # decorate
resfl.sort()
resfl.reverse() # using -log10 so larger is better
- resfl = resfl[:topn] # truncate
pvals = [x[0] for x in resfl] # need to scale
resfl = [x[1] for x in resfl] # drop decoration
+ resfl = resfl[:topn] # truncate
maxp = max(pvals) # need to scale
minp = min(pvals)
prange = abs(maxp-minp) + 0.5 # fudge
scalefact = 1000.0/prange
logf.write('###maxp=%f,minp=%f,prange=%f,scalefact=%f\n' % (maxp,minp,prange,scalefact))
for i,row in enumerate(resfl):
- row[ppos] = '%d' % (int(scalefact*pvals[i]))
+ row[ppos] = '%d' % (int(scalefact*pvals[i]))
resfl[i] = row # replace
outf = file(outfname,'w')
outf.write(header)
--- a/tools/rgenetics/rgWebLogo3.xml Tue Apr 05 14:12:39 2011 -0400
+++ b/tools/rgenetics/rgWebLogo3.xml Tue Apr 05 14:14:32 2011 -0400
@@ -5,7 +5,7 @@
#if $range.mode == 'part'
-l "$range.seqstart" -u "$range.seqend"
#end if
- </command>
+ </command><inputs><page><param format="fasta" name="input" type="data" label="Fasta File" />
@@ -71,7 +71,7 @@
<param name = "mode" value="complete" /><param name = "size" value="medium" /><param name = "colours" value="auto" />
- <output name="output" file="rgWebLogo3_test.jpg" ftype="jpg" />
+ <output name="output" file="rgWebLogo3_test.jpg" ftype="jpg" compare="sim_size" delta="10000" /></test></tests>
@@ -90,6 +90,15 @@
----
+**Warning about input Fasta format files**
+
+The Weblogo3 program used by this tool will fail if your fasta sequences are not all EXACTLY the same length.
+
+Fasta alignments from the companion ClustalW Galaxy tool will work but many other fasta files may cause this tool to fail - please do not file
+a Galaxy bug report - this is a feature of the tool and a problem with your source data - not a tool error - please make certain all your fasta
+sequences are the same length!
+
+----
**Attribution**
http://bitbucket.org/galaxy/galaxy-central/changeset/79021bb57c1f/
changeset: r5348:79021bb57c1f
user: jgoecks
date: 2011-04-05 20:16:26
summary: Merge.
affected #: 1 file (207 bytes)
--- a/tool_conf.xml.main Tue Apr 05 14:14:32 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 14:16:26 2011 -0400
@@ -169,6 +169,12 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
+ <section name="Motif Tools" id="motifs">
+ <tool file="rgenetics/rgWebLogo3.xml" />
+ </section>
+ <section name="Multiple Alignments" id="clustal">
+ <tool file="rgenetics/rgClustalw.xml" />
+ </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: fubar: reverted unintended changes to tool_conf.xml.main
by Bitbucket 05 Apr '11
by Bitbucket 05 Apr '11
05 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/4257de2ebdd0/
changeset: r5345:4257de2ebdd0
user: fubar
date: 2011-04-05 20:14:08
summary: reverted unintended changes to tool_conf.xml.main
affected #: 1 file (207 bytes)
--- a/tool_conf.xml.main Tue Apr 05 14:07:10 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 14:14:08 2011 -0400
@@ -169,6 +169,12 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
+ <section name="Motif Tools" id="motifs">
+ <tool file="rgenetics/rgWebLogo3.xml" />
+ </section>
+ <section name="Multiple Alignments" id="clustal">
+ <tool file="rgenetics/rgClustalw.xml" />
+ </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new changesets in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/232df3fff6b3/
changeset: r5342:232df3fff6b3
user: fubar
date: 2011-03-28 01:50:50
summary: minor tweaks to rgCaCo.py
affected #: 1 file (17 bytes)
--- a/tools/rgenetics/rgCaCo.py Fri Mar 25 13:26:40 2011 -0400
+++ b/tools/rgenetics/rgCaCo.py Sun Mar 27 19:50:50 2011 -0400
@@ -53,28 +53,26 @@
resfl = resfl[1:]
headl = [x.strip().upper() for x in headl]
headIndex = dict(zip(headl,range(0,len(headl))))
- chrpos = headIndex.get('CHR',None)
- rspos = headIndex.get('RS',None)
- offspos = headIndex.get('OFFSET',None)
- ppos = headIndex.get('LOG10ARMITAGEP',None)
- wewant = [chrpos,rspos,offspos,ppos]
+ whatwewant = ['CHR','RS','OFFSET','LOG10ARMITAGEP']
+ wewant = [headIndex.get(x,None) for x in whatwewant]
if None in wewant: # missing something
- logf.write('### Error missing a required header in makeGFF - headIndex=%s\n' % headIndex)
+ logf.write('### Error missing a required header from %s in makeGFF - headIndex=%s\n' % (whatwewant,headIndex))
return
- resfl = [x for x in resfl if x[ppos] > '']
+ ppos = wewant[3] # last in list
+ resfl = [x for x in resfl if x[ppos] > '' and x[ppos] <> 'NA']
resfl = [(float(x[ppos]),x) for x in resfl] # decorate
resfl.sort()
resfl.reverse() # using -log10 so larger is better
- resfl = resfl[:topn] # truncate
pvals = [x[0] for x in resfl] # need to scale
resfl = [x[1] for x in resfl] # drop decoration
+ resfl = resfl[:topn] # truncate
maxp = max(pvals) # need to scale
minp = min(pvals)
prange = abs(maxp-minp) + 0.5 # fudge
scalefact = 1000.0/prange
logf.write('###maxp=%f,minp=%f,prange=%f,scalefact=%f\n' % (maxp,minp,prange,scalefact))
for i,row in enumerate(resfl):
- row[ppos] = '%d' % (int(scalefact*pvals[i]))
+ row[ppos] = '%d' % (int(scalefact*pvals[i]))
resfl[i] = row # replace
outf = file(outfname,'w')
outf.write(header)
http://bitbucket.org/galaxy/galaxy-central/changeset/be1accb7a6d0/
changeset: r5343:be1accb7a6d0
user: fubar
date: 2011-04-05 19:57:14
summary: merge
affected #: 33 files (24.1 KB)
--- a/cron/add_manual_builds.py Sun Mar 27 19:50:50 2011 -0400
+++ b/cron/add_manual_builds.py Tue Apr 05 13:57:14 2011 -0400
@@ -21,12 +21,12 @@
build_file_out = open(build_file,'a')
for line in open(input_file):
try:
- fields = line.split("\t")
+ fields = line.replace("\n","").replace("\r","").split("\t")
build = fields.pop(0)
if build in existing_builds: continue # if build exists, leave alone
name = fields.pop(0)
try: # get chrom lens if included in file, otherwise still add build
- chrs = fields.pop(0).replace("\n","").replace("\r","").split(",")
+ chrs = fields.pop(0).split(",")
except:
chrs = []
print>>build_file_out, build+"\t"+name+" ("+build+")"
--- a/datatypes_conf.xml.sample Sun Mar 27 19:50:50 2011 -0400
+++ b/datatypes_conf.xml.sample Tue Apr 05 13:57:14 2011 -0400
@@ -128,9 +128,9 @@
<converter file="wiggle_to_simple_converter.xml" target_datatype="interval"/><!-- <display file="gbrowse/gbrowse_wig.xml" /> --></datatype>
- <datatype extension="array_tree" type="galaxy.datatypes.data:Data" /><datatype extension="summary_tree" type="galaxy.datatypes.data:Data" /><datatype extension="interval_index" type="galaxy.datatypes.data:Data" />
+ <datatype extension="tabix" type="galaxy.datatypes.data:Data" /><!-- Start EMBOSS tools --><datatype extension="acedb" type="galaxy.datatypes.data:Text"/><datatype extension="asn1" type="galaxy.datatypes.data:Text"/>
--- a/lib/galaxy/config.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/config.py Tue Apr 05 13:57:14 2011 -0400
@@ -2,7 +2,7 @@
Universe configuration builder.
"""
-import sys, os
+import sys, os, tempfile
import logging, logging.config
import ConfigParser
from galaxy.util import string_as_bool
@@ -39,6 +39,7 @@
# Where dataset files are stored
self.file_path = resolve_path( kwargs.get( "file_path", "database/files" ), self.root )
self.new_file_path = resolve_path( kwargs.get( "new_file_path", "database/tmp" ), self.root )
+ tempfile.tempdir = self.new_file_path
self.openid_consumer_cache_path = resolve_path( kwargs.get( "openid_consumer_cache_path", "database/openid_consumer_cache" ), self.root )
self.cookie_path = kwargs.get( "cookie_path", "/" )
# web API
--- a/lib/galaxy/datatypes/converters/gff_to_interval_index_converter.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/datatypes/converters/gff_to_interval_index_converter.py Tue Apr 05 13:57:14 2011 -0400
@@ -32,7 +32,7 @@
convert_gff_coords_to_bed( feature )
index.add( feature.chrom, feature.start, feature.end, offset )
- offset += feature.raw_size()
+ offset += feature.raw_size
index.write( open(out_fname, "w") )
--- a/lib/galaxy/datatypes/data.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/datatypes/data.py Tue Apr 05 13:57:14 2011 -0400
@@ -354,6 +354,7 @@
class Text( Data ):
file_ext = 'txt'
+ line_class = 'line'
"""Add metadata elements"""
MetadataElement( name="data_lines", default=0, desc="Number of data lines", readonly=True, optional=True, visible=False, no_value=0 )
@@ -417,26 +418,30 @@
data_lines += 1
return data_lines
def set_peek( self, dataset, line_count=None, is_multi_byte=False ):
+ """
+ Set the peek. This method is used by various subclasses of Text.
+ """
if not dataset.dataset.purged:
# The file must exist on disk for the get_file_peek() method
dataset.peek = get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
if line_count is None:
# See if line_count is stored in the metadata
- if dataset.metadata.data_lines is not None:
- dataset.blurb = "%s %s" % ( util.commaify( str(dataset.metadata.data_lines) ), inflector.cond_plural(dataset.metadata.data_lines, "line") )
+ if dataset.metadata.data_lines:
+ dataset.blurb = "%s %s" % ( util.commaify( str(dataset.metadata.data_lines) ), inflector.cond_plural(dataset.metadata.data_lines, self.line_class) )
else:
# Number of lines is not known ( this should not happen ), and auto-detect is
# needed to set metadata
# This can happen when the file is larger than max_optional_metadata_filesize.
if int(dataset.get_size()) <= 1048576:
#Small dataset, recount all lines and reset peek afterward.
- dataset.metadata.data_lines = self.count_data_lines(dataset)
- self.set_peek(dataset)
+ lc = self.count_data_lines(dataset)
+ dataset.metadata.data_lines = lc
+ dataset.blurb = "%s %s" % ( util.commaify( str(lc) ), inflector.cond_plural(lc, self.line_class) )
else:
est_lines = self.estimate_file_lines(dataset)
- dataset.blurb = "~%s %s" % ( util.commaify(util.roundify(str(est_lines))), inflector.cond_plural(est_lines, "line") )
+ dataset.blurb = "~%s %s" % ( util.commaify(util.roundify(str(est_lines))), inflector.cond_plural(est_lines, self.line_class) )
else:
- dataset.blurb = "%s %s" % util.commaify( str(line_count) ), inflector.cond_plural(line_count, "line")
+ dataset.blurb = "%s %s" % ( util.commaify( str(line_count) ), inflector.cond_plural(line_count, self.line_class) )
else:
dataset.peek = 'file does not exist'
dataset.blurb = 'file purged from disk'
--- a/lib/galaxy/datatypes/interval.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/datatypes/interval.py Tue Apr 05 13:57:14 2011 -0400
@@ -45,6 +45,7 @@
class Interval( Tabular ):
"""Tab delimited data containing interval information"""
file_ext = "interval"
+ line_class = "region"
"""Add metadata elements"""
MetadataElement( name="chromCol", default=1, desc="Chrom column", param=metadata.ColumnParameter )
@@ -60,23 +61,6 @@
self.add_display_app ( 'ucsc', 'display at UCSC', 'as_ucsc_display_file', 'ucsc_links' )
def init_meta( self, dataset, copy_from=None ):
Tabular.init_meta( self, dataset, copy_from=copy_from )
- def set_peek( self, dataset, line_count=None, is_multi_byte=False ):
- """Set the peek and blurb text"""
- if not dataset.dataset.purged:
- dataset.peek = data.get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
- if line_count is None:
- # See if line_count is stored in the metadata
- if dataset.metadata.data_lines is not None:
- dataset.blurb = "%s regions" % util.commaify( str( dataset.metadata.data_lines ) )
- else:
- # Number of lines is not known ( this should not happen ), and auto-detect is
- # needed to set metadata
- dataset.blurb = "~%s regions" % util.commaify(util.roundify(str(self.estimate_file_lines(dataset))))
- else:
- dataset.blurb = "%s regions" % util.commaify( str( line_count ) )
- else:
- dataset.peek = 'file does not exist'
- dataset.blurb = 'file purged from disk'
def set_meta( self, dataset, overwrite = True, first_line_is_header = False, **kwd ):
"""Tries to guess from the line the location number of the column for the chromosome, region start-end and strand"""
Tabular.set_meta( self, dataset, overwrite = overwrite, skip = 0 )
--- a/lib/galaxy/datatypes/tabular.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/datatypes/tabular.py Tue Apr 05 13:57:14 2011 -0400
@@ -223,8 +223,8 @@
out.append( '<tr><td>' )
out.append( '%s</td></tr>' % escape( comments.pop(0) ) )
return "".join( out )
- def set_peek( self, dataset, line_count=None, is_multi_byte=False ):
- data.Text.set_peek( self, dataset, line_count=line_count, is_multi_byte=is_multi_byte )
+ def set_peek( self, dataset, line_count=None, is_multi_byte=False):
+ super(Tabular, self).set_peek( dataset, line_count=line_count, is_multi_byte=is_multi_byte)
if dataset.metadata.comment_lines:
dataset.blurb = "%s, %s comments" % ( dataset.blurb, util.commaify( str( dataset.metadata.comment_lines ) ) )
def display_peek( self, dataset ):
@@ -383,6 +383,7 @@
class Pileup( Tabular ):
"""Tab delimited data in pileup (6- or 10-column) format"""
file_ext = "pileup"
+ line_class = "genomic coordinate"
"""Add metadata elements"""
MetadataElement( name="chromCol", default=1, desc="Chrom column", param=metadata.ColumnParameter )
@@ -392,24 +393,6 @@
def init_meta( self, dataset, copy_from=None ):
Tabular.init_meta( self, dataset, copy_from=copy_from )
- def set_peek( self, dataset, line_count=None, is_multi_byte=False ):
- """Set the peek and blurb text"""
- if not dataset.dataset.purged:
- dataset.peek = data.get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
- if line_count is None:
- # See if line_count is stored in the metadata
- if dataset.metadata.data_lines is not None:
- dataset.blurb = "%s genomic coordinates" % util.commaify( str( dataset.metadata.data_lines ) )
- else:
- # Number of lines is not known ( this should not happen ), and auto-detect is
- # needed to set metadata
- dataset.blurb = "? genomic coordinates"
- else:
- dataset.blurb = "%s genomic coordinates" % util.commaify( str( line_count ) )
- else:
- dataset.peek = 'file does not exist'
- dataset.blurb = 'file purged from disk'
-
def make_html_table( self, dataset, skipchars=[] ):
"""Create HTML table, used for displaying peek"""
out = ['<table cellspacing="0" cellpadding="3">']
--- a/lib/galaxy/datatypes/util/gff_util.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/datatypes/util/gff_util.py Tue Apr 05 13:57:14 2011 -0400
@@ -11,7 +11,7 @@
only attribute is 'group.'
"""
def __init__( self, reader, fields, chrom_col, feature_col, start_col, end_col, \
- strand_col, score_col, default_strand, fix_strand=False, raw_line='' ):
+ strand_col, score_col, default_strand, fix_strand=False ):
# HACK: GFF format allows '.' for strand but GenomicInterval does not. To get around this,
# temporarily set strand and then unset after initing GenomicInterval.
unknown_strand = False
@@ -34,8 +34,7 @@
raise MissingFieldError( "No field for score_col (%d)" % score_col )
self.score = self.fields[ self.score_col ]
- # Attributes specific to GFF.
- self.raw_line = raw_line
+ # GFF attributes.
self.attributes = parse_gff_attributes( fields[8] )
class GFFFeature( GFFInterval ):
@@ -43,11 +42,13 @@
A GFF feature, which can include multiple intervals.
"""
def __init__( self, reader, chrom_col, feature_col, start_col, end_col, \
- strand_col, score_col, default_strand, fix_strand=False, intervals=[] ):
+ strand_col, score_col, default_strand, fix_strand=False, intervals=[], \
+ raw_size=0 ):
GFFInterval.__init__( self, reader, intervals[0].fields, chrom_col, feature_col, \
start_col, end_col, strand_col, score_col, default_strand, \
fix_strand=fix_strand )
self.intervals = intervals
+ self.raw_size = raw_size
# Use intervals to set feature attributes.
for interval in self.intervals:
# Error checking. NOTE: intervals need not share the same strand.
@@ -68,20 +69,6 @@
if not name:
name = self.attributes.get( 'group', None )
return name
-
- def raw_size( self ):
- """
- Returns raw size of feature; raw size is the number of bytes that
- comprise feature.
- """
- # Feature length is all intervals/lines that comprise feature.
- feature_len = 0
- for interval in self.intervals:
- # HACK: +1 for EOL char. Need bx-python to provide raw_line itself
- # b/c TableReader strips EOL characters, thus changing the line
- # length.
- feature_len += len( interval.raw_line ) + 1
- return feature_len
class GFFIntervalToBEDReaderWrapper( NiceReaderWrapper ):
"""
@@ -124,7 +111,7 @@
def parse_row( self, line ):
interval = GFFInterval( self, line.split( "\t" ), self.chrom_col, self.feature_col, \
self.start_col, self.end_col, self.strand_col, self.score_col, \
- self.default_strand, fix_strand=self.fix_strand, raw_line=line )
+ self.default_strand, fix_strand=self.fix_strand )
return interval
def next( self ):
@@ -151,7 +138,8 @@
#
# Get next GFFFeature
- #
+ #
+ raw_size = 0
# If there is no seed interval, set one. Also, if there are no more
# intervals to read, this is where iterator dies.
@@ -161,6 +149,8 @@
self.seed_interval = GenomicIntervalReader.next( self )
except ParseError, e:
handle_parse_error( e )
+ finally:
+ raw_size += len( self.current_line )
# If header or comment, clear seed interval and return it.
if isinstance( self.seed_interval, ( Header, Comment ) ):
@@ -187,6 +177,9 @@
break
except ParseError, e:
handle_parse_error( e )
+ continue
+ finally:
+ raw_size += len( self.current_line )
# If interval not associated with feature, break.
group = interval.attributes.get( 'group', None )
@@ -214,7 +207,7 @@
return GFFFeature( self, self.chrom_col, self.feature_col, self.start_col, \
self.end_col, self.strand_col, self.score_col, \
self.default_strand, fix_strand=self.fix_strand, \
- intervals=feature_intervals )
+ intervals=feature_intervals, raw_size=raw_size )
def convert_bed_coords_to_gff( interval ):
--- a/lib/galaxy/model/__init__.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/model/__init__.py Tue Apr 05 13:57:14 2011 -0400
@@ -103,14 +103,14 @@
# For historical reasons state propogates down to datasets
for da in self.output_datasets:
da.dataset.state = state
- def get_param_values( self, app ):
+ def get_param_values( self, app, ignore_errors=False ):
"""
Read encoded parameter values from the database and turn back into a
dict of tool parameter values.
"""
param_dict = dict( [ ( p.name, p.value ) for p in self.parameters ] )
tool = app.toolbox.tools_by_id[self.tool_id]
- param_dict = tool.params_from_strings( param_dict, app )
+ param_dict = tool.params_from_strings( param_dict, app, ignore_errors=ignore_errors )
return param_dict
def check_if_output_datasets_deleted( self ):
"""
--- a/lib/galaxy/model/mapping.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/model/mapping.py Tue Apr 05 13:57:14 2011 -0400
@@ -1268,7 +1268,7 @@
assign_mapper( context, Library, Library.table,
properties=dict(
root_folder=relation( LibraryFolder, backref=backref( "library_root" ) )
- )
+ )
)
assign_mapper( context, LibraryInfoAssociation, LibraryInfoAssociation.table,
@@ -1281,26 +1281,26 @@
) )
assign_mapper( context, LibraryFolder, LibraryFolder.table,
- properties=dict(
- folders=relation(
- LibraryFolder,
+ properties=dict(
+ folders=relation(
+ LibraryFolder,
primaryjoin=( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ),
order_by=asc( LibraryFolder.table.c.name ),
backref=backref( "parent", primaryjoin=( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ), remote_side=[LibraryFolder.table.c.id] ) ),
- active_folders=relation( LibraryFolder,
- primaryjoin=( ( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ) & ( not_( LibraryFolder.table.c.deleted ) ) ),
- order_by=asc( LibraryFolder.table.c.name ),
+ active_folders=relation( LibraryFolder,
+ primaryjoin=( ( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ) & ( not_( LibraryFolder.table.c.deleted ) ) ),
+ order_by=asc( LibraryFolder.table.c.name ),
lazy=True, #"""sqlalchemy.exceptions.ArgumentError: Error creating eager relationship 'active_folders' on parent class '<class 'galaxy.model.LibraryFolder'>' to child class '<class 'galaxy.model.LibraryFolder'>': Cant use eager loading on a self referential relationship."""
viewonly=True ),
datasets=relation( LibraryDataset,
- primaryjoin=( ( LibraryDataset.table.c.folder_id == LibraryFolder.table.c.id ) ),
- order_by=asc( LibraryDataset.table.c._name ),
- lazy=False,
+ primaryjoin=( ( LibraryDataset.table.c.folder_id == LibraryFolder.table.c.id ) ),
+ order_by=asc( LibraryDataset.table.c._name ),
+ lazy=True,
viewonly=True ),
active_datasets=relation( LibraryDataset,
primaryjoin=( ( LibraryDataset.table.c.folder_id == LibraryFolder.table.c.id ) & ( not_( LibraryDataset.table.c.deleted ) ) ),
- order_by=asc( LibraryDataset.table.c._name ),
- lazy=False,
+ order_by=asc( LibraryDataset.table.c._name ),
+ lazy=True,
viewonly=True )
) )
--- a/lib/galaxy/tools/__init__.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/tools/__init__.py Tue Apr 05 13:57:14 2011 -0400
@@ -1252,7 +1252,21 @@
for input in inputs.itervalues():
# No value, insert the default
if input.name not in values:
- messages[ input.name ] = "No value found for '%s%s', used default" % ( prefix, input.label )
+ if isinstance( input, Conditional ):
+ messages[ input.name ] = { input.test_param.name: "No value found for '%s%s', used default" % ( prefix, input.label ) }
+ test_value = input.test_param.get_initial_value( trans, context )
+ current_case = input.get_current_case( test_value, trans )
+ self.check_and_update_param_values_helper( input.cases[ current_case ].inputs, {}, trans, messages[ input.name ], context, prefix )
+ elif isinstance( input, Repeat ):
+ if input.min:
+ messages[ input.name ] = []
+ for i in range( input.min ):
+ rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 )
+ rep_dict = dict()
+ messages[ input.name ].append( rep_dict )
+ self.check_and_update_param_values_helper( input.inputs, {}, trans, rep_dict, context, rep_prefix )
+ else:
+ messages[ input.name ] = "No value found for '%s%s', used default" % ( prefix, input.label )
values[ input.name ] = input.get_initial_value( trans, context )
# Value, visit recursively as usual
else:
--- a/lib/galaxy/tools/actions/__init__.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/tools/actions/__init__.py Tue Apr 05 13:57:14 2011 -0400
@@ -133,16 +133,18 @@
else:
new_list.append( value )
return new_list
- def wrap_values( inputs, input_values ):
+ def wrap_values( inputs, input_values, skip_missing_values = False ):
# Wrap tool inputs as necessary
for input in inputs.itervalues():
+ if input.name not in input_values and skip_missing_values:
+ continue
if isinstance( input, Repeat ):
for d in input_values[ input.name ]:
- wrap_values( input.inputs, d )
+ wrap_values( input.inputs, d, skip_missing_values = skip_missing_values )
elif isinstance( input, Conditional ):
values = input_values[ input.name ]
current = values[ "__current_case__" ]
- wrap_values( input.cases[current].inputs, values )
+ wrap_values( input.cases[current].inputs, values, skip_missing_values = skip_missing_values )
elif isinstance( input, DataToolParameter ):
input_values[ input.name ] = \
galaxy.tools.DatasetFilenameWrapper( input_values[ input.name ],
@@ -254,7 +256,7 @@
if output.change_format:
if params is None:
params = make_dict_copy( incoming )
- wrap_values( tool.inputs, params )
+ wrap_values( tool.inputs, params, skip_missing_values = not tool.check_values )
for change_elem in output.change_format:
for when_elem in change_elem.findall( 'when' ):
check = when_elem.get( 'input', None )
@@ -304,7 +306,7 @@
# <outputs>
# <data format="input" name="output" label="Blat on ${<input_param>.name}" />
# </outputs>
- wrap_values( tool.inputs, params )
+ wrap_values( tool.inputs, params, skip_missing_values = not tool.check_values )
#tool (only needing to be set once) and on_string (set differently for each label) are overwritten for each output dataset label being determined
params['tool'] = tool
params['on_string'] = on_text
--- a/lib/galaxy/visualization/tracks/data_providers.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/visualization/tracks/data_providers.py Tue Apr 05 13:57:14 2011 -0400
@@ -11,13 +11,16 @@
pkg_resources.require( "pysam" )
pkg_resources.require( "numpy" )
from galaxy.datatypes.util.gff_util import *
+from galaxy.util.json import from_json_string
from bx.interval_index_file import Indexes
from bx.arrays.array_tree import FileArrayTreeDict
from bx.bbi.bigwig_file import BigWigFile
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.tracks.summary import *
from galaxy.datatypes.tabular import Vcf
-from galaxy.datatypes.interval import Bed, Gff
+from galaxy.datatypes.interval import Bed, Gff, Gtf
+from galaxy.datatypes.util.gff_util import parse_gff_attributes
+
from pysam import csamtools
MAX_VALS = 5000 # only display first MAX_VALS features
@@ -126,7 +129,7 @@
return st.chrom_blocks.keys()
- def get_summary( self, chrom, start, end, **kwargs):
+ def get_summary( self, chrom, start, end, **kwargs ):
filename = self.converted_dataset.file_name
st = self.CACHE[filename]
if st is None:
@@ -170,7 +173,7 @@
self.CACHE[filename] = st
# Check for data.
- return st.chrom_blocks.get(chrom, None) is not None or st.chrom_blocks.get(chrom[3:], None) is not None
+ return st.chrom_blocks.get(chrom, None) is not None or (chrom and st.chrom_blocks.get(chrom[3:], None) is not None)
class VcfDataProvider( TracksDataProvider ):
"""
@@ -303,12 +306,12 @@
if read.is_proper_pair:
if qname in paired_pending: # one in dict is always first
pair = paired_pending[qname]
- results.append( [ "%i_%s" % ( read.pos, qname ),
+ results.append( [ "%i_%s" % ( pair['start'], qname ),
pair['start'],
read.pos + read_len,
qname,
[ pair['start'], pair['end'], pair['cigar'], pair['seq'] ],
- [ read.pos, read.pos + read_len, read.cigar, seq]
+ [ read.pos, read.pos + read_len, read.cigar, seq ]
] )
del paired_pending[qname]
else:
@@ -484,9 +487,76 @@
col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
def write_data_to_file( self, chrom, start, end, filename ):
- # TODO: write function.
- pass
-
+ source = open( self.original_dataset.file_name )
+ index = Indexes( self.converted_dataset.file_name )
+ out = open( filename, 'w' )
+ for start, end, offset in index.find(chrom, start, end):
+ source.seek( offset )
+ if isinstance( self.original_dataset.datatype, Gff ):
+ reader = GFFReaderWrapper( source, fix_strand=True )
+ feature = reader.next()
+ for interval in feature.intervals:
+ out.write(interval.raw_line + '\n')
+ elif isinstance( self.original_dataset.datatype, Bed ):
+ out.write( source.readline() )
+ out.close()
+
+ def get_filters( self ):
+ """ Returns a dataset's filters. """
+
+ # is_ functions taken from Tabular.set_meta
+ def is_int( column_text ):
+ try:
+ int( column_text )
+ return True
+ except:
+ return False
+ def is_float( column_text ):
+ try:
+ float( column_text )
+ return True
+ except:
+ if column_text.strip().lower() == 'na':
+ return True #na is special cased to be a float
+ return False
+
+ #
+ # Get filters.
+ # TODOs:
+ # (a) might be useful to move this into each datatype's set_meta method;
+ # (b) could look at first N lines to ensure GTF attribute types are consistent.
+ #
+ filters = []
+ # HACK: first 8 fields are for drawing, so start filter column index at 9.
+ filter_col = 8
+ if isinstance( self.original_dataset.datatype, Gff ):
+ # Can filter by score and GTF attributes.
+ filters = [ { 'name': 'Score', 'type': 'int', 'index': filter_col } ]
+ filter_col += 1
+ if isinstance( self.original_dataset.datatype, Gtf ):
+ for i, line in enumerate( open(self.original_dataset.file_name) ):
+ if not line.startswith('#'):
+ # Look at first line for attributes and types.
+ attributes = parse_gff_attributes( line.split('\t')[8] )
+ for attr, value in attributes.items():
+ # Get attribute type.
+ if is_int( value ):
+ attr_type = 'int'
+ elif is_float( value ):
+ attr_type = 'float'
+ else:
+ attr_type = 'str'
+ # Add to filters.
+ if attr_type is not 'str':
+ filters.append( { 'name': attr, 'type': attr_type, 'index': filter_col } )
+ filter_col += 1
+ break
+ elif isinstance( self.original_dataset.datatype, Bed ):
+ # Can filter by score column only.
+ filters = [ { 'name': 'Score', 'type': 'int', 'index': filter_col } ]
+
+ return filters
+
def get_data( self, chrom, start, end, **kwargs ):
start, end = int(start), int(end)
source = open( self.original_dataset.file_name )
@@ -509,6 +579,7 @@
#
# First three entries are mandatory, others are optional.
#
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
no_detail = ( "no_detail" in kwargs )
for start, end, offset in index.find(chrom, start, end):
if count >= MAX_VALS:
@@ -522,7 +593,7 @@
# GFF dataset.
reader = GFFReaderWrapper( source, fix_strand=True )
feature = reader.next()
- payload = package_gff_feature( feature, no_detail )
+ payload = package_gff_feature( feature, no_detail, filter_cols )
payload.insert( 0, offset )
elif isinstance( self.original_dataset.datatype, Bed ):
# BED dataset.
@@ -536,15 +607,11 @@
#end = min( len( feature ), 8 )
#payload.extend( feature[ 3:end ] )
- # Name, score, strand, thick start, thick end.
+ # Name, strand, thick start, thick end.
if length >= 4:
payload.append(feature[3])
- if length >= 5:
- payload.append( float(feature[4]) )
if length >= 6:
payload.append(feature[5])
-
- # Thick start, end.
if length >= 8:
payload.append(int(feature[6]))
payload.append(int(feature[7]))
@@ -555,7 +622,11 @@
block_starts = [ int(n) for n in feature[11].split(',') if n != '' ]
blocks = zip( block_sizes, block_starts )
payload.append( [ ( start + block[1], start + block[1] + block[0] ) for block in blocks ] )
-
+
+ # Score (filter data)
+ if length >= 5 and filter_cols and filter_cols[0] == "Score":
+ payload.append( float(feature[4]) )
+
results.append( payload )
return { 'data': results, 'message': message }
@@ -587,7 +658,7 @@
payload = package_gff_feature( feature )
payload.insert( 0, offset )
results.append( payload )
- offset += feature.raw_size()
+ offset += feature.raw_size
return { 'data': results, 'message': message }
@@ -644,7 +715,7 @@
pass
return data_provider
-def package_gff_feature( feature, no_detail=False ):
+def package_gff_feature( feature, no_detail=False, filter_cols=[] ):
""" Package a GFF feature in an array for data providers. """
feature = convert_gff_coords_to_bed( feature )
@@ -656,7 +727,6 @@
payload = [ feature.start,
feature.end,
feature.name(),
- feature.score,
feature.strand,
# No notion of thick start, end in GFF, so make everything
# thick.
@@ -677,4 +747,13 @@
blocks = zip( block_sizes, block_starts )
payload.append( [ ( feature.start + block[1], feature.start + block[1] + block[0] ) for block in blocks ] )
+ # Add filter data to payload.
+ for col in filter_cols:
+ if col == "Score":
+ payload.append( feature.score )
+ elif col in feature.attributes:
+ payload.append( feature.attributes[col] )
+ else:
+ # Dummy value.
+ payload.append( "na" )
return payload
--- a/lib/galaxy/visualization/tracks/visual_analytics.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/visualization/tracks/visual_analytics.py Tue Apr 05 13:57:14 2011 -0400
@@ -1,5 +1,7 @@
-from galaxy.tools.parameters.basic import IntegerToolParameter, FloatToolParameter
+import urllib
+from galaxy.tools.parameters.basic import IntegerToolParameter, FloatToolParameter, SelectToolParameter
+from galaxy.tools.parameters.dynamic_options import DynamicOptions
def get_dataset_job( hda ):
# Get dataset's job.
@@ -28,14 +30,19 @@
tool_param_values = dict( [ ( p.name, p.value ) for p in job.parameters ] )
tool_param_values = tool.params_from_strings( tool_param_values, trans.app, ignore_errors=True )
for name, input in tool.inputs.items():
- if type( input ) == IntegerToolParameter:
- tool_params.append( { 'name' : name, 'label': input.label, 'type': 'int', \
- 'value': tool_param_values.get( name, input.value ), \
- 'min' : input.min, 'max' : input.max } )
- elif type( input ) == FloatToolParameter:
- tool_params.append( { 'name' : name, 'label': input.label, 'type': 'float', \
- 'value': tool_param_values.get( name, input.value ), \
- 'min' : input.min, 'max' : input.max } )
+ if type( input ) == IntegerToolParameter or type( input ) == FloatToolParameter:
+ param_dict = { 'name' : name, 'label' : input.label, \
+ 'value' : tool_param_values.get( name, input.value ), \
+ 'type' : 'number', 'init_value' : input.value,
+ 'html' : urllib.quote( input.get_html() ) }
+ if input.min:
+ param_dict['min'] = input.min
+ if input.max:
+ param_dict['max'] = input.max
+ tool_params.append( param_dict )
+ elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions:
+ tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \
+ 'html' : urllib.quote( input.get_html() ) } )
# If tool has parameters that can be interactively modified, return tool.
# Return empty set otherwise.
--- a/lib/galaxy/web/api/workflows.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/web/api/workflows.py Tue Apr 05 13:57:14 2011 -0400
@@ -57,7 +57,7 @@
inputs = {}
for step in latest_workflow.steps:
if step.type == 'data_input':
- inputs[step.id] = {'label':"Input Dataset", 'value':""}
+ inputs[step.id] = {'label':step.tool_inputs['name'], 'value':""}
else:
pass
# Eventually, allow regular tool parameters to be inserted and modified at runtime.
--- a/lib/galaxy/web/controllers/tool_runner.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/web/controllers/tool_runner.py Tue Apr 05 13:57:14 2011 -0400
@@ -120,7 +120,7 @@
error( "The '%s' tool does not currently support rerunning." % tool.name )
# Get the job's parameters
try:
- params_objects = job.get_param_values( trans.app )
+ params_objects = job.get_param_values( trans.app, ignore_errors = True )
except:
raise Exception( "Failed to get parameters for dataset id %d " % data.id )
upgrade_messages = tool.check_and_update_param_values( params_objects, trans )
--- a/lib/galaxy/web/controllers/tracks.py Sun Mar 27 19:50:50 2011 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Tue Apr 05 13:57:14 2011 -0400
@@ -2,7 +2,7 @@
Support for constructing and viewing custom "track" browsers within Galaxy.
"""
-import re, time, pkg_resources
+import re, pkg_resources
pkg_resources.require( "bx-python" )
from bx.seq.twobit import TwoBitFile
@@ -13,7 +13,6 @@
from galaxy.web.framework import simplejson
from galaxy.web.framework.helpers import time_ago, grids
from galaxy.util.bunch import Bunch
-from galaxy import util
from galaxy.datatypes.interval import Gff
from galaxy.visualization.tracks.data_providers import *
@@ -202,7 +201,6 @@
return trans.fill_template( "tracks/new_browser.mako", dbkeys=self._get_dbkeys( trans ), default_dbkey=kwargs.get("default_dbkey", None) )
@web.json
- @web.require_login()
def add_track_async(self, trans, hda_id=None, ldda_id=None):
if hda_id:
hda_ldda = "hda"
@@ -671,6 +669,8 @@
if not tool:
return messages.NO_TOOL
tool_params = dict( [ ( p.name, p.value ) for p in original_job.parameters ] )
+ # TODO: need to handle updates to conditional parameters; conditional
+ # params are stored in dicts (and dicts within dicts).
tool_params.update( dict( [ ( key, value ) for key, value in kwargs.items() if key in tool.inputs ] ) )
tool_params = tool.params_from_strings( tool_params, self.app )
@@ -686,13 +686,16 @@
messages_list = []
for jida in original_job.input_datasets:
input_dataset = jida.dataset
- track_type, data_sources = input_dataset.datatype.get_track_type()
- # Convert to datasource that provides 'data' because we need to
- # extract the original data.
- data_source = data_sources[ 'data' ]
- msg = self._convert_dataset( trans, input_dataset, data_source )
- if msg is not None:
- messages_list.append( msg )
+ # TODO: put together more robust way to determine if a dataset can be indexed.
+ if hasattr( input_dataset, 'get_track_type' ):
+ # Can index dataset.
+ track_type, data_sources = input_dataset.datatype.get_track_type()
+ # Convert to datasource that provides 'data' because we need to
+ # extract the original data.
+ data_source = data_sources[ 'data' ]
+ msg = self._convert_dataset( trans, input_dataset, data_source )
+ if msg is not None:
+ messages_list.append( msg )
# Return any messages generated during conversions.
return_message = _get_highest_priority_msg( messages_list )
@@ -703,51 +706,67 @@
# Set input datasets for tool. Input datasets are subsets of full
# datasets and are based on chrom, low, high.
#
- hda_permissions = trans.app.security_agent.history_get_default_permissions( original_dataset.history )
+
+ # If user is rerunning own tool, put new data in original dataset's
+ # history. If another user is running tool, put new data in current
+ # history.
+ if original_dataset.history.user == trans.user:
+ working_history = original_dataset.history
+ else:
+ working_history = trans.get_history( create=True )
+ hda_permissions = trans.app.security_agent.history_get_default_permissions( working_history )
messages_list = []
for jida in original_job.input_datasets:
input_dataset = jida.dataset
- track_type, data_sources = input_dataset.datatype.get_track_type()
- data_source = data_sources[ 'data' ]
- converted_dataset = input_dataset.get_converted_dataset( trans, data_source )
+ if hasattr( input_dataset, 'get_track_type' ):
+ #
+ # Dataset can be indexed and hence a subset can be extracted.
+ #
+ track_type, data_sources = input_dataset.datatype.get_track_type()
+ data_source = data_sources[ 'data' ]
+ converted_dataset = input_dataset.get_converted_dataset( trans, data_source )
- #
- # Create new HDA for input dataset's subset.
- #
- subset_dataset = trans.app.model.HistoryDatasetAssociation( extension=input_dataset.ext, \
- dbkey=input_dataset.dbkey, \
- create_dataset=True, \
- sa_session=trans.sa_session,
- name="Subset [%s:%i-%i] of data %i" % \
- ( chrom, low, high, input_dataset.hid ),
- visible=False )
- input_dataset.history.add_dataset( subset_dataset )
- trans.sa_session.add( subset_dataset )
- trans.app.security_agent.set_all_dataset_permissions( subset_dataset.dataset, hda_permissions )
- if input_dataset.extension == 'bam':
- data_provider = BamDataProvider( original_dataset=input_dataset, converted_dataset=converted_dataset )
- data_provider.write_data_to_file( chrom, low, high, subset_dataset.file_name )
- # TODO: size not working.
- subset_dataset.set_size()
- subset_dataset.info = "Data subset for trackster"
- subset_dataset.set_dataset_state( trans.app.model.Dataset.states.OK )
- trans.sa_session.flush()
+ #
+ # Create new HDA for input dataset's subset.
+ #
+ new_dataset = trans.app.model.HistoryDatasetAssociation( extension=input_dataset.ext, \
+ dbkey=input_dataset.dbkey, \
+ create_dataset=True, \
+ sa_session=trans.sa_session,
+ name="Subset [%s:%i-%i] of data %i" % \
+ ( chrom, low, high, input_dataset.hid ),
+ visible=False )
+ working_history.add_dataset( new_dataset )
+ trans.sa_session.add( new_dataset )
+ trans.app.security_agent.set_all_dataset_permissions( new_dataset.dataset, hda_permissions )
- # Add dataset to tool's parameters.
- tool_params[ jida.name ] = subset_dataset
+ # Write subset of data to new dataset
+ data_provider_class = get_data_provider( original_dataset=input_dataset )
+ data_provider = data_provider_class( original_dataset=input_dataset,
+ converted_dataset=converted_dataset )
+ data_provider.write_data_to_file( chrom, low, high, new_dataset.file_name )
+
+ # TODO: size not working.
+ new_dataset.set_size()
+ new_dataset.info = "Data subset for trackster"
+ new_dataset.set_dataset_state( trans.app.model.Dataset.states.OK )
+ trans.sa_session.flush()
+
+ # Add dataset to tool's parameters.
+ tool_params[ jida.name ] = new_dataset
#
# Start tool and handle outputs.
#
try:
- subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=original_dataset.history )
+ subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=working_history )
except Exception, e:
# Lots of things can go wrong when trying to execute tool.
return to_json_string( { "error" : True, "message" : e.__class__.__name__ + ": " + str(e) } )
for output in subset_job_outputs.values():
output.visible = False
trans.sa_session.flush()
-
+
# Return new track that corresponds to the original dataset.
output_name = None
for joda in original_job.output_datasets:
--- a/static/june_2007_style/blue/trackster.css Sun Mar 27 19:50:50 2011 -0400
+++ b/static/june_2007_style/blue/trackster.css Tue Apr 05 13:57:14 2011 -0400
@@ -22,7 +22,7 @@
.track{background:white;}
.track-header{text-align:left;padding:4px 0px;color:#666;}
.track-header .menubutton{margin-left:0px;}
-.track-content{overflow:hidden;text-align:center;border-bottom:1px solid #bbb;background:#eee url('/static/images/tracks/diag_bg.gif');min-height:16px;}
+.track-content{overflow:hidden;text-align:center;border-top:1px solid #eee;border-bottom:1px solid #eee;background:#eee url('/static/images/tracks/diag_bg.gif');min-height:16px;}
.label-track .track-content{background:white;}
.track-tile{background:white;}
.track-tile canvas{position:relative;z-index:100;border:solid white;border-width:2px 0px 0px 0px;}
@@ -38,11 +38,12 @@
.top-labeltrack{position:relative;border-bottom:solid #999 1px;}
.nav-labeltrack{border-top:solid #999 1px;border-bottom:solid #333 1px;}
input{font:10px verdana;}
-.values{padding-left:0.25em;}
-.dynamic-tool,.filters{width:400px;margin-left:0.25em;padding-bottom:0.5em;}
+.dynamic-tool,.filters{width:410px;margin-left:0.25em;padding-bottom:0.5em;}
.slider-row{margin-top:0.4em;margin-left:1em;}
.slider-label{float:left;font-weight:bold;}
.slider{float:right;width:200px;position:relative;}
.tool-name{font-size:110%;font-weight:bold;}
+.param-row{margin-top:0.2em;margin-left:1em;}
+.param-label{float:left;font-weight:bold;padding-top:0.2em;}
.child-track-icon{background:url('../images/fugue/arrow-000-small-bw.png') no-repeat;width:30px;cursor:move;}
.track-resize{background:white url('../images/visualization/draggable_vertical.png') no-repeat top center;position:absolute;right:3px;bottom:-4px;width:14px;height:7px;border:solid #999 1px;z-index:100;}
--- a/static/june_2007_style/trackster.css.tmpl Sun Mar 27 19:50:50 2011 -0400
+++ b/static/june_2007_style/trackster.css.tmpl Tue Apr 05 13:57:14 2011 -0400
@@ -146,8 +146,8 @@
.track-content {
overflow: hidden;
text-align: center;
-/* border-top: 1px solid #eee; */
- border-bottom: 1px solid #bbb;
+ border-top: 1px solid #eee;
+ border-bottom: 1px solid #eee;
background: #eee url('/static/images/tracks/diag_bg.gif');
min-height: 16px;
}
@@ -228,11 +228,8 @@
input {
font: 10px verdana;
}
-.values {
- padding-left: 0.25em;
-}
.dynamic-tool, .filters {
- width: 400px;
+ width: 410px;
margin-left: 0.25em;
padding-bottom:0.5em;
}
@@ -240,7 +237,7 @@
margin-top: 0.4em;
margin-left: 1em;
}
-.slider-label {
+.param-label, .slider-label {
float: left;
font-weight: bold;
}
@@ -253,6 +250,15 @@
font-size: 110%;
font-weight: bold;
}
+.param-row {
+ margin-top: 0.2em;
+ margin-left: 1em;
+}
+.param-label{
+ float: left;
+ font-weight: bold;
+ padding-top: 0.2em;
+}
.child-track-icon {
background:url('../images/fugue/arrow-000-small-bw.png') no-repeat;
width: 30px;
--- a/static/scripts/packed/trackster.js Sun Mar 27 19:50:50 2011 -0400
+++ b/static/scripts/packed/trackster.js Tue Apr 05 13:57:14 2011 -0400
@@ -1,1 +1,1 @@
-CanvasRenderingContext2D.prototype.dashedLine=function(c,j,b,h,f){if(f===undefined){f=4}var e=b-c;var d=h-j;var g=Math.floor(Math.sqrt(e*e+d*d)/f);var l=e/g;var k=d/g;var a;for(a=0;a<g;a++,c+=l,j+=k){if(a%2!==0){continue}this.fillRect(c,j,f,1)}};CanvasRenderingContext2D.prototype.drawDownwardEquilateralTriangle=function(b,a,e){var d=b-e/2,c=b+e/2,f=a-Math.sqrt(e*3/2);this.beginPath();this.moveTo(d,f);this.lineTo(c,f);this.lineTo(b,a);this.lineTo(d,f);this.strokeStyle=this.fillStyle;this.fill();this.stroke();this.closePath()};function sortable(a,b){a.bind("drag",{handle:b,relative:true},function(h,j){var g=$(this).parent();var f=g.children();var c;for(c=0;c<f.length;c++){if(j.offsetY<$(f.get(c)).position().top){break}}if(c===f.length){if(this!==f.get(c-1)){g.append(this)}}else{if(this!==f.get(c)){$(this).insertBefore(f.get(c))}}})}var NO_OVERLAP=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005;function compute_overlap(e,b){var g=e[0],f=e[1],d=b[0],c=b[1],a;if(g<d){if(f<d){a=NO_OVERLAP}else{if(f<=c){a=OVERLAP_START}else{a=CONTAINS}}}else{if(g>c){a=NO_OVERLAP}else{if(f<=c){a=CONTAINED_BY}else{a=OVERLAP_END}}}return a}function is_overlap(b,a){return(compute_overlap(b,a)!==NO_OVERLAP)}var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=1,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,ERROR_PADDING=10,LABEL_SPACING=2,PACK_SPACING=5,MIN_SQUISH_VIEW_WIDTH=12000,DEFAULT_FONT="9px Monaco, Lucida Console, monospace",DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=100,DEFAULT_DATA_QUERY_WAIT=5000,MAX_CHROMS_SELECTABLE=100,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset. ",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_CANNOT_RUN_TOOL="Tool cannot be rerun: ",DATA_LOADING="Loading data...",DATA_OK="Ready for display",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}var CONTEXT=DUMMY_CANVAS.getContext("2d");CONTEXT.font=DEFAULT_FONT;var CHAR_WIDTH_PX=CONTEXT.measureText("A").width,CHAR_HEIGHT_PX=9;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!==-1){this.move_key_to_end(b,a)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},move_key_to_end:function(b,a){this.key_ary.splice(a,1);this.key_ary.push(b)},clear:function(){this.obj_cache={};this.key_ary=[]},size:function(){return this.key_ary.length}});var DataManager=function(b,a,c){Cache.call(this,b);this.track=a;this.subset=(c!==undefined?c:true)};$.extend(DataManager.prototype,Cache.prototype,{load_data:function(d,a,f,h,b,e){var g={chrom:d,low:a,high:f,mode:h,resolution:b,dataset_id:this.track.dataset_id,hda_ldda:this.track.hda_ldda};$.extend(g,e);var c=this;return $.getJSON(this.track.data_url,g,function(j){c.set_data(a,f,h,j)})},get_data:function(j,k,c,h,b,f){var l=this.get(this.gen_key(k,c,h));if(l){return l}if(this.subset){var m,g,a,e,h,l;for(var d=0;d<this.key_ary.length;d++){m=this.key_ary[d];g=this.split_key(m);a=g[0];e=g[1];if(k>=a&&c<=e){l=this.obj_cache[m];if(l.dataset_type!=="summary_tree"&&l.extra_info!=="no_detail"){this.move_key_to_end(m,d);return l}}}}return this.load_data(j,k,c,h,b,f)},set_data:function(b,c,d,a){return this.set(this.gen_key(b,c,d),a)},gen_key:function(a,c,d){var b=a+"_"+c+"_"+d;return b},split_key:function(a){return a.split("_")}});var View=function(a,d,c,b,e){this.container=a;this.chrom=null;this.vis_id=c;this.dbkey=b;this.title=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init(e);this.reset()};$.extend(View.prototype,{init:function(d){var c=this.container,a=this;this.top_container=$("<div/>").addClass("top-container").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(c);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var b=function(f){if(f.type==="focusout"||(f.keyCode||f.which)===13||(f.keyCode||f.which)===27){if((f.keyCode||f.which)!==27){a.go_to($(this).val())}$(this).hide();$(this).val("");a.location_span.show();a.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",b).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").appendTo(this.nav_controls);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.val(a.chrom+":"+a.low+"-"+a.high);a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a id='zoom-out' />").click(function(){a.zoom_out();a.redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a id='zoom-in' />").click(function(){a.zoom_in();a.redraw()}).appendTo(this.nav_controls);this.load_chroms({low:0},d);this.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())});this.intro_div.show();this.content_div.bind("click",function(f){$(this).find("input").trigger("blur")});this.content_div.bind("dblclick",function(f){a.zoom_in(f.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(f,g){this.current_x=g.offsetX}).bind("drag",function(f,h){var j=h.offsetX-this.current_x;this.current_x=h.offsetX;var g=Math.round(j/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-g)});this.overview_close.bind("click",function(){for(var f=0,e=a.tracks.length;f<e;f++){a.tracks[f].is_overview=false}$(this).siblings().filter("canvas").remove();$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("draginit",function(f,g){if(f.clientX>a.viewport_container.width()-16){return false}}).bind("dragstart",function(f,g){g.original_low=a.low;g.current_height=f.clientY;g.current_x=g.offsetX}).bind("drag",function(h,k){var f=$(this);var l=k.offsetX-k.current_x;var g=f.scrollTop()-(h.clientY-k.current_height);f.scrollTop(g);k.current_height=h.clientY;k.current_x=k.offsetX;var j=Math.round(l/a.viewport_container.width()*(a.high-a.low));a.move_delta(j)}).bind("mousewheel",function(h,k,g,f){if(g){var j=Math.round(-g/a.viewport_container.width()*(a.high-a.low));a.move_delta(j)}});this.top_labeltrack.bind("dragstart",function(f,g){return $("<div />").css({height:a.content_div.height()+a.top_labeltrack.height()+a.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(k,l){$(l.proxy).css({left:Math.min(k.pageX,l.startX),width:Math.abs(k.pageX-l.startX)});var g=Math.min(k.pageX,l.startX)-a.container.offset().left,f=Math.max(k.pageX,l.startX)-a.container.offset().left,j=(a.high-a.low),h=a.viewport_container.width();a.update_location(Math.round(g/h*j)+a.low,Math.round(f/h*j)+a.low)}).bind("dragend",function(l,m){var g=Math.min(l.pageX,m.startX),f=Math.max(l.pageX,m.startX),j=(a.high-a.low),h=a.viewport_container.width(),k=a.low;a.low=Math.round(g/h*j)+k;a.high=Math.round(f/h*j)+k;$(m.proxy).remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window()});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+commatize(b))},load_chroms:function(b,c){b.num=MAX_CHROMS_SELECTABLE;$.extend(b,(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}));var a=this;$.ajax({url:chrom_url,data:b,dataType:"json",success:function(e){if(e.chrom_info.length===0){alert("Invalid chromosome: "+b.chrom);return}if(e.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=e.chrom_info;var h='<option value="">Select Chrom/Contig</option>';for(var g=0,d=a.chrom_data.length;g<d;g++){var f=a.chrom_data[g].chrom;h+='<option value="'+f+'">'+f+"</option>"}if(e.prev_chroms){h+='<option value="previous">Previous '+MAX_CHROMS_SELECTABLE+"</option>"}if(e.next_chroms){h+='<option value="next">Next '+MAX_CHROMS_SELECTABLE+"</option>"}a.chrom_select.html(h);if(c){c()}a.chrom_start_index=e.start_index},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}})},change_chrom:function(e,b,g){if(!e||e==="None"){return}var d=this;if(e==="previous"){d.load_chroms({low:this.chrom_start_index-MAX_CHROMS_SELECTABLE});return}if(e==="next"){d.load_chroms({low:this.chrom_start_index+MAX_CHROMS_SELECTABLE});return}var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){d.load_chroms({chrom:e},function(){d.change_chrom(e,b,g)});return}else{if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len-1;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()}},go_to:function(f){var k=this,a,d,b=f.split(":"),h=b[0],j=b[1];if(j!==undefined){try{var g=j.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}k.change_chrom(h,a,d)},move_fraction:function(c){var a=this;var b=a.high-a.low;this.move_delta(c*b)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);sortable(a.container_div,".draghandle");this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);this.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Tool=function(a,b){this.name=a;this.params=b};$.extend(Tool.prototype,{get_param_values_dict:function(){var b={};for(var a=0;a<this.params.length;a++){var c=this.params[a];b[c.name]=c.value}return b},get_param_values:function(){var b=[];for(var a=0;a<this.params.length;a++){b[a]=this.params[a].value}return b}});var NumberToolParameter=function(c,b,e,a,d){this.name=c;this.label=b;this.min=e;this.max=a;this.value=d};var get_tool_from_dict=function(f){if(obj_length(f)===0){return undefined}var b=f.name;var l=f.params;var c=Array();for(var e=0;e<l.length;e++){var g=l[e];var a=g.name,k=g.label,h=g.type,d=g.min,j=g.max,m=g.value;c[c.length]=new NumberToolParameter(a,k,d,j,m)}return new Tool(b,c)};var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.slider_min=Number.MAX_VALUE;this.slider_max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.slider_min){this.slider_min=b[this.index];a=true}if(b[this.index]>this.slider_max){this.slider_max=b[this.index];a=false}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.slider_min<b||this.slider_max>a){this.slider.slider("option","min",this.slider_min);this.slider.slider("option","max",this.slider_max);this.slider.slider("option","values",[this.slider_min,this.slider_max])}}});var get_filters_from_dict=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e==="int"||e==="float"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var TrackConfig=function(a){this.track=a.track;this.params=a.params;this.values={};if(a.saved_values){this.restore_values(a.saved_values)}this.onchange=a.onchange};$.extend(TrackConfig.prototype,{restore_values:function(a){var b=this;$.each(this.params,function(c,d){if(a[d.key]!==undefined){b.values[d.key]=a[d.key]}else{b.values[d.key]=d.default_value}})},build_form:function(){var b=this;var a=$("<div />");$.each(this.params,function(f,d){if(!d.hidden){var c="param_"+f;var l=$("<div class='form-row' />").appendTo(a);l.append($("<label />").attr("for",c).text(d.label+":"));if(d.type==="bool"){l.append($('<input type="checkbox" />').attr("id",c).attr("name",c).attr("checked",b.values[d.key]))}else{if(d.type==="color"){var h=b.values[d.key];var g=$("<input />").attr("id",c).attr("name",c).val(h);var j=$("<div class='tipsy tipsy-north' style='position: absolute;' />").hide();var e=$("<div style='background-color: black; padding: 10px;'></div>").appendTo(j);var k=$("<div/>").appendTo(e).farbtastic({width:100,height:100,callback:g,color:h});$("<div />").append(g).append(j).appendTo(l).bind("click",function(m){j.css({left:$(this).position().left+($(g).width()/2)-60,top:$(this).position().top+$(this.height)}).show();$(document).bind("click.color-picker",function(){j.hide();$(document).unbind("click.color-picker")});m.stopPropagation()})}else{l.append($("<input />").attr("id",c).attr("name",c).val(b.values[d.key]))}}}});return a},update_from_form:function(a){var c=this;var b=false;$.each(this.params,function(d,f){if(!f.hidden){var g="param_"+d;var e=a.find("#"+g).val();if(f.type==="float"){e=parseFloat(e)}else{if(f.type==="int"){e=parseInt(e)}else{if(f.type==="bool"){e=a.find("#"+g).is(":checked")}}}if(e!==c.values[f.key]){c.values[f.key]=e;b=true}}});if(b){this.onchange()}}});var Track=function(b,a,e,c,d){this.name=b;this.view=a;this.parent_element=e;this.data_url=(c?c:default_data_url);this.data_url_extra_params={};this.data_query_wait=(d?d:DEFAULT_DATA_QUERY_WAIT);this.dataset_check_url=converted_datasets_state_url;this.container_div=$("<div />").addClass("track").css("position","relative");if(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)};$.extend(Track.prototype,{init:function(){var a=this;a.enabled=false;a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_div.css("height","auto");a.container_div.removeClass("nodata error pending");if(!a.dataset_id){return}$.getJSON(converted_datasets_state_url,{hda_ldda:a.hda_ldda,dataset_id:a.dataset_id,chrom:a.view.chrom},function(b){if(!b||b==="error"||b.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(b.message){var d=a.view.tracks.indexOf(a);var c=$(" <a href='javascript:void(0);'></a>").text("View error").bind("click",function(){show_modal("Trackster Error","<pre>"+b.message+"</pre>",{Close:hide_modal})});a.content_div.append(c)}}else{if(b==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(b==="no data"||(b.data!==undefined&&(b.data===null||b.data.length===0))){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(b==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},a.data_query_wait)}else{if(b.status==="data"){if(b.valid_chroms){a.valid_chroms=b.valid_chroms;a.make_name_popup_menu()}a.content_div.text(DATA_OK);if(a.view.chrom){a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;$.when(a.predraw_init()).done(function(){a.draw()})}}}}}}})},predraw_init:function(){},update_name:function(a){this.old_name=this.name;this.name=a;this.name_div.text(this.name)},revert_name:function(){this.name=this.old_name;this.name_div.text(this.name)}});var TiledTrack=function(b,j,n){var c=this,o=c.view;this.filters=(b!==undefined?get_filters_from_dict(b):[]);this.filters_available=false;this.filters_visible=false;this.tool=(j!==undefined?get_tool_from_dict(j):undefined);this.parent_track=n;this.child_tracks=[];if(c.hidden){return}if(this.parent_track){this.header_div.find(".draghandle").removeClass("draghandle").addClass("child-track-icon").addClass("icon-button");this.parent_element.addClass("child-track");this.tool=undefined}this.filters_div=$("<div/>").addClass("filters").hide();this.header_div.after(this.filters_div);this.filters_div.bind("drag",function(q){q.stopPropagation()}).bind("dblclick",function(q){q.stopPropagation()});$.each(this.filters,function(t,w){var u=$("<div/>").addClass("slider-row").appendTo(c.filters_div);var v=$("<div/>").addClass("slider-label").appendTo(u);var s=$("<span/>").addClass("name").appendTo(v);s.text(w.name+" ");var r=$("<span/>").addClass("values").appendTo(v);var q=$("<div/>").addClass("slider").appendTo(u);w.control_element=$("<div/>").attr("id",w.name+"-filter-control").appendTo(q);w.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(y,z){var x=z.values;r.text("["+x[0]+"-"+x[1]+"]");w.low=x[0];w.high=x[1];c.draw(true,true)},change:function(x,y){w.control_element.slider("option","slide").call(w.control_element,x,y)}});w.slider=w.control_element;w.slider_label=r;$("<div style='clear: both;'/>").appendTo(u)});if(this.tool){this.dynamic_tool_div=$("<div/>").addClass("dynamic-tool").hide();this.header_div.after(this.dynamic_tool_div);this.dynamic_tool_div.bind("drag",function(q){q.stopPropagation()}).bind("click",function(q){q.stopPropagation()}).bind("dblclick",function(q){q.stopPropagation()});var m=$("<div class='tool-name'>").appendTo(this.dynamic_tool_div).text(this.tool.name);var l=this.tool.params;var c=this;$.each(this.tool.params,function(x,s){var v=$("<div>").addClass("slider-row").appendTo(c.dynamic_tool_div);var u=$("<div>").addClass("slider-label").appendTo(v);var z=$("<span class='param-name'>").text(s.label+" ").appendTo(u);var t=$("<span/>").text(s.value);var w=$("<span class='param-value'>").appendTo(u).append("[").append(t).append("]");var y=$("<div/>").addClass("slider").appendTo(v);var q=$("<div id='"+s.name+"-param-control'>").appendTo(y);var r=(s.max<=1?0.01:(s.max<=1000?1:5));q.slider({min:s.min,max:s.max,step:r,value:s.value,slide:function(A,C){var B=C.value;s.value=B;if(0<B&&B<1){B=parseFloat(B).toFixed(2)}t.text(B)},change:function(A,B){s.value=B.value}});w.click(function(){var C=t,B=C.text(),A=(s.max<=1?4:s.max.length);C.text("");$("<input type='text'/>").attr("size",A).attr("maxlength",A).attr("value",B).appendTo(C).focus().select().click(function(D){D.stopPropagation()}).blur(function(){$(this).remove();C.text(B)}).keyup(function(F){if(F.keyCode===27){$(this).trigger("blur")}else{if(F.keyCode===13){var D=$(this),E=parseFloat(D.val());if(isNaN(E)||E>s.max||E<s.min){alert("Parameter value must be in the range ["+s.min+"-"+s.max+"]");return $(this)}C.text(E);q.slider("value",E);s.value=E}}})});$("<div style='clear: both;'/>").appendTo(v)});var p=$("<div>").addClass("slider-row").appendTo(this.dynamic_tool_div);var k=$("<input type='submit'>").attr("value","Run").appendTo(p);var c=this;k.click(function(){c.run_tool()})}c.child_tracks_container=$("<div/>").addClass("child-tracks-container").hide();c.container_div.append(c.child_tracks_container);if(c.display_modes!==undefined){if(c.mode_div===undefined){c.mode_div=$("<div class='right-float menubutton popup' />").appendTo(c.header_div);var e=(c.track_config&&c.track_config.values.mode?c.track_config.values.mode:c.display_modes[0]);c.mode=e;c.mode_div.text(e);var d=function(q){c.mode_div.text(q);c.mode=q;c.track_config.values.mode=q;c.tile_cache.clear();c.draw()};var a={};for(var f=0,h=c.display_modes.length;f<h;f++){var g=c.display_modes[f];a[g]=function(q){return function(){d(q)}}(g)}make_popupmenu(c.mode_div,a)}else{c.mode_div.hide()}}this.make_name_popup_menu()};$.extend(TiledTrack.prototype,Track.prototype,{make_name_popup_menu:function(){var b=this;var a={};a["Edit configuration"]=function(){var h=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},f=function(){b.track_config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},g=function(j){if((j.keyCode||j.which)===27){h()}else{if((j.keyCode||j.which)===13){f()}}};$(window).bind("keypress.check_enter_esc",g);show_modal("Configure Track",b.track_config.build_form(),{Cancel:h,OK:f})};if(b.filters_available>0){var e=(b.filters_div.is(":visible")?"Hide filters":"Show filters");a[e]=function(){b.filters_visible=(b.filters_div.is(":visible"));b.filters_div.toggle();b.make_name_popup_menu()}}if(b.tool){var e=(b.dynamic_tool_div.is(":visible")?"Hide Tool":"Show Tool");a[e]=function(){if(!b.dynamic_tool_div.is(":visible")){b.update_name(b.name+b.tool_region_and_parameters_str())}else{menu_option_text="Show dynamic tool";b.revert_name()}b.dynamic_tool_div.toggle();b.make_name_popup_menu()}}if(b.valid_chroms){a["List chrom/contigs with data"]=function(){show_modal("Chrom/contigs with data","<p>"+b.valid_chroms.join("<br/>")+"</p>",{Close:function(){hide_modal()}})}}var c=view;var d=function(){$("#no-tracks").show()};if(this.parent_track){c=this.parent_track;d=function(){}}a.Remove=function(){c.remove_track(b);if(c.num_tracks===0){d()}};make_popupmenu(b.name_div,a)},draw:function(a,d){var s=this.view.low,g=this.view.high,j=g-s,l=this.view.container.width(),m=this.view.resolution;var e=$("<div style='position: relative;'></div>"),f=l/j;if(!d){this.content_div.children().remove()}this.content_div.append(e);this.max_height=0;var o=Math.floor(s/m/DENSITY);var c={};while((o*DENSITY*m)<g){var r=l+"_"+f+"_"+o;var h=this.tile_cache.get(r);var p=o*DENSITY*this.view.resolution;var b=p+DENSITY*this.view.resolution;if(!a&&h){this.show_tile(h,e,p,f)}else{this.delayed_draw(a,r,p,b,o,m,e,f,c)}o+=1}if(d){var k=this;var q=setInterval(function(){if(obj_length(c)===0){var v=k.content_div.children();var u=false;for(var w=v.length-1,t=0;w>=t;w--){var x=$(v[w]);if(u){x.remove()}else{if(x.children().length!==0){u=true}}}clearInterval(q)}},50)}for(var n=0;n<this.child_tracks.length;n++){this.child_tracks[n].draw(a,d)}},delayed_draw:function(b,j,g,l,c,e,k,m,f){var d=this;var h=function(u,n,p,o,s,t,q){returned_tile=d.draw_tile(n,p,o,s,t,q);var r=$("<div class='track-tile'>").prepend(returned_tile);tile_element=r;d.tile_cache.set(j,tile_element);d.show_tile(tile_element,s,g,t);delete f[u]};var a=setTimeout(function(){if(g<=d.view.high&&l>=d.view.low){var n=(b?undefined:d.tile_cache.get(j));if(n){d.show_tile(n,k,g,m);delete f[a]}else{$.when(d.data_cache.get_data(view.chrom,g,l,d.mode,e,d.data_url_extra_params)).then(function(){var o=d.data_cache.get_data(view.chrom,g,l,d.mode,e,d.data_url_extra_params);if(view.reference_track&&m>CHAR_WIDTH_PX){$.when(view.reference_track.data_cache.get_data(view.chrom,g,l,d.mode,e,view.reference_track.data_url_extra_params)).then(function(){var p=view.reference_track.data_cache.get_data(view.chrom,g,l,d.mode,e,view.reference_track.data_url_extra_params);h(a,o,e,c,k,m,p)})}else{h(a,o,e,c,k,m)}})}}},50);f[a]=true},show_tile:function(h,j,e,k){var a=this;var c=this.view.high-this.view.low,b=(e-this.view.low)*k;if(this.left_offset){b-=this.left_offset}h.css({position:"absolute",top:0,left:b,height:""});j.append(h);a.max_height=Math.max(a.max_height,h.height());a.content_div.css("height",a.max_height+"px");j.children().css("height",a.max_height+"px");if(a.hidden){return}for(var g=0;g<a.filters.length;g++){a.filters[g].update_ui_elt()}var d=false;if(a.example_feature){for(var g=0;g<a.filters.length;g++){if(a.filters[g].applies_to(a.example_feature)){d=true;break}}}if(a.filters_available!==d){a.filters_available=d;if(!a.filters_available){a.filters_div.hide()}a.make_name_popup_menu()}},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")},run_tool:function(){var b={dataset_id:this.original_dataset_id,chrom:this.view.chrom,low:this.view.low,high:this.view.high,tool_id:this.tool.name};$.extend(b,this.tool.get_param_values_dict());var d=this,c=b.tool_id+d.tool_region_and_parameters_str(b.chrom,b.low,b.high),e;if(d.track_type==="FeatureTrack"){e=new ToolDataFeatureTrack(c,view,d.hda_ldda,undefined,{},{},d)}this.add_track(e);e.content_div.text("Starting job.");view.has_changes=true;var a=function(){$.getJSON(run_tool_url,b,function(f){if(f==="no converter"){e.container_div.addClass("error");e.content_div.text(DATA_NOCONVERTER)}else{if(f.error){e.container_div.addClass("error");e.content_div.text(DATA_CANNOT_RUN_TOOL+f.message)}else{if(f==="pending"){e.container_div.addClass("pending");e.content_div.text("Converting input data so that it can be easily reused.");setTimeout(a,2000)}else{e.dataset_id=f.dataset_id;e.content_div.text("Running job.");e.init()}}}})};a()},tool_region_and_parameters_str:function(c,a,d){var b=this,e=(c!==undefined&&a!==undefined&&d!==undefined?c+":"+a+"-"+d:"all");return" - region=["+e+"], parameters=["+b.tool.get_param_values().join(", ")+"]"},add_track:function(a){a.track_id=this.track_id+"_"+this.child_tracks.length;a.container_div.attr("id","track_"+a.track_id);this.child_tracks_container.append(a.container_div);sortable(a.container_div,".child-track-icon");if(!$(this.child_tracks_container).is(":visible")){this.child_tracks_container.show()}this.child_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()})}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.view.container.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);a.reference_track=this;this.left_offset=200;this.height_px=12;this.font=DEFAULT_FONT;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url;this.data_url_extra_params={dbkey:a.dbkey};this.data_cache=new DataManager(CACHED_DATA,this,false);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{draw_tile:function(m,g,b,j,n){var f=this,d=DENSITY*g;if(n>CHAR_WIDTH_PX){if(m===null){f.content_div.css("height","0px");return}var e=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(e)}e=$(e);var l=e.get(0).getContext("2d");e.get(0).width=Math.ceil(d*n+f.left_offset);e.get(0).height=f.height_px;l.font=DEFAULT_FONT;l.textAlign="center";for(var h=0,k=m.length;h<k;h++){var a=Math.round(h*n);l.fillText(m[h],a+f.left_offset,10)}return e}this.content_div.css("height","0px")}});var LineTrack=function(e,c,f,a,d){var b=this;this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,e,c,c.viewport_container);TiledTrack.call(this);this.min_height_px=16;this.max_height_px=400;this.height_px=80;this.hda_ldda=f;this.dataset_id=a;this.original_dataset_id=a;this.data_cache=new DataManager(CACHED_DATA,this);this.tile_cache=new Cache(CACHED_TILES_LINE);this.track_config=new TrackConfig({track:this,params:[{key:"color",label:"Color",type:"color",default_value:"black"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.height_px,hidden:true}],saved_values:d,onchange:function(){b.vertical_range=b.prefs.max_value-b.prefs.min_value;$("#linetrack_"+b.track_id+"_minval").text(b.prefs.min_value);$("#linetrack_"+b.track_id+"_maxval").text(b.prefs.max_value);b.tile_cache.clear();b.draw()}});this.prefs=this.track_config.values;this.height_px=this.track_config.values.height;this.vertical_range=this.track_config.values.max_value-this.track_config.values.min_value;(function(g){var k=false;var j=false;var h=$("<div class='track-resize'>");$(g.container_div).hover(function(){k=true;h.show()},function(){k=false;if(!j){h.hide()}});h.hide().bind("dragstart",function(l,m){j=true;m.original_height=$(g.content_div).height()}).bind("drag",function(m,n){var l=Math.min(Math.max(n.original_height+n.deltaY,g.min_height_px),g.max_height_px);$(g.content_div).css("height",l);g.height_px=l;g.draw(true)}).bind("dragend",function(l,m){g.tile_cache.clear();j=false;if(!k){h.hide()}g.track_config.values.height=g.height_px}).appendTo(g.container_div)})(this)};$.extend(LineTrack.prototype,TiledTrack.prototype,{predraw_init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;return $.getJSON(a.data_url,{stats:true,chrom:a.view.chrom,low:null,high:null,hda_ldda:a.hda_ldda,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"24px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",bottom:"2px",left:"10px"});f.prependTo(a.container_div)})},draw_tile:function(j,q,t,c,e){if(this.vertical_range===undefined){return}var o=this,u=t*DENSITY*q,a=DENSITY*q,B=q+"_"+t,v={hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,resolution:this.view.resolution};var b=document.createElement("canvas"),z=j.data;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(b)}b=$(b);b.get(0).width=Math.ceil(a*e);b.get(0).height=o.height_px;var p=b.get(0).getContext("2d"),k=false,l=o.prefs.min_value,g=o.prefs.max_value,n=o.vertical_range,w=o.total_frequency,d=o.height_px,m=o.mode;var A=Math.round(d+l/n*d);p.beginPath();p.moveTo(0,A);p.lineTo(a*e,A);p.fillStyle="#aaa";p.stroke();p.beginPath();p.fillStyle=o.prefs.color;var x,h,f;if(z.length>1){f=Math.ceil((z[1][0]-z[0][0])*e)}else{f=10}for(var r=0,s=z.length;r<s;r++){x=Math.round((z[r][0]-u)*e);h=z[r][1];if(h===null){if(k&&m==="Filled"){p.lineTo(x,d)}k=false;continue}if(h<l){h=l}else{if(h>g){h=g}}if(m==="Histogram"){h=Math.round(h/n*d);p.fillRect(x,A,f,-h)}else{if(m==="Intensity"){h=255-Math.floor((h-l)/n*255);p.fillStyle="rgb("+h+","+h+","+h+")";p.fillRect(x,0,f,d)}else{h=Math.round(d-(h-l)/n*d);if(k){p.lineTo(x,h)}else{k=true;if(m==="Filled"){p.moveTo(x,d);p.lineTo(x,h)}else{p.moveTo(x,h)}}}}}if(m==="Filled"){if(k){p.lineTo(x,A);p.lineTo(0,A)}p.fill()}else{p.stroke()}return b}});var FeatureTrack=function(a,f,e,j,h,c,d,g){var b=this;this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];this.track_config=new TrackConfig({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:h,onchange:function(){b.tile_cache.clear();b.draw()}});this.prefs=this.track_config.values;Track.call(this,a,f,f.viewport_container);TiledTrack.call(this,c,d,g);this.height_px=0;this.container_div.addClass("feature-track");this.hda_ldda=e;this.dataset_id=j;this.original_dataset_id=j;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.default_font=DEFAULT_FONT;this.inc_slots={};this.start_end_dct={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new DataManager(20,this);this.left_offset=200};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{incremental_slots:function(a,h,p){var q=this.inc_slots[a];if(!q||(q.mode!==p)){q={};q.w_scale=a;q.mode=p;this.inc_slots[a]=q;this.start_end_dct[a]={}}var l=q.w_scale,w=[],x=[],j=0,n=this.view.max_low;for(var u=0,v=h.length;u<v;u++){var g=h[u],k=g[0];if(q[k]!==undefined){j=Math.max(j,q[k]);x.push(q[k])}else{w.push(u)}}var d=this.start_end_dct[a];var m=function(D,E){for(var C=0;C<=MAX_FEATURE_DEPTH;C++){var A=false,F=d[C];if(F!==undefined){for(var z=0,B=F.length;z<B;z++){var y=F[z];if(E>y[0]&&D<y[1]){A=true;break}}}if(!A){return C}}return -1};for(var u=0,v=w.length;u<v;u++){var g=h[w[u]],k=g[0],s=g[1],b=g[2],o=g[3],c=Math.floor((s-n)*l),f=Math.ceil((b-n)*l),t=CONTEXT.measureText(o).width,e;if(o!==undefined&&p==="Pack"){t+=(LABEL_SPACING+PACK_SPACING);if(c-t>=0){c-=t;e="left"}else{f+=t;e="right"}}var r=m(c,f);if(r>=0){if(d[r]===undefined){d[r]=[]}d[r].push([c,f]);q[k]=r;j=Math.max(j,r)}else{}}return j+1},draw_summary_tree:function(b,o,n,l,r,j,f,e){var c=j+LABEL_SPACING+CHAR_HEIGHT_PX;delta_x_px=Math.ceil(n*r);var h=$("<div />").addClass("yaxislabel");h.text(l);h.css({position:"absolute",top:"22px",left:"10px"});h.prependTo(this.container_div);var q=b.get(0).getContext("2d");for(var d=0,g=o.length;d<g;d++){var m=Math.floor((o[d][0]-f)*r);var k=o[d][1];if(!k){continue}var p=k/l*j;q.fillStyle="black";q.fillRect(m+e,c-p,delta_x_px,p);var a=4;if(this.prefs.show_counts&&(q.measureText(k).width+a)<delta_x_px){q.fillStyle="#666";q.textAlign="center";q.fillText(k,m+e+(delta_x_px/2),10)}}},draw_element:function(p,f,g,x,j,r,I,M,N,a,A){var u=x[0],K=x[1],C=x[2]-1,s=x[3],D=Math.floor(Math.max(0,(K-r)*M)),q=Math.ceil(Math.min(a,Math.max(0,(C-r)*M))),B=ERROR_PADDING+(g==="Dense"?0:(0+j))*N,o,G,t=null,O=null,d=this.prefs.block_color,F=this.prefs.label_color;if(g==="Dense"){p.fillStyle=d;p.fillRect(D+A,B,q-D,DENSE_FEATURE_HEIGHT)}else{if(g==="no_detail"){p.fillStyle=d;p.fillRect(D+A,B+5,q-D,DENSE_FEATURE_HEIGHT)}else{var n=x[5],z=x[6],E=x[7],e=x[8];if(z&&E){t=Math.floor(Math.max(0,(z-r)*M));O=Math.ceil(Math.min(a,Math.max(0,(E-r)*M)))}var L,v;if(g==="Squish"){L=1;v=SQUISH_FEATURE_HEIGHT}else{L=5;v=PACK_FEATURE_HEIGHT}if(!e){if(x.strand){if(x.strand==="+"){p.fillStyle=RIGHT_STRAND_INV}else{if(x.strand==="-"){p.fillStyle=LEFT_STRAND_INV}}}else{p.fillStyle=d}p.fillRect(D+A,B,q-D,v)}else{var m,w;if(g==="Squish"){p.fillStyle=CONNECTOR_COLOR;m=B+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;w=1}else{if(n){var m=B;var w=v;if(n==="+"){p.fillStyle=RIGHT_STRAND}else{if(n==="-"){p.fillStyle=LEFT_STRAND}}}else{p.fillStyle=CONNECTOR_COLOR;m+=(SQUISH_FEATURE_HEIGHT/2)+1;w=1}}p.fillRect(D+A,m,q-D,w);for(var J=0,c=e.length;J<c;J++){var h=e[J],b=Math.floor(Math.max(0,(h[0]-r)*M)),y=Math.ceil(Math.min(a,Math.max((h[1]-1-r)*M)));if(b>y){continue}p.fillStyle=d;p.fillRect(b+A,B+(v-L)/2+1,y-b,L);if(t!==undefined&&!(b>O||y<t)){var H=Math.max(b,t),l=Math.min(y,O);p.fillRect(H+A,B+1,l-H,v)}}}if(g==="Pack"&&K>r){p.fillStyle=F;if(f===0&&D-p.measureText(s).width<0){p.textAlign="left";p.fillText(s,q+A+LABEL_SPACING,B+8)}else{p.textAlign="right";p.fillText(s,D+A-LABEL_SPACING,B+8)}p.fillStyle=d}}}},get_y_scale:function(b){var a;if(b==="summary_tree"){}if(b==="Dense"){a=DENSE_TRACK_HEIGHT}else{if(b==="no_detail"){a=NO_DETAIL_TRACK_HEIGHT}else{if(b==="Squish"){a=SQUISH_TRACK_HEIGHT}else{a=PACK_TRACK_HEIGHT}}}return a},draw_tile:function(o,x,C,k,m,d){var t=this;var E=C*DENSITY*x,a=(C+1)*DENSITY*x,q=a-E,F={hda_ldda:t.hda_ldda,dataset_id:t.dataset_id,resolution:this.view.resolution,mode:this.mode};var v=Math.ceil(q*m),s=this.mode,H=25,g=this.left_offset,p,h;var c=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(c)}c=$(c);if(s==="Auto"){if(o.dataset_type==="summary_tree"){s=o.dataset_type}else{if(o.extra_info==="no_detail"){s="no_detail"}else{var G=o.data;if((G.length&&G.length<4)||(this.view.high-this.view.low>MIN_SQUISH_VIEW_WIDTH)){s="Squish"}else{s="Pack"}}}}var y=this.get_y_scale(s);if(s==="summary_tree"){h=this.summary_draw_height}if(s==="Dense"){h=H}else{if(s==="no_detail"||s==="Squish"||s==="Pack"){h=this.incremental_slots(m,o.data,s)*y+H;p=this.inc_slots[m]}}c.get(0).width=v+g;c.get(0).height=h;if(o.dataset_type==="summary_tree"){c.get(0).height+=LABEL_SPACING+CHAR_HEIGHT_PX}k.parent().css("height",Math.max(this.height_px,h)+"px");var w=c.get(0).getContext("2d");w.fillStyle=this.prefs.block_color;w.font=this.default_font;w.textAlign="right";this.container_div.find(".yaxislabel").remove();if(s==="summary_tree"){this.draw_summary_tree(c,o.data,o.delta,o.max,m,h,E,g);return c}if(o.message){c.css({"border-top":"1px solid red"});w.fillStyle="red";w.textAlign="left";var r=w.textBaseline;w.textBaseline="top";w.fillText(o.message,g,0);w.textBaseline=r;if(!o.data){return c}}this.example_feature=(o.data.length?o.data[0]:undefined);var G=o.data;for(var z=0,B=G.length;z<B;z++){var j=G[z],l=j[0],u=j[1],b=j[2],e=(p&&p[l]!==undefined?p[l]:null);var A=false;var n;for(var D=0;D<this.filters.length;D++){n=this.filters[D];n.update_attrs(j);if(!n.keep(j)){A=true;break}}if(A){continue}if(is_overlap([u,b],[E,a])&&(s=="Dense"||e!==null)){this.draw_element(w,C,s,j,e,E,a,m,y,v,g,d)}}return c}});var VcfTrack=function(d,b,f,a,c,e){FeatureTrack.call(this,d,b,f,a,c,e);this.track_type="VcfTrack"};$.extend(VcfTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{draw_element:function(u,p,j,e,x,c,m,v,s){var j=data[i],l=j[0],t=j[1],d=j[2]-1,o=j[3],g=Math.floor(Math.max(0,(t-x)*m)),k=Math.ceil(Math.min(s,Math.max(0,(d-x)*m))),f=ERROR_PADDING+(p==="Dense"?0:(0+e))*v,a,y,b=null,n=null;if(no_label){u.fillStyle=block_color;u.fillRect(g+left_offset,f+5,k-g,1)}else{var w=j[4],r=j[5],h=j[6];a=9;y=1;u.fillRect(g+left_offset,f,k-g,a);if(p!=="Dense"&&o!==undefined&&t>x){u.fillStyle=label_color;if(tile_index===0&&g-u.measureText(o).width<0){u.textAlign="left";u.fillText(o,k+2+left_offset,f+8)}else{u.textAlign="right";u.fillText(o,g-2+left_offset,f+8)}u.fillStyle=block_color}var q=w+" / "+r;if(t>x&&u.measureText(q).width<(k-g)){u.fillStyle="white";u.textAlign="center";u.fillText(q,left_offset+g+(k-g)/2,f+8);u.fillStyle=block_color}}}});var ReadTrack=function(d,b,f,a,c,e){FeatureTrack.call(this,d,b,f,a,c,e);this.track_config=new TrackConfig({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:c,onchange:function(){this.track.tile_cache.clear();this.track.draw()}});this.prefs=this.track_config.values;this.track_type="ReadTrack";this.make_name_popup_menu()};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{get_y_scale:function(b){var a;if(b==="summary_tree"){}if(b==="Dense"){a=DENSE_TRACK_HEIGHT}else{if(b==="Squish"){a=SQUISH_TRACK_HEIGHT}else{a=PACK_TRACK_HEIGHT;if(this.track_config.values.show_insertions){a*=2}}}return a},draw_read:function(m,d,J,n,D,G,e,o,y,a){m.textAlign="center";var l=this,u=[n,D],C=0,z=0,f=0;var r=[];if((d==="Pack"||this.mode==="Auto")&&o!==undefined&&J>CHAR_WIDTH_PX){f=Math.round(J/2)}if(!e){e=[[0,o.length]]}for(var h=0,k=e.length;h<k;h++){var b=e[h],g="MIDNSHP=X"[b[0]],v=b[1];if(g==="H"||g==="S"){C-=v}var x=G+C,B=Math.floor(Math.max(0,(x-n)*J)),E=Math.floor(Math.max(0,(x+v-n)*J));switch(g){case"H":break;case"S":case"M":case"=":var p=compute_overlap([x,x+v],u);if(p!==NO_OVERLAP){var q=o.slice(z,z+v);if(f>0){m.fillStyle=this.prefs.block_color;m.fillRect(B+this.left_offset-f,y+1,E-B,9);m.fillStyle=CONNECTOR_COLOR;for(var I=0,j=q.length;I<j;I++){if(this.track_config.values.show_differences&&a){var s=a[x-n+I];if(!s||s.toLowerCase()===q[I].toLowerCase()){continue}}if(x+I>=n&&x+I<=D){var A=Math.floor(Math.max(0,(x+I-n)*J));m.fillText(q[I],A+this.left_offset,y+9)}}}else{m.fillStyle=this.prefs.block_color;m.fillRect(B+this.left_offset,y+(this.mode!=="Dense"?4:5),E-B,(d!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}z+=v;C+=v;break;case"N":m.fillStyle=CONNECTOR_COLOR;m.fillRect(B+this.left_offset-f,y+5,E-B,1);C+=v;break;case"D":m.fillStyle="red";m.fillRect(B+this.left_offset-f,y+4,E-B,3);C+=v;break;case"P":break;case"I":var p=compute_overlap([x,x+v],u),K=this.left_offset+B-f;if(p!==NO_OVERLAP){var q=o.slice(z,z+v);if(this.track_config.values.show_insertions){var w=this.left_offset+B-(E-B)/2;if((d==="Pack"||this.mode==="Auto")&&o!==undefined&&J>CHAR_WIDTH_PX){m.fillStyle="yellow";m.fillRect(w-f,y-9,E-B,9);r[r.length]={type:"triangle",data:[K,y+4,5]};m.fillStyle=CONNECTOR_COLOR;switch(p){case (OVERLAP_START):q=q.slice(n-x);break;case (OVERLAP_END):q=q.slice(0,x-D);break;case (CONTAINED_BY):break;case (CONTAINS):q=q.slice(n-x,x-D);break}for(var I=0,j=q.length;I<j;I++){var A=Math.floor(Math.max(0,(x+I-n)*J));m.fillText(q[I],A+this.left_offset-(E-B)/2,y)}}else{m.fillStyle="yellow";m.fillRect(w,y+(this.mode!=="Dense"?2:5),E-B,(d!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((d==="Pack"||this.mode==="Auto")&&o!==undefined&&J>CHAR_WIDTH_PX){r[r.length]={type:"text",data:[q.length,K,y+9]}}else{}}}z+=v;break;case"X":z+=v;break}}m.fillStyle="yellow";var t,L,H;for(var F=0;F<r.length;F++){t=r[F];L=t.type;H=t.data;if(L==="text"){m.font="bold "+DEFAULT_FONT;m.fillText(H[0],H[1],H[2]);m.font=DEFAULT_FONT}else{if(L=="triangle"){m.drawDownwardEquilateralTriangle(H[0],H[1],H[2])}}}},draw_element:function(w,y,r,k,e,A,b,n,x,u,f,c){var m=k[0],v=k[1],d=k[2],o=k[3],h=Math.floor(Math.max(0,(v-A)*n)),j=Math.ceil(Math.min(u,Math.max(0,(d-A)*n))),g=(r==="Dense"?1:(1+e))*x,z=this.prefs.block_color,l=this.prefs.label_color;t=0;w.fillStyle=z;if(k[5] instanceof Array){var s=Math.floor(Math.max(0,(k[4][0]-A)*n)),q=Math.ceil(Math.min(u,Math.max(0,(k[4][1]-A)*n))),p=Math.floor(Math.max(0,(k[5][0]-A)*n)),a=Math.ceil(Math.min(u,Math.max(0,(k[5][1]-A)*n)));if(k[4][1]>=A&&k[4][0]<=b&&k[4][2]){this.draw_read(w,r,n,A,b,k[4][0],k[4][2],k[4][3],g,c)}if(k[5][1]>=A&&k[5][0]<=b&&k[5][2]){this.draw_read(w,r,n,A,b,k[5][0],k[5][2],k[5][3],g,c)}if(p>q){w.fillStyle=CONNECTOR_COLOR;w.dashedLine(q+f,g+5,f+p,g+5)}}else{w.fillStyle=z;this.draw_read(w,r,n,A,b,v,k[4],k[5],g,c)}if(r==="Pack"&&v>A){w.fillStyle=this.prefs.label_color;if((r==="Pack"||this.mode==="Auto")&&n>CHAR_WIDTH_PX){var t=Math.round(n/2)}if(y===0&&h-w.measureText(o).width<0){w.textAlign="left";w.fillText(o,j+f+LABEL_SPACING-t,g+8)}else{w.textAlign="right";w.fillText(o,h+f-LABEL_SPACING-t,g+8)}w.fillStyle=z}}});var ToolDataFeatureTrack=function(e,c,g,a,d,f,b){FeatureTrack.call(this,e,c,g,a,d,f,{},b);this.track_type="ToolDataFeatureTrack";this.data_url=raw_data_url;this.data_query_wait=1000;this.dataset_check_url=dataset_state_url};$.extend(ToolDataFeatureTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{predraw_init:function(){var b=this;var a=function(){if(b.data_cache.size()===0){setTimeout(a,300)}else{b.data_url=default_data_url;b.data_query_wait=DEFAULT_DATA_QUERY_WAIT;b.dataset_state_url=converted_datasets_state_url;$.getJSON(b.dataset_state_url,{dataset_id:b.dataset_id,hda_ldda:b.hda_ldda},function(c){})}};a()}});
\ No newline at end of file
+var extend=function(){var c=arguments[0];for(var b=1;b<arguments.length;b++){var a=arguments[b];for(key in a){c[key]=a[key]}}};var trackster_module=function(f,Q){var o=f("slotting"),G=f("painters");var V=function(W,X){this.document=W;this.default_font=X!==undefined?X:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};extend(V.prototype,{load_pattern:function(W,aa){var X=this.patterns,Y=this.dummy_context,Z=new Image();Z.src=image_path+aa;Z.onload=function(){X[W]=Y.createPattern(Z,"repeat")}},get_pattern:function(W){return this.patterns[W]},new_canvas:function(){var W=this.document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(W)}W.manager=this;return W}});var B=function(W,X){W.bind("drag",{handle:X,relative:true},function(ab,ac){var aa=$(this).parent();var Z=aa.children();var Y;for(Y=0;Y<Z.length;Y++){if(ac.offsetY<$(Z.get(Y)).position().top){break}}if(Y===Z.length){if(this!==Z.get(Y-1)){aa.append(this)}}else{if(this!==Z.get(Y)){$(this).insertBefore(Z.get(Y))}}})};var h=function(Y,W){var X=W-Y;return(X<=2?0.01:(X<=100?1:(X<=1000?5:10)))};var C=9,z=10,L=C+2,w=100,D=12000,J=200,r=10,F=5000,s=100,m="There was an error in indexing this dataset. ",E="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",A="No data for this chrom/contig.",p="Currently indexing... please wait",u="Tool cannot be rerun: ",a="Loading data...",R="Ready for display",d=10,q=5,y=5;function t(W){return Math.round(W*1000)/1000}var c=function(W){this.num_elements=W;this.clear()};extend(c.prototype,{get:function(X){var W=this.key_ary.indexOf(X);if(W!==-1){this.move_key_to_end(X,W)}return this.obj_cache[X]},set:function(X,Y){if(!this.obj_cache[X]){if(this.key_ary.length>=this.num_elements){var W=this.key_ary.shift();delete this.obj_cache[W]}this.key_ary.push(X)}this.obj_cache[X]=Y;return Y},move_key_to_end:function(X,W){this.key_ary.splice(W,1);this.key_ary.push(X)},clear:function(){this.obj_cache={};this.key_ary=[]},size:function(){return this.key_ary.length}});var K=function(X,W,Y){c.call(this,X);this.track=W;this.subset=(Y!==undefined?Y:true)};extend(K.prototype,c.prototype,{load_data:function(ad,ae,Z,ac,W,ab){var Y={chrom:ad,low:ae,high:Z,mode:ac,resolution:W,dataset_id:this.track.dataset_id,hda_ldda:this.track.hda_ldda};$.extend(Y,ab);var af=[];for(var aa=0;aa<this.track.filters.length;aa++){af[af.length]=this.track.filters[aa].name}Y.filter_cols=JSON.stringify(af);var X=this;return $.getJSON(this.track.data_url,Y,function(ag){X.set_data(ae,Z,ac,ag)})},get_data:function(Y,W,ab,ac,X,aa){var Z=this.get(this.gen_key(W,ab,ac));if(Z){return Z}Z=this.load_data(Y,W,ab,ac,X,aa);this.set_data(W,ab,ac,Z);return Z},set_data:function(X,Y,Z,W){return this.set(this.gen_key(X,Y,Z),W)},gen_key:function(W,Y,Z){var X=W+"_"+Y+"_"+Z;return X},split_key:function(W){return W.split("_")}});var U=function(W,Z,Y,X,aa){this.container=W;this.chrom=null;this.vis_id=Y;this.dbkey=X;this.title=Z;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init(aa);this.canvas_manager=new V(W.get(0).ownerDocument);this.reset()};extend(U.prototype,{init:function(Z){var Y=this.container,W=this;this.top_container=$("<div/>").addClass("top-container").appendTo(Y);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(Y);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(Y);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var X=function(aa){if(aa.type==="focusout"||(aa.keyCode||aa.which)===13||(aa.keyCode||aa.which)===27){if((aa.keyCode||aa.which)!==27){W.go_to($(this).val())}$(this).hide();$(this).val("");W.location_span.show();W.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",X).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").appendTo(this.nav_controls);this.location_span.bind("click",function(){W.location_span.hide();W.chrom_select.hide();W.nav_input.val(W.chrom+":"+W.low+"-"+W.high);W.nav_input.css("display","inline-block");W.nav_input.select();W.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a id='zoom-out' />").click(function(){W.zoom_out();W.redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a id='zoom-in' />").click(function(){W.zoom_in();W.redraw()}).appendTo(this.nav_controls);this.load_chroms({low:0},Z);this.chrom_select.bind("change",function(){W.change_chrom(W.chrom_select.val())});this.intro_div.show();this.content_div.bind("click",function(aa){$(this).find("input").trigger("blur")});this.content_div.bind("dblclick",function(aa){W.zoom_in(aa.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(aa,ab){this.current_x=ab.offsetX}).bind("drag",function(aa,ac){var ad=ac.offsetX-this.current_x;this.current_x=ac.offsetX;var ab=Math.round(ad/W.viewport_container.width()*(W.max_high-W.max_low));W.move_delta(-ab)});this.overview_close.bind("click",function(){for(var ab=0,aa=W.tracks.length;ab<aa;ab++){W.tracks[ab].is_overview=false}$(this).siblings().filter("canvas").remove();$(this).parent().css("height",W.overview_box.height());W.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("draginit",function(aa,ab){if(aa.clientX>W.viewport_container.width()-16){return false}}).bind("dragstart",function(aa,ab){ab.original_low=W.low;ab.current_height=aa.clientY;ab.current_x=ab.offsetX}).bind("drag",function(ac,ae){var aa=$(this);var af=ae.offsetX-ae.current_x;var ab=aa.scrollTop()-(ac.clientY-ae.current_height);aa.scrollTop(ab);ae.current_height=ac.clientY;ae.current_x=ae.offsetX;var ad=Math.round(af/W.viewport_container.width()*(W.high-W.low));W.move_delta(ad)}).bind("mousewheel",function(ac,ae,ab,aa){if(ab){var ad=Math.round(-ab/W.viewport_container.width()*(W.high-W.low));W.move_delta(ad)}});this.top_labeltrack.bind("dragstart",function(aa,ab){return $("<div />").css({height:W.content_div.height()+W.top_labeltrack.height()+W.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ae,af){$(af.proxy).css({left:Math.min(ae.pageX,af.startX),width:Math.abs(ae.pageX-af.startX)});var ab=Math.min(ae.pageX,af.startX)-W.container.offset().left,aa=Math.max(ae.pageX,af.startX)-W.container.offset().left,ad=(W.high-W.low),ac=W.viewport_container.width();W.update_location(Math.round(ab/ac*ad)+W.low,Math.round(aa/ac*ad)+W.low)}).bind("dragend",function(af,ag){var ab=Math.min(af.pageX,ag.startX),aa=Math.max(af.pageX,ag.startX),ad=(W.high-W.low),ac=W.viewport_container.width(),ae=W.low;W.low=Math.round(ab/ac*ad)+ae;W.high=Math.round(aa/ac*ad)+ae;$(ag.proxy).remove();W.redraw()});this.add_label_track(new T(this,this.top_labeltrack));this.add_label_track(new T(this,this.nav_labeltrack));$(window).bind("resize",function(){W.resize_window()});$(document).bind("redraw",function(){W.redraw()});this.reset();$(window).trigger("resize")},update_location:function(W,X){this.location_span.text(commatize(W)+" - "+commatize(X));this.nav_input.val(this.chrom+":"+commatize(W)+"-"+commatize(X))},load_chroms:function(X,Y){X.num=s;$.extend(X,(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}));var W=this;$.ajax({url:chrom_url,data:X,dataType:"json",success:function(aa){if(aa.chrom_info.length===0){alert("Invalid chromosome: "+X.chrom);return}if(aa.reference){W.add_label_track(new x(W))}W.chrom_data=aa.chrom_info;var ad='<option value="">Select Chrom/Contig</option>';for(var ac=0,Z=W.chrom_data.length;ac<Z;ac++){var ab=W.chrom_data[ac].chrom;ad+='<option value="'+ab+'">'+ab+"</option>"}if(aa.prev_chroms){ad+='<option value="previous">Previous '+s+"</option>"}if(aa.next_chroms){ad+='<option value="next">Next '+s+"</option>"}W.chrom_select.html(ad);if(Y){Y()}W.chrom_start_index=aa.start_index},error:function(){alert("Could not load chroms for this dbkey:",W.dbkey)}})},change_chrom:function(aa,X,ac){if(!aa||aa==="None"){return}var Z=this;if(aa==="previous"){Z.load_chroms({low:this.chrom_start_index-s});return}if(aa==="next"){Z.load_chroms({low:this.chrom_start_index+s});return}var ab=$.grep(Z.chrom_data,function(ae,af){return ae.chrom===aa})[0];if(ab===undefined){Z.load_chroms({chrom:aa},function(){Z.change_chrom(aa,X,ac)});return}else{if(aa!==Z.chrom){Z.chrom=aa;if(!Z.chrom){Z.intro_div.show()}else{Z.intro_div.hide()}Z.chrom_select.val(Z.chrom);Z.max_high=ab.len-1;Z.reset();Z.redraw(true);for(var ad=0,W=Z.tracks.length;ad<W;ad++){var Y=Z.tracks[ad];if(Y.init){Y.init()}}}if(X!==undefined&&ac!==undefined){Z.low=Math.max(X,0);Z.high=Math.min(ac,Z.max_high)}Z.reset_overview();Z.redraw()}},go_to:function(aa){var ae=this,W,Z,X=aa.split(":"),ac=X[0],ad=X[1];if(ad!==undefined){try{var ab=ad.split("-");W=parseInt(ab[0].replace(/,/g,""),10);Z=parseInt(ab[1].replace(/,/g,""),10)}catch(Y){return false}}ae.change_chrom(ac,W,Z)},move_fraction:function(Y){var W=this;var X=W.high-W.low;this.move_delta(Y*X)},move_delta:function(Y){var W=this;var X=W.high-W.low;if(W.low-Y<W.max_low){W.low=W.max_low;W.high=W.max_low+X}else{if(W.high-Y>W.max_high){W.high=W.max_high;W.low=W.max_high-X}else{W.high-=Y;W.low-=Y}}W.redraw()},add_track:function(W){W.view=this;W.track_id=this.track_id_counter;this.tracks.push(W);if(W.init){W.init()}W.container_div.attr("id","track_"+W.track_id);B(W.container_div,".draghandle");this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(W){W.view=this;this.label_tracks.push(W)},remove_track:function(W){this.has_changes=true;W.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(W)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(ad){var ac=this.high-this.low,ab=this.low,X=this.high;if(ab<this.max_low){ab=this.max_low}if(X>this.max_high){X=this.max_high}if(this.high!==0&&ac<this.min_separation){X=ab+this.min_separation}this.low=Math.floor(ab);this.high=Math.ceil(X);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(r,Math.max(0,Math.ceil(Math.log(this.resolution,r)/Math.log(r))));var W=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var aa=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:W,width:Math.max(ae,aa)}).show();if(aa<ae){this.overview_box.css("left",W-(ae-aa)/2)}if(this.overview_highlight){this.overview_highlight.css({left:W,width:aa})}this.update_location(this.low,this.high);if(!ad){for(var Y=0,Z=this.tracks.length;Y<Z;Y++){if(this.tracks[Y]&&this.tracks[Y].enabled){this.tracks[Y].draw()}}for(Y=0,Z=this.label_tracks.length;Y<Z;Y++){this.label_tracks[Y].draw()}}},zoom_in:function(X,Y){if(this.max_high===0||this.high-this.low<this.min_separation){return}var Z=this.high-this.low,aa=Z/2+this.low,W=(Z/this.zoom_factor)/2;if(X){aa=X/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(aa-W);this.high=Math.round(aa+W);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var X=this.high-this.low,Y=X/2+this.low,W=(X*this.zoom_factor)/2;this.low=Math.round(Y-W);this.high=Math.round(Y+W);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var n=function(X,aa){this.track=X;this.name=aa.name;this.params=[];var ai=aa.params;for(var Y=0;Y<ai.length;Y++){var ad=ai[Y],W=ad.name,ah=ad.label,Z=unescape(ad.html),af=ad.type;if(af==="number"){this.params[this.params.length]=new g(W,ah,Z,ad.min,ad.max)}else{if(af=="select"){this.params[this.params.length]=new I(W,ah,Z)}else{console.log("WARNING: unrecognized tool parameter type:",W,af)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(ak){ak.stopPropagation()}).bind("click",function(ak){ak.stopPropagation()}).bind("dblclick",function(ak){ak.stopPropagation()});var ag=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var ae=this.params;var ab=this;$.each(this.params,function(al,ao){var an=$("<div>").addClass("param-row").appendTo(ab.parent_div);var ak=$("<div>").addClass("param-label").text(ao.label).appendTo(an);var am=$("<div/>").addClass("slider").html(ao.html).appendTo(an);$("<div style='clear: both;'/>").appendTo(an)});this.parent_div.find("input").click(function(){$(this).select()});var aj=$("<div>").addClass("slider-row").appendTo(this.parent_div);var ac=$("<input type='submit'>").attr("value","Run").appendTo(aj);var ab=this;ac.click(function(){ab.run()})};extend(n.prototype,{get_param_values_dict:function(){var W={};this.parent_div.find(":input").each(function(){var X=$(this).attr("name"),Y=$(this).val();W[X]=JSON.stringify(Y)});return W},get_param_values:function(){var X=[];var W={};this.parent_div.find(":input").each(function(){var Y=$(this).attr("name"),Z=$(this).val();if(Y){X[X.length]=Z}});return X},run:function(){var X={dataset_id:this.track.original_dataset_id,chrom:this.track.view.chrom,low:this.track.view.low,high:this.track.view.high,tool_id:this.name};$.extend(X,this.get_param_values_dict());var Z=this.track,Y=X.tool_id+Z.tool_region_and_parameters_str(X.chrom,X.low,X.high),aa;if(Z.track_type==="FeatureTrack"){aa=new N(Y,view,Z.hda_ldda,undefined,{},{},Z)}this.track.add_track(aa);aa.content_div.text("Starting job.");var W=function(){$.getJSON(run_tool_url,X,function(ab){if(ab==="no converter"){aa.container_div.addClass("error");aa.content_div.text(E)}else{if(ab.error){aa.container_div.addClass("error");aa.content_div.text(u+ab.message)}else{if(ab==="pending"){aa.container_div.addClass("pending");aa.content_div.text("Converting input data so that it can be easily reused.");setTimeout(W,2000)}else{aa.dataset_id=ab.dataset_id;aa.content_div.text("Running job.");aa.init()}}}})};W()}});var I=function(X,W,Y){this.name=X;this.label=W;this.html=Y};var g=function(Y,X,aa,Z,W){I.call(this,Y,X,aa);this.min=Z;this.max=W};var j=function(X,W,Y){this.name=X;this.index=W;this.value=Y};var O=function(X,W){this.name=X;this.index=W;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.min=Number.MAX_VALUE;this.max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};extend(O.prototype,{applies_to:function(W){if(W.length>this.index){return true}return false},keep:function(W){if(!this.applies_to(W)){return true}return(W[this.index]>=this.low&&W[this.index]<=this.high)},update_attrs:function(X){var W=false;if(!this.applies_to(X)){return W}if(X[this.index]<this.min){this.min=Math.floor(X[this.index]);W=true}if(X[this.index]>this.max){this.max=Math.ceil(X[this.index]);W=true}return W},update_ui_elt:function(){var X=this.slider.slider("option","min"),W=this.slider.slider("option","max");if(this.min<X||this.max>W){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",h(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var v=function(W){var ac=[];for(var Z=0;Z<W.length;Z++){var ab=W[Z];var Y=ab.name,aa=ab.type,X=ab.index;if(aa==="int"||aa==="float"){ac[Z]=new O(Y,X)}else{ac[Z]=new j(Y,X,aa)}}return ac};var S=function(W){this.track=W.track;this.params=W.params;this.values={};if(W.saved_values){this.restore_values(W.saved_values)}this.onchange=W.onchange};extend(S.prototype,{restore_values:function(W){var X=this;$.each(this.params,function(Y,Z){if(W[Z.key]!==undefined){X.values[Z.key]=W[Z.key]}else{X.values[Z.key]=Z.default_value}})},build_form:function(){var X=this;var W=$("<div />");$.each(this.params,function(ab,Z){if(!Z.hidden){var Y="param_"+ab;var ag=$("<div class='form-row' />").appendTo(W);ag.append($("<label />").attr("for",Y).text(Z.label+":"));if(Z.type==="bool"){ag.append($('<input type="checkbox" />').attr("id",Y).attr("name",Y).attr("checked",X.values[Z.key]))}else{if(Z.type==="color"){var ad=X.values[Z.key];var ac=$("<input />").attr("id",Y).attr("name",Y).val(ad);var ae=$("<div class='tipsy tipsy-north' style='position: absolute;' />").hide();var aa=$("<div style='background-color: black; padding: 10px;'></div>").appendTo(ae);var af=$("<div/>").appendTo(aa).farbtastic({width:100,height:100,callback:ac,color:ad});$("<div />").append(ac).append(ae).appendTo(ag).bind("click",function(ah){ae.css({left:$(this).position().left+($(ac).width()/2)-60,top:$(this).position().top+$(this.height)}).show();$(document).bind("click.color-picker",function(){ae.hide();$(document).unbind("click.color-picker")});ah.stopPropagation()})}else{ag.append($("<input />").attr("id",Y).attr("name",Y).val(X.values[Z.key]))}}}});return W},update_from_form:function(W){var Y=this;var X=false;$.each(this.params,function(Z,ab){if(!ab.hidden){var ac="param_"+Z;var aa=W.find("#"+ac).val();if(ab.type==="float"){aa=parseFloat(aa)}else{if(ab.type==="int"){aa=parseInt(aa)}else{if(ab.type==="bool"){aa=W.find("#"+ac).is(":checked")}}}if(aa!==Y.values[ab.key]){Y.values[ab.key]=aa;X=true}}});if(X){this.onchange()}}});var b=function(W,X,Y){this.track=W;this.canvas=X;this.histo_max=Y};var k=function(X,W,aa,Y,Z){this.name=X;this.view=W;this.parent_element=aa;this.data_url=(Y?Y:default_data_url);this.data_url_extra_params={};this.data_query_wait=(Z?Z:F);this.dataset_check_url=converted_datasets_state_url;this.container_div=$("<div />").addClass("track").css("position","relative");if(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)};extend(k.prototype,{init:function(){var W=this;W.enabled=false;W.tile_cache.clear();W.data_cache.clear();W.initial_canvas=undefined;W.content_div.css("height","auto");W.container_div.removeClass("nodata error pending");if(!W.dataset_id){return}$.getJSON(converted_datasets_state_url,{hda_ldda:W.hda_ldda,dataset_id:W.dataset_id,chrom:W.view.chrom},function(X){if(!X||X==="error"||X.kind==="error"){W.container_div.addClass("error");W.content_div.text(m);if(X.message){var Z=W.view.tracks.indexOf(W);var Y=$(" <a href='javascript:void(0);'></a>").text("View error").bind("click",function(){show_modal("Trackster Error","<pre>"+X.message+"</pre>",{Close:hide_modal})});W.content_div.append(Y)}}else{if(X==="no converter"){W.container_div.addClass("error");W.content_div.text(E)}else{if(X==="no data"||(X.data!==undefined&&(X.data===null||X.data.length===0))){W.container_div.addClass("nodata");W.content_div.text(A)}else{if(X==="pending"){W.container_div.addClass("pending");W.content_div.text(p);setTimeout(function(){W.init()},W.data_query_wait)}else{if(X.status==="data"){if(X.valid_chroms){W.valid_chroms=X.valid_chroms;W.make_name_popup_menu()}W.content_div.text(R);if(W.view.chrom){W.content_div.text("");W.content_div.css("height",W.height_px+"px");W.enabled=true;$.when(W.predraw_init()).done(function(){W.draw()})}}}}}}})},predraw_init:function(){},update_name:function(W){this.old_name=this.name;this.name=W;this.name_div.text(this.name)},revert_name:function(){this.name=this.old_name;this.name_div.text(this.name)}});var H=function(X,ad,ag){var Y=this,ah=Y.view;this.filters=(X!==undefined?v(X):[]);this.filters_available=false;this.filters_visible=false;this.tool=(ad!==undefined&&obj_length(ad)>0?new n(this,ad):undefined);this.parent_track=ag;this.child_tracks=[];if(Y.hidden){return}var af=function(ai,aj,ak){ai.click(function(){var al=aj.text();max=parseFloat(ak.slider("option","max")),input_size=(max<=1?4:max<=1000000?max.toString().length:6),multi_value=false;if(ak.slider("option","values")){input_size=2*input_size+1;multi_value=true}aj.text("");$("<input type='text'/>").attr("size",input_size).attr("maxlength",input_size).attr("value",al).appendTo(aj).focus().select().click(function(am){am.stopPropagation()}).blur(function(){$(this).remove();aj.text(al)}).keyup(function(aq){if(aq.keyCode===27){$(this).trigger("blur")}else{if(aq.keyCode===13){var ao=ak.slider("option","min"),am=ak.slider("option","max"),ap=function(ar){return(isNaN(ar)||ar>am||ar<ao)},an=$(this).val();if(!multi_value){an=parseFloat(an);if(ap(an)){alert("Parameter value must be in the range ["+ao+"-"+am+"]");return $(this)}}else{an=an.split("-");an=[parseFloat(an[0]),parseFloat(an[1])];if(ap(an[0])||ap(an[1])){alert("Parameter value must be in the range ["+ao+"-"+am+"]");return $(this)}}ak.slider((multi_value?"values":"value"),an)}}})})};if(this.parent_track){this.header_div.find(".draghandle").removeClass("draghandle").addClass("child-track-icon").addClass("icon-button");this.parent_element.addClass("child-track");this.tool=undefined}this.filters_div=$("<div/>").addClass("filters").hide();this.header_div.after(this.filters_div);this.filters_div.bind("drag",function(ai){ai.stopPropagation()}).bind("click",function(ai){ai.stopPropagation()}).bind("dblclick",function(ai){ai.stopPropagation()});$.each(this.filters,function(ao,aj){var al=$("<div/>").addClass("slider-row").appendTo(Y.filters_div);var ai=$("<div/>").addClass("slider-label").appendTo(al);var aq=$("<span/>").addClass("slider-name").text(aj.name+" ").appendTo(ai);var ak=$("<span/>");var am=$("<span/>").addClass("slider-value").appendTo(ai).append("[").append(ak).append("]");var ap=$("<div/>").addClass("slider").appendTo(al);aj.control_element=$("<div/>").attr("id",aj.name+"-filter-control").appendTo(ap);var an=[0,0];aj.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(ar,at){an=at.values;ak.text(at.values[0]+"-"+at.values[1]);setTimeout(function(){if(at.values[0]==an[0]&&at.values[1]==an[1]){var au=at.values;ak.text(au[0]+"-"+au[1]);aj.low=au[0];aj.high=au[1];Y.draw(true,true)}},50)},change:function(ar,at){aj.control_element.slider("option","slide").call(aj.control_element,ar,at)}});aj.slider=aj.control_element;aj.slider_label=ak;af(am,ak,aj.control_element);$("<div style='clear: both;'/>").appendTo(al)});if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}Y.child_tracks_container=$("<div/>").addClass("child-tracks-container").hide();Y.container_div.append(Y.child_tracks_container);if(Y.display_modes!==undefined){if(Y.mode_div===undefined){Y.mode_div=$("<div class='right-float menubutton popup' />").appendTo(Y.header_div);var aa=(Y.track_config&&Y.track_config.values.mode?Y.track_config.values.mode:Y.display_modes[0]);Y.mode=aa;Y.mode_div.text(aa);var Z=function(ai){Y.mode_div.text(ai);Y.mode=ai;Y.track_config.values.mode=ai;Y.tile_cache.clear();Y.draw()};var W={};for(var ab=0,ae=Y.display_modes.length;ab<ae;ab++){var ac=Y.display_modes[ab];W[ac]=function(ai){return function(){Z(ai)}}(ac)}make_popupmenu(Y.mode_div,W)}else{Y.mode_div.hide()}}this.make_name_popup_menu()};extend(H.prototype,k.prototype,{make_name_popup_menu:function(){var X=this;var W={};W["Edit configuration"]=function(){var ad=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ab=function(){X.track_config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(ae){if((ae.keyCode||ae.which)===27){ad()}else{if((ae.keyCode||ae.which)===13){ab()}}};$(window).bind("keypress.check_enter_esc",ac);show_modal("Configure Track",X.track_config.build_form(),{Cancel:ad,OK:ab})};if(X.filters_available>0){var aa=(X.filters_div.is(":visible")?"Hide filters":"Show filters");W[aa]=function(){X.filters_visible=(X.filters_div.is(":visible"));X.filters_div.toggle();X.make_name_popup_menu()}}if(X.tool){var aa=(X.dynamic_tool_div.is(":visible")?"Hide tool":"Show tool");W[aa]=function(){if(!X.dynamic_tool_div.is(":visible")){X.update_name(X.name+X.tool_region_and_parameters_str())}else{menu_option_text="Show dynamic tool";X.revert_name()}X.dynamic_tool_div.toggle();X.make_name_popup_menu()}}if(X.valid_chroms){W["List chrom/contigs with data"]=function(){show_modal("Chrom/contigs with data","<p>"+X.valid_chroms.join("<br/>")+"</p>",{Close:function(){hide_modal()}})}}var Y=view;var Z=function(){$("#no-tracks").show()};if(this.parent_track){Y=this.parent_track;Z=function(){}}W.Remove=function(){Y.remove_track(X);if(Y.num_tracks===0){Z()}};make_popupmenu(X.name_div,W)},draw:function(W,Z){var an=this.view.low,ac=this.view.high,ae=ac-an,ag=this.view.container.width(),ab=ag/ae,ah=this.view.resolution,aa=$("<div style='position: relative;'></div>");if(!Z){this.content_div.children().remove()}this.content_div.append(aa);this.max_height=0;var aj=Math.floor(an/ah/J);var Y={};while((aj*J*ah)<ac){var am=ag+"_"+ab+"_"+aj;var ad=this.tile_cache.get(am);var ak=aj*J*this.view.resolution;var X=ak+J*this.view.resolution;if(!W&&ad){this.show_tile(ad,aa,ak,ab)}else{this.delayed_draw(W,am,ak,X,aj,ah,aa,ab,Y)}aj+=1}var af=this;var al=setInterval(function(){if(obj_length(Y)===0){clearInterval(al);if(Z){var aq=af.content_div.children();var ap=false;for(var ar=aq.length-1,ao=0;ar>=ao;ar--){var av=$(aq[ar]);if(ap){av.remove()}else{if(av.children().length!==0){ap=true}}}}for(var au=0;au<af.filters.length;au++){af.filters[au].update_ui_elt()}var at=false;if(af.example_feature){for(var au=0;au<af.filters.length;au++){if(af.filters[au].applies_to(af.example_feature)){at=true;break}}}if(af.filters_available!==at){af.filters_available=at;if(!af.filters_available){af.filters_div.hide()}af.make_name_popup_menu()}}},50);for(var ai=0;ai<this.child_tracks.length;ai++){this.child_tracks[ai].draw(W,Z)}},delayed_draw:function(X,ae,ac,ag,Y,aa,af,ah,ab){var Z=this;var ad=function(ap,ai,ak,aj,an,ao,al){returned_tile=Z.draw_tile(ai,ak,aj,an,ao,al);var am=$("<div class='track-tile'>").prepend(returned_tile);tile_element=am;Z.tile_cache.set(ae,tile_element);Z.show_tile(tile_element,an,ac,ao);delete ab[ap]};var W=setTimeout(function(){if(ac<=Z.view.high&&ag>=Z.view.low){var ai=(X?undefined:Z.tile_cache.get(ae));if(ai){Z.show_tile(ai,af,ac,ah);delete ab[W]}else{$.when(Z.data_cache.get_data(view.chrom,ac,ag,Z.mode,aa,Z.data_url_extra_params)).then(function(aj){if(view.reference_track&&ah>view.canvas_manager.char_width_px){$.when(view.reference_track.data_cache.get_data(view.chrom,ac,ag,Z.mode,aa,view.reference_track.data_url_extra_params)).then(function(ak){ad(W,aj,aa,Y,af,ah,ak)})}else{ad(W,aj,aa,Y,af,ah)}})}}},50);ab[W]=true},show_tile:function(W,ab,Z,ac){var X=this;var Y=this.view.high-this.view.low,aa=(Z-this.view.low)*ac;if(this.left_offset){aa-=this.left_offset}W.css({position:"absolute",top:0,left:aa,height:""});ab.append(W);X.max_height=Math.max(X.max_height,W.height());X.content_div.css("height",X.max_height+"px");ab.children().css("height",X.max_height+"px")},set_overview:function(){var W=this.view;if(this.initial_canvas&&this.is_overview){W.overview_close.show();W.overview_viewport.append(this.initial_canvas);W.overview_highlight.show().height(this.initial_canvas.height());W.overview_viewport.height(this.initial_canvas.height()+W.overview_box.height())}$(window).trigger("resize")},tool_region_and_parameters_str:function(Y,W,Z){var X=this,aa=(Y!==undefined&&W!==undefined&&Z!==undefined?Y+":"+W+"-"+Z:"all");return" - region=["+aa+"], parameters=["+X.tool.get_param_values().join(", ")+"]"},add_track:function(W){W.track_id=this.track_id+"_"+this.child_tracks.length;W.container_div.attr("id","track_"+W.track_id);this.child_tracks_container.append(W.container_div);B(W.container_div,".child-track-icon");if(!$(this.child_tracks_container).is(":visible")){this.child_tracks_container.show()}this.child_tracks.push(W);this.view.has_changes=true},remove_track:function(W){W.container_div.fadeOut("slow",function(){$(this).remove()})}});var T=function(W,X){this.track_type="LabelTrack";this.hidden=true;k.call(this,null,W,X);this.container_div.addClass("label-track")};extend(T.prototype,k.prototype,{draw:function(){var Y=this.view,Z=Y.high-Y.low,ac=Math.floor(Math.pow(10,Math.floor(Math.log(Z)/Math.log(10)))),W=Math.floor(Y.low/ac)*ac,aa=this.view.container.width(),X=$("<div style='position: relative; height: 1.3em;'></div>");while(W<Y.high){var ab=(W-Y.low)/Z*aa;X.append($("<div class='label'>"+commatize(W)+"</div>").css({position:"absolute",left:ab-1}));W+=ac}this.content_div.children(":first").remove();this.content_div.append(X)}});var x=function(W){this.track_type="ReferenceTrack";this.hidden=true;k.call(this,null,W,W.top_labeltrack);H.call(this);W.reference_track=this;this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url;this.data_url_extra_params={dbkey:W.dbkey};this.data_cache=new K(y,this,false);this.tile_cache=new c(q)};extend(x.prototype,H.prototype,{draw_tile:function(ag,ab,X,ad,ah){var aa=this,Y=J*ab;if(ah>this.view.canvas_manager.char_width_px){if(ag===null){aa.content_div.css("height","0px");return}var Z=this.view.canvas_manager.new_canvas();var af=Z.getContext("2d");Z.width=Math.ceil(Y*ah+aa.left_offset);Z.height=aa.height_px;af.font=af.canvas.manager.default_font;af.textAlign="center";for(var ac=0,ae=ag.length;ac<ae;ac++){var W=Math.round(ac*ah);af.fillText(ag[ac],W+aa.left_offset,10)}return Z}this.content_div.css("height","0px")}});var l=function(aa,Y,ab,W,Z){var X=this;this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";k.call(this,aa,Y,Y.viewport_container);H.call(this);this.min_height_px=16;this.max_height_px=400;this.height_px=80;this.hda_ldda=ab;this.dataset_id=W;this.original_dataset_id=W;this.data_cache=new K(y,this);this.tile_cache=new c(q);this.track_config=new S({track:this,params:[{key:"color",label:"Color",type:"color",default_value:"black"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.height_px,hidden:true}],saved_values:Z,onchange:function(){X.vertical_range=X.prefs.max_value-X.prefs.min_value;$("#linetrack_"+X.track_id+"_minval").text(X.prefs.min_value);$("#linetrack_"+X.track_id+"_maxval").text(X.prefs.max_value);X.tile_cache.clear();X.draw()}});this.prefs=this.track_config.values;this.height_px=this.track_config.values.height;this.vertical_range=this.track_config.values.max_value-this.track_config.values.min_value;this.add_resize_handle()};extend(l.prototype,H.prototype,{add_resize_handle:function(){var W=this;var Z=false;var Y=false;var X=$("<div class='track-resize'>");$(W.container_div).hover(function(){Z=true;X.show()},function(){Z=false;if(!Y){X.hide()}});X.hide().bind("dragstart",function(aa,ab){Y=true;ab.original_height=$(W.content_div).height()}).bind("drag",function(ab,ac){var aa=Math.min(Math.max(ac.original_height+ac.deltaY,W.min_height_px),W.max_height_px);$(W.content_div).css("height",aa);W.height_px=aa;W.draw(true)}).bind("dragend",function(aa,ab){W.tile_cache.clear();Y=false;if(!Z){X.hide()}W.track_config.values.height=W.height_px}).appendTo(W.container_div)},predraw_init:function(){var W=this,X=W.view.tracks.indexOf(W);W.vertical_range=undefined;return $.getJSON(W.data_url,{stats:true,chrom:W.view.chrom,low:null,high:null,hda_ldda:W.hda_ldda,dataset_id:W.dataset_id},function(Y){W.container_div.addClass("line-track");var aa=Y.data;if(isNaN(parseFloat(W.prefs.min_value))||isNaN(parseFloat(W.prefs.max_value))){W.prefs.min_value=aa.min;W.prefs.max_value=aa.max;$("#track_"+X+"_minval").val(W.prefs.min_value);$("#track_"+X+"_maxval").val(W.prefs.max_value)}W.vertical_range=W.prefs.max_value-W.prefs.min_value;W.total_frequency=aa.total_frequency;W.container_div.find(".yaxislabel").remove();var ab=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+X+"_minval").text(t(W.prefs.min_value));var Z=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+X+"_maxval").text(t(W.prefs.max_value));Z.css({position:"absolute",top:"24px",left:"10px"});Z.prependTo(W.container_div);ab.css({position:"absolute",bottom:"2px",left:"10px"});ab.prependTo(W.container_div)})},draw_tile:function(ah,aa,X,ae,ag){if(this.vertical_range===undefined){return}var ab=X*J*aa,Z=J*aa,W=Math.ceil(Z*ag),ad=this.height_px;var Y=this.view.canvas_manager.new_canvas();Y.width=W,Y.height=ad;var af=Y.getContext("2d");var ac=new G.LinePainter(ah.data,ab,ab+Z,this.prefs.min_value,this.prefs.max_value,this.prefs.color,this.mode);ac.draw(af,W,ad);return Y}});var e=function(W,ab,aa,ae,ad,Y,Z,ac){var X=this;this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];this.track_config=new S({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:ad,onchange:function(){X.tile_cache.clear();X.draw()}});this.prefs=this.track_config.values;k.call(this,W,ab,ab.viewport_container);H.call(this,Y,Z,ac);this.height_px=0;this.container_div.addClass("feature-track");this.hda_ldda=aa;this.dataset_id=ae;this.original_dataset_id=ae;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.inc_slots={};this.start_end_dct={};this.tile_cache=new c(d);this.data_cache=new K(20,this);this.left_offset=200;this.painter=G.LinkedFeaturePainter};extend(e.prototype,H.prototype,{update_auto_mode:function(W){if(this.mode=="Auto"){if(W=="no_detail"){W="reduced to feature spans"}else{if(W=="summary_tree"){W="reduced to coverage histogram"}}this.mode_div.text("Auto ("+W+")")}},incremental_slots:function(aa,X,Z){var Y=this.view.canvas_manager.dummy_context,W=this.inc_slots[aa];if(!W||(W.mode!==Z)){W=new (o.FeatureSlotter)(aa,Z==="Pack",w,function(ab){return Y.measureText(ab)});W.mode=Z;this.inc_slots[aa]=W}return W.slot_features(X)},draw_tile:function(ai,aq,av,ae,ag,Z){var an=this,ax=av*J*aq,X=(av+1)*J*aq,ak=X-ax,ao=Math.ceil(ak*ag),am=this.mode,aB=25,aa=this.left_offset,aj,ab;if(am==="Auto"){if(ai.dataset_type==="summary_tree"){am=ai.dataset_type}else{if(ai.extra_info==="no_detail"){am="no_detail"}else{var aA=ai.data;if((aA.length&&aA.length<4)||(this.view.high-this.view.low>D)){am="Squish"}else{am="Pack"}}}this.update_auto_mode(am)}if(am==="summary_tree"){ab=this.summary_draw_height;ae.parent().css("height",Math.max(this.height_px,ab)+"px");this.container_div.find(".yaxislabel").remove();var W=$("<div />").addClass("yaxislabel");W.text(ai.max);W.css({position:"absolute",top:"22px",left:"10px"});W.prependTo(this.container_div);var Y=this.view.canvas_manager.new_canvas();Y.width=ao+aa;Y.height=ab+L;var ay=new G.SummaryTreePainter(ai.data,ai.delta,ai.max,ax,X,this.prefs.show_counts);var ap=Y.getContext("2d");ap.translate(aa,L);ay.draw(ap,ao,ab);return Y}var aj,ad=1;if(am==="no_detail"||am==="Squish"||am==="Pack"){ad=this.incremental_slots(ag,ai.data,am);aj=this.inc_slots[ag].slots}var af=[];if(ai.data){for(var ar=0,au=ai.data.length;ar<au;ar++){var ac=ai.data[ar];var at=false;var ah;for(var aw=0,az=this.filters.length;aw<az;aw++){ah=this.filters[aw];ah.update_attrs(ac);if(!ah.keep(ac)){at=true;break}}if(!at){af.push(ac)}}}var ay=new (this.painter)(af,ax,X,this.prefs,am,Z);var ab=ay.get_required_height(ad)+z;var Y=this.view.canvas_manager.new_canvas();Y.width=ao+aa;Y.height=ab;ae.parent().css("height",Math.max(this.height_px,ab)+"px");var ap=Y.getContext("2d");ap.fillStyle=this.prefs.block_color;ap.font=ap.canvas.manager.default_font;ap.textAlign="right";this.container_div.find(".yaxislabel").remove();if(ai.message){$(Y).css({"border-top":"1px solid red"});ap.fillStyle="red";ap.textAlign="left";var al=ap.textBaseline;ap.textBaseline="top";ap.fillText(ai.message,aa,0);ap.textBaseline=al;if(!ai.data){return Y}}this.example_feature=(ai.data.length?ai.data[0]:undefined);ap.translate(aa,z);ay.draw(ap,ao,ab,aj);return Y}});var M=function(Z,X,ab,W,Y,aa){e.call(this,Z,X,ab,W,Y,aa);this.track_type="VcfTrack";this.painter=G.VariantPainter};extend(M.prototype,H.prototype,e.prototype);var P=function(Z,X,ab,W,Y,aa){e.call(this,Z,X,ab,W,Y,aa);this.track_config=new S({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:Y,onchange:function(){this.track.tile_cache.clear();this.track.draw()}});this.prefs=this.track_config.values;this.track_type="ReadTrack";this.painter=G.ReadPainter;this.make_name_popup_menu()};extend(P.prototype,H.prototype,e.prototype);var N=function(aa,Y,ac,W,Z,ab,X){e.call(this,aa,Y,ac,W,Z,ab,{},X);this.track_type="ToolDataFeatureTrack";this.data_url=raw_data_url;this.data_query_wait=1000;this.dataset_check_url=dataset_state_url};extend(N.prototype,H.prototype,e.prototype,{predraw_init:function(){var X=this;var W=function(){if(X.data_cache.size()===0){setTimeout(W,300)}else{X.data_url=default_data_url;X.data_query_wait=F;X.dataset_state_url=converted_datasets_state_url;$.getJSON(X.dataset_state_url,{dataset_id:X.dataset_id,hda_ldda:X.hda_ldda},function(Y){})}};W()}});Q.View=U;Q.LineTrack=l;Q.FeatureTrack=e;Q.ReadTrack=P};var slotting_module=function(c,b){var d=2,a=5;b.FeatureSlotter=function(h,g,e,f){this.slots={};this.start_end_dct={};this.w_scale=h;this.include_label=g;this.max_rows=e;this.measureText=f};extend(b.FeatureSlotter.prototype,{slot_features:function(l){var o=this.w_scale,r=this.slots,g=this.start_end_dct,x=[],z=[],m=0,y=this.max_rows;for(var v=0,w=l.length;v<w;v++){var k=l[v],n=k[0];if(r[n]!==undefined){m=Math.max(m,r[n]);z.push(r[n])}else{x.push(v)}}var p=function(F,G){for(var E=0;E<=y;E++){var C=false,H=g[E];if(H!==undefined){for(var B=0,D=H.length;B<D;B++){var A=H[B];if(G>A[0]&&F<A[1]){C=true;break}}}if(!C){return E}}return -1};for(var v=0,w=x.length;v<w;v++){var k=l[x[v]],n=k[0],t=k[1],e=k[2],q=k[3],f=Math.floor(t*o),j=Math.ceil(e*o),u=this.measureText(q).width,h;if(q!==undefined&&this.include_label){u+=(d+a);if(f-u>=0){f-=u;h="left"}else{j+=u;h="right"}}var s=p(f,j);if(s>=0){if(g[s]===undefined){g[s]=[]}g[s].push([f,j]);r[n]=s;m=Math.max(m,s)}else{}}return m+1}})};var painters_module=function(k,A){var q=function(L,D,J,C,I,G){if(G===undefined){G=4}var F=C-D;var E=I-J;var H=Math.floor(Math.sqrt(F*F+E*E)/G);var M=F/H;var K=E/H;var B;for(B=0;B<H;B++,D+=M,J+=K){if(B%2!==0){continue}L.fillRect(D,J,G,1)}};var r=function(D,C,B,G){var F=C-G/2,E=C+G/2,H=B-Math.sqrt(G*3/2);D.beginPath();D.moveTo(F,H);D.lineTo(E,H);D.lineTo(C,B);D.lineTo(F,H);D.strokeStyle=this.fillStyle;D.fill();D.stroke();D.closePath()};var v=function(E,G,C,F,B,D){this.data=E;this.delta=G;this.max=C;this.view_start=F;this.view_end=B;this.show_counts=D};v.prototype.draw=function(O,B,N){var G=this.view_start,Q=this.view_end-this.view_start,P=B/Q;var L=this.data,K=this.delta,I=this.max,D=N;delta_x_px=Math.ceil(K*P);O.save();for(var E=0,F=L.length;E<F;E++){var J=Math.floor((L[E][0]-G)*P);var H=L[E][1];if(!H){continue}var M=H/I*N;O.fillStyle="black";O.fillRect(J,D-M,delta_x_px,M);var C=4;if(this.show_counts&&(O.measureText(H).width+C)<delta_x_px){O.fillStyle="#666";O.textAlign="center";O.fillText(H,J+(delta_x_px/2),10)}}O.restore()};var c=function(E,H,B,C,G,D,F){this.data=E;this.view_start=H;this.view_end=B;this.min_value=C;this.max_value=G;this.color=D;this.mode=F;this.overflow_color="#F66"};c.prototype.draw=function(Q,P,N){var I=false,J=this.min_value,G=this.max_value,M=G-J,C=N,D=this.view_start,O=this.view_end-this.view_start,E=P/O,K=this.mode,U=this.data;Q.save();var V=Math.round(N+J/M*N);if(K!=="Intensity"){Q.fillStyle="#aaa";Q.fillRect(0,V,P,1)}Q.beginPath();Q.fillStyle=this.color;var T,H,F;if(U.length>1){F=Math.ceil((U[1][0]-U[0][0])*E)}else{F=10}for(var R=0,S=U.length;R<S;R++){T=Math.round((U[R][0]-D)*E);H=U[R][1];if(H===null){if(I&&K==="Filled"){Q.lineTo(T,C)}I=false;continue}if(H<J){H=J}else{if(H>G){H=G}}if(K==="Histogram"){H=Math.round(H/M*C);Q.fillRect(T,V,F,-H)}else{if(K==="Intensity"){H=255-Math.floor((H-J)/M*255);Q.fillStyle="rgb("+H+","+H+","+H+")";Q.fillRect(T,0,F,C)}else{H=Math.round(C-(H-J)/M*C);if(I){Q.lineTo(T,H)}else{I=true;if(K==="Filled"){Q.moveTo(T,C);Q.lineTo(T,H)}else{Q.moveTo(T,H)}}}}}if(K==="Filled"){if(I){Q.lineTo(T,V);Q.lineTo(0,V)}Q.fill()}else{Q.stroke()}var B=-1,L=-1;Q.fillStyle=this.overflow_color;for(var R=0,S=U.length;R<S;R++){H=U[R][1];T=Math.round((U[R][0]-D)*E);x_minus_scaled=Math.round((U[R][0]-1-D)*E);if(L>=0&&(H===null||H<G)){Q.fillRect(L,0,x_minus_scaled-L+1,2);L=-1}else{if(B>=0&&(H===null||H>J)){Q.fillRect(B,N-2,x_minus_scaled-B+1,2);B=-1}}if(H!==null&&H>G&&L<0){L=T}else{if(H!==null&&H<J&&B<0){B=T}}}Q.restore()};var p=function(D,F,B,C,E){this.data=D;this.view_start=F;this.view_end=B;this.prefs=C;this.mode=E};extend(p.prototype,{get_required_height:function(C){var B=y_scale=this.get_row_height(),D=this.mode;if(D==="no_detail"||D==="Squish"||D==="Pack"){B=C*y_scale}return B+Math.max(Math.round(y_scale/2),5)},draw:function(N,E,M,J){var H=this.data,K=this.view_start,O=this.view_end;N.save();N.fillStyle=this.prefs.block_color;N.textAlign="right";var R=this.view_end-this.view_start,Q=E/R,D=this.get_row_height();for(var G=0,I=H.length;G<I;G++){var P=H[G],F=P[0],B=P[1],C=P[2],L=(J&&J[F]!==undefined?J[F]:null);if((B<O&&C>K)&&(this.mode=="Dense"||L!==null)){this.draw_element(N,this.mode,P,L,K,O,Q,D,E)}}N.restore()}});var d=10,j=3,n=5,z=10,g=1,t=3,f=3,a=9,o=2,h="#ccc";var s=function(D,F,B,C,E){p.call(this,D,F,B,C,E)};extend(s.prototype,p.prototype,{get_row_height:function(){var C=this.mode,B;if(C==="Dense"){B=d}else{if(C==="no_detail"){B=j}else{if(C==="Squish"){B=n}else{B=z}}}return B},draw_element:function(N,G,V,I,P,af,aj,ak,B){var S=V[0],ah=V[1],Z=V[2]-1,Q=V[3],aa=Math.floor(Math.max(0,(ah-P)*aj)),O=Math.ceil(Math.min(B,Math.max(0,(Z-P)*aj))),Y=(G==="Dense"?0:(0+I))*ak,M,ad,R=null,al=null,E=this.prefs.block_color,ac=this.prefs.label_color;if(G=="Dense"){I=1}if(G==="no_detail"){N.fillStyle=E;N.fillRect(aa,Y+5,O-aa,g)}else{var L=V[4],X=V[5],ab=V[6],F=V[7];if(X&&ab){R=Math.floor(Math.max(0,(X-P)*aj));al=Math.ceil(Math.min(B,Math.max(0,(ab-P)*aj)))}var ai,T;if(G==="Squish"||G==="Dense"){ai=1;T=f}else{ai=5;T=a}if(!F){if(V.strand){if(V.strand==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand_inv")}else{if(V.strand==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand_inv")}}}else{N.fillStyle=E}N.fillRect(aa,Y,O-aa,T)}else{var K,U;if(G==="Squish"||G==="Dense"){N.fillStyle=h;K=Y+Math.floor(f/2)+1;U=1}else{if(L){var K=Y;var U=T;if(L==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand")}else{if(L==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand")}}}else{N.fillStyle=h;K+=(f/2)+1;U=1}}N.fillRect(aa,K,O-aa,U);for(var ag=0,D=F.length;ag<D;ag++){var H=F[ag],C=Math.floor(Math.max(0,(H[0]-P)*aj)),W=Math.ceil(Math.min(B,Math.max((H[1]-1-P)*aj)));if(C>W){continue}N.fillStyle=E;N.fillRect(C,Y+(T-ai)/2+1,W-C,ai);if(R!==undefined&&ab>X&&!(C>al||W<R)){var ae=Math.max(C,R),J=Math.min(W,al);N.fillRect(ae,Y+1,J-ae,T);if(F.length==1&&G=="Pack"){if(L==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand_inv")}else{if(L==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand_inv")}}if(ae+14<J){ae+=2;J-=2}N.fillRect(ae,Y+1,J-ae,T)}}}}if(G==="Pack"&&ah>P){N.fillStyle=ac;if(P===0&&aa-N.measureText(Q).width<0){N.textAlign="left";N.fillText(Q,O+o,Y+8)}else{N.textAlign="right";N.fillText(Q,aa-o,Y+8)}N.fillStyle=E}}}});var b=function(D,F,B,C,E){p.call(this,D,F,B,C,E)};extend(b.prototype,p.prototype,{draw_element:function(U,P,J,F,X,D,M,V,S){var J=data[i],L=J[0],T=J[1],E=J[2]-1,O=J[3],H=Math.floor(Math.max(0,(T-X)*M)),K=Math.ceil(Math.min(S,Math.max(0,(E-X)*M))),G=(P==="Dense"?0:(0+F))*V,B,Y,C=null,N=null;if(no_label){U.fillStyle=block_color;U.fillRect(H+left_offset,G+5,K-H,1)}else{var W=J[4],R=J[5],I=J[6];B=9;Y=1;U.fillRect(H+left_offset,G,K-H,B);if(P!=="Dense"&&O!==undefined&&T>X){U.fillStyle=label_color;if(X===0&&H-U.measureText(O).width<0){U.textAlign="left";U.fillText(O,K+2+left_offset,G+8)}else{U.textAlign="right";U.fillText(O,H-2+left_offset,G+8)}U.fillStyle=block_color}var Q=W+" / "+R;if(T>X&&U.measureText(Q).width<(K-H)){U.fillStyle="white";U.textAlign="center";U.fillText(Q,left_offset+H+(K-H)/2,G+8);U.fillStyle=block_color}}}});var y=1001,m=1002,e=1003,x=1004,l=1005;var w=function(F,C){var H=F[0],G=F[1],E=C[0],D=C[1],B;if(H<E){if(G<E){B=y}else{if(G<=D){B=e}else{B=m}}}else{if(H>D){B=y}else{if(G<=D){B=l}else{B=x}}}return B};var u=function(E,G,B,D,F,C){p.call(this,E,G,B,D,F);this.ref_seq=C};extend(u.prototype,p.prototype,{get_row_height:function(){var B,C=this.mode;if(C==="Dense"){B=d}else{if(C==="Squish"){B=n}else{B=z;if(this.prefs.show_insertions){B*=2}}}return B},draw_read:function(Y,T,O,ad,D,X,L,I,H){Y.textAlign="center";var W=this,C=[ad,D],R=0,Z=0,V=0;ref_seq=this.ref_seq,char_width_px=Y.canvas.manager.char_width_px;var ai=[];if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){V=Math.round(O/2)}if(!L){L=[[0,I.length]]}for(var P=0,ab=L.length;P<ab;P++){var M=L[P],E="MIDNSHP=X"[M[0]],Q=M[1];if(E==="H"||E==="S"){R-=Q}var J=X+R,ah=Math.floor(Math.max(0,(J-ad)*O)),K=Math.floor(Math.max(0,(J+Q-ad)*O));switch(E){case"H":break;case"S":case"M":case"=":var S=w([J,J+Q],C);if(S!==y){var U=I.slice(Z,Z+Q);if(V>0){Y.fillStyle=this.prefs.block_color;Y.fillRect(ah-V,H+1,K-ah,9);Y.fillStyle=h;for(var af=0,B=U.length;af<B;af++){if(this.prefs.show_differences&&ref_seq){var N=ref_seq[J-ad+af];if(!N||N.toLowerCase()===U[af].toLowerCase()){continue}}if(J+af>=ad&&J+af<=D){var ag=Math.floor(Math.max(0,(J+af-ad)*O));Y.fillText(U[af],ag,H+9)}}}else{Y.fillStyle=this.prefs.block_color;Y.fillRect(ah,H+4,K-ah,f)}}Z+=Q;R+=Q;break;case"N":Y.fillStyle=h;Y.fillRect(ah-V,H+5,K-ah,1);R+=Q;break;case"D":Y.fillStyle="red";Y.fillRect(ah-V,H+4,K-ah,3);R+=Q;break;case"P":break;case"I":var S=w([J,J+Q],C),ac=ah-V;if(S!==y){var U=I.slice(Z,Z+Q);if(this.prefs.show_insertions){var G=ah-(K-ah)/2;if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){Y.fillStyle="yellow";Y.fillRect(G-V,H-9,K-ah,9);ai[ai.length]={type:"triangle",data:[ac,H+4,5]};Y.fillStyle=h;switch(S){case (e):U=U.slice(ad-J);break;case (x):U=U.slice(0,J-D);break;case (l):break;case (m):U=U.slice(ad-J,J-D);break}for(var af=0,B=U.length;af<B;af++){var ag=Math.floor(Math.max(0,(J+af-ad)*O));Y.fillText(U[af],ag-(K-ah)/2,H)}}else{Y.fillStyle="yellow";Y.fillRect(G,H+(this.mode!=="Dense"?2:5),K-ah,(T!=="Dense"?f:t))}}else{if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){ai[ai.length]={type:"text",data:[U.length,ac,H+9]}}else{}}}Z+=Q;break;case"X":Z+=Q;break}}Y.fillStyle="yellow";var ae,F,aj;for(var aa=0;aa<ai.length;aa++){ae=ai[aa];F=ae.type;aj=ae.data;if(F==="text"){Y.save();Y.font="bold "+Y.font;Y.fillText(aj[0],aj[1],aj[2]);Y.restore()}else{if(F=="triangle"){r(Y,aj[0],aj[1],aj[2])}}}},draw_element:function(U,P,H,E,X,C,L,V,S){var K=H[0],T=H[1],D=H[2],M=H[3],G=Math.floor(Math.max(0,(T-X)*L)),I=Math.ceil(Math.min(S,Math.max(0,(D-X)*L))),F=(P==="Dense"?0:(0+E))*V,Y=this.prefs.block_color,J=this.prefs.label_color,R=0;if((P==="Pack"||this.mode==="Auto")&&L>U.canvas.manager.char_width_px){var R=Math.round(L/2)}U.fillStyle=Y;if(H[5] instanceof Array){var Q=Math.floor(Math.max(0,(H[4][0]-X)*L)),O=Math.ceil(Math.min(S,Math.max(0,(H[4][1]-X)*L))),N=Math.floor(Math.max(0,(H[5][0]-X)*L)),B=Math.ceil(Math.min(S,Math.max(0,(H[5][1]-X)*L)));if(H[4][1]>=X&&H[4][0]<=C&&H[4][2]){this.draw_read(U,P,L,X,C,H[4][0],H[4][2],H[4][3],F)}if(H[5][1]>=X&&H[5][0]<=C&&H[5][2]){this.draw_read(U,P,L,X,C,H[5][0],H[5][2],H[5][3],F)}if(N>O){U.fillStyle=h;q(U,O-R,F+5,N-R,F+5)}}else{U.fillStyle=Y;this.draw_read(U,P,L,X,C,T,H[4],H[5],F)}if(P==="Pack"&&T>X){U.fillStyle=this.prefs.label_color;var W=1;if(W===0&&G-U.measureText(M).width<0){U.textAlign="left";U.fillText(M,I+o-R,F+8)}else{U.textAlign="right";U.fillText(M,G-o-R,F+8)}U.fillStyle=Y}}});A.SummaryTreePainter=v;A.LinePainter=c;A.LinkedFeaturePainter=s;A.ReadPainter=u;A.VariantPainter=b};(function(d){var c={};var b=function(e){return c[e]};var a=function(f,g){var e={};g(b,e);c[f]=e};a("slotting",slotting_module);a("painters",painters_module);a("trackster",trackster_module);for(key in c.trackster){d[key]=c.trackster[key]}})(window);
\ No newline at end of file
--- a/static/scripts/trackster.js Sun Mar 27 19:50:50 2011 -0400
+++ b/static/scripts/trackster.js Tue Apr 05 13:57:14 2011 -0400
@@ -2,56 +2,79 @@
2010-2011: James Taylor, Kanwei Li, Jeremy Goecks
*/
-/**
- * Draw a dashed line on a canvas using filled rectangles. This function is based on:
- * http://vetruvet.blogspot.com/2010/10/drawing-dashed-lines-on-html5-canvas.h…
- * However, that approach uses lines, which don't seem to render as well, so use
- * rectangles instead.
- */
-CanvasRenderingContext2D.prototype.dashedLine = function(x1, y1, x2, y2, dashLen) {
- if (dashLen === undefined) { dashLen = 4; }
- var dX = x2 - x1;
- var dY = y2 - y1;
- var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
- var dashX = dX / dashes;
- var dashY = dY / dashes;
- var q;
-
- for (q = 0; q < dashes; q++, x1 += dashX, y1 += dashY) {
- if (q % 2 !== 0) {
- continue;
+/** Simple extend function for inheritence */
+var extend = function() {
+ var target = arguments[0];
+ for ( var i = 1; i < arguments.length; i++ ) {
+ var other = arguments[i];
+ for ( key in other ) {
+ target[key] = other[key];
}
- this.fillRect(x1, y1, dashLen, 1);
}
};
+// Encapsulate -- anything to be availabe outside this block is added to exports
+var trackster_module = function(require, exports){
+
+var slotting = require('slotting'),
+ painters = require('painters');
+
+// ---- Canvas management and extensions ----
+
/**
- * Draw an isosceles triangle that points down.
+ * Canvas manager is used to create canvases, for browsers, this deals with
+ * backward comparibility using excanvas, as well as providing a pattern cache
*/
-CanvasRenderingContext2D.prototype.drawDownwardEquilateralTriangle = function(down_vertex_x, down_vertex_y, side_len) {
- // Compute other two points of triangle.
- var
- x1 = down_vertex_x - side_len/2,
- x2 = down_vertex_x + side_len/2,
- y = down_vertex_y - Math.sqrt( side_len*3/2 );
-
- // Draw and fill.
- this.beginPath();
- this.moveTo(x1, y);
- this.lineTo(x2, y);
- this.lineTo(down_vertex_x, down_vertex_y);
- this.lineTo(x1, y);
+var CanvasManager = function( document, default_font ) {
+ this.document = document;
+ this.default_font = default_font !== undefined ? default_font : "9px Monaco, Lucida Console, monospace";
+
+ this.dummy_canvas = this.new_canvas();
+ this.dummy_context = this.dummy_canvas.getContext('2d');
+ this.dummy_context.font = this.default_font;
+
+ this.char_width_px = this.dummy_context.measureText("A").width;
+
+ this.patterns = {};
- this.strokeStyle = this.fillStyle;
- this.fill();
- this.stroke();
- this.closePath();
-};
+ // FIXME: move somewhere to make this more general
+ this.load_pattern( 'right_strand', "/visualization/strand_right.png" );
+ this.load_pattern( 'left_strand', "/visualization/strand_left.png" );
+ this.load_pattern( 'right_strand_inv', "/visualization/strand_right_inv.png" );
+ this.load_pattern( 'left_strand_inv', "/visualization/strand_left_inv.png" );
+}
+
+extend( CanvasManager.prototype, {
+ load_pattern: function( key, path ) {
+ var patterns = this.patterns,
+ dummy_context = this.dummy_context,
+ image = new Image();
+ // FIXME: where does image_path come from? not in browser.mako...
+ image.src = image_path + path;
+ image.onload = function() {
+ patterns[key] = dummy_context.createPattern( image, "repeat" );
+ }
+ },
+ get_pattern: function( key ) {
+ return this.patterns[key];
+ },
+ new_canvas: function() {
+ var canvas = this.document.createElement("canvas");
+ // If using excanvas in IE, we need to explicately attach the canvas
+ // methods to the DOM element
+ if (window.G_vmlCanvasManager) { G_vmlCanvasManager.initElement(canvas); }
+ // Keep a reference back to the manager
+ canvas.manager = this;
+ return canvas;
+ }
+});
+
+// ---- Web UI specific utilities ----
/**
* Make `element` sortable in parent by dragging `handle` (a selector)
*/
-function sortable( element, handle ) {
+var sortable = function( element, handle ) {
element.bind( "drag", { handle: handle, relative: true }, function ( e, d ) {
var parent = $(this).parent();
var children = parent.children();
@@ -77,47 +100,11 @@
}
/**
- * Compute the type of overlap between two regions. They are assumed to be on the same chrom/contig.
- * The overlap is computed relative to the second region; hence, OVERLAP_START indicates that the first
- * region overlaps the start (but not the end) of the second region.
+ * Calculates step for slider with a given min, max.
*/
-var NO_OVERLAP = 1001, CONTAINS = 1002, OVERLAP_START = 1003, OVERLAP_END = 1004, CONTAINED_BY = 1005;
-function compute_overlap(first_region, second_region) {
- var
- first_start = first_region[0], first_end = first_region[1],
- second_start = second_region[0], second_end = second_region[1],
- overlap;
- if (first_start < second_start) {
- if (first_end < second_start) {
- overlap = NO_OVERLAP;
- }
- else if (first_end <= second_end) {
- overlap = OVERLAP_START;
- }
- else { // first_end > second_end
- overlap = CONTAINS;
- }
- }
- else { // first_start >= second_start
- if (first_start > second_end) {
- overlap = NO_OVERLAP;
- }
- else if (first_end <= second_end) {
- overlap = CONTAINED_BY;
- }
- else {
- overlap = OVERLAP_END;
- }
- }
-
- return overlap;
-}
-
-/**
- * Returns true if there is any overlap between regions.
- */
-function is_overlap(first_region, second_region) {
- return (compute_overlap(first_region, second_region) !== NO_OVERLAP);
+var get_slider_step = function(min, max) {
+ var range = max - min;
+ return (range <= 2 ? 0.01 : (range <= 100 ? 1 : (range <= 1000 ? 5 : 10)));
}
/**
@@ -126,30 +113,21 @@
var
// Drawing constants; track height is (constant) height of track, and feature height is the
// height of individual features within tracks. Feature height, then, should always be less
- // than track height.
- DENSE_TRACK_HEIGHT = 10,
- NO_DETAIL_TRACK_HEIGHT = 3,
- SQUISH_TRACK_HEIGHT = 5,
- PACK_TRACK_HEIGHT = 10,
- NO_DETAIL_FEATURE_HEIGHT = 1,
- DENSE_FEATURE_HEIGHT = 1,
- SQUISH_FEATURE_HEIGHT = 3,
- PACK_FEATURE_HEIGHT = 9,
+ // than track height.
+ CHAR_HEIGHT_PX = 9, // FIXME: font size may not be static
ERROR_PADDING = 10, // Padding at the top of tracks for error messages
- LABEL_SPACING = 2,
- PACK_SPACING = 5,
+ SUMMARY_TREE_TOP_PADDING = CHAR_HEIGHT_PX + 2,
+ // Maximum number of rows un a slotted track
+ MAX_FEATURE_DEPTH = 100,
// Minimum width for window for squish to be used.
MIN_SQUISH_VIEW_WIDTH = 12000,
// Other constants.
- DEFAULT_FONT = "9px Monaco, Lucida Console, monospace",
DENSITY = 200,
FEATURE_LEVELS = 10,
- MAX_FEATURE_DEPTH = 100,
DEFAULT_DATA_QUERY_WAIT = 5000,
// Maximum number of chromosomes that are selectable at any one time.
MAX_CHROMS_SELECTABLE = 100,
- CONNECTOR_COLOR = "#ccc",
DATA_ERROR = "There was an error in indexing this dataset. ",
DATA_NOCONVERTER = "A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",
DATA_NONE = "No data for this chrom/contig.",
@@ -159,41 +137,7 @@
DATA_OK = "Ready for display",
CACHED_TILES_FEATURE = 10,
CACHED_TILES_LINE = 5,
- CACHED_DATA = 5,
- DUMMY_CANVAS = document.createElement("canvas"),
- RIGHT_STRAND, LEFT_STRAND;
-
-// Get information for rendering canvas elements.
-if (window.G_vmlCanvasManager) {
- G_vmlCanvasManager.initElement(DUMMY_CANVAS);
-}
-var
- CONTEXT = DUMMY_CANVAS.getContext("2d");
-CONTEXT.font = DEFAULT_FONT; // To ensure consistent measureText width
-var
- CHAR_WIDTH_PX = CONTEXT.measureText("A").width,
- CHAR_HEIGHT_PX = 9; // Taken from DEFAULT_FONT.
-
-var right_img = new Image();
-right_img.src = image_path + "/visualization/strand_right.png";
-right_img.onload = function() {
- RIGHT_STRAND = CONTEXT.createPattern(right_img, "repeat");
-};
-var left_img = new Image();
-left_img.src = image_path + "/visualization/strand_left.png";
-left_img.onload = function() {
- LEFT_STRAND = CONTEXT.createPattern(left_img, "repeat");
-};
-var right_img_inv = new Image();
-right_img_inv.src = image_path + "/visualization/strand_right_inv.png";
-right_img_inv.onload = function() {
- RIGHT_STRAND_INV = CONTEXT.createPattern(right_img_inv, "repeat");
-};
-var left_img_inv = new Image();
-left_img_inv.src = image_path + "/visualization/strand_left_inv.png";
-left_img_inv.onload = function() {
- LEFT_STRAND_INV = CONTEXT.createPattern(left_img_inv, "repeat");
-};
+ CACHED_DATA = 5;
function round_1000(num) {
return Math.round(num * 1000) / 1000;
@@ -206,7 +150,7 @@
this.num_elements = num_elements;
this.clear();
};
-$.extend(Cache.prototype, {
+extend(Cache.prototype, {
get: function(key) {
var index = this.key_ary.indexOf(key);
if (index !== -1) {
@@ -250,15 +194,25 @@
this.track = track;
this.subset = (subset !== undefined ? subset : true);
};
-$.extend(DataManager.prototype, Cache.prototype, {
+extend(DataManager.prototype, Cache.prototype, {
/**
* Load data from server; returns AJAX object so that use of Deferred is possible.
*/
load_data: function(chrom, low, high, mode, resolution, extra_params) {
+ // Setup data request params.
var params = {"chrom": chrom, "low": low, "high": high, "mode": mode,
"resolution": resolution, "dataset_id" : this.track.dataset_id,
"hda_ldda": this.track.hda_ldda};
$.extend(params, extra_params);
+
+ // Add track filters to params.
+ var filter_names = [];
+ for (var i = 0; i < this.track.filters.length; i++) {
+ filter_names[filter_names.length] = this.track.filters[i].name;
+ }
+ params.filter_cols = JSON.stringify(filter_names);
+
+ // Do request.
var manager = this;
return $.getJSON(this.track.data_url, params, function (result) {
manager.set_data(low, high, mode, result);
@@ -291,6 +245,8 @@
// the data was "index" or "data." Also could slice the data so that
// only data points in request are returned.
//
+
+ /* Disabling for now, more detailed data is never loaded for line tracks
if (this.subset) {
var key, split_key, entry_low, entry_high, mode, entry;
for (var i = 0; i < this.key_ary.length; i++) {
@@ -310,11 +266,13 @@
}
}
}
+ */
- //
- // Load data from server.
- //
- return this.load_data(chrom, low, high, mode, resolution, extra_params);
+ // Load data from server. The deferred is immediately saved until the
+ // data is ready, it then replaces itself with the actual data
+ entry = this.load_data(chrom, low, high, mode, resolution, extra_params);
+ this.set_data( low, high, mode, entry );
+ return entry
},
set_data: function(low, high, mode, result) {
//console.log("set_data", low, high, mode, result);
@@ -354,9 +312,10 @@
this.min_separation = 30;
this.has_changes = false;
this.init( callback );
+ this.canvas_manager = new CanvasManager( container.get(0).ownerDocument );
this.reset();
};
-$.extend( View.prototype, {
+extend( View.prototype, {
init: function( callback ) {
// Create DOM elements
var parent_element = this.container,
@@ -797,63 +756,175 @@
});
/**
- * Encapsulation of tools that users can apply to tracks/datasets.
+ * Encapsulation of a tool that users can apply to tracks/datasets.
*/
-var Tool = function(name, params) {
- this.name = name;
- this.params = params;
+var Tool = function(track, tool_dict) {
+ //
+ // Unpack tool information from dictionary.
+ //
+ this.track = track;
+ this.name = tool_dict.name;
+ this.params = [];
+ var params_dict = tool_dict.params;
+ for (var i = 0; i < params_dict.length; i++) {
+ var param_dict = params_dict[i],
+ name = param_dict.name,
+ label = param_dict.label,
+ html = unescape(param_dict.html),
+ type = param_dict.type;
+ if (type === "number") {
+ this.params[this.params.length] =
+ new NumberParameter(name, label, html, param_dict.min, param_dict.max);
+ }
+ else if (type == "select") {
+ this.params[this.params.length] = new ToolParameter(name, label, html);
+ }
+ else {
+ console.log("WARNING: unrecognized tool parameter type:", name, type);
+ }
+ }
+
+ //
+ // Create div elt for tool UI.
+ //
+ this.parent_div = $("<div/>").addClass("dynamic-tool").hide();
+ // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz.
+ this.parent_div.bind("drag", function(e) {
+ e.stopPropagation();
+ }).bind("click", function(e) {
+ e.stopPropagation();
+ }).bind("dblclick", function(e) {
+ e.stopPropagation();
+ });
+ var name_div = $("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);
+ var tool_params = this.params;
+ var tool = this;
+ $.each(this.params, function(index, param) {
+ var param_div = $("<div>").addClass("param-row").appendTo(tool.parent_div);
+ // Param label.
+ var label_div = $("<div>").addClass("param-label").text(param.label).appendTo(param_div);
+ // Param HTML.
+ // TODO: either generalize .slider CSS attributes or create new rule for tool input div.
+ var html_div = $("<div/>").addClass("slider").html(param.html).appendTo(param_div);
+
+ // Add to clear floating layout.
+ $("<div style='clear: both;'/>").appendTo(param_div);
+ });
+
+ // Highlight value for inputs for easy replacement.
+ this.parent_div.find("input").click(function() { $(this).select() });
+
+ // Add 'Go' button.
+ var run_tool_row = $("<div>").addClass("slider-row").appendTo(this.parent_div);
+ var run_tool_button = $("<input type='submit'>").attr("value", "Run").appendTo(run_tool_row);
+ var tool = this;
+ run_tool_button.click( function() {
+ tool.run();
+ });
};
-$.extend(Tool.prototype, {
- // Returns a dictionary of parameter values; key is parameter name, value
- // is parameter value.
+extend(Tool.prototype, {
+ /**
+ * Returns dictionary of parameter name-values.
+ */
get_param_values_dict: function() {
var param_dict = {};
- for (var i = 0; i < this.params.length; i++) {
- var param = this.params[i];
- param_dict[param.name] = param.value;
- }
+ this.parent_div.find(":input").each(function() {
+ var name = $(this).attr("name"), value = $(this).val();
+ param_dict[name] = JSON.stringify(value);
+ });
return param_dict;
},
- // Returns an array of parameter values.
+ /**
+ * Returns array of parameter values.
+ */
get_param_values: function() {
var param_values = [];
- for (var i = 0; i < this.params.length; i++) {
- param_values[i] = this.params[i].value;
+ var param_dict = {};
+ this.parent_div.find(":input").each(function() {
+ // Only include inputs with names; this excludes Run button.
+ var name = $(this).attr("name"), value = $(this).val();
+ if (name) {
+ param_values[param_values.length] = value;
+ }
+ });
+ return param_values;
+ },
+ /**
+ * Run tool. This creates a new child track, runs tool, and places tool's output in the new track.
+ */
+ run: function() {
+ // Put together params for running tool.
+ var url_params = {
+ dataset_id: this.track.original_dataset_id,
+ chrom: this.track.view.chrom,
+ low: this.track.view.low,
+ high: this.track.view.high,
+ tool_id: this.name
+ };
+ $.extend(url_params, this.get_param_values_dict());
+
+ //
+ // Create track for tool's output immediately to provide user feedback.
+ //
+ var
+ current_track = this.track,
+ // Set name of track to include tool name, parameters, and region used.
+ track_name = url_params.tool_id +
+ current_track.tool_region_and_parameters_str(url_params.chrom, url_params.low, url_params.high),
+ new_track;
+
+ // TODO: add support for other kinds of tool data tracks.
+ if (current_track.track_type === 'FeatureTrack') {
+ new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track);
}
- return param_values;
+
+ this.track.add_track(new_track);
+ new_track.content_div.text("Starting job.");
+
+ // Run tool.
+ var json_run_tool = function() {
+ $.getJSON(run_tool_url, url_params, function(track_data) {
+ if (track_data === "no converter") {
+ // No converter available for input datasets, so cannot run tool.
+ new_track.container_div.addClass("error");
+ new_track.content_div.text(DATA_NOCONVERTER);
+ }
+ else if (track_data.error) {
+ // General error.
+ new_track.container_div.addClass("error");
+ new_track.content_div.text(DATA_CANNOT_RUN_TOOL + track_data.message);
+ }
+ else if (track_data === "pending") {
+ // Converting/indexing input datasets; show message and try again.
+ new_track.container_div.addClass("pending");
+ new_track.content_div.text("Converting input data so that it can be easily reused.");
+ setTimeout(json_run_tool, 2000);
+ }
+ else {
+ // Job submitted and running.
+ new_track.dataset_id = track_data.dataset_id;
+ new_track.content_div.text("Running job.");
+ new_track.init();
+ }
+ });
+ };
+ json_run_tool();
}
});
-var NumberToolParameter = function(name, label, min, max, init_value) {
+/**
+ * Tool parameters.
+ */
+var ToolParameter = function(name, label, html) {
this.name = name;
this.label = label;
+ this.html = html;
+};
+
+var NumberParameter = function(name, label, html, min, max) {
+ ToolParameter.call(this, name, label, html)
this.min = min;
this.max = max;
- this.value = init_value;
-}
-
-// Uses a dictionary to construct a tool object.
-var get_tool_from_dict = function(tool_dict) {
- if (obj_length(tool_dict) === 0) {
- return undefined;
- }
-
- // Get tool.
- var tool_name = tool_dict.name;
- var params_dict = tool_dict.params;
- var params = Array();
- for (var i = 0; i < params_dict.length; i++) {
- var param_dict = params_dict[i];
- var
- name = param_dict.name,
- label = param_dict.label,
- type = param_dict.type,
- min = param_dict.min,
- max = param_dict.max,
- value = param_dict.value;
- params[params.length] = new NumberToolParameter(name, label, min, max, value);
- }
- return new Tool(tool_name, params);
};
/**
@@ -864,6 +935,9 @@
this.index = index;
this.value = value;
};
+/**
+ * Number filters have a min, max as well as a low, high; low and high are used
+ */
var NumberFilter = function(name, index) {
this.name = name;
// Index into payload to filter.
@@ -872,21 +946,25 @@
this.low = -Number.MAX_VALUE;
this.high = Number.MAX_VALUE;
// Slide min/max. These values are used to set/update slider.
- this.slider_min = Number.MAX_VALUE;
- this.slider_max = -Number.MAX_VALUE;
+ this.min = Number.MAX_VALUE;
+ this.max = -Number.MAX_VALUE;
// UI Slider element and label that is associated with filter.
this.slider = null;
this.slider_label = null;
};
-$.extend(NumberFilter.prototype, {
- // Returns true if filter can be applied to element.
+extend(NumberFilter.prototype, {
+ /**
+ * Returns true if filter can be applied to element.
+ */
applies_to: function(element) {
if (element.length > this.index) {
return true;
}
return false;
},
- // Returns true iff element is in [low, high]; range is inclusive.
+ /**
+ * Returns true iff element is in [low, high]; range is inclusive.
+ */
keep: function(element) {
if ( !this.applies_to( element ) ) {
// No element to filter on.
@@ -894,7 +972,9 @@
}
return (element[this.index] >= this.low && element[this.index] <= this.high);
},
- // Update filter's min and max values based on element's values.
+ /**
+ * Update filter's min and max values based on element's values.
+ */
update_attrs: function(element) {
var updated = false;
if (!this.applies_to(element) ) {
@@ -902,29 +982,32 @@
}
// Update filter's min, max based on element values.
- if (element[this.index] < this.slider_min) {
- this.slider_min = element[this.index];
+ if (element[this.index] < this.min) {
+ this.min = Math.floor(element[this.index]);
updated = true;
}
- if (element[this.index] > this.slider_max) {
- this.slider_max = element[this.index];
- updated = false;
+ if (element[this.index] > this.max) {
+ this.max = Math.ceil(element[this.index]);
+ updated = true;
}
return updated;
},
- // Update filter's slider.
+ /**
+ * Update filter's slider.
+ */
update_ui_elt: function () {
var
slider_min = this.slider.slider("option", "min"),
slider_max = this.slider.slider("option", "max");
- if (this.slider_min < slider_min || this.slider_max > slider_max) {
- // Need to update slider.
- this.slider.slider("option", "min", this.slider_min);
- this.slider.slider("option", "max", this.slider_max);
+ if (this.min < slider_min || this.max > slider_max) {
+ // Update slider min, max, step.
+ this.slider.slider("option", "min", this.min);
+ this.slider.slider("option", "max", this.max);
+ this.slider.slider("option", "step", get_slider_step(this.min, this.max));
// Refresh slider:
// TODO: do we want to keep current values or reset to min/max?
// Currently we reset values:
- this.slider.slider("option", "values", [this.slider_min, this.slider_max]);
+ this.slider.slider("option", "values", [this.min, this.max]);
// To use the current values.
//var values = this.slider.slider( "option", "values" );
//this.slider.slider( "option", "values", values );
@@ -932,7 +1015,9 @@
}
});
-// Parse filters dict and return filters.
+/**
+ * Parse filters dict and return filters.
+ */
var get_filters_from_dict = function(filters_dict) {
var filters = [];
for (var i = 0; i < filters_dict.length; i++) {
@@ -947,6 +1032,9 @@
return filters;
};
+/**
+ * Container for track configuration data.
+ */
var TrackConfig = function( options ) {
this.track = options.track;
this.params = options.params;
@@ -956,7 +1044,7 @@
}
this.onchange = options.onchange
}
-$.extend( TrackConfig.prototype, {
+extend( TrackConfig.prototype, {
restore_values: function( values ) {
var track_config = this;
$.each( this.params, function( index, param ) {
@@ -1036,6 +1124,15 @@
});
/**
+ * Tiles for TiledTracks.
+ */
+var Tile = function(track, canvas, histo_max) {
+ this.track = track;
+ this.canvas = canvas;
+ this.histo_max = histo_max;
+};
+
+/**
* Tracks are objects can be added to the View.
*
* Track object hierarchy:
@@ -1078,7 +1175,7 @@
this.content_div = $("<div class='track-content'>").appendTo(this.container_div);
this.parent_element.append(this.container_div);
};
-$.extend( Track.prototype, {
+extend(Track.prototype, {
/**
* Initialize and draw the track.
*/
@@ -1159,7 +1256,7 @@
}
});
-var TiledTrack = function(filters, tool, parent_track) {
+var TiledTrack = function(filters, tool_dict, parent_track) {
var track = this,
view = track.view;
@@ -1168,7 +1265,7 @@
// filters_available is determined by data, filters_visible is set by user.
this.filters_available = false;
this.filters_visible = false;
- this.tool = (tool !== undefined ? get_tool_from_dict( tool ) : undefined);
+ this.tool = (tool_dict !== undefined && obj_length(tool_dict) > 0 ? new Tool(this, tool_dict) : undefined);
//
// TODO: Right now there is only the notion of a parent track and multiple child tracks. However,
@@ -1185,6 +1282,66 @@
// Init HTML elements for tool, filters.
//
+ // Function that supports inline text editing of slider values for tools, filters.
+ // Enable users to edit parameter's value via a text box.
+ var edit_slider_values = function(container, span, slider) {
+ container.click(function() {
+ var cur_value = span.text();
+ max = parseFloat(slider.slider("option", "max")),
+ input_size = (max <= 1 ? 4 : max <= 1000000 ? max.toString().length : 6),
+ multi_value = false;
+ // Increase input size if there are two values.
+ if (slider.slider("option", "values")) {
+ input_size = 2*input_size + 1;
+ multi_value = true;
+ }
+ span.text("");
+ // Temporary input for changing value.
+ $("<input type='text'/>").attr("size", input_size).attr("maxlength", input_size)
+ .attr("value", cur_value).appendTo(span).focus().select()
+ .click(function(e) {
+ // Don't want click to propogate up to values_span and restart everything.
+ e.stopPropagation();
+ }).blur(function() {
+ $(this).remove();
+ span.text(cur_value);
+ }).keyup(function(e) {
+ if (e.keyCode === 27) {
+ // Escape key.
+ $(this).trigger("blur");
+ } else if (e.keyCode === 13) {
+ //
+ // Enter/return key initiates callback. If new value(s) are in slider range,
+ // change value (which calls slider's change() function).
+ //
+ var slider_min = slider.slider("option", "min"),
+ slider_max = slider.slider("option", "max"),
+ invalid = function(a_val) {
+ return (isNaN(a_val) || a_val > slider_max || a_val < slider_min);
+ },
+ new_value = $(this).val();
+ if (!multi_value) {
+ new_value = parseFloat(new_value);
+ if (invalid(new_value)) {
+ alert("Parameter value must be in the range [" + slider_min + "-" + slider_max + "]");
+ return $(this);
+ }
+ }
+ else { // Multi value.
+ new_value = new_value.split("-");
+ new_value = [parseFloat(new_value[0]), parseFloat(new_value[1])];
+ if (invalid(new_value[0]) || invalid(new_value[1])) {
+ alert("Parameter value must be in the range [" + slider_min + "-" + slider_max + "]");
+ return $(this);
+ }
+ }
+ slider.slider((multi_value ? "values" : "value"), new_value);
+ }
+ });
+ });
+ };
+
+
// If track has parent:
// -replace drag handle with child-track icon button; (TODO: eventually, we'll want to be able
// to make a set of child tracks dragable.)
@@ -1201,6 +1358,8 @@
// Disable dragging, double clicking on div so that actions on slider do not impact viz.
this.filters_div.bind("drag", function(e) {
e.stopPropagation();
+ }).bind("click", function(e) {
+ e.stopPropagation();
}).bind("dblclick", function(e) {
e.stopPropagation();
});
@@ -1209,36 +1368,49 @@
// Set up filter label (name, values).
var filter_label = $("<div/>").addClass("slider-label").appendTo(filter_div)
- var name_span = $("<span/>").addClass("name").appendTo(filter_label);
- name_span.text(filter.name + " "); // Extra spacing to separate name and values
- var values_span = $("<span/>").addClass("values").appendTo(filter_label);
+ var name_span = $("<span/>").addClass("slider-name").text(filter.name + " ").appendTo(filter_label);
+ var values_span = $("<span/>");
+ var values_span_container = $("<span/>").addClass("slider-value").appendTo(filter_label).append("[").append(values_span).append("]");
// Set up slider for filter.
- // TODO: generate custom interaction elements based on filter type.
var slider_div = $("<div/>").addClass("slider").appendTo(filter_div);
filter.control_element = $("<div/>").attr("id", filter.name + "-filter-control").appendTo(slider_div);
+ var prev_values = [0,0];
filter.control_element.slider({
range: true,
min: Number.MAX_VALUE,
max: -Number.MIN_VALUE,
values: [0, 0],
slide: function(event, ui) {
- var values = ui.values;
- // Set new values in UI.
- values_span.text("[" + values[0] + "-" + values[1] + "]");
- // Set new values in filter.
- filter.low = values[0];
- filter.high = values[1];
- // Redraw track.
- track.draw(true, true);
+ //
+ // Always update UI values, but set timeout for doing more--especially drawing--
+ // so that viz is more responsive.
+ //
+ prev_values = ui.values;
+ values_span.text(ui.values[0] + "-" + ui.values[1]);
+ setTimeout(function() {
+ if (ui.values[0] == prev_values[0] && ui.values[1] == prev_values[1]) {
+ var values = ui.values;
+ // Set new values in UI.
+ values_span.text(values[0] + "-" + values[1]);
+ // Set new values in filter.
+ filter.low = values[0];
+ filter.high = values[1];
+ // Redraw track.
+ track.draw(true, true);
+ }
+ }, 50);
},
- change: function( event, ui ) {
- filter.control_element.slider("option", "slide").call( filter.control_element, event, ui );
+ change: function(event, ui) {
+ filter.control_element.slider("option", "slide").call(filter.control_element, event, ui);
}
});
filter.slider = filter.control_element;
filter.slider_label = values_span;
+ // Enable users to edit slider values via text box.
+ edit_slider_values(values_span_container, values_span, filter.control_element);
+
// Add to clear floating layout.
$("<div style='clear: both;'/>").appendTo(filter_div);
});
@@ -1247,102 +1419,8 @@
// Create dynamic tool div.
//
if (this.tool) {
- // Create div elt for tool UI.
- this.dynamic_tool_div = $("<div/>").addClass("dynamic-tool").hide();
+ this.dynamic_tool_div = this.tool.parent_div;
this.header_div.after(this.dynamic_tool_div);
- // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz.
- this.dynamic_tool_div.bind( "drag", function(e) {
- e.stopPropagation();
- }).bind("click", function( e ) {
- e.stopPropagation();
- }).bind("dblclick", function( e ) {
- e.stopPropagation();
- });
- var name_div = $("<div class='tool-name'>").appendTo(this.dynamic_tool_div).text(this.tool.name);
- var tool_params = this.tool.params;
- var track = this;
- $.each(this.tool.params, function(index, param) {
- var param_div = $("<div>").addClass("slider-row").appendTo(track.dynamic_tool_div);
-
- // Slider label.
- var label_div = $("<div>").addClass("slider-label").appendTo(param_div);
- var name_span = $("<span class='param-name'>").text(param.label + " ").appendTo(label_div);
- var values_span = $("<span/>").text(param.value);
- var values_span_container = $("<span class='param-value'>").appendTo(label_div).append("[").append(values_span).append("]");
-
- // Slider.
- var slider_div = $("<div/>").addClass("slider").appendTo(param_div);
- var slider = $("<div id='" + param.name + "-param-control'>").appendTo(slider_div);
- // Make step reasonable.
- var step = (param.max <= 1 ? 0.01 : (param.max <= 1000 ? 1 : 5));
- slider.slider({
- min: param.min,
- max: param.max,
- step: step,
- value: param.value,
- slide: function(event, ui) {
- var value = ui.value;
- param.value = value;
- // Set new value in UI.
- if (0 < value && value < 1) {
- value = parseFloat(value).toFixed(2);
- }
- values_span.text(value);
- },
- change: function(event, ui) {
- param.value = ui.value;
- }
- });
-
- // Enable users to edit parameter's value via a text box.
- values_span_container.click(function() {
- var span = values_span,
- cur_value = span.text(),
- // TODO: is there a better way to handle input size when param max is <= 1?
- input_size = (param.max <= 1 ? 4 : param.max.length);
- span.text("");
- // Temporary input for changing value.
- $("<input type='text'/>").attr("size", input_size).attr("maxlength", input_size)
- .attr("value", cur_value).appendTo(span).focus().select()
- .click(function(e) {
- // Don't want click to propogate up to values_span and restart everything.
- e.stopPropagation();
- }).blur(function() {
- $(this).remove();
- span.text(cur_value);
- }).keyup(function(e) {
- if ( e.keyCode === 27 ) {
- // Escape key.
- $(this).trigger("blur");
- } else if ( e.keyCode === 13 ) {
- // Enter/return key sets new value.
- var input = $(this),
- new_value = parseFloat(input.val());
- if (isNaN(new_value) || new_value > param.max || new_value < param.min) {
- // TODO: display popup menu instead of alert?
- alert("Parameter value must be in the range [" + param.min + "-" + param.max + "]");
- return $(this);
- }
- // Update value in three places; update param value last b/c slider updates param value
- // as well and slider may round values depending on its settings.
- span.text(new_value);
- slider.slider('value', new_value);
- param.value = new_value;
- }
- });
- });
-
- // Add to clear floating layout.
- $("<div style='clear: both;'/>").appendTo(param_div);
- });
-
- // Add 'Go' button.
- var run_tool_row = $("<div>").addClass("slider-row").appendTo(this.dynamic_tool_div);
- var run_tool_button = $("<input type='submit'>").attr("value", "Run").appendTo(run_tool_row);
- var track = this;
- run_tool_button.click( function() {
- track.run_tool();
- });
}
//
@@ -1403,7 +1481,7 @@
}
*/
};
-$.extend( TiledTrack.prototype, Track.prototype, {
+extend(TiledTrack.prototype, Track.prototype, {
/**
* Make popup menu for track name.
*/
@@ -1467,7 +1545,7 @@
//
if (track.tool) {
// Show/hide dynamic tool menu item.
- var text = (track.dynamic_tool_div.is(":visible") ? "Hide Tool" : "Show Tool");
+ var text = (track.dynamic_tool_div.is(":visible") ? "Hide tool" : "Show tool");
track_dropdown[text] = function() {
// Set track name, toggle tool div, and remake menu.
if (!track.dynamic_tool_div.is(":visible")) {
@@ -1521,10 +1599,10 @@
high = this.view.high,
range = high - low,
width = this.view.container.width(),
- resolution = this.view.resolution;
-
- var parent_element = $("<div style='position: relative;'></div>"),
- w_scale = width / range;
+ // w_scale units are pixels per base.
+ w_scale = width / range,
+ resolution = this.view.resolution,
+ parent_element = $("<div style='position: relative;'></div>");
if (!clear_after) { this.content_div.children().remove(); }
this.content_div.append( parent_element );
@@ -1551,15 +1629,17 @@
}
//
- // Actions to take after tiles have been drawn:
- // (1) remove old tile(s);
- // (2) update filtering UI elements.
+ // Post-draw actions:
//
- if (clear_after) {
- var track = this;
- var intervalId = setInterval(function() {
- if (obj_length(draw_tile_dict) === 0) {
- // All tiles have been drawn; clear out track content in order to show the most recent content.
+ var track = this;
+ var intervalId = setInterval(function() {
+ if (obj_length(draw_tile_dict) === 0) {
+ // All tiles have been drawn.
+ clearInterval(intervalId);
+
+ // Clear tiles?
+ if (clear_after) {
+ // Clear out track content in order to show the most recent content.
// Most recent content is the div with children (tiles) most recently appended to track.
// However, do not delete recently-appended empty content as calls to draw() may still be active
// and using these divs.
@@ -1575,12 +1655,38 @@
remove = true;
}
}
+ }
+
+ //
+ // Update filter attributes, UI.
+ //
- // Method complete; do not call it again.
- clearInterval(intervalId);
+ // Update filtering UI.
+ for (var f = 0; f < track.filters.length; f++) {
+ track.filters[f].update_ui_elt();
}
- }, 50);
- }
+
+ // Determine if filters are available; this is based on the example feature.
+ var filters_available = false;
+ if (track.example_feature) {
+ for (var f = 0; f < track.filters.length; f++) {
+ if (track.filters[f].applies_to(track.example_feature)) {
+ filters_available = true;
+ break;
+ }
+ }
+ }
+
+ // If filter availability changed, hide filter div if necessary and update menu.
+ if (track.filters_available !== filters_available) {
+ track.filters_available = filters_available;
+ if (!track.filters_available) {
+ track.filters_div.hide();
+ }
+ track.make_name_popup_menu();
+ }
+ }
+ }, 50);
//
// Draw child tracks.
@@ -1593,6 +1699,8 @@
var track = this;
// Put a 50ms delay on drawing so that if the user scrolls fast, we don't load extra data
var draw_and_show_tile = function(id, result, resolution, tile_index, parent_element, w_scale, seq_data) {
+ // DEBUG: this is still called too many times when moving slowly,
+ // console.log( "draw_and_show_tile", resolution, tile_index, w_scale );
returned_tile = track.draw_tile(result, resolution, tile_index, parent_element, w_scale, seq_data)
// Wrap element in div for background
@@ -1631,23 +1739,17 @@
// Really draw tile: get data, seq data if available, and draw tile.
//
$.when(track.data_cache.get_data(view.chrom, tile_low, tile_high, track.mode,
- resolution, track.data_url_extra_params)).then(function() {
- // Data available for track.
- var result = track.data_cache.get_data(view.chrom, tile_low, tile_high, track.mode,
- resolution, track.data_url_extra_params);
+ resolution, track.data_url_extra_params)).then(function(tile_data) {
// If sequence data needed, get that and draw. Otherwise draw.
- if (view.reference_track && w_scale > CHAR_WIDTH_PX) {
+ if (view.reference_track && w_scale > view.canvas_manager.char_width_px) {
$.when(view.reference_track.data_cache.get_data(view.chrom, tile_low, tile_high,
track.mode, resolution,
- view.reference_track.data_url_extra_params)).then(function() {
- var seq_data = view.reference_track.data_cache.get_data(view.chrom, tile_low, tile_high,
- track.mode, resolution,
- view.reference_track.data_url_extra_params);
- draw_and_show_tile(id, result, resolution, tile_index, parent_element, w_scale, seq_data);
+ view.reference_track.data_url_extra_params)).then(function(seq_data) {
+ draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale, seq_data);
});
}
else {
- draw_and_show_tile(id, result, resolution, tile_index, parent_element, w_scale);
+ draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale);
}
});
}
@@ -1678,40 +1780,7 @@
parent_element.append(tile_element);
track.max_height = Math.max(track.max_height, tile_element.height());
track.content_div.css("height", track.max_height + "px");
- parent_element.children().css("height", track.max_height + "px");
-
- if (track.hidden) { return; }
-
- //
- // Update filter attributes, UI.
- // TODO: this could be done after all tiles are drawn, but there's no reliable way to detect
- // that right now.
- //
-
- // Update filtering UI.
- for (var f = 0; f < track.filters.length; f++) {
- track.filters[f].update_ui_elt();
- }
-
- // Determine if filters are available; this is based on the example feature.
- var filters_available = false;
- if (track.example_feature) {
- for (var f = 0; f < track.filters.length; f++) {
- if (track.filters[f].applies_to(track.example_feature)) {
- filters_available = true;
- break;
- }
- }
- }
-
- // If filter availability changed, hide filter div if necessary and update menu.
- if (track.filters_available !== filters_available) {
- track.filters_available = filters_available;
- if (!track.filters_available) {
- track.filters_div.hide();
- }
- track.make_name_popup_menu();
- }
+ parent_element.children().css("height", track.max_height + "px");
},
// Set track as the overview track in the visualization.
set_overview: function() {
@@ -1725,66 +1794,6 @@
}
$(window).trigger("resize");
},
- // Run track's tool.
- run_tool: function() {
- // Put together params for running tool.
- var url_params = {
- dataset_id: this.original_dataset_id,
- chrom: this.view.chrom,
- low: this.view.low,
- high: this.view.high,
- tool_id: this.tool.name
- };
- $.extend(url_params, this.tool.get_param_values_dict());
-
- //
- // Create track for tool's output immediately to provide user feedback.
- //
- var
- current_track = this,
- // Set name of track to include tool name, parameters, and region used.
- track_name = url_params.tool_id +
- current_track.tool_region_and_parameters_str(url_params.chrom, url_params.low, url_params.high),
- new_track;
-
- // TODO: add support for other kinds of tool data tracks.
- if (current_track.track_type === 'FeatureTrack') {
- new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track);
- }
-
- this.add_track(new_track);
- new_track.content_div.text("Starting job.");
- view.has_changes = true;
-
- // Run tool.
- var json_run_tool = function() {
- $.getJSON(run_tool_url, url_params, function(track_data) {
- if (track_data === "no converter") {
- // No converter available for input datasets, so cannot run tool.
- new_track.container_div.addClass("error");
- new_track.content_div.text(DATA_NOCONVERTER);
- }
- else if (track_data.error) {
- // General error.
- new_track.container_div.addClass("error");
- new_track.content_div.text(DATA_CANNOT_RUN_TOOL + track_data.message);
- }
- else if (track_data === "pending") {
- // Converting/indexing input datasets; show message and try again.
- new_track.container_div.addClass("pending");
- new_track.content_div.text("Converting input data so that it can be easily reused.");
- setTimeout(json_run_tool, 2000);
- }
- else {
- // Job submitted and running.
- new_track.dataset_id = track_data.dataset_id;
- new_track.content_div.text("Running job.");
- new_track.init();
- }
- });
- };
- json_run_tool();
- },
/**
* Utility function that creates a label string describing the region and parameters of a track's tool.
*/
@@ -1808,6 +1817,7 @@
this.child_tracks_container.show();
}
this.child_tracks.push(child_track);
+ this.view.has_changes = true;
},
/**
* Remove a child track from this track.
@@ -1823,7 +1833,7 @@
Track.call( this, null, view, parent_element );
this.container_div.addClass( "label-track" );
};
-$.extend( LabelTrack.prototype, Track.prototype, {
+extend( LabelTrack.prototype, Track.prototype, {
draw: function() {
var view = this.view,
range = view.high - view.low,
@@ -1854,7 +1864,6 @@
view.reference_track = this;
this.left_offset = 200;
this.height_px = 12;
- this.font = DEFAULT_FONT;
this.container_div.addClass( "reference-track" );
this.content_div.css("background", "none");
this.content_div.css("min-height", "0px");
@@ -1864,7 +1873,7 @@
this.data_cache = new DataManager(CACHED_DATA, this, false);
this.tile_cache = new Cache(CACHED_TILES_LINE);
};
-$.extend(ReferenceTrack.prototype, TiledTrack.prototype, {
+extend(ReferenceTrack.prototype, TiledTrack.prototype, {
/**
* Draw ReferenceTrack tile.
*/
@@ -1872,19 +1881,16 @@
var track = this,
tile_length = DENSITY * resolution;
- if (w_scale > CHAR_WIDTH_PX) {
+ if (w_scale > this.view.canvas_manager.char_width_px) {
if (seq === null) {
track.content_div.css("height", "0px");
return;
}
- var canvas = document.createElement("canvas");
- if (window.G_vmlCanvasManager) { G_vmlCanvasManager.initElement(canvas); } // EXCANVAS HACK
- canvas = $(canvas);
-
- var ctx = canvas.get(0).getContext("2d");
- canvas.get(0).width = Math.ceil( tile_length * w_scale + track.left_offset);
- canvas.get(0).height = track.height_px;
- ctx.font = DEFAULT_FONT;
+ var canvas = this.view.canvas_manager.new_canvas();
+ var ctx = canvas.getContext("2d");
+ canvas.width = Math.ceil( tile_length * w_scale + track.left_offset);
+ canvas.height = track.height_px;
+ ctx.font = ctx.canvas.manager.default_font;
ctx.textAlign = "center";
for (var c = 0, str_len = seq.length; c < str_len; c++) {
var c_start = Math.round(c * w_scale);
@@ -1938,10 +1944,14 @@
this.height_px = this.track_config.values.height;
this.vertical_range = this.track_config.values.max_value - this.track_config.values.min_value;
- // Add control for resizing
- // Trickery here to deal with the hovering drag handle, can probably be
- // pulled out and reused.
- (function( track ){
+ this.add_resize_handle();
+};
+extend(LineTrack.prototype, TiledTrack.prototype, {
+ add_resize_handle: function () {
+ // Add control for resizing
+ // Trickery here to deal with the hovering drag handle, can probably be
+ // pulled out and reused.
+ var track = this;
var in_handle = false;
var in_drag = false;
var drag_control = $( "<div class='track-resize'>" )
@@ -1969,9 +1979,7 @@
if ( ! in_handle ) { drag_control.hide(); }
track.track_config.values.height = track.height_px;
}).appendTo( track.container_div );
- })(this);
-};
-$.extend(LineTrack.prototype, TiledTrack.prototype, {
+ },
predraw_init: function() {
var track = this,
track_id = track.view.tracks.indexOf(track);
@@ -2012,98 +2020,22 @@
return;
}
- var track = this,
- tile_low = tile_index * DENSITY * resolution,
+ var tile_low = tile_index * DENSITY * resolution,
tile_length = DENSITY * resolution,
- key = resolution + "_" + tile_index,
- params = { hda_ldda: this.hda_ldda, dataset_id: this.dataset_id, resolution: this.view.resolution };
+ width = Math.ceil( tile_length * w_scale ),
+ height = this.height_px;
+ // Create canvas
+ var canvas = this.view.canvas_manager.new_canvas();
+ canvas.width = width,
+ canvas.height = height;
- var canvas = document.createElement("canvas"),
- data = result.data;
- if (window.G_vmlCanvasManager) { G_vmlCanvasManager.initElement(canvas); } // EXCANVAS HACK
- canvas = $(canvas);
-
- canvas.get(0).width = Math.ceil( tile_length * w_scale );
- canvas.get(0).height = track.height_px;
- var ctx = canvas.get(0).getContext("2d"),
- in_path = false,
- min_value = track.prefs.min_value,
- max_value = track.prefs.max_value,
- vertical_range = track.vertical_range,
- total_frequency = track.total_frequency,
- height_px = track.height_px,
- mode = track.mode;
-
- // Pixel position of 0 on the y axis
- var y_zero = Math.round( height_px + min_value / vertical_range * height_px );
-
- // Line at 0.0
- ctx.beginPath();
- ctx.moveTo( 0, y_zero );
- ctx.lineTo( tile_length * w_scale, y_zero );
- // ctx.lineWidth = 0.5;
- ctx.fillStyle = "#aaa";
- ctx.stroke();
+ // Paint line onto full canvas
+ var ctx = canvas.getContext("2d");
+ var painter = new painters.LinePainter( result.data, tile_low, tile_low + tile_length,
+ this.prefs.min_value, this.prefs.max_value, this.prefs.color, this.mode );
+ painter.draw( ctx, width, height );
- ctx.beginPath();
- ctx.fillStyle = track.prefs.color;
- var x_scaled, y, delta_x_px;
- if (data.length > 1) {
- delta_x_px = Math.ceil((data[1][0] - data[0][0]) * w_scale);
- } else {
- delta_x_px = 10;
- }
- for (var i = 0, len = data.length; i < len; i++) {
- x_scaled = Math.round((data[i][0] - tile_low) * w_scale);
- y = data[i][1];
- if (y === null) {
- if (in_path && mode === "Filled") {
- ctx.lineTo(x_scaled, height_px);
- }
- in_path = false;
- continue;
- }
- if (y < min_value) {
- y = min_value;
- } else if (y > max_value) {
- y = max_value;
- }
-
- if (mode === "Histogram") {
- // y becomes the bar height in pixels, which is the negated for canvas coords
- y = Math.round( y / vertical_range * height_px );
- ctx.fillRect(x_scaled, y_zero, delta_x_px, - y );
- } else if (mode === "Intensity" ) {
- y = 255 - Math.floor( (y - min_value) / vertical_range * 255 );
- ctx.fillStyle = "rgb(" +y+ "," +y+ "," +y+ ")";
- ctx.fillRect(x_scaled, 0, delta_x_px, height_px);
- } else {
- // console.log(y, track.min_value, track.vertical_range, (y - track.min_value) / track.vertical_range * track.height_px);
- y = Math.round( height_px - (y - min_value) / vertical_range * height_px );
- // console.log(canvas.get(0).height, canvas.get(0).width);
- if (in_path) {
- ctx.lineTo(x_scaled, y);
- } else {
- in_path = true;
- if (mode === "Filled") {
- ctx.moveTo(x_scaled, height_px);
- ctx.lineTo(x_scaled, y);
- } else {
- ctx.moveTo(x_scaled, y);
- }
- }
- }
- }
- if (mode === "Filled") {
- if (in_path) {
- ctx.lineTo( x_scaled, y_zero );
- ctx.lineTo( 0, y_zero );
- }
- ctx.fill();
- } else {
- ctx.stroke();
- }
return canvas;
}
});
@@ -2148,14 +2080,25 @@
this.show_labels_scale = 0.001;
this.showing_details = false;
this.summary_draw_height = 30;
- this.default_font = DEFAULT_FONT;
this.inc_slots = {};
this.start_end_dct = {};
this.tile_cache = new Cache(CACHED_TILES_FEATURE);
this.data_cache = new DataManager(20, this);
this.left_offset = 200;
+
+ this.painter = painters.LinkedFeaturePainter;
};
-$.extend(FeatureTrack.prototype, TiledTrack.prototype, {
+extend(FeatureTrack.prototype, TiledTrack.prototype, {
+ update_auto_mode: function( mode ) {
+ if ( this.mode == "Auto" ) {
+ if ( mode == "no_detail" ) {
+ mode = "reduced to feature spans";
+ } else if ( mode == "summary_tree" ) {
+ mode = "reduced to coverage histogram";
+ }
+ this.mode_div.text( "Auto (" + mode + ")" );
+ }
+ },
/**
* Place features in slots for drawing (i.e. pack features).
* this.inc_slots[level] is created in this method. this.inc_slots[level]
@@ -2164,27 +2107,292 @@
* Returns the number of slots used to pack features.
*/
incremental_slots: function(level, features, mode) {
- //
+
// Get/create incremental slots for level. If display mode changed,
// need to create new slots.
- //
- var inc_slots = this.inc_slots[level];
+
+ var dummy_context = this.view.canvas_manager.dummy_context,
+ inc_slots = this.inc_slots[level];
if (!inc_slots || (inc_slots.mode !== mode)) {
- inc_slots = {};
- inc_slots.w_scale = level;
+ inc_slots = new (slotting.FeatureSlotter)( level, mode === "Pack", MAX_FEATURE_DEPTH, function ( x ) { return dummy_context.measureText( x ) } );
inc_slots.mode = mode;
this.inc_slots[level] = inc_slots;
- this.start_end_dct[level] = {};
+ }
+
+ return inc_slots.slot_features( features );
+ },
+ /**
+ * Draw FeatureTrack tile.
+ */
+ draw_tile: function(result, resolution, tile_index, parent_element, w_scale, ref_seq) {
+ var track = this,
+ tile_low = tile_index * DENSITY * resolution,
+ tile_high = ( tile_index + 1 ) * DENSITY * resolution,
+ tile_span = tile_high - tile_low,
+ width = Math.ceil( tile_span * w_scale ),
+ mode = this.mode,
+ min_height = 25,
+ left_offset = this.left_offset,
+ slots,
+ required_height;
+
+ // Set display mode if Auto.
+ if (mode === "Auto") {
+ if (result.dataset_type === "summary_tree") {
+ mode = result.dataset_type;
+ } else if (result.extra_info === "no_detail") {
+ mode = "no_detail";
+ } else {
+ // Choose b/t Squish and Pack.
+ // Proxy measures for using Squish:
+ // (a) error message re: limiting number of features shown;
+ // (b) X number of features shown;
+ // (c) size of view shown.
+ // TODO: cannot use (a) and (b) because it requires coordinating mode across tiles;
+ // fix this so that tiles are redrawn as necessary to use the same mode.
+ //if ( (result.message && result.message.match(/^Only the first [\d]+/)) ||
+ // (result.data && result.data.length > 2000) ||
+ var data = result.data;
+ if ( (data.length && data.length < 4) ||
+ (this.view.high - this.view.low > MIN_SQUISH_VIEW_WIDTH) ) {
+ mode = "Squish";
+ } else {
+ mode = "Pack";
+ }
+ }
+ this.update_auto_mode( mode );
}
- //
+ // Drawing the summary tree (feature coverage histogram)
+ if ( mode === "summary_tree" ) {
+ // Set height of parent_element
+ required_height = this.summary_draw_height;
+ parent_element.parent().css("height", Math.max(this.height_px, required_height) + "px");
+ // Add label to container div showing maximum count
+ // TODO: this shouldn't be done at the tile level
+ this.container_div.find(".yaxislabel").remove();
+ var max_label = $("<div />").addClass('yaxislabel');
+ max_label.text( result.max );
+ max_label.css({ position: "absolute", top: "22px", left: "10px" });
+ max_label.prependTo(this.container_div);
+ // Create canvas
+ var canvas = this.view.canvas_manager.new_canvas();
+ canvas.width = width + left_offset;
+ // Extra padding at top of summary tree
+ canvas.height = required_height + SUMMARY_TREE_TOP_PADDING;
+ // Paint summary tree into canvas
+ var painter = new painters.SummaryTreePainter( result.data, result.delta, result.max, tile_low, tile_high, this.prefs.show_counts );
+ var ctx = canvas.getContext("2d");
+ // Deal with left_offset by translating
+ ctx.translate( left_offset, SUMMARY_TREE_TOP_PADDING );
+ painter.draw( ctx, width, required_height );
+ // Canvas element is returned
+ return canvas;
+ }
+
+ // Start dealing with row-by-row tracks
+
+ // If working with a mode where slotting is neccesary, update the incremental slotting
+ var slots, slots_required = 1;
+ if ( mode === "no_detail" || mode === "Squish" || mode === "Pack" ) {
+ slots_required = this.incremental_slots(w_scale, result.data, mode);
+ slots = this.inc_slots[w_scale].slots;
+ }
+
+ // Filter features
+ var filtered = [];
+ if ( result.data ) {
+ for (var i = 0, len = result.data.length; i < len; i++) {
+ var feature = result.data[i];
+ var hide_feature = false;
+ var filter;
+ for (var f = 0, flen = this.filters.length; f < flen; f++) {
+ filter = this.filters[f];
+ filter.update_attrs(feature);
+ if (!filter.keep(feature)) {
+ hide_feature = true;
+ break;
+ }
+ }
+ if (!hide_feature) {
+ filtered.push( feature );
+ }
+ }
+ }
+
+ // Create painter, and canvas of sufficient size to contain all features
+ // HACK: ref_seq will only be defined for ReadTracks, and only the ReadPainter accepts that argument
+ var painter = new (this.painter)( filtered, tile_low, tile_high, this.prefs, mode, ref_seq );
+ // FIXME: ERROR_PADDING is an ugly gap most of the time
+ var required_height = painter.get_required_height( slots_required ) + ERROR_PADDING;
+ var canvas = this.view.canvas_manager.new_canvas();
+
+ canvas.width = width + left_offset;
+ canvas.height = required_height;
+
+ parent_element.parent().css("height", Math.max(this.height_px, required_height) + "px");
+ // console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
+ var ctx = canvas.getContext("2d");
+ ctx.fillStyle = this.prefs.block_color;
+ ctx.font = ctx.canvas.manager.default_font;
+ ctx.textAlign = "right";
+ this.container_div.find(".yaxislabel").remove();
+
+ // If there is a message, draw it on canvas so that it moves around with canvas, and make the border red
+ // to indicate region where message is applicable
+ if (result.message) {
+ $(canvas).css({
+ "border-top": "1px solid red"
+ });
+
+ ctx.fillStyle = "red";
+ ctx.textAlign = "left";
+ var old_base = ctx.textBaseline;
+ ctx.textBaseline = "top";
+ ctx.fillText(result.message, left_offset, 0);
+ ctx.textBaseline = old_base;
+
+ // If there's no data, return.
+ if (!result.data) {
+ return canvas;
+ }
+ }
+
+ // Set example feature. This is needed so that track can update its UI based on feature attributes.
+ this.example_feature = (result.data.length ? result.data[0] : undefined);
+
+ // Draw features
+ ctx.translate( left_offset, ERROR_PADDING );
+ painter.draw( ctx, width, required_height, slots );
+
+ return canvas;
+ }
+});
+
+var VcfTrack = function(name, view, hda_ldda, dataset_id, prefs, filters) {
+ FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters);
+ this.track_type = "VcfTrack";
+ this.painter = painters.VariantPainter;
+};
+
+extend(VcfTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype);
+
+
+var ReadTrack = function (name, view, hda_ldda, dataset_id, prefs, filters) {
+ FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters);
+
+ this.track_config = new TrackConfig( {
+ track: this,
+ params: [
+ { key: 'block_color', label: 'Block color', type: 'color', default_value: '#444' },
+ { key: 'label_color', label: 'Label color', type: 'color', default_value: 'black' },
+ { key: 'show_insertions', label: 'Show insertions', type: 'bool', default_value: false },
+ { key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
+ { key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true },
+ { key: 'mode', type: 'string', default_value: this.mode, hidden: true },
+ ],
+ saved_values: prefs,
+ onchange: function() {
+ this.track.tile_cache.clear();
+ this.track.draw();
+ }
+ });
+ this.prefs = this.track_config.values;
+
+ this.track_type = "ReadTrack";
+ this.painter = painters.ReadPainter;
+ this.make_name_popup_menu();
+};
+extend(ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype);
+
+/**
+ * Feature track that displays data generated from tool.
+ */
+var ToolDataFeatureTrack = function(name, view, hda_ldda, dataset_id, prefs, filters, parent_track) {
+ FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters, {}, parent_track);
+ this.track_type = "ToolDataFeatureTrack";
+
+ // Set up track to fetch initial data from raw data URL when the dataset--not the converted datasets--
+ // is ready.
+ this.data_url = raw_data_url;
+ this.data_query_wait = 1000;
+ this.dataset_check_url = dataset_state_url;
+};
+
+extend(ToolDataFeatureTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
+ /**
+ * For this track type, the predraw init sets up postdraw init.
+ */
+ predraw_init: function() {
+ // Postdraw init: once data has been fetched, reset data url, wait time and start indexing.
+ var track = this;
+ var post_init = function() {
+ if (track.data_cache.size() === 0) {
+ // Track still drawing initial data, so do nothing.
+ setTimeout(post_init, 300);
+ }
+ else {
+ // Track drawing done: reset dataset check, data URL, wait time and get dataset state to start
+ // indexing.
+ track.data_url = default_data_url;
+ track.data_query_wait = DEFAULT_DATA_QUERY_WAIT;
+ track.dataset_state_url = converted_datasets_state_url;
+ $.getJSON(track.dataset_state_url, {dataset_id : track.dataset_id, hda_ldda: track.hda_ldda}, function(track_data) {});
+ }
+ };
+ post_init();
+ }
+});
+
+// Exports
+
+exports.View = View;
+exports.LineTrack = LineTrack;
+exports.FeatureTrack = FeatureTrack;
+exports.ReadTrack = ReadTrack;
+
+// End trackster_module encapsulation
+};
+
+// ---- To be extracted ------------------------------------------------------
+
+// ---- Feature Packing ----
+
+// Encapsulation
+var slotting_module = function(require, exports) {
+
+// HACK: LABEL_SPACING is currently duplicated between here and painters
+var LABEL_SPACING = 2,
+ PACK_SPACING = 5;
+
+/**
+ * FeatureSlotter determines slots in which to draw features for vertical
+ * packing.
+ *
+ * This implementation is incremental, any feature assigned a slot will be
+ * retained for slotting future features.
+ */
+exports.FeatureSlotter = function ( w_scale, include_label, max_rows, measureText ) {
+ this.slots = {};
+ this.start_end_dct = {};
+ this.w_scale = w_scale;
+ this.include_label = include_label;
+ this.max_rows = max_rows;
+ this.measureText = measureText;
+}
+
+/**
+ * Slot a set of features, `this.slots` will be updated with slots by id, and
+ * the largest slot required for the passed set of features is returned
+ */
+extend( exports.FeatureSlotter.prototype, {
+ slot_features: function( features ) {
+ var w_scale = this.w_scale, inc_slots = this.slots, start_end_dct = this.start_end_dct,
+ undone = [], slotted = [], highest_slot = 0, max_rows = this.max_rows;
+
// If feature already exists in slots (from previously seen tiles), use the same slot,
// otherwise if not seen, add to "undone" list for slot calculation.
- //
- var w_scale = inc_slots.w_scale,
- undone = [], slotted = [],
- highest_slot = 0, // To measure how big to draw canvas
- max_low = this.view.max_low;
+
// TODO: Should calculate zoom tile index, which will improve performance
// by only having to look at a smaller subset
// if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
@@ -2198,16 +2406,14 @@
undone.push(i);
}
}
-
- //
+
// Slot unslotted features.
- //
- var start_end_dct = this.start_end_dct[level];
// Find the first slot such that current feature doesn't overlap any other features in that slot.
// Returns -1 if no slot was found.
var find_slot = function(f_start, f_end) {
- for (var slot_num = 0; slot_num <= MAX_FEATURE_DEPTH; slot_num++) {
+ // TODO: Fix constants
+ for (var slot_num = 0; slot_num <= max_rows; slot_num++) {
var has_overlap = false,
slot = start_end_dct[slot_num];
if (slot !== undefined) {
@@ -2236,15 +2442,16 @@
feature_end = feature[2],
feature_name = feature[3],
// Where to start, end drawing on screen.
- f_start = Math.floor( (feature_start - max_low) * w_scale ),
- f_end = Math.ceil( (feature_end - max_low) * w_scale ),
- text_len = CONTEXT.measureText(feature_name).width,
+ f_start = Math.floor( feature_start * w_scale ),
+ f_end = Math.ceil( feature_end * w_scale ),
+ text_len = this.measureText(feature_name).width,
text_align;
// Update start, end drawing locations to include feature name.
// Try to put the name on the left, if not, put on right.
- if (feature_name !== undefined && mode === "Pack") {
+ if (feature_name !== undefined && this.include_label ) {
// Add gap for label spacing and extra pack space padding
+ // TODO: Fix constants
text_len += (LABEL_SPACING + PACK_SPACING);
if (f_start - text_len >= 0) {
f_start -= text_len;
@@ -2257,6 +2464,7 @@
// Find slot.
var slot_num = find_slot(f_start, f_end);
+
/*
if (slot_num < 0) {
@@ -2275,7 +2483,7 @@
if (slot_num >= 0) {
console.log(feature_uid, "found slot with text on the right");
}
-
+
}
*/
// Do slotting.
@@ -2308,188 +2516,325 @@
}
*/
return highest_slot + 1;
- },
- /**
- * Draw summary tree on canvas.
- */
- draw_summary_tree: function(canvas, points, delta, max, w_scale, required_height, tile_low, left_offset) {
- var
- // Set base Y so that max label and data do not overlap. Base Y is where rectangle bases
- // start. However, height of each rectangle is relative to required_height; hence, the
- // max rectangle is required_height.
- base_y = required_height + LABEL_SPACING + CHAR_HEIGHT_PX;
- delta_x_px = Math.ceil(delta * w_scale);
+ }
+});
+
+// End slotting_module encapsulation
+};
+
+// ---- Painters ----
+
+var painters_module = function(require, exports){
+
+/**
+ * Draw a dashed line on a canvas using filled rectangles. This function is based on:
+ * http://vetruvet.blogspot.com/2010/10/drawing-dashed-lines-on-html5-canvas.h…
+ * However, that approach uses lines, which don't seem to render as well, so use
+ * rectangles instead.
+ */
+var dashedLine = function(ctx, x1, y1, x2, y2, dashLen) {
+ if (dashLen === undefined) { dashLen = 4; }
+ var dX = x2 - x1;
+ var dY = y2 - y1;
+ var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
+ var dashX = dX / dashes;
+ var dashY = dY / dashes;
+ var q;
+
+ for (q = 0; q < dashes; q++, x1 += dashX, y1 += dashY) {
+ if (q % 2 !== 0) {
+ continue;
+ }
+ ctx.fillRect(x1, y1, dashLen, 1);
+ }
+};
+
+/**
+ * Draw an isosceles triangle that points down.
+ */
+var drawDownwardEquilateralTriangle = function(ctx, down_vertex_x, down_vertex_y, side_len) {
+ // Compute other two points of triangle.
+ var
+ x1 = down_vertex_x - side_len/2,
+ x2 = down_vertex_x + side_len/2,
+ y = down_vertex_y - Math.sqrt( side_len*3/2 );
- var max_label = $("<div />").addClass('yaxislabel');
- max_label.text(max);
+ // Draw and fill.
+ ctx.beginPath();
+ ctx.moveTo(x1, y);
+ ctx.lineTo(x2, y);
+ ctx.lineTo(down_vertex_x, down_vertex_y);
+ ctx.lineTo(x1, y);
+
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fill();
+ ctx.stroke();
+ ctx.closePath();
+};
+
+/**
+ * SummaryTreePainter, a histogram showing number of intervals in a region
+ */
+var SummaryTreePainter = function( data, delta, max, view_start, view_end, show_counts ) {
+ // Data and data properties
+ this.data = data;
+ this.delta = delta;
+ this.max = max;
+ // View
+ this.view_start = view_start;
+ this.view_end = view_end;
+ // Drawing prefs
+ this.show_counts = show_counts;
+}
+
+SummaryTreePainter.prototype.draw = function( ctx, width, height ) {
+
+ var view_start = this.view_start,
+ view_range = this.view_end - this.view_start,
+ w_scale = width / view_range;
+
+ var points = this.data, delta = this.delta, max = this.max,
+ // Set base Y so that max label and data do not overlap. Base Y is where rectangle bases
+ // start. However, height of each rectangle is relative to required_height; hence, the
+ // max rectangle is required_height.
+ base_y = height;
+ delta_x_px = Math.ceil(delta * w_scale);
+
+ ctx.save();
+
+ for (var i = 0, len = points.length; i < len; i++) {
- max_label.css({ position: "absolute", top: "22px", left: "10px" });
- max_label.prependTo(this.container_div);
-
- var ctx = canvas.get(0).getContext("2d");
- for (var i = 0, len = points.length; i < len; i++) {
- var x = Math.floor( (points[i][0] - tile_low) * w_scale );
- var y = points[i][1];
-
- if (!y) { continue; }
- var y_px = y / max * required_height;
-
- ctx.fillStyle = "black";
- ctx.fillRect(x + left_offset, base_y - y_px, delta_x_px, y_px);
-
- // Draw number count if it can fit the number with some padding, otherwise things clump up
- var text_padding_req_x = 4;
- if (this.prefs.show_counts && (ctx.measureText(y).width + text_padding_req_x) < delta_x_px) {
- ctx.fillStyle = "#666";
- ctx.textAlign = "center";
- ctx.fillText(y, x + left_offset + (delta_x_px/2), 10);
+ var x = Math.floor( (points[i][0] - view_start) * w_scale );
+ var y = points[i][1];
+
+ if (!y) { continue; }
+ var y_px = y / max * height;
+
+ ctx.fillStyle = "black";
+ ctx.fillRect( x, base_y - y_px, delta_x_px, y_px );
+
+ // Draw number count if it can fit the number with some padding, otherwise things clump up
+ var text_padding_req_x = 4;
+ if (this.show_counts && (ctx.measureText(y).width + text_padding_req_x) < delta_x_px) {
+ ctx.fillStyle = "#666";
+ ctx.textAlign = "center";
+ ctx.fillText(y, x + (delta_x_px/2), 10);
+ }
+ }
+
+ ctx.restore();
+}
+
+var LinePainter = function( data, view_start, view_end, min_value, max_value, color, mode ) {
+ // Data and data properties
+ this.data = data;
+ // View
+ this.view_start = view_start;
+ this.view_end = view_end;
+ // Drawing prefs
+ this.min_value = min_value;
+ this.max_value = max_value;
+ this.color = color;
+ this.mode = mode;
+ this.overflow_color = "#F66";
+}
+
+LinePainter.prototype.draw = function( ctx, width, height ) {
+ var
+ in_path = false,
+ min_value = this.min_value,
+ max_value = this.max_value,
+ vertical_range = max_value - min_value,
+ height_px = height,
+ view_start = this.view_start,
+ view_range = this.view_end - this.view_start,
+ w_scale = width / view_range,
+ mode = this.mode,
+ data = this.data;
+
+ ctx.save();
+
+ // Pixel position of 0 on the y axis
+ var y_zero = Math.round( height + min_value / vertical_range * height );
+
+ // Line at 0.0
+ if ( mode !== "Intensity" ) {
+ ctx.fillStyle = "#aaa";
+ ctx.fillRect( 0, y_zero, width, 1 );
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = this.color;
+ var x_scaled, y, delta_x_px;
+ if (data.length > 1) {
+ delta_x_px = Math.ceil((data[1][0] - data[0][0]) * w_scale);
+ } else {
+ delta_x_px = 10;
+ }
+ for (var i = 0, len = data.length; i < len; i++) {
+ x_scaled = Math.round((data[i][0] - view_start) * w_scale);
+ y = data[i][1];
+ if (y === null) {
+ if (in_path && mode === "Filled") {
+ ctx.lineTo(x_scaled, height_px);
+ }
+ in_path = false;
+ continue;
+ }
+ if (y < min_value) {
+ y = min_value;
+ } else if (y > max_value) {
+ y = max_value;
+ }
+
+ if (mode === "Histogram") {
+ // y becomes the bar height in pixels, which is the negated for canvas coords
+ y = Math.round( y / vertical_range * height_px );
+ ctx.fillRect(x_scaled, y_zero, delta_x_px, - y );
+ } else if (mode === "Intensity" ) {
+ y = 255 - Math.floor( (y - min_value) / vertical_range * 255 );
+ ctx.fillStyle = "rgb(" +y+ "," +y+ "," +y+ ")";
+ ctx.fillRect(x_scaled, 0, delta_x_px, height_px);
+ } else {
+ // console.log(y, track.min_value, track.vertical_range, (y - track.min_value) / track.vertical_range * track.height_px);
+ y = Math.round( height_px - (y - min_value) / vertical_range * height_px );
+ // console.log(canvas.get(0).height, canvas.get(0).width);
+ if (in_path) {
+ ctx.lineTo(x_scaled, y);
+ } else {
+ in_path = true;
+ if (mode === "Filled") {
+ ctx.moveTo(x_scaled, height_px);
+ ctx.lineTo(x_scaled, y);
+ } else {
+ ctx.moveTo(x_scaled, y);
+ }
}
}
+ }
+ if (mode === "Filled") {
+ if (in_path) {
+ ctx.lineTo( x_scaled, y_zero );
+ ctx.lineTo( 0, y_zero );
+ }
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
+
+ // Draw lines at bounderies if overflowing min or max
+ var overflow_min_start = -1,
+ overflow_max_start = -1;
+ ctx.fillStyle = this.overflow_color;
+ for (var i = 0, len = data.length; i < len; i++) {
+ y = data[i][1];
+ x_scaled = Math.round((data[i][0] - view_start) * w_scale);
+ x_minus_scaled = Math.round((data[i][0] - 1 - view_start) * w_scale);
+
+ // If we are in a min/max run, check if it should be ended
+ if ( overflow_max_start >= 0 && ( y === null || y < max_value ) ) {
+ // Value does not exist or is in valid range, any overflow ends
+ ctx.fillRect( overflow_max_start, 0, x_minus_scaled - overflow_max_start + 1, 2 );
+ overflow_max_start = -1;
+ } else if ( overflow_min_start >= 0 && ( y === null || y > min_value ) ) {
+ // Draw bottom overflow bar
+ ctx.fillRect( overflow_min_start, height - 2, x_minus_scaled - overflow_min_start + 1, 2 );
+ overflow_min_start = -1;
+ }
+
+ // Now check if we should start a new one (this may happen on the same
+ // base as above if switching between min/max)
+ if ( y !== null && y > max_value && overflow_max_start < 0 ) {
+ // Top overflows and we are not already in a run of overflow
+ overflow_max_start = x_scaled;
+ } else if ( y !== null && y < min_value && overflow_min_start < 0 ) {
+ // Bottom overflows and we are not already in a run
+ overflow_min_start = x_scaled;
+ }
+ }
+
+ ctx.restore();
+}
+
+var FeaturePainter = function( data, view_start, view_end, prefs, mode ) {
+ this.data = data;
+ this.view_start = view_start;
+ this.view_end = view_end;
+ this.prefs = prefs;
+ this.mode = mode;
+}
+
+extend( FeaturePainter.prototype, {
+
+ get_required_height: function( rows_required ) {
+ // y_scale is the height per row
+ var required_height = y_scale = this.get_row_height(), mode = this.mode;
+ // If using a packing mode, need to multiply by the number of slots used
+ if (mode === "no_detail" || mode === "Squish" || mode === "Pack") {
+ required_height = rows_required * y_scale;
+ }
+ // Pad bottom by half a row, at least 5 px
+ return required_height + Math.max( Math.round( y_scale / 2 ), 5 );
},
- /**
- * Draw feature.
- */
- draw_element: function(ctx, tile_index, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width, left_offset) {
- var
- feature_uid = feature[0],
- feature_start = feature[1],
- // -1 b/c intervals are half-open.
- feature_end = feature[2] - 1,
- feature_name = feature[3],
- f_start = Math.floor( Math.max(0, (feature_start - tile_low) * w_scale) ),
- f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
- y_center = ERROR_PADDING + (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
- thickness, y_start, thick_start = null, thick_end = null,
- block_color = this.prefs.block_color,
- label_color = this.prefs.label_color;
-
- // Dense mode displays the same for all data.
- if (mode === "Dense") {
- ctx.fillStyle = block_color;
- ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, DENSE_FEATURE_HEIGHT);
- }
- else if (mode === "no_detail") {
- // No details for feature, so only one way to display.
- ctx.fillStyle = block_color;
- // TODO: what should width be here?
- ctx.fillRect(f_start + left_offset, y_center + 5, f_end - f_start, DENSE_FEATURE_HEIGHT);
- }
- else { // Mode is either Squish or Pack:
- // Feature details.
- var feature_strand = feature[5],
- feature_ts = feature[6],
- feature_te = feature[7],
- feature_blocks = feature[8];
-
- if (feature_ts && feature_te) {
- thick_start = Math.floor( Math.max(0, (feature_ts - tile_low) * w_scale) );
- thick_end = Math.ceil( Math.min(width, Math.max(0, (feature_te - tile_low) * w_scale)) );
- }
-
- // Set vars that depend on mode.
- var thin_height, thick_height;
- if (mode === "Squish") {
- thin_height = 1;
- thick_height = SQUISH_FEATURE_HEIGHT;
- } else { // mode === "Pack"
- thin_height = 5;
- thick_height = PACK_FEATURE_HEIGHT;
- }
-
- // Draw feature/feature blocks + connectors.
- if (!feature_blocks) {
- // If there are no blocks, treat the feature as one big exon.
- if ( feature.strand ) {
- if (feature.strand === "+") {
- ctx.fillStyle = RIGHT_STRAND_INV;
- } else if (feature.strand === "-") {
- ctx.fillStyle = LEFT_STRAND_INV;
- }
- }
- else { // No strand.
- ctx.fillStyle = block_color;
- }
- ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, thick_height);
- } else {
- // There are feature blocks and mode is either Squish or Pack.
- //
- // Approach: (a) draw whole feature as connector/intron and (b) draw blocks as
- // needed. This ensures that whole feature, regardless of whether it starts with
- // a block, is visible.
- //
+
+ draw: function( ctx, width, height, slots ) {
+
+ var data = this.data, view_start = this.view_start, view_end = this.view_end;
+
+ ctx.save();
+
+ ctx.fillStyle = this.prefs.block_color;
+ ctx.textAlign = "right";
+
+ var view_range = this.view_end - this.view_start,
+ w_scale = width / view_range,
+ y_scale = this.get_row_height();
+
+ for (var i = 0, len = data.length; i < len; i++) {
+ var feature = data[i],
+ feature_uid = feature[0],
+ feature_start = feature[1],
+ feature_end = feature[2],
+ // Slot valid only if features are slotted and this feature is slotted;
+ // feature may not be due to lack of space.
+ slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
- // Draw whole feature as connector/intron.
- var cur_y_center, cur_height;
- if (mode === "Squish") {
- ctx.fillStyle = CONNECTOR_COLOR;
- cur_y_center = y_center + Math.floor(SQUISH_FEATURE_HEIGHT/2) + 1;
- cur_height = 1;
- }
- else { // mode === "Pack"
- if (feature_strand) {
- var cur_y_center = y_center;
- var cur_height = thick_height;
- if (feature_strand === "+") {
- ctx.fillStyle = RIGHT_STRAND;
- } else if (feature_strand === "-") {
- ctx.fillStyle = LEFT_STRAND;
- }
- }
- else {
- ctx.fillStyle = CONNECTOR_COLOR;
- cur_y_center += (SQUISH_FEATURE_HEIGHT/2) + 1;
- cur_height = 1;
- }
- }
- ctx.fillRect(f_start + left_offset, cur_y_center, f_end - f_start, cur_height);
-
- for (var k = 0, k_len = feature_blocks.length; k < k_len; k++) {
- var block = feature_blocks[k],
- block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) ),
- // -1 b/c intervals are half-open.
- block_end = Math.ceil( Math.min(width, Math.max((block[1] - 1 - tile_low) * w_scale)) );
-
- // Skip drawing if block not on tile.
- if (block_start > block_end) { continue; }
-
- // Draw thin block.
- ctx.fillStyle = block_color;
- ctx.fillRect(block_start + left_offset, y_center + (thick_height-thin_height)/2 + 1,
- block_end - block_start, thin_height);
-
- // If block intersects with thick region, draw block as thick.
- if (thick_start !== undefined && !(block_start > thick_end || block_end < thick_start) ) {
- var block_thick_start = Math.max(block_start, thick_start),
- block_thick_end = Math.min(block_end, thick_end);
- ctx.fillRect(block_thick_start + left_offset, y_center + 1,
- block_thick_end - block_thick_start, thick_height);
- }
- }
- }
-
- // Draw label for Pack mode.
- if (mode === "Pack" && feature_start > tile_low) {
- ctx.fillStyle = label_color;
- if (tile_index === 0 && f_start - ctx.measureText(feature_name).width < 0) {
- ctx.textAlign = "left";
- ctx.fillText(feature_name, f_end + left_offset + LABEL_SPACING, y_center + 8);
- } else {
- ctx.textAlign = "right";
- ctx.fillText(feature_name, f_start + left_offset - LABEL_SPACING, y_center + 8);
- }
- ctx.fillStyle = block_color;
+ // Draw feature if there's overlap and mode is dense or feature is slotted (as it must be for all non-dense modes).
+ if ( ( feature_start < view_end && feature_end > view_start ) && (this.mode == "Dense" || slot !== null)) {
+ this.draw_element(ctx, this.mode, feature, slot, view_start, view_end, w_scale, y_scale,
+ width );
}
}
- },
+
+ ctx.restore();
+ }
+});
+
+// Contstants specific to feature tracks moved here (HACKING, these should
+// basically all be configuration options)
+var DENSE_TRACK_HEIGHT = 10,
+ NO_DETAIL_TRACK_HEIGHT = 3,
+ SQUISH_TRACK_HEIGHT = 5,
+ PACK_TRACK_HEIGHT = 10,
+ NO_DETAIL_FEATURE_HEIGHT = 1,
+ DENSE_FEATURE_HEIGHT = 3,
+ SQUISH_FEATURE_HEIGHT = 3,
+ PACK_FEATURE_HEIGHT = 9,
+ LABEL_SPACING = 2,
+ CONNECTOR_COLOR = "#ccc";
+
+var LinkedFeaturePainter = function( data, view_start, view_end, prefs, mode ) {
+ FeaturePainter.call( this, data, view_start, view_end, prefs, mode );
+}
+
+extend( LinkedFeaturePainter.prototype, FeaturePainter.prototype, {
+
/**
- * Returns y_scale based on mode.
+ * Height of a single row, depends on mode
*/
- get_y_scale: function(mode) {
- var y_scale;
- if (mode === "summary_tree") {
- // No scale needed.
- }
- if (mode === "Dense") {
+ get_row_height: function() {
+ var mode = this.mode, y_scale;
+ if (mode === "Dense") {
y_scale = DENSE_TRACK_HEIGHT;
}
else if (mode === "no_detail") {
@@ -2503,174 +2848,172 @@
}
return y_scale;
},
- /**
- * Draw FeatureTrack tile.
- */
- draw_tile: function(result, resolution, tile_index, parent_element, w_scale, ref_seq) {
- var track = this;
- var tile_low = tile_index * DENSITY * resolution,
- tile_high = ( tile_index + 1 ) * DENSITY * resolution,
- tile_span = tile_high - tile_low,
- params = { hda_ldda: track.hda_ldda, dataset_id: track.dataset_id,
- resolution: this.view.resolution, mode: this.mode };
-
- //
- // Create/set/compute some useful vars.
- //
- var width = Math.ceil( tile_span * w_scale ),
- mode = this.mode,
- min_height = 25,
- left_offset = this.left_offset,
- slots, required_height;
+
+ draw_element: function(ctx, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width ) {
+ var
+ feature_uid = feature[0],
+ feature_start = feature[1],
+ // -1 b/c intervals are half-open.
+ feature_end = feature[2] - 1,
+ feature_name = feature[3],
+ f_start = Math.floor( Math.max(0, (feature_start - tile_low) * w_scale) ),
+ f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
+ y_center = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
+ thickness, y_start, thick_start = null, thick_end = null,
+ block_color = this.prefs.block_color,
+ label_color = this.prefs.label_color;
+
+ // Dense mode displays the same for all data.
+ /*
+ if (mode === "Dense") {
+ ctx.fillStyle = block_color;
+ ctx.fillRect(f_start, y_center, f_end - f_start, DENSE_FEATURE_HEIGHT);
+ }
+ */
- var canvas = document.createElement("canvas");
- if (window.G_vmlCanvasManager) { G_vmlCanvasManager.initElement(canvas); } // EXCANVAS HACK
- canvas = $(canvas);
-
- //
- // Set mode if Auto.
- //
- if (mode === "Auto") {
- if (result.dataset_type === "summary_tree") {
- mode = result.dataset_type;
- } else if (result.extra_info === "no_detail") {
- mode = "no_detail";
- } else {
- // Choose b/t Squish and Pack.
- // Proxy measures for using Squish:
- // (a) error message re: limiting number of features shown;
- // (b) X number of features shown;
- // (c) size of view shown.
- // TODO: cannot use (a) and (b) because it requires coordinating mode across tiles;
- // fix this so that tiles are redrawn as necessary to use the same mode.
- //if ( (result.message && result.message.match(/^Only the first [\d]+/)) ||
- // (result.data && result.data.length > 2000) ||
- var data = result.data;
- if ( (data.length && data.length < 4) ||
- (this.view.high - this.view.low > MIN_SQUISH_VIEW_WIDTH) ) {
- mode = "Squish";
- } else {
- mode = "Pack";
- }
- }
- }
-
- var y_scale = this.get_y_scale(mode);
-
- //
- // Pack reads, set required height.
- //
- if (mode === "summary_tree") {
- required_height = this.summary_draw_height;
- }
- if (mode === "Dense") {
- required_height = min_height;
- }
- else if (mode === "no_detail" || mode === "Squish" || mode === "Pack") {
- // Calculate new slots incrementally for this new chunk of data and update height if necessary.
- required_height = this.incremental_slots(w_scale, result.data, mode) * y_scale + min_height;
- slots = this.inc_slots[w_scale];
+ if ( mode == "Dense" ) {
+ slot = 1;
}
- //
- // Set up for drawing.
- //
- canvas.get(0).width = width + left_offset;
- canvas.get(0).height = required_height;
- if (result.dataset_type === "summary_tree") {
- // Increase canvas height in order to display max label.
- canvas.get(0).height += LABEL_SPACING + CHAR_HEIGHT_PX;
- }
- parent_element.parent().css("height", Math.max(this.height_px, required_height) + "px");
- // console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
- var ctx = canvas.get(0).getContext("2d");
- ctx.fillStyle = this.prefs.block_color;
- ctx.font = this.default_font;
- ctx.textAlign = "right";
- this.container_div.find(".yaxislabel").remove();
-
- //
- // Draw summary tree. If tree is drawn, canvas is returned.
- //
- if (mode === "summary_tree") {
- this.draw_summary_tree(canvas, result.data, result.delta, result.max, w_scale, required_height,
- tile_low, left_offset);
- return canvas;
- }
-
- //
- // If there is a message, draw it on canvas so that it moves around with canvas, and make the border red
- // to indicate region where message is applicable
- if (result.message) {
- canvas.css({
- "border-top": "1px solid red"
- });
+ if (mode === "no_detail") {
+ // No details for feature, so only one way to display.
+ ctx.fillStyle = block_color;
+ // TODO: what should width be here?
+ ctx.fillRect(f_start, y_center + 5, f_end - f_start, NO_DETAIL_FEATURE_HEIGHT);
+ }
+ else { // Mode is either Squish or Pack:
+ // Feature details.
+ var feature_strand = feature[4],
+ feature_ts = feature[5],
+ feature_te = feature[6],
+ feature_blocks = feature[7];
+
+ if (feature_ts && feature_te) {
+ thick_start = Math.floor( Math.max(0, (feature_ts - tile_low) * w_scale) );
+ thick_end = Math.ceil( Math.min(width, Math.max(0, (feature_te - tile_low) * w_scale)) );
+ }
+
+ // Set vars that depend on mode.
+ var thin_height, thick_height;
+ if (mode === "Squish" || mode === "Dense" ) {
+ thin_height = 1;
+ thick_height = SQUISH_FEATURE_HEIGHT;
+ } else { // mode === "Pack"
+ thin_height = 5;
+ thick_height = PACK_FEATURE_HEIGHT;
+ }
+
+ // Draw feature/feature blocks + connectors.
+ if (!feature_blocks) {
+ // If there are no blocks, treat the feature as one big exon.
+ if ( feature.strand ) {
+ if (feature.strand === "+") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'right_strand_inv' );
+ } else if (feature.strand === "-") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'left_strand_inv' );
+ }
+ }
+ else { // No strand.
+ ctx.fillStyle = block_color;
+ }
+ ctx.fillRect(f_start, y_center, f_end - f_start, thick_height);
+ } else {
+ // There are feature blocks and mode is either Squish or Pack.
+ //
+ // Approach: (a) draw whole feature as connector/intron and (b) draw blocks as
+ // needed. This ensures that whole feature, regardless of whether it starts with
+ // a block, is visible.
+ //
+
+ // Draw whole feature as connector/intron.
+ var cur_y_center, cur_height;
+ if (mode === "Squish" || mode === "Dense") {
+ ctx.fillStyle = CONNECTOR_COLOR;
+ cur_y_center = y_center + Math.floor(SQUISH_FEATURE_HEIGHT/2) + 1;
+ cur_height = 1;
+ }
+ else { // mode === "Pack"
+ if (feature_strand) {
+ var cur_y_center = y_center;
+ var cur_height = thick_height;
+ if (feature_strand === "+") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'right_strand' );
+ } else if (feature_strand === "-") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'left_strand' );
+ }
+ }
+ else {
+ ctx.fillStyle = CONNECTOR_COLOR;
+ cur_y_center += (SQUISH_FEATURE_HEIGHT/2) + 1;
+ cur_height = 1;
+ }
+ }
+ ctx.fillRect(f_start, cur_y_center, f_end - f_start, cur_height);
+
+ for (var k = 0, k_len = feature_blocks.length; k < k_len; k++) {
+ var block = feature_blocks[k],
+ block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) ),
+ // -1 b/c intervals are half-open.
+ block_end = Math.ceil( Math.min(width, Math.max((block[1] - 1 - tile_low) * w_scale)) );
- ctx.fillStyle = "red";
- ctx.textAlign = "left";
- var old_base = ctx.textBaseline;
- ctx.textBaseline = "top";
- ctx.fillText(result.message, left_offset, 0);
- ctx.textBaseline = old_base;
+ // Skip drawing if block not on tile.
+ if (block_start > block_end) { continue; }
- // If there's no data, return.
- if (!result.data) {
- return canvas;
+ // Draw thin block.
+ ctx.fillStyle = block_color;
+ ctx.fillRect(block_start, y_center + (thick_height-thin_height)/2 + 1,
+ block_end - block_start, thin_height);
+
+ // If block intersects with thick region, draw block as thick.
+ // - No thick is sometimes encoded as thick_start == thick_end, so don't draw in that case
+ if (thick_start !== undefined && feature_te > feature_ts && !(block_start > thick_end || block_end < thick_start) ) {
+ var block_thick_start = Math.max(block_start, thick_start),
+ block_thick_end = Math.min(block_end, thick_end);
+ ctx.fillRect(block_thick_start, y_center + 1,
+ block_thick_end - block_thick_start, thick_height);
+ if ( feature_blocks.length == 1 && mode == "Pack") {
+ // Exactly one block means we have no introns, but do have a distinct "thick" region,
+ // draw arrows over it if in pack mode
+ if (feature_strand === "+") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'right_strand_inv' );
+ } else if (feature_strand === "-") {
+ ctx.fillStyle = ctx.canvas.manager.get_pattern( 'left_strand_inv' );
+ }
+ // If region is wide enough in pixels, pad a bit
+ if ( block_thick_start + 14 < block_thick_end ) {
+ block_thick_start += 2;
+ block_thick_end -= 2;
+ }
+ ctx.fillRect( block_thick_start, y_center + 1,
+ block_thick_end - block_thick_start, thick_height );
+ }
+ }
+ }
+ }
+
+ // Draw label for Pack mode.
+ if (mode === "Pack" && feature_start > tile_low) {
+ ctx.fillStyle = label_color;
+ // FIXME: assumption here that the entire view starts at 0
+ if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
+ ctx.textAlign = "left";
+ ctx.fillText(feature_name, f_end + LABEL_SPACING, y_center + 8);
+ } else {
+ ctx.textAlign = "right";
+ ctx.fillText(feature_name, f_start - LABEL_SPACING, y_center + 8);
+ }
+ ctx.fillStyle = block_color;
}
}
-
- //
- // Set example feature. This is needed so that track can update its UI based on feature attributes.
- //
- this.example_feature = (result.data.length ? result.data[0] : undefined);
-
- //
- // Draw elements.
- //
- var data = result.data;
- for (var i = 0, len = data.length; i < len; i++) {
- var feature = data[i],
- feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- // Slot valid only if features are slotted and this feature is slotted;
- // feature may not be due to lack of space.
- slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
-
- // Apply filters to feature.
- var hide_feature = false;
- var filter;
- for (var f = 0; f < this.filters.length; f++) {
- filter = this.filters[f];
- filter.update_attrs( feature );
- if ( !filter.keep( feature ) ) {
- hide_feature = true;
- break;
- }
- }
- if (hide_feature) {
- continue;
- }
-
- // Draw feature if there's overlap and mode is dense or feature is slotted (as it must be for all non-dense modes).
- if (is_overlap([feature_start, feature_end], [tile_low, tile_high]) && (mode == "Dense" || slot !== null)) {
- this.draw_element(ctx, tile_index, mode, feature, slot, tile_low, tile_high, w_scale, y_scale,
- width, left_offset, ref_seq);
- }
- }
- return canvas;
}
});
-var VcfTrack = function(name, view, hda_ldda, dataset_id, prefs, filters) {
- FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters);
- this.track_type = "VcfTrack";
-};
-$.extend(VcfTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
- /**
- * Draw a VCF entry.
- */
+var VariantPainter = function( data, view_start, view_end, prefs, mode ) {
+ FeaturePainter.call( this, data, view_start, view_end, prefs, mode );
+}
+
+extend( VariantPainter.prototype, FeaturePainter.prototype, {
draw_element: function(ctx, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width) {
var feature = data[i],
feature_uid = feature[0],
@@ -2681,7 +3024,7 @@
// All features need a start, end, and vertical center.
f_start = Math.floor( Math.max(0, (feature_start - tile_low) * w_scale) ),
f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
- y_center = ERROR_PADDING + (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
+ y_center = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
thickness, y_start, thick_start = null, thick_end = null;
if (no_label) {
@@ -2700,7 +3043,7 @@
if (mode !== "Dense" && feature_name !== undefined && feature_start > tile_low) {
// Draw label
ctx.fillStyle = label_color;
- if (tile_index === 0 && f_start - ctx.measureText(feature_name).width < 0) {
+ if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
ctx.textAlign = "left";
ctx.fillText(feature_name, f_end + 2 + left_offset, y_center + 8);
} else {
@@ -2722,39 +3065,54 @@
}
});
-var ReadTrack = function (name, view, hda_ldda, dataset_id, prefs, filters) {
- FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters);
+/**
+ * Compute the type of overlap between two regions. They are assumed to be on the same chrom/contig.
+ * The overlap is computed relative to the second region; hence, OVERLAP_START indicates that the first
+ * region overlaps the start (but not the end) of the second region.
+ */
+var NO_OVERLAP = 1001, CONTAINS = 1002, OVERLAP_START = 1003, OVERLAP_END = 1004, CONTAINED_BY = 1005;
+var compute_overlap = function(first_region, second_region) {
+ var
+ first_start = first_region[0], first_end = first_region[1],
+ second_start = second_region[0], second_end = second_region[1],
+ overlap;
+ if (first_start < second_start) {
+ if (first_end < second_start) {
+ overlap = NO_OVERLAP;
+ }
+ else if (first_end <= second_end) {
+ overlap = OVERLAP_START;
+ }
+ else { // first_end > second_end
+ overlap = CONTAINS;
+ }
+ }
+ else { // first_start >= second_start
+ if (first_start > second_end) {
+ overlap = NO_OVERLAP;
+ }
+ else if (first_end <= second_end) {
+ overlap = CONTAINED_BY;
+ }
+ else {
+ overlap = OVERLAP_END;
+ }
+ }
- this.track_config = new TrackConfig( {
- track: this,
- params: [
- { key: 'block_color', label: 'Block color', type: 'color', default_value: '#444' },
- { key: 'label_color', label: 'Label color', type: 'color', default_value: 'black' },
- { key: 'show_insertions', label: 'Show insertions', type: 'bool', default_value: false },
- { key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
- { key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true },
- { key: 'mode', type: 'string', default_value: this.mode, hidden: true },
- ],
- saved_values: prefs,
- onchange: function() {
- this.track.tile_cache.clear();
- this.track.draw();
- }
- });
- this.prefs = this.track_config.values;
-
- this.track_type = "ReadTrack";
- this.make_name_popup_menu();
-};
-$.extend(ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
+ return overlap;
+}
+
+var ReadPainter = function( data, view_start, view_end, prefs, mode, ref_seq ) {
+ FeaturePainter.call( this, data, view_start, view_end, prefs, mode );
+ this.ref_seq = ref_seq;
+}
+
+extend( ReadPainter.prototype, FeaturePainter.prototype, {
/**
* Returns y_scale based on mode.
*/
- get_y_scale: function(mode) {
- var y_scale;
- if (mode === "summary_tree") {
- // No scale needed.
- }
+ get_row_height: function() {
+ var y_scale, mode = this.mode;
if (mode === "Dense") {
y_scale = DENSE_TRACK_HEIGHT;
}
@@ -2763,7 +3121,7 @@
}
else { // mode === "Pack"
y_scale = PACK_TRACK_HEIGHT;
- if (this.track_config.values.show_insertions) {
+ if (this.prefs.show_insertions) {
y_scale *= 2;
}
}
@@ -2772,20 +3130,22 @@
/**
* Draw a single read.
*/
- draw_read: function(ctx, mode, w_scale, tile_low, tile_high, feature_start, cigar, orig_seq, y_center, ref_seq) {
+ draw_read: function(ctx, mode, w_scale, tile_low, tile_high, feature_start, cigar, orig_seq, y_center) {
ctx.textAlign = "center";
var track = this,
tile_region = [tile_low, tile_high],
base_offset = 0,
seq_offset = 0,
- gap = 0;
+ gap = 0
+ ref_seq = this.ref_seq,
+ char_width_px = ctx.canvas.manager.char_width_px;
// Keep list of items that need to be drawn on top of initial drawing layer.
var draw_last = [];
// Gap is needed so that read is offset and hence first base can be drawn on read.
// TODO-FIX: using this gap offsets reads so that their start is not visually in sync with other tracks.
- if ((mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > CHAR_WIDTH_PX) {
+ if ((mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > char_width_px) {
gap = Math.round(w_scale/2);
}
if (!cigar) {
@@ -2819,12 +3179,12 @@
var seq = orig_seq.slice(seq_offset, seq_offset + cig_len);
if (gap > 0) {
ctx.fillStyle = this.prefs.block_color;
- ctx.fillRect(s_start + this.left_offset - gap, y_center + 1, s_end - s_start, 9);
+ ctx.fillRect(s_start - gap, y_center + 1, s_end - s_start, 9);
ctx.fillStyle = CONNECTOR_COLOR;
// TODO: this can be made much more efficient by computing the complete sequence
// to draw and then drawing it.
for (var c = 0, str_len = seq.length; c < str_len; c++) {
- if (this.track_config.values.show_differences && ref_seq) {
+ if (this.prefs.show_differences && ref_seq) {
var ref_char = ref_seq[seq_start - tile_low + c];
if (!ref_char || ref_char.toLowerCase() === seq[c].toLowerCase()) {
continue;
@@ -2832,16 +3192,13 @@
}
if (seq_start + c >= tile_low && seq_start + c <= tile_high) {
var c_start = Math.floor( Math.max(0, (seq_start + c - tile_low) * w_scale) );
- ctx.fillText(seq[c], c_start + this.left_offset, y_center + 9);
+ ctx.fillText(seq[c], c_start, y_center + 9);
}
}
} else {
ctx.fillStyle = this.prefs.block_color;
// TODO: This is a pretty hack-ish way to fill rectangle based on mode.
- ctx.fillRect(s_start + this.left_offset,
- y_center + (this.mode !== "Dense" ? 4 : 5),
- s_end - s_start,
- (mode !== "Dense" ? SQUISH_FEATURE_HEIGHT : DENSE_FEATURE_HEIGHT) );
+ ctx.fillRect(s_start, y_center + 4, s_end - s_start, SQUISH_FEATURE_HEIGHT);
}
}
seq_offset += cig_len;
@@ -2849,14 +3206,14 @@
break;
case "N": // Skipped bases.
ctx.fillStyle = CONNECTOR_COLOR;
- ctx.fillRect(s_start + this.left_offset - gap, y_center + 5, s_end - s_start, 1);
+ ctx.fillRect(s_start - gap, y_center + 5, s_end - s_start, 1);
//ctx.dashedLine(s_start + this.left_offset, y_center + 5, this.left_offset + s_end, y_center + 5);
// No change in seq_offset because sequence not used when skipping.
base_offset += cig_len;
break;
case "D": // Deletion.
ctx.fillStyle = "red";
- ctx.fillRect(s_start + this.left_offset - gap, y_center + 4, s_end - s_start, 3);
+ ctx.fillRect(s_start - gap, y_center + 4, s_end - s_start, 3);
// TODO: is this true? No change in seq_offset because sequence not used when skipping.
base_offset += cig_len;
break;
@@ -2868,21 +3225,21 @@
// the sequence region and the tile region.
var
seq_tile_overlap = compute_overlap([seq_start, seq_start + cig_len], tile_region),
- insert_x_coord = this.left_offset + s_start - gap;
+ insert_x_coord = s_start - gap;
if (seq_tile_overlap !== NO_OVERLAP) {
var seq = orig_seq.slice(seq_offset, seq_offset + cig_len);
// Insertion point is between the sequence start and the previous base: (-gap) moves
// back from sequence start to insertion point.
- if (this.track_config.values.show_insertions) {
+ if (this.prefs.show_insertions) {
//
// Show inserted sequence above, centered on insertion point.
//
// Draw sequence.
// X center is offset + start - <half_sequence_length>
- var x_center = this.left_offset + s_start - (s_end - s_start)/2;
- if ( (mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > CHAR_WIDTH_PX) {
+ var x_center = s_start - (s_end - s_start)/2;
+ if ( (mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > char_width_px) {
// Draw sequence container.
ctx.fillStyle = "yellow";
ctx.fillRect(x_center - gap, y_center - 9, s_end - s_start, 9);
@@ -2906,7 +3263,7 @@
// Draw sequence.
for (var c = 0, str_len = seq.length; c < str_len; c++) {
var c_start = Math.floor( Math.max(0, (seq_start + c - tile_low) * w_scale) );
- ctx.fillText(seq[c], c_start + this.left_offset - (s_end - s_start)/2, y_center);
+ ctx.fillText(seq[c], c_start - (s_end - s_start)/2, y_center);
}
}
else {
@@ -2918,7 +3275,7 @@
}
}
else {
- if ( (mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > CHAR_WIDTH_PX) {
+ if ( (mode === "Pack" || this.mode === "Auto") && orig_seq !== undefined && w_scale > char_width_px) {
// Show insertions with a single number at the insertion point.
draw_last[draw_last.length] = {type: "text", data: [seq.length, insert_x_coord, y_center + 9]};
}
@@ -2947,31 +3304,37 @@
type = item["type"];
data = item["data"];
if (type === "text") {
- ctx.font = "bold " + DEFAULT_FONT;
+ ctx.save();
+ ctx.font = "bold " + ctx.font;
ctx.fillText(data[0], data[1], data[2]);
- ctx.font = DEFAULT_FONT;
+ ctx.restore();
}
else if (type == "triangle") {
- ctx.drawDownwardEquilateralTriangle(data[0], data[1], data[2]);
+ drawDownwardEquilateralTriangle(ctx, data[0], data[1], data[2]);
}
}
},
/**
- * Draw a complete read.
+ * Draw a complete read pair
*/
- draw_element: function(ctx, tile_index, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width, left_offset, ref_seq) {
+ draw_element: function(ctx, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width ) {
// All features need a start, end, and vertical center.
- var
- feature_uid = feature[0],
+ var feature_uid = feature[0],
feature_start = feature[1],
feature_end = feature[2],
feature_name = feature[3],
f_start = Math.floor( Math.max(0, (feature_start - tile_low) * w_scale) ),
f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
- y_center = (mode === "Dense" ? 1 : (1 + slot)) * y_scale,
+ y_center = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
block_color = this.prefs.block_color,
- label_color = this.prefs.label_color;
- gap = 0; // Left-gap for label text since we align chrom text to the position tick
+ label_color = this.prefs.label_color,
+ // Left-gap for label text since we align chrom text to the position tick.
+ gap = 0;
+
+ // TODO: fix gap usage; also see note on gap in draw_read.
+ if ((mode === "Pack" || this.mode === "Auto") && w_scale > ctx.canvas.manager.char_width_px) {
+ var gap = Math.round(w_scale/2);
+ }
// Draw read.
ctx.fillStyle = block_color;
@@ -2984,78 +3347,71 @@
// Draw left/forward read.
if (feature[4][1] >= tile_low && feature[4][0] <= tile_high && feature[4][2]) {
- this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature[4][0], feature[4][2], feature[4][3], y_center, ref_seq);
+ this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature[4][0], feature[4][2], feature[4][3], y_center);
}
// Draw right/reverse read.
if (feature[5][1] >= tile_low && feature[5][0] <= tile_high && feature[5][2]) {
- this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature[5][0], feature[5][2], feature[5][3], y_center, ref_seq);
+ this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature[5][0], feature[5][2], feature[5][3], y_center);
}
// Draw connector.
if (b2_start > b1_end) {
ctx.fillStyle = CONNECTOR_COLOR;
- //ctx.fillRect(b1_end + left_offset, y_center + 5, b2_start - b1_end, 1);
- ctx.dashedLine(b1_end + left_offset, y_center + 5, left_offset + b2_start, y_center + 5);
+ dashedLine(ctx, b1_end - gap, y_center + 5, b2_start - gap, y_center + 5);
}
} else {
// Read is single.
ctx.fillStyle = block_color;
- this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature_start, feature[4], feature[5], y_center, ref_seq);
+ this.draw_read(ctx, mode, w_scale, tile_low, tile_high, feature_start, feature[4], feature[5], y_center);
}
if (mode === "Pack" && feature_start > tile_low) {
// Draw label.
ctx.fillStyle = this.prefs.label_color;
- if ( (mode === "Pack" || this.mode === "Auto") && w_scale > CHAR_WIDTH_PX) {
- var gap = Math.round(w_scale/2);
- }
+ // FIXME: eliminate tile_index
+ var tile_index = 1;
if (tile_index === 0 && f_start - ctx.measureText(feature_name).width < 0) {
ctx.textAlign = "left";
- ctx.fillText(feature_name, f_end + left_offset + LABEL_SPACING - gap, y_center + 8);
+ ctx.fillText(feature_name, f_end + LABEL_SPACING - gap, y_center + 8);
} else {
ctx.textAlign = "right";
- ctx.fillText(feature_name, f_start + left_offset - LABEL_SPACING - gap, y_center + 8);
+ ctx.fillText(feature_name, f_start - LABEL_SPACING - gap, y_center + 8);
}
ctx.fillStyle = block_color;
}
}
});
-/**
- * Feature track that displays data generated from tool.
- */
-var ToolDataFeatureTrack = function(name, view, hda_ldda, dataset_id, prefs, filters, parent_track) {
- FeatureTrack.call(this, name, view, hda_ldda, dataset_id, prefs, filters, {}, parent_track);
- this.track_type = "ToolDataFeatureTrack";
-
- // Set up track to fetch initial data from raw data URL when the dataset--not the converted datasets--
- // is ready.
- this.data_url = raw_data_url;
- this.data_query_wait = 1000;
- this.dataset_check_url = dataset_state_url;
+exports.SummaryTreePainter = SummaryTreePainter;
+exports.LinePainter = LinePainter;
+exports.LinkedFeaturePainter = LinkedFeaturePainter;
+exports.ReadPainter = ReadPainter;
+exports.VariantPainter = VariantPainter;
+
+// End painters_module encapsulation
};
-$.extend(ToolDataFeatureTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
- /**
- * For this track type, the predraw init sets up postdraw init.
- */
- predraw_init: function() {
- // Postdraw init: once data has been fetched, reset data url, wait time and start indexing.
- var track = this;
- var post_init = function() {
- if (track.data_cache.size() === 0) {
- // Track still drawing initial data, so do nothing.
- setTimeout(post_init, 300);
- }
- else {
- // Track drawing done: reset dataset check, data URL, wait time and get dataset state to start
- // indexing.
- track.data_url = default_data_url;
- track.data_query_wait = DEFAULT_DATA_QUERY_WAIT;
- track.dataset_state_url = converted_datasets_state_url;
- $.getJSON(track.dataset_state_url, { dataset_id : track.dataset_id, hda_ldda: track.hda_ldda }, function(track_data) {});
- }
- };
- post_init();
+// Finally, compose and export trackster module exports into globals
+// These will be replaced with require statements in CommonJS
+(function(target){
+ // Faking up a CommonJS like loader here, each module gets a require and
+ // and exports. We avoid resolution problems by just ordering carefully.
+ var modules = {};
+ // Provide a require function
+ var require = function( name ) {
+ return modules[name];
+ };
+ // Run module will run the module_function provided and store in the
+ // require dict using key
+ var run_module = function( key, module_function ) {
+ var exports = {};
+ module_function( require, exports );
+ modules[key] = exports;
+ };
+ // Run all modules
+ run_module( 'slotting', slotting_module );
+ run_module( 'painters', painters_module );
+ run_module( 'trackster', trackster_module );
+ // Export trackster stuff
+ for ( key in modules.trackster ) {
+ target[key] = modules.trackster[key];
}
-});
-
-
+})(window);
\ No newline at end of file
--- a/templates/tracks/browser.mako Sun Mar 27 19:50:50 2011 -0400
+++ b/templates/tracks/browser.mako Tue Apr 05 13:57:14 2011 -0400
@@ -69,6 +69,7 @@
chrom_url = "${h.url_for( action='chroms' )}",
dataset_state_url = "${h.url_for( action='dataset_state' )}",
converted_datasets_state_url = "${h.url_for( action='converted_datasets_state' )}",
+ filters_url = "${h.url_for( action='filters' )}",
addable_track_types = { "LineTrack": LineTrack, "FeatureTrack": FeatureTrack, "ReadTrack": ReadTrack },
view;
--- a/test-data/blastp_rhodopsin_vs_four_human.tabular Sun Mar 27 19:50:50 2011 -0400
+++ b/test-data/blastp_rhodopsin_vs_four_human.tabular Tue Apr 05 13:57:14 2011 -0400
@@ -1,6 +1,6 @@
-gi|57163783|ref|NP_001009242.1| Subject_4 96.55 348 12 0 1 348 1 348 0.0 679
-gi|3024260|sp|P56514.1|OPSD_BUFBU Subject_4 83.33 354 53 2 1 354 1 348 6e-178 605
-gi|283855846|gb|ADB45242.1| Subject_4 94.82 328 17 0 1 328 11 338 0.0 630
-gi|283855823|gb|ADB45229.1| Subject_4 94.82 328 17 0 1 328 11 338 0.0 630
-gi|223523|prf||0811197A Subject_4 93.10 348 23 1 1 347 1 348 0.0 651
-gi|12583665|dbj|BAB21486.1| Subject_4 81.09 349 65 1 1 349 1 348 2e-172 587
+gi|57163783|ref|NP_001009242.1| sp|P08100|OPSD_HUMAN 96.55 348 12 0 1 348 1 348 0.0 679
+gi|3024260|sp|P56514.1|OPSD_BUFBU sp|P08100|OPSD_HUMAN 83.33 354 53 2 1 354 1 348 6e-178 605
+gi|283855846|gb|ADB45242.1| sp|P08100|OPSD_HUMAN 94.82 328 17 0 1 328 11 338 0.0 630
+gi|283855823|gb|ADB45229.1| sp|P08100|OPSD_HUMAN 94.82 328 17 0 1 328 11 338 0.0 630
+gi|223523|prf||0811197A sp|P08100|OPSD_HUMAN 93.10 348 23 1 1 347 1 348 0.0 651
+gi|12583665|dbj|BAB21486.1| sp|P08100|OPSD_HUMAN 81.09 349 65 1 1 349 1 348 2e-172 587
--- a/test-data/tblastn_four_human_vs_rhodopsin.tabular Sun Mar 27 19:50:50 2011 -0400
+++ b/test-data/tblastn_four_human_vs_rhodopsin.tabular Tue Apr 05 13:57:14 2011 -0400
@@ -1,10 +1,10 @@
-sp|P08100|OPSD_HUMAN Subject_1 96.55 348 12 0 1 348 1 1044 0.0 732
-sp|P08100|OPSD_HUMAN Subject_2 84.80 342 51 1 1 341 42 1067 0.0 646
-sp|P08100|OPSD_HUMAN Subject_3 93.24 74 5 0 239 312 3147 3368 1e-72 151
-sp|P08100|OPSD_HUMAN Subject_3 91.53 59 5 0 177 235 2855 3031 1e-72 126
-sp|P08100|OPSD_HUMAN Subject_3 96.40 111 4 0 11 121 1 333 1e-64 229
-sp|P08100|OPSD_HUMAN Subject_3 93.22 59 4 0 119 177 1404 1580 1e-32 122
-sp|P08100|OPSD_HUMAN Subject_3 88.46 26 3 0 312 337 4222 4299 6e-13 57.7
-sp|P08100|OPSD_HUMAN Subject_4 95.09 326 16 0 11 336 1 978 0.0 658
-sp|P08100|OPSD_HUMAN Subject_5 93.39 348 23 0 1 348 1 1044 0.0 711
-sp|P08100|OPSD_HUMAN Subject_6 82.16 342 60 1 1 341 23 1048 0.0 626
+sp|P08100|OPSD_HUMAN gi|57163782|ref|NM_001009242.1| 96.55 348 12 0 1 348 1 1044 0.0 732
+sp|P08100|OPSD_HUMAN gi|2734705|gb|U59921.1|BBU59921 84.80 342 51 1 1 341 42 1067 0.0 646
+sp|P08100|OPSD_HUMAN gi|283855845|gb|GQ290303.1| 93.24 74 5 0 239 312 3147 3368 1e-72 151
+sp|P08100|OPSD_HUMAN gi|283855845|gb|GQ290303.1| 91.53 59 5 0 177 235 2855 3031 1e-72 126
+sp|P08100|OPSD_HUMAN gi|283855845|gb|GQ290303.1| 96.40 111 4 0 11 121 1 333 1e-64 229
+sp|P08100|OPSD_HUMAN gi|283855845|gb|GQ290303.1| 93.22 59 4 0 119 177 1404 1580 1e-32 122
+sp|P08100|OPSD_HUMAN gi|283855845|gb|GQ290303.1| 88.46 26 3 0 312 337 4222 4299 6e-13 57.7
+sp|P08100|OPSD_HUMAN gi|283855822|gb|GQ290312.1| 95.09 326 16 0 11 336 1 978 0.0 658
+sp|P08100|OPSD_HUMAN gi|18148870|dbj|AB062417.1| 93.39 348 23 0 1 348 1 1044 0.0 711
+sp|P08100|OPSD_HUMAN gi|12583664|dbj|AB043817.1| 82.16 342 60 1 1 341 23 1048 0.0 626
--- a/tool-data/shared/ucsc/manual_builds.txt Sun Mar 27 19:50:50 2011 -0400
+++ b/tool-data/shared/ucsc/manual_builds.txt Tue Apr 05 13:57:14 2011 -0400
@@ -698,3 +698,5 @@
Hydra_JCVI Hydra magnipapillata str. 105
Araly1 Arabidopsis lyrata
Zea_mays_B73_RefGen_v2 Maize (Zea mays) chr1=301354135,chr2=237068928,chr3=232140222,chr4=241473566,chr5=217872898,chr6=169174371,chr7=176764813,chr8=175793772,chr9=156750718,chr10=150189513,chr11=7140224
+Homo_sapiens_AK1 Korean Man chrM=16571,chr1=247249719,chr2=242951149,chr3=199501827,chr4=191273063,chr5=180857866,chr6=170899992,chr7=158821424,chr8=146274826,chr9=140273252,chr10=135374737,chr11=134452384,chr12=132349534,chr13=114142980,chr14=106368585,chr15=100338915,chr16=88827254,chr17=78774742,chr18=76117153,chr19=63811651,chr20=62435964,chr21=46944323,chr22=49691432,chrX=154913754,chrY=57772954
+Tcas_3.0 Red Flour Beetle (Tribolium castaneum)
--- a/tool_conf.xml.main Sun Mar 27 19:50:50 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 13:57:14 2011 -0400
@@ -169,6 +169,12 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
+ <section name="Motif Tools" id="motifs">
+ <tool file="rgenetics/rgWebLogo3.xml" />
+ </section>
+ <section name="Multiple Alignments" id="clustal">
+ <tool file="rgenetics/rgClustalw.xml" />
+ </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
--- a/tools/ncbi_blast_plus/ncbi_blastp_wrapper.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/ncbi_blast_plus/ncbi_blastp_wrapper.xml Tue Apr 05 13:57:14 2011 -0400
@@ -133,6 +133,8 @@
<param name="subject" value="rhodopsin_proteins.fasta" ftype="fasta" /><param name="database" value="" /><param name="evalue_cutoff" value="1e-8" />
+ <param name="blast_type" value="blastp" />
+ <param name="out_format" value="6" /><param name="adv_opts_selector" value="advanced" /><param name="filter_query" value="True" /><param name="matrix" value="BLOSUM62" />
--- a/tools/ncbi_blast_plus/ncbi_tblastn_wrapper.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/ncbi_blast_plus/ncbi_tblastn_wrapper.xml Tue Apr 05 13:57:14 2011 -0400
@@ -138,7 +138,7 @@
<output name="output1" file="tblastn_four_human_vs_rhodopsin.tabular" ftype="tabular" /></test><test>
- <!-- Same as above, but parse deflines -->
+ <!-- Same as above, but parse deflines - on BLAST 2.2.25+ makes no difference --><param name="query" value="four_human_proteins.fasta" ftype="fasta" /><param name="db_opts_selector" value="file" /><param name="subject" value="rhodopsin_nucs.fasta" ftype="fasta" />
@@ -151,7 +151,7 @@
<param name="max_hits" value="0" /><param name="word_size" value="0" /><param name="parse_deflines" value="true" />
- <output name="output1" file="tblastn_four_human_vs_rhodopsin_parse_deflines.tabular" ftype="tabular" />
+ <output name="output1" file="tblastn_four_human_vs_rhodopsin.tabular" ftype="tabular" /></test></tests><help>
--- a/tools/new_operations/intersect.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/new_operations/intersect.xml Tue Apr 05 13:57:14 2011 -0400
@@ -28,7 +28,7 @@
<param format="interval,gff" name="input2" type="data" help="Second dataset"><label>that intersect</label></param>
- <param name="min" size="4" type="integer" value="1" help="(bp)">
+ <param name="min" size="4" type="integer" value="1" min="1" help="(bp)"><label>for at least</label></param></inputs>
--- a/tools/new_operations/subtract.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/new_operations/subtract.xml Tue Apr 05 13:57:14 2011 -0400
@@ -31,7 +31,7 @@
<option value="-p">Non-overlapping pieces of intervals</option></param>
- <param name="min" size="4" type="integer" value="1" help="(bp)">
+ <param name="min" size="4" type="integer" value="1" min="1" help="(bp)"><label>where minimal overlap is</label></param></inputs>
--- a/tools/ngs_rna/cufflinks_wrapper.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/ngs_rna/cufflinks_wrapper.xml Tue Apr 05 13:57:14 2011 -0400
@@ -42,7 +42,7 @@
</command><inputs><param format="sam,bam" name="input" type="data" label="SAM or BAM file of aligned RNA-Seq reads" help=""/>
- <param name="max_intron_len" type="integer" value="300000" min="0" max="600000" label="Max Intron Length" help=""/>
+ <param name="max_intron_len" type="integer" value="300000" min="1" max="600000" label="Max Intron Length" help=""/><param name="min_isoform_fraction" type="float" value="0.05" min="0" max="1" label="Min Isoform Fraction" help=""/><param name="pre_mrna_fraction" type="float" value="0.05" min="0" max="1" label="Pre MRNA Fraction" help=""/><param name="min_map_quality" type="integer" value="0" min="0" max="255" label="Min SAM Map Quality" help=""/>
--- a/tools/ngs_rna/tophat_wrapper.py Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/ngs_rna/tophat_wrapper.py Tue Apr 05 13:57:14 2011 -0400
@@ -208,6 +208,10 @@
tmp_stderr.close()
if returncode != 0:
raise Exception, stderr
+
+ # Copy output files from tmp directory to specified files.
+ shutil.copyfile( os.path.join( "tophat_out", "junctions.bed" ), options.junctions_output_file )
+ shutil.copyfile( os.path.join( "tophat_out", "accepted_hits.bam" ), options.accepted_hits_output_file )
# TODO: look for errors in program output.
except Exception, e:
--- a/tools/ngs_rna/tophat_wrapper.xml Sun Mar 27 19:50:50 2011 -0400
+++ b/tools/ngs_rna/tophat_wrapper.xml Tue Apr 05 13:57:14 2011 -0400
@@ -397,8 +397,8 @@
)
</filter></data>
- <data format="bed" name="junctions" label="${tool.name} on ${on_string}: splice junctions" from_work_dir="tophat_out/junctions.bed"/>
- <data format="bam" name="accepted_hits" label="${tool.name} on ${on_string}: accepted_hits" from_work_dir="tophat_out/accepted_hits.bam"/>
+ <data format="bed" name="junctions" label="${tool.name} on ${on_string}: splice junctions"/>
+ <data format="bam" name="accepted_hits" label="${tool.name} on ${on_string}: accepted_hits"/></outputs><tests>
http://bitbucket.org/galaxy/galaxy-central/changeset/b643d662fe14/
changeset: r5344:b643d662fe14
user: fubar
date: 2011-04-05 20:07:10
summary: change to weblogo test jpg comparison and code cleanups to rgCaCo
affected #: 2 files (723 bytes)
--- a/tool_conf.xml.main Tue Apr 05 13:57:14 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 14:07:10 2011 -0400
@@ -169,12 +169,6 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
- <section name="Motif Tools" id="motifs">
- <tool file="rgenetics/rgWebLogo3.xml" />
- </section>
- <section name="Multiple Alignments" id="clustal">
- <tool file="rgenetics/rgClustalw.xml" />
- </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
--- a/tools/rgenetics/rgWebLogo3.xml Tue Apr 05 13:57:14 2011 -0400
+++ b/tools/rgenetics/rgWebLogo3.xml Tue Apr 05 14:07:10 2011 -0400
@@ -5,7 +5,7 @@
#if $range.mode == 'part'
-l "$range.seqstart" -u "$range.seqend"
#end if
- </command>
+ </command><inputs><page><param format="fasta" name="input" type="data" label="Fasta File" />
@@ -71,7 +71,7 @@
<param name = "mode" value="complete" /><param name = "size" value="medium" /><param name = "colours" value="auto" />
- <output name="output" file="rgWebLogo3_test.jpg" ftype="jpg" />
+ <output name="output" file="rgWebLogo3_test.jpg" ftype="jpg" compare="sim_size" delta="10000" /></test></tests>
@@ -90,6 +90,15 @@
----
+**Warning about input Fasta format files**
+
+The Weblogo3 program used by this tool will fail if your fasta sequences are not all EXACTLY the same length.
+
+Fasta alignments from the companion ClustalW Galaxy tool will work but many other fasta files may cause this tool to fail - please do not file
+a Galaxy bug report - this is a feature of the tool and a problem with your source data - not a tool error - please make certain all your fasta
+sequences are the same length!
+
+----
**Attribution**
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Added clustalw and weblogo tools to Main tool_conf. Thanks Ross.
by Bitbucket 05 Apr '11
by Bitbucket 05 Apr '11
05 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/d3fd4d73675c/
changeset: r5341:d3fd4d73675c
user: natefoo
date: 2011-04-05 18:08:42
summary: Added clustalw and weblogo tools to Main tool_conf. Thanks Ross.
affected #: 1 file (207 bytes)
--- a/tool_conf.xml.main Tue Apr 05 11:51:48 2011 -0400
+++ b/tool_conf.xml.main Tue Apr 05 12:08:42 2011 -0400
@@ -169,6 +169,12 @@
<!-- <tool file="hyphy/hyphy_dnds_wrapper.xml" /> --><tool file="evolution/mutate_snp_codon.xml" /></section>
+ <section name="Motif Tools" id="motifs">
+ <tool file="rgenetics/rgWebLogo3.xml" />
+ </section>
+ <section name="Multiple Alignments" id="clustal">
+ <tool file="rgenetics/rgClustalw.xml" />
+ </section><section name="Metagenomic analyses" id="tax_manipulation"><tool file="taxonomy/gi2taxonomy.xml" /><tool file="taxonomy/t2t_report.xml" />
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/a98119b07764/
changeset: r5340:a98119b07764
user: jgoecks
date: 2011-04-05 17:51:48
summary: Refactor and enhance trackster visual analytics: (a) move all visual analytics code into Tool class for encapsulation; (b) put tool outputs in appropriate history when user is rerunning his own tool; (c) enable users not logged in to run tools; (d) use tool HTML to display inputs rather than sliders.
affected #: 9 files (4.7 KB)
--- a/lib/galaxy/visualization/tracks/visual_analytics.py Mon Apr 04 23:27:25 2011 -0400
+++ b/lib/galaxy/visualization/tracks/visual_analytics.py Tue Apr 05 11:51:48 2011 -0400
@@ -1,3 +1,5 @@
+import urllib
+
from galaxy.tools.parameters.basic import IntegerToolParameter, FloatToolParameter, SelectToolParameter
from galaxy.tools.parameters.dynamic_options import DynamicOptions
@@ -28,17 +30,19 @@
tool_param_values = dict( [ ( p.name, p.value ) for p in job.parameters ] )
tool_param_values = tool.params_from_strings( tool_param_values, trans.app, ignore_errors=True )
for name, input in tool.inputs.items():
- if type( input ) == IntegerToolParameter:
- tool_params.append( { 'name' : name, 'label' : input.label, \
- 'value' : tool_param_values.get( name, input.value ), \
- 'type' : 'int', 'min' : input.min, 'max' : input.max } )
- elif type( input ) == FloatToolParameter:
- tool_params.append( { 'name' : name, 'label' : input.label, \
- 'value' : tool_param_values.get( name, input.value ), \
- 'type' : 'float', 'min' : input.min, 'max' : input.max } )
+ if type( input ) == IntegerToolParameter or type( input ) == FloatToolParameter:
+ param_dict = { 'name' : name, 'label' : input.label, \
+ 'value' : tool_param_values.get( name, input.value ), \
+ 'type' : 'number', 'init_value' : input.value,
+ 'html' : urllib.quote( input.get_html() ) }
+ if input.min:
+ param_dict['min'] = input.min
+ if input.max:
+ param_dict['max'] = input.max
+ tool_params.append( param_dict )
elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions:
tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \
- 'options' : [ option[:2] for option in input.get_options( trans, None ) ] } )
+ 'html' : urllib.quote( input.get_html() ) } )
# If tool has parameters that can be interactively modified, return tool.
# Return empty set otherwise.
--- a/lib/galaxy/web/controllers/tracks.py Mon Apr 04 23:27:25 2011 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Tue Apr 05 11:51:48 2011 -0400
@@ -201,7 +201,6 @@
return trans.fill_template( "tracks/new_browser.mako", dbkeys=self._get_dbkeys( trans ), default_dbkey=kwargs.get("default_dbkey", None) )
@web.json
- @web.require_login()
def add_track_async(self, trans, hda_id=None, ldda_id=None):
if hda_id:
hda_ldda = "hda"
@@ -707,8 +706,15 @@
# Set input datasets for tool. Input datasets are subsets of full
# datasets and are based on chrom, low, high.
#
- job_history = trans.get_history( create=True )
- hda_permissions = trans.app.security_agent.history_get_default_permissions( job_history )
+
+ # If user is rerunning own tool, put new data in original dataset's
+ # history. If another user is running tool, put new data in current
+ # history.
+ if original_dataset.history.user == trans.user:
+ working_history = original_dataset.history
+ else:
+ working_history = trans.get_history( create=True )
+ hda_permissions = trans.app.security_agent.history_get_default_permissions( working_history )
messages_list = []
for jida in original_job.input_datasets:
input_dataset = jida.dataset
@@ -730,7 +736,7 @@
name="Subset [%s:%i-%i] of data %i" % \
( chrom, low, high, input_dataset.hid ),
visible=False )
- job_history.add_dataset( new_dataset )
+ working_history.add_dataset( new_dataset )
trans.sa_session.add( new_dataset )
trans.app.security_agent.set_all_dataset_permissions( new_dataset.dataset, hda_permissions )
@@ -753,14 +759,14 @@
# Start tool and handle outputs.
#
try:
- subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=job_history )
+ subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=working_history )
except Exception, e:
# Lots of things can go wrong when trying to execute tool.
return to_json_string( { "error" : True, "message" : e.__class__.__name__ + ": " + str(e) } )
for output in subset_job_outputs.values():
output.visible = False
trans.sa_session.flush()
-
+
# Return new track that corresponds to the original dataset.
output_name = None
for joda in original_job.output_datasets:
--- a/static/june_2007_style/blue/trackster.css Mon Apr 04 23:27:25 2011 -0400
+++ b/static/june_2007_style/blue/trackster.css Tue Apr 05 11:51:48 2011 -0400
@@ -38,10 +38,12 @@
.top-labeltrack{position:relative;border-bottom:solid #999 1px;}
.nav-labeltrack{border-top:solid #999 1px;border-bottom:solid #333 1px;}
input{font:10px verdana;}
-.dynamic-tool,.filters{width:400px;margin-left:0.25em;padding-bottom:0.5em;}
+.dynamic-tool,.filters{width:410px;margin-left:0.25em;padding-bottom:0.5em;}
.slider-row{margin-top:0.4em;margin-left:1em;}
.slider-label{float:left;font-weight:bold;}
.slider{float:right;width:200px;position:relative;}
.tool-name{font-size:110%;font-weight:bold;}
+.param-row{margin-top:0.2em;margin-left:1em;}
+.param-label{float:left;font-weight:bold;padding-top:0.2em;}
.child-track-icon{background:url('../images/fugue/arrow-000-small-bw.png') no-repeat;width:30px;cursor:move;}
.track-resize{background:white url('../images/visualization/draggable_vertical.png') no-repeat top center;position:absolute;right:3px;bottom:-4px;width:14px;height:7px;border:solid #999 1px;z-index:100;}
--- a/static/june_2007_style/trackster.css.tmpl Mon Apr 04 23:27:25 2011 -0400
+++ b/static/june_2007_style/trackster.css.tmpl Tue Apr 05 11:51:48 2011 -0400
@@ -229,7 +229,7 @@
font: 10px verdana;
}
.dynamic-tool, .filters {
- width: 400px;
+ width: 410px;
margin-left: 0.25em;
padding-bottom:0.5em;
}
@@ -237,7 +237,7 @@
margin-top: 0.4em;
margin-left: 1em;
}
-.slider-label {
+.param-label, .slider-label {
float: left;
font-weight: bold;
}
@@ -250,6 +250,15 @@
font-size: 110%;
font-weight: bold;
}
+.param-row {
+ margin-top: 0.2em;
+ margin-left: 1em;
+}
+.param-label{
+ float: left;
+ font-weight: bold;
+ padding-top: 0.2em;
+}
.child-track-icon {
background:url('../images/fugue/arrow-000-small-bw.png') no-repeat;
width: 30px;
--- a/static/scripts/packed/trackster.js Mon Apr 04 23:27:25 2011 -0400
+++ b/static/scripts/packed/trackster.js Tue Apr 05 11:51:48 2011 -0400
@@ -1,1 +1,1 @@
-CanvasRenderingContext2D.prototype.dashedLine=function(c,j,b,h,f){if(f===undefined){f=4}var e=b-c;var d=h-j;var g=Math.floor(Math.sqrt(e*e+d*d)/f);var l=e/g;var k=d/g;var a;for(a=0;a<g;a++,c+=l,j+=k){if(a%2!==0){continue}this.fillRect(c,j,f,1)}};CanvasRenderingContext2D.prototype.drawDownwardEquilateralTriangle=function(b,a,e){var d=b-e/2,c=b+e/2,f=a-Math.sqrt(e*3/2);this.beginPath();this.moveTo(d,f);this.lineTo(c,f);this.lineTo(b,a);this.lineTo(d,f);this.strokeStyle=this.fillStyle;this.fill();this.stroke();this.closePath()};function sortable(a,b){a.bind("drag",{handle:b,relative:true},function(h,j){var g=$(this).parent();var f=g.children();var c;for(c=0;c<f.length;c++){if(j.offsetY<$(f.get(c)).position().top){break}}if(c===f.length){if(this!==f.get(c-1)){g.append(this)}}else{if(this!==f.get(c)){$(this).insertBefore(f.get(c))}}})}var NO_OVERLAP=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005;function compute_overlap(e,b){var g=e[0],f=e[1],d=b[0],c=b[1],a;if(g<d){if(f<d){a=NO_OVERLAP}else{if(f<=c){a=OVERLAP_START}else{a=CONTAINS}}}else{if(g>c){a=NO_OVERLAP}else{if(f<=c){a=CONTAINED_BY}else{a=OVERLAP_END}}}return a}function is_overlap(b,a){return(compute_overlap(b,a)!==NO_OVERLAP)}function get_slider_step(c,a){var b=a-c;return(b<=1?0.01:(b<=1000?1:5))}var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=1,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,ERROR_PADDING=10,LABEL_SPACING=2,PACK_SPACING=5,MIN_SQUISH_VIEW_WIDTH=12000,DEFAULT_FONT="9px Monaco, Lucida Console, monospace",DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=100,DEFAULT_DATA_QUERY_WAIT=5000,MAX_CHROMS_SELECTABLE=100,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset. ",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_CANNOT_RUN_TOOL="Tool cannot be rerun: ",DATA_LOADING="Loading data...",DATA_OK="Ready for display",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}var CONTEXT=DUMMY_CANVAS.getContext("2d");CONTEXT.font=DEFAULT_FONT;var CHAR_WIDTH_PX=CONTEXT.measureText("A").width,CHAR_HEIGHT_PX=9;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!==-1){this.move_key_to_end(b,a)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},move_key_to_end:function(b,a){this.key_ary.splice(a,1);this.key_ary.push(b)},clear:function(){this.obj_cache={};this.key_ary=[]},size:function(){return this.key_ary.length}});var DataManager=function(b,a,c){Cache.call(this,b);this.track=a;this.subset=(c!==undefined?c:true)};$.extend(DataManager.prototype,Cache.prototype,{load_data:function(h,j,d,g,a,f){var c={chrom:h,low:j,high:d,mode:g,resolution:a,dataset_id:this.track.dataset_id,hda_ldda:this.track.hda_ldda};$.extend(c,f);var k=[];for(var e=0;e<this.track.filters.length;e++){k[k.length]=this.track.filters[e].name}c.filter_cols=JSON.stringify(k);var b=this;return $.getJSON(this.track.data_url,c,function(l){b.set_data(j,d,g,l)})},get_data:function(j,k,c,h,b,f){var l=this.get(this.gen_key(k,c,h));if(l){return l}if(this.subset){var m,g,a,e,h,l;for(var d=0;d<this.key_ary.length;d++){m=this.key_ary[d];g=this.split_key(m);a=g[0];e=g[1];if(k>=a&&c<=e){l=this.obj_cache[m];if(l.dataset_type!=="summary_tree"&&l.extra_info!=="no_detail"){this.move_key_to_end(m,d);return l}}}}return this.load_data(j,k,c,h,b,f)},set_data:function(b,c,d,a){return this.set(this.gen_key(b,c,d),a)},gen_key:function(a,c,d){var b=a+"_"+c+"_"+d;return b},split_key:function(a){return a.split("_")}});var View=function(a,d,c,b,e){this.container=a;this.chrom=null;this.vis_id=c;this.dbkey=b;this.title=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init(e);this.canvas_manager=new CanvasManager(a.get(0).ownerDocument);this.reset()};$.extend(View.prototype,{init:function(d){var c=this.container,a=this;this.top_container=$("<div/>").addClass("top-container").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(c);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var b=function(f){if(f.type==="focusout"||(f.keyCode||f.which)===13||(f.keyCode||f.which)===27){if((f.keyCode||f.which)!==27){a.go_to($(this).val())}$(this).hide();$(this).val("");a.location_span.show();a.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",b).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").appendTo(this.nav_controls);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.val(a.chrom+":"+a.low+"-"+a.high);a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a id='zoom-out' />").click(function(){a.zoom_out();a.redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a id='zoom-in' />").click(function(){a.zoom_in();a.redraw()}).appendTo(this.nav_controls);this.load_chroms({low:0},d);this.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())});this.intro_div.show();this.content_div.bind("click",function(f){$(this).find("input").trigger("blur")});this.content_div.bind("dblclick",function(f){a.zoom_in(f.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(f,g){this.current_x=g.offsetX}).bind("drag",function(f,h){var j=h.offsetX-this.current_x;this.current_x=h.offsetX;var g=Math.round(j/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-g)});this.overview_close.bind("click",function(){for(var f=0,e=a.tracks.length;f<e;f++){a.tracks[f].is_overview=false}$(this).siblings().filter("canvas").remove();$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("draginit",function(f,g){if(f.clientX>a.viewport_container.width()-16){return false}}).bind("dragstart",function(f,g){g.original_low=a.low;g.current_height=f.clientY;g.current_x=g.offsetX}).bind("drag",function(h,k){var f=$(this);var l=k.offsetX-k.current_x;var g=f.scrollTop()-(h.clientY-k.current_height);f.scrollTop(g);k.current_height=h.clientY;k.current_x=k.offsetX;var j=Math.round(l/a.viewport_container.width()*(a.high-a.low));a.move_delta(j)}).bind("mousewheel",function(h,k,g,f){if(g){var j=Math.round(-g/a.viewport_container.width()*(a.high-a.low));a.move_delta(j)}});this.top_labeltrack.bind("dragstart",function(f,g){return $("<div />").css({height:a.content_div.height()+a.top_labeltrack.height()+a.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(k,l){$(l.proxy).css({left:Math.min(k.pageX,l.startX),width:Math.abs(k.pageX-l.startX)});var g=Math.min(k.pageX,l.startX)-a.container.offset().left,f=Math.max(k.pageX,l.startX)-a.container.offset().left,j=(a.high-a.low),h=a.viewport_container.width();a.update_location(Math.round(g/h*j)+a.low,Math.round(f/h*j)+a.low)}).bind("dragend",function(l,m){var g=Math.min(l.pageX,m.startX),f=Math.max(l.pageX,m.startX),j=(a.high-a.low),h=a.viewport_container.width(),k=a.low;a.low=Math.round(g/h*j)+k;a.high=Math.round(f/h*j)+k;$(m.proxy).remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window()});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+commatize(b))},load_chroms:function(b,c){b.num=MAX_CHROMS_SELECTABLE;$.extend(b,(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}));var a=this;$.ajax({url:chrom_url,data:b,dataType:"json",success:function(e){if(e.chrom_info.length===0){alert("Invalid chromosome: "+b.chrom);return}if(e.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=e.chrom_info;var h='<option value="">Select Chrom/Contig</option>';for(var g=0,d=a.chrom_data.length;g<d;g++){var f=a.chrom_data[g].chrom;h+='<option value="'+f+'">'+f+"</option>"}if(e.prev_chroms){h+='<option value="previous">Previous '+MAX_CHROMS_SELECTABLE+"</option>"}if(e.next_chroms){h+='<option value="next">Next '+MAX_CHROMS_SELECTABLE+"</option>"}a.chrom_select.html(h);if(c){c()}a.chrom_start_index=e.start_index},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}})},change_chrom:function(e,b,g){if(!e||e==="None"){return}var d=this;if(e==="previous"){d.load_chroms({low:this.chrom_start_index-MAX_CHROMS_SELECTABLE});return}if(e==="next"){d.load_chroms({low:this.chrom_start_index+MAX_CHROMS_SELECTABLE});return}var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){d.load_chroms({chrom:e},function(){d.change_chrom(e,b,g)});return}else{if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len-1;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()}},go_to:function(f){var k=this,a,d,b=f.split(":"),h=b[0],j=b[1];if(j!==undefined){try{var g=j.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}k.change_chrom(h,a,d)},move_fraction:function(c){var a=this;var b=a.high-a.low;this.move_delta(c*b)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);sortable(a.container_div,".draghandle");this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);this.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Tool=function(g){this.name=g.name;this.params=[];var a=g.params;for(var e=0;e<a.length;e++){var d=a[e],c=d.name,b=d.label,f=d.type;if(f==="int"||f==="float"){this.params[this.params.length]=new NumberParameter(c,b,d.min,d.max,d.value)}else{if(f=="select"){this.params[this.params.length]=new SelectParameter(c,b,d.options)}else{console.log("WARNING: unrecognized tool parameter type:",c,f)}}}};$.extend(Tool.prototype,{get_param_values_dict:function(){var b={};for(var a=0;a<this.params.length;a++){var c=this.params[a];b[c.name]=JSON.stringify(c.value)}return b},get_param_values:function(){var b=[];for(var a=0;a<this.params.length;a++){b[a]=this.params[a].value}return b}});var NumberParameter=function(c,b,e,a,d){this.name=c;this.label=b;this.min=e;this.max=a;this.value=d};var SelectParameter=function(c,b,a){this.name=c;this.label=b;this.options=a;this.value=(a.length!==0?a[0][1]:null)};var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.min=Number.MAX_VALUE;this.max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.min){this.min=Math.floor(b[this.index]);a=true}if(b[this.index]>this.max){this.max=Math.ceil(b[this.index]);a=true}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.min<b||this.max>a){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var get_filters_from_dict=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e==="int"||e==="float"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var TrackConfig=function(a){this.track=a.track;this.params=a.params;this.values={};if(a.saved_values){this.restore_values(a.saved_values)}this.onchange=a.onchange};$.extend(TrackConfig.prototype,{restore_values:function(a){var b=this;$.each(this.params,function(c,d){if(a[d.key]!==undefined){b.values[d.key]=a[d.key]}else{b.values[d.key]=d.default_value}})},build_form:function(){var b=this;var a=$("<div />");$.each(this.params,function(f,d){if(!d.hidden){var c="param_"+f;var l=$("<div class='form-row' />").appendTo(a);l.append($("<label />").attr("for",c).text(d.label+":"));if(d.type==="bool"){l.append($('<input type="checkbox" />').attr("id",c).attr("name",c).attr("checked",b.values[d.key]))}else{if(d.type==="color"){var h=b.values[d.key];var g=$("<input />").attr("id",c).attr("name",c).val(h);var j=$("<div class='tipsy tipsy-north' style='position: absolute;' />").hide();var e=$("<div style='background-color: black; padding: 10px;'></div>").appendTo(j);var k=$("<div/>").appendTo(e).farbtastic({width:100,height:100,callback:g,color:h});$("<div />").append(g).append(j).appendTo(l).bind("click",function(m){j.css({left:$(this).position().left+($(g).width()/2)-60,top:$(this).position().top+$(this.height)}).show();$(document).bind("click.color-picker",function(){j.hide();$(document).unbind("click.color-picker")});m.stopPropagation()})}else{l.append($("<input />").attr("id",c).attr("name",c).val(b.values[d.key]))}}}});return a},update_from_form:function(a){var c=this;var b=false;$.each(this.params,function(d,f){if(!f.hidden){var g="param_"+d;var e=a.find("#"+g).val();if(f.type==="float"){e=parseFloat(e)}else{if(f.type==="int"){e=parseInt(e)}else{if(f.type==="bool"){e=a.find("#"+g).is(":checked")}}}if(e!==c.values[f.key]){c.values[f.key]=e;b=true}}});if(b){this.onchange()}}});var Tile=function(a,b,c){this.track=a;this.canvas=b;this.histo_max=c};var Track=function(b,a,e,c,d){this.name=b;this.view=a;this.parent_element=e;this.data_url=(c?c:default_data_url);this.data_url_extra_params={};this.data_query_wait=(d?d:DEFAULT_DATA_QUERY_WAIT);this.dataset_check_url=converted_datasets_state_url;this.container_div=$("<div />").addClass("track").css("position","relative");if(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)};$.extend(Track.prototype,{init:function(){var a=this;a.enabled=false;a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_div.css("height","auto");a.container_div.removeClass("nodata error pending");if(!a.dataset_id){return}$.getJSON(converted_datasets_state_url,{hda_ldda:a.hda_ldda,dataset_id:a.dataset_id,chrom:a.view.chrom},function(b){if(!b||b==="error"||b.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(b.message){var d=a.view.tracks.indexOf(a);var c=$(" <a href='javascript:void(0);'></a>").text("View error").bind("click",function(){show_modal("Trackster Error","<pre>"+b.message+"</pre>",{Close:hide_modal})});a.content_div.append(c)}}else{if(b==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(b==="no data"||(b.data!==undefined&&(b.data===null||b.data.length===0))){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(b==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},a.data_query_wait)}else{if(b.status==="data"){if(b.valid_chroms){a.valid_chroms=b.valid_chroms;a.make_name_popup_menu()}a.content_div.text(DATA_OK);if(a.view.chrom){a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;$.when(a.predraw_init()).done(function(){a.draw()})}}}}}}})},predraw_init:function(){},update_name:function(a){this.old_name=this.name;this.name=a;this.name_div.text(this.name)},revert_name:function(){this.name=this.old_name;this.name_div.text(this.name)}});var TiledTrack=function(b,h,o){var c=this,p=c.view;this.filters=(b!==undefined?get_filters_from_dict(b):[]);this.filters_available=false;this.filters_visible=false;this.tool=(h!==undefined&&obj_length(h)>0?new Tool(h):undefined);this.parent_track=o;this.child_tracks=[];if(c.hidden){return}var k=function(r,s,t){r.click(function(){var u=s.text();max=parseFloat(t.slider("option","max")),input_size=(max<=1?4:max<=1000000?max.toString().length:6),multi_value=false;if(t.slider("option","values")){input_size=2*input_size+1;multi_value=true}s.text("");$("<input type='text'/>").attr("size",input_size).attr("maxlength",input_size).attr("value",u).appendTo(s).focus().select().click(function(v){v.stopPropagation()}).blur(function(){$(this).remove();s.text(u)}).keyup(function(z){if(z.keyCode===27){$(this).trigger("blur")}else{if(z.keyCode===13){var x=t.slider("option","min"),v=t.slider("option","max"),y=function(A){return(isNaN(A)||A>v||A<x)},w=$(this).val();if(!multi_value){w=parseFloat(w);if(y(w)){alert("Parameter value must be in the range ["+x+"-"+v+"]");return $(this)}}else{w=w.split("-");w=[parseFloat(w[0]),parseFloat(w[1])];if(y(w[0])||y(w[1])){alert("Parameter value must be in the range ["+x+"-"+v+"]");return $(this)}}t.slider((multi_value?"values":"value"),w)}}})})};if(this.parent_track){this.header_div.find(".draghandle").removeClass("draghandle").addClass("child-track-icon").addClass("icon-button");this.parent_element.addClass("child-track");this.tool=undefined}this.filters_div=$("<div/>").addClass("filters").hide();this.header_div.after(this.filters_div);this.filters_div.bind("drag",function(r){r.stopPropagation()}).bind("click",function(r){r.stopPropagation()}).bind("dblclick",function(r){r.stopPropagation()});$.each(this.filters,function(x,s){var u=$("<div/>").addClass("slider-row").appendTo(c.filters_div);var r=$("<div/>").addClass("slider-label").appendTo(u);var z=$("<span/>").addClass("slider-name").text(s.name+" ").appendTo(r);var t=$("<span/>");var v=$("<span/>").addClass("slider-value").appendTo(r).append("[").append(t).append("]");var y=$("<div/>").addClass("slider").appendTo(u);s.control_element=$("<div/>").attr("id",s.name+"-filter-control").appendTo(y);var w=[0,0];s.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(A,B){w=B.values;t.text(B.values[0]+"-"+B.values[1]);setTimeout(function(){if(B.values[0]==w[0]&&B.values[1]==w[1]){var C=B.values;t.text(C[0]+"-"+C[1]);s.low=C[0];s.high=C[1];c.draw(true,true)}},50)},change:function(A,B){s.control_element.slider("option","slide").call(s.control_element,A,B)}});s.slider=s.control_element;s.slider_label=t;k(v,t,s.control_element);$("<div style='clear: both;'/>").appendTo(u)});if(this.tool){this.dynamic_tool_div=$("<div/>").addClass("dynamic-tool").hide();this.header_div.after(this.dynamic_tool_div);this.dynamic_tool_div.bind("drag",function(r){r.stopPropagation()}).bind("click",function(r){r.stopPropagation()}).bind("dblclick",function(r){r.stopPropagation()});var n=$("<div class='tool-name'>").appendTo(this.dynamic_tool_div).text(this.tool.name);var m=this.tool.params;var c=this;$.each(this.tool.params,function(A,s){if(s instanceof NumberParameter){var x=$("<div>").addClass("slider-row").appendTo(c.dynamic_tool_div);var u=$("<div>").addClass("slider-label").appendTo(x);var C=$("<span/>").addClass("slider-name").text(s.label+" ").appendTo(u);var t=$("<span/>").text(s.value);var y=$("<span/>").addClass("slider-value").appendTo(u).append("[").append(t).append("]");var B=$("<div/>").addClass("slider").appendTo(x);var r=$("<div id='"+s.name+"-param-control'>").appendTo(B);r.slider({min:s.min,max:s.max,step:get_slider_step(s.min,s.max),value:s.value,slide:function(F,H){var G=H.value;s.value=G;if(0<G&&G<1){G=parseFloat(G).toFixed(2)}t.text(G)},change:function(F,G){r.slider("option","slide").call(r,F,G)}});k(y,t,r);$("<div style='clear: both;'/>").appendTo(x)}else{if(s instanceof SelectParameter){var x=$("<div>").addClass("slider-row").appendTo(c.dynamic_tool_div);var u=$("<div>").addClass("slider-label").appendTo(x);var C=$("<span/>").addClass("slider-name").text(s.label+" ").appendTo(u);var E=$("<div/>").addClass("slider").appendTo(x);var w=$("<select/>").appendTo(E);w.change(function(){s.value=$(this).val()});var D=w.attr("options");for(var z=0;z<s.options.length;z++){var v=s.options[z];D[D.length]=new Option(v[0],v[1])}$("<div style='clear: both;'/>").appendTo(x)}}});var q=$("<div>").addClass("slider-row").appendTo(this.dynamic_tool_div);var l=$("<input type='submit'>").attr("value","Run").appendTo(q);var c=this;l.click(function(){c.run_tool()})}c.child_tracks_container=$("<div/>").addClass("child-tracks-container").hide();c.container_div.append(c.child_tracks_container);if(c.display_modes!==undefined){if(c.mode_div===undefined){c.mode_div=$("<div class='right-float menubutton popup' />").appendTo(c.header_div);var e=(c.track_config&&c.track_config.values.mode?c.track_config.values.mode:c.display_modes[0]);c.mode=e;c.mode_div.text(e);var d=function(r){c.mode_div.text(r);c.mode=r;c.track_config.values.mode=r;c.tile_cache.clear();c.draw()};var a={};for(var f=0,j=c.display_modes.length;f<j;f++){var g=c.display_modes[f];a[g]=function(r){return function(){d(r)}}(g)}make_popupmenu(c.mode_div,a)}else{c.mode_div.hide()}}this.make_name_popup_menu()};$.extend(TiledTrack.prototype,Track.prototype,{make_name_popup_menu:function(){var b=this;var a={};a["Edit configuration"]=function(){var h=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},f=function(){b.track_config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},g=function(j){if((j.keyCode||j.which)===27){h()}else{if((j.keyCode||j.which)===13){f()}}};$(window).bind("keypress.check_enter_esc",g);show_modal("Configure Track",b.track_config.build_form(),{Cancel:h,OK:f})};if(b.filters_available>0){var e=(b.filters_div.is(":visible")?"Hide filters":"Show filters");a[e]=function(){b.filters_visible=(b.filters_div.is(":visible"));b.filters_div.toggle();b.make_name_popup_menu()}}if(b.tool){var e=(b.dynamic_tool_div.is(":visible")?"Hide tool":"Show tool");a[e]=function(){if(!b.dynamic_tool_div.is(":visible")){b.update_name(b.name+b.tool_region_and_parameters_str())}else{menu_option_text="Show dynamic tool";b.revert_name()}b.dynamic_tool_div.toggle();b.make_name_popup_menu()}}if(b.valid_chroms){a["List chrom/contigs with data"]=function(){show_modal("Chrom/contigs with data","<p>"+b.valid_chroms.join("<br/>")+"</p>",{Close:function(){hide_modal()}})}}var c=view;var d=function(){$("#no-tracks").show()};if(this.parent_track){c=this.parent_track;d=function(){}}a.Remove=function(){c.remove_track(b);if(c.num_tracks===0){d()}};make_popupmenu(b.name_div,a)},draw:function(a,d){var s=this.view.low,g=this.view.high,j=g-s,l=this.view.container.width(),f=l/j,m=this.view.resolution,e=$("<div style='position: relative;'></div>");if(!d){this.content_div.children().remove()}this.content_div.append(e);this.max_height=0;var o=Math.floor(s/m/DENSITY);var c={};while((o*DENSITY*m)<g){var r=l+"_"+f+"_"+o;var h=this.tile_cache.get(r);var p=o*DENSITY*this.view.resolution;var b=p+DENSITY*this.view.resolution;if(!a&&h){this.show_tile(h,e,p,f)}else{this.delayed_draw(a,r,p,b,o,m,e,f,c)}o+=1}var k=this;var q=setInterval(function(){if(obj_length(c)===0){clearInterval(q);if(d){var v=k.content_div.children();var u=false;for(var w=v.length-1,t=0;w>=t;w--){var z=$(v[w]);if(u){z.remove()}else{if(z.children().length!==0){u=true}}}}for(var y=0;y<k.filters.length;y++){k.filters[y].update_ui_elt()}var x=false;if(k.example_feature){for(var y=0;y<k.filters.length;y++){if(k.filters[y].applies_to(k.example_feature)){x=true;break}}}if(k.filters_available!==x){k.filters_available=x;if(!k.filters_available){k.filters_div.hide()}k.make_name_popup_menu()}}},50);for(var n=0;n<this.child_tracks.length;n++){this.child_tracks[n].draw(a,d)}},delayed_draw:function(b,j,g,l,c,e,k,m,f){var d=this;var h=function(u,n,p,o,s,t,q){returned_tile=d.draw_tile(n,p,o,s,t,q);var r=$("<div class='track-tile'>").prepend(returned_tile);tile_element=r;d.tile_cache.set(j,tile_element);d.show_tile(tile_element,s,g,t);delete f[u]};var a=setTimeout(function(){if(g<=d.view.high&&l>=d.view.low){var n=(b?undefined:d.tile_cache.get(j));if(n){d.show_tile(n,k,g,m);delete f[a]}else{$.when(d.data_cache.get_data(view.chrom,g,l,d.mode,e,d.data_url_extra_params)).then(function(o){if(view.reference_track&&m>CHAR_WIDTH_PX){$.when(view.reference_track.data_cache.get_data(view.chrom,g,l,d.mode,e,view.reference_track.data_url_extra_params)).then(function(p){h(a,o,e,c,k,m,p)})}else{h(a,o,e,c,k,m)}})}}},50);f[a]=true},show_tile:function(a,f,d,g){var b=this;var c=this.view.high-this.view.low,e=(d-this.view.low)*g;if(this.left_offset){e-=this.left_offset}a.css({position:"absolute",top:0,left:e,height:""});f.append(a);b.max_height=Math.max(b.max_height,a.height());b.content_div.css("height",b.max_height+"px");f.children().css("height",b.max_height+"px")},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")},run_tool:function(){var b={dataset_id:this.original_dataset_id,chrom:this.view.chrom,low:this.view.low,high:this.view.high,tool_id:this.tool.name};$.extend(b,this.tool.get_param_values_dict());var d=this,c=b.tool_id+d.tool_region_and_parameters_str(b.chrom,b.low,b.high),e;if(d.track_type==="FeatureTrack"){e=new ToolDataFeatureTrack(c,view,d.hda_ldda,undefined,{},{},d)}this.add_track(e);e.content_div.text("Starting job.");view.has_changes=true;var a=function(){$.getJSON(run_tool_url,b,function(f){if(f==="no converter"){e.container_div.addClass("error");e.content_div.text(DATA_NOCONVERTER)}else{if(f.error){e.container_div.addClass("error");e.content_div.text(DATA_CANNOT_RUN_TOOL+f.message)}else{if(f==="pending"){e.container_div.addClass("pending");e.content_div.text("Converting input data so that it can be easily reused.");setTimeout(a,2000)}else{e.dataset_id=f.dataset_id;e.content_div.text("Running job.");e.init()}}}})};a()},tool_region_and_parameters_str:function(c,a,d){var b=this,e=(c!==undefined&&a!==undefined&&d!==undefined?c+":"+a+"-"+d:"all");return" - region=["+e+"], parameters=["+b.tool.get_param_values().join(", ")+"]"},add_track:function(a){a.track_id=this.track_id+"_"+this.child_tracks.length;a.container_div.attr("id","track_"+a.track_id);this.child_tracks_container.append(a.container_div);sortable(a.container_div,".child-track-icon");if(!$(this.child_tracks_container).is(":visible")){this.child_tracks_container.show()}this.child_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()})}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.view.container.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);a.reference_track=this;this.left_offset=200;this.height_px=12;this.font=DEFAULT_FONT;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url;this.data_url_extra_params={dbkey:a.dbkey};this.data_cache=new DataManager(CACHED_DATA,this,false);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{draw_tile:function(m,g,b,j,n){var f=this,d=DENSITY*g;if(n>CHAR_WIDTH_PX){if(m===null){f.content_div.css("height","0px");return}var e=this.view.canvas_manager.new_canvas();var l=e.getContext("2d");e.width=Math.ceil(d*n+f.left_offset);e.height=f.height_px;l.font=DEFAULT_FONT;l.textAlign="center";for(var h=0,k=m.length;h<k;h++){var a=Math.round(h*n);l.fillText(m[h],a+f.left_offset,10)}return e}this.content_div.css("height","0px")}});var LineTrack=function(e,c,f,a,d){var b=this;this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,e,c,c.viewport_container);TiledTrack.call(this);this.min_height_px=16;this.max_height_px=400;this.height_px=80;this.hda_ldda=f;this.dataset_id=a;this.original_dataset_id=a;this.data_cache=new DataManager(CACHED_DATA,this);this.tile_cache=new Cache(CACHED_TILES_LINE);this.track_config=new TrackConfig({track:this,params:[{key:"color",label:"Color",type:"color",default_value:"black"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.height_px,hidden:true}],saved_values:d,onchange:function(){b.vertical_range=b.prefs.max_value-b.prefs.min_value;$("#linetrack_"+b.track_id+"_minval").text(b.prefs.min_value);$("#linetrack_"+b.track_id+"_maxval").text(b.prefs.max_value);b.tile_cache.clear();b.draw()}});this.prefs=this.track_config.values;this.height_px=this.track_config.values.height;this.vertical_range=this.track_config.values.max_value-this.track_config.values.min_value;this.add_resize_handle()};$.extend(LineTrack.prototype,TiledTrack.prototype,{add_resize_handle:function(){var a=this;var d=false;var c=false;var b=$("<div class='track-resize'>");$(a.container_div).hover(function(){d=true;b.show()},function(){d=false;if(!c){b.hide()}});b.hide().bind("dragstart",function(f,g){c=true;g.original_height=$(a.content_div).height()}).bind("drag",function(g,h){var f=Math.min(Math.max(h.original_height+h.deltaY,a.min_height_px),a.max_height_px);$(a.content_div).css("height",f);a.height_px=f;a.draw(true)}).bind("dragend",function(f,g){a.tile_cache.clear();c=false;if(!d){b.hide()}a.track_config.values.height=a.height_px}).appendTo(a.container_div)},predraw_init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;return $.getJSON(a.data_url,{stats:true,chrom:a.view.chrom,low:null,high:null,hda_ldda:a.hda_ldda,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"24px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",bottom:"2px",left:"10px"});f.prependTo(a.container_div)})},draw_tile:function(m,e,b,j,l){if(this.vertical_range===undefined){return}var f=b*DENSITY*e,d=DENSITY*e,a=Math.ceil(d*l),h=this.height_px;var c=this.view.canvas_manager.new_canvas();c.width=a,c.height=h;var k=c.getContext("2d");var g=new LinePainter(m.data,f,f+d,this.prefs.min_value,this.prefs.max_value,this.prefs.color,this.mode);g.draw(k,a,h);return c}});var FeatureTrack=function(a,f,e,j,h,c,d,g){var b=this;this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];this.track_config=new TrackConfig({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:h,onchange:function(){b.tile_cache.clear();b.draw()}});this.prefs=this.track_config.values;Track.call(this,a,f,f.viewport_container);TiledTrack.call(this,c,d,g);this.height_px=0;this.container_div.addClass("feature-track");this.hda_ldda=e;this.dataset_id=j;this.original_dataset_id=j;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.default_font=DEFAULT_FONT;this.inc_slots={};this.start_end_dct={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new DataManager(20,this);this.left_offset=200;this.painter=LinkedFeaturePainter};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{incremental_slots:function(d,b,c){var a=this.inc_slots[d];if(!a||(a.mode!==c)){a=new FeatureSlotter(d,c==="Pack",function(e){return CONTEXT.measureText(e)});a.mode=c;this.inc_slots[d]=a}return a.slot_features(b)},get_y_scale:function(b){var a;if(b==="summary_tree"){}if(b==="Dense"){a=DENSE_TRACK_HEIGHT}else{if(b==="no_detail"){a=NO_DETAIL_TRACK_HEIGHT}else{if(b==="Squish"){a=SQUISH_TRACK_HEIGHT}else{a=PACK_TRACK_HEIGHT}}}return a},draw_tile:function(o,w,A,k,m,d){var t=this,C=A*DENSITY*w,b=(A+1)*DENSITY*w,q=b-C,u=Math.ceil(q*m),s=this.mode,G=25,e=this.left_offset,p,g;if(s==="Auto"){if(o.dataset_type==="summary_tree"){s=o.dataset_type}else{if(o.extra_info==="no_detail"){s="no_detail"}else{var F=o.data;if((F.length&&F.length<4)||(this.view.high-this.view.low>MIN_SQUISH_VIEW_WIDTH)){s="Squish"}else{s="Pack"}}}}if(s==="summary_tree"){g=this.summary_draw_height;k.parent().css("height",Math.max(this.height_px,g)+"px");this.container_div.find(".yaxislabel").remove();var a=$("<div />").addClass("yaxislabel");a.text(o.max);a.css({position:"absolute",top:"22px",left:"10px"});a.prependTo(this.container_div);var c=this.view.canvas_manager.new_canvas();c.width=u+e;c.height=g+LABEL_SPACING+CHAR_HEIGHT_PX;var D=new SummaryTreePainter(o.data,o.delta,o.max,C,b,this.prefs.show_counts);var v=c.getContext("2d");v.translate(e,0);D.draw(v,u,g);return c}var p,j=1;if(s==="no_detail"||s==="Squish"||s==="Pack"){j=this.incremental_slots(m,o.data,s);p=this.inc_slots[m].slots}var l=[];if(o.data){for(var x=0,z=o.data.length;x<z;x++){var h=o.data[x];var y=false;var n;for(var B=0,E=this.filters.length;B<E;B++){n=this.filters[B];n.update_attrs(h);if(!n.keep(h)){y=true;break}}if(!y){l.push(h)}}}var D=new (this.painter)(l,C,b,this.prefs,s,d);var g=D.get_required_height(j)+ERROR_PADDING;var c=this.view.canvas_manager.new_canvas();c.width=u+e;c.height=g;k.parent().css("height",Math.max(this.height_px,g)+"px");var v=c.getContext("2d");v.fillStyle=this.prefs.block_color;v.font=this.default_font;v.textAlign="right";this.container_div.find(".yaxislabel").remove();if(o.message){$(c).css({"border-top":"1px solid red"});v.fillStyle="red";v.textAlign="left";var r=v.textBaseline;v.textBaseline="top";v.fillText(o.message,e,0);v.textBaseline=r;if(!o.data){return c}}this.example_feature=(o.data.length?o.data[0]:undefined);v.translate(e,ERROR_PADDING);D.draw(v,u,g,p);return c}});var VcfTrack=function(d,b,f,a,c,e){FeatureTrack.call(this,d,b,f,a,c,e);this.track_type="VcfTrack";this.painter=VariantPainter};$.extend(VcfTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype);var ReadTrack=function(d,b,f,a,c,e){FeatureTrack.call(this,d,b,f,a,c,e);this.track_config=new TrackConfig({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:c,onchange:function(){this.track.tile_cache.clear();this.track.draw()}});this.prefs=this.track_config.values;this.track_type="ReadTrack";this.painter=ReadPainter;this.make_name_popup_menu()};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype);var ToolDataFeatureTrack=function(e,c,g,a,d,f,b){FeatureTrack.call(this,e,c,g,a,d,f,{},b);this.track_type="ToolDataFeatureTrack";this.data_url=raw_data_url;this.data_query_wait=1000;this.dataset_check_url=dataset_state_url};$.extend(ToolDataFeatureTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{predraw_init:function(){var b=this;var a=function(){if(b.data_cache.size()===0){setTimeout(a,300)}else{b.data_url=default_data_url;b.data_query_wait=DEFAULT_DATA_QUERY_WAIT;b.dataset_state_url=converted_datasets_state_url;$.getJSON(b.dataset_state_url,{dataset_id:b.dataset_id,hda_ldda:b.hda_ldda},function(c){})}};a()}});var extend=function(){var c=arguments[0];for(var b=1;b<arguments.length;b++){var a=arguments[b];for(key in a){c[key]=a[key]}}};var CanvasManager=function(a){this.document=a};CanvasManager.prototype.new_canvas=function(){var a=this.document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(a)}return a};var FeatureSlotter=function(c,b,a){this.slots={};this.start_end_dct={};this.w_scale=c;this.include_label=b;this.measureText=a};FeatureSlotter.prototype.slot_features=function(g){var k=this.w_scale,n=this.slots,c=this.start_end_dct,t=[],u=[],h=0;for(var r=0,s=g.length;r<s;r++){var e=g[r],j=e[0];if(n[j]!==undefined){h=Math.max(h,n[j]);u.push(n[j])}else{t.push(r)}}var l=function(A,B){for(var z=0;z<=MAX_FEATURE_DEPTH;z++){var x=false,C=c[z];if(C!==undefined){for(var w=0,y=C.length;w<y;w++){var v=C[w];if(B>v[0]&&A<v[1]){x=true;break}}}if(!x){return z}}return -1};for(var r=0,s=t.length;r<s;r++){var e=g[t[r]],j=e[0],p=e[1],a=e[2],m=e[3],b=Math.floor(p*k),f=Math.ceil(a*k),q=this.measureText(m).width,d;if(m!==undefined&&this.include_label){q+=(LABEL_SPACING+PACK_SPACING);if(b-q>=0){b-=q;d="left"}else{f+=q;d="right"}}var o=l(b,f);if(o>=0){if(c[o]===undefined){c[o]=[]}c[o].push([b,f]);n[j]=o;h=Math.max(h,o)}else{}}return h+1};var SummaryTreePainter=function(d,f,b,e,a,c){this.data=d;this.delta=f;this.max=b;this.view_start=e;this.view_end=a;this.show_counts=c};SummaryTreePainter.prototype.draw=function(o,a,n){var f=this.view_start,q=this.view_end-this.view_start,p=a/q;var l=this.data,k=this.delta,h=this.max,c=n+LABEL_SPACING+CHAR_HEIGHT_PX;delta_x_px=Math.ceil(k*p);o.save();for(var d=0,e=l.length;d<e;d++){var j=Math.floor((l[d][0]-f)*p);var g=l[d][1];if(!g){continue}var m=g/h*n;o.fillStyle="black";o.fillRect(j,c-m,delta_x_px,m);var b=4;if(this.show_counts&&(o.measureText(g).width+b)<delta_x_px){o.fillStyle="#666";o.textAlign="center";o.fillText(g,j+(delta_x_px/2),10)}}o.restore()};var LinePainter=function(d,g,a,b,f,c,e){this.data=d;this.view_start=g;this.view_end=a;this.min_value=b;this.max_value=f;this.color=c;this.mode=e};LinePainter.prototype.draw=function(o,n,l){var g=false,h=this.min_value,e=this.max_value,k=e-h,a=l,b=this.view_start,m=this.view_end-this.view_start,c=n/m,j=this.mode,s=this.data;o.save();var t=Math.round(l+h/k*l);if(j!=="Intensity"){o.beginPath();o.moveTo(0,t);o.lineTo(n,t);o.fillStyle="#aaa";o.stroke()}o.beginPath();o.fillStyle=this.color;var r,f,d;if(s.length>1){d=Math.ceil((s[1][0]-s[0][0])*c)}else{d=10}for(var p=0,q=s.length;p<q;p++){r=Math.round((s[p][0]-b)*c);f=s[p][1];if(f===null){if(g&&j==="Filled"){o.lineTo(r,a)}g=false;continue}if(f<h){f=h}else{if(f>e){f=e}}if(j==="Histogram"){f=Math.round(f/k*a);o.fillRect(r,t,d,-f)}else{if(j==="Intensity"){f=255-Math.floor((f-h)/k*255);o.fillStyle="rgb("+f+","+f+","+f+")";o.fillRect(r,0,d,a)}else{f=Math.round(a-(f-h)/k*a);if(g){o.lineTo(r,f)}else{g=true;if(j==="Filled"){o.moveTo(r,a);o.lineTo(r,f)}else{o.moveTo(r,f)}}}}}if(j==="Filled"){if(g){o.lineTo(r,t);o.lineTo(0,t)}o.fill()}else{o.stroke()}o.restore()};var FeaturePainter=function(c,e,a,b,d){this.data=c;this.view_start=e;this.view_end=a;this.prefs=b;this.mode=d};extend(FeaturePainter.prototype,{get_required_height:function(b){var a=y_scale=this.get_row_height(),c=this.mode;if(c==="no_detail"||c==="Squish"||c==="Pack"){a=b*y_scale}return a+Math.round(y_scale/2)},draw:function(n,d,m,j){var g=this.data,k=this.view_start,o=this.view_end;n.save();n.fillStyle=this.prefs.block_color;n.textAlign="right";var r=this.view_end-this.view_start,q=d/r,c=this.get_row_height();for(var f=0,h=g.length;f<h;f++){var p=g[f],e=p[0],a=p[1],b=p[2],l=(j&&j[e]!==undefined?j[e]:null);if(is_overlap([a,b],[k,o])&&(this.mode=="Dense"||l!==null)){this.draw_element(n,this.mode,p,l,k,o,q,c,d)}}n.restore()}});var LinkedFeaturePainter=function(c,e,a,b,d){FeaturePainter.call(this,c,e,a,b,d)};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var b=this.mode,a;if(b==="summary_tree"){}if(b==="Dense"){a=DENSE_TRACK_HEIGHT}else{if(b==="no_detail"){a=NO_DETAIL_TRACK_HEIGHT}else{if(b==="Squish"){a=SQUISH_TRACK_HEIGHT}else{a=PACK_TRACK_HEIGHT}}}return a},draw_element:function(p,g,x,j,r,H,L,M,a){var u=x[0],J=x[1],B=x[2]-1,s=x[3],C=Math.floor(Math.max(0,(J-r)*L)),q=Math.ceil(Math.min(a,Math.max(0,(B-r)*L))),A=(g==="Dense"?0:(0+j))*M,o,F,t=null,N=null,d=this.prefs.block_color,E=this.prefs.label_color;if(g==="Dense"){p.fillStyle=d;p.fillRect(C,A,q-C,DENSE_FEATURE_HEIGHT)}else{if(g==="no_detail"){p.fillStyle=d;p.fillRect(C,A+5,q-C,DENSE_FEATURE_HEIGHT)}else{var n=x[4],z=x[5],D=x[6],e=x[7];if(z&&D){t=Math.floor(Math.max(0,(z-r)*L));N=Math.ceil(Math.min(a,Math.max(0,(D-r)*L)))}var K,v;if(g==="Squish"){K=1;v=SQUISH_FEATURE_HEIGHT}else{K=5;v=PACK_FEATURE_HEIGHT}if(!e){if(x.strand){if(x.strand==="+"){p.fillStyle=RIGHT_STRAND_INV}else{if(x.strand==="-"){p.fillStyle=LEFT_STRAND_INV}}}else{p.fillStyle=d}p.fillRect(C,A,q-C,v)}else{var m,w;if(g==="Squish"){p.fillStyle=CONNECTOR_COLOR;m=A+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;w=1}else{if(n){var m=A;var w=v;if(n==="+"){p.fillStyle=RIGHT_STRAND}else{if(n==="-"){p.fillStyle=LEFT_STRAND}}}else{p.fillStyle=CONNECTOR_COLOR;m+=(SQUISH_FEATURE_HEIGHT/2)+1;w=1}}p.fillRect(C,m,q-C,w);for(var I=0,c=e.length;I<c;I++){var h=e[I],b=Math.floor(Math.max(0,(h[0]-r)*L)),y=Math.ceil(Math.min(a,Math.max((h[1]-1-r)*L)));if(b>y){continue}p.fillStyle=d;p.fillRect(b,A+(v-K)/2+1,y-b,K);if(t!==undefined&&!(b>N||y<t)){var G=Math.max(b,t),l=Math.min(y,N);p.fillRect(G,A+1,l-G,v)}}}if(g==="Pack"&&J>r){p.fillStyle=E;var f=1;if(f===0&&C-p.measureText(s).width<0){p.textAlign="left";p.fillText(s,q+LABEL_SPACING,A+8)}else{p.textAlign="right";p.fillText(s,C-LABEL_SPACING,A+8)}p.fillStyle=d}}}}});var VariantPainter=function(c,e,a,b,d){FeaturePainter.call(this,c,e,a,b,d)};extend(VariantPainter.prototype,FeaturePainter.prototype,{draw_element:function(u,p,j,e,x,c,m,v,s){var j=data[i],l=j[0],t=j[1],d=j[2]-1,o=j[3],g=Math.floor(Math.max(0,(t-x)*m)),k=Math.ceil(Math.min(s,Math.max(0,(d-x)*m))),f=(p==="Dense"?0:(0+e))*v,a,y,b=null,n=null;if(no_label){u.fillStyle=block_color;u.fillRect(g+left_offset,f+5,k-g,1)}else{var w=j[4],r=j[5],h=j[6];a=9;y=1;u.fillRect(g+left_offset,f,k-g,a);if(p!=="Dense"&&o!==undefined&&t>x){u.fillStyle=label_color;if(tile_index===0&&g-u.measureText(o).width<0){u.textAlign="left";u.fillText(o,k+2+left_offset,f+8)}else{u.textAlign="right";u.fillText(o,g-2+left_offset,f+8)}u.fillStyle=block_color}var q=w+" / "+r;if(t>x&&u.measureText(q).width<(k-g)){u.fillStyle="white";u.textAlign="center";u.fillText(q,left_offset+g+(k-g)/2,f+8);u.fillStyle=block_color}}}});var ReadPainter=function(d,f,a,c,e,b){FeaturePainter.call(this,d,f,a,c,e);this.ref_seq=b};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var a,b=this.mode;if(b==="summary_tree"){}if(b==="Dense"){a=DENSE_TRACK_HEIGHT}else{if(b==="Squish"){a=SQUISH_TRACK_HEIGHT}else{a=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){a*=2}}}return a},draw_read:function(z,u,p,E,d,y,m,j,h){z.textAlign="center";var x=this,b=[E,d],s=0,A=0,w=0;ref_seq=this.ref_seq;var J=[];if((u==="Pack"||this.mode==="Auto")&&j!==undefined&&p>CHAR_WIDTH_PX){w=Math.round(p/2)}if(!m){m=[[0,j.length]]}for(var q=0,C=m.length;q<C;q++){var n=m[q],e="MIDNSHP=X"[n[0]],r=n[1];if(e==="H"||e==="S"){s-=r}var k=y+s,I=Math.floor(Math.max(0,(k-E)*p)),l=Math.floor(Math.max(0,(k+r-E)*p));switch(e){case"H":break;case"S":case"M":case"=":var t=compute_overlap([k,k+r],b);if(t!==NO_OVERLAP){var v=j.slice(A,A+r);if(w>0){z.fillStyle=this.prefs.block_color;z.fillRect(I-w,h+1,l-I,9);z.fillStyle=CONNECTOR_COLOR;for(var G=0,a=v.length;G<a;G++){if(this.prefs.show_differences&&ref_seq){var o=ref_seq[k-E+G];if(!o||o.toLowerCase()===v[G].toLowerCase()){continue}}if(k+G>=E&&k+G<=d){var H=Math.floor(Math.max(0,(k+G-E)*p));z.fillText(v[G],H,h+9)}}}else{z.fillStyle=this.prefs.block_color;z.fillRect(I,h+(this.mode!=="Dense"?4:5),l-I,(u!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}A+=r;s+=r;break;case"N":z.fillStyle=CONNECTOR_COLOR;z.fillRect(I-w,h+5,l-I,1);s+=r;break;case"D":z.fillStyle="red";z.fillRect(I-w,h+4,l-I,3);s+=r;break;case"P":break;case"I":var t=compute_overlap([k,k+r],b),D=I-w;if(t!==NO_OVERLAP){var v=j.slice(A,A+r);if(this.prefs.show_insertions){var g=I-(l-I)/2;if((u==="Pack"||this.mode==="Auto")&&j!==undefined&&p>CHAR_WIDTH_PX){z.fillStyle="yellow";z.fillRect(g-w,h-9,l-I,9);J[J.length]={type:"triangle",data:[D,h+4,5]};z.fillStyle=CONNECTOR_COLOR;switch(t){case (OVERLAP_START):v=v.slice(E-k);break;case (OVERLAP_END):v=v.slice(0,k-d);break;case (CONTAINED_BY):break;case (CONTAINS):v=v.slice(E-k,k-d);break}for(var G=0,a=v.length;G<a;G++){var H=Math.floor(Math.max(0,(k+G-E)*p));z.fillText(v[G],H-(l-I)/2,h)}}else{z.fillStyle="yellow";z.fillRect(g,h+(this.mode!=="Dense"?2:5),l-I,(u!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((u==="Pack"||this.mode==="Auto")&&j!==undefined&&p>CHAR_WIDTH_PX){J[J.length]={type:"text",data:[v.length,D,h+9]}}else{}}}A+=r;break;case"X":A+=r;break}}z.fillStyle="yellow";var F,f,K;for(var B=0;B<J.length;B++){F=J[B];f=F.type;K=F.data;if(f==="text"){z.font="bold "+DEFAULT_FONT;z.fillText(K[0],K[1],K[2]);z.font=DEFAULT_FONT}else{if(f=="triangle"){z.drawDownwardEquilateralTriangle(K[0],K[1],K[2])}}}},draw_element:function(u,p,g,d,x,b,l,v,s){var k=g[0],t=g[1],c=g[2],m=g[3],f=Math.floor(Math.max(0,(t-x)*l)),h=Math.ceil(Math.min(s,Math.max(0,(c-x)*l))),e=(p==="Dense"?1:(1+d))*v,y=this.prefs.block_color,j=this.prefs.label_color,r=0;if((p==="Pack"||this.mode==="Auto")&&l>CHAR_WIDTH_PX){var r=Math.round(l/2)}u.fillStyle=y;if(g[5] instanceof Array){var q=Math.floor(Math.max(0,(g[4][0]-x)*l)),o=Math.ceil(Math.min(s,Math.max(0,(g[4][1]-x)*l))),n=Math.floor(Math.max(0,(g[5][0]-x)*l)),a=Math.ceil(Math.min(s,Math.max(0,(g[5][1]-x)*l)));if(g[4][1]>=x&&g[4][0]<=b&&g[4][2]){this.draw_read(u,p,l,x,b,g[4][0],g[4][2],g[4][3],e)}if(g[5][1]>=x&&g[5][0]<=b&&g[5][2]){this.draw_read(u,p,l,x,b,g[5][0],g[5][2],g[5][3],e)}if(n>o){u.fillStyle=CONNECTOR_COLOR;u.dashedLine(o-r,e+5,n-r,e+5)}}else{u.fillStyle=y;this.draw_read(u,p,l,x,b,t,g[4],g[5],e)}if(p==="Pack"&&t>x){u.fillStyle=this.prefs.label_color;var w=1;if(w===0&&f-u.measureText(m).width<0){u.textAlign="left";u.fillText(m,h+LABEL_SPACING-r,e+8)}else{u.textAlign="right";u.fillText(m,f-LABEL_SPACING-r,e+8)}u.fillStyle=y}}});
\ No newline at end of file
+var extend=function(){var c=arguments[0];for(var b=1;b<arguments.length;b++){var a=arguments[b];for(key in a){c[key]=a[key]}}};var trackster_module=function(f,Q){var o=f("slotting"),G=f("painters");var V=function(W,X){this.document=W;this.default_font=X!==undefined?X:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};extend(V.prototype,{load_pattern:function(W,aa){var X=this.patterns,Y=this.dummy_context,Z=new Image();Z.src=image_path+aa;Z.onload=function(){X[W]=Y.createPattern(Z,"repeat")}},get_pattern:function(W){return this.patterns[W]},new_canvas:function(){var W=this.document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(W)}W.manager=this;return W}});var B=function(W,X){W.bind("drag",{handle:X,relative:true},function(ab,ac){var aa=$(this).parent();var Z=aa.children();var Y;for(Y=0;Y<Z.length;Y++){if(ac.offsetY<$(Z.get(Y)).position().top){break}}if(Y===Z.length){if(this!==Z.get(Y-1)){aa.append(this)}}else{if(this!==Z.get(Y)){$(this).insertBefore(Z.get(Y))}}})};var h=function(Y,W){var X=W-Y;return(X<=2?0.01:(X<=100?1:(X<=1000?5:10)))};var C=9,z=10,L=C+2,w=100,D=12000,J=200,r=10,F=5000,s=100,m="There was an error in indexing this dataset. ",E="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",A="No data for this chrom/contig.",p="Currently indexing... please wait",u="Tool cannot be rerun: ",a="Loading data...",R="Ready for display",d=10,q=5,y=5;function t(W){return Math.round(W*1000)/1000}var c=function(W){this.num_elements=W;this.clear()};extend(c.prototype,{get:function(X){var W=this.key_ary.indexOf(X);if(W!==-1){this.move_key_to_end(X,W)}return this.obj_cache[X]},set:function(X,Y){if(!this.obj_cache[X]){if(this.key_ary.length>=this.num_elements){var W=this.key_ary.shift();delete this.obj_cache[W]}this.key_ary.push(X)}this.obj_cache[X]=Y;return Y},move_key_to_end:function(X,W){this.key_ary.splice(W,1);this.key_ary.push(X)},clear:function(){this.obj_cache={};this.key_ary=[]},size:function(){return this.key_ary.length}});var K=function(X,W,Y){c.call(this,X);this.track=W;this.subset=(Y!==undefined?Y:true)};extend(K.prototype,c.prototype,{load_data:function(ad,ae,Z,ac,W,ab){var Y={chrom:ad,low:ae,high:Z,mode:ac,resolution:W,dataset_id:this.track.dataset_id,hda_ldda:this.track.hda_ldda};$.extend(Y,ab);var af=[];for(var aa=0;aa<this.track.filters.length;aa++){af[af.length]=this.track.filters[aa].name}Y.filter_cols=JSON.stringify(af);var X=this;return $.getJSON(this.track.data_url,Y,function(ag){X.set_data(ae,Z,ac,ag)})},get_data:function(Y,W,ab,ac,X,aa){var Z=this.get(this.gen_key(W,ab,ac));if(Z){return Z}Z=this.load_data(Y,W,ab,ac,X,aa);this.set_data(W,ab,ac,Z);return Z},set_data:function(X,Y,Z,W){return this.set(this.gen_key(X,Y,Z),W)},gen_key:function(W,Y,Z){var X=W+"_"+Y+"_"+Z;return X},split_key:function(W){return W.split("_")}});var U=function(W,Z,Y,X,aa){this.container=W;this.chrom=null;this.vis_id=Y;this.dbkey=X;this.title=Z;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init(aa);this.canvas_manager=new V(W.get(0).ownerDocument);this.reset()};extend(U.prototype,{init:function(Z){var Y=this.container,W=this;this.top_container=$("<div/>").addClass("top-container").appendTo(Y);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(Y);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(Y);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var X=function(aa){if(aa.type==="focusout"||(aa.keyCode||aa.which)===13||(aa.keyCode||aa.which)===27){if((aa.keyCode||aa.which)!==27){W.go_to($(this).val())}$(this).hide();$(this).val("");W.location_span.show();W.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",X).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").appendTo(this.nav_controls);this.location_span.bind("click",function(){W.location_span.hide();W.chrom_select.hide();W.nav_input.val(W.chrom+":"+W.low+"-"+W.high);W.nav_input.css("display","inline-block");W.nav_input.select();W.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a id='zoom-out' />").click(function(){W.zoom_out();W.redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a id='zoom-in' />").click(function(){W.zoom_in();W.redraw()}).appendTo(this.nav_controls);this.load_chroms({low:0},Z);this.chrom_select.bind("change",function(){W.change_chrom(W.chrom_select.val())});this.intro_div.show();this.content_div.bind("click",function(aa){$(this).find("input").trigger("blur")});this.content_div.bind("dblclick",function(aa){W.zoom_in(aa.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(aa,ab){this.current_x=ab.offsetX}).bind("drag",function(aa,ac){var ad=ac.offsetX-this.current_x;this.current_x=ac.offsetX;var ab=Math.round(ad/W.viewport_container.width()*(W.max_high-W.max_low));W.move_delta(-ab)});this.overview_close.bind("click",function(){for(var ab=0,aa=W.tracks.length;ab<aa;ab++){W.tracks[ab].is_overview=false}$(this).siblings().filter("canvas").remove();$(this).parent().css("height",W.overview_box.height());W.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("draginit",function(aa,ab){if(aa.clientX>W.viewport_container.width()-16){return false}}).bind("dragstart",function(aa,ab){ab.original_low=W.low;ab.current_height=aa.clientY;ab.current_x=ab.offsetX}).bind("drag",function(ac,ae){var aa=$(this);var af=ae.offsetX-ae.current_x;var ab=aa.scrollTop()-(ac.clientY-ae.current_height);aa.scrollTop(ab);ae.current_height=ac.clientY;ae.current_x=ae.offsetX;var ad=Math.round(af/W.viewport_container.width()*(W.high-W.low));W.move_delta(ad)}).bind("mousewheel",function(ac,ae,ab,aa){if(ab){var ad=Math.round(-ab/W.viewport_container.width()*(W.high-W.low));W.move_delta(ad)}});this.top_labeltrack.bind("dragstart",function(aa,ab){return $("<div />").css({height:W.content_div.height()+W.top_labeltrack.height()+W.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ae,af){$(af.proxy).css({left:Math.min(ae.pageX,af.startX),width:Math.abs(ae.pageX-af.startX)});var ab=Math.min(ae.pageX,af.startX)-W.container.offset().left,aa=Math.max(ae.pageX,af.startX)-W.container.offset().left,ad=(W.high-W.low),ac=W.viewport_container.width();W.update_location(Math.round(ab/ac*ad)+W.low,Math.round(aa/ac*ad)+W.low)}).bind("dragend",function(af,ag){var ab=Math.min(af.pageX,ag.startX),aa=Math.max(af.pageX,ag.startX),ad=(W.high-W.low),ac=W.viewport_container.width(),ae=W.low;W.low=Math.round(ab/ac*ad)+ae;W.high=Math.round(aa/ac*ad)+ae;$(ag.proxy).remove();W.redraw()});this.add_label_track(new T(this,this.top_labeltrack));this.add_label_track(new T(this,this.nav_labeltrack));$(window).bind("resize",function(){W.resize_window()});$(document).bind("redraw",function(){W.redraw()});this.reset();$(window).trigger("resize")},update_location:function(W,X){this.location_span.text(commatize(W)+" - "+commatize(X));this.nav_input.val(this.chrom+":"+commatize(W)+"-"+commatize(X))},load_chroms:function(X,Y){X.num=s;$.extend(X,(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}));var W=this;$.ajax({url:chrom_url,data:X,dataType:"json",success:function(aa){if(aa.chrom_info.length===0){alert("Invalid chromosome: "+X.chrom);return}if(aa.reference){W.add_label_track(new x(W))}W.chrom_data=aa.chrom_info;var ad='<option value="">Select Chrom/Contig</option>';for(var ac=0,Z=W.chrom_data.length;ac<Z;ac++){var ab=W.chrom_data[ac].chrom;ad+='<option value="'+ab+'">'+ab+"</option>"}if(aa.prev_chroms){ad+='<option value="previous">Previous '+s+"</option>"}if(aa.next_chroms){ad+='<option value="next">Next '+s+"</option>"}W.chrom_select.html(ad);if(Y){Y()}W.chrom_start_index=aa.start_index},error:function(){alert("Could not load chroms for this dbkey:",W.dbkey)}})},change_chrom:function(aa,X,ac){if(!aa||aa==="None"){return}var Z=this;if(aa==="previous"){Z.load_chroms({low:this.chrom_start_index-s});return}if(aa==="next"){Z.load_chroms({low:this.chrom_start_index+s});return}var ab=$.grep(Z.chrom_data,function(ae,af){return ae.chrom===aa})[0];if(ab===undefined){Z.load_chroms({chrom:aa},function(){Z.change_chrom(aa,X,ac)});return}else{if(aa!==Z.chrom){Z.chrom=aa;if(!Z.chrom){Z.intro_div.show()}else{Z.intro_div.hide()}Z.chrom_select.val(Z.chrom);Z.max_high=ab.len-1;Z.reset();Z.redraw(true);for(var ad=0,W=Z.tracks.length;ad<W;ad++){var Y=Z.tracks[ad];if(Y.init){Y.init()}}}if(X!==undefined&&ac!==undefined){Z.low=Math.max(X,0);Z.high=Math.min(ac,Z.max_high)}Z.reset_overview();Z.redraw()}},go_to:function(aa){var ae=this,W,Z,X=aa.split(":"),ac=X[0],ad=X[1];if(ad!==undefined){try{var ab=ad.split("-");W=parseInt(ab[0].replace(/,/g,""),10);Z=parseInt(ab[1].replace(/,/g,""),10)}catch(Y){return false}}ae.change_chrom(ac,W,Z)},move_fraction:function(Y){var W=this;var X=W.high-W.low;this.move_delta(Y*X)},move_delta:function(Y){var W=this;var X=W.high-W.low;if(W.low-Y<W.max_low){W.low=W.max_low;W.high=W.max_low+X}else{if(W.high-Y>W.max_high){W.high=W.max_high;W.low=W.max_high-X}else{W.high-=Y;W.low-=Y}}W.redraw()},add_track:function(W){W.view=this;W.track_id=this.track_id_counter;this.tracks.push(W);if(W.init){W.init()}W.container_div.attr("id","track_"+W.track_id);B(W.container_div,".draghandle");this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(W){W.view=this;this.label_tracks.push(W)},remove_track:function(W){this.has_changes=true;W.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(W)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(ad){var ac=this.high-this.low,ab=this.low,X=this.high;if(ab<this.max_low){ab=this.max_low}if(X>this.max_high){X=this.max_high}if(this.high!==0&&ac<this.min_separation){X=ab+this.min_separation}this.low=Math.floor(ab);this.high=Math.ceil(X);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(r,Math.max(0,Math.ceil(Math.log(this.resolution,r)/Math.log(r))));var W=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var aa=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:W,width:Math.max(ae,aa)}).show();if(aa<ae){this.overview_box.css("left",W-(ae-aa)/2)}if(this.overview_highlight){this.overview_highlight.css({left:W,width:aa})}this.update_location(this.low,this.high);if(!ad){for(var Y=0,Z=this.tracks.length;Y<Z;Y++){if(this.tracks[Y]&&this.tracks[Y].enabled){this.tracks[Y].draw()}}for(Y=0,Z=this.label_tracks.length;Y<Z;Y++){this.label_tracks[Y].draw()}}},zoom_in:function(X,Y){if(this.max_high===0||this.high-this.low<this.min_separation){return}var Z=this.high-this.low,aa=Z/2+this.low,W=(Z/this.zoom_factor)/2;if(X){aa=X/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(aa-W);this.high=Math.round(aa+W);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var X=this.high-this.low,Y=X/2+this.low,W=(X*this.zoom_factor)/2;this.low=Math.round(Y-W);this.high=Math.round(Y+W);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var n=function(X,aa){this.track=X;this.name=aa.name;this.params=[];var ai=aa.params;for(var Y=0;Y<ai.length;Y++){var ad=ai[Y],W=ad.name,ah=ad.label,Z=unescape(ad.html),af=ad.type;if(af==="number"){this.params[this.params.length]=new g(W,ah,Z,ad.min,ad.max)}else{if(af=="select"){this.params[this.params.length]=new I(W,ah,Z)}else{console.log("WARNING: unrecognized tool parameter type:",W,af)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(ak){ak.stopPropagation()}).bind("click",function(ak){ak.stopPropagation()}).bind("dblclick",function(ak){ak.stopPropagation()});var ag=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var ae=this.params;var ab=this;$.each(this.params,function(al,ao){var an=$("<div>").addClass("param-row").appendTo(ab.parent_div);var ak=$("<div>").addClass("param-label").text(ao.label).appendTo(an);var am=$("<div/>").addClass("slider").html(ao.html).appendTo(an);$("<div style='clear: both;'/>").appendTo(an)});this.parent_div.find("input").click(function(){$(this).select()});var aj=$("<div>").addClass("slider-row").appendTo(this.parent_div);var ac=$("<input type='submit'>").attr("value","Run").appendTo(aj);var ab=this;ac.click(function(){ab.run()})};extend(n.prototype,{get_param_values_dict:function(){var W={};this.parent_div.find(":input").each(function(){var X=$(this).attr("name"),Y=$(this).val();W[X]=JSON.stringify(Y)});return W},get_param_values:function(){var X=[];var W={};this.parent_div.find(":input").each(function(){var Y=$(this).attr("name"),Z=$(this).val();if(Y){X[X.length]=Z}});return X},run:function(){var X={dataset_id:this.track.original_dataset_id,chrom:this.track.view.chrom,low:this.track.view.low,high:this.track.view.high,tool_id:this.name};$.extend(X,this.get_param_values_dict());var Z=this.track,Y=X.tool_id+Z.tool_region_and_parameters_str(X.chrom,X.low,X.high),aa;if(Z.track_type==="FeatureTrack"){aa=new N(Y,view,Z.hda_ldda,undefined,{},{},Z)}this.track.add_track(aa);aa.content_div.text("Starting job.");var W=function(){$.getJSON(run_tool_url,X,function(ab){if(ab==="no converter"){aa.container_div.addClass("error");aa.content_div.text(E)}else{if(ab.error){aa.container_div.addClass("error");aa.content_div.text(u+ab.message)}else{if(ab==="pending"){aa.container_div.addClass("pending");aa.content_div.text("Converting input data so that it can be easily reused.");setTimeout(W,2000)}else{aa.dataset_id=ab.dataset_id;aa.content_div.text("Running job.");aa.init()}}}})};W()}});var I=function(X,W,Y){this.name=X;this.label=W;this.html=Y};var g=function(Y,X,aa,Z,W){I.call(this,Y,X,aa);this.min=Z;this.max=W};var j=function(X,W,Y){this.name=X;this.index=W;this.value=Y};var O=function(X,W){this.name=X;this.index=W;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.min=Number.MAX_VALUE;this.max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};extend(O.prototype,{applies_to:function(W){if(W.length>this.index){return true}return false},keep:function(W){if(!this.applies_to(W)){return true}return(W[this.index]>=this.low&&W[this.index]<=this.high)},update_attrs:function(X){var W=false;if(!this.applies_to(X)){return W}if(X[this.index]<this.min){this.min=Math.floor(X[this.index]);W=true}if(X[this.index]>this.max){this.max=Math.ceil(X[this.index]);W=true}return W},update_ui_elt:function(){var X=this.slider.slider("option","min"),W=this.slider.slider("option","max");if(this.min<X||this.max>W){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",h(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var v=function(W){var ac=[];for(var Z=0;Z<W.length;Z++){var ab=W[Z];var Y=ab.name,aa=ab.type,X=ab.index;if(aa==="int"||aa==="float"){ac[Z]=new O(Y,X)}else{ac[Z]=new j(Y,X,aa)}}return ac};var S=function(W){this.track=W.track;this.params=W.params;this.values={};if(W.saved_values){this.restore_values(W.saved_values)}this.onchange=W.onchange};extend(S.prototype,{restore_values:function(W){var X=this;$.each(this.params,function(Y,Z){if(W[Z.key]!==undefined){X.values[Z.key]=W[Z.key]}else{X.values[Z.key]=Z.default_value}})},build_form:function(){var X=this;var W=$("<div />");$.each(this.params,function(ab,Z){if(!Z.hidden){var Y="param_"+ab;var ag=$("<div class='form-row' />").appendTo(W);ag.append($("<label />").attr("for",Y).text(Z.label+":"));if(Z.type==="bool"){ag.append($('<input type="checkbox" />').attr("id",Y).attr("name",Y).attr("checked",X.values[Z.key]))}else{if(Z.type==="color"){var ad=X.values[Z.key];var ac=$("<input />").attr("id",Y).attr("name",Y).val(ad);var ae=$("<div class='tipsy tipsy-north' style='position: absolute;' />").hide();var aa=$("<div style='background-color: black; padding: 10px;'></div>").appendTo(ae);var af=$("<div/>").appendTo(aa).farbtastic({width:100,height:100,callback:ac,color:ad});$("<div />").append(ac).append(ae).appendTo(ag).bind("click",function(ah){ae.css({left:$(this).position().left+($(ac).width()/2)-60,top:$(this).position().top+$(this.height)}).show();$(document).bind("click.color-picker",function(){ae.hide();$(document).unbind("click.color-picker")});ah.stopPropagation()})}else{ag.append($("<input />").attr("id",Y).attr("name",Y).val(X.values[Z.key]))}}}});return W},update_from_form:function(W){var Y=this;var X=false;$.each(this.params,function(Z,ab){if(!ab.hidden){var ac="param_"+Z;var aa=W.find("#"+ac).val();if(ab.type==="float"){aa=parseFloat(aa)}else{if(ab.type==="int"){aa=parseInt(aa)}else{if(ab.type==="bool"){aa=W.find("#"+ac).is(":checked")}}}if(aa!==Y.values[ab.key]){Y.values[ab.key]=aa;X=true}}});if(X){this.onchange()}}});var b=function(W,X,Y){this.track=W;this.canvas=X;this.histo_max=Y};var k=function(X,W,aa,Y,Z){this.name=X;this.view=W;this.parent_element=aa;this.data_url=(Y?Y:default_data_url);this.data_url_extra_params={};this.data_query_wait=(Z?Z:F);this.dataset_check_url=converted_datasets_state_url;this.container_div=$("<div />").addClass("track").css("position","relative");if(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)};extend(k.prototype,{init:function(){var W=this;W.enabled=false;W.tile_cache.clear();W.data_cache.clear();W.initial_canvas=undefined;W.content_div.css("height","auto");W.container_div.removeClass("nodata error pending");if(!W.dataset_id){return}$.getJSON(converted_datasets_state_url,{hda_ldda:W.hda_ldda,dataset_id:W.dataset_id,chrom:W.view.chrom},function(X){if(!X||X==="error"||X.kind==="error"){W.container_div.addClass("error");W.content_div.text(m);if(X.message){var Z=W.view.tracks.indexOf(W);var Y=$(" <a href='javascript:void(0);'></a>").text("View error").bind("click",function(){show_modal("Trackster Error","<pre>"+X.message+"</pre>",{Close:hide_modal})});W.content_div.append(Y)}}else{if(X==="no converter"){W.container_div.addClass("error");W.content_div.text(E)}else{if(X==="no data"||(X.data!==undefined&&(X.data===null||X.data.length===0))){W.container_div.addClass("nodata");W.content_div.text(A)}else{if(X==="pending"){W.container_div.addClass("pending");W.content_div.text(p);setTimeout(function(){W.init()},W.data_query_wait)}else{if(X.status==="data"){if(X.valid_chroms){W.valid_chroms=X.valid_chroms;W.make_name_popup_menu()}W.content_div.text(R);if(W.view.chrom){W.content_div.text("");W.content_div.css("height",W.height_px+"px");W.enabled=true;$.when(W.predraw_init()).done(function(){W.draw()})}}}}}}})},predraw_init:function(){},update_name:function(W){this.old_name=this.name;this.name=W;this.name_div.text(this.name)},revert_name:function(){this.name=this.old_name;this.name_div.text(this.name)}});var H=function(X,ad,ag){var Y=this,ah=Y.view;this.filters=(X!==undefined?v(X):[]);this.filters_available=false;this.filters_visible=false;this.tool=(ad!==undefined&&obj_length(ad)>0?new n(this,ad):undefined);this.parent_track=ag;this.child_tracks=[];if(Y.hidden){return}var af=function(ai,aj,ak){ai.click(function(){var al=aj.text();max=parseFloat(ak.slider("option","max")),input_size=(max<=1?4:max<=1000000?max.toString().length:6),multi_value=false;if(ak.slider("option","values")){input_size=2*input_size+1;multi_value=true}aj.text("");$("<input type='text'/>").attr("size",input_size).attr("maxlength",input_size).attr("value",al).appendTo(aj).focus().select().click(function(am){am.stopPropagation()}).blur(function(){$(this).remove();aj.text(al)}).keyup(function(aq){if(aq.keyCode===27){$(this).trigger("blur")}else{if(aq.keyCode===13){var ao=ak.slider("option","min"),am=ak.slider("option","max"),ap=function(ar){return(isNaN(ar)||ar>am||ar<ao)},an=$(this).val();if(!multi_value){an=parseFloat(an);if(ap(an)){alert("Parameter value must be in the range ["+ao+"-"+am+"]");return $(this)}}else{an=an.split("-");an=[parseFloat(an[0]),parseFloat(an[1])];if(ap(an[0])||ap(an[1])){alert("Parameter value must be in the range ["+ao+"-"+am+"]");return $(this)}}ak.slider((multi_value?"values":"value"),an)}}})})};if(this.parent_track){this.header_div.find(".draghandle").removeClass("draghandle").addClass("child-track-icon").addClass("icon-button");this.parent_element.addClass("child-track");this.tool=undefined}this.filters_div=$("<div/>").addClass("filters").hide();this.header_div.after(this.filters_div);this.filters_div.bind("drag",function(ai){ai.stopPropagation()}).bind("click",function(ai){ai.stopPropagation()}).bind("dblclick",function(ai){ai.stopPropagation()});$.each(this.filters,function(ao,aj){var al=$("<div/>").addClass("slider-row").appendTo(Y.filters_div);var ai=$("<div/>").addClass("slider-label").appendTo(al);var aq=$("<span/>").addClass("slider-name").text(aj.name+" ").appendTo(ai);var ak=$("<span/>");var am=$("<span/>").addClass("slider-value").appendTo(ai).append("[").append(ak).append("]");var ap=$("<div/>").addClass("slider").appendTo(al);aj.control_element=$("<div/>").attr("id",aj.name+"-filter-control").appendTo(ap);var an=[0,0];aj.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(ar,at){an=at.values;ak.text(at.values[0]+"-"+at.values[1]);setTimeout(function(){if(at.values[0]==an[0]&&at.values[1]==an[1]){var au=at.values;ak.text(au[0]+"-"+au[1]);aj.low=au[0];aj.high=au[1];Y.draw(true,true)}},50)},change:function(ar,at){aj.control_element.slider("option","slide").call(aj.control_element,ar,at)}});aj.slider=aj.control_element;aj.slider_label=ak;af(am,ak,aj.control_element);$("<div style='clear: both;'/>").appendTo(al)});if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}Y.child_tracks_container=$("<div/>").addClass("child-tracks-container").hide();Y.container_div.append(Y.child_tracks_container);if(Y.display_modes!==undefined){if(Y.mode_div===undefined){Y.mode_div=$("<div class='right-float menubutton popup' />").appendTo(Y.header_div);var aa=(Y.track_config&&Y.track_config.values.mode?Y.track_config.values.mode:Y.display_modes[0]);Y.mode=aa;Y.mode_div.text(aa);var Z=function(ai){Y.mode_div.text(ai);Y.mode=ai;Y.track_config.values.mode=ai;Y.tile_cache.clear();Y.draw()};var W={};for(var ab=0,ae=Y.display_modes.length;ab<ae;ab++){var ac=Y.display_modes[ab];W[ac]=function(ai){return function(){Z(ai)}}(ac)}make_popupmenu(Y.mode_div,W)}else{Y.mode_div.hide()}}this.make_name_popup_menu()};extend(H.prototype,k.prototype,{make_name_popup_menu:function(){var X=this;var W={};W["Edit configuration"]=function(){var ad=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ab=function(){X.track_config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(ae){if((ae.keyCode||ae.which)===27){ad()}else{if((ae.keyCode||ae.which)===13){ab()}}};$(window).bind("keypress.check_enter_esc",ac);show_modal("Configure Track",X.track_config.build_form(),{Cancel:ad,OK:ab})};if(X.filters_available>0){var aa=(X.filters_div.is(":visible")?"Hide filters":"Show filters");W[aa]=function(){X.filters_visible=(X.filters_div.is(":visible"));X.filters_div.toggle();X.make_name_popup_menu()}}if(X.tool){var aa=(X.dynamic_tool_div.is(":visible")?"Hide tool":"Show tool");W[aa]=function(){if(!X.dynamic_tool_div.is(":visible")){X.update_name(X.name+X.tool_region_and_parameters_str())}else{menu_option_text="Show dynamic tool";X.revert_name()}X.dynamic_tool_div.toggle();X.make_name_popup_menu()}}if(X.valid_chroms){W["List chrom/contigs with data"]=function(){show_modal("Chrom/contigs with data","<p>"+X.valid_chroms.join("<br/>")+"</p>",{Close:function(){hide_modal()}})}}var Y=view;var Z=function(){$("#no-tracks").show()};if(this.parent_track){Y=this.parent_track;Z=function(){}}W.Remove=function(){Y.remove_track(X);if(Y.num_tracks===0){Z()}};make_popupmenu(X.name_div,W)},draw:function(W,Z){var an=this.view.low,ac=this.view.high,ae=ac-an,ag=this.view.container.width(),ab=ag/ae,ah=this.view.resolution,aa=$("<div style='position: relative;'></div>");if(!Z){this.content_div.children().remove()}this.content_div.append(aa);this.max_height=0;var aj=Math.floor(an/ah/J);var Y={};while((aj*J*ah)<ac){var am=ag+"_"+ab+"_"+aj;var ad=this.tile_cache.get(am);var ak=aj*J*this.view.resolution;var X=ak+J*this.view.resolution;if(!W&&ad){this.show_tile(ad,aa,ak,ab)}else{this.delayed_draw(W,am,ak,X,aj,ah,aa,ab,Y)}aj+=1}var af=this;var al=setInterval(function(){if(obj_length(Y)===0){clearInterval(al);if(Z){var aq=af.content_div.children();var ap=false;for(var ar=aq.length-1,ao=0;ar>=ao;ar--){var av=$(aq[ar]);if(ap){av.remove()}else{if(av.children().length!==0){ap=true}}}}for(var au=0;au<af.filters.length;au++){af.filters[au].update_ui_elt()}var at=false;if(af.example_feature){for(var au=0;au<af.filters.length;au++){if(af.filters[au].applies_to(af.example_feature)){at=true;break}}}if(af.filters_available!==at){af.filters_available=at;if(!af.filters_available){af.filters_div.hide()}af.make_name_popup_menu()}}},50);for(var ai=0;ai<this.child_tracks.length;ai++){this.child_tracks[ai].draw(W,Z)}},delayed_draw:function(X,ae,ac,ag,Y,aa,af,ah,ab){var Z=this;var ad=function(ap,ai,ak,aj,an,ao,al){returned_tile=Z.draw_tile(ai,ak,aj,an,ao,al);var am=$("<div class='track-tile'>").prepend(returned_tile);tile_element=am;Z.tile_cache.set(ae,tile_element);Z.show_tile(tile_element,an,ac,ao);delete ab[ap]};var W=setTimeout(function(){if(ac<=Z.view.high&&ag>=Z.view.low){var ai=(X?undefined:Z.tile_cache.get(ae));if(ai){Z.show_tile(ai,af,ac,ah);delete ab[W]}else{$.when(Z.data_cache.get_data(view.chrom,ac,ag,Z.mode,aa,Z.data_url_extra_params)).then(function(aj){if(view.reference_track&&ah>view.canvas_manager.char_width_px){$.when(view.reference_track.data_cache.get_data(view.chrom,ac,ag,Z.mode,aa,view.reference_track.data_url_extra_params)).then(function(ak){ad(W,aj,aa,Y,af,ah,ak)})}else{ad(W,aj,aa,Y,af,ah)}})}}},50);ab[W]=true},show_tile:function(W,ab,Z,ac){var X=this;var Y=this.view.high-this.view.low,aa=(Z-this.view.low)*ac;if(this.left_offset){aa-=this.left_offset}W.css({position:"absolute",top:0,left:aa,height:""});ab.append(W);X.max_height=Math.max(X.max_height,W.height());X.content_div.css("height",X.max_height+"px");ab.children().css("height",X.max_height+"px")},set_overview:function(){var W=this.view;if(this.initial_canvas&&this.is_overview){W.overview_close.show();W.overview_viewport.append(this.initial_canvas);W.overview_highlight.show().height(this.initial_canvas.height());W.overview_viewport.height(this.initial_canvas.height()+W.overview_box.height())}$(window).trigger("resize")},tool_region_and_parameters_str:function(Y,W,Z){var X=this,aa=(Y!==undefined&&W!==undefined&&Z!==undefined?Y+":"+W+"-"+Z:"all");return" - region=["+aa+"], parameters=["+X.tool.get_param_values().join(", ")+"]"},add_track:function(W){W.track_id=this.track_id+"_"+this.child_tracks.length;W.container_div.attr("id","track_"+W.track_id);this.child_tracks_container.append(W.container_div);B(W.container_div,".child-track-icon");if(!$(this.child_tracks_container).is(":visible")){this.child_tracks_container.show()}this.child_tracks.push(W);this.view.has_changes=true},remove_track:function(W){W.container_div.fadeOut("slow",function(){$(this).remove()})}});var T=function(W,X){this.track_type="LabelTrack";this.hidden=true;k.call(this,null,W,X);this.container_div.addClass("label-track")};extend(T.prototype,k.prototype,{draw:function(){var Y=this.view,Z=Y.high-Y.low,ac=Math.floor(Math.pow(10,Math.floor(Math.log(Z)/Math.log(10)))),W=Math.floor(Y.low/ac)*ac,aa=this.view.container.width(),X=$("<div style='position: relative; height: 1.3em;'></div>");while(W<Y.high){var ab=(W-Y.low)/Z*aa;X.append($("<div class='label'>"+commatize(W)+"</div>").css({position:"absolute",left:ab-1}));W+=ac}this.content_div.children(":first").remove();this.content_div.append(X)}});var x=function(W){this.track_type="ReferenceTrack";this.hidden=true;k.call(this,null,W,W.top_labeltrack);H.call(this);W.reference_track=this;this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url;this.data_url_extra_params={dbkey:W.dbkey};this.data_cache=new K(y,this,false);this.tile_cache=new c(q)};extend(x.prototype,H.prototype,{draw_tile:function(ag,ab,X,ad,ah){var aa=this,Y=J*ab;if(ah>this.view.canvas_manager.char_width_px){if(ag===null){aa.content_div.css("height","0px");return}var Z=this.view.canvas_manager.new_canvas();var af=Z.getContext("2d");Z.width=Math.ceil(Y*ah+aa.left_offset);Z.height=aa.height_px;af.font=af.canvas.manager.default_font;af.textAlign="center";for(var ac=0,ae=ag.length;ac<ae;ac++){var W=Math.round(ac*ah);af.fillText(ag[ac],W+aa.left_offset,10)}return Z}this.content_div.css("height","0px")}});var l=function(aa,Y,ab,W,Z){var X=this;this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";k.call(this,aa,Y,Y.viewport_container);H.call(this);this.min_height_px=16;this.max_height_px=400;this.height_px=80;this.hda_ldda=ab;this.dataset_id=W;this.original_dataset_id=W;this.data_cache=new K(y,this);this.tile_cache=new c(q);this.track_config=new S({track:this,params:[{key:"color",label:"Color",type:"color",default_value:"black"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.height_px,hidden:true}],saved_values:Z,onchange:function(){X.vertical_range=X.prefs.max_value-X.prefs.min_value;$("#linetrack_"+X.track_id+"_minval").text(X.prefs.min_value);$("#linetrack_"+X.track_id+"_maxval").text(X.prefs.max_value);X.tile_cache.clear();X.draw()}});this.prefs=this.track_config.values;this.height_px=this.track_config.values.height;this.vertical_range=this.track_config.values.max_value-this.track_config.values.min_value;this.add_resize_handle()};extend(l.prototype,H.prototype,{add_resize_handle:function(){var W=this;var Z=false;var Y=false;var X=$("<div class='track-resize'>");$(W.container_div).hover(function(){Z=true;X.show()},function(){Z=false;if(!Y){X.hide()}});X.hide().bind("dragstart",function(aa,ab){Y=true;ab.original_height=$(W.content_div).height()}).bind("drag",function(ab,ac){var aa=Math.min(Math.max(ac.original_height+ac.deltaY,W.min_height_px),W.max_height_px);$(W.content_div).css("height",aa);W.height_px=aa;W.draw(true)}).bind("dragend",function(aa,ab){W.tile_cache.clear();Y=false;if(!Z){X.hide()}W.track_config.values.height=W.height_px}).appendTo(W.container_div)},predraw_init:function(){var W=this,X=W.view.tracks.indexOf(W);W.vertical_range=undefined;return $.getJSON(W.data_url,{stats:true,chrom:W.view.chrom,low:null,high:null,hda_ldda:W.hda_ldda,dataset_id:W.dataset_id},function(Y){W.container_div.addClass("line-track");var aa=Y.data;if(isNaN(parseFloat(W.prefs.min_value))||isNaN(parseFloat(W.prefs.max_value))){W.prefs.min_value=aa.min;W.prefs.max_value=aa.max;$("#track_"+X+"_minval").val(W.prefs.min_value);$("#track_"+X+"_maxval").val(W.prefs.max_value)}W.vertical_range=W.prefs.max_value-W.prefs.min_value;W.total_frequency=aa.total_frequency;W.container_div.find(".yaxislabel").remove();var ab=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+X+"_minval").text(t(W.prefs.min_value));var Z=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+X+"_maxval").text(t(W.prefs.max_value));Z.css({position:"absolute",top:"24px",left:"10px"});Z.prependTo(W.container_div);ab.css({position:"absolute",bottom:"2px",left:"10px"});ab.prependTo(W.container_div)})},draw_tile:function(ah,aa,X,ae,ag){if(this.vertical_range===undefined){return}var ab=X*J*aa,Z=J*aa,W=Math.ceil(Z*ag),ad=this.height_px;var Y=this.view.canvas_manager.new_canvas();Y.width=W,Y.height=ad;var af=Y.getContext("2d");var ac=new G.LinePainter(ah.data,ab,ab+Z,this.prefs.min_value,this.prefs.max_value,this.prefs.color,this.mode);ac.draw(af,W,ad);return Y}});var e=function(W,ab,aa,ae,ad,Y,Z,ac){var X=this;this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];this.track_config=new S({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:ad,onchange:function(){X.tile_cache.clear();X.draw()}});this.prefs=this.track_config.values;k.call(this,W,ab,ab.viewport_container);H.call(this,Y,Z,ac);this.height_px=0;this.container_div.addClass("feature-track");this.hda_ldda=aa;this.dataset_id=ae;this.original_dataset_id=ae;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.inc_slots={};this.start_end_dct={};this.tile_cache=new c(d);this.data_cache=new K(20,this);this.left_offset=200;this.painter=G.LinkedFeaturePainter};extend(e.prototype,H.prototype,{update_auto_mode:function(W){if(this.mode=="Auto"){if(W=="no_detail"){W="reduced to feature spans"}else{if(W=="summary_tree"){W="reduced to coverage histogram"}}this.mode_div.text("Auto ("+W+")")}},incremental_slots:function(aa,X,Z){var Y=this.view.canvas_manager.dummy_context,W=this.inc_slots[aa];if(!W||(W.mode!==Z)){W=new (o.FeatureSlotter)(aa,Z==="Pack",w,function(ab){return Y.measureText(ab)});W.mode=Z;this.inc_slots[aa]=W}return W.slot_features(X)},draw_tile:function(ai,aq,av,ae,ag,Z){var an=this,ax=av*J*aq,X=(av+1)*J*aq,ak=X-ax,ao=Math.ceil(ak*ag),am=this.mode,aB=25,aa=this.left_offset,aj,ab;if(am==="Auto"){if(ai.dataset_type==="summary_tree"){am=ai.dataset_type}else{if(ai.extra_info==="no_detail"){am="no_detail"}else{var aA=ai.data;if((aA.length&&aA.length<4)||(this.view.high-this.view.low>D)){am="Squish"}else{am="Pack"}}}this.update_auto_mode(am)}if(am==="summary_tree"){ab=this.summary_draw_height;ae.parent().css("height",Math.max(this.height_px,ab)+"px");this.container_div.find(".yaxislabel").remove();var W=$("<div />").addClass("yaxislabel");W.text(ai.max);W.css({position:"absolute",top:"22px",left:"10px"});W.prependTo(this.container_div);var Y=this.view.canvas_manager.new_canvas();Y.width=ao+aa;Y.height=ab+L;var ay=new G.SummaryTreePainter(ai.data,ai.delta,ai.max,ax,X,this.prefs.show_counts);var ap=Y.getContext("2d");ap.translate(aa,L);ay.draw(ap,ao,ab);return Y}var aj,ad=1;if(am==="no_detail"||am==="Squish"||am==="Pack"){ad=this.incremental_slots(ag,ai.data,am);aj=this.inc_slots[ag].slots}var af=[];if(ai.data){for(var ar=0,au=ai.data.length;ar<au;ar++){var ac=ai.data[ar];var at=false;var ah;for(var aw=0,az=this.filters.length;aw<az;aw++){ah=this.filters[aw];ah.update_attrs(ac);if(!ah.keep(ac)){at=true;break}}if(!at){af.push(ac)}}}var ay=new (this.painter)(af,ax,X,this.prefs,am,Z);var ab=ay.get_required_height(ad)+z;var Y=this.view.canvas_manager.new_canvas();Y.width=ao+aa;Y.height=ab;ae.parent().css("height",Math.max(this.height_px,ab)+"px");var ap=Y.getContext("2d");ap.fillStyle=this.prefs.block_color;ap.font=ap.canvas.manager.default_font;ap.textAlign="right";this.container_div.find(".yaxislabel").remove();if(ai.message){$(Y).css({"border-top":"1px solid red"});ap.fillStyle="red";ap.textAlign="left";var al=ap.textBaseline;ap.textBaseline="top";ap.fillText(ai.message,aa,0);ap.textBaseline=al;if(!ai.data){return Y}}this.example_feature=(ai.data.length?ai.data[0]:undefined);ap.translate(aa,z);ay.draw(ap,ao,ab,aj);return Y}});var M=function(Z,X,ab,W,Y,aa){e.call(this,Z,X,ab,W,Y,aa);this.track_type="VcfTrack";this.painter=G.VariantPainter};extend(M.prototype,H.prototype,e.prototype);var P=function(Z,X,ab,W,Y,aa){e.call(this,Z,X,ab,W,Y,aa);this.track_config=new S({track:this,params:[{key:"block_color",label:"Block color",type:"color",default_value:"#444"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},],saved_values:Y,onchange:function(){this.track.tile_cache.clear();this.track.draw()}});this.prefs=this.track_config.values;this.track_type="ReadTrack";this.painter=G.ReadPainter;this.make_name_popup_menu()};extend(P.prototype,H.prototype,e.prototype);var N=function(aa,Y,ac,W,Z,ab,X){e.call(this,aa,Y,ac,W,Z,ab,{},X);this.track_type="ToolDataFeatureTrack";this.data_url=raw_data_url;this.data_query_wait=1000;this.dataset_check_url=dataset_state_url};extend(N.prototype,H.prototype,e.prototype,{predraw_init:function(){var X=this;var W=function(){if(X.data_cache.size()===0){setTimeout(W,300)}else{X.data_url=default_data_url;X.data_query_wait=F;X.dataset_state_url=converted_datasets_state_url;$.getJSON(X.dataset_state_url,{dataset_id:X.dataset_id,hda_ldda:X.hda_ldda},function(Y){})}};W()}});Q.View=U;Q.LineTrack=l;Q.FeatureTrack=e;Q.ReadTrack=P};var slotting_module=function(c,b){var d=2,a=5;b.FeatureSlotter=function(h,g,e,f){this.slots={};this.start_end_dct={};this.w_scale=h;this.include_label=g;this.max_rows=e;this.measureText=f};extend(b.FeatureSlotter.prototype,{slot_features:function(l){var o=this.w_scale,r=this.slots,g=this.start_end_dct,x=[],z=[],m=0,y=this.max_rows;for(var v=0,w=l.length;v<w;v++){var k=l[v],n=k[0];if(r[n]!==undefined){m=Math.max(m,r[n]);z.push(r[n])}else{x.push(v)}}var p=function(F,G){for(var E=0;E<=y;E++){var C=false,H=g[E];if(H!==undefined){for(var B=0,D=H.length;B<D;B++){var A=H[B];if(G>A[0]&&F<A[1]){C=true;break}}}if(!C){return E}}return -1};for(var v=0,w=x.length;v<w;v++){var k=l[x[v]],n=k[0],t=k[1],e=k[2],q=k[3],f=Math.floor(t*o),j=Math.ceil(e*o),u=this.measureText(q).width,h;if(q!==undefined&&this.include_label){u+=(d+a);if(f-u>=0){f-=u;h="left"}else{j+=u;h="right"}}var s=p(f,j);if(s>=0){if(g[s]===undefined){g[s]=[]}g[s].push([f,j]);r[n]=s;m=Math.max(m,s)}else{}}return m+1}})};var painters_module=function(k,A){var q=function(L,D,J,C,I,G){if(G===undefined){G=4}var F=C-D;var E=I-J;var H=Math.floor(Math.sqrt(F*F+E*E)/G);var M=F/H;var K=E/H;var B;for(B=0;B<H;B++,D+=M,J+=K){if(B%2!==0){continue}L.fillRect(D,J,G,1)}};var r=function(D,C,B,G){var F=C-G/2,E=C+G/2,H=B-Math.sqrt(G*3/2);D.beginPath();D.moveTo(F,H);D.lineTo(E,H);D.lineTo(C,B);D.lineTo(F,H);D.strokeStyle=this.fillStyle;D.fill();D.stroke();D.closePath()};var v=function(E,G,C,F,B,D){this.data=E;this.delta=G;this.max=C;this.view_start=F;this.view_end=B;this.show_counts=D};v.prototype.draw=function(O,B,N){var G=this.view_start,Q=this.view_end-this.view_start,P=B/Q;var L=this.data,K=this.delta,I=this.max,D=N;delta_x_px=Math.ceil(K*P);O.save();for(var E=0,F=L.length;E<F;E++){var J=Math.floor((L[E][0]-G)*P);var H=L[E][1];if(!H){continue}var M=H/I*N;O.fillStyle="black";O.fillRect(J,D-M,delta_x_px,M);var C=4;if(this.show_counts&&(O.measureText(H).width+C)<delta_x_px){O.fillStyle="#666";O.textAlign="center";O.fillText(H,J+(delta_x_px/2),10)}}O.restore()};var c=function(E,H,B,C,G,D,F){this.data=E;this.view_start=H;this.view_end=B;this.min_value=C;this.max_value=G;this.color=D;this.mode=F;this.overflow_color="#F66"};c.prototype.draw=function(Q,P,N){var I=false,J=this.min_value,G=this.max_value,M=G-J,C=N,D=this.view_start,O=this.view_end-this.view_start,E=P/O,K=this.mode,U=this.data;Q.save();var V=Math.round(N+J/M*N);if(K!=="Intensity"){Q.fillStyle="#aaa";Q.fillRect(0,V,P,1)}Q.beginPath();Q.fillStyle=this.color;var T,H,F;if(U.length>1){F=Math.ceil((U[1][0]-U[0][0])*E)}else{F=10}for(var R=0,S=U.length;R<S;R++){T=Math.round((U[R][0]-D)*E);H=U[R][1];if(H===null){if(I&&K==="Filled"){Q.lineTo(T,C)}I=false;continue}if(H<J){H=J}else{if(H>G){H=G}}if(K==="Histogram"){H=Math.round(H/M*C);Q.fillRect(T,V,F,-H)}else{if(K==="Intensity"){H=255-Math.floor((H-J)/M*255);Q.fillStyle="rgb("+H+","+H+","+H+")";Q.fillRect(T,0,F,C)}else{H=Math.round(C-(H-J)/M*C);if(I){Q.lineTo(T,H)}else{I=true;if(K==="Filled"){Q.moveTo(T,C);Q.lineTo(T,H)}else{Q.moveTo(T,H)}}}}}if(K==="Filled"){if(I){Q.lineTo(T,V);Q.lineTo(0,V)}Q.fill()}else{Q.stroke()}var B=-1,L=-1;Q.fillStyle=this.overflow_color;for(var R=0,S=U.length;R<S;R++){H=U[R][1];T=Math.round((U[R][0]-D)*E);x_minus_scaled=Math.round((U[R][0]-1-D)*E);if(L>=0&&(H===null||H<G)){Q.fillRect(L,0,x_minus_scaled-L+1,2);L=-1}else{if(B>=0&&(H===null||H>J)){Q.fillRect(B,N-2,x_minus_scaled-B+1,2);B=-1}}if(H!==null&&H>G&&L<0){L=T}else{if(H!==null&&H<J&&B<0){B=T}}}Q.restore()};var p=function(D,F,B,C,E){this.data=D;this.view_start=F;this.view_end=B;this.prefs=C;this.mode=E};extend(p.prototype,{get_required_height:function(C){var B=y_scale=this.get_row_height(),D=this.mode;if(D==="no_detail"||D==="Squish"||D==="Pack"){B=C*y_scale}return B+Math.max(Math.round(y_scale/2),5)},draw:function(N,E,M,J){var H=this.data,K=this.view_start,O=this.view_end;N.save();N.fillStyle=this.prefs.block_color;N.textAlign="right";var R=this.view_end-this.view_start,Q=E/R,D=this.get_row_height();for(var G=0,I=H.length;G<I;G++){var P=H[G],F=P[0],B=P[1],C=P[2],L=(J&&J[F]!==undefined?J[F]:null);if((B<O&&C>K)&&(this.mode=="Dense"||L!==null)){this.draw_element(N,this.mode,P,L,K,O,Q,D,E)}}N.restore()}});var d=10,j=3,n=5,z=10,g=1,t=3,f=3,a=9,o=2,h="#ccc";var s=function(D,F,B,C,E){p.call(this,D,F,B,C,E)};extend(s.prototype,p.prototype,{get_row_height:function(){var C=this.mode,B;if(C==="Dense"){B=d}else{if(C==="no_detail"){B=j}else{if(C==="Squish"){B=n}else{B=z}}}return B},draw_element:function(N,G,V,I,P,af,aj,ak,B){var S=V[0],ah=V[1],Z=V[2]-1,Q=V[3],aa=Math.floor(Math.max(0,(ah-P)*aj)),O=Math.ceil(Math.min(B,Math.max(0,(Z-P)*aj))),Y=(G==="Dense"?0:(0+I))*ak,M,ad,R=null,al=null,E=this.prefs.block_color,ac=this.prefs.label_color;if(G=="Dense"){I=1}if(G==="no_detail"){N.fillStyle=E;N.fillRect(aa,Y+5,O-aa,g)}else{var L=V[4],X=V[5],ab=V[6],F=V[7];if(X&&ab){R=Math.floor(Math.max(0,(X-P)*aj));al=Math.ceil(Math.min(B,Math.max(0,(ab-P)*aj)))}var ai,T;if(G==="Squish"||G==="Dense"){ai=1;T=f}else{ai=5;T=a}if(!F){if(V.strand){if(V.strand==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand_inv")}else{if(V.strand==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand_inv")}}}else{N.fillStyle=E}N.fillRect(aa,Y,O-aa,T)}else{var K,U;if(G==="Squish"||G==="Dense"){N.fillStyle=h;K=Y+Math.floor(f/2)+1;U=1}else{if(L){var K=Y;var U=T;if(L==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand")}else{if(L==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand")}}}else{N.fillStyle=h;K+=(f/2)+1;U=1}}N.fillRect(aa,K,O-aa,U);for(var ag=0,D=F.length;ag<D;ag++){var H=F[ag],C=Math.floor(Math.max(0,(H[0]-P)*aj)),W=Math.ceil(Math.min(B,Math.max((H[1]-1-P)*aj)));if(C>W){continue}N.fillStyle=E;N.fillRect(C,Y+(T-ai)/2+1,W-C,ai);if(R!==undefined&&ab>X&&!(C>al||W<R)){var ae=Math.max(C,R),J=Math.min(W,al);N.fillRect(ae,Y+1,J-ae,T);if(F.length==1&&G=="Pack"){if(L==="+"){N.fillStyle=N.canvas.manager.get_pattern("right_strand_inv")}else{if(L==="-"){N.fillStyle=N.canvas.manager.get_pattern("left_strand_inv")}}if(ae+14<J){ae+=2;J-=2}N.fillRect(ae,Y+1,J-ae,T)}}}}if(G==="Pack"&&ah>P){N.fillStyle=ac;if(P===0&&aa-N.measureText(Q).width<0){N.textAlign="left";N.fillText(Q,O+o,Y+8)}else{N.textAlign="right";N.fillText(Q,aa-o,Y+8)}N.fillStyle=E}}}});var b=function(D,F,B,C,E){p.call(this,D,F,B,C,E)};extend(b.prototype,p.prototype,{draw_element:function(U,P,J,F,X,D,M,V,S){var J=data[i],L=J[0],T=J[1],E=J[2]-1,O=J[3],H=Math.floor(Math.max(0,(T-X)*M)),K=Math.ceil(Math.min(S,Math.max(0,(E-X)*M))),G=(P==="Dense"?0:(0+F))*V,B,Y,C=null,N=null;if(no_label){U.fillStyle=block_color;U.fillRect(H+left_offset,G+5,K-H,1)}else{var W=J[4],R=J[5],I=J[6];B=9;Y=1;U.fillRect(H+left_offset,G,K-H,B);if(P!=="Dense"&&O!==undefined&&T>X){U.fillStyle=label_color;if(X===0&&H-U.measureText(O).width<0){U.textAlign="left";U.fillText(O,K+2+left_offset,G+8)}else{U.textAlign="right";U.fillText(O,H-2+left_offset,G+8)}U.fillStyle=block_color}var Q=W+" / "+R;if(T>X&&U.measureText(Q).width<(K-H)){U.fillStyle="white";U.textAlign="center";U.fillText(Q,left_offset+H+(K-H)/2,G+8);U.fillStyle=block_color}}}});var y=1001,m=1002,e=1003,x=1004,l=1005;var w=function(F,C){var H=F[0],G=F[1],E=C[0],D=C[1],B;if(H<E){if(G<E){B=y}else{if(G<=D){B=e}else{B=m}}}else{if(H>D){B=y}else{if(G<=D){B=l}else{B=x}}}return B};var u=function(E,G,B,D,F,C){p.call(this,E,G,B,D,F);this.ref_seq=C};extend(u.prototype,p.prototype,{get_row_height:function(){var B,C=this.mode;if(C==="Dense"){B=d}else{if(C==="Squish"){B=n}else{B=z;if(this.prefs.show_insertions){B*=2}}}return B},draw_read:function(Y,T,O,ad,D,X,L,I,H){Y.textAlign="center";var W=this,C=[ad,D],R=0,Z=0,V=0;ref_seq=this.ref_seq,char_width_px=Y.canvas.manager.char_width_px;var ai=[];if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){V=Math.round(O/2)}if(!L){L=[[0,I.length]]}for(var P=0,ab=L.length;P<ab;P++){var M=L[P],E="MIDNSHP=X"[M[0]],Q=M[1];if(E==="H"||E==="S"){R-=Q}var J=X+R,ah=Math.floor(Math.max(0,(J-ad)*O)),K=Math.floor(Math.max(0,(J+Q-ad)*O));switch(E){case"H":break;case"S":case"M":case"=":var S=w([J,J+Q],C);if(S!==y){var U=I.slice(Z,Z+Q);if(V>0){Y.fillStyle=this.prefs.block_color;Y.fillRect(ah-V,H+1,K-ah,9);Y.fillStyle=h;for(var af=0,B=U.length;af<B;af++){if(this.prefs.show_differences&&ref_seq){var N=ref_seq[J-ad+af];if(!N||N.toLowerCase()===U[af].toLowerCase()){continue}}if(J+af>=ad&&J+af<=D){var ag=Math.floor(Math.max(0,(J+af-ad)*O));Y.fillText(U[af],ag,H+9)}}}else{Y.fillStyle=this.prefs.block_color;Y.fillRect(ah,H+4,K-ah,f)}}Z+=Q;R+=Q;break;case"N":Y.fillStyle=h;Y.fillRect(ah-V,H+5,K-ah,1);R+=Q;break;case"D":Y.fillStyle="red";Y.fillRect(ah-V,H+4,K-ah,3);R+=Q;break;case"P":break;case"I":var S=w([J,J+Q],C),ac=ah-V;if(S!==y){var U=I.slice(Z,Z+Q);if(this.prefs.show_insertions){var G=ah-(K-ah)/2;if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){Y.fillStyle="yellow";Y.fillRect(G-V,H-9,K-ah,9);ai[ai.length]={type:"triangle",data:[ac,H+4,5]};Y.fillStyle=h;switch(S){case (e):U=U.slice(ad-J);break;case (x):U=U.slice(0,J-D);break;case (l):break;case (m):U=U.slice(ad-J,J-D);break}for(var af=0,B=U.length;af<B;af++){var ag=Math.floor(Math.max(0,(J+af-ad)*O));Y.fillText(U[af],ag-(K-ah)/2,H)}}else{Y.fillStyle="yellow";Y.fillRect(G,H+(this.mode!=="Dense"?2:5),K-ah,(T!=="Dense"?f:t))}}else{if((T==="Pack"||this.mode==="Auto")&&I!==undefined&&O>char_width_px){ai[ai.length]={type:"text",data:[U.length,ac,H+9]}}else{}}}Z+=Q;break;case"X":Z+=Q;break}}Y.fillStyle="yellow";var ae,F,aj;for(var aa=0;aa<ai.length;aa++){ae=ai[aa];F=ae.type;aj=ae.data;if(F==="text"){Y.save();Y.font="bold "+Y.font;Y.fillText(aj[0],aj[1],aj[2]);Y.restore()}else{if(F=="triangle"){r(Y,aj[0],aj[1],aj[2])}}}},draw_element:function(U,P,H,E,X,C,L,V,S){var K=H[0],T=H[1],D=H[2],M=H[3],G=Math.floor(Math.max(0,(T-X)*L)),I=Math.ceil(Math.min(S,Math.max(0,(D-X)*L))),F=(P==="Dense"?0:(0+E))*V,Y=this.prefs.block_color,J=this.prefs.label_color,R=0;if((P==="Pack"||this.mode==="Auto")&&L>U.canvas.manager.char_width_px){var R=Math.round(L/2)}U.fillStyle=Y;if(H[5] instanceof Array){var Q=Math.floor(Math.max(0,(H[4][0]-X)*L)),O=Math.ceil(Math.min(S,Math.max(0,(H[4][1]-X)*L))),N=Math.floor(Math.max(0,(H[5][0]-X)*L)),B=Math.ceil(Math.min(S,Math.max(0,(H[5][1]-X)*L)));if(H[4][1]>=X&&H[4][0]<=C&&H[4][2]){this.draw_read(U,P,L,X,C,H[4][0],H[4][2],H[4][3],F)}if(H[5][1]>=X&&H[5][0]<=C&&H[5][2]){this.draw_read(U,P,L,X,C,H[5][0],H[5][2],H[5][3],F)}if(N>O){U.fillStyle=h;q(U,O-R,F+5,N-R,F+5)}}else{U.fillStyle=Y;this.draw_read(U,P,L,X,C,T,H[4],H[5],F)}if(P==="Pack"&&T>X){U.fillStyle=this.prefs.label_color;var W=1;if(W===0&&G-U.measureText(M).width<0){U.textAlign="left";U.fillText(M,I+o-R,F+8)}else{U.textAlign="right";U.fillText(M,G-o-R,F+8)}U.fillStyle=Y}}});A.SummaryTreePainter=v;A.LinePainter=c;A.LinkedFeaturePainter=s;A.ReadPainter=u;A.VariantPainter=b};(function(d){var c={};var b=function(e){return c[e]};var a=function(f,g){var e={};g(b,e);c[f]=e};a("slotting",slotting_module);a("painters",painters_module);a("trackster",trackster_module);for(key in c.trackster){d[key]=c.trackster[key]}})(window);
\ No newline at end of file
--- a/static/scripts/trackster.js Mon Apr 04 23:27:25 2011 -0400
+++ b/static/scripts/trackster.js Tue Apr 05 11:51:48 2011 -0400
@@ -104,7 +104,7 @@
*/
var get_slider_step = function(min, max) {
var range = max - min;
- return (range <= 1 ? 0.01 : (range <= 1000 ? 1 : 5));
+ return (range <= 2 ? 0.01 : (range <= 100 ? 1 : (range <= 1000 ? 5 : 10)));
}
/**
@@ -756,10 +756,13 @@
});
/**
- * Encapsulation of tools that users can apply to tracks/datasets.
+ * Encapsulation of a tool that users can apply to tracks/datasets.
*/
-var Tool = function(tool_dict) {
- // Unpack tool from dictionary.
+var Tool = function(track, tool_dict) {
+ //
+ // Unpack tool information from dictionary.
+ //
+ this.track = track;
this.name = tool_dict.name;
this.params = [];
var params_dict = tool_dict.params;
@@ -767,56 +770,161 @@
var param_dict = params_dict[i],
name = param_dict.name,
label = param_dict.label,
+ html = unescape(param_dict.html),
type = param_dict.type;
- if (type === "int" || type === "float") {
+ if (type === "number") {
this.params[this.params.length] =
- new NumberParameter(name, label, param_dict.min, param_dict.max, param_dict.value);
+ new NumberParameter(name, label, html, param_dict.min, param_dict.max);
}
else if (type == "select") {
- this.params[this.params.length] = new SelectParameter(name, label, param_dict.options);
+ this.params[this.params.length] = new ToolParameter(name, label, html);
}
else {
console.log("WARNING: unrecognized tool parameter type:", name, type);
}
}
+
+ //
+ // Create div elt for tool UI.
+ //
+ this.parent_div = $("<div/>").addClass("dynamic-tool").hide();
+ // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz.
+ this.parent_div.bind("drag", function(e) {
+ e.stopPropagation();
+ }).bind("click", function(e) {
+ e.stopPropagation();
+ }).bind("dblclick", function(e) {
+ e.stopPropagation();
+ });
+ var name_div = $("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);
+ var tool_params = this.params;
+ var tool = this;
+ $.each(this.params, function(index, param) {
+ var param_div = $("<div>").addClass("param-row").appendTo(tool.parent_div);
+ // Param label.
+ var label_div = $("<div>").addClass("param-label").text(param.label).appendTo(param_div);
+ // Param HTML.
+ // TODO: either generalize .slider CSS attributes or create new rule for tool input div.
+ var html_div = $("<div/>").addClass("slider").html(param.html).appendTo(param_div);
+
+ // Add to clear floating layout.
+ $("<div style='clear: both;'/>").appendTo(param_div);
+ });
+
+ // Highlight value for inputs for easy replacement.
+ this.parent_div.find("input").click(function() { $(this).select() });
+
+ // Add 'Go' button.
+ var run_tool_row = $("<div>").addClass("slider-row").appendTo(this.parent_div);
+ var run_tool_button = $("<input type='submit'>").attr("value", "Run").appendTo(run_tool_row);
+ var tool = this;
+ run_tool_button.click( function() {
+ tool.run();
+ });
};
extend(Tool.prototype, {
- // Returns a dictionary of parameter values; key is parameter name, value
- // is parameter value.
+ /**
+ * Returns dictionary of parameter name-values.
+ */
get_param_values_dict: function() {
var param_dict = {};
- for (var i = 0; i < this.params.length; i++) {
- var param = this.params[i];
- param_dict[param.name] = JSON.stringify(param.value);
- }
+ this.parent_div.find(":input").each(function() {
+ var name = $(this).attr("name"), value = $(this).val();
+ param_dict[name] = JSON.stringify(value);
+ });
return param_dict;
},
- // Returns an array of parameter values.
+ /**
+ * Returns array of parameter values.
+ */
get_param_values: function() {
var param_values = [];
- for (var i = 0; i < this.params.length; i++) {
- param_values[i] = this.params[i].value;
+ var param_dict = {};
+ this.parent_div.find(":input").each(function() {
+ // Only include inputs with names; this excludes Run button.
+ var name = $(this).attr("name"), value = $(this).val();
+ if (name) {
+ param_values[param_values.length] = value;
+ }
+ });
+ return param_values;
+ },
+ /**
+ * Run tool. This creates a new child track, runs tool, and places tool's output in the new track.
+ */
+ run: function() {
+ // Put together params for running tool.
+ var url_params = {
+ dataset_id: this.track.original_dataset_id,
+ chrom: this.track.view.chrom,
+ low: this.track.view.low,
+ high: this.track.view.high,
+ tool_id: this.name
+ };
+ $.extend(url_params, this.get_param_values_dict());
+
+ //
+ // Create track for tool's output immediately to provide user feedback.
+ //
+ var
+ current_track = this.track,
+ // Set name of track to include tool name, parameters, and region used.
+ track_name = url_params.tool_id +
+ current_track.tool_region_and_parameters_str(url_params.chrom, url_params.low, url_params.high),
+ new_track;
+
+ // TODO: add support for other kinds of tool data tracks.
+ if (current_track.track_type === 'FeatureTrack') {
+ new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track);
}
- return param_values;
+
+ this.track.add_track(new_track);
+ new_track.content_div.text("Starting job.");
+
+ // Run tool.
+ var json_run_tool = function() {
+ $.getJSON(run_tool_url, url_params, function(track_data) {
+ if (track_data === "no converter") {
+ // No converter available for input datasets, so cannot run tool.
+ new_track.container_div.addClass("error");
+ new_track.content_div.text(DATA_NOCONVERTER);
+ }
+ else if (track_data.error) {
+ // General error.
+ new_track.container_div.addClass("error");
+ new_track.content_div.text(DATA_CANNOT_RUN_TOOL + track_data.message);
+ }
+ else if (track_data === "pending") {
+ // Converting/indexing input datasets; show message and try again.
+ new_track.container_div.addClass("pending");
+ new_track.content_div.text("Converting input data so that it can be easily reused.");
+ setTimeout(json_run_tool, 2000);
+ }
+ else {
+ // Job submitted and running.
+ new_track.dataset_id = track_data.dataset_id;
+ new_track.content_div.text("Running job.");
+ new_track.init();
+ }
+ });
+ };
+ json_run_tool();
}
});
/**
* Tool parameters.
*/
-var NumberParameter = function(name, label, min, max, init_value) {
+var ToolParameter = function(name, label, html) {
this.name = name;
this.label = label;
+ this.html = html;
+};
+
+var NumberParameter = function(name, label, html, min, max) {
+ ToolParameter.call(this, name, label, html)
this.min = min;
this.max = max;
- this.value = init_value;
-};
-
-var SelectParameter = function(name, label, options) {
- this.name = name;
- this.label = label;
- this.options = options;
- this.value = (options.length !== 0 ? options[0][1] : null);
};
/**
@@ -1157,7 +1265,7 @@
// filters_available is determined by data, filters_visible is set by user.
this.filters_available = false;
this.filters_visible = false;
- this.tool = (tool_dict !== undefined && obj_length(tool_dict) > 0 ? new Tool(tool_dict) : undefined);
+ this.tool = (tool_dict !== undefined && obj_length(tool_dict) > 0 ? new Tool(this, tool_dict) : undefined);
//
// TODO: Right now there is only the notion of a parent track and multiple child tracks. However,
@@ -1250,7 +1358,7 @@
// Disable dragging, double clicking on div so that actions on slider do not impact viz.
this.filters_div.bind("drag", function(e) {
e.stopPropagation();
- }).bind("click", function( e ) {
+ }).bind("click", function(e) {
e.stopPropagation();
}).bind("dblclick", function(e) {
e.stopPropagation();
@@ -1311,89 +1419,8 @@
// Create dynamic tool div.
//
if (this.tool) {
- // Create div elt for tool UI.
- this.dynamic_tool_div = $("<div/>").addClass("dynamic-tool").hide();
+ this.dynamic_tool_div = this.tool.parent_div;
this.header_div.after(this.dynamic_tool_div);
- // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz.
- this.dynamic_tool_div.bind( "drag", function(e) {
- e.stopPropagation();
- }).bind("click", function( e ) {
- e.stopPropagation();
- }).bind("dblclick", function( e ) {
- e.stopPropagation();
- });
- var name_div = $("<div class='tool-name'>").appendTo(this.dynamic_tool_div).text(this.tool.name);
- var tool_params = this.tool.params;
- var track = this;
- $.each(this.tool.params, function(index, param) {
-
- if (param instanceof NumberParameter) {
- var param_div = $("<div>").addClass("slider-row").appendTo(track.dynamic_tool_div);
-
- // Slider label.
- var label_div = $("<div>").addClass("slider-label").appendTo(param_div);
- var name_span = $("<span/>").addClass("slider-name").text(param.label + " ").appendTo(label_div);
- var values_span = $("<span/>").text(param.value);
- var values_span_container = $("<span/>").addClass("slider-value").appendTo(label_div).append("[").append(values_span).append("]");
-
- // Slider.
- var slider_div = $("<div/>").addClass("slider").appendTo(param_div);
- var slider = $("<div id='" + param.name + "-param-control'>").appendTo(slider_div);
- // Step must have a value so that (max-min)%step == 0.
- slider.slider({
- min: param.min,
- max: param.max,
- step: get_slider_step(param.min, param.max),
- value: param.value,
- slide: function(event, ui) {
- var value = ui.value;
- param.value = value;
- // Set new value in UI.
- if (0 < value && value < 1) {
- value = parseFloat(value).toFixed(2);
- }
- values_span.text(value);
- },
- change: function(event, ui) {
- slider.slider("option", "slide").call(slider, event, ui);
- }
- });
-
- // Enable users to edit parameter's value via text box.
- edit_slider_values(values_span_container, values_span, slider);
-
- // Add to clear floating layout.
- $("<div style='clear: both;'/>").appendTo(param_div);
- }
- else if (param instanceof SelectParameter) {
- var param_div = $("<div>").addClass("slider-row").appendTo(track.dynamic_tool_div);
-
- // Param label.
- var label_div = $("<div>").addClass("slider-label").appendTo(param_div);
- var name_span = $("<span/>").addClass("slider-name").text(param.label + " ").appendTo(label_div);
-
- // Param selector.
- var select_div = $("<div/>").addClass("slider").appendTo(param_div);
- var select_obj = $("<select/>").appendTo(select_div);
- select_obj.change(function() {param.value = $(this).val();} );
- var options = select_obj.attr("options");
- for (var i = 0; i < param.options.length; i++) {
- var option_data = param.options[i]
- options[options.length] = new Option(option_data[0], option_data[1]);
- }
-
- // Add to clear floating layout.
- $("<div style='clear: both;'/>").appendTo(param_div);
- }
- });
-
- // Add 'Go' button.
- var run_tool_row = $("<div>").addClass("slider-row").appendTo(this.dynamic_tool_div);
- var run_tool_button = $("<input type='submit'>").attr("value", "Run").appendTo(run_tool_row);
- var track = this;
- run_tool_button.click( function() {
- track.run_tool();
- });
}
//
@@ -1767,66 +1794,6 @@
}
$(window).trigger("resize");
},
- // Run track's tool.
- run_tool: function() {
- // Put together params for running tool.
- var url_params = {
- dataset_id: this.original_dataset_id,
- chrom: this.view.chrom,
- low: this.view.low,
- high: this.view.high,
- tool_id: this.tool.name
- };
- $.extend(url_params, this.tool.get_param_values_dict());
-
- //
- // Create track for tool's output immediately to provide user feedback.
- //
- var
- current_track = this,
- // Set name of track to include tool name, parameters, and region used.
- track_name = url_params.tool_id +
- current_track.tool_region_and_parameters_str(url_params.chrom, url_params.low, url_params.high),
- new_track;
-
- // TODO: add support for other kinds of tool data tracks.
- if (current_track.track_type === 'FeatureTrack') {
- new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track);
- }
-
- this.add_track(new_track);
- new_track.content_div.text("Starting job.");
- view.has_changes = true;
-
- // Run tool.
- var json_run_tool = function() {
- $.getJSON(run_tool_url, url_params, function(track_data) {
- if (track_data === "no converter") {
- // No converter available for input datasets, so cannot run tool.
- new_track.container_div.addClass("error");
- new_track.content_div.text(DATA_NOCONVERTER);
- }
- else if (track_data.error) {
- // General error.
- new_track.container_div.addClass("error");
- new_track.content_div.text(DATA_CANNOT_RUN_TOOL + track_data.message);
- }
- else if (track_data === "pending") {
- // Converting/indexing input datasets; show message and try again.
- new_track.container_div.addClass("pending");
- new_track.content_div.text("Converting input data so that it can be easily reused.");
- setTimeout(json_run_tool, 2000);
- }
- else {
- // Job submitted and running.
- new_track.dataset_id = track_data.dataset_id;
- new_track.content_div.text("Running job.");
- new_track.init();
- }
- });
- };
- json_run_tool();
- },
/**
* Utility function that creates a label string describing the region and parameters of a track's tool.
*/
@@ -1850,6 +1817,7 @@
this.child_tracks_container.show();
}
this.child_tracks.push(child_track);
+ this.view.has_changes = true;
},
/**
* Remove a child track from this track.
--- a/tools/new_operations/intersect.xml Mon Apr 04 23:27:25 2011 -0400
+++ b/tools/new_operations/intersect.xml Tue Apr 05 11:51:48 2011 -0400
@@ -28,7 +28,7 @@
<param format="interval,gff" name="input2" type="data" help="Second dataset"><label>that intersect</label></param>
- <param name="min" size="4" type="integer" value="1" min="0" max="600000" help="(bp)">
+ <param name="min" size="4" type="integer" value="1" min="1" help="(bp)"><label>for at least</label></param></inputs>
--- a/tools/new_operations/subtract.xml Mon Apr 04 23:27:25 2011 -0400
+++ b/tools/new_operations/subtract.xml Tue Apr 05 11:51:48 2011 -0400
@@ -31,7 +31,7 @@
<option value="-p">Non-overlapping pieces of intervals</option></param>
- <param name="min" size="4" type="integer" value="1" min="0" max="600000" help="(bp)">
+ <param name="min" size="4" type="integer" value="1" min="1" help="(bp)"><label>where minimal overlap is</label></param></inputs>
--- a/tools/ngs_rna/cufflinks_wrapper.xml Mon Apr 04 23:27:25 2011 -0400
+++ b/tools/ngs_rna/cufflinks_wrapper.xml Tue Apr 05 11:51:48 2011 -0400
@@ -42,7 +42,7 @@
</command><inputs><param format="sam,bam" name="input" type="data" label="SAM or BAM file of aligned RNA-Seq reads" help=""/>
- <param name="max_intron_len" type="integer" value="300000" min="0" max="600000" label="Max Intron Length" help=""/>
+ <param name="max_intron_len" type="integer" value="300000" min="1" max="600000" label="Max Intron Length" help=""/><param name="min_isoform_fraction" type="float" value="0.05" min="0" max="1" label="Min Isoform Fraction" help=""/><param name="pre_mrna_fraction" type="float" value="0.05" min="0" max="1" label="Pre MRNA Fraction" help=""/><param name="min_map_quality" type="integer" value="0" min="0" max="255" label="Min SAM Map Quality" help=""/>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: james_taylor: trackster: draw lines to indicate when line tracks overflow the visible region
by Bitbucket 04 Apr '11
by Bitbucket 04 Apr '11
04 Apr '11
1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/b53f0963bffc/
changeset: r5339:b53f0963bffc
user: james_taylor
date: 2011-04-05 05:27:25
summary: trackster: draw lines to indicate when line tracks overflow the visible region
affected #: 1 file (1.4 KB)
--- a/static/scripts/trackster.js Mon Apr 04 13:40:09 2011 -0400
+++ b/static/scripts/trackster.js Mon Apr 04 23:27:25 2011 -0400
@@ -2668,6 +2668,7 @@
this.max_value = max_value;
this.color = color;
this.mode = mode;
+ this.overflow_color = "#F66";
}
LinePainter.prototype.draw = function( ctx, width, height ) {
@@ -2690,14 +2691,6 @@
// Line at 0.0
if ( mode !== "Intensity" ) {
- /*
- ctx.beginPath();
- ctx.moveTo( 0, y_zero );
- ctx.lineTo( width, y_zero );
- // ctx.lineWidth = 0.5;
- ctx.fillStyle = "#aaa";
- ctx.stroke();
- */
ctx.fillStyle = "#aaa";
ctx.fillRect( 0, y_zero, width, 1 );
}
@@ -2761,6 +2754,37 @@
ctx.stroke();
}
+ // Draw lines at bounderies if overflowing min or max
+ var overflow_min_start = -1,
+ overflow_max_start = -1;
+ ctx.fillStyle = this.overflow_color;
+ for (var i = 0, len = data.length; i < len; i++) {
+ y = data[i][1];
+ x_scaled = Math.round((data[i][0] - view_start) * w_scale);
+ x_minus_scaled = Math.round((data[i][0] - 1 - view_start) * w_scale);
+
+ // If we are in a min/max run, check if it should be ended
+ if ( overflow_max_start >= 0 && ( y === null || y < max_value ) ) {
+ // Value does not exist or is in valid range, any overflow ends
+ ctx.fillRect( overflow_max_start, 0, x_minus_scaled - overflow_max_start + 1, 2 );
+ overflow_max_start = -1;
+ } else if ( overflow_min_start >= 0 && ( y === null || y > min_value ) ) {
+ // Draw bottom overflow bar
+ ctx.fillRect( overflow_min_start, height - 2, x_minus_scaled - overflow_min_start + 1, 2 );
+ overflow_min_start = -1;
+ }
+
+ // Now check if we should start a new one (this may happen on the same
+ // base as above if switching between min/max)
+ if ( y !== null && y > max_value && overflow_max_start < 0 ) {
+ // Top overflows and we are not already in a run of overflow
+ overflow_max_start = x_scaled;
+ } else if ( y !== null && y < min_value && overflow_min_start < 0 ) {
+ // Bottom overflows and we are not already in a run
+ overflow_min_start = x_scaled;
+ }
+ }
+
ctx.restore();
}
@@ -2806,7 +2830,7 @@
// Slot valid only if features are slotted and this feature is slotted;
// feature may not be due to lack of space.
slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
-
+
// Draw feature if there's overlap and mode is dense or feature is slotted (as it must be for all non-dense modes).
if ( ( feature_start < view_end && feature_end > view_start ) && (this.mode == "Dense" || slot !== null)) {
this.draw_element(ctx, this.mode, feature, slot, view_start, view_end, w_scale, y_scale,
@@ -3146,7 +3170,7 @@
seq_offset = 0,
gap = 0
ref_seq = this.ref_seq,
- char_width_px = ctx.canvas.manager.char_width_px;
+ char_width_px = ctx.canvas.manager.char_width_px;
// Keep list of items that need to be drawn on top of initial drawing layer.
var draw_last = [];
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0