Invent the third dimension. Update homepage screenshots.
This commit is contained in:
Generated
+169
-1
@@ -12,7 +12,10 @@
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"react-force-graph-2d": "^1.29.1",
|
||||
"tailwindcss": "^4.2.4"
|
||||
"react-force-graph-3d": "^1.29.1",
|
||||
"tailwindcss": "^4.2.4",
|
||||
"three": "^0.184.0",
|
||||
"three-spritetext": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.0",
|
||||
@@ -33,6 +36,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
@@ -2515,6 +2527,22 @@
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/3d-force-graph": {
|
||||
"version": "1.80.0",
|
||||
"resolved": "https://registry.npmjs.org/3d-force-graph/-/3d-force-graph-1.80.0.tgz",
|
||||
"integrity": "sha512-tzI353gW1nXPpnC7VTa3JjMg+3cp77qOLUFO0vucPTfF+q5R6sQsNsIqVTbRIb7RSypn14nBa4yfkOe9ThxASw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accessor-fn": "1",
|
||||
"kapsule": "^1.16",
|
||||
"three": ">=0.179 <1",
|
||||
"three-forcegraph": "1",
|
||||
"three-render-objects": "^1.41"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/accessor-fn": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz",
|
||||
@@ -2930,6 +2958,18 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/data-bind-mapper": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/data-bind-mapper/-/data-bind-mapper-1.0.3.tgz",
|
||||
"integrity": "sha512-QmU3lyEnbENQPo0M1F9BMu4s6cqNNp8iJA+b/HP2sSb7pf3dxwF3+EP1eO69rwBfH9kFJ1apmzrtogAmVt2/Xw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accessor-fn": "1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
@@ -3570,6 +3610,44 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ngraph.events": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.4.0.tgz",
|
||||
"integrity": "sha512-NeDGI4DSyjBNBRtA86222JoYietsmCXbs8CEB0dZ51Xeh4lhVl1y3wpWLumczvnha8sFQIW4E0vvVWwgmX2mGw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ngraph.forcelayout": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.forcelayout/-/ngraph.forcelayout-3.3.1.tgz",
|
||||
"integrity": "sha512-MKBuEh1wujyQHFTW57y5vd/uuEOK0XfXYxm3lC7kktjJLRdt/KEKEknyOlc6tjXflqBKEuYBBcu7Ax5VY+S6aw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"ngraph.events": "^1.0.0",
|
||||
"ngraph.merge": "^1.0.0",
|
||||
"ngraph.random": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ngraph.graph": {
|
||||
"version": "20.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.graph/-/ngraph.graph-20.1.2.tgz",
|
||||
"integrity": "sha512-W/G3GBR3Y5UxMLHTUCPP9v+pbtpzwuAEIqP5oZV+9IwgxAIEZwh+Foc60iPc1idlnK7Zxu0p3puxAyNmDvBd0Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"ngraph.events": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ngraph.merge": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.merge/-/ngraph.merge-1.0.0.tgz",
|
||||
"integrity": "sha512-5J8YjGITUJeapsomtTALYsw7rFveYkM+lBj3QiYZ79EymQcuri65Nw3knQtFxQBU1r5iOaVRXrSwMENUPK62Vg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ngraph.random": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.random/-/ngraph.random-1.2.0.tgz",
|
||||
"integrity": "sha512-4EUeAGbB2HWX9njd6bP6tciN6ByJfoaAvmVL9QTaZSeXrW46eNGA9GajiXiPBbvFqxUWFkEbyo6x5qsACUuVfA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
@@ -3698,6 +3776,18 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/polished": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
|
||||
"integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.17.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.12",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
|
||||
@@ -3792,6 +3882,23 @@
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-force-graph-3d": {
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/react-force-graph-3d/-/react-force-graph-3d-1.29.1.tgz",
|
||||
"integrity": "sha512-5Vp+PGpYnO+zLwgK2NvNqdXHvsWLrFzpDfJW1vUA1twjo9SPvXqfUYQrnRmAbD+K2tOxkZw1BkbH31l5b4TWHg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"3d-force-graph": "^1.79",
|
||||
"prop-types": "15",
|
||||
"react-kapsule": "^2.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@@ -3924,6 +4031,67 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.184.0",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.184.0.tgz",
|
||||
"integrity": "sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/three-forcegraph": {
|
||||
"version": "1.43.4",
|
||||
"resolved": "https://registry.npmjs.org/three-forcegraph/-/three-forcegraph-1.43.4.tgz",
|
||||
"integrity": "sha512-FtmiZP/T16ZQaHza3JDaDn0YTXFtg9e7pGnTeU8nzu0NNkx7MpWbF/GvmpbQsWHx3rukHtkRv1fTorLPB3FDEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accessor-fn": "1",
|
||||
"d3-array": "1 - 3",
|
||||
"d3-force-3d": "2 - 3",
|
||||
"d3-scale": "1 - 4",
|
||||
"d3-scale-chromatic": "1 - 3",
|
||||
"data-bind-mapper": "1",
|
||||
"kapsule": "^1.16",
|
||||
"ngraph.forcelayout": "3",
|
||||
"ngraph.graph": "20",
|
||||
"tinycolor2": "1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.118.3"
|
||||
}
|
||||
},
|
||||
"node_modules/three-render-objects": {
|
||||
"version": "1.41.1",
|
||||
"resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.41.1.tgz",
|
||||
"integrity": "sha512-0H7l7yREPVKfO3HL7RjPQ67T0phHgnyMeEc4ww/OCEfK6jbsm7psEcrR0SGFqGDyS/pDQTPi4DyPbS/xlHRJKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tweenjs/tween.js": "18 - 25",
|
||||
"accessor-fn": "1",
|
||||
"float-tooltip": "^1.7",
|
||||
"kapsule": "^1.16",
|
||||
"polished": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.179"
|
||||
}
|
||||
},
|
||||
"node_modules/three-spritetext": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.10.0.tgz",
|
||||
"integrity": "sha512-t08iP1FCU1lQh8T5MmCpdijKgas8GDHJE0LqMGBuVu3xqMMpFnEZhTlih7FlxLPQizHIGoumUSpfOlY1GO/Tgg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.86.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinycolor2": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||
|
||||
@@ -12,12 +12,18 @@
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"react-force-graph-2d": "^1.29.1",
|
||||
"tailwindcss": "^4.2.4"
|
||||
"react-force-graph-3d": "^1.29.1",
|
||||
"tailwindcss": "^4.2.4",
|
||||
"three": "^0.184.0",
|
||||
"three-spritetext": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"parcel": "^2.14.0",
|
||||
"parcel-reporter-static-files-copy": "^1.5.3"
|
||||
},
|
||||
"@parcel/resolver-default": {
|
||||
"packageExports": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 />;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 64 KiB |
Reference in New Issue
Block a user