88 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <div class="molstar-page">
 | 
						|
    <PageDescription>
 | 
						|
      <h1>Mol* 뷰어 테스트</h1>
 | 
						|
      <div class="box">
 | 
						|
        <p>간단한 PDB 구조(1CRN)를 불러와 Mol*로 렌더링합니다.</p>
 | 
						|
      </div>
 | 
						|
    </PageDescription>
 | 
						|
 | 
						|
    <div
 | 
						|
      ref="containerRef"
 | 
						|
      class="viewer-wrap"
 | 
						|
      :style="{ height: containerHeight }"
 | 
						|
    >
 | 
						|
      <div ref="viewerRef" class="molstar-viewer" />
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script setup lang="ts">
 | 
						|
import { onMounted, onBeforeUnmount, ref } from "vue";
 | 
						|
import { Viewer } from "molstar/lib/apps/viewer/app";
 | 
						|
import "molstar/build/viewer/molstar.css";
 | 
						|
 | 
						|
definePageMeta({
 | 
						|
  title: "Mol* 테스트",
 | 
						|
  description: "Mol* 뷰어 테스트 페이지",
 | 
						|
});
 | 
						|
 | 
						|
const viewerRef = ref<HTMLDivElement | null>(null);
 | 
						|
const containerRef = ref<HTMLDivElement | null>(null);
 | 
						|
const containerHeight = ref<string>("80vh");
 | 
						|
let viewer: Viewer | null = null;
 | 
						|
 | 
						|
onMounted(async () => {
 | 
						|
  if (!viewerRef.value) return;
 | 
						|
 | 
						|
  viewer = await Viewer.create(viewerRef.value, {
 | 
						|
    layoutIsExpanded: true,
 | 
						|
    layoutShowControls: true,
 | 
						|
    viewportShowExpand: true,
 | 
						|
  });
 | 
						|
 | 
						|
  // 예시 구조: 1CRN
 | 
						|
  await viewer.loadStructureFromUrl(
 | 
						|
    "https://files.rcsb.org/download/1CRN.pdb",
 | 
						|
    "pdb"
 | 
						|
  );
 | 
						|
 | 
						|
  const resizeToAvailableHeight = () => {
 | 
						|
    if (!containerRef.value) return;
 | 
						|
    const rect = containerRef.value.getBoundingClientRect();
 | 
						|
    const bottomPadding = 16; // 여백
 | 
						|
    const available = window.innerHeight - rect.top - bottomPadding;
 | 
						|
    containerHeight.value = `${Math.max(300, available)}px`;
 | 
						|
    viewer?.handleResize();
 | 
						|
  };
 | 
						|
 | 
						|
  resizeToAvailableHeight();
 | 
						|
  window.addEventListener("resize", resizeToAvailableHeight);
 | 
						|
  // 정리 함수 저장
 | 
						|
  (containerRef as any)._off = () =>
 | 
						|
    window.removeEventListener("resize", resizeToAvailableHeight);
 | 
						|
});
 | 
						|
 | 
						|
onBeforeUnmount(() => {
 | 
						|
  viewer?.dispose?.();
 | 
						|
  viewer = null;
 | 
						|
  (containerRef as any)?._off?.();
 | 
						|
});
 | 
						|
</script>
 | 
						|
 | 
						|
<style scoped>
 | 
						|
.viewer-wrap {
 | 
						|
  width: 100%;
 | 
						|
  overflow: hidden; /* 내부 Mol*에서 자체 스크롤 관리 */
 | 
						|
}
 | 
						|
.molstar-viewer {
 | 
						|
  position: relative;
 | 
						|
  width: 100%;
 | 
						|
  height: 100%;
 | 
						|
}
 | 
						|
 | 
						|
.msp-plugin .msp-layout-expanded {
 | 
						|
  position: inherit;
 | 
						|
}
 | 
						|
</style>
 |