summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2021-08-23 21:33:42 +0200
committerJules Laplace <julescarbon@gmail.com>2021-08-23 21:33:42 +0200
commita05d52a7b13607181ce0443b17769bb02532dfc1 (patch)
treef5c4722363f29a610d1a4f95efbd9351999083f6 /src
parent5ddde1cbb70bf4bc2df127fced5afb966069d299 (diff)
importing rtf
Diffstat (limited to 'src')
-rw-r--r--src/graph.js120
-rw-r--r--src/index.js150
-rw-r--r--src/views/Detail.js31
3 files changed, 156 insertions, 145 deletions
diff --git a/src/graph.js b/src/graph.js
new file mode 100644
index 0000000..fdac979
--- /dev/null
+++ b/src/graph.js
@@ -0,0 +1,120 @@
+import * as THREE from "three";
+import ForceGraph3D from "3d-force-graph";
+import SpriteText from "three-spritetext";
+import { union } from "./utils/set_utils.js";
+
+const IMG_SCALE = 20;
+
+export default function buildGraph(db, handlers) {
+ const linkable = {};
+ const groups = {};
+ const data = { nodes: [], links: [] };
+
+ // console.log(db);
+
+ /**
+ * load nodes and links
+ */
+
+ db.page.forEach((item, index) => {
+ const node = {
+ title: item.title,
+ id: index,
+ data: item,
+ groups: [],
+ };
+ data.nodes.push(node);
+ for (let tagIndex = 0; tagIndex < 8; tagIndex += 1) {
+ const group = item["tag_" + tagIndex];
+ if (!group) continue;
+ group -= 1;
+ node.groups.push(group);
+ if (group in groups) {
+ groups[group].push(index);
+ } else {
+ groups[group] = [index];
+ }
+ if (group in linkable) {
+ data.links.push({
+ source: choice(linkable[group]),
+ // source: linkable[group][0],
+ target: index,
+ });
+ // option: don't link to the root node more than once
+ // if (window.location.hash === "#dense" && linkable[group][0]) {
+ if (linkable[group][0]) {
+ linkable[group].push(index);
+ } else {
+ linkable[group] = [index];
+ }
+ } else {
+ linkable[group] = [index];
+ }
+ }
+ });
+
+ /**
+ * find common links
+ */
+
+ data.links.forEach((link) => {
+ const a = data.nodes[link.source];
+ const b = data.nodes[link.target];
+
+ !a.links && (a.links = []);
+ !b.links && (b.links = []);
+ a.links.push(link);
+ b.links.push(link);
+ });
+
+ const highlightNodes = new Set();
+ const highlightLinks = new Set();
+ let selectedNode = null;
+
+ /** build group */
+
+ let graph = ForceGraph3D();
+ graph(document.querySelector("#graph"))
+ .graphData(data)
+ .showNavInfo(false)
+ .nodeLabel((node) => node.title)
+ .nodeThreeObject((node) => {
+ let sprite;
+ if (node.data.thumbnail?.uri) {
+ const imgTexture = new THREE.TextureLoader().load(
+ node.data.thumbnail.uri
+ );
+ // console.log(imgTexture);
+ const aspect = node.data.thumbnail.width / node.data.thumbnail.height;
+ const material = new THREE.SpriteMaterial({ map: imgTexture });
+ sprite = new THREE.Sprite(material);
+ sprite.scale.set(IMG_SCALE, IMG_SCALE / aspect);
+ return sprite;
+ } else {
+ sprite = new SpriteText(
+ node.title.split(/[ :]+/).slice(0, 3).join(" ")
+ );
+ sprite.material.depthWrite = false; // make sprite background transparent
+ sprite.color = "#888888"; // colors[node.groups[0]]; // node.groups.length - 1]];
+ sprite.textHeight = 4;
+ return sprite;
+ }
+ })
+ .onNodeClick(handlers.click);
+
+ // graph.d3Force("charge").strength(-150);
+
+ // camera orbit
+ const distance = 250;
+ let angle = 0;
+ graph.cameraPosition({
+ x: distance * Math.sin(angle),
+ z: distance * Math.cos(angle),
+ });
+
+ // stars();
+}
+
+const randint = (limit) => Math.floor(Math.random() * limit);
+const choice = (list) => list[randint(list.length)];
+const commonGroups = (a, b) => union(a.groups, b.groups);
diff --git a/src/index.js b/src/index.js
index e23db17..c51ecd1 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,161 +1,21 @@
/**
* No.6092 site for Charles Stankievech
- * - load db.json
- * - map the nodes to a graph
- * - click the nodes to open them
- * - some of the nodes are images, others are 3D
*/
-import ForceGraph3D from "3d-force-graph";
-import SpriteText from "three-spritetext";
-import { union } from "./utils/set_utils.js";
-import stars from "./utils/stars.js";
-
-const colors = [
- "rgba(111,53,158,1.0)",
- "rgba(220,188,253,1.0)",
- "rgba(30,177,237,1.0)",
- "rgba(148,206,88,1.0)",
- "rgba(252,42,28,1.0)",
- "rgba(255,253,56,1.0)",
- "rgba(43,253,183,1.0)",
- "rgba(252,76,252,1.0)",
- "rgba(205,254,170,1.0)",
- "rgba(254,205,195,1.0)",
- "rgba(199,227,254,1.0)",
- "rgba(253,191,45,1.0)",
- "rgba(253,191,45,1.0)",
-];
+import buildGraph from "./graph.js";
async function main() {
const db = await loadDB();
- const groups = {};
- const linkable = {};
- const data = { nodes: [], links: [] };
-
- console.log(db);
-
- /**
- * load nodes and links
- */
-
- db.page.forEach((item, index) => {
- const node = {
- title: item.title,
- id: index,
- groups: [],
- };
- data.nodes.push(node);
- for (let tagIndex = 0; tagIndex < 8; tagIndex += 1) {
- const group = item["tag_" + tagIndex];
- if (!group) continue;
- group -= 1;
- node.groups.push(group);
- if (group in groups) {
- groups[group].push(index);
- } else {
- groups[group] = [index];
- }
- if (group in linkable) {
- data.links.push({
- // source: choice(linkable[group]),
- source: linkable[group][0],
- target: index,
- });
- // option: don't link to the root node more than once
- // if (window.location.hash === "#dense" && linkable[group][0]) {
- if (linkable[group][0]) {
- linkable[group].push(index);
- } else {
- linkable[group] = [index];
- }
- } else {
- linkable[group] = [index];
- }
- }
- });
-
- /**
- * find common links
- */
-
- data.links.forEach((link) => {
- const a = data.nodes[link.source];
- const b = data.nodes[link.target];
-
- !a.links && (a.links = []);
- !b.links && (b.links = []);
- a.links.push(link);
- b.links.push(link);
- });
-
- const highlightNodes = new Set();
- const highlightLinks = new Set();
- let selectedNode = null;
-
- /** build group */
-
- let graph = ForceGraph3D();
- graph(document.querySelector("#graph"))
- .graphData(data)
- .nodeLabel((node) => node.title)
- .nodeThreeObject((node) => {
- const sprite = new SpriteText(
- node.title.split(/[ :]+/).slice(0, 3).join(" ")
- );
- sprite.material.depthWrite = false; // make sprite background transparent
- sprite.color = colors[node.groups[0]]; // node.groups.length - 1]];
- sprite.textHeight = 4;
- return sprite;
- })
- // .nodeColor((node) =>
- // highlightNodes.has(node.id)
- // ? node === selectedNode
- // ? colors[commonGroups(selectedNode, node)[0]]
- // : colors[commonGroups(selectedNode, node)[0]].replace("1.0", "0.8")
- // : colors[commonGroups(selectedNode, node)[0]].replace("1.0", "0.6")
- // )
- .linkWidth((link) => (highlightLinks.has(link) ? 4 : 1))
- .onNodeClick((node) => {
- // no state change
- if (!node && !highlightNodes.size) return;
-
- selectedNode = selectedNode === node ? null : node;
-
- highlightNodes.clear();
- highlightLinks.clear();
- if (node) {
- node.groups.forEach((group) =>
- groups[group].forEach((neighbor) => highlightNodes.add(neighbor))
- );
- node.links.forEach((link) => highlightLinks.add(link));
- }
-
- updateHighlight();
- });
-
- function updateHighlight() {
- graph.nodeColor(graph.nodeColor()).linkWidth(graph.linkWidth());
+ function handleClick(node) {
+ console.log(node);
}
- graph.d3Force("charge").strength(-150);
-
- // camera orbit
- const distance = 250;
- let angle = 0;
- graph.cameraPosition({
- x: distance * Math.sin(angle),
- z: distance * Math.cos(angle),
+ buildGraph(db, {
+ click: handleClick,
});
-
- stars();
}
-const randint = (limit) => Math.floor(Math.random() * limit);
-const choice = (list) => list[randint(list.length)];
-const commonGroups = (a, b) => union(a.groups, b.groups);
-
async function loadDB() {
const request = await fetch("/assets/db.json");
return await request.json();
diff --git a/src/views/Detail.js b/src/views/Detail.js
new file mode 100644
index 0000000..51598c1
--- /dev/null
+++ b/src/views/Detail.js
@@ -0,0 +1,31 @@
+/**
+ * Detail view, displaying text plus media
+ */
+
+export default function Detail({ node }) {
+ const index = id + 1;
+ const { id, data } = node;
+ return (
+ <div className="detail">
+ <div className="content">
+ <div className="title">
+ {index}
+ <br />
+ {data.author}
+ <br />
+ {data.title}
+ <br />
+ </div>
+ <div
+ className="caption"
+ dangerouslySetInnerHTML={{ __html: data.caption }}
+ />
+ <div
+ className="description"
+ dangerouslySetInnerHTML={{ __html: data.description }}
+ />
+ </div>
+ <div className="media"></div>
+ </div>
+ );
+}