Merge branch 'main' of https://demo.stam.kr/leejisun9/bio_frontend
This commit is contained in:
		
							
								
								
									
										65
									
								
								public/cy_custom.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								public/cy_custom.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					(function () {
 | 
				
			||||||
 | 
					    const EXTREME_ZOOM_MIN = 1e-4;
 | 
				
			||||||
 | 
					    const EXTREME_ZOOM_MAX = 1e4;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    function applyCustomZoomHandling(cy) {
 | 
				
			||||||
 | 
					      let zoomFramePending = false;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      if (!cy || typeof cy.zoom !== 'function') {
 | 
				
			||||||
 | 
					        console.warn('🚫 유효하지 않은 Cytoscape 인스턴스입니다.');
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      cy.userZoomingEnabled(false); // Cytoscape 기본 줌 비활성화
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      const container = cy.container();
 | 
				
			||||||
 | 
					      if (!container) {
 | 
				
			||||||
 | 
					        console.warn('🚫 Cytoscape container를 찾을 수 없습니다.');
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      container.addEventListener(
 | 
				
			||||||
 | 
					        'wheel',
 | 
				
			||||||
 | 
					        (event) => {
 | 
				
			||||||
 | 
					          event.preventDefault();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					          if (zoomFramePending) return;
 | 
				
			||||||
 | 
					          zoomFramePending = true;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					          requestAnimationFrame(() => {
 | 
				
			||||||
 | 
					            const currentZoom = cy.zoom();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					            const clampedDelta = Math.max(-100, Math.min(100, event.deltaY));
 | 
				
			||||||
 | 
					            const zoomFactor = 1 + (clampedDelta > 0 ? -0.05 : 0.05);
 | 
				
			||||||
 | 
					            const nextZoom = currentZoom * zoomFactor;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					            const isValid =
 | 
				
			||||||
 | 
					              isFinite(nextZoom) &&
 | 
				
			||||||
 | 
					              nextZoom >= EXTREME_ZOOM_MIN &&
 | 
				
			||||||
 | 
					              nextZoom <= EXTREME_ZOOM_MAX;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					            if (isValid) {
 | 
				
			||||||
 | 
					              const rect = container.getBoundingClientRect();
 | 
				
			||||||
 | 
					              const renderedPosition = {
 | 
				
			||||||
 | 
					                x: event.clientX - rect.left,
 | 
				
			||||||
 | 
					                y: event.clientY - rect.top
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              cy.zoom({
 | 
				
			||||||
 | 
					                level: nextZoom,
 | 
				
			||||||
 | 
					                renderedPosition
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              console.warn("🚫 휠 줌 비정상 값 차단:", nextZoom);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					            zoomFramePending = false;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        { passive: false }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    // ✅ 전역(window)으로 함수 등록
 | 
				
			||||||
 | 
					    window.applyCustomZoomHandling = applyCustomZoomHandling;
 | 
				
			||||||
 | 
					  })();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
							
								
								
									
										28
									
								
								public/igv.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								public/igv.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					/* IGV blue lines & UI custom style (기본 파란색: #3579f6) */
 | 
				
			||||||
 | 
					.igv-blue-line {
 | 
				
			||||||
 | 
					  background: #3579f6 !important;
 | 
				
			||||||
 | 
					  width: 2px !important;
 | 
				
			||||||
 | 
					  z-index: 1000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.igv-blue-fill {
 | 
				
			||||||
 | 
					  background: rgba(53, 121, 246, 0.18) !important;
 | 
				
			||||||
 | 
					  z-index: 999;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.igv-control-btn {
 | 
				
			||||||
 | 
					  background: #f5faff;
 | 
				
			||||||
 | 
					  color: #3579f6;
 | 
				
			||||||
 | 
					  border: 1.5px solid #3579f6;
 | 
				
			||||||
 | 
					  border-radius: 5px;
 | 
				
			||||||
 | 
					  padding: 6px 16px;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: background 0.2s, border 0.2s, color 0.2s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.igv-control-btn:hover {
 | 
				
			||||||
 | 
					  background: #3579f6;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  border: 2px solid #2456a6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.igv-blue-line.selected {
 | 
				
			||||||
 | 
					  box-shadow: 0 0 8px #3579f6;
 | 
				
			||||||
 | 
					} 
 | 
				
			||||||
							
								
								
									
										67298
									
								
								public/igv.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67298
									
								
								public/igv.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										222
									
								
								public/igv_custom.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								public/igv_custom.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					// igv_custom.js
 | 
				
			||||||
 | 
					// IGV 브라우저가 생성된 후, 파란색 라인 2개를 ideogram/viewport에 추가하고 드래그로 이동 가능하게 함
 | 
				
			||||||
 | 
					// 라인 위치 변경 시 window에 커스텀 이벤트('igv-blue-lines-changed')를 dispatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  // 설정값
 | 
				
			||||||
 | 
					  const LINE_COLOR = '#007bff';
 | 
				
			||||||
 | 
					  const LINE_WIDTH = 2;
 | 
				
			||||||
 | 
					  const INIT_RATIO_1 = 0.3; // 30% 위치
 | 
				
			||||||
 | 
					  const INIT_RATIO_2 = 0.7; // 70% 위치
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 내부 상태
 | 
				
			||||||
 | 
					  let viewportRect = null;
 | 
				
			||||||
 | 
					  let dragging = null; // 'start' or 'end' or null
 | 
				
			||||||
 | 
					  let dragOffset = 0;
 | 
				
			||||||
 | 
					  let startRatio = INIT_RATIO_1;
 | 
				
			||||||
 | 
					  let endRatio = INIT_RATIO_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 라인 DOM
 | 
				
			||||||
 | 
					  let viewportLines = [];
 | 
				
			||||||
 | 
					  let viewportFill = null;
 | 
				
			||||||
 | 
					  let ideogramLines = [];
 | 
				
			||||||
 | 
					  let ideogramFill = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // IGV가 준비되면 실행
 | 
				
			||||||
 | 
					  function waitForIGVAndInit() {
 | 
				
			||||||
 | 
					    const check = () => {
 | 
				
			||||||
 | 
					      const viewport = document.querySelector('.igv-viewport-content');
 | 
				
			||||||
 | 
					      if (viewport) {
 | 
				
			||||||
 | 
					        setupLines();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        setTimeout(check, 300);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    check();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 라인 생성 및 이벤트 바인딩
 | 
				
			||||||
 | 
					  function setupLines() {
 | 
				
			||||||
 | 
					    // 모든 파란 라인 삭제
 | 
				
			||||||
 | 
					    document.querySelectorAll('.igv-blue-line').forEach(el => el.remove());
 | 
				
			||||||
 | 
					    // 기존 fill 오버레이 삭제
 | 
				
			||||||
 | 
					    document.querySelectorAll('.igv-blue-fill').forEach(el => el.remove());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 모든 .igv-viewport-content 중, height가 16px 초과인 첫 번째를 메인 뷰포트로 간주
 | 
				
			||||||
 | 
					    const viewports = Array.from(document.querySelectorAll('.igv-viewport-content'));
 | 
				
			||||||
 | 
					    const mainViewport = viewports.find(vp => {
 | 
				
			||||||
 | 
					      const h = vp.offsetHeight || parseInt(vp.style.height, 10);
 | 
				
			||||||
 | 
					      return h > 16;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (!mainViewport) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 이미 있으면 중복 생성 방지
 | 
				
			||||||
 | 
					    if (mainViewport.parentNode.querySelector('.igv-blue-line')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    viewportRect = mainViewport.getBoundingClientRect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 라인 2개 생성 (뷰포트)
 | 
				
			||||||
 | 
					    viewportLines = [createLine('start', 'viewport', mainViewport), createLine('end', 'viewport', mainViewport)];
 | 
				
			||||||
 | 
					    viewportLines.forEach(line => mainViewport.parentNode.appendChild(line));
 | 
				
			||||||
 | 
					    // fill 오버레이 생성 및 추가 (뷰포트)
 | 
				
			||||||
 | 
					    viewportFill = document.createElement('div');
 | 
				
			||||||
 | 
					    viewportFill.className = 'igv-blue-fill';
 | 
				
			||||||
 | 
					    Object.assign(viewportFill.style, {
 | 
				
			||||||
 | 
					      position: 'absolute',
 | 
				
			||||||
 | 
					      top: (viewportRect.top - mainViewport.getBoundingClientRect().top) + 'px',
 | 
				
			||||||
 | 
					      height: viewportRect.height + 'px',
 | 
				
			||||||
 | 
					      background: 'rgba(0,123,255,0.18)',
 | 
				
			||||||
 | 
					      zIndex: 999,
 | 
				
			||||||
 | 
					      pointerEvents: 'none',
 | 
				
			||||||
 | 
					      borderRadius: '2px',
 | 
				
			||||||
 | 
					      transition: 'left 0.08s, width 0.08s',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    mainViewport.parentNode.appendChild(viewportFill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // === ideogram(미니맵)에도 라인/오버레이 추가 ===
 | 
				
			||||||
 | 
					    const ideogram = document.querySelector('.igv-ideogram-content') || document.querySelector('.igv-ideogram');
 | 
				
			||||||
 | 
					    if (ideogram) {
 | 
				
			||||||
 | 
					      const ideogramRect = ideogram.getBoundingClientRect();
 | 
				
			||||||
 | 
					      ideogramLines = [createLine('start', 'ideogram', ideogram), createLine('end', 'ideogram', ideogram)];
 | 
				
			||||||
 | 
					      ideogramLines.forEach(line => ideogram.parentNode.appendChild(line));
 | 
				
			||||||
 | 
					      ideogramFill = document.createElement('div');
 | 
				
			||||||
 | 
					      ideogramFill.className = 'igv-blue-fill';
 | 
				
			||||||
 | 
					      Object.assign(ideogramFill.style, {
 | 
				
			||||||
 | 
					        position: 'absolute',
 | 
				
			||||||
 | 
					        top: (ideogramRect.top - ideogram.parentNode.getBoundingClientRect().top) + 'px',
 | 
				
			||||||
 | 
					        height: ideogramRect.height + 'px',
 | 
				
			||||||
 | 
					        background: 'rgba(0,123,255,0.18)',
 | 
				
			||||||
 | 
					        zIndex: 999,
 | 
				
			||||||
 | 
					        pointerEvents: 'none',
 | 
				
			||||||
 | 
					        borderRadius: '2px',
 | 
				
			||||||
 | 
					        transition: 'left 0.08s, width 0.08s',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      ideogram.parentNode.appendChild(ideogramFill);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateLinePositions();
 | 
				
			||||||
 | 
					    bindDragEvents();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 라인 DOM 생성
 | 
				
			||||||
 | 
					  function createLine(which, area, parentEl) {
 | 
				
			||||||
 | 
					    const line = document.createElement('div');
 | 
				
			||||||
 | 
					    line.className = 'igv-blue-line';
 | 
				
			||||||
 | 
					    line.dataset.which = which;
 | 
				
			||||||
 | 
					    line.dataset.area = area;
 | 
				
			||||||
 | 
					    line._parentEl = parentEl; // 커스텀 속성으로 부모 저장
 | 
				
			||||||
 | 
					    Object.assign(line.style, {
 | 
				
			||||||
 | 
					      position: 'absolute',
 | 
				
			||||||
 | 
					      top: area === 'ideogram' ? (viewportRect.top - parentEl.getBoundingClientRect().top) + 'px' : (viewportRect.top - parentEl.getBoundingClientRect().top) + 'px',
 | 
				
			||||||
 | 
					      width: LINE_WIDTH + 'px',
 | 
				
			||||||
 | 
					      height: area === 'ideogram' ? viewportRect.height + 'px' : viewportRect.height + 'px',
 | 
				
			||||||
 | 
					      background: LINE_COLOR,
 | 
				
			||||||
 | 
					      zIndex: 1000,
 | 
				
			||||||
 | 
					      cursor: 'ew-resize',
 | 
				
			||||||
 | 
					      userSelect: 'none',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    line.addEventListener('mousedown', (e) => startDrag(which, e));
 | 
				
			||||||
 | 
					    return line;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 라인 위치 갱신
 | 
				
			||||||
 | 
					  function updateLinePositions() {
 | 
				
			||||||
 | 
					    viewportRect = document.querySelector('.igv-viewport-content').getBoundingClientRect();
 | 
				
			||||||
 | 
					    let baseArea = document.querySelector('.igv-viewport-content canvas, .igv-viewport-content svg');
 | 
				
			||||||
 | 
					    let baseRect = baseArea ? baseArea.getBoundingClientRect() : viewportRect;
 | 
				
			||||||
 | 
					    // viewport 라인 위치 (실제 베이스 표시 영역 기준)
 | 
				
			||||||
 | 
					    const baseWidth = baseRect.width;
 | 
				
			||||||
 | 
					    const baseLeft = baseRect.left;
 | 
				
			||||||
 | 
					    const startX_view = baseLeft + baseWidth * startRatio;
 | 
				
			||||||
 | 
					    const endX_view = baseLeft + baseWidth * endRatio;
 | 
				
			||||||
 | 
					    viewportLines[0].style.left = (startX_view - viewportLines[0]._parentEl.getBoundingClientRect().left) + 'px';
 | 
				
			||||||
 | 
					    viewportLines[1].style.left = (endX_view - viewportLines[1]._parentEl.getBoundingClientRect().left) + 'px';
 | 
				
			||||||
 | 
					    // fill 오버레이 위치/크기 갱신
 | 
				
			||||||
 | 
					    if (viewportFill) {
 | 
				
			||||||
 | 
					      const left = Math.min(startX_view, endX_view) - viewportFill.parentNode.getBoundingClientRect().left;
 | 
				
			||||||
 | 
					      const width = Math.abs(endX_view - startX_view);
 | 
				
			||||||
 | 
					      viewportFill.style.left = left + 'px';
 | 
				
			||||||
 | 
					      viewportFill.style.width = width + 'px';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // === ideogram(미니맵) 라인/오버레이 위치 갱신 ===
 | 
				
			||||||
 | 
					    const ideogram = document.querySelector('.igv-ideogram-content') || document.querySelector('.igv-ideogram');
 | 
				
			||||||
 | 
					    if (ideogram && ideogramLines.length === 2 && ideogramFill) {
 | 
				
			||||||
 | 
					      const ideogramRect = ideogram.getBoundingClientRect();
 | 
				
			||||||
 | 
					      const ideogramWidth = ideogramRect.width;
 | 
				
			||||||
 | 
					      const ideogramLeft = ideogramRect.left;
 | 
				
			||||||
 | 
					      const startX_ideo = ideogramLeft + ideogramWidth * startRatio;
 | 
				
			||||||
 | 
					      const endX_ideo = ideogramLeft + ideogramWidth * endRatio;
 | 
				
			||||||
 | 
					      ideogramLines[0].style.left = (startX_ideo - ideogram.parentNode.getBoundingClientRect().left) + 'px';
 | 
				
			||||||
 | 
					      ideogramLines[1].style.left = (endX_ideo - ideogram.parentNode.getBoundingClientRect().left) + 'px';
 | 
				
			||||||
 | 
					      // fill
 | 
				
			||||||
 | 
					      const left = Math.min(startX_ideo, endX_ideo) - ideogramFill.parentNode.getBoundingClientRect().left;
 | 
				
			||||||
 | 
					      const width = Math.abs(endX_ideo - startX_ideo);
 | 
				
			||||||
 | 
					      ideogramFill.style.left = left + 'px';
 | 
				
			||||||
 | 
					      ideogramFill.style.width = width + 'px';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 드래그 이벤트 바인딩
 | 
				
			||||||
 | 
					  function bindDragEvents() {
 | 
				
			||||||
 | 
					    document.addEventListener('mousemove', onDrag);
 | 
				
			||||||
 | 
					    document.addEventListener('mouseup', stopDrag);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function startDrag(which, e) {
 | 
				
			||||||
 | 
					    dragging = which;
 | 
				
			||||||
 | 
					    dragOffset = e.clientX;
 | 
				
			||||||
 | 
					    e.preventDefault();
 | 
				
			||||||
 | 
					    e.stopPropagation();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function onDrag(e) {
 | 
				
			||||||
 | 
					    if (!dragging) return;
 | 
				
			||||||
 | 
					    const areaWidth = viewportRect.width;
 | 
				
			||||||
 | 
					    let x = e.clientX - viewportRect.left;
 | 
				
			||||||
 | 
					    let ratio = x / areaWidth;
 | 
				
			||||||
 | 
					    ratio = Math.max(0, Math.min(1, ratio));
 | 
				
			||||||
 | 
					    if (dragging === 'start') {
 | 
				
			||||||
 | 
					      startRatio = Math.min(ratio, endRatio - 0.01);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      endRatio = Math.max(ratio, startRatio + 0.01);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    updateLinePositions();
 | 
				
			||||||
 | 
					    fireChangeEvent();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function stopDrag() {
 | 
				
			||||||
 | 
					    dragging = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 라인 위치 변경 이벤트 발생
 | 
				
			||||||
 | 
					  function fireChangeEvent() {
 | 
				
			||||||
 | 
					    console.log('fireChangeEvent 호출됨', { startRatio, endRatio });
 | 
				
			||||||
 | 
					    window.dispatchEvent(new CustomEvent('igv-blue-lines-changed', {
 | 
				
			||||||
 | 
					      detail: {
 | 
				
			||||||
 | 
					        startRatio,
 | 
				
			||||||
 | 
					        endRatio
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 외부에서 라인 위치를 강제로 지정할 수 있도록 export
 | 
				
			||||||
 | 
					  window.igvCustom = {
 | 
				
			||||||
 | 
					    setLineRatios: (start, end) => {
 | 
				
			||||||
 | 
					      startRatio = start;
 | 
				
			||||||
 | 
					      endRatio = end;
 | 
				
			||||||
 | 
					      updateLinePositions();
 | 
				
			||||||
 | 
					      fireChangeEvent();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    getLineRatios: () => ({ startRatio, endRatio }),
 | 
				
			||||||
 | 
					    setupLines: setupLines
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 스타일 추가
 | 
				
			||||||
 | 
					  const style = document.createElement('style');
 | 
				
			||||||
 | 
					  style.innerHTML = `.igv-blue-line { pointer-events: auto !important; }
 | 
				
			||||||
 | 
					  .igv-blue-fill { pointer-events: none !important; }`;
 | 
				
			||||||
 | 
					  document.head.appendChild(style);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // IGV가 준비되면 실행
 | 
				
			||||||
 | 
					  setTimeout(waitForIGVAndInit, 1000);
 | 
				
			||||||
 | 
					})(); 
 | 
				
			||||||
		Reference in New Issue
	
	Block a user