summaryrefslogtreecommitdiff
path: root/src/views/Graph.js
blob: 7188a7480a9d67f021f7f3c2520cce88b63950cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
 * Main interaction logic
 */

import React, { useState, useEffect, useCallback } from "react";

import Detail from "./Detail.js";
import Legend from "./Legend.js";
import Quote from "./Quote.js";
import Credits from "./Credits.js";
import Title from "./Title.js";
import buildGraph from "../graph.js";
import { footprint } from "../utils/shoelace.js";

export default function Graph({ db }) {
  const [node, setNode] = useState(null);
  const [graph, setGraph] = useState(null);
  const [selectedCategory, setSelectedCategory] = useState(null);
  const [detailVisible, setDetailVisible] = useState(false);
  const [creditsVisible, setCreditsVisible] = useState(false);
  const [introDone, setIntroDone] = useState(false);
  const [introCurtainDone, setIntroCurtainDone] = useState(false);
  const [introTextDone, setIntroTextDone] = useState(false);

  /** Build the graph */
  useEffect(() => {
    const graph = buildGraph({
      db,
      handlers: {
        click: handleClick,
      },
    });
    setGraph(graph);
    setTimeout(() => {
      setIntroCurtainDone(true);
      graph.onLoad();
      setTimeout(() => {
        setIntroDone(true);
      }, 4000);
      setTimeout(() => {
        setIntroTextDone(true);
      }, 8000);
    }, 10);
  }, []);

  /** Click to open a node */
  const handleClick = useCallback((node) => {
    setNode(node);
    setDetailVisible(true);
    footprint("details", { id: node.id + 1 });
  });

  /** Click to close the media modal */
  const handleClose = useCallback((node) => {
    setDetailVisible(false);
  });

  /** Select or clear the category */
  const handleSelect = useCallback((category) => {
    if (category === selectedCategory) {
      setSelectedCategory(null);
      graph.onSelect(null);
    } else {
      setSelectedCategory(category);
      graph.onSelect(category);
    }
  });

  const handleCredits = useCallback((newState) => {
    setCreditsVisible(newState);
    if (newState) {
      footprint("credits");
    }
  }, []);

  return (
    <div className={introTextDone ? "" : "intro-text"}>
      <Detail node={node} visible={detailVisible} onClose={handleClose} />
      <Legend
        visible={introDone && !detailVisible && !creditsVisible}
        selected={selectedCategory}
        onSelect={handleSelect}
      />
      <Quote visible={introDone && !detailVisible && !creditsVisible} />
      <Credits
        onToggle={handleCredits}
        visible={introDone && !detailVisible}
        open={creditsVisible}
      />
      <Title visible={introDone /* && !detailVisible && !creditsVisible*/} />
      <div className={introCurtainDone ? "curtain done" : "curtain"} />
    </div>
  );
}