Invent the third dimension. Update homepage screenshots.
This commit is contained in:
@@ -24,6 +24,9 @@ export function Home() {
|
||||
<p className="text-center">
|
||||
A great introduction to the dataset on a curated set of examples
|
||||
</p>
|
||||
<p className="text-center">
|
||||
Also <a className="underline" href="#3d">available in 3D</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="m-2 rounded-3xl w-full sm:w-[48%] bg-gray-200 p-10 flex flex-col items-center">
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import ForceGraph3D from "react-force-graph-3d";
|
||||
|
||||
import data from "./data/data.json";
|
||||
import titlesData from "./data/titles.json";
|
||||
import HomeButton from "./utils/HomeButton";
|
||||
import { FloatingPanel } from "./utils/FloatingPanel";
|
||||
import { DetailsPanel } from "./utils/DetailsPanel";
|
||||
import { FloatingPanelStack } from "./utils/FloatingPanelStack";
|
||||
import { drawRoundedRect, getConnectedComponents } from "./graph/common";
|
||||
import { buildGraph } from "./VizSmallConnected";
|
||||
import * as THREE from 'three';
|
||||
import SpriteText from 'three-spritetext';
|
||||
|
||||
export function VizSmall3D() {
|
||||
const fgRef = useRef();
|
||||
const [selectedNode, setSelectedNode] = useState(null);
|
||||
const [minGraphSize, setMinGraphSize] = useState(10);
|
||||
const [showLabel, setShowLabel] = useState(false);
|
||||
|
||||
const graphData = useMemo(() => {
|
||||
const full = buildGraph(data);
|
||||
|
||||
const components = getConnectedComponents(full.nodes, full.links);
|
||||
|
||||
// keep only components large enough
|
||||
const validIds = new Set(
|
||||
components
|
||||
.filter(comp => comp.length >= minGraphSize && comp.length < 50)
|
||||
.flat()
|
||||
);
|
||||
|
||||
const filteredNodes = full.nodes.filter(n => validIds.has(n.id));
|
||||
|
||||
const filteredLinks = full.links.filter(
|
||||
l => validIds.has(l.source) && validIds.has(l.target)
|
||||
);
|
||||
|
||||
return {
|
||||
nodes: filteredNodes,
|
||||
links: filteredLinks
|
||||
};
|
||||
}, [minGraphSize]);
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HomeButton />
|
||||
<ForceGraph3D
|
||||
ref={fgRef}
|
||||
graphData={graphData}
|
||||
nodeLabel={(node) => node.label}
|
||||
nodeAutoColorBy="type"
|
||||
linkColor={() => "black"}
|
||||
linkWidth={2.5}
|
||||
onNodeClick={(node) => setSelectedNode(node)}
|
||||
backgroundColor="white"
|
||||
nodeThreeObject={(node) => {
|
||||
const circle = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(node.members.length * 2),
|
||||
new THREE.MeshLambertMaterial({
|
||||
color: node.type.includes("claim") ? "DarkMagenta" : "green",
|
||||
transparent: true,
|
||||
opacity: 0.75
|
||||
}));
|
||||
|
||||
if (!showLabel) {
|
||||
return circle;
|
||||
}
|
||||
|
||||
const group = new THREE.Group();
|
||||
group.add(circle);
|
||||
|
||||
const text = new SpriteText(node.label);
|
||||
text.textHeight = 8;
|
||||
text.offsetY = -12;
|
||||
text.color = "black";
|
||||
|
||||
group.add(text);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
/>
|
||||
<FloatingPanelStack>
|
||||
<DetailsPanel selectedNode={selectedNode} data={data} />
|
||||
<FloatingPanel title={"Config"}>
|
||||
<label className="flex">
|
||||
<span className="mr-1 grow">Show Labels</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showLabel}
|
||||
onChange={() => setShowLabel(!showLabel)}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Min connected graph size: <strong>{minGraphSize}</strong>
|
||||
</label>
|
||||
<br />
|
||||
<input
|
||||
type="range"
|
||||
min="9"
|
||||
max="20"
|
||||
value={minGraphSize}
|
||||
onChange={(e) => setMinGraphSize(Number(e.target.value))}
|
||||
/>
|
||||
</FloatingPanel>
|
||||
</FloatingPanelStack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { DetailsPanel } from "./utils/DetailsPanel";
|
||||
import { FloatingPanelStack } from "./utils/FloatingPanelStack";
|
||||
import { drawRoundedRect, getConnectedComponents } from "./graph/common";
|
||||
|
||||
function buildGraph(data) {
|
||||
export function buildGraph(data) {
|
||||
const nodes = [];
|
||||
const links = [];
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link href="./index.css" type="text/css" rel="stylesheet" />
|
||||
<title>Parcel React App</title>
|
||||
<title>LLMs For Disinformation Analysis</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import { VizSmallConnected } from "./VizSmallConnected";
|
||||
import { VizTimeFilter } from "./VizTimeFilter";
|
||||
import { Home } from "./Home";
|
||||
import { VizSmall3D } from "./VizSmall3D";
|
||||
|
||||
export function AppRouter() {
|
||||
const [route, setRoute] = useState(() => window.location.hash);
|
||||
@@ -19,6 +20,7 @@ export function AppRouter() {
|
||||
|
||||
if (route === "#small") return <VizSmallConnected />;
|
||||
if (route === "#time") return <VizTimeFilter />;
|
||||
if (route === "#3d") return <VizSmall3D />;
|
||||
return <Home />;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user