Files
bio_frontend/pages/test/pathwayJson.vue
leejisun9 2ec34ff321 mearge
2025-09-12 11:10:43 +09:00

130 lines
3.6 KiB
Vue

<template>
<div>
<select v-model="selectedGroup" @change="focusGroup">
<option v-for="g in groups" :key="g" :value="g">
Group {{ g }}
</option>
</select>
<div ref="cyEl" style="width: 100%; height: 800px;"></div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import cytoscape from "cytoscape";
let CytoscapeOverlays = null
if (import.meta.client) {
const useOverlay = (await import('@/composables/useOverlay')).default
CytoscapeOverlays = await useOverlay()
}
useHead({
script: [
{
src: '/dist/cy_custom.js',
defer: true
}
]
});
const cyEl = ref(null);
const cy = ref(null);
const selectedGroup = ref(null);
const groups = ref([]);
onMounted(() => {
fetch("/group43200.json")
.then(res => res.json())
.then(data => {
const nodes = data.entries.map(e => ({
data: { id: `n${e.id}`, label: e.graphics.name, group: e.group },
position: { x: e.graphics.x, y: e.graphics.y },
}));
const edges = data.relations.map(r => ({
data: {
source: `n${r.entry1}`,
target: `n${r.entry2}`,
}
}));
groups.value = [...new Set(data.entries.map(e => e.group))];
const colorPalette = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080'];
const groupColorMap = {};
groups.value.forEach((group, index) => {
groupColorMap[group] = colorPalette[index % colorPalette.length];
});
cy.value = cytoscape({
container: cyEl.value,
elements: [...nodes, ...edges],
style: [
{
selector: 'node',
style: {
label: 'data(label)',
'background-color': (node) => groupColorMap[node.data('group')] || '#ccc',
'text-valign': 'center',
'text-halign': 'center',
'width': 30,
'height': 30
}
},
{
selector: 'edge',
style: {
'line-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}
],
layout: { name: 'preset' },
zoomingEnabled: true,
userZoomingEnabled: true
});
setTimeout(() => {
if (typeof applyCustomZoomHandling === 'function') {
applyCustomZoomHandling(cy.value);
}
}, 100);
});
});
function focusGroup() {
if (!cy.value || !selectedGroup.value) return;
const groupNodes = cy.value.nodes().filter(ele => ele.data('group') === selectedGroup.value);
if (groupNodes.length === 0) return;
const bb = groupNodes.boundingBox();
const container = cy.value.container();
const viewportWidth = container.clientWidth;
const viewportHeight = container.clientHeight;
const padding = 40;
const zoomX = (viewportWidth - 2 * padding) / bb.w;
const zoomY = (viewportHeight - 2 * padding) / bb.h;
const zoom = Math.min(zoomX, zoomY, 5);
cy.value.animate({
zoom: zoom,
center: { eles: groupNodes }
}, {
duration: 800
});
}
</script>
<style>
.cy-container {
width: 100vw !important;
max-width: 100vw !important;
min-width: 0 !important;
height: 800px !important;
overflow: hidden !important;
position: relative;
}
</style>