130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			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>
							 | 
						||
| 
								 | 
							
								  
							 |