@cocorof/graphier 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,12 +39,14 @@ const ref = useRef<NetworkGraph3DRef>(null);
39
39
  <GraphMinimap graphRef={ref} width={200} height={140} />
40
40
  ```
41
41
 
42
- - `layout.dimensions: 2` — simulation runs in 2D (z locked to 0); camera locks to pan/zoom (drag pans, wheel/pinch zooms, rotation off).
42
+ - `layout.dimensions: 2` — flat Obsidian-style plane: simulation runs in 2D (z locked to 0). Left-drag pans, right-drag tilts/orbits the world, wheel/pinch zooms, arrows/WASD pan and z/x zoom (v1.4.1).
43
+ - `enableNodeDrag={false}` — left-drag always reaches the camera even over nodes; essential for dense graphs (v1.4.1).
43
44
  - `layout.clusterBy: "type" | "group"` + `clusterStrength` — pulls same-key nodes toward a shared centroid so categories form visible clusters.
44
45
  - `linkVisibility={(link) => bool}` — reheat-free per-edge filter (e.g. hide a link type).
45
46
  - `visibleNodeIds` — client-side filter; hidden nodes/edges/labels vanish via per-instance scale + collapsed segments. Positions are preserved: toggling filters never reheats the simulation.
46
47
  - `hoverHighlight` / `hoverHighlightHops` — Obsidian-style neighborhood emphasis on hover (selection wins while active).
47
48
  - `theme="paper"` — light background preset; edge blending switches to normal automatically (additive lines vanish on white) and highlight/dim directions invert.
49
+ - `renderer.navigation` — remap pointer/keyboard navigation per consumer, e.g. `{ leftButton: "pan", rightButton: "rotate", keyboard: "pan" }` for pan-first 3D graphs (v1.4.2).
48
50
  - `GraphMinimap` — 2D-canvas overview (no second WebGL context): draws all visible nodes + the camera viewport rectangle, click/drag to pan. Powered by `ref.getGraphSnapshot()` / `ref.getViewportRect()` / `ref.panTo(x, y)`.
49
51
 
50
52
  ## Install
package/dist/index.cjs CHANGED
@@ -2284,34 +2284,38 @@ function createScene(container, backgroundColor, style, rendererConfig) {
2284
2284
  flags
2285
2285
  };
2286
2286
  }
2287
- function applyCameraMode2D(state, is2D) {
2287
+ const MOUSE_ACTION = {
2288
+ rotate: THREE__namespace.MOUSE.ROTATE,
2289
+ pan: THREE__namespace.MOUSE.PAN
2290
+ };
2291
+ function applyNavigationMode(state, is2D, nav) {
2288
2292
  const { controls, camera, keyboard } = state;
2289
2293
  state.flags.is2D = is2D;
2290
- controls.enableRotate = true;
2294
+ const left = (nav == null ? void 0 : nav.leftButton) ?? (is2D ? "pan" : "rotate");
2295
+ const right = (nav == null ? void 0 : nav.rightButton) ?? (is2D ? "rotate" : "pan");
2296
+ controls.mouseButtons = {
2297
+ LEFT: MOUSE_ACTION[left],
2298
+ MIDDLE: THREE__namespace.MOUSE.DOLLY,
2299
+ RIGHT: MOUSE_ACTION[right]
2300
+ };
2301
+ controls.enableRotate = left === "rotate" || right === "rotate";
2302
+ controls.touches = left === "pan" ? { ONE: THREE__namespace.TOUCH.PAN, TWO: THREE__namespace.TOUCH.DOLLY_PAN } : { ONE: THREE__namespace.TOUCH.ROTATE, TWO: THREE__namespace.TOUCH.DOLLY_PAN };
2291
2303
  controls.enableZoom = is2D;
2292
2304
  controls.screenSpacePanning = is2D;
2293
- keyboard.setEnabled(true);
2294
- keyboard.setMode(is2D ? "pan" : state.flags.keyboardMode3D);
2305
+ const kb = (nav == null ? void 0 : nav.keyboard) ?? (is2D ? "pan" : state.flags.keyboardMode3D);
2306
+ if (kb === "off") {
2307
+ keyboard.setEnabled(false);
2308
+ } else {
2309
+ keyboard.setEnabled(true);
2310
+ keyboard.setMode(kb);
2311
+ }
2295
2312
  if (is2D) {
2296
- controls.mouseButtons = {
2297
- LEFT: THREE__namespace.MOUSE.PAN,
2298
- MIDDLE: THREE__namespace.MOUSE.DOLLY,
2299
- RIGHT: THREE__namespace.MOUSE.ROTATE
2300
- };
2301
- controls.touches = { ONE: THREE__namespace.TOUCH.PAN, TWO: THREE__namespace.TOUCH.DOLLY_PAN };
2302
2313
  const t = controls.target;
2303
2314
  const dist = Math.max(camera.position.distanceTo(t), 50);
2304
2315
  t.z = 0;
2305
2316
  camera.up.set(0, 1, 0);
2306
2317
  camera.position.set(t.x, t.y, dist);
2307
2318
  camera.lookAt(t);
2308
- } else {
2309
- controls.mouseButtons = {
2310
- LEFT: THREE__namespace.MOUSE.ROTATE,
2311
- MIDDLE: THREE__namespace.MOUSE.DOLLY,
2312
- RIGHT: THREE__namespace.MOUSE.PAN
2313
- };
2314
- controls.touches = { ONE: THREE__namespace.TOUCH.ROTATE, TWO: THREE__namespace.TOUCH.DOLLY_PAN };
2315
2319
  }
2316
2320
  controls.update();
2317
2321
  }
@@ -3518,10 +3522,11 @@ function NetworkGraph3DInner(props, ref) {
3518
3522
  );
3519
3523
  }
3520
3524
  }, [visibleSet, linkVisibility, mergedData]);
3525
+ const navKey = JSON.stringify((rendererProp == null ? void 0 : rendererProp.navigation) ?? null);
3521
3526
  react.useEffect(() => {
3522
3527
  const s = sceneRef.current;
3523
- if (s) applyCameraMode2D(s, is2D);
3524
- }, [is2D]);
3528
+ if (s) applyNavigationMode(s, is2D, rendererProp == null ? void 0 : rendererProp.navigation);
3529
+ }, [is2D, navKey]);
3525
3530
  react.useEffect(() => {
3526
3531
  const gObj = graphObjRef.current;
3527
3532
  const sceneState = sceneRef.current;
@@ -3773,11 +3778,12 @@ function NetworkGraph3DInner(props, ref) {
3773
3778
  const s = sceneRef.current;
3774
3779
  if (!s) return null;
3775
3780
  const cam = s.camera;
3776
- const dist = Math.abs(cam.position.z);
3781
+ const t = s.controls.target;
3782
+ const dist = Math.max(cam.position.distanceTo(t), 1);
3777
3783
  const halfH = Math.tan(cam.fov * Math.PI / 360) * dist;
3778
3784
  return {
3779
- cx: cam.position.x,
3780
- cy: cam.position.y,
3785
+ cx: t.x,
3786
+ cy: t.y,
3781
3787
  halfW: halfH * cam.aspect,
3782
3788
  halfH
3783
3789
  };