282 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			282 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| 
								 | 
							
								<template>
							 | 
						||
| 
								 | 
							
								    <div id="app">
							 | 
						||
| 
								 | 
							
								      <main role="main" class="container-fluid">
							 | 
						||
| 
								 | 
							
								        <div style="padding-top: 64px">
							 | 
						||
| 
								 | 
							
								          <div>
							 | 
						||
| 
								 | 
							
								            <ul
							 | 
						||
| 
								 | 
							
								              class="navbar-nav mr-auto"
							 | 
						||
| 
								 | 
							
								              style="list-style:none; padding-left:0; margin:0;"
							 | 
						||
| 
								 | 
							
								            >
							 | 
						||
| 
								 | 
							
								              <li
							 | 
						||
| 
								 | 
							
								                class="nav-item dropdown"
							 | 
						||
| 
								 | 
							
								                style="position: relative; display: inline-block;"
							 | 
						||
| 
								 | 
							
								              >
							 | 
						||
| 
								 | 
							
								                <a
							 | 
						||
| 
								 | 
							
								                  href="#"
							 | 
						||
| 
								 | 
							
								                  id="igv-example-api-dropdown"
							 | 
						||
| 
								 | 
							
								                  @click.prevent="toggleDropdown"
							 | 
						||
| 
								 | 
							
								                  aria-haspopup="true"
							 | 
						||
| 
								 | 
							
								                  :aria-expanded="isDropdownOpen.toString()"
							 | 
						||
| 
								 | 
							
								                  style="color: black; cursor: pointer; user-select: none;"
							 | 
						||
| 
								 | 
							
								                  >Tracks</a
							 | 
						||
| 
								 | 
							
								                >
							 | 
						||
| 
								 | 
							
								                <ul
							 | 
						||
| 
								 | 
							
								                  v-show="isDropdownOpen"
							 | 
						||
| 
								 | 
							
								                  class="dropdown-menu"
							 | 
						||
| 
								 | 
							
								                  style="width:350px; position: absolute; top: 100%; left: 0; background: white; border: 1px solid #ccc; box-shadow: 0 2px 5px rgba(0,0,0,0.15); padding: 5px 0; margin: 0; list-style:none; z-index: 1000;"
							 | 
						||
| 
								 | 
							
								                >
							 | 
						||
| 
								 | 
							
								                  <li>
							 | 
						||
| 
								 | 
							
								                    <a
							 | 
						||
| 
								 | 
							
								                      href="#"
							 | 
						||
| 
								 | 
							
								                      @click.prevent="loadCopyNumberTrack"
							 | 
						||
| 
								 | 
							
								                      style="display:block; padding: 8px 20px; color: black; text-decoration: none;"
							 | 
						||
| 
								 | 
							
								                      >Copy Number</a
							 | 
						||
| 
								 | 
							
								                    >
							 | 
						||
| 
								 | 
							
								                  </li>
							 | 
						||
| 
								 | 
							
								                  <li>
							 | 
						||
| 
								 | 
							
								                    <a
							 | 
						||
| 
								 | 
							
								                      href="#"
							 | 
						||
| 
								 | 
							
								                      @click.prevent="loadDbSnpTrack"
							 | 
						||
| 
								 | 
							
								                      style="display:block; padding: 8px 20px; color: black; text-decoration: none;"
							 | 
						||
| 
								 | 
							
								                      >dbSNP 137 (bed tabix)</a
							 | 
						||
| 
								 | 
							
								                    >
							 | 
						||
| 
								 | 
							
								                  </li>
							 | 
						||
| 
								 | 
							
								                  <li>
							 | 
						||
| 
								 | 
							
								                    <a
							 | 
						||
| 
								 | 
							
								                      href="#"
							 | 
						||
| 
								 | 
							
								                      @click.prevent="loadBigWigTrack"
							 | 
						||
| 
								 | 
							
								                      style="display:block; padding: 8px 20px; color: black; text-decoration: none;"
							 | 
						||
| 
								 | 
							
								                      >Encode bigwig</a
							 | 
						||
| 
								 | 
							
								                    >
							 | 
						||
| 
								 | 
							
								                  </li>
							 | 
						||
| 
								 | 
							
								                  <li>
							 | 
						||
| 
								 | 
							
								                    <a
							 | 
						||
| 
								 | 
							
								                      href="#"
							 | 
						||
| 
								 | 
							
								                      @click.prevent="loadBamTrack"
							 | 
						||
| 
								 | 
							
								                      style="display:block; padding: 8px 20px; color: black; text-decoration: none;"
							 | 
						||
| 
								 | 
							
								                      >1KG Bam (HG02450)</a
							 | 
						||
| 
								 | 
							
								                    >
							 | 
						||
| 
								 | 
							
								                  </li>
							 | 
						||
| 
								 | 
							
								                </ul>
							 | 
						||
| 
								 | 
							
								              </li>
							 | 
						||
| 
								 | 
							
								            </ul>
							 | 
						||
| 
								 | 
							
								          </div>
							 | 
						||
| 
								 | 
							
								          <!-- 탭 콘텐츠 -->
							 | 
						||
| 
								 | 
							
								          <div class="tab-content" id="viewerTabContent">
							 | 
						||
| 
								 | 
							
								            <div
							 | 
						||
| 
								 | 
							
								              class="tab-pane fade show active"
							 | 
						||
| 
								 | 
							
								              id="igv-viewer"
							 | 
						||
| 
								 | 
							
								              role="tabpanel"
							 | 
						||
| 
								 | 
							
								            >
							 | 
						||
| 
								 | 
							
								              <div style="padding-top: 20px">
							 | 
						||
| 
								 | 
							
								                이 예제는 드롭다운 메뉴에서 동적으로 트랙을 추가하는 igv.js API의
							 | 
						||
| 
								 | 
							
								                사용을 보여줍니다.
							 | 
						||
| 
								 | 
							
								                위의 메뉴에서 'CopyNumber'를 선택하면 다음과 같은 호출이 실행됩니다.
							 | 
						||
| 
								 | 
							
								                <p>
							 | 
						||
| 
								 | 
							
								                  <pre>
							 | 
						||
| 
								 | 
							
								                  igv.browser.loadTrack({
							 | 
						||
| 
								 | 
							
								                      url: 'https://s3.amazonaws.com/igv.org.demo/GBM-TP.seg.gz',
							 | 
						||
| 
								 | 
							
								                      name: 'GBM Copy # (TCGA Broad GDAC)'});
							 | 
						||
| 
								 | 
							
								                  </pre>
							 | 
						||
| 
								 | 
							
								                </p>
							 | 
						||
| 
								 | 
							
								                자세한 내용은
							 | 
						||
| 
								 | 
							
								                <a href="https://github.com/igvteam/igv.js/wiki">개발자 위키</a>를
							 | 
						||
| 
								 | 
							
								                참조하세요.
							 | 
						||
| 
								 | 
							
								              </div>
							 | 
						||
| 
								 | 
							
								              <div id="igvDiv" style="padding-top: 20px"></div>
							 | 
						||
| 
								 | 
							
								            </div>
							 | 
						||
| 
								 | 
							
								          </div>
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								      </main>
							 | 
						||
| 
								 | 
							
								    </div>
							 | 
						||
| 
								 | 
							
								  </template>
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  <script>
							 | 
						||
| 
								 | 
							
								  export default {
							 | 
						||
| 
								 | 
							
								    name: "App",
							 | 
						||
| 
								 | 
							
								    data() {
							 | 
						||
| 
								 | 
							
								      return {
							 | 
						||
| 
								 | 
							
								        browser: null,
							 | 
						||
| 
								 | 
							
								        isDropdownOpen: false,
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    mounted() {
							 | 
						||
| 
								 | 
							
								      // 외부 클릭시 드롭다운 닫기
							 | 
						||
| 
								 | 
							
								      document.addEventListener("click", this.handleClickOutside);
							 | 
						||
| 
								 | 
							
								      this.initializeIGV();
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    beforeUnmount() {
							 | 
						||
| 
								 | 
							
								      document.removeEventListener("click", this.handleClickOutside);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    methods: {
							 | 
						||
| 
								 | 
							
								      toggleDropdown() {
							 | 
						||
| 
								 | 
							
								        this.isDropdownOpen = !this.isDropdownOpen;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      closeDropdown() {
							 | 
						||
| 
								 | 
							
								        this.isDropdownOpen = false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      handleClickOutside(event) {
							 | 
						||
| 
								 | 
							
								        const dropdown = this.$el.querySelector("#igv-example-api-dropdown");
							 | 
						||
| 
								 | 
							
								        const menu = this.$el.querySelector(".dropdown-menu");
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								          dropdown &&
							 | 
						||
| 
								 | 
							
								          menu &&
							 | 
						||
| 
								 | 
							
								          !dropdown.contains(event.target) &&
							 | 
						||
| 
								 | 
							
								          !menu.contains(event.target)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								          this.closeDropdown();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								      async initializeIGV() {
							 | 
						||
| 
								 | 
							
								        await this.waitForIGV();
							 | 
						||
| 
								 | 
							
								        await this.$nextTick();
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								        const igvDiv = document.getElementById("igvDiv");
							 | 
						||
| 
								 | 
							
								        if (!igvDiv) {
							 | 
						||
| 
								 | 
							
								          console.error("❌ #igvDiv가 존재하지 않습니다.");
							 | 
						||
| 
								 | 
							
								          return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								        const options = {
							 | 
						||
| 
								 | 
							
								          locus: "chr1:155,160,475-155,184,282",
							 | 
						||
| 
								 | 
							
								          genome: "hg19",
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								          this.browser = await igv.createBrowser(igvDiv, options);
							 | 
						||
| 
								 | 
							
								          window.igv = { browser: this.browser };
							 | 
						||
| 
								 | 
							
								          this.addBaseClickEvent();
							 | 
						||
| 
								 | 
							
								          this.browser.on("locuschange", this.addBaseClickEvent);
							 | 
						||
| 
								 | 
							
								          this.browser.on("trackclick", this.addBaseClickEvent);
							 | 
						||
| 
								 | 
							
								        } catch (error) {
							 | 
						||
| 
								 | 
							
								          console.error("IGV 브라우저 생성 중 오류:", error);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      waitForIGV() {
							 | 
						||
| 
								 | 
							
								        return new Promise((resolve) => {
							 | 
						||
| 
								 | 
							
								          const checkIGV = () => {
							 | 
						||
| 
								 | 
							
								            if (typeof igv !== "undefined") {
							 | 
						||
| 
								 | 
							
								              resolve();
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								              setTimeout(checkIGV, 100);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								          checkIGV();
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      addBaseClickEvent() {
							 | 
						||
| 
								 | 
							
								        setTimeout(() => {
							 | 
						||
| 
								 | 
							
								          const texts = document.querySelectorAll("#igvDiv text");
							 | 
						||
| 
								 | 
							
								          texts.forEach((text) => {
							 | 
						||
| 
								 | 
							
								            const base = text.textContent;
							 | 
						||
| 
								 | 
							
								            if (["A", "T", "C", "G"].includes(base)) {
							 | 
						||
| 
								 | 
							
								              text.style.cursor = "pointer";
							 | 
						||
| 
								 | 
							
								              text.onclick = () => {
							 | 
						||
| 
								 | 
							
								                text.textContent = this.getComplement(text.textContent);
							 | 
						||
| 
								 | 
							
								              };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        }, 300);
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      getComplement(base) {
							 | 
						||
| 
								 | 
							
								        switch (base) {
							 | 
						||
| 
								 | 
							
								          case "A":
							 | 
						||
| 
								 | 
							
								            return "T";
							 | 
						||
| 
								 | 
							
								          case "T":
							 | 
						||
| 
								 | 
							
								            return "A";
							 | 
						||
| 
								 | 
							
								          case "C":
							 | 
						||
| 
								 | 
							
								            return "G";
							 | 
						||
| 
								 | 
							
								          case "G":
							 | 
						||
| 
								 | 
							
								            return "C";
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return base;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      loadCopyNumberTrack() {
							 | 
						||
| 
								 | 
							
								        if (this.browser) {
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList = this.browser.loadTrackList.bind(this.browser);
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList([
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              url: "https://s3.amazonaws.com/igv.org.demo/GBM-TP.seg.gz",
							 | 
						||
| 
								 | 
							
								              indexed: false,
							 | 
						||
| 
								 | 
							
								              isLog: true,
							 | 
						||
| 
								 | 
							
								              name: "GBM Copy # (TCGA Broad GDAC)",
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								          ]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this.closeDropdown();
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      loadDbSnpTrack() {
							 | 
						||
| 
								 | 
							
								        if (this.browser) {
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList = this.browser.loadTrackList.bind(this.browser);
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList([
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              type: "annotation",
							 | 
						||
| 
								 | 
							
								              format: "bed",
							 | 
						||
| 
								 | 
							
								              url: "https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz",
							 | 
						||
| 
								 | 
							
								              indexURL:
							 | 
						||
| 
								 | 
							
								                "https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz.tbi",
							 | 
						||
| 
								 | 
							
								              visibilityWindow: 200000,
							 | 
						||
| 
								 | 
							
								              name: "dbSNP 137",
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								          ]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this.closeDropdown();
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      loadBigWigTrack() {
							 | 
						||
| 
								 | 
							
								        if (this.browser) {
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList = this.browser.loadTrackList.bind(this.browser);
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList([
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              type: "wig",
							 | 
						||
| 
								 | 
							
								              format: "bigwig",
							 | 
						||
| 
								 | 
							
								              url: "https://s3.amazonaws.com/igv.broadinstitute.org/data/hg19/encode/wgEncodeBroadHistoneGm12878H3k4me3StdSig.bigWig",
							 | 
						||
| 
								 | 
							
								              name: "Gm12878H3k4me3",
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								          ]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this.closeDropdown();
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      loadBamTrack() {
							 | 
						||
| 
								 | 
							
								        if (this.browser) {
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList = this.browser.loadTrackList.bind(this.browser);
							 | 
						||
| 
								 | 
							
								          this.browser.loadTrackList([
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              type: "alignment",
							 | 
						||
| 
								 | 
							
								              format: "bam",
							 | 
						||
| 
								 | 
							
								              url: "https://1000genomes.s3.amazonaws.com/phase3/data/HG02450/alignment/HG02450.mapped.ILLUMINA.bwa.ACB.low_coverage.20120522.bam",
							 | 
						||
| 
								 | 
							
								              indexURL:
							 | 
						||
| 
								 | 
							
								                "https://1000genomes.s3.amazonaws.com/phase3/data/HG02450/alignment/HG02450.mapped.ILLUMINA.bwa.ACB.low_coverage.20120522.bam.bai",
							 | 
						||
| 
								 | 
							
								              name: "HG02450",
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								          ]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this.closeDropdown();
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								  </script>
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  <style>
							 | 
						||
| 
								 | 
							
								  #app {
							 | 
						||
| 
								 | 
							
								    font-family: Avenir, Helvetica, Arial, sans-serif;
							 | 
						||
| 
								 | 
							
								    -webkit-font-smoothing: antialiased;
							 | 
						||
| 
								 | 
							
								    -moz-osx-font-smoothing: grayscale;
							 | 
						||
| 
								 | 
							
								    color: #2c3e50;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  pre {
							 | 
						||
| 
								 | 
							
								    padding: 10px;
							 | 
						||
| 
								 | 
							
								    border-radius: 4px;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  .nav-tabs {
							 | 
						||
| 
								 | 
							
								    margin-bottom: 20px;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  .tab-content {
							 | 
						||
| 
								 | 
							
								    padding-top: 20px;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  </style>
							 | 
						||
| 
								 | 
							
								  
							 |