@vitessce/launcher 3.9.4 → 3.9.6

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.
@@ -11115,6 +11115,7 @@ const FileType$1 = {
11115
11115
  // Neuroglancer
11116
11116
  // Precomputed (mesh) format
11117
11117
  OBS_SEGMENTATIONS_NG_PRECOMPUTED: "obsSegmentations.ng-precomputed",
11118
+ OBS_POINTS_NG_ANNOTATIONS: "obsPoints.ng-annotations",
11118
11119
  // New file types to support old file types:
11119
11120
  // - cells.json
11120
11121
  OBS_EMBEDDING_CELLS_JSON: "obsEmbedding.cells.json",
@@ -11321,7 +11322,7 @@ const ViewHelpMapping = {
11321
11322
  FEATURE_VALUE_HISTOGRAM: "The feature value histogram displays the distribution of values (e.g., expression) for the selected feature (e.g., gene).",
11322
11323
  DOT_PLOT: "The dot plot displays summary information about expression of the selected features (e.g., genes) for each selected observation set (e.g., cell type).",
11323
11324
  FEATURE_BAR_PLOT: "The feature bar plot displays one bar per observation (e.g., cell) along the x-axis, where the value of a selected feature (e.g., gene) is encoded along the y-axis.",
11324
- NEUROGLANCER: "The Neuroglancer view displays 3d meshes using Neuroglancer developed by Google.",
11325
+ NEUROGLANCER: "This view displays 3D meshes and points using Neuroglancer developed by Google.",
11325
11326
  TREEMAP: "The treemap provides an overview of the current state of sample-level or cell-level selection and filtering.",
11326
11327
  VOLCANO_PLOT: "The volcano plot displays differential expression results. Each data point represents a feature (as opposed to an observation).",
11327
11328
  OBS_SET_COMPOSITION_BAR_PLOT: "The set composition bar plot displays the results of a compositional analysis conducted using the scCODA method (Büttner et al. 2021 Nature Communications).",
@@ -11373,6 +11374,7 @@ const ViewHelpMapping = {
11373
11374
  [FileType$1.FEATURE_LABELS_MUDATA_ZARR]: DataType$3.FEATURE_LABELS,
11374
11375
  [FileType$1.OBS_SEGMENTATIONS_GLB]: DataType$3.OBS_SEGMENTATIONS,
11375
11376
  [FileType$1.OBS_SEGMENTATIONS_NG_PRECOMPUTED]: DataType$3.OBS_SEGMENTATIONS,
11377
+ [FileType$1.OBS_POINTS_NG_ANNOTATIONS]: DataType$3.OBS_POINTS,
11376
11378
  [FileType$1.IMAGE_SPATIALDATA_ZARR]: DataType$3.IMAGE,
11377
11379
  [FileType$1.LABELS_SPATIALDATA_ZARR]: DataType$3.OBS_SEGMENTATIONS,
11378
11380
  [FileType$1.SHAPES_SPATIALDATA_ZARR]: DataType$3.OBS_SEGMENTATIONS,
@@ -11592,6 +11594,8 @@ const ALT_ZARR_STORE_TYPES = {
11592
11594
  ];
11593
11595
  const COMPONENT_COORDINATION_TYPES = {
11594
11596
  [ViewType$1.NEUROGLANCER]: [
11597
+ CoordinationType$1.META_COORDINATION_SCOPES,
11598
+ CoordinationType$1.META_COORDINATION_SCOPES_BY,
11595
11599
  CoordinationType$1.DATASET,
11596
11600
  CoordinationType$1.SPATIAL_TARGET_X,
11597
11601
  CoordinationType$1.SPATIAL_TARGET_Y,
@@ -11613,7 +11617,26 @@ const COMPONENT_COORDINATION_TYPES = {
11613
11617
  CoordinationType$1.OBS_COLOR_ENCODING,
11614
11618
  CoordinationType$1.EMBEDDING_TYPE,
11615
11619
  CoordinationType$1.ADDITIONAL_OBS_SETS,
11616
- CoordinationType$1.TOOLTIPS_VISIBLE
11620
+ CoordinationType$1.TOOLTIPS_VISIBLE,
11621
+ CoordinationType$1.FILE_UID,
11622
+ CoordinationType$1.IMAGE_LAYER,
11623
+ CoordinationType$1.SEGMENTATION_LAYER,
11624
+ CoordinationType$1.IMAGE_CHANNEL,
11625
+ CoordinationType$1.SEGMENTATION_CHANNEL,
11626
+ CoordinationType$1.POINT_LAYER,
11627
+ CoordinationType$1.FEATURE_COLOR,
11628
+ CoordinationType$1.FEATURE_FILTER_MODE,
11629
+ CoordinationType$1.FEATURE_HIGHLIGHT,
11630
+ CoordinationType$1.FEATURE_SELECTION,
11631
+ CoordinationType$1.FEATURE_VALUE_COLORMAP,
11632
+ CoordinationType$1.FEATURE_VALUE_COLORMAP_RANGE,
11633
+ CoordinationType$1.SPATIAL_LAYER_COLOR,
11634
+ CoordinationType$1.SPATIAL_LAYER_OPACITY,
11635
+ CoordinationType$1.SPATIAL_LAYER_VISIBLE,
11636
+ CoordinationType$1.SPATIAL_CHANNEL_COLOR,
11637
+ CoordinationType$1.SPATIAL_CHANNEL_OPACITY,
11638
+ CoordinationType$1.SPATIAL_CHANNEL_VISIBLE,
11639
+ CoordinationType$1.LEGEND_VISIBLE
11617
11640
  ],
11618
11641
  [ViewType$1.SCATTERPLOT]: [
11619
11642
  CoordinationType$1.DATASET,
@@ -12720,17 +12743,26 @@ const meshGlbSchema = z.object({
12720
12743
  sceneScaleZ: z.number(),
12721
12744
  materialSide: z.enum(["front", "back"])
12722
12745
  }).partial().nullable();
12723
- const ngSchema = z.object({
12746
+ const ngPrecomputedMeshSchema = z.object({
12724
12747
  // TODO: Should this explicitly specify sharded vs. unsharded?
12725
12748
  // Or can/should that be inferred from the data?
12726
- dimensionX: z.number(),
12727
- dimensionY: z.number(),
12728
- dimensionZ: z.number(),
12729
- dimensionUnit: z.enum(["nm", "um", "µm", "mm", "cm", "m"]),
12749
+ // Note: None of these make sense to specify at the file level, since they
12750
+ // are global camera settings that would apply to all layers.
12751
+ // Intead, initial values should be set via the usual coordination space mechanism,
12752
+ // and the NeuroglancerSubscriber should handle conversion into values to pass to Neuroglancer.
12753
+ // dimensionX: z.number(),
12754
+ // dimensionY: z.number(),
12755
+ // dimensionZ: z.number(),
12756
+ // dimensionUnit: z.enum(['nm', 'um', 'µm', 'mm', 'cm', 'm']),
12730
12757
  // TODO: should the following be passed via coordination types instead?
12731
- projectionScale: z.number(),
12732
- position: z.array(z.number()).length(3),
12733
- projectionOrientation: z.array(z.number()).length(4)
12758
+ // projectionScale: z.number(),
12759
+ // position: z.array(z.number()).length(3),
12760
+ // projectionOrientation: z.array(z.number()).length(4),
12761
+ }).partial().nullable();
12762
+ const ngPointAnnotationSchema = z.object({
12763
+ projectionAnnotationSpacing: z.number(),
12764
+ featureIndexProp: z.string().optional().describe("The name of the Neuroglancer AnnotationProperty containing feature IDs. For example, specify 'gene' to use prop_gene() in the Neuroglancer shader code."),
12765
+ pointIndexProp: z.string().optional().describe("The name of the Neuroglancer AnnotationProperty containing point IDs. For example, specify 'point_id' to use prop_point_id() in the Neuroglancer shader code.")
12734
12766
  }).partial().nullable();
12735
12767
  const obsEmbeddingAnndataSchema = annDataObsEmbedding;
12736
12768
  const obsSpotsAnndataSchema = annDataObsLocations;
@@ -211787,22 +211819,22 @@ async function getDecoder(fileDirectory) {
211787
211819
  const Decoder = await importFn();
211788
211820
  return new Decoder(fileDirectory);
211789
211821
  }
211790
- addDecoder([void 0, 1], () => import("./raw-DIDBeWlq.js").then((m2) => m2.default));
211791
- addDecoder(5, () => import("./lzw-CcpH5iJt.js").then((m2) => m2.default));
211822
+ addDecoder([void 0, 1], () => import("./raw-gTiCW4uC.js").then((m2) => m2.default));
211823
+ addDecoder(5, () => import("./lzw-BZquPZzK.js").then((m2) => m2.default));
211792
211824
  addDecoder(6, () => {
211793
211825
  throw new Error("old style JPEG compression is not supported.");
211794
211826
  });
211795
- addDecoder(7, () => import("./jpeg-CDMJPRrU.js").then((m2) => m2.default));
211796
- addDecoder([8, 32946], () => import("./deflate-CrWHFwMs.js").then((m2) => m2.default));
211797
- addDecoder(32773, () => import("./packbits-BeOEJDb9.js").then((m2) => m2.default));
211827
+ addDecoder(7, () => import("./jpeg-sdYhU6M1.js").then((m2) => m2.default));
211828
+ addDecoder([8, 32946], () => import("./deflate-ByRX5czT.js").then((m2) => m2.default));
211829
+ addDecoder(32773, () => import("./packbits-CCy9a1OH.js").then((m2) => m2.default));
211798
211830
  addDecoder(
211799
211831
  34887,
211800
- () => import("./lerc-BfnnHmSr.js").then(async (m2) => {
211832
+ () => import("./lerc-DU3LD97H.js").then(async (m2) => {
211801
211833
  await m2.zstd.init();
211802
211834
  return m2;
211803
211835
  }).then((m2) => m2.default)
211804
211836
  );
211805
- addDecoder(50001, () => import("./webimage-BPux70Xk.js").then((m2) => m2.default));
211837
+ addDecoder(50001, () => import("./webimage-H51ZBpKw.js").then((m2) => m2.default));
211806
211838
  function copyNewSize(array2, width2, height2, samplesPerPixel = 1) {
211807
211839
  return new (Object.getPrototypeOf(array2)).constructor(width2 * height2 * samplesPerPixel);
211808
211840
  }
@@ -229403,13 +229435,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
229403
229435
  */
229404
229436
  componentDidUpdate(prevProps) {
229405
229437
  this.viewInfoDidUpdate();
229406
- const shallowDiff = (propName) => prevProps[propName] !== this.props[propName];
229438
+ const shallowDiff2 = (propName) => prevProps[propName] !== this.props[propName];
229407
229439
  let forceUpdate = false;
229408
- if (["obsEmbedding", "obsEmbeddingIndex"].some(shallowDiff)) {
229440
+ if (["obsEmbedding", "obsEmbeddingIndex"].some(shallowDiff2)) {
229409
229441
  this.onUpdateCellsData();
229410
229442
  forceUpdate = true;
229411
229443
  }
229412
- if (["stratifiedData"].some(shallowDiff)) {
229444
+ if (["stratifiedData"].some(shallowDiff2)) {
229413
229445
  this.onUpdateStratifiedData();
229414
229446
  forceUpdate = true;
229415
229447
  }
@@ -229428,7 +229460,7 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
229428
229460
  "cellColorEncoding",
229429
229461
  "getExpressionValue",
229430
229462
  "embeddingPointsVisible"
229431
- ].some(shallowDiff)) {
229463
+ ].some(shallowDiff2)) {
229432
229464
  this.onUpdateCellsLayer();
229433
229465
  forceUpdate = true;
229434
229466
  }
@@ -229440,7 +229472,7 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
229440
229472
  "embeddingContoursVisible",
229441
229473
  "cellSetLabelsVisible",
229442
229474
  "cellSetLabelSize"
229443
- ].some(shallowDiff)) {
229475
+ ].some(shallowDiff2)) {
229444
229476
  this.onUpdateContourLayers();
229445
229477
  forceUpdate = true;
229446
229478
  }
@@ -229450,11 +229482,11 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
229450
229482
  "cellSetLabelsVisible",
229451
229483
  "cellSetLabelSize",
229452
229484
  "embeddingContoursVisible"
229453
- ].some(shallowDiff)) {
229485
+ ].some(shallowDiff2)) {
229454
229486
  this.onUpdateCellSetsLayers(false);
229455
229487
  forceUpdate = true;
229456
229488
  }
229457
- if (shallowDiff("viewState")) {
229489
+ if (shallowDiff2("viewState")) {
229458
229490
  this.onUpdateCellSetsLayers(true);
229459
229491
  forceUpdate = true;
229460
229492
  }
@@ -254219,21 +254251,21 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
254219
254251
  */
254220
254252
  componentDidUpdate(prevProps) {
254221
254253
  this.viewInfoDidUpdate();
254222
- const shallowDiff = (propName) => prevProps[propName] !== this.props[propName];
254254
+ const shallowDiff2 = (propName) => prevProps[propName] !== this.props[propName];
254223
254255
  let forceUpdate = false;
254224
254256
  if ([
254225
254257
  "obsSegmentations",
254226
254258
  "obsSegmentationsType",
254227
254259
  "obsCentroids"
254228
- ].some(shallowDiff)) {
254260
+ ].some(shallowDiff2)) {
254229
254261
  this.onUpdateCellsData();
254230
254262
  forceUpdate = true;
254231
254263
  }
254232
- if (["cellColors"].some(shallowDiff)) {
254264
+ if (["cellColors"].some(shallowDiff2)) {
254233
254265
  this.onUpdateCellColors();
254234
254266
  forceUpdate = true;
254235
254267
  }
254236
- if (["expressionData"].some(shallowDiff)) {
254268
+ if (["expressionData"].some(shallowDiff2)) {
254237
254269
  this.onUpdateExpressionData();
254238
254270
  forceUpdate = true;
254239
254271
  }
@@ -254252,7 +254284,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
254252
254284
  "cellColorEncoding",
254253
254285
  "geneExpressionColormap",
254254
254286
  "segmentationLayerCallbacks"
254255
- ].some(shallowDiff)) {
254287
+ ].some(shallowDiff2)) {
254256
254288
  this.onUpdateCellsLayer();
254257
254289
  forceUpdate = true;
254258
254290
  }
@@ -254260,7 +254292,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
254260
254292
  "obsLocations",
254261
254293
  "obsLocationsLabels",
254262
254294
  "obsLocationsFeatureIndex"
254263
- ].some(shallowDiff)) {
254295
+ ].some(shallowDiff2)) {
254264
254296
  this.onUpdateMoleculesData();
254265
254297
  forceUpdate = true;
254266
254298
  }
@@ -254270,15 +254302,15 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
254270
254302
  "obsLocationsIndex",
254271
254303
  "obsLocationsLabels",
254272
254304
  "obsLocationsFeatureIndex"
254273
- ].some(shallowDiff)) {
254305
+ ].some(shallowDiff2)) {
254274
254306
  this.onUpdateMoleculesLayer();
254275
254307
  forceUpdate = true;
254276
254308
  }
254277
- if (["neighborhoods"].some(shallowDiff)) {
254309
+ if (["neighborhoods"].some(shallowDiff2)) {
254278
254310
  this.onUpdateNeighborhoodsData();
254279
254311
  forceUpdate = true;
254280
254312
  }
254281
- if (["neighborhoodLayerDefsDefs", "neighborhoods"].some(shallowDiff)) {
254313
+ if (["neighborhoodLayerDefsDefs", "neighborhoods"].some(shallowDiff2)) {
254282
254314
  this.onUpdateNeighborhoodsLayer();
254283
254315
  forceUpdate = true;
254284
254316
  }
@@ -254292,7 +254324,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
254292
254324
  "imageLayerCallbacks",
254293
254325
  "geneExpressionColormap",
254294
254326
  "photometricInterpretation"
254295
- ].some(shallowDiff)) {
254327
+ ].some(shallowDiff2)) {
254296
254328
  this.onUpdateImages();
254297
254329
  forceUpdate = true;
254298
254330
  }
@@ -256042,24 +256074,24 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256042
256074
  */
256043
256075
  componentDidUpdate(prevProps) {
256044
256076
  this.viewInfoDidUpdate();
256045
- const shallowDiff = (propName) => prevProps[propName] !== this.props[propName];
256046
- const shallowDiffByLayer = (propName, scopeName) => prevProps?.[propName]?.[scopeName] !== this.props?.[propName]?.[scopeName];
256077
+ const shallowDiff2 = (propName) => prevProps[propName] !== this.props[propName];
256078
+ const shallowDiffByLayer2 = (propName, scopeName) => prevProps?.[propName]?.[scopeName] !== this.props?.[propName]?.[scopeName];
256047
256079
  const shallowDiffByChannel = (propName, firstName, secondName) => prevProps?.[propName]?.[firstName]?.[secondName] !== this.props?.[propName]?.[firstName]?.[secondName];
256048
256080
  const shallowDiffByLayerCoordination = (propName, layerScope) => prevProps?.[propName]?.[0]?.[layerScope] !== this.props?.[propName]?.[0]?.[layerScope];
256049
256081
  const shallowDiffByChannelCoordination = (propName, layerScope, channelScope) => prevProps?.[propName]?.[0]?.[layerScope]?.[channelScope] !== this.props?.[propName]?.[0]?.[layerScope]?.[channelScope];
256050
256082
  let forceUpdate = false;
256051
- if (shallowDiff("segmentationLayerScopes")) {
256083
+ if (shallowDiff2("segmentationLayerScopes")) {
256052
256084
  this.onUpdateAllSegmentationsData();
256053
256085
  forceUpdate = true;
256054
256086
  } else {
256055
256087
  this.props.segmentationLayerScopes?.forEach((layerScope) => {
256056
- if (shallowDiffByLayer("obsSegmentations", layerScope)) {
256088
+ if (shallowDiffByLayer2("obsSegmentations", layerScope)) {
256057
256089
  this.onUpdateSegmentationsData(layerScope);
256058
256090
  forceUpdate = true;
256059
256091
  }
256060
256092
  });
256061
256093
  }
256062
- if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff)) {
256094
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff2)) {
256063
256095
  this.onUpdateAllSegmentationsLocationsData();
256064
256096
  forceUpdate = true;
256065
256097
  } else {
@@ -256072,7 +256104,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256072
256104
  });
256073
256105
  });
256074
256106
  }
256075
- if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff)) {
256107
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff2)) {
256076
256108
  this.onUpdateAllSegmentationsSetsData();
256077
256109
  forceUpdate = true;
256078
256110
  } else {
@@ -256085,7 +256117,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256085
256117
  });
256086
256118
  });
256087
256119
  }
256088
- if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff)) {
256120
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff2)) {
256089
256121
  this.onUpdateAllSegmentationsIndexData();
256090
256122
  forceUpdate = true;
256091
256123
  } else {
@@ -256098,7 +256130,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256098
256130
  });
256099
256131
  });
256100
256132
  }
256101
- if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff)) {
256133
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(shallowDiff2)) {
256102
256134
  this.onUpdateAllSegmentationsExpressionData();
256103
256135
  forceUpdate = true;
256104
256136
  } else {
@@ -256123,49 +256155,49 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256123
256155
  "segmentationLayerCoordination",
256124
256156
  "segmentationChannelScopesByLayer",
256125
256157
  "segmentationChannelCoordination"
256126
- ].some(shallowDiff)) {
256158
+ ].some(shallowDiff2)) {
256127
256159
  this.onUpdateSegmentationsLayer();
256128
256160
  forceUpdate = true;
256129
256161
  }
256130
- if (shallowDiff("spotLayerScopes")) {
256162
+ if (shallowDiff2("spotLayerScopes")) {
256131
256163
  this.onUpdateAllSpotsData();
256132
256164
  forceUpdate = true;
256133
256165
  } else {
256134
256166
  this.props.spotLayerScopes.forEach((layerScope) => {
256135
- if (shallowDiffByLayer("obsSpots", layerScope)) {
256167
+ if (shallowDiffByLayer2("obsSpots", layerScope)) {
256136
256168
  this.onUpdateSpotsData(layerScope);
256137
256169
  forceUpdate = true;
256138
256170
  }
256139
256171
  });
256140
256172
  }
256141
- if (shallowDiff("spotLayerScopes")) {
256173
+ if (shallowDiff2("spotLayerScopes")) {
256142
256174
  this.onUpdateAllSpotsSetsData();
256143
256175
  forceUpdate = true;
256144
256176
  } else {
256145
256177
  this.props.spotLayerScopes.forEach((layerScope) => {
256146
- if (shallowDiffByLayer("obsSpotsSets", layerScope) || shallowDiffByLayer("obsSpots", layerScope) || shallowDiffByLayerCoordination("spotLayerCoordination", layerScope)) {
256178
+ if (shallowDiffByLayer2("obsSpotsSets", layerScope) || shallowDiffByLayer2("obsSpots", layerScope) || shallowDiffByLayerCoordination("spotLayerCoordination", layerScope)) {
256147
256179
  this.onUpdateSpotsSetsData(layerScope);
256148
256180
  forceUpdate = true;
256149
256181
  }
256150
256182
  });
256151
256183
  }
256152
- if (shallowDiff("spotLayerScopes")) {
256184
+ if (shallowDiff2("spotLayerScopes")) {
256153
256185
  this.onUpdateAllSpotsIndexData();
256154
256186
  forceUpdate = true;
256155
256187
  } else {
256156
256188
  this.props.spotLayerScopes.forEach((layerScope) => {
256157
- if (shallowDiffByLayer("spotMatrixIndices", layerScope) || shallowDiffByLayer("obsSpots", layerScope)) {
256189
+ if (shallowDiffByLayer2("spotMatrixIndices", layerScope) || shallowDiffByLayer2("obsSpots", layerScope)) {
256158
256190
  this.onUpdateSpotsIndexData(layerScope);
256159
256191
  forceUpdate = true;
256160
256192
  }
256161
256193
  });
256162
256194
  }
256163
- if (shallowDiff("spotLayerScopes")) {
256195
+ if (shallowDiff2("spotLayerScopes")) {
256164
256196
  this.onUpdateAllSpotsExpressionData();
256165
256197
  forceUpdate = true;
256166
256198
  } else {
256167
256199
  this.props.spotLayerScopes.forEach((layerScope) => {
256168
- if (shallowDiffByLayer("spotMatrixIndices", layerScope) || shallowDiffByLayer("obsSpots", layerScope) || shallowDiffByLayer("spotMultiExpressionData", layerScope)) {
256200
+ if (shallowDiffByLayer2("spotMatrixIndices", layerScope) || shallowDiffByLayer2("obsSpots", layerScope) || shallowDiffByLayer2("spotMultiExpressionData", layerScope)) {
256169
256201
  this.onUpdateSpotsExpressionData(layerScope);
256170
256202
  forceUpdate = true;
256171
256203
  }
@@ -256180,16 +256212,16 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256180
256212
  // Coordination props.
256181
256213
  "spotLayerScopes",
256182
256214
  "spotLayerCoordination"
256183
- ].some(shallowDiff)) {
256215
+ ].some(shallowDiff2)) {
256184
256216
  this.onUpdateSpotsLayer();
256185
256217
  forceUpdate = true;
256186
256218
  }
256187
- if (shallowDiff("pointLayerScopes")) {
256219
+ if (shallowDiff2("pointLayerScopes")) {
256188
256220
  this.onUpdateAllPointsData();
256189
256221
  forceUpdate = true;
256190
256222
  } else {
256191
256223
  this.props.pointLayerScopes.forEach((layerScope) => {
256192
- if (shallowDiffByLayer("obsPoints", layerScope) || shallowDiffByLayer("pointMultiObsLabels", layerScope) || shallowDiffByLayer("pointMatrixIndices", layerScope)) {
256224
+ if (shallowDiffByLayer2("obsPoints", layerScope) || shallowDiffByLayer2("pointMultiObsLabels", layerScope) || shallowDiffByLayer2("pointMatrixIndices", layerScope)) {
256193
256225
  this.onUpdatePointsData(layerScope);
256194
256226
  forceUpdate = true;
256195
256227
  }
@@ -256203,7 +256235,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256203
256235
  // Coordination props.
256204
256236
  "pointLayerScopes",
256205
256237
  "pointLayerCoordination"
256206
- ].some(shallowDiff)) {
256238
+ ].some(shallowDiff2)) {
256207
256239
  this.onUpdatePointsLayer();
256208
256240
  forceUpdate = true;
256209
256241
  }
@@ -256215,7 +256247,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
256215
256247
  "imageLayerCoordination",
256216
256248
  "imageChannelScopesByLayer",
256217
256249
  "imageChannelCoordination"
256218
- ].some(shallowDiff)) {
256250
+ ].some(shallowDiff2)) {
256219
256251
  this.onUpdateImages();
256220
256252
  forceUpdate = true;
256221
256253
  }
@@ -256354,12 +256386,12 @@ class ErrorBoundary extends React__default.Component {
256354
256386
  }
256355
256387
  }
256356
256388
  const LazySpatialThree = React__default.lazy(async () => {
256357
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-Chf9TR4u.js");
256389
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-xAWMcZc7.js");
256358
256390
  return { default: SpatialWrapper2 };
256359
256391
  });
256360
256392
  const SpatialThreeAdapter = React__default.forwardRef((props, ref2) => jsxRuntimeExports.jsx("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsxRuntimeExports.jsx(ErrorBoundary, { children: jsxRuntimeExports.jsx(Suspense, { fallback: jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: jsxRuntimeExports.jsx(LazySpatialThree, { ...props }) }) }) }));
256361
256393
  const LazySpatialAccelerated = React__default.lazy(async () => {
256362
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-fYLGd5-F.js");
256394
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-vYTQdcDn.js");
256363
256395
  return { default: SpatialWrapper2 };
256364
256396
  });
256365
256397
  const SpatialAcceleratedAdapter = React__default.forwardRef((props, ref2) => jsxRuntimeExports.jsx("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsxRuntimeExports.jsx(ErrorBoundary, { children: jsxRuntimeExports.jsx(Suspense, { fallback: jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: jsxRuntimeExports.jsx(LazySpatialAccelerated, { ...props }) }) }) }));
@@ -271397,7 +271429,7 @@ function HiglassGlobalStyles(props) {
271397
271429
  }
271398
271430
  register({ dataFetcher: ZarrMultivecDataFetcher_default, config: ZarrMultivecDataFetcher_default.config }, { pluginType: "dataFetcher" });
271399
271431
  const LazyHiGlassComponent = React__default.lazy(async () => {
271400
- const { HiGlassComponent } = await import("./higlass-DXSQ9sk_.js");
271432
+ const { HiGlassComponent } = await import("./higlass-JheOYeK6.js");
271401
271433
  return { default: HiGlassComponent };
271402
271434
  });
271403
271435
  const HG_SIZE = 800;
@@ -274344,7 +274376,7 @@ function NeuroglancerGlobalStyles(props) {
274344
274376
  const { classes: classes2 } = props;
274345
274377
  return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(GlobalStyles$3, { styles: globalNeuroglancerCss }), jsxRuntimeExports.jsx(ScopedGlobalStyles, { styles: globalNeuroglancerStyles, parentClassName: classes2.neuroglancerWrapper })] });
274346
274378
  }
274347
- const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-BvdUAGCt.js"));
274379
+ const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-DQisjzJ2.js"));
274348
274380
  function createWorker() {
274349
274381
  return new WorkerFactory();
274350
274382
  }
@@ -274421,107 +274453,548 @@ class NeuroglancerComp extends PureComponent {
274421
274453
  return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(NeuroglancerGlobalStyles, { classes: classes2 }), jsxRuntimeExports.jsx("div", { className: classes2.neuroglancerWrapper, children: jsxRuntimeExports.jsx(Suspense, { fallback: jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: jsxRuntimeExports.jsx(LazyReactNeuroglancer, { brainMapsClientId: "NOT_A_VALID_ID", viewerState, onViewerStateChanged: this.onViewerStateChanged, bundleRoot: this.bundleRoot, cellColorMapping, ref: this.onRef }) }) })] });
274422
274454
  }
274423
274455
  }
274456
+ function useMemoCustomComparison(factory2, dependencies2, customIsEqual) {
274457
+ const ref2 = useRef(
274458
+ /** @type {{ deps: any; value: T } | undefined} */
274459
+ void 0
274460
+ );
274461
+ if (ref2.current === void 0 || !customIsEqual(ref2.current.deps, dependencies2)) {
274462
+ ref2.current = { deps: dependencies2, value: factory2() };
274463
+ }
274464
+ return ref2.current.value;
274465
+ }
274466
+ const shallowDiff = (prevDeps, nextDeps, depName) => prevDeps[depName] !== nextDeps[depName];
274467
+ const shallowDiffByLayer = (prevDeps, nextDeps, depName, scopeName) => prevDeps?.[depName]?.[scopeName] !== nextDeps?.[depName]?.[scopeName];
274468
+ const shallowDiffByChannelWithKeys = (prevDeps, nextDeps, depName, firstName, secondName, keys2) => keys2.some((k) => prevDeps?.[depName]?.[firstName]?.[secondName]?.[k] !== nextDeps?.[depName]?.[firstName]?.[secondName]?.[k]);
274469
+ const shallowDiffByLayerCoordinationWithKeys = (prevDeps, nextDeps, depName, layerScope, keys2) => keys2.some((k) => prevDeps?.[depName]?.[0]?.[layerScope]?.[k] !== nextDeps?.[depName]?.[0]?.[layerScope]?.[k]);
274470
+ const shallowDiffByChannelCoordinationWithKeys = (prevDeps, nextDeps, depName, layerScope, channelScope, keys2) => keys2.some((k) => prevDeps?.[depName]?.[0]?.[layerScope]?.[channelScope]?.[k] !== nextDeps?.[depName]?.[0]?.[layerScope]?.[channelScope]?.[k]);
274471
+ function customIsEqualForCellColors(prevDeps, nextDeps) {
274472
+ let forceUpdate = false;
274473
+ const curriedShallowDiff = (depName) => shallowDiff(prevDeps, nextDeps, depName);
274474
+ const curriedShallowDiffByChannelWithKeys = (depName, firstName, secondName, keys2) => shallowDiffByChannelWithKeys(prevDeps, nextDeps, depName, firstName, secondName, keys2);
274475
+ const curriedShallowDiffByChannelCoordinationWithKeys = (depName, layerScope, channelScope, keys2) => shallowDiffByChannelCoordinationWithKeys(prevDeps, nextDeps, depName, layerScope, channelScope, keys2);
274476
+ if (curriedShallowDiff("theme")) {
274477
+ forceUpdate = true;
274478
+ }
274479
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(curriedShallowDiff)) {
274480
+ forceUpdate = true;
274481
+ } else {
274482
+ nextDeps.segmentationLayerScopes?.forEach((layerScope) => {
274483
+ nextDeps.segmentationChannelScopesByLayer?.[layerScope]?.forEach((channelScope) => {
274484
+ if (curriedShallowDiffByChannelWithKeys("obsSegmentationsSetsData", layerScope, channelScope, [
274485
+ "obsSets",
274486
+ "obsIndex"
274487
+ ]) || curriedShallowDiffByChannelCoordinationWithKeys("segmentationChannelCoordination", layerScope, channelScope, [
274488
+ "obsSetColor",
274489
+ "obsColorEncoding",
274490
+ "obsSetSelection",
274491
+ "additionalObsSets"
274492
+ ])) {
274493
+ forceUpdate = true;
274494
+ }
274495
+ });
274496
+ });
274497
+ }
274498
+ return !forceUpdate;
274499
+ }
274500
+ function customIsEqualForInitialViewerState(prevDeps, nextDeps) {
274501
+ let forceUpdate = false;
274502
+ const curriedShallowDiff = (depName) => shallowDiff(prevDeps, nextDeps, depName);
274503
+ const curriedShallowDiffByLayer = (depName, scopeName) => shallowDiffByLayer(prevDeps, nextDeps, depName, scopeName);
274504
+ const curriedShallowDiffByLayerCoordinationWithKeys = (depName, layerScope, keys2) => shallowDiffByLayerCoordinationWithKeys(prevDeps, nextDeps, depName, layerScope, keys2);
274505
+ const curriedShallowDiffByChannelCoordinationWithKeys = (depName, layerScope, channelScope, keys2) => shallowDiffByChannelCoordinationWithKeys(prevDeps, nextDeps, depName, layerScope, channelScope, keys2);
274506
+ if (["segmentationLayerScopes", "segmentationChannelScopesByLayer"].some(curriedShallowDiff)) {
274507
+ forceUpdate = true;
274508
+ } else {
274509
+ nextDeps.segmentationLayerScopes?.forEach((layerScope) => {
274510
+ if (curriedShallowDiffByLayer("obsSegmentationsData", layerScope) || curriedShallowDiffByLayerCoordinationWithKeys("segmentationLayerCoordination", layerScope, [
274511
+ "spatialLayerVisible"
274512
+ ])) {
274513
+ forceUpdate = true;
274514
+ }
274515
+ nextDeps.segmentationChannelScopesByLayer?.[layerScope]?.forEach((channelScope) => {
274516
+ if (curriedShallowDiffByChannelCoordinationWithKeys("segmentationChannelCoordination", layerScope, channelScope, [
274517
+ "spatialChannelVisible"
274518
+ ])) {
274519
+ forceUpdate = true;
274520
+ }
274521
+ });
274522
+ });
274523
+ }
274524
+ if (curriedShallowDiff("pointLayerScopes")) {
274525
+ forceUpdate = true;
274526
+ } else {
274527
+ nextDeps.pointLayerScopes?.forEach((layerScope) => {
274528
+ if (curriedShallowDiffByLayer("obsPointsData", layerScope) || curriedShallowDiffByLayer("pointMultiIndicesData", layerScope) || curriedShallowDiffByLayerCoordinationWithKeys("pointLayerCoordination", layerScope, [
274529
+ "spatialLayerVisible",
274530
+ "obsColorEncoding",
274531
+ "spatialLayerColor",
274532
+ "featureSelection",
274533
+ "featureFilterMode",
274534
+ "featureColor"
274535
+ ]) || Math.abs(prevDeps?.pointLayerCoordination?.[0]?.[layerScope]?.spatialLayerOpacity - nextDeps?.pointLayerCoordination?.[0]?.[layerScope]?.spatialLayerOpacity) >= 0.05) {
274536
+ forceUpdate = true;
274537
+ }
274538
+ });
274539
+ }
274540
+ return !forceUpdate;
274541
+ }
274542
+ function normalizeColor(rgbColor) {
274543
+ return rgbColor.map((c2) => c2 / 255);
274544
+ }
274545
+ function toVec3(normalizedColor) {
274546
+ return `vec3(${normalizedColor.join(", ")})`;
274547
+ }
274548
+ function toVec4(normalizedColor, alpha2) {
274549
+ return `vec4(${normalizedColor.join(", ")}, ${alpha2})`;
274550
+ }
274551
+ function getSpatialLayerColorShader(staticColor, opacity2) {
274552
+ const norm2 = normalizeColor(staticColor);
274553
+ return `
274554
+ void main() {
274555
+ setColor(${toVec4(norm2, opacity2)});
274556
+ }
274557
+ `;
274558
+ }
274559
+ function getSpatialLayerColorWithSelectionShader(staticColor, opacity2, featureIndices, defaultColor, featureIndexProp) {
274560
+ const normStatic = normalizeColor(staticColor);
274561
+ const normDefault = normalizeColor(defaultColor);
274562
+ const numFeatures = featureIndices.length;
274563
+ const indicesArr = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274564
+ return `
274565
+ void main() {
274566
+ int geneIndex = prop_${featureIndexProp}();
274567
+ ${indicesArr}
274568
+ bool isSelected = false;
274569
+ for (int i = 0; i < ${numFeatures}; ++i) {
274570
+ if (geneIndex == selectedIndices[i]) {
274571
+ isSelected = true;
274572
+ }
274573
+ }
274574
+ if (isSelected) {
274575
+ setColor(${toVec4(normStatic, opacity2)});
274576
+ } else {
274577
+ setColor(${toVec4(normDefault, opacity2)});
274578
+ }
274579
+ }
274580
+ `;
274581
+ }
274582
+ function getSpatialLayerColorFilteredShader(staticColor, opacity2, featureIndices, featureIndexProp) {
274583
+ const normStatic = normalizeColor(staticColor);
274584
+ const numFeatures = featureIndices.length;
274585
+ const indicesArr = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274586
+ return `
274587
+ void main() {
274588
+ int geneIndex = prop_${featureIndexProp}();
274589
+ ${indicesArr}
274590
+ bool isSelected = false;
274591
+ for (int i = 0; i < ${numFeatures}; ++i) {
274592
+ if (geneIndex == selectedIndices[i]) {
274593
+ isSelected = true;
274594
+ }
274595
+ }
274596
+ if (!isSelected) {
274597
+ discard;
274598
+ }
274599
+ setColor(${toVec4(normStatic, opacity2)});
274600
+ }
274601
+ `;
274602
+ }
274603
+ function getGeneSelectionNoSelectionShader(staticColor, opacity2) {
274604
+ const norm2 = normalizeColor(staticColor);
274605
+ return `
274606
+ void main() {
274607
+ setColor(${toVec4(norm2, opacity2)});
274608
+ }
274609
+ `;
274610
+ }
274611
+ function getGeneSelectionWithSelectionShader(featureIndices, featureColors, staticColor, defaultColor, opacity2, featureIndexProp) {
274612
+ const numFeatures = featureIndices.length;
274613
+ const normDefault = normalizeColor(defaultColor);
274614
+ const normColors = featureColors.map((c2) => normalizeColor(c2));
274615
+ const normStatic = normalizeColor(staticColor);
274616
+ const colorArr = normColors.map((c2) => c2 ? toVec3(c2) : toVec3(normStatic));
274617
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274618
+ const colorsDecl = `vec3 featureColors[${numFeatures}] = vec3[${numFeatures}](${colorArr.join(", ")});`;
274619
+ return `
274620
+ void main() {
274621
+ int geneIndex = prop_${featureIndexProp}();
274622
+ ${indicesDecl}
274623
+ ${colorsDecl}
274624
+ vec4 color = ${toVec4(normDefault, opacity2)};
274625
+ for (int i = 0; i < ${numFeatures}; ++i) {
274626
+ if (geneIndex == selectedIndices[i]) {
274627
+ color = vec4(featureColors[i], ${opacity2});
274628
+ }
274629
+ }
274630
+ setColor(color);
274631
+ }
274632
+ `;
274633
+ }
274634
+ function getGeneSelectionFilteredShader(featureIndices, featureColors, staticColor, opacity2, featureIndexProp) {
274635
+ const numFeatures = featureIndices.length;
274636
+ const normColors = featureColors.map((c2) => normalizeColor(c2));
274637
+ const normStatic = normalizeColor(staticColor);
274638
+ const colorArr = normColors.map((c2) => c2 ? toVec3(c2) : toVec3(normStatic));
274639
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274640
+ const colorsDecl = `vec3 featureColors[${numFeatures}] = vec3[${numFeatures}](${colorArr.join(", ")});`;
274641
+ return `
274642
+ void main() {
274643
+ int geneIndex = prop_${featureIndexProp}();
274644
+ ${indicesDecl}
274645
+ ${colorsDecl}
274646
+ bool isSelected = false;
274647
+ vec3 matchedColor = vec3(0.0);
274648
+ for (int i = 0; i < ${numFeatures}; ++i) {
274649
+ if (geneIndex == selectedIndices[i]) {
274650
+ isSelected = true;
274651
+ matchedColor = featureColors[i];
274652
+ }
274653
+ }
274654
+ if (!isSelected) {
274655
+ discard;
274656
+ }
274657
+ setColor(vec4(matchedColor, ${opacity2}));
274658
+ }
274659
+ `;
274660
+ }
274661
+ function getRandomByFeatureShader(opacity2, featureIndexProp) {
274662
+ const paletteSize = PALETTE.length;
274663
+ const normPalette = PALETTE.map((c2) => normalizeColor(c2));
274664
+ const paletteDecl = `vec3 palette[${paletteSize}] = vec3[${paletteSize}](${normPalette.map((c2) => toVec3(c2)).join(", ")});`;
274665
+ return `
274666
+ void main() {
274667
+ int geneIndex = prop_${featureIndexProp}();
274668
+ ${paletteDecl}
274669
+ int colorIdx = geneIndex - (geneIndex / ${paletteSize}) * ${paletteSize};
274670
+ if (colorIdx < 0) { colorIdx = -colorIdx; }
274671
+ vec3 color = palette[colorIdx];
274672
+ setColor(vec4(color, ${opacity2}));
274673
+ }
274674
+ `;
274675
+ }
274676
+ function getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity2, featureIndexProp) {
274677
+ const paletteSize = PALETTE.length;
274678
+ const normPalette = PALETTE.map((c2) => normalizeColor(c2));
274679
+ const normDefault = normalizeColor(defaultColor);
274680
+ const numFeatures = featureIndices.length;
274681
+ const paletteDecl = `vec3 palette[${paletteSize}] = vec3[${paletteSize}](${normPalette.map((c2) => toVec3(c2)).join(", ")});`;
274682
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274683
+ return `
274684
+ void main() {
274685
+ int geneIndex = prop_${featureIndexProp}();
274686
+ ${paletteDecl}
274687
+ ${indicesDecl}
274688
+ bool isSelected = false;
274689
+ for (int i = 0; i < ${numFeatures}; ++i) {
274690
+ if (geneIndex == selectedIndices[i]) {
274691
+ isSelected = true;
274692
+ }
274693
+ }
274694
+ if (isSelected) {
274695
+ int colorIdx = geneIndex - (geneIndex / ${paletteSize}) * ${paletteSize};
274696
+ if (colorIdx < 0) { colorIdx = -colorIdx; }
274697
+ setColor(vec4(palette[colorIdx], ${opacity2}));
274698
+ } else {
274699
+ setColor(${toVec4(normDefault, opacity2)});
274700
+ }
274701
+ }
274702
+ `;
274703
+ }
274704
+ function getRandomByFeatureFilteredShader(featureIndices, opacity2, featureIndexProp) {
274705
+ const paletteSize = PALETTE.length;
274706
+ const normPalette = PALETTE.map((c2) => normalizeColor(c2));
274707
+ const numFeatures = featureIndices.length;
274708
+ const paletteDecl = `vec3 palette[${paletteSize}] = vec3[${paletteSize}](${normPalette.map((c2) => toVec3(c2)).join(", ")});`;
274709
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274710
+ return `
274711
+ void main() {
274712
+ int geneIndex = prop_${featureIndexProp}();
274713
+ ${paletteDecl}
274714
+ ${indicesDecl}
274715
+ bool isSelected = false;
274716
+ for (int i = 0; i < ${numFeatures}; ++i) {
274717
+ if (geneIndex == selectedIndices[i]) {
274718
+ isSelected = true;
274719
+ }
274720
+ }
274721
+ if (!isSelected) {
274722
+ discard;
274723
+ }
274724
+ int colorIdx = geneIndex - (geneIndex / ${paletteSize}) * ${paletteSize};
274725
+ if (colorIdx < 0) { colorIdx = -colorIdx; }
274726
+ setColor(vec4(palette[colorIdx], ${opacity2}));
274727
+ }
274728
+ `;
274729
+ }
274730
+ function hashToFloatGlsl() {
274731
+ return `
274732
+ float hashToFloat(int v, int seed) {
274733
+ int h = v ^ (seed * 16777619);
274734
+ h = h * 747796405 + 2891336453;
274735
+ h = ((h >> 16) ^ h) * 2654435769;
274736
+ h = ((h >> 16) ^ h);
274737
+ return float(h & 0x7FFFFFFF) / float(0x7FFFFFFF);
274738
+ }
274739
+ `;
274740
+ }
274741
+ function getRandomPerPointShader(opacity2, featureIndexProp, pointIndexProp) {
274742
+ return `
274743
+ ${hashToFloatGlsl()}
274744
+ void main() {
274745
+ int geneIndex = prop_${featureIndexProp}();
274746
+ int pointIndex = prop_${pointIndexProp}();
274747
+ float r = hashToFloat(pointIndex, 0);
274748
+ float g = hashToFloat(pointIndex, 1);
274749
+ float b = hashToFloat(pointIndex, 2);
274750
+ setColor(vec4(r, g, b, ${opacity2}));
274751
+ }
274752
+ `;
274753
+ }
274754
+ function getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity2, featureIndexProp, pointIndexProp) {
274755
+ const normDefault = normalizeColor(defaultColor);
274756
+ const numFeatures = featureIndices.length;
274757
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274758
+ return `
274759
+ ${hashToFloatGlsl()}
274760
+ void main() {
274761
+ int geneIndex = prop_${featureIndexProp}();
274762
+ int pointIndex = prop_${pointIndexProp}();
274763
+ ${indicesDecl}
274764
+ bool isSelected = false;
274765
+ for (int i = 0; i < ${numFeatures}; ++i) {
274766
+ if (geneIndex == selectedIndices[i]) {
274767
+ isSelected = true;
274768
+ }
274769
+ }
274770
+ if (isSelected) {
274771
+ float r = hashToFloat(pointIndex, 0);
274772
+ float g = hashToFloat(pointIndex, 1);
274773
+ float b = hashToFloat(pointIndex, 2);
274774
+ setColor(vec4(r, g, b, ${opacity2}));
274775
+ } else {
274776
+ setColor(${toVec4(normDefault, opacity2)});
274777
+ }
274778
+ }
274779
+ `;
274780
+ }
274781
+ function getRandomPerPointFilteredShader(featureIndices, opacity2, featureIndexProp, pointIndexProp) {
274782
+ const numFeatures = featureIndices.length;
274783
+ const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(", ")});`;
274784
+ return `
274785
+ ${hashToFloatGlsl()}
274786
+ void main() {
274787
+ int geneIndex = prop_${featureIndexProp}();
274788
+ int pointIndex = prop_${pointIndexProp}();
274789
+ ${indicesDecl}
274790
+ bool isSelected = false;
274791
+ for (int i = 0; i < ${numFeatures}; ++i) {
274792
+ if (geneIndex == selectedIndices[i]) {
274793
+ isSelected = true;
274794
+ }
274795
+ }
274796
+ if (!isSelected) {
274797
+ discard;
274798
+ }
274799
+ float r = hashToFloat(pointIndex, 0);
274800
+ float g = hashToFloat(pointIndex, 1);
274801
+ float b = hashToFloat(pointIndex, 2);
274802
+ setColor(vec4(r, g, b, ${opacity2}));
274803
+ }
274804
+ `;
274805
+ }
274806
+ function getPointsShader(layerCoordination) {
274807
+ const { theme, featureIndex, spatialLayerOpacity, obsColorEncoding, spatialLayerColor, featureSelection, featureFilterMode, featureColor, featureIndexProp, pointIndexProp } = layerCoordination;
274808
+ const defaultColor = getDefaultColor(theme);
274809
+ const opacity2 = spatialLayerOpacity ?? 1;
274810
+ const staticColor = Array.isArray(spatialLayerColor) && spatialLayerColor.length === 3 ? spatialLayerColor : defaultColor;
274811
+ const hasFeatureSelection = Array.isArray(featureSelection) && featureSelection.length > 0;
274812
+ const isFiltered = featureFilterMode === "featureSelection";
274813
+ let featureIndices = [];
274814
+ if (hasFeatureSelection && Array.isArray(featureIndex)) {
274815
+ featureIndices = featureSelection.map((name2) => featureIndex.indexOf(name2)).filter((i2) => i2 >= 0);
274816
+ }
274817
+ const hasResolvedIndices = featureIndices.length > 0;
274818
+ const resolvedFeatureColors = hasResolvedIndices ? featureSelection.filter((name2) => featureIndex?.indexOf(name2) >= 0).map((name2) => {
274819
+ const match2 = Array.isArray(featureColor) ? featureColor.find((fc) => fc.name === name2)?.color : null;
274820
+ return match2 || staticColor;
274821
+ }) : [];
274822
+ if (obsColorEncoding === "spatialLayerColor") {
274823
+ if (!hasFeatureSelection || !hasResolvedIndices) {
274824
+ return getSpatialLayerColorShader(staticColor, opacity2);
274825
+ }
274826
+ if (isFiltered) {
274827
+ return getSpatialLayerColorFilteredShader(staticColor, opacity2, featureIndices, featureIndexProp);
274828
+ }
274829
+ return getSpatialLayerColorWithSelectionShader(staticColor, opacity2, featureIndices, defaultColor, featureIndexProp);
274830
+ }
274831
+ if (obsColorEncoding === "geneSelection") {
274832
+ if (!featureIndexProp) {
274833
+ throw new Error("In order to use gene-based color encoding for Neuroglancer Points, options.featureIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.");
274834
+ }
274835
+ if (!hasFeatureSelection || !hasResolvedIndices) {
274836
+ return getGeneSelectionNoSelectionShader(staticColor, opacity2);
274837
+ }
274838
+ if (isFiltered) {
274839
+ return getGeneSelectionFilteredShader(featureIndices, resolvedFeatureColors, staticColor, opacity2, featureIndexProp);
274840
+ }
274841
+ return getGeneSelectionWithSelectionShader(featureIndices, resolvedFeatureColors, staticColor, defaultColor, opacity2, featureIndexProp);
274842
+ }
274843
+ if (obsColorEncoding === "randomByFeature") {
274844
+ if (!featureIndexProp) {
274845
+ throw new Error("In order to use gene-based color encoding for Neuroglancer Points, options.featureIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.");
274846
+ }
274847
+ if (!hasFeatureSelection || !hasResolvedIndices) {
274848
+ return getRandomByFeatureShader(opacity2, featureIndexProp);
274849
+ }
274850
+ if (isFiltered) {
274851
+ return getRandomByFeatureFilteredShader(featureIndices, opacity2, featureIndexProp);
274852
+ }
274853
+ return getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity2, featureIndexProp);
274854
+ }
274855
+ if (obsColorEncoding === "random") {
274856
+ if (!pointIndexProp) {
274857
+ throw new Error("In order to use per-point color encoding for Neuroglancer Points, options.pointIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.");
274858
+ }
274859
+ if (!hasFeatureSelection || !hasResolvedIndices) {
274860
+ return getRandomPerPointShader(opacity2, featureIndexProp, pointIndexProp);
274861
+ }
274862
+ if (isFiltered) {
274863
+ return getRandomPerPointFilteredShader(featureIndices, opacity2, featureIndexProp, pointIndexProp);
274864
+ }
274865
+ return getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity2, featureIndexProp, pointIndexProp);
274866
+ }
274867
+ return getSpatialLayerColorShader(staticColor, opacity2);
274868
+ }
274424
274869
  const DEFAULT_NG_PROPS = {
274425
274870
  layout: "3d",
274426
274871
  position: [0, 0, 0],
274427
274872
  projectionOrientation: [0, 0, 0, 1],
274428
274873
  projectionScale: 1024,
274429
- crossSectionScale: 1
274874
+ crossSectionScale: 1,
274875
+ dimensions: {
274876
+ x: [1, "nm"],
274877
+ y: [1, "nm"],
274878
+ z: [1, "nm"]
274879
+ },
274880
+ layers: []
274430
274881
  };
274431
274882
  function toPrecomputedSource(url) {
274432
274883
  if (!url) {
274433
- return void 0;
274884
+ throw new Error("toPrecomputedSource: URL is required");
274434
274885
  }
274435
274886
  return `precomputed://${url}`;
274436
274887
  }
274437
- const UNIT_TO_NM = {
274438
- nm: 1,
274439
- um: 1e3,
274440
- µm: 1e3,
274441
- mm: 1e6,
274442
- cm: 1e7,
274443
- m: 1e9
274444
- };
274445
- function isInNanometerRange(value2, unit2, minNm = 1, maxNm = 100) {
274446
- const n3 = typeof value2 === "number" ? value2 : Number(value2);
274447
- if (!Number.isFinite(n3))
274448
- return false;
274449
- const factor = unit2 && UNIT_TO_NM[unit2];
274450
- if (!factor)
274451
- return false;
274452
- const nm = n3 * factor;
274453
- return nm >= minNm && nm <= maxNm;
274454
- }
274455
- function normalizeDimensionsToNanometers(opts2) {
274456
- const { dimensionUnit, dimensionX, dimensionY, dimensionZ } = opts2;
274457
- if (!dimensionUnit || !dimensionX || !dimensionY || !dimensionZ) {
274458
- console.warn("Missing dimension info");
274888
+ function toNgLayerName(dataType, layerScope, channelScope = null) {
274889
+ if (dataType === DataType$3.OBS_SEGMENTATIONS) {
274890
+ return `obsSegmentations-${layerScope}-${channelScope}`;
274459
274891
  }
274460
- const xNm = isInNanometerRange(dimensionX, dimensionUnit);
274461
- const yNm = isInNanometerRange(dimensionY, dimensionUnit);
274462
- const zNm = isInNanometerRange(dimensionZ, dimensionUnit);
274463
- if (!xNm || !yNm || !zNm) {
274464
- console.warn("Dimension was converted to nm units");
274892
+ if (dataType === DataType$3.OBS_POINTS) {
274893
+ return `obsPoints-${layerScope}`;
274465
274894
  }
274466
- return {
274467
- x: xNm ? [dimensionX, dimensionUnit] : [1, "nm"],
274468
- y: yNm ? [dimensionY, dimensionUnit] : [1, "nm"],
274469
- z: zNm ? [dimensionZ, dimensionUnit] : [1, "nm"]
274470
- };
274895
+ throw new Error(`Unsupported data type: ${dataType}`);
274471
274896
  }
274472
- function extractDataTypeEntities(loaders, dataset, dataType) {
274473
- const datasetEntry = loaders?.[dataset];
274474
- const internMap = datasetEntry?.loaders?.[dataType];
274475
- if (!internMap || typeof internMap.entries !== "function")
274476
- return [];
274477
- return Array.from(internMap.entries()).map(([key2, loader2]) => {
274478
- const url = loader2?.url ?? loader2?.dataSource?.url ?? void 0;
274479
- const fileUid = key2?.fileUid ?? loader2?.coordinationValues?.fileUid ?? void 0;
274480
- const { position: position2, projectionOrientation, projectionScale, crossSectionScale } = loader2?.options ?? {};
274481
- const isPrecomputed = loader2?.fileType.includes("precomputed");
274482
- if (!isPrecomputed) {
274483
- console.warn("Filetype needs to be precomputed");
274484
- }
274485
- return {
274486
- key: key2,
274487
- type: "segmentation",
274488
- fileUid,
274489
- layout: DEFAULT_NG_PROPS.layout,
274490
- url,
274491
- source: toPrecomputedSource(url),
274492
- name: fileUid ?? key2?.name ?? "segmentation",
274493
- // For precomputed: nm is the unit used
274494
- dimensions: normalizeDimensionsToNanometers(loader2?.options),
274495
- // If not provided, no error, but difficult to see the data
274496
- position: Array.isArray(position2) && position2.length === 3 ? position2 : DEFAULT_NG_PROPS.position,
274497
- // If not provided, will have a default orientation
274498
- projectionOrientation: Array.isArray(projectionOrientation) && projectionOrientation.length === 4 ? projectionOrientation : DEFAULT_NG_PROPS.projectionOrientation,
274499
- projectionScale: Number.isFinite(projectionScale) ? projectionScale : DEFAULT_NG_PROPS.projectionScale,
274500
- crossSectionScale: Number.isFinite(crossSectionScale) ? crossSectionScale : DEFAULT_NG_PROPS.crossSectionScale
274501
- };
274502
- });
274503
- }
274504
- function useExtractOptionsForNg(loaders, dataset, dataType) {
274505
- const extractedEntities = useMemo$1(() => extractDataTypeEntities(loaders, dataset, dataType), [loaders, dataset, dataType]);
274506
- const layers = useMemo$1(() => extractedEntities.filter((t4) => t4.source).map((t4) => ({
274507
- type: t4.type,
274508
- source: t4.source,
274509
- segments: [],
274510
- name: t4.name || "segmentation"
274511
- })), [extractedEntities]);
274512
- const viewerState = useMemo$1(() => ({
274513
- dimensions: extractedEntities[0]?.dimensions,
274514
- position: extractedEntities[0]?.position,
274515
- crossSectionScale: extractedEntities[0]?.crossSectionScale,
274516
- projectionOrientation: extractedEntities[0]?.projectionOrientation,
274517
- projectionScale: extractedEntities[0]?.projectionScale,
274518
- layers,
274519
- layout: extractedEntities[0].layout
274520
- }));
274521
- return [viewerState];
274522
- }
274523
- function useNeuroglancerViewerState(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
274524
- return useExtractOptionsForNg(loaders, dataset, DataType$3.OBS_SEGMENTATIONS);
274897
+ function useNeuroglancerViewerState(theme, segmentationLayerScopes, segmentationChannelScopesByLayer, segmentationLayerCoordination, segmentationChannelCoordination, obsSegmentationsUrls, obsSegmentationsData, pointLayerScopes, pointLayerCoordination, obsPointsUrls, obsPointsData, pointMultiIndicesData) {
274898
+ const viewerState = useMemoCustomComparison(() => {
274899
+ let result = cloneDeep$1(DEFAULT_NG_PROPS);
274900
+ segmentationLayerScopes.forEach((layerScope) => {
274901
+ const layerCoordination = segmentationLayerCoordination[0][layerScope];
274902
+ const channelScopes = segmentationChannelScopesByLayer[layerScope] || [];
274903
+ const layerData = obsSegmentationsData[layerScope];
274904
+ const layerUrl = obsSegmentationsUrls[layerScope]?.[0]?.url;
274905
+ if (layerUrl && layerData) {
274906
+ const { spatialLayerVisible } = layerCoordination || {};
274907
+ channelScopes.forEach((channelScope) => {
274908
+ const channelCoordination = segmentationChannelCoordination[0]?.[layerScope]?.[channelScope];
274909
+ const { spatialChannelVisible } = channelCoordination || {};
274910
+ result = {
274911
+ ...result,
274912
+ layers: [
274913
+ ...result.layers,
274914
+ {
274915
+ type: "segmentation",
274916
+ source: toPrecomputedSource(layerUrl),
274917
+ segments: [],
274918
+ name: toNgLayerName(DataType$3.OBS_SEGMENTATIONS, layerScope, channelScope),
274919
+ visible: spatialLayerVisible && spatialChannelVisible,
274920
+ // Both layer and channel
274921
+ // visibility must be true for the layer to be visible.
274922
+ // TODO: update this to extract specific properties from
274923
+ // neuroglancerOptions as needed.
274924
+ ...layerData.neuroglancerOptions ?? {}
274925
+ }
274926
+ ]
274927
+ };
274928
+ });
274929
+ }
274930
+ });
274931
+ pointLayerScopes.forEach((layerScope) => {
274932
+ const layerCoordination = pointLayerCoordination[0][layerScope];
274933
+ const layerData = obsPointsData[layerScope];
274934
+ const layerUrl = obsPointsUrls[layerScope]?.[0]?.url;
274935
+ const featureIndex = pointMultiIndicesData[layerScope]?.featureIndex;
274936
+ if (layerUrl && layerData) {
274937
+ const { spatialLayerVisible, spatialLayerOpacity, obsColorEncoding, spatialLayerColor, featureSelection, featureFilterMode, featureColor } = layerCoordination || {};
274938
+ const shader = getPointsShader({
274939
+ theme,
274940
+ featureIndex,
274941
+ spatialLayerOpacity,
274942
+ obsColorEncoding,
274943
+ spatialLayerColor,
274944
+ featureSelection,
274945
+ featureFilterMode,
274946
+ featureColor,
274947
+ featureIndexProp: layerData.neuroglancerOptions?.featureIndexProp,
274948
+ pointIndexProp: layerData.neuroglancerOptions?.pointIndexProp
274949
+ });
274950
+ result = {
274951
+ ...result,
274952
+ layers: [
274953
+ ...result.layers,
274954
+ {
274955
+ type: "annotation",
274956
+ source: {
274957
+ url: toPrecomputedSource(layerUrl),
274958
+ subsources: {
274959
+ default: true
274960
+ },
274961
+ enableDefaultSubsources: false
274962
+ },
274963
+ tab: "annotations",
274964
+ shader,
274965
+ name: toNgLayerName(DataType$3.OBS_POINTS, layerScope),
274966
+ visible: spatialLayerVisible,
274967
+ // Options from layerData.neuroglancerOptions
274968
+ // like projectionAnnotationSpacing:
274969
+ projectionAnnotationSpacing: layerData.neuroglancerOptions?.projectionAnnotationSpacing ?? 1
274970
+ }
274971
+ ],
274972
+ // TODO: is this needed?
274973
+ // The selected layer here will overwrite anything
274974
+ // that was previously specified.
274975
+ selectedLayer: {
274976
+ // size: ? // TODO: is this needed?
274977
+ layer: toNgLayerName(DataType$3.OBS_POINTS, layerScope)
274978
+ }
274979
+ };
274980
+ }
274981
+ });
274982
+ return result;
274983
+ }, {
274984
+ theme,
274985
+ segmentationLayerScopes,
274986
+ segmentationChannelScopesByLayer,
274987
+ segmentationLayerCoordination,
274988
+ segmentationChannelCoordination,
274989
+ obsSegmentationsUrls,
274990
+ obsSegmentationsData,
274991
+ pointLayerScopes,
274992
+ pointLayerCoordination,
274993
+ obsPointsUrls,
274994
+ obsPointsData,
274995
+ pointMultiIndicesData
274996
+ }, customIsEqualForInitialViewerState);
274997
+ return viewerState;
274525
274998
  }
274526
274999
  /**
274527
275000
  * @license
@@ -304195,9 +304668,29 @@ function rgbToHex$1(rgb2) {
304195
304668
  return typeof rgb2 === "string" ? rgb2 : `#${rgb2.map((c2) => c2.toString(16).padStart(2, "0")).join("")}`;
304196
304669
  }
304197
304670
  function NeuroglancerSubscriber(props) {
304198
- const { coordinationScopes: coordinationScopesRaw, closeButtonVisible, downloadButtonVisible, removeGridComponent, theme, title: title2 = "Neuroglancer", helpText = ViewHelpMapping.NEUROGLANCER } = props;
304671
+ const {
304672
+ uuid: uuid2,
304673
+ coordinationScopes: coordinationScopesRaw,
304674
+ coordinationScopesBy: coordinationScopesByRaw,
304675
+ closeButtonVisible,
304676
+ downloadButtonVisible,
304677
+ removeGridComponent,
304678
+ theme,
304679
+ title: title2 = "Spatial",
304680
+ subtitle = "Powered by Neuroglancer",
304681
+ helpText = ViewHelpMapping.NEUROGLANCER,
304682
+ // Note: this is a temporary mechanism
304683
+ // to pass an initial NG camera state.
304684
+ // Ideally, all camera state should be passed via
304685
+ // the existing spatialZoom, spatialTargetX, spatialRotationOrbit, etc,
304686
+ // and then NeuroglancerSubscriber should internally convert
304687
+ // to NG-compatible values, which would eliminate the need for this.
304688
+ initialNgCameraState
304689
+ } = props;
304199
304690
  const loaders = useLoaders();
304691
+ const mergeCoordination = useMergeCoordination();
304200
304692
  const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
304693
+ const coordinationScopesBy = useCoordinationScopesBy(coordinationScopes, coordinationScopesByRaw);
304201
304694
  const [{
304202
304695
  dataset,
304203
304696
  obsType,
@@ -304227,11 +304720,129 @@ function NeuroglancerSubscriber(props) {
304227
304720
  setSpatialRotationOrbit: setRotationOrbit,
304228
304721
  setSpatialZoom: setZoom
304229
304722
  }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.NEUROGLANCER], coordinationScopes);
304723
+ const [ngWidth, ngHeight, containerRef] = useGridItemSize();
304724
+ const [segmentationLayerScopes, segmentationChannelScopesByLayer] = useMultiCoordinationScopesSecondaryNonNull(CoordinationType$1.SEGMENTATION_CHANNEL, CoordinationType$1.SEGMENTATION_LAYER, coordinationScopes, coordinationScopesBy);
304725
+ const pointLayerScopes = useMultiCoordinationScopesNonNull(CoordinationType$1.POINT_LAYER, coordinationScopes);
304726
+ const segmentationLayerCoordination = useComplexCoordination([
304727
+ CoordinationType$1.FILE_UID,
304728
+ CoordinationType$1.SEGMENTATION_CHANNEL,
304729
+ CoordinationType$1.SPATIAL_LAYER_VISIBLE,
304730
+ CoordinationType$1.SPATIAL_LAYER_OPACITY
304731
+ ], coordinationScopes, coordinationScopesBy, CoordinationType$1.SEGMENTATION_LAYER);
304732
+ const segmentationChannelCoordination = useComplexCoordinationSecondary([
304733
+ CoordinationType$1.OBS_TYPE,
304734
+ CoordinationType$1.SPATIAL_TARGET_C,
304735
+ CoordinationType$1.SPATIAL_CHANNEL_VISIBLE,
304736
+ CoordinationType$1.SPATIAL_CHANNEL_OPACITY,
304737
+ CoordinationType$1.SPATIAL_CHANNEL_COLOR,
304738
+ CoordinationType$1.SPATIAL_SEGMENTATION_FILLED,
304739
+ CoordinationType$1.SPATIAL_SEGMENTATION_STROKE_WIDTH,
304740
+ CoordinationType$1.OBS_COLOR_ENCODING,
304741
+ CoordinationType$1.FEATURE_SELECTION,
304742
+ CoordinationType$1.FEATURE_AGGREGATION_STRATEGY,
304743
+ CoordinationType$1.FEATURE_VALUE_COLORMAP,
304744
+ CoordinationType$1.FEATURE_VALUE_COLORMAP_RANGE,
304745
+ CoordinationType$1.OBS_SET_COLOR,
304746
+ CoordinationType$1.OBS_SET_SELECTION,
304747
+ CoordinationType$1.ADDITIONAL_OBS_SETS,
304748
+ CoordinationType$1.OBS_HIGHLIGHT,
304749
+ CoordinationType$1.TOOLTIPS_VISIBLE,
304750
+ CoordinationType$1.TOOLTIP_CROSSHAIRS_VISIBLE,
304751
+ CoordinationType$1.LEGEND_VISIBLE
304752
+ ], coordinationScopes, coordinationScopesBy, CoordinationType$1.SEGMENTATION_LAYER, CoordinationType$1.SEGMENTATION_CHANNEL);
304753
+ const pointLayerCoordination = useComplexCoordination([
304754
+ CoordinationType$1.OBS_TYPE,
304755
+ CoordinationType$1.SPATIAL_LAYER_VISIBLE,
304756
+ CoordinationType$1.SPATIAL_LAYER_OPACITY,
304757
+ CoordinationType$1.OBS_COLOR_ENCODING,
304758
+ CoordinationType$1.FEATURE_COLOR,
304759
+ CoordinationType$1.FEATURE_FILTER_MODE,
304760
+ CoordinationType$1.FEATURE_SELECTION,
304761
+ CoordinationType$1.FEATURE_VALUE_COLORMAP,
304762
+ CoordinationType$1.FEATURE_VALUE_COLORMAP_RANGE,
304763
+ CoordinationType$1.SPATIAL_LAYER_COLOR,
304764
+ CoordinationType$1.OBS_HIGHLIGHT,
304765
+ CoordinationType$1.TOOLTIPS_VISIBLE,
304766
+ CoordinationType$1.TOOLTIP_CROSSHAIRS_VISIBLE,
304767
+ CoordinationType$1.LEGEND_VISIBLE
304768
+ ], coordinationScopes, coordinationScopesBy, CoordinationType$1.POINT_LAYER);
304769
+ const [obsPointsData, obsPointsDataStatus, obsPointsUrls, obsPointsErrors] = useMultiObsPoints(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, uuid2);
304770
+ const [pointMultiIndicesData, pointMultiIndicesDataStatus, pointMultiIndicesDataErrors] = usePointMultiObsFeatureMatrixIndices(coordinationScopes, coordinationScopesBy, loaders, dataset);
304771
+ const [obsSegmentationsData, obsSegmentationsDataStatus, obsSegmentationsUrls, obsSegmentationsDataErrors] = useMultiObsSegmentations(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, uuid2);
304772
+ const [obsSegmentationsSetsData, obsSegmentationsSetsDataStatus, obsSegmentationsSetsDataErrors] = useSegmentationMultiObsSets(coordinationScopes, coordinationScopesBy, loaders, dataset);
304773
+ const [segmentationMultiExpressionData, segmentationMultiLoadedFeatureSelection, segmentationMultiExpressionExtents, segmentationMultiExpressionNormData, segmentationMultiFeatureSelectionStatus, segmentationMultiFeatureSelectionErrors] = useSegmentationMultiFeatureSelection(coordinationScopes, coordinationScopesBy, loaders, dataset);
304774
+ const [segmentationMultiIndicesData, segmentationMultiIndicesDataStatus, segmentationMultiIndicesDataErrors] = useSegmentationMultiObsFeatureMatrixIndices(coordinationScopes, coordinationScopesBy, loaders, dataset);
304775
+ const errors = [
304776
+ ...obsPointsErrors,
304777
+ ...obsSegmentationsDataErrors,
304778
+ ...obsSegmentationsSetsDataErrors,
304779
+ ...pointMultiIndicesDataErrors,
304780
+ ...segmentationMultiFeatureSelectionErrors,
304781
+ ...segmentationMultiIndicesDataErrors
304782
+ ];
304783
+ const isReady = useReady([
304784
+ // Points
304785
+ obsPointsDataStatus,
304786
+ pointMultiIndicesDataStatus,
304787
+ // Segmentations
304788
+ obsSegmentationsDataStatus,
304789
+ obsSegmentationsSetsDataStatus,
304790
+ segmentationMultiFeatureSelectionStatus,
304791
+ segmentationMultiIndicesDataStatus
304792
+ ]);
304230
304793
  const { classes: classes2 } = useStyles$5();
304231
- const [{ obsSets: cellSets }] = useObsSetsData(loaders, dataset, false, { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor }, { cellSetSelection, obsSetColor: cellSetColor }, { obsType });
304232
- const [{ obsIndex }] = useObsEmbeddingData(loaders, dataset, true, {}, {}, { obsType, embeddingType: mapping });
304233
- const [initalViewerState] = useNeuroglancerViewerState(loaders, dataset);
304234
- const latestViewerStateRef = useRef(initalViewerState);
304794
+ const segmentationColorMapping = useMemoCustomComparison(() => {
304795
+ const result = {};
304796
+ segmentationLayerScopes?.forEach((layerScope) => {
304797
+ result[layerScope] = {};
304798
+ segmentationChannelScopesByLayer?.[layerScope]?.forEach((channelScope) => {
304799
+ const { obsSets: layerSets, obsIndex: layerIndex } = obsSegmentationsSetsData?.[layerScope]?.[channelScope] || {};
304800
+ if (layerSets && layerIndex) {
304801
+ const { obsSetColor, obsColorEncoding, obsSetSelection, additionalObsSets } = segmentationChannelCoordination[0][layerScope][channelScope];
304802
+ const mergedCellSets = mergeObsSets(layerSets, additionalObsSets);
304803
+ const cellColors = getCellColors({
304804
+ cellSets: mergedCellSets,
304805
+ cellSetSelection: obsSetSelection,
304806
+ cellSetColor: obsSetColor,
304807
+ obsIndex: layerIndex,
304808
+ theme
304809
+ });
304810
+ const ngCellColors = {};
304811
+ cellColors.forEach((color2, i2) => {
304812
+ ngCellColors[i2] = rgbToHex$1(color2);
304813
+ });
304814
+ result[layerScope][channelScope] = ngCellColors;
304815
+ }
304816
+ });
304817
+ });
304818
+ return result;
304819
+ }, {
304820
+ // The dependencies for the comparison,
304821
+ // used by the custom equality function.
304822
+ segmentationLayerScopes,
304823
+ segmentationChannelScopesByLayer,
304824
+ obsSegmentationsSetsData,
304825
+ segmentationChannelCoordination,
304826
+ theme
304827
+ }, customIsEqualForCellColors);
304828
+ const initalViewerState = useNeuroglancerViewerState(theme, segmentationLayerScopes, segmentationChannelScopesByLayer, segmentationLayerCoordination, segmentationChannelCoordination, obsSegmentationsUrls, obsSegmentationsData, pointLayerScopes, pointLayerCoordination, obsPointsUrls, obsPointsData, pointMultiIndicesData);
304829
+ const [latestViewerStateIteration, incrementLatestViewerStateIteration] = useReducer((x2) => x2 + 1, 0);
304830
+ const latestViewerStateRef = useRef({
304831
+ ...initalViewerState,
304832
+ ...initialNgCameraState ?? {}
304833
+ });
304834
+ useEffect(() => {
304835
+ const prevNgCameraState = {
304836
+ position: latestViewerStateRef.current.position,
304837
+ projectionOrientation: latestViewerStateRef.current.projectionOrientation,
304838
+ projectionScale: latestViewerStateRef.current.projectionScale
304839
+ };
304840
+ latestViewerStateRef.current = {
304841
+ ...initalViewerState,
304842
+ ...prevNgCameraState
304843
+ };
304844
+ incrementLatestViewerStateIteration();
304845
+ }, [initalViewerState]);
304235
304846
  const initialRotationPushedRef = useRef(false);
304236
304847
  const ngRotPushAtRef = useRef(0);
304237
304848
  const lastInteractionSource = useRef(null);
@@ -304257,20 +304868,6 @@ function NeuroglancerSubscriber(props) {
304257
304868
  tx: spatialTargetX,
304258
304869
  ty: spatialTargetY
304259
304870
  });
304260
- const mergedCellSets = useMemo$1(() => mergeObsSets(cellSets, additionalCellSets), [cellSets, additionalCellSets]);
304261
- const cellColors = useMemo$1(() => getCellColors({
304262
- cellSets: mergedCellSets,
304263
- cellSetSelection,
304264
- cellSetColor,
304265
- obsIndex,
304266
- theme
304267
- }), [
304268
- mergedCellSets,
304269
- theme,
304270
- cellSetColor,
304271
- cellSetSelection,
304272
- obsIndex
304273
- ]);
304274
304871
  const handleStateUpdate = useCallback((newState) => {
304275
304872
  lastInteractionSource.current = LAST_INTERACTION_SOURCE.neuroglancer;
304276
304873
  const { projectionScale, projectionOrientation, position: position2 } = newState;
@@ -304362,25 +304959,12 @@ function NeuroglancerSubscriber(props) {
304362
304959
  setCellSetColor,
304363
304960
  setCellSetSelection
304364
304961
  ]);
304365
- const batchedUpdateTimeoutRef = useRef(null);
304366
- const [batchedCellColors, setBatchedCellColors] = useState(cellColors);
304367
- useEffect(() => {
304368
- if (batchedUpdateTimeoutRef.current) {
304369
- clearTimeout(batchedUpdateTimeoutRef.current);
304370
- }
304371
- batchedUpdateTimeoutRef.current = setTimeout(() => {
304372
- setBatchedCellColors(cellColors);
304373
- }, 100);
304374
- }, [cellColors]);
304375
- const cellColorMapping = useMemo$1(() => {
304376
- const colorMapping = {};
304377
- batchedCellColors.forEach((color2, cell2) => {
304378
- colorMapping[cell2] = rgbToHex$1(color2);
304379
- });
304380
- return colorMapping;
304381
- }, [batchedCellColors]);
304962
+ const cellColorMapping = useMemo$1(() => segmentationColorMapping?.[segmentationLayerScopes?.[0]]?.[segmentationChannelScopesByLayer?.[segmentationLayerScopes?.[0]]?.[0]] ?? {}, [segmentationColorMapping]);
304382
304963
  const derivedViewerState = useMemo$1(() => {
304383
304964
  const { current: current2 } = latestViewerStateRef;
304965
+ if (current2.layers.length <= 0) {
304966
+ return current2;
304967
+ }
304384
304968
  const nextSegments = Object.keys(cellColorMapping);
304385
304969
  const prevLayer = current2?.layers?.[0] || {};
304386
304970
  const prevSegments = prevLayer.segments || [];
@@ -304466,12 +305050,15 @@ function NeuroglancerSubscriber(props) {
304466
305050
  spatialRotationY,
304467
305051
  spatialRotationZ,
304468
305052
  spatialTargetX,
304469
- spatialTargetY
305053
+ spatialTargetY,
305054
+ initalViewerState,
305055
+ latestViewerStateIteration
304470
305056
  ]);
304471
305057
  const onSegmentHighlight = useCallback((obsId) => {
304472
305058
  setCellHighlight(String(obsId));
304473
- }, [obsIndex, setCellHighlight]);
304474
- return jsxRuntimeExports.jsx(TitleInfo, { title: title2, helpText, isSpatial: true, theme, closeButtonVisible, downloadButtonVisible, removeGridComponent, isReady: true, withPadding: false, children: jsxRuntimeExports.jsx(NeuroglancerComp, { classes: classes2, onSegmentClick, onSelectHoveredCoords: onSegmentHighlight, viewerState: derivedViewerState, cellColorMapping, setViewerState: handleStateUpdate }) });
305059
+ }, [setCellHighlight]);
305060
+ const hasLayers = derivedViewerState?.layers?.length > 0;
305061
+ return jsxRuntimeExports.jsx(TitleInfo, { title: title2, info: subtitle, helpText, isSpatial: true, theme, closeButtonVisible, downloadButtonVisible, removeGridComponent, isReady, errors, withPadding: false, children: jsxRuntimeExports.jsxs("div", { style: { position: "relative", width: "100%", height: "100%" }, ref: containerRef, children: [jsxRuntimeExports.jsx("div", { style: { position: "absolute", top: 0, right: 0, zIndex: 50 }, children: jsxRuntimeExports.jsx(MultiLegend, { theme: "dark", maxHeight: ngHeight, segmentationLayerScopes, segmentationLayerCoordination, segmentationChannelScopesByLayer, segmentationChannelCoordination }) }), hasLayers ? jsxRuntimeExports.jsx(NeuroglancerComp, { classes: classes2, onSegmentClick, onSelectHoveredCoords: onSegmentHighlight, viewerState: derivedViewerState, cellColorMapping, setViewerState: handleStateUpdate }) : null] }) });
304475
305062
  }
304476
305063
  const FEATURE_AGGREGATION_STRATEGIES = ["first", "last", "sum", "mean"];
304477
305064
  function CellSetExpressionPlotOptions(props) {
@@ -360317,7 +360904,7 @@ class ObsSpotsCsvLoader extends CsvLoader {
360317
360904
  const payload = await this.getSourceData();
360318
360905
  const coordinationValues = {
360319
360906
  spotLayer: CL({
360320
- obsType: "spot",
360907
+ obsType: this.coordinationValues?.obsType ?? "spot",
360321
360908
  // obsColorEncoding: 'spatialLayerColor',
360322
360909
  // spatialLayerColor: [255, 255, 255],
360323
360910
  spatialLayerVisible: true,
@@ -360357,7 +360944,7 @@ class ObsPointsCsvLoader extends CsvLoader {
360357
360944
  const payload = await this.getSourceData();
360358
360945
  const coordinationValues = {
360359
360946
  pointLayer: CL({
360360
- obsType: "point",
360947
+ obsType: this.coordinationValues?.obsType ?? "point",
360361
360948
  // obsColorEncoding: 'spatialLayerColor',
360362
360949
  // spatialLayerColor: [255, 255, 255],
360363
360950
  spatialLayerVisible: true,
@@ -361923,7 +362510,7 @@ class ObsSpotsAnndataLoader extends AbstractTwoStepLoader {
361923
362510
  const { path: path2 } = this.options;
361924
362511
  const coordinationValues = {
361925
362512
  spotLayer: CL({
361926
- obsType: "spot",
362513
+ obsType: this.coordinationValues?.obsType ?? "spot",
361927
362514
  // obsColorEncoding: 'spatialLayerColor',
361928
362515
  // spatialLayerColor: [255, 255, 255],
361929
362516
  spatialLayerVisible: true,
@@ -361967,7 +362554,7 @@ class ObsPointsAnndataLoader extends AbstractTwoStepLoader {
361967
362554
  const { path: path2 } = this.options;
361968
362555
  const coordinationValues = {
361969
362556
  pointLayer: CL({
361970
- obsType: "point",
362557
+ obsType: this.coordinationValues?.obsType ?? "point",
361971
362558
  // obsColorEncoding: 'spatialLayerColor',
361972
362559
  // spatialLayerColor: [255, 255, 255],
361973
362560
  spatialLayerVisible: true,
@@ -363454,7 +364041,7 @@ class SpatialDataObsSpotsLoader extends AbstractTwoStepLoader {
363454
364041
  const spatialSpotRadius = obsRadius?.data?.[0];
363455
364042
  const coordinationValues = {
363456
364043
  spotLayer: CL({
363457
- obsType: "spot",
364044
+ obsType: this.coordinationValues?.obsType ?? "spot",
363458
364045
  // obsColorEncoding: 'spatialLayerColor',
363459
364046
  // spatialLayerColor: [255, 255, 255],
363460
364047
  spatialLayerVisible: true,
@@ -363669,7 +364256,7 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
363669
364256
  ]);
363670
364257
  const coordinationValues = {
363671
364258
  pointLayer: CL({
363672
- obsType: "point",
364259
+ obsType: this.coordinationValues?.obsType ?? "point",
363673
364260
  obsColorEncoding: "spatialLayerColor",
363674
364261
  spatialLayerColor: [255, 255, 255],
363675
364262
  spatialLayerVisible: true,
@@ -363737,12 +364324,26 @@ class PrecomputedMeshSource {
363737
364324
  }
363738
364325
  }
363739
364326
  class PrecomputedMeshDataLoader extends AbstractTwoStepLoader {
363740
- /* eslint-disable class-methods-use-this */
363741
- async load(url) {
364327
+ async load() {
364328
+ const { url, options } = this;
363742
364329
  return new LoaderResult({
363743
364330
  obsIndex: null,
363744
364331
  obsSegmentations: {},
363745
- obsSegmentationsType: "mesh"
364332
+ obsSegmentationsType: "mesh",
364333
+ neuroglancerOptions: options
364334
+ }, url);
364335
+ }
364336
+ }
364337
+ class NgAnnotationPointsDataLoader extends AbstractTwoStepLoader {
364338
+ async load() {
364339
+ const { url, options } = this;
364340
+ return new LoaderResult({
364341
+ obsIndex: null,
364342
+ obsPoints: null,
364343
+ featureIds: null,
364344
+ obsPointsModelMatrix: null,
364345
+ obsPointsTilingType: "neuroglancer",
364346
+ neuroglancerOptions: options
363746
364347
  }, url);
363747
364348
  }
363748
364349
  }
@@ -385701,7 +386302,8 @@ const baseFileTypes = [
385701
386302
  ...makeZarrFileTypes(FileType$1.OBS_EMBEDDING_SPATIALDATA_ZARR, DataType$3.OBS_EMBEDDING, SpatialDataObsEmbeddingLoader, SpatialDataTableSource, obsEmbeddingSpatialdataSchema),
385702
386303
  ...makeZarrFileTypes(FileType$1.FEATURE_LABELS_SPATIALDATA_ZARR, DataType$3.FEATURE_LABELS, SpatialDataFeatureLabelsLoader, SpatialDataTableSource, featureLabelsAnndataSchema),
385703
386304
  makeFileType(FileType$1.OBS_SEGMENTATIONS_GLB, DataType$3.OBS_SEGMENTATIONS, GlbDataLoader, GlbSource, meshGlbSchema),
385704
- makeFileType(FileType$1.OBS_SEGMENTATIONS_NG_PRECOMPUTED, DataType$3.OBS_SEGMENTATIONS, PrecomputedMeshDataLoader, PrecomputedMeshSource, ngSchema),
386305
+ makeFileType(FileType$1.OBS_SEGMENTATIONS_NG_PRECOMPUTED, DataType$3.OBS_SEGMENTATIONS, PrecomputedMeshDataLoader, PrecomputedMeshSource, ngPrecomputedMeshSchema),
386306
+ makeFileType(FileType$1.OBS_POINTS_NG_ANNOTATIONS, DataType$3.OBS_POINTS, NgAnnotationPointsDataLoader, PrecomputedMeshSource, ngPointAnnotationSchema),
385705
386307
  // All legacy file types
385706
386308
  makeFileType(FileType$1.OBS_FEATURE_MATRIX_EXPRESSION_MATRIX_ZARR, DataType$3.OBS_FEATURE_MATRIX, MatrixZarrAsObsFeatureMatrixLoader, ZarrDataSource, z.null()),
385707
386309
  makeFileType(FileType$1.IMAGE_RASTER_JSON, DataType$3.IMAGE, RasterJsonAsImageLoader, JsonSource, rasterJsonSchema),