Skip to content

0014. 그래프 보기는 force-graph를 React 래퍼 없이 쓰고, 그래프 모드의 사이드바는 루트 칸 목록으로 둔다

This content is not available in your language yet.

옵시디언 같은 그래프 보기를 만든다. 연결 폴더(프로젝트 루트)마다 그 안의 .md 파일이 노드, 파일 사이의 링크가 선이다. 노드와 선 목록은 window.graph.build(root)가 만든다(PR #61).

그래프 화면에는 확대와 축소, 화면 이동, 노드 끌기, 마우스를 올린 노드와 이웃의 강조, 노드 누르기가 필요하다. 배치는 힘 기반이라 연결된 노드끼리 모여야 하고, 옵시디언의 힘 설정(Center, Repel, Link force, Link distance)과 같은 손맛이면 좋다. 저장소 하나에 .md 파일이 2~3천 개까지 있을 수 있다.

그래프는 편집기 영역의 탭으로 연다. 이 앱의 탭은 숨긴 채 DOM에 남겨 두고, 보일 때만 드러낸다.

  • 그래프 화면은 force-graph로 그리고, React 래퍼(react-force-graph-2d) 없이 인스턴스를 직접 다룬다. useEffect에서 new ForceGraph(element)로 만들고 언마운트할 때 _destructor()로 정리한다. 화면 모듈은 React.lazy로 그래프 탭을 처음 열 때 불러온다.
  • 힘 설정은 코드의 상수로 둔다. d3Force('charge')와 d3Force('link')에 상수를 넣고, 설정 화면에 여는 일은 하지 않는다.
  • 그래프 모드의 사이드바는 트리 대신 루트 칸 목록을 보여 준다. 레일에 그래프 아이콘을 더하고, 그래프 모드에서는 연결 폴더마다 이름과 .md 파일 수만 적힌 칸을 둔다. worktree, 파일, git 트리와 우클릭 메뉴는 없다. 사이드바의 모양이 모드에 따라 달라지는 것은 이 모드가 처음이다. 머리(제목과 프로젝트 추가 단추)는 다른 모드와 같다.
  • force-graph를 고른 이유: 확대, 이동, 노드 끌기, 올리기와 누르기 판정이 기본으로 들어 있다. 배치 엔진이 d3-force라 옵시디언과 같은 힘(중심, 반발, 선의 당김과 길이)을 그대로 쓴다. 캔버스로 그려 2~3천 노드도 충분히 돈다. MIT이고 gzip 약 57KB다.
  • React 래퍼를 쓰지 않는 이유: 래퍼(react-kapsule)는 React가 fiber를 다시 쓸 때 인스턴스를 다시 만들지 않는 문제가 있다(vasturiano/react-force-graph#596). 이 앱은 탭을 숨긴 채 유지하므로 그 경우를 만날 수 있다. 직접 다루면 만들기, 크기 맞추기, 멈추기와 다시 돌기, 정리를 탭의 생애에 맞춰 부를 수 있다.
  • d3-force를 직접 쓴다. 의존성은 가장 작다. 그러나 캔버스 그리기, 확대와 이동, 끌기, 올리기 판정을 모두 새로 만들어야 한다.
  • sigma와 graphology를 쓴다. WebGL이라 수만 노드에도 빠르다. 그러나 이 앱의 규모(2~3천 노드)에는 캔버스로 충분하고, 힘 배치는 따로 붙이는 ForceAtlas2라 옵시디언의 d3-force 설정과 손맛이 다르다. 라이브러리도 둘을 들여야 한다.
  • cytoscape를 쓴다. 그래프 분석과 배치 종류가 많지만 무겁고, 이번에 필요한 것(힘 배치 하나와 기본 상호작용)에 비해 크다.
  • 사이드바에 트리를 그대로 두고 그래프 단추만 더한다. 모양은 한 가지로 유지된다. 그러나 그래프는 루트 단위라 worktree, 파일, git 트리가 쓸 데가 없고, 루트마다 .md 파일 수를 보여 주는 편이 어떤 그래프를 열지 고르기 쉽다.
  • 올리기 강조가 엔진이 멈춘 뒤에도 보이도록 autoPauseRedraw(false)로 계속 그린다. 그래프 탭이 보이는 동안은 매 프레임 캔버스를 다시 그리고, 탭이 숨으면 pauseAnimation()으로 멈춘다.
  • force-graph의 올리기 판정용 캔버스는 800ms 간격으로만 다시 그려진다(vasturiano/force-graph#366). 노드가 움직이는 동안에는 올리기 판정이 잠깐 늦을 수 있다.
  • 그래프 탭은 보일 때마다 그래프를 다시 받는다. 같은 id의 노드는 앞 배치의 자리를 이어 받아 흩어지지 않는다.
  • 그래프 화면 파일(GraphSlot, GraphView, graphStyle)은 features/graph/가 아니라 workspace/에 둔다. PaneTree가 탭 자리를 그리므로 ADR 0008의 renderer 의존 방향에서 workspace가 import할 수 있는 자리여야 한다. 루트 칸 목록은 쓰는 곳이 사이드바뿐이라 features/sidebar/에 둔다.
  • 힘 설정을 사용자가 고칠 수 있게 하거나, 무리를 색으로 나누는 일은 나중에 따로 한다.