--- // src/components/KnowledgeGraph.astro // Enhanced interactive visualization of content connections using Cytoscape.js export interface GraphNode { id: string; label: string; type: 'post' | 'tag' | 'category'; // Node types to distinguish posts from tags category?: string; tags?: string[]; url?: string; // URL for linking } export interface GraphEdge { source: string; target: string; type: 'post-tag' | 'post-category' | 'post-post'; // Edge types strength?: number; } export interface GraphData { nodes: GraphNode[]; edges: GraphEdge[]; } interface Props { graphData: GraphData; height?: string; // e.g., '500px' initialFilter?: string; // Optional initial filter } const { graphData, height = "50vh", initialFilter = "all" } = Astro.props; // Generate colors based on node types const nodeTypeColors = { 'post': '#3B82F6', // Blue for posts 'tag': '#10B981', // Green for tags 'category': '#8B5CF6' // Purple for categories }; // Generate predefined colors for categories const predefinedColors = { 'Kubernetes': '#326CE5', 'Docker': '#2496ED', 'DevOps': '#FF6F61', 'Homelab': '#06B6D4', 'Networking': '#9333EA', 'Infrastructure': '#10B981', 'Automation': '#F59E0B', 'Security': '#EF4444', 'Monitoring': '#6366F1', 'Storage': '#8B5CF6', 'Obsidian': '#7C3AED', 'Tutorial': '#3B82F6', 'Uncategorized': '#A0AEC0' }; // Calculate node sizes const nodeSizes = {}; const minSize = 15; const maxSize = 35; const degreeMap = new Map(); graphData.nodes.forEach(node => degreeMap.set(node.id, 0)); graphData.edges.forEach(edge => { degreeMap.set(edge.source, (degreeMap.get(edge.source) || 0) + 1); degreeMap.set(edge.target, (degreeMap.get(edge.target) || 0) + 1); }); const maxDegree = Math.max(...Array.from(degreeMap.values()), 1); graphData.nodes.forEach(node => { const degree = degreeMap.get(node.id) || 0; // Make tags slightly smaller than posts by default const baseSize = node.type === 'post' ? minSize : minSize * 0.8; const normalizedSize = maxDegree === 0 ? 0.5 : degree / maxDegree; nodeSizes[node.id] = baseSize + normalizedSize * (maxSize - minSize); }); // Count node types for legend const nodeTypeCounts = { post: graphData.nodes.filter(node => node.type === 'post').length, tag: graphData.nodes.filter(node => node.type === 'tag').length, category: graphData.nodes.filter(node => node.type === 'category').length }; ---
How to use the Knowledge Graph

This Knowledge Graph visualizes connections between blog content:

  • Posts - Blog articles (circle nodes)
  • Tags - Content topics (diamond nodes)

Interactions:

  • Click a node to see its connections and details
  • Click a tag node to filter posts by that tag
  • Click a post node to highlight that specific post
  • Use the filter buttons below to focus on specific topics
  • Use mouse wheel to zoom in/out and drag to pan
  • Click an empty area to reset the view
Initializing Knowledge Graph...

Node Title

Type
Category: Category Name
Tags:
Connections:
View Content

Knowledge Graph Explorer

Select a post in the graph to view its content here