improved literary analysis pgae and added compare works sub page

This commit is contained in:
Harivansh Rathi 2024-12-04 12:38:18 -05:00
parent 0134c81526
commit 5ca37d03f2
13 changed files with 3953 additions and 59 deletions

View file

@ -0,0 +1,19 @@
// For smaller network visualizations in subpages
const subGraphConfig = {
nodeRelSize: 4,
linkDistance: 80,
d3: {
alphaDecay: 0.05, // Faster decay for smaller graphs
alphaMin: 0.001,
velocityDecay: 1
},
cooldownTicks: 30,
cooldownTime: 1500,
};
// Use static positioning for very small networks
const staticLayout = {
enableNodeDrag: false,
staticGraph: true,
nodePosition: { x: node => node.initialX, y: node => node.initialY }
};

View file

@ -0,0 +1,132 @@
import { useRef, useCallback, useState, useEffect } from 'react';
const InteractiveGraph = ({ graphData, onNodeSelect }) => {
const graphRef = useRef();
const [selectedNode, setSelectedNode] = useState(null);
const clickTimeoutRef = useRef(null);
const [isProcessingClick, setIsProcessingClick] = useState(false);
// Cleanup function for the timeout
useEffect(() => {
return () => {
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
};
}, []);
const handleNodeClick = useCallback((node) => {
if (!node || isProcessingClick) return;
// Prevent multiple clicks
setIsProcessingClick(true);
// Clear any existing timeout
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
// Set the selected node immediately
setSelectedNode(node);
onNodeSelect(node);
// Reset the processing flag after a short delay
clickTimeoutRef.current = setTimeout(() => {
setIsProcessingClick(false);
}, 300); // 300ms debounce
}, [onNodeSelect, isProcessingClick]);
// Calculate static positions based on container size
const containerWidth = 600;
const containerHeight = 600;
const graphConfig = {
nodeRelSize: 8,
nodeVal: 30,
width: containerWidth,
height: containerHeight,
backgroundColor: "#ffffff",
nodeColor: node => node.type === 'protagonist' ? "#4CAF50" :
node.type === 'antagonist' ? "#f44336" : "#2196F3",
// Static layout configuration
staticGraph: true,
nodePosition: node => ({
x: containerWidth/2 + Math.cos(node.index * (2 * Math.PI / graphData.nodes.length)) * (containerWidth/3),
y: containerHeight/2 + Math.sin(node.index * (2 * Math.PI / graphData.nodes.length)) * (containerHeight/3)
}),
// Interaction settings
enableNodeDrag: false,
enableZoom: true,
minZoom: 0.5,
maxZoom: 2.5,
cooldownTime: 0, // Disable force simulation cooldown
warmupTicks: 0, // Disable initial ticks
// Node appearance
nodeResolution: 16,
// Completely disable all tooltips/labels
nodeLabel: null,
nodeCanvasObject: null,
nodeCanvasObjectMode: null,
enableNodeHover: false,
enableLinkHover: false,
// Link appearance
linkWidth: 2,
linkColor: () => "#999999",
linkOpacity: 0.6,
};
return (
<div style={{
display: 'flex',
gap: '20px',
width: '100%',
maxWidth: '1000px',
margin: '0 auto'
}}>
<div style={{
width: containerWidth,
height: containerHeight,
border: '1px solid #eee',
position: 'relative'
}}>
<ForceGraph
{...graphConfig}
ref={graphRef}
graphData={graphData}
onNodeClick={handleNodeClick}
/>
</div>
{/* Right side popup */}
<div style={{
width: '300px',
padding: '20px',
backgroundColor: '#fff',
border: '1px solid #eee',
borderRadius: '4px',
height: 'fit-content',
visibility: selectedNode ? 'visible' : 'hidden',
opacity: selectedNode ? 1 : 0,
transition: 'opacity 0.2s ease-in-out'
}}>
{selectedNode && (
<>
<h3 style={{ margin: '0 0 10px 0' }}>{selectedNode.name}</h3>
<p style={{ margin: '0 0 10px 0' }}>Type: {selectedNode.type}</p>
<p style={{ margin: '0 0 10px 0' }}>Novel: {selectedNode.novel}</p>
{selectedNode.class && (
<p style={{ margin: '0 0 10px 0' }}>Class: {selectedNode.class}</p>
)}
</>
)}
</div>
</div>
);
};
export default InteractiveGraph;

View file

@ -30,12 +30,20 @@ const Navbar = () => {
<Link to="/market-calculator" className="text-sage-700 hover:text-sage-900 transition-colors">
Market Value
</Link>
<Link
to="/analysis"
className="bg-sage-100 text-sage-700 hover:bg-sage-200 px-4 py-2 rounded-md transition-colors"
>
Literary Analysis
</Link>
<div className="flex items-center space-x-2">
<Link
to="/analysis"
className="bg-sage-100 text-sage-700 hover:bg-sage-200 px-4 py-2 rounded-md transition-colors"
>
Literary Analysis
</Link>
<Link
to="/network"
className="bg-sage-100 text-sage-700 hover:bg-sage-200 px-4 py-2 rounded-md transition-colors"
>
Character Network
</Link>
</div>
</nav>
</div>
</div>

View file

@ -3,15 +3,19 @@ import Navbar from '../Navbar';
const MainLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="min-h-screen bg-cream-50">
<div className="min-h-screen bg-cream-50 flex flex-col">
<Navbar />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{children}
<main className="flex-1 flex flex-col">
<div className="flex-1 container mx-auto px-4 sm:px-6 lg:px-8 py-8 flex flex-col">
<div className="flex-1 flex flex-col">
{children}
</div>
</div>
</main>
<footer className="bg-sage-100 border-t border-sage-200 mt-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<footer className="bg-sage-100 border-t border-sage-200">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="text-center font-cormorant text-sage-900">
<p className="text-lg">"It is a truth universally acknowledged..."</p>
<p className="mt-2">© {new Date().getFullYear()} Austen's Wedding Guide</p>