@vitessce/launcher 4.1.0 → 4.1.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.
@@ -3,7 +3,7 @@ import { useRef, useEffect, useState } from "react";
3
3
  import { useThree, useFrame } from "@react-three/fiber";
4
4
  import { Bvh } from "@react-three/drei";
5
5
  import { Matrix4, Vector3, Box3, FrontSide } from "three";
6
- import { g as getXRModule, i as isValidGeometrySize, M as MeasureLine, s as stringifyLineData } from "./index-6RcG881_.js";
6
+ import { g as getXRModule, i as isValidGeometrySize, M as MeasureLine, s as stringifyLineData } from "./index-DSTEevd1.js";
7
7
  function getHandJoint(hand, jointName) {
8
8
  return hand.get(jointName);
9
9
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import React__default from "react";
3
- import { g as getDefaultExportFromCjs, d as requireAssign, f as require_export, h as require_core, j as require_fails, k as require_toObject, m as require_objectKeys, n as require_cof, o as require_wks, p as require_iterators, q as requireWeb_dom_iterable, s as requireEs6_string_iterator, t as require_anObject, v as require_hide, w as require_ctx, x as require_toLength, y as require_global, z as require_objectDp, A as require_descriptors, D as require_isObject, E as require_objectCreate, F as require_iterDefine, G as require_iterStep, H as require_meta, I as require_isArray, J as require_iobject, K as require_setToStringTag, M as require_aFunction, N as requireIterator, O as require_propertyDesc, c as commonjsGlobal, P as requireEs6_symbol, Q as requireDefineProperty, R as require_toIobject, S as require_objectGopd, T as require_html, U as require_domCreate, V as require_library, W as requireSymbol, X as require_objectPie, Y as require_has, Z as require_redefine, _ as require_objectAssign, $ as GREY_HEX, a0 as diffCameraState } from "./index-BseIw2ZD.js";
3
+ import { g as getDefaultExportFromCjs, d as requireAssign, f as require_export, h as require_core, j as require_fails, k as require_toObject, m as require_objectKeys, n as require_cof, o as require_wks, p as require_iterators, q as requireWeb_dom_iterable, s as requireEs6_string_iterator, t as require_anObject, v as require_hide, w as require_ctx, x as require_toLength, y as require_global, z as require_objectDp, A as require_descriptors, D as require_isObject, E as require_objectCreate, F as require_iterDefine, G as require_iterStep, H as require_meta, I as require_isArray, J as require_iobject, K as require_setToStringTag, M as require_aFunction, N as requireIterator, O as require_propertyDesc, c as commonjsGlobal, P as requireEs6_symbol, Q as requireDefineProperty, R as require_toIobject, S as require_objectGopd, T as require_html, U as require_domCreate, V as require_library, W as requireSymbol, X as require_objectPie, Y as require_has, Z as require_redefine, _ as require_objectAssign, $ as GREY_HEX, a0 as diffCameraState } from "./index-DfnWmR3U.js";
4
4
  var assignExports = requireAssign();
5
5
  const _Object$assign = /* @__PURE__ */ getDefaultExportFromCjs(assignExports);
6
6
  var es6_object_keys = {};
@@ -65801,7 +65801,9 @@ class Neuroglancer extends React__default.Component {
65801
65801
  const segIdsChangedForLayer = (name2) => {
65802
65802
  const prevIds = prevSegLayers.find((l) => l.name === name2)?.segments ?? [];
65803
65803
  const nextIds = nextSegLayers.find((l) => l.name === name2)?.segments ?? [];
65804
- return prevIds.length !== nextIds.length || prevIds[0] !== nextIds[0] || prevIds[prevIds.length - 1] !== nextIds[nextIds.length - 1];
65804
+ if (prevIds.length !== nextIds.length)
65805
+ return true;
65806
+ return prevIds.some((id, i) => String(id) !== String(nextIds[i]));
65805
65807
  };
65806
65808
  const allSegLayerNames = /* @__PURE__ */ new Set([
65807
65809
  ...prevSegLayers.map((l) => l.name),
@@ -65809,7 +65811,7 @@ class Neuroglancer extends React__default.Component {
65809
65811
  ]);
65810
65812
  const segmentsChanged = [...allSegLayerNames].some(segIdsChangedForLayer);
65811
65813
  const nextSegIds = nextSegLayers.flatMap((l) => l.segments ?? []);
65812
- if (segmentsChanged && nextSegIds.length > 0) {
65814
+ if (segmentsChanged && (nextSegIds.length > 0 || this.props.allowEmptySegments)) {
65813
65815
  this.preserveDimensions(() => {
65814
65816
  this.viewer.state.restoreState({ layers: nextLayers });
65815
65817
  });
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
- import { g as getXrStore } from "./xrStore-BquNcHaW.js";
3
+ import { g as getXrStore } from "./xrStore-C3wJy9QJ.js";
4
4
  function XREnterButton() {
5
5
  const [supported, setSupported] = useState(false);
6
6
  const [entered, setEntered] = useState(false);
@@ -1,7 +1,7 @@
1
1
  import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { useRef } from "react";
3
3
  import { useThree, useFrame } from "@react-three/fiber";
4
- import { g as getXRModule } from "./index-6RcG881_.js";
4
+ import { g as getXRModule } from "./index-DSTEevd1.js";
5
5
  function getHandJoint(hand, jointName) {
6
6
  return hand.get(jointName);
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { g as getXRModule } from "./index-6RcG881_.js";
3
- import { g as getXrStore } from "./xrStore-BquNcHaW.js";
2
+ import { g as getXRModule } from "./index-DSTEevd1.js";
3
+ import { g as getXrStore } from "./xrStore-C3wJy9QJ.js";
4
4
  function XRWrapper({ children }) {
5
5
  const { XR } = getXRModule();
6
6
  return jsx(XR, { store: getXrStore(), children });
@@ -1,5 +1,5 @@
1
1
  import { i as inflate_1 } from "./pako.esm-SxljTded.js";
2
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
2
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
3
3
  class DeflateDecoder extends BaseDecoder {
4
4
  decodeBlock(buffer) {
5
5
  return inflate_1(new Uint8Array(buffer)).buffer;
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import React__default, { createContext, isValidElement, PureComponent, Component, useMemo, useState, useRef, useEffect, useCallback, memo, useContext, useReducer, useLayoutEffect } from "react";
3
- import { r as requireObjectAssign, g as getDefaultExportFromCjs$1, c as commonjsGlobal, e as earcut } from "./index-BseIw2ZD.js";
3
+ import { r as requireObjectAssign, g as getDefaultExportFromCjs$1, c as commonjsGlobal, e as earcut } from "./index-DfnWmR3U.js";
4
4
  import ReactDOM__default, { unstable_batchedUpdates, createPortal } from "react-dom";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function finallyConstructor(callback) {
@@ -4,7 +4,7 @@ import { useThree, useFrame, Canvas } from "@react-three/fiber";
4
4
  import { OrbitControls } from "@react-three/drei";
5
5
  import * as THREE from "three";
6
6
  import { Data3DTexture, RedFormat, UnsignedByteType, LinearFilter, RedIntegerFormat, UnsignedIntType, NearestFilter, Vector3, Vector2, Vector4, UniformsUtils } from "three";
7
- import { l as log, i as isEqual, C as CoordinationType, u as useEventCallback } from "./index-BseIw2ZD.js";
7
+ import { l as log, i as isEqual, C as CoordinationType, u as useEventCallback } from "./index-DfnWmR3U.js";
8
8
  const LogLevel = {
9
9
  INFO: "info",
10
10
  WARN: "warn",
@@ -3,7 +3,7 @@ import React__default, { useRef, useState, useEffect, Suspense, forwardRef } fro
3
3
  import { Canvas } from "@react-three/fiber";
4
4
  import { Center, Text, Line, Bvh, OrbitControls } from "@react-three/drei";
5
5
  import { Matrix3, Matrix4, Vector3, Vector2, UniformsUtils, Data3DTexture, RedFormat, FloatType, LinearFilter, FrontSide, Scene, Group, MeshPhysicalMaterial, MeshBasicMaterial, MeshStandardMaterial, BackSide } from "three";
6
- import { C as CoordinationType, b as getImageSize } from "./index-BseIw2ZD.js";
6
+ import { C as CoordinationType, b as getImageSize } from "./index-DfnWmR3U.js";
7
7
  function MeasureLine({ currentLine, scale }) {
8
8
  const textRef = useRef(null);
9
9
  return jsxs("group", { children: [jsx(Center, { bottom: true, right: true, position: [currentLine.midPoint.x, currentLine.midPoint.y, currentLine.midPoint.z], rotation: [0, 0, 0], children: jsx(Text, { color: "gray", scale: 0.05, ref: textRef, children: `${(currentLine.startPoint.distanceTo(currentLine.endPoint) * scale).toFixed(2)} µm` }) }), jsx(Line, {
@@ -945,8 +945,8 @@ function GeometryAndMesh(props) {
945
945
  setObsHighlight(e.object.name);
946
946
  }, onPointerOut: () => setObsHighlight(null) }) })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale && renderingSettings.geometrySize ? jsx("group", { children: jsxs("mesh", { scale: renderingSettings.meshScale, ref: materialRef, children: [jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 }, stringifyLineData(object))) })] });
947
947
  }
948
- const LazyGeometryAndMeshXR = React__default.lazy(() => import("./GeometryAndMeshXR-CcEu5oNe.js").catch(() => ({ default: GeometryAndMesh })));
949
- const LazyXRSceneComponents = React__default.lazy(() => import("./XRSceneComponents-V8xqrJn_.js").catch(() => ({ default: () => null })));
948
+ const LazyGeometryAndMeshXR = React__default.lazy(() => import("./GeometryAndMeshXR-BP8AVQ0V.js").catch(() => ({ default: GeometryAndMesh })));
949
+ const LazyXRSceneComponents = React__default.lazy(() => import("./XRSceneComponents-es9Ug6ak.js").catch(() => ({ default: () => null })));
950
950
  function SpatialThree(props) {
951
951
  const materialRef = useRef(null);
952
952
  const orbitRef = useRef(null);
@@ -1303,13 +1303,13 @@ function getXRModule() {
1303
1303
  }
1304
1304
  const LazyXRWrapper = React__default.lazy(
1305
1305
  // eslint-disable-next-line implicit-arrow-linebreak, function-paren-newline
1306
- () => import("./XRWrapper-SVsD-e_G.js").catch(() => ({
1306
+ () => import("./XRWrapper-zQl6MVwX.js").catch(() => ({
1307
1307
  default: ({ children }) => children
1308
1308
  }))
1309
1309
  );
1310
1310
  const LazyXREnterButton = React__default.lazy(
1311
1311
  // eslint-disable-next-line implicit-arrow-linebreak, function-paren-newline
1312
- () => import("./XREnterButton-DRjKwHQ6.js").catch(() => ({
1312
+ () => import("./XREnterButton-C69Opx4q.js").catch(() => ({
1313
1313
  default: () => null
1314
1314
  }))
1315
1315
  );
@@ -7749,6 +7749,19 @@ function isAnnotationFrameViewStateChange(prevViewState, nextViewState, frameVie
7749
7749
  const changedKeys = TRANSITION_VIEW_STATE_KEYS.filter((key2) => prevViewState[key2] !== nextViewState[key2]);
7750
7750
  return changedKeys.length > 0 && changedKeys.every((key2) => typeof prevViewState[key2] === "number" && typeof nextViewState[key2] === "number" && frameViewState[key2] === nextViewState[key2]);
7751
7751
  }
7752
+ const UNIT_TO_METERS = {
7753
+ m: 1,
7754
+ meter: 1,
7755
+ mm: 1e-3,
7756
+ millimeter: 1e-3,
7757
+ um: 1e-6,
7758
+ µm: 1e-6,
7759
+ μm: 1e-6,
7760
+ micrometer: 1e-6,
7761
+ micron: 1e-6,
7762
+ nm: 1e-9,
7763
+ nanometer: 1e-9
7764
+ };
7752
7765
  configSchema1_0_0.shape.coordinationSpace.unwrap();
7753
7766
  configSchema1_0_0.shape.layout.element.shape.coordinationScopes.unwrap();
7754
7767
  function upgradeReplaceViewProp(prefix2, view, coordinationSpace) {
@@ -10562,6 +10575,7 @@ const CoordinationType$1 = {
10562
10575
  PIXEL_HIGHLIGHT: "pixelHighlight",
10563
10576
  // Per-image-layer
10564
10577
  TOOLTIP_CROSSHAIRS_VISIBLE: "tooltipCrosshairsVisible",
10578
+ TOOLTIP_OBS_SETS_MODE: "tooltipObsSetsMode",
10565
10579
  LEGEND_VISIBLE: "legendVisible",
10566
10580
  SPATIAL_CHANNEL_LABELS_VISIBLE: "spatialChannelLabelsVisible",
10567
10581
  SPATIAL_CHANNEL_LABELS_ORIENTATION: "spatialChannelLabelsOrientation",
@@ -10923,6 +10937,7 @@ const COMPONENT_COORDINATION_TYPES = {
10923
10937
  CoordinationType$1.SPATIAL_ORBIT_AXIS,
10924
10938
  CoordinationType$1.SPATIAL_ZOOM,
10925
10939
  CoordinationType$1.SPATIAL_CAMERA_SNAPSHOT,
10940
+ CoordinationType$1.SPATIAL_RENDERING_MODE,
10926
10941
  CoordinationType$1.OBS_FILTER,
10927
10942
  CoordinationType$1.OBS_HIGHLIGHT,
10928
10943
  CoordinationType$1.OBS_SET_SELECTION,
@@ -10990,6 +11005,7 @@ const COMPONENT_COORDINATION_TYPES = {
10990
11005
  CoordinationType$1.OBS_COLOR_ENCODING,
10991
11006
  CoordinationType$1.ADDITIONAL_OBS_SETS,
10992
11007
  CoordinationType$1.TOOLTIPS_VISIBLE,
11008
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE,
10993
11009
  CoordinationType$1.SAMPLE_TYPE,
10994
11010
  CoordinationType$1.SAMPLE_SET_SELECTION,
10995
11011
  CoordinationType$1.SAMPLE_SET_FILTER,
@@ -11041,6 +11057,7 @@ const COMPONENT_COORDINATION_TYPES = {
11041
11057
  CoordinationType$1.OBS_COLOR_ENCODING,
11042
11058
  CoordinationType$1.ADDITIONAL_OBS_SETS,
11043
11059
  CoordinationType$1.TOOLTIPS_VISIBLE,
11060
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE,
11044
11061
  CoordinationType$1.SAMPLE_TYPE,
11045
11062
  CoordinationType$1.SAMPLE_SET_SELECTION,
11046
11063
  CoordinationType$1.SAMPLE_SET_FILTER,
@@ -11122,6 +11139,7 @@ const COMPONENT_COORDINATION_TYPES = {
11122
11139
  CoordinationType$1.ADDITIONAL_OBS_SETS,
11123
11140
  CoordinationType$1.MOLECULE_HIGHLIGHT,
11124
11141
  CoordinationType$1.TOOLTIPS_VISIBLE,
11142
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE,
11125
11143
  CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
11126
11144
  CoordinationType$1.ANNOTATION_STORY,
11127
11145
  CoordinationType$1.ANNOTATION_SHAPES,
@@ -11171,6 +11189,7 @@ const COMPONENT_COORDINATION_TYPES = {
11171
11189
  CoordinationType$1.ADDITIONAL_OBS_SETS,
11172
11190
  CoordinationType$1.MOLECULE_HIGHLIGHT,
11173
11191
  CoordinationType$1.TOOLTIPS_VISIBLE,
11192
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE,
11174
11193
  CoordinationType$1.FILE_UID,
11175
11194
  CoordinationType$1.SPATIAL_TARGET_C,
11176
11195
  CoordinationType$1.SPATIAL_LAYER_VISIBLE,
@@ -11254,7 +11273,8 @@ const COMPONENT_COORDINATION_TYPES = {
11254
11273
  CoordinationType$1.FEATURE_VALUE_COLORMAP_RANGE,
11255
11274
  CoordinationType$1.OBS_COLOR_ENCODING,
11256
11275
  CoordinationType$1.ADDITIONAL_OBS_SETS,
11257
- CoordinationType$1.TOOLTIPS_VISIBLE
11276
+ CoordinationType$1.TOOLTIPS_VISIBLE,
11277
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE
11258
11278
  ],
11259
11279
  [ViewType$1.OBS_SETS]: [
11260
11280
  CoordinationType$1.DATASET,
@@ -94632,6 +94652,12 @@ function findChangedHierarchy(prevSelectedPaths, currSelectedPaths) {
94632
94652
  const changedPath = newlySelectedPaths.length > 0 ? newlySelectedPaths[0] : unselectedPaths[0];
94633
94653
  return changedPath.slice(0, -1);
94634
94654
  }
94655
+ function filterObsMembershipForTooltip(obsMembership, obsSetSelection, tooltipObsSetsMode) {
94656
+ if (tooltipObsSetsMode !== "selected") {
94657
+ return obsMembership;
94658
+ }
94659
+ return obsMembership.filter((path2) => obsSetSelection?.some((selectedPath) => selectedPath[0] === path2[0]));
94660
+ }
94635
94661
  var EOL$1 = {}, EOF$1 = {}, QUOTE$1 = 34, NEWLINE$1 = 10, RETURN$1 = 13;
94636
94662
  function objectConverter$1(columns2) {
94637
94663
  return new Function("d", "return {" + columns2.map(function(name2, i2) {
@@ -212328,22 +212354,22 @@ async function getDecoder(fileDirectory) {
212328
212354
  const Decoder = await importFn();
212329
212355
  return new Decoder(fileDirectory);
212330
212356
  }
212331
- addDecoder([void 0, 1], () => import("./raw-CUs4bhyE.js").then((m2) => m2.default));
212332
- addDecoder(5, () => import("./lzw-BuL_B2v5.js").then((m2) => m2.default));
212357
+ addDecoder([void 0, 1], () => import("./raw-D1UzT8aH.js").then((m2) => m2.default));
212358
+ addDecoder(5, () => import("./lzw-BCz1KFC-.js").then((m2) => m2.default));
212333
212359
  addDecoder(6, () => {
212334
212360
  throw new Error("old style JPEG compression is not supported.");
212335
212361
  });
212336
- addDecoder(7, () => import("./jpeg-x4QuDQjN.js").then((m2) => m2.default));
212337
- addDecoder([8, 32946], () => import("./deflate-Dvdck6bG.js").then((m2) => m2.default));
212338
- addDecoder(32773, () => import("./packbits-C3ekVfY_.js").then((m2) => m2.default));
212362
+ addDecoder(7, () => import("./jpeg-b4kIkXxx.js").then((m2) => m2.default));
212363
+ addDecoder([8, 32946], () => import("./deflate-CQONbUH_.js").then((m2) => m2.default));
212364
+ addDecoder(32773, () => import("./packbits-B9rNC1ys.js").then((m2) => m2.default));
212339
212365
  addDecoder(
212340
212366
  34887,
212341
- () => import("./lerc-DipUzJGG.js").then(async (m2) => {
212367
+ () => import("./lerc-BJIQdCtD.js").then(async (m2) => {
212342
212368
  await m2.zstd.init();
212343
212369
  return m2;
212344
212370
  }).then((m2) => m2.default)
212345
212371
  );
212346
- addDecoder(50001, () => import("./webimage-CYpiWUZZ.js").then((m2) => m2.default));
212372
+ addDecoder(50001, () => import("./webimage-Cc3Zzfmt.js").then((m2) => m2.default));
212347
212373
  function copyNewSize(array2, width2, height2, samplesPerPixel = 1) {
212348
212374
  return new (Object.getPrototypeOf(array2)).constructor(width2 * height2 * samplesPerPixel);
212349
212375
  }
@@ -234765,6 +234791,7 @@ class AbstractSpatialOrScatterplot extends PureComponent {
234765
234791
  };
234766
234792
  this.lastApplied = null;
234767
234793
  this.transitionEndViewState = null;
234794
+ this.finishedTransitionEndViewState = null;
234768
234795
  this.viewport = null;
234769
234796
  this.threeCamera = null;
234770
234797
  this.orbitControls = null;
@@ -234841,6 +234868,7 @@ class AbstractSpatialOrScatterplot extends PureComponent {
234841
234868
  * Called by DeckGL when a viewState transition ends.
234842
234869
  */
234843
234870
  onTransitionEnd() {
234871
+ this.finishedTransitionEndViewState = this.transitionEndViewState;
234844
234872
  this.transitionEndViewState = null;
234845
234873
  this.setState({ transitionViewState: null });
234846
234874
  }
@@ -234851,6 +234879,7 @@ class AbstractSpatialOrScatterplot extends PureComponent {
234851
234879
  * Instead, the stale transitionViewState is ignored by getDeckViewState.
234852
234880
  */
234853
234881
  onTransitionInterrupt() {
234882
+ this.finishedTransitionEndViewState = this.transitionEndViewState;
234854
234883
  this.transitionEndViewState = null;
234855
234884
  }
234856
234885
  /**
@@ -234863,6 +234892,13 @@ class AbstractSpatialOrScatterplot extends PureComponent {
234863
234892
  if (transitionViewState && transitionViewState.endViewState === this.transitionEndViewState && isSameZoomAndTarget(viewState, this.transitionEndViewState)) {
234864
234893
  return transitionViewState.viewState;
234865
234894
  }
234895
+ if (!isSameZoomAndTarget(viewState, this.finishedTransitionEndViewState)) {
234896
+ this.finishedTransitionEndViewState = null;
234897
+ }
234898
+ if (this.finishedTransitionEndViewState) {
234899
+ const { transitionDuration, transitionInterpolator, ...viewStateWithoutTransition } = viewState;
234900
+ return viewStateWithoutTransition;
234901
+ }
234866
234902
  if (viewState.transitionDuration) {
234867
234903
  return {
234868
234904
  ...viewState,
@@ -235019,7 +235055,8 @@ class AbstractSpatialOrScatterplot extends PureComponent {
235019
235055
  const canvas = deckRef?.current?.deck?.canvas;
235020
235056
  if (!canvas || !spatialCameraSnapshot)
235021
235057
  return;
235022
- const camera = new PerspectiveCamera(spatialCameraSnapshot.fovDegrees, 1, 0.1, 1e5);
235058
+ const { fovDegrees, projectionScale } = spatialCameraSnapshot;
235059
+ const camera = new PerspectiveCamera(fovDegrees, 1, Math.max(projectionScale * 1e-4, 1e-3), Math.max(projectionScale * 100, 1e5));
235023
235060
  camera.updateProjectionMatrix();
235024
235061
  const eventTarget = canvas.parentElement ?? canvas;
235025
235062
  const controls = new OrbitControls(camera, eventTarget);
@@ -235174,8 +235211,8 @@ class AbstractSpatialOrScatterplot extends PureComponent {
235174
235211
  viewState: {
235175
235212
  viewMatrix: rawViewMatrix,
235176
235213
  fovy: fovDegrees,
235177
- near: 0.1,
235178
- far: 1e5
235214
+ near: Math.max(projectionScale * 1e-4, 1e-3),
235215
+ far: Math.max(projectionScale * 100, 1e5)
235179
235216
  }
235180
235217
  });
235181
235218
  } else if (use3d) {
@@ -240827,7 +240864,10 @@ const useStyles$s = makeStyles()(() => ({
240827
240864
  bottom: "0px",
240828
240865
  left: "0px",
240829
240866
  paddingLeft: "10px",
240830
- paddingBottom: "10px"
240867
+ paddingBottom: "10px",
240868
+ // Keep long channel names within the view so they can be truncated.
240869
+ maxWidth: "90%",
240870
+ boxSizing: "border-box"
240831
240871
  },
240832
240872
  channelNamesLegendLayer: {
240833
240873
  display: "flex"
@@ -240862,7 +240902,7 @@ function ChannelNamesLegend(props) {
240862
240902
  const channelNames = imageWrapperInstance?.getChannelNames();
240863
240903
  const channelIndex = imageWrapperInstance?.getChannelIndex(spatialTargetC);
240864
240904
  const channelName = channelIndex !== void 0 ? channelNames?.[channelIndex] : void 0;
240865
- return spatialLayerVisible && spatialChannelVisible && spatialChannelLabelsVisible ? jsx$1(Typography, { variant: "h6", className: classes2.channelNameText, style: {
240905
+ return spatialLayerVisible && spatialChannelVisible && spatialChannelLabelsVisible ? jsx$1(Typography, { variant: "h6", className: classes2.channelNameText, noWrap: true, title: channelName, style: {
240866
240906
  color: rgbColor,
240867
240907
  fontSize: `${spatialChannelLabelSize}px`
240868
240908
  }, children: channelName }, `${layerScope}-${cScope}-${channelIndex}-${rgbColor}`) : null;
@@ -240874,6 +240914,7 @@ const DEFAULT_FEATURE_AGGREGATION_STRATEGY$3 = "first";
240874
240914
  function EmbeddingScatterplotSubscriber(props) {
240875
240915
  const {
240876
240916
  uuid: uuid2,
240917
+ viewUid: viewUidFromProps,
240877
240918
  closeButtonVisible,
240878
240919
  downloadButtonVisible,
240879
240920
  removeGridComponent,
@@ -240890,18 +240931,19 @@ function EmbeddingScatterplotSubscriber(props) {
240890
240931
  // Passed down from the ancestor <Vitessce/> or <VitS/> component.
240891
240932
  areAnnotationsEditable
240892
240933
  } = props;
240934
+ const viewUid = viewUidFromProps ?? uuid2;
240893
240935
  const loaders = useLoaders();
240894
240936
  const [
240895
240937
  // eslint-disable-next-line no-unused-vars
240896
240938
  coordinationScopes,
240897
240939
  _coordinationScopesBy,
240898
240940
  coordinationValues
240899
- ] = useViewMapping(uuid2);
240941
+ ] = useViewMapping(viewUid);
240900
240942
  const setComponentHover = useSetComponentHover();
240901
240943
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
240902
- useAnnotationFrameCoordination(uuid2, coordinationScopes, coordinationValues);
240903
- const [{ dataset, obsType, featureType, featureValueType, sampleType, embeddingZoom: zoom2, embeddingTargetX: targetX2, embeddingTargetY: targetY2, embeddingTargetZ: targetZ, embeddingType: mapping, obsFilter: cellFilter, obsHighlight: cellHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, embeddingObsSetPolygonsVisible: cellSetPolygonsVisible, embeddingObsSetLabelsVisible: cellSetLabelsVisible, embeddingObsSetLabelSize: cellSetLabelSize, embeddingObsRadius: cellRadiusFixed, embeddingObsRadiusMode: cellRadiusMode, embeddingObsOpacity: cellOpacityFixed, embeddingObsOpacityMode: cellOpacityMode, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, sampleSetSelection: sampleSetSelectionFromCoordination, sampleSetColor, embeddingPointsVisible, embeddingContoursVisible, embeddingContoursFilled, embeddingContourPercentiles: contourPercentiles, contourColorEncoding, contourColor, featureAggregationStrategy, annotationStory, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationTransitionDuration, annotationEditable, annotationFrameIndex }, { setEmbeddingZoom: setZoom, setEmbeddingTargetX: setTargetX, setEmbeddingTargetY: setTargetY, setEmbeddingTargetZ: setTargetZ, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setEmbeddingObsSetPolygonsVisible: setCellSetPolygonsVisible, setEmbeddingObsSetLabelsVisible: setCellSetLabelsVisible, setEmbeddingObsSetLabelSize: setCellSetLabelSize, setEmbeddingObsRadius: setCellRadiusFixed, setEmbeddingObsRadiusMode: setCellRadiusMode, setEmbeddingObsOpacity: setCellOpacityFixed, setEmbeddingObsOpacityMode: setCellOpacityMode, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible, setEmbeddingPointsVisible, setEmbeddingContoursVisible, setEmbeddingContoursFilled, setEmbeddingContourPercentiles: setContourPercentiles, setContourColorEncoding, setFeatureAggregationStrategy, setAnnotationStory }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes, coordinationValues, uuid2);
240904
- const annotationEditingProps = useAnnotationEditingForView(uuid2, Boolean(areAnnotationsEditable && annotationEditable && typeof annotationFrameIndex === "number"));
240944
+ useAnnotationFrameCoordination(viewUid, coordinationScopes, coordinationValues);
240945
+ const [{ dataset, obsType, featureType, featureValueType, sampleType, embeddingZoom: zoom2, embeddingTargetX: targetX2, embeddingTargetY: targetY2, embeddingTargetZ: targetZ, embeddingType: mapping, obsFilter: cellFilter, obsHighlight: cellHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, embeddingObsSetPolygonsVisible: cellSetPolygonsVisible, embeddingObsSetLabelsVisible: cellSetLabelsVisible, embeddingObsSetLabelSize: cellSetLabelSize, embeddingObsRadius: cellRadiusFixed, embeddingObsRadiusMode: cellRadiusMode, embeddingObsOpacity: cellOpacityFixed, embeddingObsOpacityMode: cellOpacityMode, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, tooltipObsSetsMode, sampleSetSelection: sampleSetSelectionFromCoordination, sampleSetColor, embeddingPointsVisible, embeddingContoursVisible, embeddingContoursFilled, embeddingContourPercentiles: contourPercentiles, contourColorEncoding, contourColor, featureAggregationStrategy, annotationStory, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationTransitionDuration, annotationEditable, annotationFrameIndex }, { setEmbeddingZoom: setZoom, setEmbeddingTargetX: setTargetX, setEmbeddingTargetY: setTargetY, setEmbeddingTargetZ: setTargetZ, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setEmbeddingObsSetPolygonsVisible: setCellSetPolygonsVisible, setEmbeddingObsSetLabelsVisible: setCellSetLabelsVisible, setEmbeddingObsSetLabelSize: setCellSetLabelSize, setEmbeddingObsRadius: setCellRadiusFixed, setEmbeddingObsRadiusMode: setCellRadiusMode, setEmbeddingObsOpacity: setCellOpacityFixed, setEmbeddingObsOpacityMode: setCellOpacityMode, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible, setEmbeddingPointsVisible, setEmbeddingContoursVisible, setEmbeddingContoursFilled, setEmbeddingContourPercentiles: setContourPercentiles, setContourColorEncoding, setFeatureAggregationStrategy, setAnnotationStory }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes, coordinationValues, viewUid);
240946
+ const annotationEditingProps = useAnnotationEditingForView(viewUid, Boolean(areAnnotationsEditable && annotationEditable && typeof annotationFrameIndex === "number"));
240905
240947
  const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes, coordinationValues);
240906
240948
  const observationsLabel = observationsLabelOverride || obsType;
240907
240949
  const sampleSetSelection = sampleSetSelectionFromProps || sampleSetSelectionFromCoordination;
@@ -241077,7 +241119,7 @@ function EmbeddingScatterplotSubscriber(props) {
241077
241119
  initialTargetY,
241078
241120
  averageFillDensity
241079
241121
  ]);
241080
- const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership);
241122
+ const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership, cellSetSelection, tooltipObsSetsMode);
241081
241123
  const allCellsSelected = !(deferredCellSetSelection && mergedCellSets);
241082
241124
  const getCellIsSelected = useCallback((object2, { index: index2 }) => allCellsSelected || obsColorIndices.colorIndices[index2] !== 0 ? 1 : 0, [allCellsSelected, obsColorIndices]);
241083
241125
  const cellRadius = cellRadiusMode === "manual" ? cellRadiusFixed : dynamicCellRadius;
@@ -241187,7 +241229,7 @@ function EmbeddingScatterplotSubscriber(props) {
241187
241229
  featureAggregationStrategyToUse,
241188
241230
  obsSetsColumns
241189
241231
  ]);
241190
- const annotationFrameCoordinationValues = getAnnotationFrameCoordinationValues(annotationStory, annotationFrameIndex, uuid2);
241232
+ const annotationFrameCoordinationValues = getAnnotationFrameCoordinationValues(annotationStory, annotationFrameIndex, viewUid);
241191
241233
  const annotationTransitionProps = useAnnotationFrameTransition({ zoom: zoom2, targetX: targetX2, targetY: targetY2 }, {
241192
241234
  zoom: annotationFrameCoordinationValues?.[CoordinationType$1.EMBEDDING_ZOOM],
241193
241235
  targetX: annotationFrameCoordinationValues?.[CoordinationType$1.EMBEDDING_TARGET_X],
@@ -241283,7 +241325,7 @@ function DualEmbeddingScatterplotSubscriber(props) {
241283
241325
  const isCaseCtrl = Array.isArray(sampleSetSelection) && sampleSetSelection.length === 2;
241284
241326
  const caseSampleSetSelection = useMemo$1(() => sampleSetSelection?.[0] ? [sampleSetSelection[0]] : null, [sampleSetSelection]);
241285
241327
  const ctrlSampleSetSelection = useMemo$1(() => sampleSetSelection?.[1] ? [sampleSetSelection[1]] : null, [sampleSetSelection]);
241286
- return jsxs("div", { style: { width: "100%", height: "100%", display: "flex", flexDirection: "row" }, children: [jsx$1("div", { style: { width: isCaseCtrl ? "50%" : "100%", display: "flex", flexDirection: "column" }, children: jsx$1(EmbeddingScatterplotSubscriber, { ...props, uuid: `${uuid2}-case`, title: isCaseCtrl ? `Scatterplot (${embeddingType}), ${caseSampleSetSelection?.[0]?.at(-1)}` : null, sampleSetSelection: caseSampleSetSelection }) }), isCaseCtrl ? jsx$1("div", { style: { width: "50%", display: "flex", flexDirection: "column" }, children: jsx$1(EmbeddingScatterplotSubscriber, { ...props, uuid: `${uuid2}-ctrl`, title: `Scatterplot (${embeddingType}), ${ctrlSampleSetSelection?.[0]?.at(-1)}`, sampleSetSelection: ctrlSampleSetSelection }) }) : null] });
241328
+ return jsxs("div", { style: { width: "100%", height: "100%", display: "flex", flexDirection: "row" }, children: [jsx$1("div", { style: { width: isCaseCtrl ? "50%" : "100%", display: "flex", flexDirection: "column" }, children: jsx$1(EmbeddingScatterplotSubscriber, { ...props, uuid: `${uuid2}-case`, viewUid: uuid2, title: isCaseCtrl ? `Scatterplot (${embeddingType}), ${caseSampleSetSelection?.[0]?.at(-1)}` : null, sampleSetSelection: caseSampleSetSelection }) }), isCaseCtrl ? jsx$1("div", { style: { width: "50%", display: "flex", flexDirection: "column" }, children: jsx$1(EmbeddingScatterplotSubscriber, { ...props, uuid: `${uuid2}-ctrl`, viewUid: uuid2, title: `Scatterplot (${embeddingType}), ${ctrlSampleSetSelection?.[0]?.at(-1)}`, sampleSetSelection: ctrlSampleSetSelection }) }) : null] });
241287
241329
  }
241288
241330
  function GatingScatterplotOptions(props) {
241289
241331
  const { featureType, gatingFeatureSelectionX, setGatingFeatureSelectionX, gatingFeatureSelectionY, setGatingFeatureSelectionY, gatingFeatureValueTransform, setGatingFeatureValueTransform, gatingFeatureValueTransformCoefficient, setGatingFeatureValueTransformCoefficient, geneSelectOptions, transformOptions } = props;
@@ -261535,7 +261577,7 @@ function SpatialSubscriber$1(props) {
261535
261577
  const setComponentHover = useSetComponentHover();
261536
261578
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
261537
261579
  useAnnotationFrameCoordination(uuid2, coordinationScopes);
261538
- const [{ dataset, obsType, featureType, featureValueType, spatialZoom: zoom2, spatialTargetX: targetX2, spatialTargetY: targetY2, spatialTargetZ: targetZ, spatialRotationX: rotationX, spatialRotationY: rotationY, spatialRotationZ: rotationZ, spatialRotationOrbit: rotationOrbit, spatialOrbitAxis: orbitAxis, spatialImageLayer: imageLayers, spatialSegmentationLayer: cellsLayer, spatialPointLayer: moleculesLayer, spatialNeighborhoodLayer: neighborhoodsLayer, obsFilter: cellFilter, obsHighlight: cellHighlight, moleculeHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, spatialAxisFixed, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, photometricInterpretation: photometricInterpretationFromCoordination, featureAggregationStrategy, annotationStory, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationTransitionDuration, annotationEditable, annotationFrameIndex }, { setSpatialZoom: setZoom, setSpatialTargetX: setTargetX, setSpatialTargetY: setTargetY, setSpatialTargetZ: setTargetZ, setSpatialRotationX: setRotationX, setSpatialRotationOrbit: setRotationOrbit, setSpatialOrbitAxis: setOrbitAxis, setSpatialImageLayer: setRasterLayers, setSpatialSegmentationLayer: setCellsLayer, setSpatialPointLayer: setMoleculesLayer, setSpatialNeighborhoodLayer: setNeighborhoodsLayer, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setMoleculeHighlight, setSpatialAxisFixed, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible, setFeatureAggregationStrategy, setAnnotationStory }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
261580
+ const [{ dataset, obsType, featureType, featureValueType, spatialZoom: zoom2, spatialTargetX: targetX2, spatialTargetY: targetY2, spatialTargetZ: targetZ, spatialRotationX: rotationX, spatialRotationY: rotationY, spatialRotationZ: rotationZ, spatialRotationOrbit: rotationOrbit, spatialOrbitAxis: orbitAxis, spatialImageLayer: imageLayers, spatialSegmentationLayer: cellsLayer, spatialPointLayer: moleculesLayer, spatialNeighborhoodLayer: neighborhoodsLayer, obsFilter: cellFilter, obsHighlight: cellHighlight, moleculeHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, spatialAxisFixed, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, tooltipObsSetsMode, photometricInterpretation: photometricInterpretationFromCoordination, featureAggregationStrategy, annotationStory, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationTransitionDuration, annotationEditable, annotationFrameIndex }, { setSpatialZoom: setZoom, setSpatialTargetX: setTargetX, setSpatialTargetY: setTargetY, setSpatialTargetZ: setTargetZ, setSpatialRotationX: setRotationX, setSpatialRotationOrbit: setRotationOrbit, setSpatialOrbitAxis: setOrbitAxis, setSpatialImageLayer: setRasterLayers, setSpatialSegmentationLayer: setCellsLayer, setSpatialPointLayer: setMoleculesLayer, setSpatialNeighborhoodLayer: setNeighborhoodsLayer, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setMoleculeHighlight, setSpatialAxisFixed, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible, setFeatureAggregationStrategy, setAnnotationStory }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
261539
261581
  const annotationEditingProps = useAnnotationEditingForView(uuid2, Boolean(areAnnotationsEditable && annotationEditable && typeof annotationFrameIndex === "number"));
261540
261582
  const { spatialZoom: initialZoom, spatialTargetX: initialTargetX, spatialTargetY: initialTargetY, spatialTargetZ: initialTargetZ } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
261541
261583
  const observationsLabel = observationsLabelOverride || obsType;
@@ -261704,7 +261746,7 @@ function SpatialSubscriber$1(props) {
261704
261746
  matrixObsIndex
261705
261747
  ]);
261706
261748
  const cellSelection = useMemo$1(() => Array.from(cellColors.keys()), [cellColors]);
261707
- const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership);
261749
+ const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership, cellSetSelection, tooltipObsSetsMode);
261708
261750
  const getTooltipObsInfo = useCallback((tooltipObsId, tooltipObsType) => {
261709
261751
  if (tooltipObsType === HOVER_MODE.MOLECULE_LAYER) {
261710
261752
  return {
@@ -262689,8 +262731,9 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
262689
262731
  const layerDefModelMatrix = image2?.obsSegmentations?.instance?.getModelMatrix();
262690
262732
  let selections;
262691
262733
  const hasChannelDimension = image2?.obsSegmentations?.instance?.hasDimC();
262734
+ const zIndex2 = image2?.obsSegmentations?.instance?.getClampedZIndex(targetZ) ?? 0;
262692
262735
  const nextLoaderSelection = channelScopes.map((cScope) => filterSelection(data2, {
262693
- z: targetZ,
262736
+ z: zIndex2,
262694
262737
  t: targetT,
262695
262738
  c: hasChannelDimension ? image2?.obsSegmentations?.instance?.getChannelIndex(channelCoordination[cScope][CoordinationType$1.SPATIAL_TARGET_C]) : void 0
262696
262739
  }));
@@ -262793,13 +262836,14 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
262793
262836
  const yMirror = new Matrix4$1().translate([0, yExtent, 0]).scale([1, -1, 1]);
262794
262837
  layerDefModelMatrix = new Matrix4$1(rawModelMatrix).multiplyRight(yMirror);
262795
262838
  }
262839
+ const zIndex2 = image2?.image?.instance?.getClampedZIndex(targetZ) ?? 0;
262796
262840
  let selections;
262797
262841
  const nextLoaderSelection = isRgb2 ? [0, 1, 2].map((targetC) => filterSelection(data2, {
262798
- z: targetZ,
262842
+ z: zIndex2,
262799
262843
  t: targetT,
262800
262844
  c: targetC
262801
262845
  })) : channelScopes.map((cScope) => filterSelection(data2, {
262802
- z: targetZ,
262846
+ z: zIndex2,
262803
262847
  t: targetT,
262804
262848
  c: image2?.image?.instance?.getChannelIndex(channelCoordination[cScope][CoordinationType$1.SPATIAL_TARGET_C])
262805
262849
  }));
@@ -263543,7 +263587,7 @@ function getXY(obsHighlight, viewInfo, obsIndex, obsLocations, useHoverInfoForTo
263543
263587
  const projectedObsCoord = viewInfo?.project(obsCoord);
263544
263588
  return [projectedObsCoord?.[0], projectedObsCoord?.[1]];
263545
263589
  }
263546
- function getObsInfo(obsSetsData, obsType, obsId) {
263590
+ function getObsInfo(obsSetsData, obsType, obsId, obsSetSelection, tooltipObsSetsMode) {
263547
263591
  let result = {
263548
263592
  [`${capitalize$3(obsType)} ID`]: obsId
263549
263593
  };
@@ -263552,7 +263596,7 @@ function getObsInfo(obsSetsData, obsType, obsId) {
263552
263596
  if (obsMembership) {
263553
263597
  result = {
263554
263598
  ...result,
263555
- ...Object.fromEntries(obsMembership.flatMap((path2) => path2.slice(1).map((pathEl, elLevel) => [
263599
+ ...Object.fromEntries(filterObsMembershipForTooltip(obsMembership, obsSetSelection, tooltipObsSetsMode).flatMap((path2) => path2.slice(1).map((pathEl, elLevel) => [
263556
263600
  `${path2[0]}${path2.length > 2 ? ` L${elLevel + 1}` : ""}`,
263557
263601
  pathEl
263558
263602
  ])))
@@ -263598,9 +263642,9 @@ function SpatialTooltipSubscriber(props) {
263598
263642
  "Pixel Value": JSON.stringify(pixelHighlight)
263599
263643
  }, x: projectedHoverCoord?.[0], y: projectedHoverCoord?.[1] + (yOffset += 30), featureType, featureLabelsMap }, layerScope) : null;
263600
263644
  }), segmentationLayerScopes?.flatMap((layerScope) => segmentationChannelScopesByLayer?.[layerScope]?.map((channelScope) => {
263601
- const { obsType, obsHighlight, tooltipsVisible, tooltipCrosshairsVisible, spatialChannelVisible } = segmentationChannelCoordination?.[0]?.[layerScope]?.[channelScope] || {};
263645
+ const { obsType, obsHighlight, tooltipsVisible, tooltipCrosshairsVisible, spatialChannelVisible, obsSetSelection, tooltipObsSetsMode } = segmentationChannelCoordination?.[0]?.[layerScope]?.[channelScope] || {};
263602
263646
  const obsSetsData = obsSegmentationsSetsData?.[layerScope]?.[channelScope];
263603
- const obsInfo = getObsInfo(obsSetsData, obsType, obsHighlight);
263647
+ const obsInfo = getObsInfo(obsSetsData, obsType, obsHighlight, obsSetSelection, tooltipObsSetsMode);
263604
263648
  if (!obsHighlight || !spatialChannelVisible || !tooltipsVisible && !tooltipCrosshairsVisible)
263605
263649
  return null;
263606
263650
  const { obsIndex, obsLocations } = obsSegmentationsLocations?.[layerScope]?.[channelScope] || {};
@@ -263657,12 +263701,12 @@ class ErrorBoundary extends React__default.Component {
263657
263701
  }
263658
263702
  }
263659
263703
  const LazySpatialThree = React__default.lazy(async () => {
263660
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-6RcG881_.js").then((n3) => n3.a);
263704
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-DSTEevd1.js").then((n3) => n3.a);
263661
263705
  return { default: SpatialWrapper2 };
263662
263706
  });
263663
263707
  const SpatialThreeAdapter = React__default.forwardRef((props, ref2) => jsx$1("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsx$1(ErrorBoundary, { fallback: jsx$1("div", { children: "3D spatial view is not available in this environment." }), children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: jsx$1(LazySpatialThree, { ...props }) }) }) }));
263664
263708
  const LazySpatialAccelerated = React__default.lazy(async () => {
263665
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-7fuq_N65.js");
263709
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-40m4CUms.js");
263666
263710
  return { default: SpatialWrapper2 };
263667
263711
  });
263668
263712
  const SpatialAcceleratedAdapter = React__default.forwardRef((props, ref2) => jsx$1("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsx$1(ErrorBoundary, { fallback: jsx$1("div", { children: "3D spatial view is not available in this environment." }), children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: jsx$1(LazySpatialAccelerated, { ...props }) }) }) }));
@@ -263919,7 +263963,7 @@ function SpatialSubscriber(props) {
263919
263963
  }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL_BETA], coordinationScopes);
263920
263964
  const annotationEditingProps = useAnnotationEditingForView(uuid2, Boolean(areAnnotationsEditable && annotationEditable && typeof annotationFrameIndex === "number"));
263921
263965
  const { spatialZoom: initialZoom, spatialTargetX: initialTargetX, spatialTargetY: initialTargetY, spatialTargetZ: initialTargetZ } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL_BETA], coordinationScopes);
263922
- const hasSpatialCameraSnapshot = Boolean(spatialCameraSnapshot);
263966
+ const hasSpatialCameraSnapshot = Boolean(spatialCameraSnapshot) && spatialRenderingMode === "3D";
263923
263967
  const [segmentationLayerScopes, segmentationChannelScopesByLayer] = useMultiCoordinationScopesSecondaryNonNull(CoordinationType$1.SEGMENTATION_CHANNEL, CoordinationType$1.SEGMENTATION_LAYER, coordinationScopes, coordinationScopesBy);
263924
263968
  const [imageLayerScopes, imageChannelScopesByLayer] = useMultiCoordinationScopesSecondaryNonNull(CoordinationType$1.IMAGE_CHANNEL, CoordinationType$1.IMAGE_LAYER, coordinationScopes, coordinationScopesBy);
263925
263969
  const spotLayerScopes = useMultiCoordinationScopesNonNull(CoordinationType$1.SPOT_LAYER, coordinationScopes);
@@ -263949,6 +263993,7 @@ function SpatialSubscriber(props) {
263949
263993
  CoordinationType$1.OBS_HIGHLIGHT,
263950
263994
  CoordinationType$1.TOOLTIPS_VISIBLE,
263951
263995
  CoordinationType$1.TOOLTIP_CROSSHAIRS_VISIBLE,
263996
+ CoordinationType$1.TOOLTIP_OBS_SETS_MODE,
263952
263997
  CoordinationType$1.LEGEND_VISIBLE
263953
263998
  ], coordinationScopes, coordinationScopesBy, CoordinationType$1.SEGMENTATION_LAYER, CoordinationType$1.SEGMENTATION_CHANNEL);
263954
263999
  const imageLayerCoordination = useComplexCoordination([
@@ -264146,6 +264191,28 @@ function SpatialSubscriber(props) {
264146
264191
  segmentationChannelScopesByLayer
264147
264192
  ]
264148
264193
  );
264194
+ const sceneMetersPerUnit = useMemo$1(() => {
264195
+ const firstLayer = Object.values(imageData ?? {})[0];
264196
+ return firstLayer?.image?.instance?.getSceneMetersPerUnit() ?? null;
264197
+ }, [imageData]);
264198
+ const sceneCameraSnapshot = useMemo$1(() => {
264199
+ if (!spatialCameraSnapshot)
264200
+ return null;
264201
+ const inMpu = spatialCameraSnapshot.metersPerUnit;
264202
+ if (!sceneMetersPerUnit || !inMpu || inMpu === sceneMetersPerUnit) {
264203
+ return spatialCameraSnapshot;
264204
+ }
264205
+ const k = inMpu / sceneMetersPerUnit;
264206
+ return {
264207
+ ...spatialCameraSnapshot,
264208
+ position: spatialCameraSnapshot.position.map((p) => p * k),
264209
+ projectionScale: spatialCameraSnapshot.projectionScale * k,
264210
+ metersPerUnit: sceneMetersPerUnit
264211
+ };
264212
+ }, [spatialCameraSnapshot, sceneMetersPerUnit]);
264213
+ const setSceneCameraSnapshot = useCallback((snapshot) => {
264214
+ setSpatialCameraSnapshot({ ...snapshot, metersPerUnit: sceneMetersPerUnit });
264215
+ }, [setSpatialCameraSnapshot, sceneMetersPerUnit]);
264149
264216
  useEffect(() => {
264150
264217
  if (width2 && height2) {
264151
264218
  if (typeof initialTargetX !== "number" || typeof initialTargetY !== "number") {
@@ -264180,6 +264247,10 @@ function SpatialSubscriber(props) {
264180
264247
  if (prevIs3dMode.current === is3dMode) {
264181
264248
  return;
264182
264249
  }
264250
+ if (hasSpatialCameraSnapshot) {
264251
+ prevIs3dMode.current = is3dMode;
264252
+ return;
264253
+ }
264183
264254
  if (typeof defaultTargetX !== "number" || typeof defaultTargetY !== "number") {
264184
264255
  return;
264185
264256
  }
@@ -264190,7 +264261,14 @@ function SpatialSubscriber(props) {
264190
264261
  setZoom(defaultZoom);
264191
264262
  setRotationX(is3dMode ? 0 : null);
264192
264263
  setRotationOrbit(is3dMode ? 0 : null);
264193
- }, [is3dMode, defaultTargetX, defaultTargetY, defaultTargetZ, defaultZoom]);
264264
+ }, [
264265
+ is3dMode,
264266
+ hasSpatialCameraSnapshot,
264267
+ defaultTargetX,
264268
+ defaultTargetY,
264269
+ defaultTargetZ,
264270
+ defaultZoom
264271
+ ]);
264194
264272
  const annotationFrameCoordinationValues = getAnnotationFrameCoordinationValues(annotationStory, annotationFrameIndex, uuid2);
264195
264273
  const annotationTransitionProps = useAnnotationFrameTransition(
264196
264274
  { zoom: zoom2, targetX: targetX2, targetY: targetY2 },
@@ -264371,7 +264449,7 @@ function SpatialSubscriber(props) {
264371
264449
  rotationX,
264372
264450
  rotationOrbit,
264373
264451
  ...annotationTransitionProps
264374
- } : DEFAULT_VIEW_STATE, orbitAxis, spatialAxisFixed, setViewState: isValidViewState ? setViewState : SET_VIEW_STATE_NOOP, originalViewState, spatialRenderingMode, updateViewInfo: setComponentViewInfo, delegateHover, obsPoints: obsPointsData, pointLayerScopes, pointLayerCoordination, pointMultiObsLabels: pointMultiObsLabelsData, pointMatrixIndices: pointMultiIndicesData, obsSpots: obsSpotsData, spotLayerScopes, spotLayerCoordination, obsSpotsSets: obsSpotsSetsData, spotMatrixIndices: spotMultiIndicesData, spotMultiExpressionData: spotMultiExpressionNormDataAggregated || spotMultiExpressionNormData, segmentationLayerScopes, segmentationLayerCoordination, segmentationChannelScopesByLayer, segmentationChannelCoordination, obsSegmentations: obsSegmentationsData, obsSegmentationsLocations: obsSegmentationsLocationsData, obsSegmentationsSets: obsSegmentationsSetsData, segmentationMatrixIndices: segmentationMultiIndicesData, segmentationMultiExpressionData: segmentationMultiExpressionNormDataAggregated || segmentationMultiExpressionNormData, bitmaskValueIsIndex, images: imageData, imageLayerScopes, imageLayerCoordination, imageChannelScopesByLayer, imageChannelCoordination, setTiledPointsLoadingProgress, spatialCameraSnapshot: hasSpatialCameraSnapshot ? spatialCameraSnapshot : null, setSpatialCameraSnapshot: hasSpatialCameraSnapshot ? setSpatialCameraSnapshot : null, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, hideRecenter: hasSpatialCameraSnapshot, ...annotationEditingProps }), !disableTooltip && jsx$1(SpatialTooltipSubscriber, {
264452
+ } : DEFAULT_VIEW_STATE, orbitAxis, spatialAxisFixed, setViewState: isValidViewState ? setViewState : SET_VIEW_STATE_NOOP, originalViewState, spatialRenderingMode, updateViewInfo: setComponentViewInfo, delegateHover, obsPoints: obsPointsData, pointLayerScopes, pointLayerCoordination, pointMultiObsLabels: pointMultiObsLabelsData, pointMatrixIndices: pointMultiIndicesData, obsSpots: obsSpotsData, spotLayerScopes, spotLayerCoordination, obsSpotsSets: obsSpotsSetsData, spotMatrixIndices: spotMultiIndicesData, spotMultiExpressionData: spotMultiExpressionNormDataAggregated || spotMultiExpressionNormData, segmentationLayerScopes, segmentationLayerCoordination, segmentationChannelScopesByLayer, segmentationChannelCoordination, obsSegmentations: obsSegmentationsData, obsSegmentationsLocations: obsSegmentationsLocationsData, obsSegmentationsSets: obsSegmentationsSetsData, segmentationMatrixIndices: segmentationMultiIndicesData, segmentationMultiExpressionData: segmentationMultiExpressionNormDataAggregated || segmentationMultiExpressionNormData, bitmaskValueIsIndex, images: imageData, imageLayerScopes, imageLayerCoordination, imageChannelScopesByLayer, imageChannelCoordination, setTiledPointsLoadingProgress, spatialCameraSnapshot: hasSpatialCameraSnapshot ? sceneCameraSnapshot : null, setSpatialCameraSnapshot: hasSpatialCameraSnapshot ? setSceneCameraSnapshot : null, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, hideRecenter: hasSpatialCameraSnapshot, ...annotationEditingProps }), !disableTooltip && jsx$1(SpatialTooltipSubscriber, {
264375
264453
  parentUuid: uuid2,
264376
264454
  width: width2,
264377
264455
  height: height2,
@@ -265268,7 +265346,7 @@ function HeatmapSubscriber(props) {
265268
265346
  const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
265269
265347
  const setComponentHover = useSetComponentHover();
265270
265348
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
265271
- const [{ dataset, obsType, featureType, featureValueType, heatmapZoomX: zoomX, heatmapTargetX: targetX2, heatmapTargetY: targetY2, featureSelection: geneSelection, obsHighlight: cellHighlight, featureHighlight: geneHighlight, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, additionalObsSets: additionalCellSets, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible }, { setHeatmapZoomX: setZoomX, setHeatmapZoomY: setZoomY, setHeatmapTargetX: setTargetX, setHeatmapTargetY: setTargetY, setObsHighlight: setCellHighlight, setFeatureSelection: setGeneSelection, setObsColorEncoding: setCellColorEncoding, setFeatureHighlight: setGeneHighlight, setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor, setFeatureValueColormapRange: setGeneExpressionColormapRange, setFeatureValueColormap: setGeneExpressionColormap, setTooltipsVisible }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.HEATMAP], coordinationScopes);
265349
+ const [{ dataset, obsType, featureType, featureValueType, heatmapZoomX: zoomX, heatmapTargetX: targetX2, heatmapTargetY: targetY2, featureSelection: geneSelection, obsHighlight: cellHighlight, featureHighlight: geneHighlight, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, additionalObsSets: additionalCellSets, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, tooltipObsSetsMode }, { setHeatmapZoomX: setZoomX, setHeatmapZoomY: setZoomY, setHeatmapTargetX: setTargetX, setHeatmapTargetY: setTargetY, setObsHighlight: setCellHighlight, setFeatureSelection: setGeneSelection, setObsColorEncoding: setCellColorEncoding, setFeatureHighlight: setGeneHighlight, setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor, setFeatureValueColormapRange: setGeneExpressionColormapRange, setFeatureValueColormap: setGeneExpressionColormap, setTooltipsVisible }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.HEATMAP], coordinationScopes);
265272
265350
  const observationsLabel = observationsLabelOverride || obsType;
265273
265351
  const observationsPluralLabel = pluralize(observationsLabel);
265274
265352
  const variablesLabel = variablesLabelOverride || featureType;
@@ -265322,7 +265400,7 @@ function HeatmapSubscriber(props) {
265322
265400
  cellSetSelection,
265323
265401
  obsIndex
265324
265402
  ]);
265325
- const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership);
265403
+ const getObsInfo2 = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership, cellSetSelection, tooltipObsSetsMode);
265326
265404
  const getObsMembership = useGetObsMembership(obsSetsMembership);
265327
265405
  const getFeatureInfo = useCallback((featureId2) => {
265328
265406
  if (featureId2) {
@@ -276499,7 +276577,7 @@ function ImageChannelController(props) {
276499
276577
  const selection = {
276500
276578
  t: ctx.queryKey[2],
276501
276579
  c: ctx.queryKey[3],
276502
- z: Math.floor(ctx.queryKey[4])
276580
+ z: ctx.meta.image?.getClampedZIndex(ctx.queryKey[4]) ?? 0
276503
276581
  };
276504
276582
  const stats = await getMultiSelectionStats({
276505
276583
  loader: loader2,
@@ -280403,7 +280481,7 @@ function HiglassGlobalStyles(props) {
280403
280481
  }
280404
280482
  register({ dataFetcher: ZarrMultivecDataFetcher_default, config: ZarrMultivecDataFetcher_default.config }, { pluginType: "dataFetcher" });
280405
280483
  const LazyHiGlassComponent = React__default.lazy(async () => {
280406
- const { HiGlassComponent } = await import("./higlass-BUwbsbhR.js");
280484
+ const { HiGlassComponent } = await import("./higlass-Br3Jz09a.js");
280407
280485
  return { default: HiGlassComponent };
280408
280486
  });
280409
280487
  const HG_SIZE = 800;
@@ -283358,7 +283436,7 @@ function NeuroglancerGlobalStyles(props) {
283358
283436
  const { classes: classes2 } = props;
283359
283437
  return jsxs(Fragment, { children: [jsx$1(GlobalStyles$3, { styles: globalNeuroglancerCss }), jsx$1(ScopedGlobalStyles, { styles: globalNeuroglancerStyles, parentClassName: classes2.neuroglancerWrapper })] });
283360
283438
  }
283361
- const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-CnmjswBO.js"));
283439
+ const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-BrGzTsrg.js"));
283362
283440
  function createWorker() {
283363
283441
  const worker = new WorkerFactory$1();
283364
283442
  worker.AsyncComputationWorker = WorkerFactory;
@@ -283456,9 +283534,9 @@ class NeuroglancerComp extends PureComponent {
283456
283534
  this.bundleRoot = null;
283457
283535
  }
283458
283536
  render() {
283459
- const { classes: classes2, viewerState, cellColorMapping, onLayerLoadingChange, onAnnotationSourceReady, onViewerReady, meshOpacity } = this.props;
283537
+ const { classes: classes2, viewerState, cellColorMapping, onLayerLoadingChange, onAnnotationSourceReady, onViewerReady, meshOpacity, allowEmptySegments } = this.props;
283460
283538
  const { bundleRootReady } = this.state;
283461
- return jsxs(Fragment, { children: [jsx$1(NeuroglancerGlobalStyles, { classes: classes2 }), jsx$1("div", { className: classes2.neuroglancerWrapper, children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: bundleRootReady && jsx$1(LazyReactNeuroglancer, { brainMapsClientId: "NOT_A_VALID_ID", viewerState, onViewerStateChanged: this.onViewerStateChanged, onLayerLoadingChange, bundleRoot: this.bundleRoot, cellColorMapping, ref: this.onRef, onAnnotationSourceReady, onViewerReady, meshOpacity }) }) })] });
283539
+ return jsxs(Fragment, { children: [jsx$1(NeuroglancerGlobalStyles, { classes: classes2 }), jsx$1("div", { className: classes2.neuroglancerWrapper, children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: bundleRootReady && jsx$1(LazyReactNeuroglancer, { brainMapsClientId: "NOT_A_VALID_ID", viewerState, onViewerStateChanged: this.onViewerStateChanged, onLayerLoadingChange, bundleRoot: this.bundleRoot, cellColorMapping, ref: this.onRef, onAnnotationSourceReady, onViewerReady, meshOpacity, allowEmptySegments }) }) })] });
283462
283540
  }
283463
283541
  }
283464
283542
  function customIsEqualForCellColors(prevDeps, nextDeps) {
@@ -284234,6 +284312,13 @@ function useNeuroglancerViewerState(theme, showAxisLines, segmentationLayerScope
284234
284312
  return viewerState;
284235
284313
  }
284236
284314
  const ANNOTATION_HEADER_OFFSET = 8;
284315
+ function ngMetersPerUnit(dimensions) {
284316
+ if (!dimensions?.x)
284317
+ return null;
284318
+ const [scale2, unit2] = dimensions.x;
284319
+ const factor = UNIT_TO_METERS[unit2];
284320
+ return factor ? scale2 * factor : null;
284321
+ }
284237
284322
  const GREY_HEX = "#323232";
284238
284323
  const EPSILON_KEYS_MAPPING_NG = {
284239
284324
  projectionScale: 5,
@@ -284389,7 +284474,14 @@ function NeuroglancerSubscriber(props) {
284389
284474
  // the existing spatialZoom, spatialTargetX, spatialRotationOrbit, etc,
284390
284475
  // and then NeuroglancerSubscriber should internally convert
284391
284476
  // to NG-compatible values, which would eliminate the need for this.
284392
- initialNgCameraState
284477
+ initialNgCameraState,
284478
+ // Detail mode: render only the meshes selected (obsSets) or hovered
284479
+ // (obsHighlight) elsewhere, with an independent camera.
284480
+ detailMode = false,
284481
+ detailUseSelection = false,
284482
+ // >1: this view shows the shared camera N× more zoomed in.
284483
+ // Pan/rotation are shared via spatialCameraSnapshot; zoom keeps a fixed ratio.
284484
+ cameraZoomFactor = 1
284393
284485
  } = props;
284394
284486
  const loaders = useLoaders();
284395
284487
  const mergeCoordination = useMergeCoordination();
@@ -284432,7 +284524,8 @@ function NeuroglancerSubscriber(props) {
284432
284524
  obsSetSelection: cellSetSelection,
284433
284525
  additionalObsSets: additionalCellSets,
284434
284526
  obsHighlight: cellHighlight,
284435
- spatialCameraSnapshot
284527
+ spatialCameraSnapshot,
284528
+ spatialRenderingMode
284436
284529
  }, { setSpatialCameraSnapshot, setAdditionalObsSets: setAdditionalCellSets, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.NEUROGLANCER], coordinationScopes);
284437
284530
  const csvUrlRef = useRef(null);
284438
284531
  const csvUrl = useMemo$1(() => {
@@ -284589,15 +284682,27 @@ function NeuroglancerSubscriber(props) {
284589
284682
  });
284590
284683
  const lastSeenCameraSnapshotRef = useRef(null);
284591
284684
  const spatialBetaJustPushedRef = useRef(false);
284685
+ const is3dMode = spatialRenderingMode === "3D";
284686
+ const hasSpatialCameraSnapshot = Boolean(spatialCameraSnapshot) && is3dMode;
284592
284687
  useEffect(() => {
284593
- if (!spatialCameraSnapshot)
284688
+ if (detailMode)
284689
+ return;
284690
+ if (!hasSpatialCameraSnapshot)
284594
284691
  return;
284595
284692
  if (spatialCameraSnapshot === lastSeenCameraSnapshotRef.current)
284596
284693
  return;
284597
284694
  lastSeenCameraSnapshotRef.current = spatialCameraSnapshot;
284598
- const { position: position2, quaternion: quaternion2, projectionScale } = spatialCameraSnapshot;
284695
+ const { quaternion: quaternion2 } = spatialCameraSnapshot;
284696
+ let { position: position2, projectionScale } = spatialCameraSnapshot;
284599
284697
  if (!Array.isArray(position2) || !Array.isArray(quaternion2))
284600
284698
  return;
284699
+ const ownMpu = ngMetersPerUnit(latestViewerStateRef.current?.dimensions);
284700
+ const inMpu = spatialCameraSnapshot.metersPerUnit;
284701
+ if (ownMpu && inMpu && ownMpu !== inMpu) {
284702
+ const k = inMpu / ownMpu;
284703
+ position2 = position2.map((p) => p * k);
284704
+ projectionScale *= k;
284705
+ }
284601
284706
  const unflipped = multiplyQuat(quaternion2, Q_Y_UP);
284602
284707
  lastInteractionSource.current = LAST_INTERACTION_SOURCE.vitessce;
284603
284708
  spatialBetaJustPushedRef.current = true;
@@ -284605,10 +284710,10 @@ function NeuroglancerSubscriber(props) {
284605
284710
  ...latestViewerStateRef.current,
284606
284711
  position: position2,
284607
284712
  projectionOrientation: unflipped,
284608
- projectionScale
284713
+ projectionScale: Number.isFinite(projectionScale) ? projectionScale / cameraZoomFactor : latestViewerStateRef.current.projectionScale
284609
284714
  };
284610
284715
  incrementLatestViewerStateIteration();
284611
- }, [spatialCameraSnapshot]);
284716
+ }, [spatialCameraSnapshot, hasSpatialCameraSnapshot, detailMode, cameraZoomFactor]);
284612
284717
  const segmentationColorMapping = useMemoCustomComparison(() => {
284613
284718
  const result = {};
284614
284719
  segmentationLayerScopes?.forEach((layerScope) => {
@@ -284805,6 +284910,8 @@ function NeuroglancerSubscriber(props) {
284805
284910
  }
284806
284911
  }, []);
284807
284912
  const updateVisibleSegments = useCallback(async () => {
284913
+ if (detailMode)
284914
+ return;
284808
284915
  if (!annotationInfoRef.current)
284809
284916
  return;
284810
284917
  if (!annotationTransformRef.current)
@@ -284927,7 +285034,7 @@ function NeuroglancerSubscriber(props) {
284927
285034
  console.warn("[updateVisibleSegments] error:", e3);
284928
285035
  setIsMeshLoading(false);
284929
285036
  }
284930
- }, [segmentationLayerScopes, pointLayerScopes, meshLoadProjectionScaleThreshold]);
285037
+ }, [segmentationLayerScopes, pointLayerScopes, meshLoadProjectionScaleThreshold, detailMode]);
284931
285038
  useEffect(() => {
284932
285039
  updateVisibleSegmentsThrottledRef.current = throttle$1(updateVisibleSegments, 500);
284933
285040
  return () => updateVisibleSegmentsThrottledRef.current?.cancel();
@@ -284945,7 +285052,7 @@ function NeuroglancerSubscriber(props) {
284945
285052
  incrementLatestViewerStateIteration();
284946
285053
  }, [initialViewerState]);
284947
285054
  const hasMatchingAnnotationSource = useMemo$1(() => {
284948
- if (!cellsUrl)
285055
+ if (detailMode || !cellsUrl)
284949
285056
  return false;
284950
285057
  const firstPointScope = pointLayerScopes?.[0];
284951
285058
  return pointsHaveMatchingSegmentation({
@@ -284954,7 +285061,7 @@ function NeuroglancerSubscriber(props) {
284954
285061
  segmentationChannelScopesByLayer,
284955
285062
  segmentationChannelCoordination
284956
285063
  });
284957
- }, [cellsUrl, pointLayerScopes, segmentationLayerScopes, segmentationChannelScopesByLayer]);
285064
+ }, [cellsUrl, pointLayerScopes, segmentationLayerScopes, segmentationChannelScopesByLayer, detailMode]);
284958
285065
  useEffect(() => {
284959
285066
  if (!cellsUrl || !annotationInfo)
284960
285067
  return;
@@ -284979,13 +285086,14 @@ function NeuroglancerSubscriber(props) {
284979
285086
  const handleStateUpdate = useCallback((newState) => {
284980
285087
  lastInteractionSource.current = LAST_INTERACTION_SOURCE.neuroglancer;
284981
285088
  const { projectionScale, projectionOrientation, position: position2 } = newState;
284982
- if (Array.isArray(position2) && Array.isArray(projectionOrientation)) {
285089
+ if (!detailMode && Array.isArray(position2) && Array.isArray(projectionOrientation)) {
284983
285090
  const flippedQuaternion = multiplyQuat(projectionOrientation, Q_Y_UP);
284984
285091
  const snapshot = {
284985
285092
  position: Array.from(position2),
284986
285093
  quaternion: Array.from(flippedQuaternion),
284987
- projectionScale,
284988
- fovDegrees: 45
285094
+ projectionScale: Number.isFinite(projectionScale) ? projectionScale * cameraZoomFactor : latestViewerStateRef.current?.projectionScale,
285095
+ fovDegrees: 45,
285096
+ metersPerUnit: ngMetersPerUnit(latestViewerStateRef.current?.dimensions)
284989
285097
  };
284990
285098
  lastSeenCameraSnapshotRef.current = snapshot;
284991
285099
  setSpatialCameraSnapshot(snapshot);
@@ -284996,8 +285104,9 @@ function NeuroglancerSubscriber(props) {
284996
285104
  projectionScale,
284997
285105
  position: position2
284998
285106
  };
284999
- updateVisibleSegmentsThrottledRef.current?.();
285000
- }, [setSpatialCameraSnapshot]);
285107
+ if (!detailMode)
285108
+ updateVisibleSegmentsThrottledRef.current?.();
285109
+ }, [setSpatialCameraSnapshot, detailMode, cameraZoomFactor]);
285001
285110
  const onSegmentClick = useCallback((value2) => {
285002
285111
  if (value2) {
285003
285112
  const id2 = String(value2);
@@ -285033,6 +285142,52 @@ function NeuroglancerSubscriber(props) {
285033
285142
  setIsLayersLoaded(true);
285034
285143
  }
285035
285144
  }, [hasMatchingAnnotationSource, isReady, segmentationLayerScopes]);
285145
+ const lastHoveredIdRef = useRef(null);
285146
+ if (detailMode && cellHighlight != null) {
285147
+ lastHoveredIdRef.current = String(cellHighlight);
285148
+ }
285149
+ const detailSegmentIds = useMemo$1(() => {
285150
+ if (!detailMode)
285151
+ return null;
285152
+ const layerScope = segmentationLayerScopes?.[0];
285153
+ const channelScope = segmentationChannelScopesByLayer?.[layerScope]?.[0];
285154
+ if (!layerScope || !channelScope)
285155
+ return [];
285156
+ const channel = segmentationChannelCoordination?.[0]?.[layerScope]?.[channelScope] ?? {};
285157
+ const selection = channel.obsSetSelection ?? cellSetSelection;
285158
+ const extraSets = channel.additionalObsSets ?? additionalCellSets;
285159
+ const layerSets = obsSegmentationsSetsData?.[layerScope]?.[channelScope]?.obsSets;
285160
+ const toMeshId = (id2) => {
285161
+ const stripped = String(id2).replace(/^.*_/, "");
285162
+ return String(cellIdToMeshIdRef.current?.[stripped] ?? stripped);
285163
+ };
285164
+ const ids = /* @__PURE__ */ new Set();
285165
+ if (detailUseSelection && selection?.length && (layerSets || extraSets)) {
285166
+ const merged = mergeObsSets(layerSets, extraSets);
285167
+ selection.forEach((setPath) => {
285168
+ let node2 = { children: merged?.tree };
285169
+ setPath.forEach((name2) => {
285170
+ node2 = node2?.children?.find((n3) => n3.name === name2);
285171
+ });
285172
+ node2?.set?.forEach(([id2]) => ids.add(toMeshId(id2)));
285173
+ });
285174
+ }
285175
+ if (lastHoveredIdRef.current != null) {
285176
+ ids.add(toMeshId(lastHoveredIdRef.current));
285177
+ }
285178
+ return [...ids].sort();
285179
+ }, [
285180
+ detailMode,
285181
+ detailUseSelection,
285182
+ segmentationLayerScopes,
285183
+ segmentationChannelScopesByLayer,
285184
+ segmentationChannelCoordination,
285185
+ cellSetSelection,
285186
+ additionalCellSets,
285187
+ obsSegmentationsSetsData,
285188
+ cellHighlight,
285189
+ csvLoaded
285190
+ ]);
285036
285191
  const meshOpacity = hasMatchingAnnotationSource ? MESH_OPACITY : void 0;
285037
285192
  const derivedViewerState = useMemo$1(() => {
285038
285193
  const { current: current2 } = latestViewerStateRef;
@@ -285055,10 +285210,31 @@ function NeuroglancerSubscriber(props) {
285055
285210
  if (current2.layers.length <= 0) {
285056
285211
  return current2;
285057
285212
  }
285213
+ if (detailMode) {
285214
+ const ids = detailSegmentIds ?? [];
285215
+ const detailLayers = current2.layers.filter((layer) => layer.type === "segmentation").map((layer) => {
285216
+ const layerScope = segmentationLayerScopes?.find((scope) => layer.name?.includes(scope));
285217
+ const colors2 = cellColorMappingByLayer?.[layerScope]?.colors ?? {};
285218
+ const fallback2 = cellColorMappingByLayer?.[layerScope]?.defaultColor ?? GREY_HEX;
285219
+ const segmentColors = {};
285220
+ ids.forEach((id2) => {
285221
+ segmentColors[id2] = colors2[id2] || fallback2;
285222
+ });
285223
+ return {
285224
+ ...layer,
285225
+ segments: ids,
285226
+ segmentColors,
285227
+ objectAlpha: 1
285228
+ };
285229
+ });
285230
+ const updated2 = isEqual$3(current2.layers, detailLayers) ? current2 : { ...current2, layers: detailLayers };
285231
+ latestViewerStateRef.current = updated2;
285232
+ return updated2;
285233
+ }
285058
285234
  const { projectionScale, projectionOrientation, position: position2 } = current2;
285059
- const rotChangedNow = !nearEq(spatialRotationX, prevCoordsRef.current.rx, ROTATION_EPS) || !nearEq(spatialRotationY, prevCoordsRef.current.ry, ROTATION_EPS) || !nearEq(spatialRotationZ, prevCoordsRef.current.rz, ROTATION_EPS) || !nearEq(spatialRotationOrbit, prevCoordsRef.current.orbit, ROTATION_EPS);
285060
- const zoomChangedNow = !nearEq(spatialZoom, prevCoordsRef.current.zoom, ROTATION_EPS);
285061
- const transChangedNow = !nearEq(spatialTargetX, prevCoordsRef.current.tx, ROTATION_EPS) || !nearEq(spatialTargetY, prevCoordsRef.current.ty, ROTATION_EPS);
285235
+ const rotChangedNow = is3dMode && (!nearEq(spatialRotationX, prevCoordsRef.current.rx, ROTATION_EPS) || !nearEq(spatialRotationY, prevCoordsRef.current.ry, ROTATION_EPS) || !nearEq(spatialRotationZ, prevCoordsRef.current.rz, ROTATION_EPS) || !nearEq(spatialRotationOrbit, prevCoordsRef.current.orbit, ROTATION_EPS));
285236
+ const zoomChangedNow = is3dMode && !nearEq(spatialZoom, prevCoordsRef.current.zoom, ROTATION_EPS);
285237
+ const transChangedNow = is3dMode && (!nearEq(spatialTargetX, prevCoordsRef.current.tx, ROTATION_EPS) || !nearEq(spatialTargetY, prevCoordsRef.current.ty, ROTATION_EPS));
285062
285238
  let nextProjectionScale = projectionScale;
285063
285239
  let nextPosition = position2;
285064
285240
  if (typeof spatialZoom === "number" && initialRenderCalibratorRef.current && lastInteractionSource.current !== LAST_INTERACTION_SOURCE.neuroglancer && zoomChangedNow) {
@@ -285079,7 +285255,7 @@ function NeuroglancerSubscriber(props) {
285079
285255
  }
285080
285256
  const vitessceRotationRaw = eulerToQuaternion(deg2rad(spatialRotationX ?? 0), deg2rad(spatialRotationOrbit ?? 0), deg2rad(spatialRotationZ ?? 0));
285081
285257
  const vitessceRotation = multiplyQuat(Q_Y_UP, vitessceRotationRaw);
285082
- const shouldForceInitialVitPush = !initialRotationPushedRef.current && valueGreaterThanEpsilon(vitessceRotation, projectionOrientation, ROTATION_EPS);
285258
+ const shouldForceInitialVitPush = is3dMode && !initialRotationPushedRef.current && valueGreaterThanEpsilon(vitessceRotation, projectionOrientation, ROTATION_EPS);
285083
285259
  const changedNowOrIInitialVitPush = rotChangedNow || zoomChangedNow || transChangedNow || shouldForceInitialVitPush;
285084
285260
  const src = lastInteractionSource.current ?? (changedNowOrIInitialVitPush ? LAST_INTERACTION_SOURCE.vitessce : null);
285085
285261
  let nextOrientation = projectionOrientation;
@@ -285166,7 +285342,10 @@ function NeuroglancerSubscriber(props) {
285166
285342
  spatialTargetY,
285167
285343
  initialViewerState,
285168
285344
  latestViewerStateIteration,
285169
- hasMatchingAnnotationSource
285345
+ hasMatchingAnnotationSource,
285346
+ detailMode,
285347
+ detailSegmentIds,
285348
+ is3dMode
285170
285349
  ]);
285171
285350
  const onSegmentHighlight = useCallback((obsId) => {
285172
285351
  const next4 = obsId != null ? String(obsId) : null;
@@ -285193,9 +285372,9 @@ function NeuroglancerSubscriber(props) {
285193
285372
  pointLayerScopes: showPointsLegend ? pointLayerScopes : void 0,
285194
285373
  pointLayerCoordination,
285195
285374
  pointMultiIndicesData
285196
- }) }), isMeshLoading ? jsx$1(Chip, { label: "Loading meshes...", size: "small", color: "primary", className: classes2.meshLoadingIndicator }) : null, jsx$1(NeuroglancerComp, { classes: classes2, onSegmentClick, onSelectHoveredCoords: onSegmentHighlight, viewerState: derivedViewerState, cellColorMapping: cellColorMappingByLayer, setViewerState: handleStateUpdate, onLayerLoadingChange: handleLayerLoadingChange, onAnnotationSourceReady, onViewerReady: (getFn) => {
285375
+ }) }), isMeshLoading ? jsx$1(Chip, { label: "Loading meshes...", size: "small", color: "primary", className: classes2.meshLoadingIndicator }) : null, jsx$1(NeuroglancerComp, { classes: classes2, onSegmentClick, onSelectHoveredCoords: detailMode ? void 0 : onSegmentHighlight, viewerState: derivedViewerState, cellColorMapping: cellColorMappingByLayer, setViewerState: handleStateUpdate, onLayerLoadingChange: handleLayerLoadingChange, onAnnotationSourceReady, onViewerReady: (getFn) => {
285197
285376
  getViewProjectionMatRef.current = getFn;
285198
- }, getMeshIdToCellId: (meshId) => meshIdToCellIdRef.current[meshId], cellsUrl, meshOpacity })] }) : null });
285377
+ }, getMeshIdToCellId: (meshId) => meshIdToCellIdRef.current[meshId], cellsUrl, meshOpacity, allowEmptySegments: detailMode })] }) : null });
285199
285378
  }
285200
285379
  const FEATURE_AGGREGATION_STRATEGIES = ["first", "last", "sum", "mean"];
285201
285380
  function CellSetExpressionPlotOptions(props) {
@@ -344219,6 +344398,17 @@ class ImageWrapper {
344219
344398
  const { labels: labels2, shape: shape2 } = Array.isArray(loader2.data) ? loader2.data[0] : loader2.data;
344220
344399
  return shape2[labels2.indexOf("z")];
344221
344400
  }
344401
+ /**
344402
+ * Clamp a z target to a valid plane index.
344403
+ * spatialTargetZ can hold a 3D camera target in scene units, which may
344404
+ * exceed the number of planes; geotiff throws on out-of-range indices.
344405
+ */
344406
+ getClampedZIndex(targetZ) {
344407
+ const numZ = this.getNumZ();
344408
+ if (!Number.isFinite(numZ) || !Number.isFinite(targetZ))
344409
+ return 0;
344410
+ return Math.min(Math.max(Math.floor(targetZ), 0), numZ - 1);
344411
+ }
344222
344412
  getNumT() {
344223
344413
  const loader2 = this.vivLoader;
344224
344414
  const { labels: labels2, shape: shape2 } = Array.isArray(loader2.data) ? loader2.data[0] : loader2.data;
@@ -344319,6 +344509,27 @@ class ImageWrapper {
344319
344509
  }
344320
344510
  return "BlackIsZero";
344321
344511
  }
344512
+ /**
344513
+ * Meters per 3D scene unit, i.e. the unit of getModelMatrix().
344514
+ * OME-TIFF: physicalSizeToMatrix divides by 1 um, so the scene is in µm
344515
+ * (only when physical sizes exist; otherwise pixels, unit unknown → null).
344516
+ * OME-Zarr: the model matrix is in the units of the NGFF axes.
344517
+ */
344518
+ getSceneMetersPerUnit() {
344519
+ const { metadata: metadata2 } = this.vivLoader;
344520
+ if (!metadata2)
344521
+ return null;
344522
+ if ("Pixels" in metadata2) {
344523
+ return this.hasPhysicalSize() ? 1e-6 : null;
344524
+ }
344525
+ if ("multiscales" in metadata2) {
344526
+ const axes = metadata2.multiscales?.[0]?.axes ?? [];
344527
+ const xAxis = axes.find((a2) => (typeof a2 === "string" ? a2 : a2?.name) === "x");
344528
+ const unit2 = typeof xAxis === "object" ? xAxis?.unit : null;
344529
+ return unit2 ? UNIT_TO_METERS[unit2.normalize("NFKC")] ?? null : null;
344530
+ }
344531
+ return null;
344532
+ }
344322
344533
  }
344323
344534
  class OmeZarrLoader extends AbstractTwoStepLoader {
344324
344535
  constructor(dataSource, params2) {
@@ -364428,6 +364639,7 @@ const baseCoordinationTypes = [
364428
364639
  new PluginCoordinationType(CoordinationType$1.SPATIAL_LAYER_COLOR, null, z.array(z.number()).length(3).nullable()),
364429
364640
  new PluginCoordinationType(CoordinationType$1.PIXEL_HIGHLIGHT, null, z.array(z.number()).length(3).nullable()),
364430
364641
  new PluginCoordinationType(CoordinationType$1.TOOLTIP_CROSSHAIRS_VISIBLE, true, z.boolean()),
364642
+ new PluginCoordinationType(CoordinationType$1.TOOLTIP_OBS_SETS_MODE, "all", z.enum(["all", "selected"])),
364431
364643
  new PluginCoordinationType(CoordinationType$1.LEGEND_VISIBLE, true, z.boolean()),
364432
364644
  new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNEL_LABELS_VISIBLE, true, z.boolean()),
364433
364645
  new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION, "vertical", z.enum(["vertical", "horizontal"])),
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a2, a1 } from "./index-BseIw2ZD.js";
1
+ import { a2, a1 } from "./index-DfnWmR3U.js";
2
2
  export {
3
3
  a2 as ControlledLauncher,
4
4
  a1 as UncontrolledLauncher
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
1
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
2
2
  const dctZigZag = new Int32Array([
3
3
  0,
4
4
  1,
@@ -1,5 +1,5 @@
1
1
  import { i as inflate_1 } from "./pako.esm-SxljTded.js";
2
- import { g as getDefaultExportFromCjs, B as BaseDecoder, L as LercParameters, a as LercAddCompression } from "./index-BseIw2ZD.js";
2
+ import { g as getDefaultExportFromCjs, B as BaseDecoder, L as LercParameters, a as LercAddCompression } from "./index-DfnWmR3U.js";
3
3
  var LercDecode = { exports: {} };
4
4
  var hasRequiredLercDecode;
5
5
  function requireLercDecode() {
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
1
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
2
2
  const MIN_BITS = 9;
3
3
  const CLEAR_CODE = 256;
4
4
  const EOI_CODE = 257;
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
1
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
2
2
  class PackbitsDecoder extends BaseDecoder {
3
3
  decodeBlock(buffer) {
4
4
  const dataView = new DataView(buffer);
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
1
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
2
2
  class RawDecoder extends BaseDecoder {
3
3
  decodeBlock(buffer) {
4
4
  return buffer;
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-BseIw2ZD.js";
1
+ import { B as BaseDecoder } from "./index-DfnWmR3U.js";
2
2
  class WebImageDecoder extends BaseDecoder {
3
3
  constructor() {
4
4
  super();
@@ -1,4 +1,4 @@
1
- import { g as getXRModule } from "./index-6RcG881_.js";
1
+ import { g as getXRModule } from "./index-DSTEevd1.js";
2
2
  let store = null;
3
3
  function getXrStore() {
4
4
  if (!store) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/launcher",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "author": "HIDIVE Lab at HMS",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -20,14 +20,14 @@
20
20
  "use-query-params": "^1.1.9",
21
21
  "react-dropzone": "^14.3.8",
22
22
  "@tanstack/react-query": "^5.80.2",
23
- "@vitessce/all": "4.1.0",
24
- "@vitessce/example-configs": "4.1.0",
25
- "@vitessce/example-plugins": "4.1.0",
26
- "@vitessce/styles": "4.1.0",
27
- "@vitessce/vit-s": "4.1.0",
28
- "@vitessce/globals": "4.1.0",
29
- "@vitessce/config": "4.1.0",
30
- "@vitessce/constants-internal": "4.1.0"
23
+ "@vitessce/all": "4.1.1",
24
+ "@vitessce/constants-internal": "4.1.1",
25
+ "@vitessce/example-configs": "4.1.1",
26
+ "@vitessce/example-plugins": "4.1.1",
27
+ "@vitessce/globals": "4.1.1",
28
+ "@vitessce/styles": "4.1.1",
29
+ "@vitessce/vit-s": "4.1.1",
30
+ "@vitessce/config": "4.1.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "react": "19.2.6",