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>
 | 
						|
   |