@cocorof/graphier 1.4.0 → 1.4.1

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/dist/index.d.ts CHANGED
@@ -230,6 +230,12 @@ export declare interface NetworkGraph3DProps {
230
230
  * simulation untouched. null/undefined shows all edges.
231
231
  */
232
232
  linkVisibility?: ((link: GraphLink) => boolean) | null;
233
+ /**
234
+ * Allow dragging individual nodes (default: true). Set false on dense
235
+ * graphs so left-drag always pans/orbits the camera instead of grabbing
236
+ * whichever node happens to be under the pointer.
237
+ */
238
+ enableNodeDrag?: boolean;
233
239
  /** Fly the camera to a node on single-click (default: true) */
234
240
  clickToFocus?: boolean;
235
241
  /** Highlight a node's neighborhood on hover when nothing is selected (default: false) */
package/dist/index.js CHANGED
@@ -2031,6 +2031,45 @@ const _right = new THREE.Vector3();
2031
2031
  const _q = new THREE.Quaternion();
2032
2032
  const _dir = new THREE.Vector3();
2033
2033
  const _worldUp = new THREE.Vector3(0, 1, 0);
2034
+ const PAN_SPEED = 0.02;
2035
+ const PAN_ZOOM_FACTOR = 0.02;
2036
+ function createPanUpdate(camera, controls, keys) {
2037
+ const _panRight = new THREE.Vector3();
2038
+ const _panUp = new THREE.Vector3();
2039
+ const _panOffset = new THREE.Vector3();
2040
+ return function update() {
2041
+ let dx = 0;
2042
+ let dy = 0;
2043
+ if (keys["ArrowLeft"] || keys["a"] || keys["A"]) dx -= 1;
2044
+ if (keys["ArrowRight"] || keys["d"] || keys["D"]) dx += 1;
2045
+ if (keys["ArrowUp"] || keys["w"] || keys["W"]) dy += 1;
2046
+ if (keys["ArrowDown"] || keys["s"] || keys["S"]) dy -= 1;
2047
+ const zoomIn = keys["z"] || keys["Z"] || keys["+"] || keys["="];
2048
+ const zoomOut = keys["x"] || keys["X"] || keys["-"] || keys["_"];
2049
+ if (!dx && !dy && !zoomIn && !zoomOut) return false;
2050
+ const target = controls.target;
2051
+ const dist = camera.position.distanceTo(target);
2052
+ if (dx || dy) {
2053
+ const step = Math.max(dist, 50) * PAN_SPEED;
2054
+ _panRight.setFromMatrixColumn(camera.matrix, 0);
2055
+ _panUp.setFromMatrixColumn(camera.matrix, 1);
2056
+ _panOffset.set(0, 0, 0).addScaledVector(_panRight, dx * step).addScaledVector(_panUp, dy * step);
2057
+ camera.position.add(_panOffset);
2058
+ target.add(_panOffset);
2059
+ }
2060
+ if (zoomIn || zoomOut) {
2061
+ const factor = zoomIn ? -PAN_ZOOM_FACTOR : PAN_ZOOM_FACTOR;
2062
+ _panOffset.copy(camera.position).sub(target);
2063
+ const newLen = Math.max(
2064
+ controls.minDistance,
2065
+ Math.min(controls.maxDistance, _panOffset.length() * (1 + factor))
2066
+ );
2067
+ _panOffset.setLength(newLen);
2068
+ camera.position.copy(target).add(_panOffset);
2069
+ }
2070
+ return true;
2071
+ };
2072
+ }
2034
2073
  function createOrbitUpdate(camera, controls, keys) {
2035
2074
  return function update() {
2036
2075
  let zoom = 0;
@@ -2130,8 +2169,13 @@ function setupKeyboardControls(camera, controls, container, mode = "fly", flySpe
2130
2169
  container.addEventListener("keyup", onKeyUp);
2131
2170
  container.addEventListener("blur", onBlur);
2132
2171
  let enabled = true;
2133
- const innerUpdate = mode === "fly" ? createFlyUpdate(camera, controls, keys, state) : createOrbitUpdate(camera, controls, keys);
2134
- const updateFn = () => enabled ? innerUpdate() : false;
2172
+ let currentMode = mode;
2173
+ const updaters = {
2174
+ fly: createFlyUpdate(camera, controls, keys, state),
2175
+ orbit: createOrbitUpdate(camera, controls, keys),
2176
+ pan: createPanUpdate(camera, controls, keys)
2177
+ };
2178
+ const updateFn = () => enabled ? updaters[currentMode]() : false;
2135
2179
  function cleanup() {
2136
2180
  container.removeEventListener("keydown", onKeyDown2);
2137
2181
  container.removeEventListener("keyup", onKeyUp);
@@ -2144,7 +2188,11 @@ function setupKeyboardControls(camera, controls, container, mode = "fly", flySpe
2144
2188
  enabled = on;
2145
2189
  if (!on) for (const k of Object.keys(keys)) keys[k] = false;
2146
2190
  }
2147
- return { update: updateFn, cleanup, setFlySpeed, setEnabled };
2191
+ function setMode(m2) {
2192
+ currentMode = m2;
2193
+ for (const k of Object.keys(keys)) keys[k] = false;
2194
+ }
2195
+ return { update: updateFn, cleanup, setFlySpeed, setEnabled, setMode };
2148
2196
  }
2149
2197
  function createScene(container, backgroundColor, style, rendererConfig) {
2150
2198
  const scene = new THREE.Scene();
@@ -2184,7 +2232,10 @@ function createScene(container, backgroundColor, style, rendererConfig) {
2184
2232
  const cameraMode = (rendererConfig == null ? void 0 : rendererConfig.cameraMode) ?? "fly";
2185
2233
  const keyboard = setupKeyboardControls(camera, controls, container, cameraMode, style.flySpeed ?? 1);
2186
2234
  controls.enableZoom = false;
2187
- const flags = { is2D: false };
2235
+ const flags = {
2236
+ is2D: false,
2237
+ keyboardMode3D: cameraMode
2238
+ };
2188
2239
  const _wheelDir = new THREE.Vector3();
2189
2240
  const onWheel = (e) => {
2190
2241
  if (flags.is2D) return;
@@ -2218,15 +2269,16 @@ function createScene(container, backgroundColor, style, rendererConfig) {
2218
2269
  function applyCameraMode2D(state, is2D) {
2219
2270
  const { controls, camera, keyboard } = state;
2220
2271
  state.flags.is2D = is2D;
2221
- controls.enableRotate = !is2D;
2272
+ controls.enableRotate = true;
2222
2273
  controls.enableZoom = is2D;
2223
2274
  controls.screenSpacePanning = is2D;
2224
- keyboard.setEnabled(!is2D);
2275
+ keyboard.setEnabled(true);
2276
+ keyboard.setMode(is2D ? "pan" : state.flags.keyboardMode3D);
2225
2277
  if (is2D) {
2226
2278
  controls.mouseButtons = {
2227
2279
  LEFT: THREE.MOUSE.PAN,
2228
2280
  MIDDLE: THREE.MOUSE.DOLLY,
2229
- RIGHT: THREE.MOUSE.PAN
2281
+ RIGHT: THREE.MOUSE.ROTATE
2230
2282
  };
2231
2283
  controls.touches = { ONE: THREE.TOUCH.PAN, TWO: THREE.TOUCH.DOLLY_PAN };
2232
2284
  const t = controls.target;
@@ -2604,11 +2656,12 @@ function setupInteraction(canvas, camera, controls, getNodesMesh, getNodes, call
2604
2656
  const dragPlane = new THREE.Plane();
2605
2657
  const dragIntersect = new THREE.Vector3();
2606
2658
  function onPointerDown2(e) {
2659
+ var _a;
2607
2660
  mouseDownPos = { x: e.clientX, y: e.clientY };
2608
2661
  if (container && document.activeElement !== container) {
2609
2662
  container.focus({ preventScroll: true });
2610
2663
  }
2611
- if (callbacks.onNodeDrag) {
2664
+ if (callbacks.onNodeDrag && (((_a = options == null ? void 0 : options.getNodeDragEnabled) == null ? void 0 : _a.call(options)) ?? true)) {
2612
2665
  const nodesMesh = getNodesMesh();
2613
2666
  if (nodesMesh) {
2614
2667
  const rect = canvas.getBoundingClientRect();
@@ -2920,6 +2973,7 @@ function NetworkGraph3DInner(props, ref) {
2920
2973
  nodeValueAccessor,
2921
2974
  visibleNodeIds,
2922
2975
  linkVisibility,
2976
+ enableNodeDrag = true,
2923
2977
  clickToFocus = true,
2924
2978
  hoverHighlight = false,
2925
2979
  hoverHighlightHops = 1
@@ -2960,6 +3014,7 @@ function NetworkGraph3DInner(props, ref) {
2960
3014
  const labelFormatterRef = useRef(labelFormatter);
2961
3015
  const highlightSetRef = useRef(null);
2962
3016
  const clickToFocusRef = useRef(clickToFocus);
3017
+ const enableNodeDragRef = useRef(enableNodeDrag);
2963
3018
  const hoverHighlightRef = useRef(hoverHighlight);
2964
3019
  const hoverHighlightHopsRef = useRef(hoverHighlightHops);
2965
3020
  const adjacencyMapRef = useRef(/* @__PURE__ */ new Map());
@@ -2981,6 +3036,7 @@ function NetworkGraph3DInner(props, ref) {
2981
3036
  selectedNodeIdRef.current = selectedNodeId;
2982
3037
  labelFormatterRef.current = labelFormatter;
2983
3038
  clickToFocusRef.current = clickToFocus;
3039
+ enableNodeDragRef.current = enableNodeDrag;
2984
3040
  hoverHighlightRef.current = hoverHighlight;
2985
3041
  hoverHighlightHopsRef.current = hoverHighlightHops;
2986
3042
  const is2D = (layoutProp == null ? void 0 : layoutProp.dimensions) === 2;
@@ -3163,7 +3219,8 @@ function NetworkGraph3DInner(props, ref) {
3163
3219
  },
3164
3220
  {
3165
3221
  getClickToFocus: () => clickToFocusRef.current,
3166
- getIs2D: () => is2DRef.current
3222
+ getIs2D: () => is2DRef.current,
3223
+ getNodeDragEnabled: () => enableNodeDragRef.current
3167
3224
  }
3168
3225
  );
3169
3226
  return () => {