@vitessce/launcher 4.0.8 → 4.0.10

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.
@@ -9,7 +9,7 @@ var _inner;
9
9
  import * as React from "react";
10
10
  import React__default, { useState, useEffect, useCallback, useContext, forwardRef as forwardRef$1, useRef, useMemo as useMemo$1, createContext as createContext$1, createElement, isValidElement, cloneElement, Children, PureComponent, version as version$6, useLayoutEffect as useLayoutEffect$1, useImperativeHandle, Component as Component$1, useDeferredValue, Suspense, useReducer } from "react";
11
11
  import { jsx as jsx$1, jsxs, Fragment } from "react/jsx-runtime";
12
- import { useLoaders, useCoordinationScopes, useCoordination, useDescription, useImageData, useReady, TitleInfo, useVitessceContainer, useSetWarning, useObsSetsData, useUrls, usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useComponentHover, useComponentViewInfo, useSetComponentHover, useSetComponentViewInfo, useInitialCoordination, useDeckCanvasSize, useMultiObsLabels, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useExpandedFeatureLabelsMap, useSampleSetsData, useSampleEdgesData, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, useAuxiliaryCoordination, useHasLoader, useObsLocationsData, useObsLabelsData, useObsSegmentationsData, useNeighborhoodsData, useMergeCoordination, useCoordinationScopesBy, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationScopesNonNull, useComplexCoordination, useComplexCoordinationSecondary, useGridItemSize, useMultiObsPoints, usePointMultiObsLabels, usePointMultiObsFeatureMatrixIndices, useMultiObsSpots, useSpotMultiObsSets, useSpotMultiFeatureLabels, useSpotMultiFeatureSelection, useSpotMultiObsFeatureMatrixIndices, useSegmentationMultiObsLocations, useMultiObsSegmentations, useSegmentationMultiObsSets, useSegmentationMultiFeatureSelection, useSegmentationMultiObsFeatureMatrixIndices, useMultiImages, useObsFeatureMatrixData, useUint8ObsFeatureMatrix, useGetObsMembership, PopperMenu, useComponentLayout, useClosestVitessceContainerSize, useWindowDimensions, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes, useViewConfigStoreApi, useViewConfig, useSetViewConfig, createLoaders, useWarning, useGenomicProfilesData, shallowDiff, shallowDiffByChannelWithKeys, shallowDiffByLayer, shallowDiffByChannelCoordinationWithKeys, shallowDiffByChannel, shallowDiffByLayerCoordinationWithKeys, useMemoCustomComparison, useSegmentationMultiObsColors, useMatchingLoader, useColumnNameMapping, useFeatureStatsData, useObsSetStatsData, useAsyncFunction, useFeatureSetStatsData, useMultiCoordinationScopes, useComparisonMetadata, logConfig, VitSContainer, createOnDrop } from "@vitessce/vit-s";
12
+ import { useLoaders, useCoordinationScopes, useCoordination, useDescription, useImageData, useReady, TitleInfo, useVitessceContainer, useSetWarning, useObsSetsData, useUrls, usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useComponentHover, useComponentViewInfo, useViewMapping, useSetComponentHover, useSetComponentViewInfo, useAnnotationFrameCoordination, useInitialCoordination, useDeckCanvasSize, useAnnotationStoryData, useMultiObsLabels, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useExpandedFeatureLabelsMap, useSampleSetsData, useSampleEdgesData, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, useAuxiliaryCoordination, useHasLoader, useObsLocationsData, useObsLabelsData, useObsSegmentationsData, useNeighborhoodsData, useMergeCoordination, useCoordinationScopesBy, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationScopesNonNull, useComplexCoordination, useComplexCoordinationSecondary, useGridItemSize, useMultiObsPoints, usePointMultiObsLabels, usePointMultiObsFeatureMatrixIndices, useMultiObsSpots, useSpotMultiObsSets, useSpotMultiFeatureLabels, useSpotMultiFeatureSelection, useSpotMultiObsFeatureMatrixIndices, useSegmentationMultiObsLocations, useMultiObsSegmentations, useSegmentationMultiObsSets, useSegmentationMultiFeatureSelection, useSegmentationMultiObsFeatureMatrixIndices, useMultiImages, useObsFeatureMatrixData, useUint8ObsFeatureMatrix, useGetObsMembership, PopperMenu, useComponentLayout, useClosestVitessceContainerSize, useWindowDimensions, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes, useViewConfigStoreApi, useViewConfig, useSetViewConfig, createLoaders, useWarning, useGenomicProfilesData, shallowDiff, shallowDiffByChannelWithKeys, shallowDiffByLayer, shallowDiffByChannelCoordinationWithKeys, shallowDiffByChannel, shallowDiffByLayerCoordinationWithKeys, useMemoCustomComparison, useSegmentationMultiObsColors, useMatchingLoader, useColumnNameMapping, useFeatureStatsData, useObsSetStatsData, useAsyncFunction, useFeatureSetStatsData, useMultiCoordinationScopes, useComparisonMetadata, logConfig, VitSContainer, createOnDrop } from "@vitessce/vit-s";
13
13
  import * as ReactDOM from "react-dom";
14
14
  import ReactDOM__default, { createPortal } from "react-dom";
15
15
  function _mergeNamespaces(n3, m2) {
@@ -5196,7 +5196,7 @@ const latestFileDefSchema = z.object({
5196
5196
  options: fileOptionsSchema.optional(),
5197
5197
  requestInit: requestInit.optional(),
5198
5198
  // New: file def can have coordinationValues.
5199
- coordinationValues: z.record(z.string()).optional()
5199
+ coordinationValues: z.record(z.any()).optional()
5200
5200
  });
5201
5201
  const datasetsSchema1_0_13 = z.array(z.object({
5202
5202
  uid: z.string(),
@@ -5227,7 +5227,8 @@ const configSchema1_0_16 = configSchema1_0_13.extend({
5227
5227
  h: z.number().int().optional(),
5228
5228
  // Updates coordinationScopes and coordinationScopesBy
5229
5229
  coordinationScopes: componentCoordinationScopes.optional(),
5230
- coordinationScopesBy: componentCoordinationScopesBy.optional()
5230
+ coordinationScopesBy: componentCoordinationScopesBy.optional(),
5231
+ coordinationValues: z.record(z.any()).optional()
5231
5232
  }))
5232
5233
  });
5233
5234
  const configSchema1_0_17 = configSchema1_0_16.extend({
@@ -10113,7 +10114,8 @@ const ViewType$1 = {
10113
10114
  TREEMAP: "treemap",
10114
10115
  SAMPLE_SET_PAIR_MANAGER: "sampleSetPairManager",
10115
10116
  FEATURE_STATS_TABLE: "featureStatsTable",
10116
- SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector"
10117
+ SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector",
10118
+ ANNOTATION_CONTROLLER: "annotationController"
10117
10119
  };
10118
10120
  const DataType$3 = {
10119
10121
  OBS_LABELS: "obsLabels",
@@ -10134,7 +10136,8 @@ const DataType$3 = {
10134
10136
  COMPARISON_METADATA: "comparisonMetadata",
10135
10137
  FEATURE_STATS: "featureStats",
10136
10138
  FEATURE_SET_STATS: "featureSetStats",
10137
- OBS_SET_STATS: "obsSetStats"
10139
+ OBS_SET_STATS: "obsSetStats",
10140
+ ANNOTATION_STORY: "annotationStory"
10138
10141
  };
10139
10142
  const AsyncFunctionType = {
10140
10143
  // String input (rather than Node input)
@@ -10166,6 +10169,7 @@ const FileType$1 = {
10166
10169
  OBS_SETS_CSV: "obsSets.csv",
10167
10170
  OBS_SETS_JSON: "obsSets.json",
10168
10171
  SAMPLE_SETS_CSV: "sampleSets.csv",
10172
+ ANNOTATION_STORY_JSON: "annotationStory.json",
10169
10173
  // OME-Zarr
10170
10174
  IMAGE_OME_ZARR: "image.ome-zarr",
10171
10175
  OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
@@ -10450,7 +10454,15 @@ const CoordinationType$1 = {
10450
10454
  FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
10451
10455
  FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
10452
10456
  // Treemap
10453
- HIERARCHY_LEVELS: "hierarchyLevels"
10457
+ HIERARCHY_LEVELS: "hierarchyLevels",
10458
+ // Annotation frames
10459
+ ANNOTATION_STORY: "annotationStory",
10460
+ ANNOTATION_FRAME_INDEX: "annotationFrameIndex",
10461
+ ANNOTATION_SHAPES: "annotationShapes",
10462
+ ANNOTATION_OVERLAY_VISIBLE: "annotationOverlayVisible",
10463
+ ANNOTATION_TRANSITION_DURATION: "annotationTransitionDuration",
10464
+ ANNOTATION_SEMANTIC_ZOOM: "annotationSemanticZoom",
10465
+ ANNOTATION_EDITABLE: "annotationEditable"
10454
10466
  };
10455
10467
  const STATUS$1 = {
10456
10468
  SUCCESS: "success"
@@ -10482,7 +10494,8 @@ const ViewHelpMapping = {
10482
10494
  SAMPLE_SET_PAIR_MANAGER: "Select pairs of sample groups.",
10483
10495
  FEATURE_STATS_TABLE: "This table displays per-feature statistics, for example, from a differential expression test.",
10484
10496
  LAYER_CONTROLLER_BETA: "The spatial layer controller provides an interface for manipulating the visualization layers displayed in the spatial view.",
10485
- SPATIAL_BETA: "The spatial view displays (potentially layered) spatially-resolved data including RGB or multiplexed images, segmentations of observations (bitmask- or polygon-based), and/or points (e.g., representing FISH transcripts)."
10497
+ SPATIAL_BETA: "The spatial view displays (potentially layered) spatially-resolved data including RGB or multiplexed images, segmentations of observations (bitmask- or polygon-based), and/or points (e.g., representing FISH transcripts).",
10498
+ ANNOTATION_CONTROLLER: "The annotation controller displays a guided sequence of narrative frames, each with descriptive text and optional shapes (rectangles, lines, arrows, ellipses, or polygons)."
10486
10499
  };
10487
10500
  ({
10488
10501
  // For new file types
@@ -10498,6 +10511,7 @@ const ViewHelpMapping = {
10498
10511
  [FileType$1.OBS_SEGMENTATIONS_JSON]: DataType$3.OBS_SEGMENTATIONS,
10499
10512
  [FileType$1.OBS_SETS_CSV]: DataType$3.OBS_SETS,
10500
10513
  [FileType$1.OBS_SETS_JSON]: DataType$3.OBS_SETS,
10514
+ [FileType$1.ANNOTATION_STORY_JSON]: DataType$3.ANNOTATION_STORY,
10501
10515
  [FileType$1.IMAGE_OME_ZARR]: DataType$3.IMAGE,
10502
10516
  [FileType$1.OBS_SEGMENTATIONS_OME_ZARR]: DataType$3.OBS_SEGMENTATIONS,
10503
10517
  [FileType$1.OBS_FEATURE_MATRIX_ANNDATA_ZARR]: DataType$3.OBS_FEATURE_MATRIX,
@@ -10620,7 +10634,8 @@ const ViewHelpMapping = {
10620
10634
  [DataType$3.OBS_SET_STATS]: [
10621
10635
  CoordinationType$1.OBS_TYPE
10622
10636
  // TODO: should sampleType, obsSetSelection, and/or sampleSetSelection be used here?
10623
- ]
10637
+ ],
10638
+ [DataType$3.ANNOTATION_STORY]: []
10624
10639
  });
10625
10640
  const ALT_ZARR_STORE_TYPES = {
10626
10641
  // For AnnData:
@@ -10753,7 +10768,9 @@ const ALT_ZARR_STORE_TYPES = {
10753
10768
  CoordinationType$1.SPATIAL_TARGET_Z,
10754
10769
  CoordinationType$1.SPATIAL_AXIS_FIXED,
10755
10770
  CoordinationType$1.SPATIAL_ORBIT_AXIS,
10756
- CoordinationType$1.FEATURE_AGGREGATION_STRATEGY
10771
+ CoordinationType$1.FEATURE_AGGREGATION_STRATEGY,
10772
+ // Annotation shapes are specific to a view's coordinate system.
10773
+ CoordinationType$1.ANNOTATION_SHAPES
10757
10774
  ];
10758
10775
  const COMPONENT_COORDINATION_TYPES = {
10759
10776
  [ViewType$1.NEUROGLANCER]: [
@@ -10845,7 +10862,14 @@ const COMPONENT_COORDINATION_TYPES = {
10845
10862
  CoordinationType$1.EMBEDDING_CONTOURS_FILLED,
10846
10863
  CoordinationType$1.EMBEDDING_CONTOUR_PERCENTILES,
10847
10864
  CoordinationType$1.CONTOUR_COLOR_ENCODING,
10848
- CoordinationType$1.CONTOUR_COLOR
10865
+ CoordinationType$1.CONTOUR_COLOR,
10866
+ CoordinationType$1.ANNOTATION_STORY,
10867
+ CoordinationType$1.ANNOTATION_SHAPES,
10868
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10869
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10870
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10871
+ CoordinationType$1.ANNOTATION_EDITABLE,
10872
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10849
10873
  ],
10850
10874
  [ViewType$1.DUAL_SCATTERPLOT]: [
10851
10875
  CoordinationType$1.DATASET,
@@ -10961,7 +10985,14 @@ const COMPONENT_COORDINATION_TYPES = {
10961
10985
  CoordinationType$1.ADDITIONAL_OBS_SETS,
10962
10986
  CoordinationType$1.MOLECULE_HIGHLIGHT,
10963
10987
  CoordinationType$1.TOOLTIPS_VISIBLE,
10964
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10988
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
10989
+ CoordinationType$1.ANNOTATION_STORY,
10990
+ CoordinationType$1.ANNOTATION_SHAPES,
10991
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10992
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10993
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10994
+ CoordinationType$1.ANNOTATION_EDITABLE,
10995
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10965
10996
  ],
10966
10997
  [ViewType$1.SPATIAL_BETA]: [
10967
10998
  CoordinationType$1.META_COORDINATION_SCOPES,
@@ -11039,7 +11070,27 @@ const COMPONENT_COORDINATION_TYPES = {
11039
11070
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
11040
11071
  CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
11041
11072
  CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
11042
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
11073
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
11074
+ CoordinationType$1.ANNOTATION_STORY,
11075
+ CoordinationType$1.ANNOTATION_SHAPES,
11076
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
11077
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
11078
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
11079
+ CoordinationType$1.ANNOTATION_EDITABLE,
11080
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
11081
+ ],
11082
+ [ViewType$1.ANNOTATION_CONTROLLER]: [
11083
+ CoordinationType$1.DATASET,
11084
+ CoordinationType$1.ANNOTATION_STORY,
11085
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
11086
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
11087
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
11088
+ CoordinationType$1.ANNOTATION_EDITABLE,
11089
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
11090
+ // Note: the annotation controller also needs to read the coordination state
11091
+ // of all other views/coordination types via the full config.
11092
+ // Note: we get/set the CoordinationType.ANNOTATION_SHAPES from the full config,
11093
+ // as this info is view-specific rather than global to the story.
11043
11094
  ],
11044
11095
  [ViewType$1.HEATMAP]: [
11045
11096
  CoordinationType$1.DATASET,
@@ -12139,6 +12190,124 @@ const moleculesLayerObj = z.object({
12139
12190
  radius: z.number(),
12140
12191
  opacity: z.number()
12141
12192
  });
12193
+ const shapeBaseObj = z.object({
12194
+ uid: z.string(),
12195
+ text: z.string().optional(),
12196
+ strokeColor: z.array(z.number()).length(3).optional(),
12197
+ strokeWidth: z.number().optional(),
12198
+ // SVG-style dash pattern, e.g. "10 5" or "10 20 30 10". "none" or omitted = solid.
12199
+ strokeDashArray: z.string().optional(),
12200
+ visible: z.boolean().optional()
12201
+ // TODO: define unit modes for x and y axes
12202
+ // ("pixels" vs "normalized" vs "physical" etc.)
12203
+ // TODO: a coordinate system identifier (e.g., "DeckGL" for now,
12204
+ // but a coordinate system from OME-NGFF/SpatialData eventually?)
12205
+ });
12206
+ const rectangleShapeObj = shapeBaseObj.extend({
12207
+ type: z.literal("rectangle"),
12208
+ // OME-XML field names verbatim (upper-left origin)
12209
+ x: z.number(),
12210
+ y: z.number(),
12211
+ width: z.number(),
12212
+ height: z.number(),
12213
+ fillColor: z.array(z.number()).length(3).optional(),
12214
+ fillOpacity: z.number().optional()
12215
+ });
12216
+ const lineShapeObj = shapeBaseObj.extend({
12217
+ type: z.literal("line"),
12218
+ // OME-XML field names verbatim
12219
+ x1: z.number(),
12220
+ y1: z.number(),
12221
+ x2: z.number(),
12222
+ y2: z.number(),
12223
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
12224
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional(),
12225
+ textPosition: z.enum(["start", "middle", "end"]).optional(),
12226
+ textBufferPx: z.number().optional()
12227
+ });
12228
+ const ellipseShapeObj = shapeBaseObj.extend({
12229
+ type: z.literal("ellipse"),
12230
+ // OME-XML field names verbatim (centre point + radii)
12231
+ x1: z.number(),
12232
+ y1: z.number(),
12233
+ radiusX: z.number(),
12234
+ radiusY: z.number(),
12235
+ fillColor: z.array(z.number()).length(3).optional(),
12236
+ fillOpacity: z.number().optional()
12237
+ });
12238
+ const polygonShapeObj = shapeBaseObj.extend({
12239
+ type: z.literal("polygon"),
12240
+ // OME-XML: array of [x, y] coordinate pairs, closed automatically
12241
+ points: z.array(z.tuple([z.number(), z.number()])),
12242
+ fillColor: z.array(z.number()).length(3).optional(),
12243
+ fillOpacity: z.number().optional()
12244
+ });
12245
+ const polylineShapeObj = shapeBaseObj.extend({
12246
+ type: z.literal("polyline"),
12247
+ // OME-XML: array of [x, y] coordinate pairs, open (not closed)
12248
+ points: z.array(z.tuple([z.number(), z.number()])),
12249
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
12250
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional()
12251
+ });
12252
+ const annotationShapeObj = z.discriminatedUnion("type", [
12253
+ rectangleShapeObj,
12254
+ lineShapeObj,
12255
+ ellipseShapeObj,
12256
+ polygonShapeObj,
12257
+ polylineShapeObj
12258
+ ]);
12259
+ const annotationShapesArray = z.array(annotationShapeObj);
12260
+ const annotationFrameObj = z.object({
12261
+ uid: z.string(),
12262
+ title: z.string().optional(),
12263
+ description: z.string().optional(),
12264
+ descriptionType: z.enum(["text", "markdown"]).optional(),
12265
+ // A frame can define per-view: coordinationValues
12266
+ // (if the view's state should not be coordinated with other views)
12267
+ // or per-view coordinationScopes/coordinationScopesBy
12268
+ // (if at this frame, the view should be coordinated with other views).
12269
+ // We can also define a frame-level coordination space,
12270
+ // which will be merged with the global coordination space.
12271
+ // TODO: datasets
12272
+ // TODO: coordinationSpace
12273
+ layout: z.array(
12274
+ // Note: for now, we will infer view objects which have a uid
12275
+ // that is present in the global layout, and do NOT have x/y/w/h defined,
12276
+ // to mean that in this frame, the layout and set of views is unchanged
12277
+ // from the global layout.
12278
+ // This will allow each frame to omit the full list of views from the layout,
12279
+ // and only specify the views whose coordination state is changing in this frame.
12280
+ // If a frame includes a view with a uid that is not present
12281
+ // in the global layout, then that view will be added to the layout at this frame.
12282
+ // This frame should also define x/y/w/h for all views,
12283
+ // since it will otherwise be ambiguous how to layout the updated set of views
12284
+ // for this frame.
12285
+ z.object({
12286
+ // The view UID. If this view uid is not present in the global layout,
12287
+ // it will be added to the layout at this frame,
12288
+ // and will need to have its coordination values initialized to their defaults
12289
+ // for any that were not fully specified.
12290
+ uid: z.string(),
12291
+ coordinationValues: z.record(
12292
+ z.string(),
12293
+ // The coordination type name, e.g. "embeddingType"
12294
+ z.any()
12295
+ ).optional()
12296
+ // TODO: support coordinationScopes/coordinationScopesBy for per-view coordination
12297
+ // at this frame.
12298
+ // TODO: view x/y/w/h once we support view layout changes per-frame.
12299
+ })
12300
+ ).optional()
12301
+ });
12302
+ const annotationStoryObj = z.object({
12303
+ // TODO: schema version for the story schema?
12304
+ // Same as current Vitessce schema version?
12305
+ uid: z.string(),
12306
+ title: z.string().optional(),
12307
+ description: z.string().optional(),
12308
+ descriptionType: z.enum(["text", "markdown"]).optional(),
12309
+ frames: z.array(annotationFrameObj)
12310
+ });
12142
12311
  class PluginViewType {
12143
12312
  name;
12144
12313
  component;
@@ -19372,7 +19541,7 @@ const { tss } = createTss({
19372
19541
  },
19373
19542
  "usePlugin": useMuiThemeStyleOverridesPlugin
19374
19543
  });
19375
- const useStyles$A = tss.create({});
19544
+ const useStyles$B = tss.create({});
19376
19545
  function createChainedFunction$1(...funcs) {
19377
19546
  return funcs.reduce((acc, func) => {
19378
19547
  if (func == null) {
@@ -20483,7 +20652,7 @@ var values$5 = Object.values || function(obj) {
20483
20652
  return obj[k];
20484
20653
  });
20485
20654
  };
20486
- var defaultProps$Q = {
20655
+ var defaultProps$R = {
20487
20656
  component: "div",
20488
20657
  childFactory: function childFactory(child) {
20489
20658
  return child;
@@ -20610,7 +20779,7 @@ TransitionGroup.propTypes = {
20610
20779
  */
20611
20780
  childFactory: _pt.func
20612
20781
  };
20613
- TransitionGroup.defaultProps = defaultProps$Q;
20782
+ TransitionGroup.defaultProps = defaultProps$R;
20614
20783
  const UNINITIALIZED = {};
20615
20784
  function useLazyRef(init2, initArg) {
20616
20785
  const ref2 = React.useRef(UNINITIALIZED);
@@ -47286,6 +47455,12 @@ CardContent.propTypes = {
47286
47455
  const AddIcon = createSvgIcon(/* @__PURE__ */ jsx$1("path", {
47287
47456
  d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6z"
47288
47457
  }), "Add");
47458
+ const ArrowRight = createSvgIcon(/* @__PURE__ */ jsx$1("path", {
47459
+ d: "m10 17 5-5-5-5z"
47460
+ }), "ArrowRight");
47461
+ const ArrowLeft = createSvgIcon(/* @__PURE__ */ jsx$1("path", {
47462
+ d: "m14 7-5 5 5 5z"
47463
+ }), "ArrowLeft");
47289
47464
  const CenterFocusStrong = createSvgIcon(/* @__PURE__ */ jsx$1("path", {
47290
47465
  d: "M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4m-7 7H3v4c0 1.1.9 2 2 2h4v-2H5zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2m0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2z"
47291
47466
  }), "CenterFocusStrong");
@@ -74182,7 +74357,7 @@ const Popper = React.forwardRef((props, ref2) => {
74182
74357
  }, [handlePopperRef]);
74183
74358
  React.useImperativeHandle(popperRefProp, () => popperRef.current, []);
74184
74359
  const [exited, setExited] = React.useState(true);
74185
- const { theme } = useStyles$A();
74360
+ const { theme } = useStyles$B();
74186
74361
  const rtlPlacement = flipPlacement(initialPlacement, theme);
74187
74362
  const [placement, setPlacement] = React.useState(rtlPlacement);
74188
74363
  React.useEffect(() => {
@@ -74916,7 +75091,7 @@ var VariableSizeList$1 = /* @__PURE__ */ createListComponent({
74916
75091
  });
74917
75092
  const VariableSizeList = VariableSizeList$1;
74918
75093
  const LIST_ROW_HEIGHT$1 = 48;
74919
- const useStyles$z = makeStyles()(() => ({
75094
+ const useStyles$A = makeStyles()(() => ({
74920
75095
  searchInput: {
74921
75096
  lineHeight: "initial",
74922
75097
  height: "auto !important"
@@ -74956,7 +75131,7 @@ const ListboxComponent$1 = React__default.forwardRef((props, ref2) => {
74956
75131
  });
74957
75132
  function SimpleAutocomplete(props) {
74958
75133
  const { getMatches, onChange, textInputLabel = "Enter a gene", getItemLabel = (option) => option.label } = props;
74959
- const { classes: classes2 } = useStyles$z();
75134
+ const { classes: classes2 } = useStyles$A();
74960
75135
  const [potentialItems, setPotentialItems] = useState([]);
74961
75136
  const handleInputChange = async (_event, value2) => {
74962
75137
  if (!value2) {
@@ -84506,7 +84681,7 @@ function defaultUrlTransform(value2) {
84506
84681
  }
84507
84682
  return "";
84508
84683
  }
84509
- const useStyles$y = makeStyles()((theme) => ({
84684
+ const useStyles$z = makeStyles()((theme) => ({
84510
84685
  description: {
84511
84686
  "& p, details, table": {
84512
84687
  fontSize: "80%",
@@ -84543,7 +84718,7 @@ const useStyles$y = makeStyles()((theme) => ({
84543
84718
  }));
84544
84719
  function Description(props) {
84545
84720
  const { description: description2, metadata: metadata2, descriptionType } = props;
84546
- const { classes: classes2 } = useStyles$y();
84721
+ const { classes: classes2 } = useStyles$z();
84547
84722
  return jsxs("div", { className: classes2.description, children: [descriptionType && descriptionType === DescriptionType.MARKDOWN ? jsx$1(Markdown, { children: description2 }) : jsx$1("p", { children: description2 }), metadata2 && Array.from(metadata2.entries()).map(([layerIndex, { name: layerName, metadata: metadataRecord }]) => metadataRecord && Object.entries(metadataRecord).length > 0 ? jsxs("details", { children: [jsx$1("summary", { children: layerName }), jsx$1("div", { className: classes2.metadataContainer, children: jsx$1("table", { children: jsx$1("tbody", { children: Object.entries(metadataRecord).map(([key2, value2]) => jsxs("tr", { children: [jsx$1("th", { title: key2, children: key2 }), jsx$1("td", { title: value2, children: value2 })] }, key2)) }) }) })] }, layerIndex) : null)] });
84548
84723
  }
84549
84724
  function DescriptionSubscriber(props) {
@@ -95165,7 +95340,7 @@ const Tooltip$2 = /* @__PURE__ */ React.forwardRef((props, ref2) => {
95165
95340
  }, extraProps), getChildren());
95166
95341
  });
95167
95342
  const nodeHeight = 32;
95168
- const useStyles$x = makeStyles()((theme) => ({
95343
+ const useStyles$y = makeStyles()((theme) => ({
95169
95344
  setsManager: {
95170
95345
  position: "relative",
95171
95346
  width: "100%",
@@ -95332,7 +95507,7 @@ const useStyles$x = makeStyles()((theme) => ({
95332
95507
  }));
95333
95508
  function SetsManagerTreeGlobalStyles(props) {
95334
95509
  const { classes: classes2 } = props;
95335
- const { theme } = useStyles$A();
95510
+ const { theme } = useStyles$B();
95336
95511
  return jsx$1(ScopedGlobalStyles, { parentClassName: classes2.setsManagerTree, styles: {
95337
95512
  ".rc-tree": {
95338
95513
  paddingLeft: "0",
@@ -95673,7 +95848,7 @@ function HelpTooltipGlobalStyles(props) {
95673
95848
  }
95674
95849
  function PopoverGlobalStyles(props) {
95675
95850
  const { classes: classes2 } = props;
95676
- const { theme } = useStyles$A();
95851
+ const { theme } = useStyles$B();
95677
95852
  return jsx$1(ScopedGlobalStyles, { parentClassName: classes2.popover, styles: {
95678
95853
  ".rc-tooltip-inner": {
95679
95854
  boxSizing: "border-box",
@@ -100357,7 +100532,7 @@ function NamedSetNodeStatic(props) {
100357
100532
  const onClick = level === 0 && !expanded ? () => onCheckLevel(nodeKey, nextLevelToCheck) : () => onNodeView(path2);
100358
100533
  const tooltipProps = disableTooltip ? { visible: false } : {};
100359
100534
  const popoverMenuConfig = makeNodeViewMenuConfig(props);
100360
- const { classes: classes2 } = useStyles$x();
100535
+ const { classes: classes2 } = useStyles$y();
100361
100536
  return jsxs("span", { children: [jsx$1(HelpTooltip, { title: tooltipText, ...tooltipProps, children: jsx$1("button", { type: "button", onClick, onKeyPress: (e3) => callbackOnKeyPress(e3, "v", () => onNodeView(path2)), className: classes2.titleButton, children: title2 }) }), popoverMenuConfig.length > 0 ? jsx$1(PopoverMenu, { menuConfig: makeNodeViewMenuConfig(props), color: level > 0 && editable ? color2 || getDefaultColor(theme) : null, setColor: (c2) => onNodeSetColor(path2, c2), children: jsx$1("span", { children: jsx$1(SvgMenu, { className: classes2.nodeMenuIcon, "aria-label": "Open Node View Menu" }) }) }) : null, level > 0 && isChecking ? checkbox2 : null, level > 0 && jsx$1("span", { className: classes2.nodeSizeLabel, children: niceSize })] });
100362
100537
  }
100363
100538
  function NamedSetNodeEditing(props) {
@@ -100369,7 +100544,7 @@ function NamedSetNodeEditing(props) {
100369
100544
  onNodeSetName(path2, currentTitle, true);
100370
100545
  }
100371
100546
  }
100372
- const { classes: classes2 } = useStyles$x();
100547
+ const { classes: classes2 } = useStyles$y();
100373
100548
  return jsxs("span", { className: classes2.titleButtonWithInput, children: [jsx$1("input", {
100374
100549
  // eslint-disable-next-line jsx-a11y/no-autofocus
100375
100550
  autoFocus: true,
@@ -100395,7 +100570,7 @@ function LevelsButtons(props) {
100395
100570
  onCheckLevel(nodeKey, newLevel);
100396
100571
  }
100397
100572
  }
100398
- const { classes: classes2 } = useStyles$x();
100573
+ const { classes: classes2 } = useStyles$y();
100399
100574
  return jsx$1("div", { className: classes2.levelButtonsContainer, children: range$e(1, height2 + 1).map((i2) => {
100400
100575
  const isChecked = isEqual$3(path2, checkedLevelPath) && i2 === checkedLevelIndex;
100401
100576
  return jsx$1("div", { children: jsx$1(HelpTooltip, { title: getLevelTooltipText(i2), children: jsx$1("input", { className: clsx(classes2.levelRadioButton, { [classes2.levelRadioButtonChecked]: isChecked && !hasColorEncoding }), type: "checkbox", value: i2, checked: isChecked && hasColorEncoding, onChange: onCheck }) }) }, i2);
@@ -100479,7 +100654,7 @@ let TreeNode$1 = class TreeNode extends TreeNode$2 {
100479
100654
  };
100480
100655
  function PlusButton(props) {
100481
100656
  const { datatype, onError, onImportTree, onCreateLevelZeroNode, importable, editable } = props;
100482
- const { classes: classes2 } = useStyles$x();
100657
+ const { classes: classes2 } = useStyles$y();
100483
100658
  const onImport = useCallback((importHandler, mimeType) => () => {
100484
100659
  const uploadInputNode = document.createElement("input");
100485
100660
  uploadInputNode.setAttribute("type", "file");
@@ -100596,7 +100771,7 @@ function SetsManager(props) {
100596
100771
  }, onNodeCheckNewName, onNodeSetIsEditing: setIsEditingNodeName, onNodeRemove, onExportLevelZeroNodeJSON, onExportLevelZeroNodeTabular, onExportSetJSON, disableTooltip: isDragging, onDragStart: () => setIsDragging(true), onDragEnd: () => setIsDragging(false), children: renderTreeNodes(node2.children, readOnly, newPath) }, pathToKey$1(newPath));
100597
100772
  });
100598
100773
  }
100599
- const { classes: classes2 } = useStyles$x();
100774
+ const { classes: classes2 } = useStyles$y();
100600
100775
  return jsxs("div", { className: classes2.setsManager, children: [jsx$1(SetsManagerTreeGlobalStyles, { classes: classes2 }), jsxs("div", { className: classes2.setsManagerTree, children: [jsx$1(Tree$1, { draggable: false, checkable, checkedKeys: setSelectionKeys, expandedKeys: setExpansionKeys, autoExpandParent, onCheck: (checkedKeys, info2) => onCheckNode(info2.node.props.nodeKey, info2.checked), onExpand: (expandedKeys, info2) => onExpandNode(expandedKeys, info2.node.props.nodeKey, info2.expanded), children: renderTreeNodes(processedSets.tree, true, []) }), jsx$1(Tree$1, { draggable: true, checkable, checkedKeys: additionalSetSelectionKeys, expandedKeys: additionalSetExpansionKeys, autoExpandParent, onCheck: (checkedKeys, info2) => onCheckNode(info2.node.props.nodeKey, info2.checked), onExpand: (expandedKeys, info2) => onExpandNode(expandedKeys, info2.node.props.nodeKey, info2.expanded), onDrop: (info2) => {
100601
100776
  const { eventKey: dropKey } = info2.node.props;
100602
100777
  const { eventKey: dragKey } = info2.dragNode.props;
@@ -112967,6 +113142,12 @@ function multiply$4(out, a2, b2) {
112967
113142
  out[2] = a2[2] * b2[2];
112968
113143
  return out;
112969
113144
  }
113145
+ function distance$3(a2, b2) {
113146
+ var x2 = b2[0] - a2[0];
113147
+ var y2 = b2[1] - a2[1];
113148
+ var z2 = b2[2] - a2[2];
113149
+ return Math.hypot(x2, y2, z2);
113150
+ }
112970
113151
  function squaredLength$2(a2) {
112971
113152
  var x2 = a2[0];
112972
113153
  var y2 = a2[1];
@@ -113090,6 +113271,7 @@ function angle$3(a2, b2) {
113090
113271
  }
113091
113272
  var sub$1 = subtract$1;
113092
113273
  var mul$1 = multiply$4;
113274
+ var dist$1 = distance$3;
113093
113275
  var len = length$5;
113094
113276
  var sqrLen = squaredLength$2;
113095
113277
  (function() {
@@ -127560,7 +127742,7 @@ function noop$9() {
127560
127742
  const getCursor$1 = ({
127561
127743
  isDragging
127562
127744
  }) => isDragging ? "grabbing" : "grab";
127563
- const defaultProps$P = {
127745
+ const defaultProps$Q = {
127564
127746
  id: "",
127565
127747
  width: "100%",
127566
127748
  height: "100%",
@@ -127691,7 +127873,7 @@ class Deck {
127691
127873
  this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
127692
127874
  });
127693
127875
  this.props = {
127694
- ...defaultProps$P,
127876
+ ...defaultProps$Q,
127695
127877
  ...props
127696
127878
  };
127697
127879
  props = this.props;
@@ -128193,7 +128375,7 @@ class Deck {
128193
128375
  metrics.gpuMemory = memoryStats.get("GPU Memory").count;
128194
128376
  }
128195
128377
  }
128196
- _defineProperty$3(Deck, "defaultProps", defaultProps$P);
128378
+ _defineProperty$3(Deck, "defaultProps", defaultProps$Q);
128197
128379
  _defineProperty$3(Deck, "VERSION", deckGlobal.VERSION);
128198
128380
  class ShaderAttribute {
128199
128381
  constructor(dataColumn, opts2) {
@@ -130948,7 +131130,7 @@ const areViewportsEqual = memoize$3(({
130948
131130
  return oldViewport.equals(viewport2);
130949
131131
  });
130950
131132
  let pickingColorCache = new Uint8ClampedArray(0);
130951
- const defaultProps$O = {
131133
+ const defaultProps$P = {
130952
131134
  data: {
130953
131135
  type: "data",
130954
131136
  value: EMPTY_ARRAY$1,
@@ -131823,7 +132005,7 @@ class Layer extends Component {
131823
132005
  this.setNeedsUpdate();
131824
132006
  }
131825
132007
  }
131826
- _defineProperty$3(Layer, "defaultProps", defaultProps$O);
132008
+ _defineProperty$3(Layer, "defaultProps", defaultProps$P);
131827
132009
  _defineProperty$3(Layer, "layerName", "Layer");
131828
132010
  const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
131829
132011
  class CompositeLayer extends Layer {
@@ -132982,7 +133164,7 @@ const parameters = {
132982
133164
  blendEquation: [32774, 32774],
132983
133165
  depthTest: false
132984
133166
  };
132985
- const defaultProps$N = {
133167
+ const defaultProps$O = {
132986
133168
  getFilterValue: {
132987
133169
  type: "accessor",
132988
133170
  value: 0
@@ -133158,8 +133340,126 @@ class DataFilterExtension extends LayerExtension {
133158
133340
  }
133159
133341
  }
133160
133342
  }
133161
- _defineProperty$3(DataFilterExtension, "defaultProps", defaultProps$N);
133343
+ _defineProperty$3(DataFilterExtension, "defaultProps", defaultProps$O);
133162
133344
  _defineProperty$3(DataFilterExtension, "extensionName", "DataFilterExtension");
133345
+ const dashShaders = {
133346
+ inject: {
133347
+ "vs:#decl": "\nattribute vec2 instanceDashArrays;\nattribute float instanceDashOffsets;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n",
133348
+ "vs:#main-end": "\nvDashArray = instanceDashArrays;\nvDashOffset = instanceDashOffsets / width.x;\n",
133349
+ "fs:#decl": "\nuniform float dashAlignMode;\nuniform float capType;\nuniform bool dashGapPickable;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n\nfloat round(float x) {\n return floor(x + 0.5);\n}\n",
133350
+ "fs:#main-start": "\n float solidLength = vDashArray.x;\n float gapLength = vDashArray.y;\n float unitLength = solidLength + gapLength;\n\n float offset;\n\n if (unitLength > 0.0) {\n if (dashAlignMode == 0.0) {\n offset = vDashOffset;\n } else {\n unitLength = vPathLength / round(vPathLength / unitLength);\n offset = solidLength / 2.0;\n }\n\n float unitOffset = mod(clamp(vPathPosition.y, 0.0, vPathLength) + offset, unitLength);\n\n if (gapLength > 0.0 && unitOffset > solidLength) {\n if (capType <= 0.5) {\n if (!(dashGapPickable && picking_uActive)) {\n discard;\n }\n } else {\n // caps are rounded, test the distance to solid ends\n float distToEnd = length(vec2(\n min(unitOffset - solidLength, unitLength - unitOffset),\n vPathPosition.x\n ));\n if (distToEnd > 1.0) {\n if (!(dashGapPickable && picking_uActive)) {\n discard;\n }\n }\n }\n }\n }\n"
133351
+ }
133352
+ };
133353
+ const offsetShaders = {
133354
+ inject: {
133355
+ "vs:#decl": "\nattribute float instanceOffsets;\n",
133356
+ "vs:DECKGL_FILTER_SIZE": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n size *= offsetWidth;\n",
133357
+ "vCornerOffset = offsetVec;": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n vec2 offsetCenter = -instanceOffsets * (isCap ? perp : miterVec * miterSize) * 2.0;\n vCornerOffset = vCornerOffset * offsetWidth - offsetCenter;\n",
133358
+ "fs:#main-start": "\n float isInside;\n isInside = step(-1.0, vPathPosition.x) * step(vPathPosition.x, 1.0);\n if (isInside == 0.0) {\n discard;\n }\n"
133359
+ }
133360
+ };
133361
+ const defaultProps$N = {
133362
+ getDashArray: {
133363
+ type: "accessor",
133364
+ value: [0, 0]
133365
+ },
133366
+ getOffset: {
133367
+ type: "accessor",
133368
+ value: 0
133369
+ },
133370
+ dashJustified: false,
133371
+ dashGapPickable: false
133372
+ };
133373
+ class PathStyleExtension extends LayerExtension {
133374
+ constructor({
133375
+ dash: dash2 = false,
133376
+ offset: offset2 = false,
133377
+ highPrecisionDash = false
133378
+ } = {}) {
133379
+ super({
133380
+ dash: dash2 || highPrecisionDash,
133381
+ offset: offset2,
133382
+ highPrecisionDash
133383
+ });
133384
+ }
133385
+ isEnabled(layer) {
133386
+ return "pathTesselator" in layer.state;
133387
+ }
133388
+ getShaders(extension2) {
133389
+ if (!extension2.isEnabled(this)) {
133390
+ return null;
133391
+ }
133392
+ let result = {};
133393
+ if (extension2.opts.dash) {
133394
+ result = mergeShaders(result, dashShaders);
133395
+ }
133396
+ if (extension2.opts.offset) {
133397
+ result = mergeShaders(result, offsetShaders);
133398
+ }
133399
+ return result;
133400
+ }
133401
+ initializeState(context2, extension2) {
133402
+ const attributeManager = this.getAttributeManager();
133403
+ if (!attributeManager || !extension2.isEnabled(this)) {
133404
+ return;
133405
+ }
133406
+ if (extension2.opts.dash) {
133407
+ attributeManager.addInstanced({
133408
+ instanceDashArrays: {
133409
+ size: 2,
133410
+ accessor: "getDashArray"
133411
+ }
133412
+ });
133413
+ }
133414
+ if (extension2.opts.highPrecisionDash) {
133415
+ attributeManager.addInstanced({
133416
+ instanceDashOffsets: {
133417
+ size: 1,
133418
+ accessor: "getPath",
133419
+ transform: extension2.getDashOffsets.bind(this)
133420
+ }
133421
+ });
133422
+ }
133423
+ if (extension2.opts.offset) {
133424
+ attributeManager.addInstanced({
133425
+ instanceOffsets: {
133426
+ size: 1,
133427
+ accessor: "getOffset"
133428
+ }
133429
+ });
133430
+ }
133431
+ }
133432
+ updateState(params2, extension2) {
133433
+ if (!extension2.isEnabled(this)) {
133434
+ return;
133435
+ }
133436
+ const uniforms = {};
133437
+ if (extension2.opts.dash) {
133438
+ uniforms.dashAlignMode = this.props.dashJustified ? 1 : 0;
133439
+ uniforms.dashGapPickable = Boolean(this.props.dashGapPickable);
133440
+ }
133441
+ this.state.model.setUniforms(uniforms);
133442
+ }
133443
+ getDashOffsets(path2) {
133444
+ const result = [0];
133445
+ const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
133446
+ const isNested2 = Array.isArray(path2[0]);
133447
+ const geometrySize = isNested2 ? path2.length : path2.length / positionSize;
133448
+ let p;
133449
+ let prevP;
133450
+ for (let i2 = 0; i2 < geometrySize - 1; i2++) {
133451
+ p = isNested2 ? path2[i2] : path2.slice(i2 * positionSize, i2 * positionSize + positionSize);
133452
+ p = this.projectPosition(p);
133453
+ if (i2 > 0) {
133454
+ result[i2] = result[i2 - 1] + dist$1(prevP, p);
133455
+ }
133456
+ prevP = p;
133457
+ }
133458
+ return result;
133459
+ }
133460
+ }
133461
+ _defineProperty$3(PathStyleExtension, "defaultProps", defaultProps$N);
133462
+ _defineProperty$3(PathStyleExtension, "extensionName", "PathStyleExtension");
133163
133463
  const defaultProps$M = {
133164
133464
  clipBounds: [0, 0, 1, 1]
133165
133465
  };
@@ -206578,22 +206878,22 @@ async function getDecoder(fileDirectory) {
206578
206878
  const Decoder = await importFn();
206579
206879
  return new Decoder(fileDirectory);
206580
206880
  }
206581
- addDecoder([void 0, 1], () => import("./raw-BwfqFKnC.js").then((m2) => m2.default));
206582
- addDecoder(5, () => import("./lzw-C3J5vfxA.js").then((m2) => m2.default));
206881
+ addDecoder([void 0, 1], () => import("./raw-Dj68nKkt.js").then((m2) => m2.default));
206882
+ addDecoder(5, () => import("./lzw-qFTDY_99.js").then((m2) => m2.default));
206583
206883
  addDecoder(6, () => {
206584
206884
  throw new Error("old style JPEG compression is not supported.");
206585
206885
  });
206586
- addDecoder(7, () => import("./jpeg-BPOKuzw4.js").then((m2) => m2.default));
206587
- addDecoder([8, 32946], () => import("./deflate-VkbGW_mo.js").then((m2) => m2.default));
206588
- addDecoder(32773, () => import("./packbits-DQbepi9i.js").then((m2) => m2.default));
206886
+ addDecoder(7, () => import("./jpeg-CEf0iZx_.js").then((m2) => m2.default));
206887
+ addDecoder([8, 32946], () => import("./deflate-CfZSfJdV.js").then((m2) => m2.default));
206888
+ addDecoder(32773, () => import("./packbits-CuKfEitB.js").then((m2) => m2.default));
206589
206889
  addDecoder(
206590
206890
  34887,
206591
- () => import("./lerc-BFyulmkx.js").then(async (m2) => {
206891
+ () => import("./lerc-Cj4x7L9q.js").then(async (m2) => {
206592
206892
  await m2.zstd.init();
206593
206893
  return m2;
206594
206894
  }).then((m2) => m2.default)
206595
206895
  );
206596
- addDecoder(50001, () => import("./webimage-BLWky4cY.js").then((m2) => m2.default));
206896
+ addDecoder(50001, () => import("./webimage-DzOyYQvp.js").then((m2) => m2.default));
206597
206897
  function copyNewSize(array2, width2, height2, samplesPerPixel = 1) {
206598
206898
  return new (Object.getPrototypeOf(array2)).constructor(width2 * height2 * samplesPerPixel);
206599
206899
  }
@@ -217089,7 +217389,7 @@ function padColors({ colors: colors2, channelsVisible }) {
217089
217389
  ).reduce((acc, val) => acc.concat(val), []);
217090
217390
  return paddedColors;
217091
217391
  }
217092
- const defaultProps$3$1 = {
217392
+ const defaultProps$3$2 = {
217093
217393
  colors: { type: "array", value: null, compare: true },
217094
217394
  opacity: { type: "number", value: 1, compare: true },
217095
217395
  transparentColor: { type: "array", value: null, compare: true },
@@ -217106,9 +217406,9 @@ const ColorPaletteExtension = class extends LayerExtension {
217106
217406
  const {
217107
217407
  colors: colors2,
217108
217408
  channelsVisible,
217109
- opacity: opacity2 = defaultProps$3$1.opacity.value,
217110
- transparentColor = defaultProps$3$1.transparentColor.value,
217111
- useTransparentColor = defaultProps$3$1.useTransparentColor.value
217409
+ opacity: opacity2 = defaultProps$3$2.opacity.value,
217410
+ transparentColor = defaultProps$3$2.transparentColor.value,
217411
+ useTransparentColor = defaultProps$3$2.useTransparentColor.value
217112
217412
  } = this.props;
217113
217413
  const paddedColors = padColors({
217114
217414
  channelsVisible: channelsVisible || this.selections.map(() => true),
@@ -217124,7 +217424,7 @@ const ColorPaletteExtension = class extends LayerExtension {
217124
217424
  }
217125
217425
  };
217126
217426
  ColorPaletteExtension.extensionName = "ColorPaletteExtension";
217127
- ColorPaletteExtension.defaultProps = defaultProps$3$1;
217427
+ ColorPaletteExtension.defaultProps = defaultProps$3$2;
217128
217428
  const fs$4 = `// lens bounds for ellipse
217129
217429
  uniform float majorLensAxis;
217130
217430
  uniform float minorLensAxis;
@@ -218426,7 +218726,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
218426
218726
  };
218427
218727
  MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
218428
218728
  MultiscaleImageLayer.defaultProps = defaultProps$4;
218429
- const defaultProps$3 = {
218729
+ const defaultProps$3$1 = {
218430
218730
  pickable: { type: "boolean", value: true, compare: true },
218431
218731
  loader: {
218432
218732
  type: "object",
@@ -218513,7 +218813,7 @@ const OverviewLayer = class extends CompositeLayer {
218513
218813
  }
218514
218814
  };
218515
218815
  OverviewLayer.layerName = "OverviewLayer";
218516
- OverviewLayer.defaultProps = defaultProps$3;
218816
+ OverviewLayer.defaultProps = defaultProps$3$1;
218517
218817
  function getPosition$1(boundingBox, position2, length2) {
218518
218818
  const viewWidth2 = boundingBox[2][0] - boundingBox[0][0];
218519
218819
  const viewHeight2 = boundingBox[2][1] - boundingBox[0][1];
@@ -219526,7 +219826,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
219526
219826
  }
219527
219827
  return newArr;
219528
219828
  }
219529
- const defaultProps$2 = {
219829
+ const defaultProps$3 = {
219530
219830
  hoveredCell: { type: "number", value: null, compare: true },
219531
219831
  // We do not want to deep-compare cellColorData,
219532
219832
  // as it is potentially a TypedArray with millions of elements.
@@ -219643,7 +219943,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
219643
219943
  }
219644
219944
  };
219645
219945
  BitmaskLayer$1.layerName = "BitmaskLayer";
219646
- BitmaskLayer$1.defaultProps = defaultProps$2;
219946
+ BitmaskLayer$1.defaultProps = defaultProps$3;
219647
219947
  const vs = `
219648
219948
  #define SHADER_NAME bitmask-layer-vertex-shader
219649
219949
 
@@ -219985,7 +220285,7 @@ function isEqualShallow(prevArr, nextArr) {
219985
220285
  }
219986
220286
  return prevArr === nextArr;
219987
220287
  }
219988
- const defaultProps$1 = {
220288
+ const defaultProps$2 = {
219989
220289
  channelStrokeWidths: { type: "array", value: null, compare: true },
219990
220290
  channelsFilled: { type: "array", value: null, compare: true },
219991
220291
  channelOpacities: { type: "array", value: null, compare: true },
@@ -220249,7 +220549,7 @@ class BitmaskLayer2 extends XRLayer {
220249
220549
  }
220250
220550
  }
220251
220551
  BitmaskLayer2.layerName = "BitmaskLayer";
220252
- BitmaskLayer2.defaultProps = defaultProps$1;
220552
+ BitmaskLayer2.defaultProps = defaultProps$2;
220253
220553
  var isNumeric$2 = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, mathceil = Math.ceil, mathfloor$1 = Math.floor, bignumberError = "[BigNumber Error] ", tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ", BASE$1 = 1e14, LOG_BASE$1 = 14, MAX_SAFE_INTEGER$3 = 9007199254740991, POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, MAX$1 = 1e9;
220254
220554
  function clone$3(configObject) {
220255
220555
  var div2, convertBase2, parseNumeric, P2 = BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }, ONE = new BigNumber2(1), DECIMAL_PLACES = 20, ROUNDING_MODE = 4, TO_EXP_NEG = -7, TO_EXP_POS = 21, MIN_EXP = -1e7, MAX_EXP = 1e7, CRYPTO = false, MODULO_MODE = 1, POW_PRECISION = 0, FORMAT = {
@@ -223192,7 +223492,7 @@ function ringArea(coords) {
223192
223492
  return total * FACTOR;
223193
223493
  }
223194
223494
  const DEFAULT_THRESHOLD = 1;
223195
- const defaultProps = {
223495
+ const defaultProps$1 = {
223196
223496
  // for text
223197
223497
  obsSetPath: { type: "object" },
223198
223498
  sampleSetPath: { type: "object" },
@@ -223366,8 +223666,1078 @@ class ContourLayerWithText extends ContourLayer {
223366
223666
  }
223367
223667
  }
223368
223668
  ContourLayerWithText.layerName = "ContourLayerWithText";
223369
- ContourLayerWithText.defaultProps = defaultProps;
223370
- const useStyles$w = makeStyles()(() => ({
223669
+ ContourLayerWithText.defaultProps = defaultProps$1;
223670
+ const ARROW_SCREEN_PX = 14;
223671
+ const LABEL_FONT_FAMILY$1 = '"Roboto", "Helvetica", "Arial", sans-serif';
223672
+ const LABEL_FONT_WEIGHT = "bold";
223673
+ const LABEL_FONT_SIZE = 14;
223674
+ const RATIO_CLUSTER = 0.1;
223675
+ const RATIO_DOT = 0.3;
223676
+ const RATIO_GEO_FADE = 0.55;
223677
+ const RATIO_TIPS = 0.7;
223678
+ const RATIO_LABEL = 0.55;
223679
+ const RATIO_LABEL_FULL = 0.75;
223680
+ function textBgColor(strokeColor) {
223681
+ const [r3, g2, b2] = strokeColor;
223682
+ const lum = (0.299 * r3 + 0.587 * g2 + 0.114 * b2) / 255;
223683
+ return lum > 0.45 ? [20, 20, 20, 210] : [245, 245, 245, 210];
223684
+ }
223685
+ function parseDashArray(strokeDashArray) {
223686
+ if (!strokeDashArray || strokeDashArray === "none")
223687
+ return null;
223688
+ const nums = strokeDashArray.trim().split(/\s+/).map(Number).filter((n3) => !Number.isNaN(n3) && n3 >= 0);
223689
+ return nums.length >= 2 ? [nums[0], nums[1]] : null;
223690
+ }
223691
+ function computeEllipsePolygon(cx, cy, rx, ry, numSegments = 64) {
223692
+ const pts = [];
223693
+ for (let i2 = 0; i2 < numSegments; i2++) {
223694
+ const angle2 = 2 * Math.PI * i2 / numSegments;
223695
+ pts.push([cx + rx * Math.cos(angle2), cy + ry * Math.sin(angle2)]);
223696
+ }
223697
+ return pts;
223698
+ }
223699
+ function createPreviewLayer(inProgress, hoverCoord, strokeColor = [255, 255, 0]) {
223700
+ if (!inProgress || inProgress.vertices.length === 0)
223701
+ return null;
223702
+ const { type: type2, vertices } = inProgress;
223703
+ const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
223704
+ const previewColor = [...strokeColor, 160];
223705
+ const cursor2 = hoverCoord ?? vertices[vertices.length - 1];
223706
+ if (type2 === "rectangle" && vertices.length === 1) {
223707
+ const [ax, ay] = vertices[0];
223708
+ const [bx, by] = cursor2;
223709
+ const path2 = [[ax, ay], [bx, ay], [bx, by], [ax, by], [ax, ay]];
223710
+ return new PathLayer({
223711
+ ...base2,
223712
+ id: "annotation-preview-rectangle",
223713
+ data: [{ path: path2 }],
223714
+ getPath: (d) => d.path,
223715
+ getColor: previewColor,
223716
+ getWidth: 1,
223717
+ widthUnits: "pixels",
223718
+ extensions: [new PathStyleExtension({ dash: true })],
223719
+ getDashArray: [8, 4]
223720
+ });
223721
+ }
223722
+ if (type2 === "line" && vertices.length === 1) {
223723
+ const path2 = [vertices[0], cursor2];
223724
+ return new PathLayer({
223725
+ ...base2,
223726
+ id: "annotation-preview-line",
223727
+ data: [{ path: path2 }],
223728
+ getPath: (d) => d.path,
223729
+ getColor: previewColor,
223730
+ getWidth: 1,
223731
+ widthUnits: "pixels",
223732
+ extensions: [new PathStyleExtension({ dash: true })],
223733
+ getDashArray: [8, 4]
223734
+ });
223735
+ }
223736
+ if (type2 === "ellipse" && vertices.length === 1) {
223737
+ const [cx, cy] = vertices[0];
223738
+ const [ex, ey] = cursor2;
223739
+ const rx = Math.abs(ex - cx);
223740
+ const ry = Math.abs(ey - cy);
223741
+ if (rx < 1 && ry < 1)
223742
+ return null;
223743
+ const pts = computeEllipsePolygon(cx, cy, Math.max(rx, 1), Math.max(ry, 1));
223744
+ const path2 = [...pts, pts[0]];
223745
+ return new PathLayer({
223746
+ ...base2,
223747
+ id: "annotation-preview-ellipse",
223748
+ data: [{ path: path2 }],
223749
+ getPath: (d) => d.path,
223750
+ getColor: previewColor,
223751
+ getWidth: 1,
223752
+ widthUnits: "pixels",
223753
+ extensions: [new PathStyleExtension({ dash: true })],
223754
+ getDashArray: [8, 4]
223755
+ });
223756
+ }
223757
+ if ((type2 === "polygon" || type2 === "polyline") && vertices.length >= 1) {
223758
+ const path2 = [...vertices, cursor2];
223759
+ if (type2 === "polygon" && vertices.length >= 2)
223760
+ path2.push(vertices[0]);
223761
+ return new PathLayer({
223762
+ ...base2,
223763
+ id: `annotation-preview-${type2}`,
223764
+ data: [{ path: path2 }],
223765
+ getPath: (d) => d.path,
223766
+ getColor: previewColor,
223767
+ getWidth: 1,
223768
+ widthUnits: "pixels",
223769
+ jointRounded: true,
223770
+ capRounded: true,
223771
+ extensions: [new PathStyleExtension({ dash: true })],
223772
+ getDashArray: [8, 4]
223773
+ });
223774
+ }
223775
+ return null;
223776
+ }
223777
+ function computeTickCap(tipX, tipY, dirX, dirY, dataSize) {
223778
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
223779
+ if (len2 === 0)
223780
+ return null;
223781
+ const ux = dirX / len2;
223782
+ const uy = dirY / len2;
223783
+ const px2 = -uy;
223784
+ const py2 = ux;
223785
+ const half = dataSize * 0.55;
223786
+ return [
223787
+ [tipX + px2 * half, tipY + py2 * half],
223788
+ [tipX - px2 * half, tipY - py2 * half]
223789
+ ];
223790
+ }
223791
+ function computeArrowhead(tipX, tipY, dirX, dirY, dataSize) {
223792
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
223793
+ if (len2 === 0)
223794
+ return null;
223795
+ const ux = dirX / len2;
223796
+ const uy = dirY / len2;
223797
+ const px2 = -uy;
223798
+ const py2 = ux;
223799
+ const halfBase = dataSize * 0.4;
223800
+ const bx = tipX - ux * dataSize;
223801
+ const by = tipY - uy * dataSize;
223802
+ return [
223803
+ [tipX, tipY],
223804
+ [bx + px2 * halfBase, by + py2 * halfBase],
223805
+ [bx - px2 * halfBase, by - py2 * halfBase]
223806
+ ];
223807
+ }
223808
+ function fmtCommas(n3) {
223809
+ return Math.round(n3).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
223810
+ }
223811
+ function getMeasurementLabel(shape2, physicalPixelSize, viewType = ViewType$1.SPATIAL) {
223812
+ const pps = physicalPixelSize;
223813
+ const px2 = pps?.x ?? 1;
223814
+ const py2 = pps?.y ?? 1;
223815
+ const unit2 = pps ? pps.unit ?? "" : null;
223816
+ const hasPhys = !!pps;
223817
+ const isEmbedding = viewType === ViewType$1.SCATTERPLOT;
223818
+ const fmtDist = (d) => {
223819
+ if (hasPhys)
223820
+ return `${d.toFixed(2)} ${unit2}`;
223821
+ if (isEmbedding)
223822
+ return d.toFixed(2);
223823
+ return `${fmtCommas(d)} px`;
223824
+ };
223825
+ const fmtArea = (a2) => {
223826
+ if (hasPhys)
223827
+ return `${a2.toFixed(2)} ${unit2}²`;
223828
+ if (isEmbedding)
223829
+ return a2.toFixed(2);
223830
+ return `${fmtCommas(a2)} px²`;
223831
+ };
223832
+ if (shape2.type === "line") {
223833
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
223834
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
223835
+ const dist2 = hasPhys ? Math.sqrt((dx * px2) ** 2 + (dy * py2) ** 2) : Math.sqrt(dx * dx + dy * dy);
223836
+ return fmtDist(dist2);
223837
+ }
223838
+ if (shape2.type === "rectangle") {
223839
+ return fmtArea(hasPhys ? Math.abs(shape2.width ?? 0) * px2 * Math.abs(shape2.height ?? 0) * py2 : Math.abs((shape2.width ?? 0) * (shape2.height ?? 0)));
223840
+ }
223841
+ if (shape2.type === "ellipse") {
223842
+ const rx = Math.abs(shape2.radiusX ?? 0);
223843
+ const ry = Math.abs(shape2.radiusY ?? 0);
223844
+ return fmtArea(hasPhys ? Math.PI * rx * px2 * ry * py2 : Math.PI * rx * ry);
223845
+ }
223846
+ if (shape2.type === "polygon" && shape2.points?.length >= 3) {
223847
+ const pts = shape2.points;
223848
+ let shoelace = 0;
223849
+ for (let i2 = 0; i2 < pts.length; i2++) {
223850
+ const [ax, ay] = pts[i2];
223851
+ const [bx, by] = pts[(i2 + 1) % pts.length];
223852
+ shoelace += (hasPhys ? ax * px2 : ax) * (hasPhys ? by * py2 : by) - (hasPhys ? bx * px2 : bx) * (hasPhys ? ay * py2 : ay);
223853
+ }
223854
+ return fmtArea(Math.abs(shoelace / 2));
223855
+ }
223856
+ if (shape2.type === "polyline" && shape2.points?.length >= 2) {
223857
+ let total = 0;
223858
+ for (let i2 = 0; i2 < shape2.points.length - 1; i2++) {
223859
+ const [ax, ay] = shape2.points[i2];
223860
+ const [bx, by] = shape2.points[i2 + 1];
223861
+ total += hasPhys ? Math.sqrt(((bx - ax) * px2) ** 2 + ((by - ay) * py2) ** 2) : Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2);
223862
+ }
223863
+ return fmtDist(total);
223864
+ }
223865
+ return null;
223866
+ }
223867
+ function pickBelowPerp(ux, uy) {
223868
+ const rp = [uy, -ux];
223869
+ const lp = [-uy, ux];
223870
+ return rp[1] > lp[1] || rp[1] === lp[1] && rp[0] > lp[0] ? rp : lp;
223871
+ }
223872
+ function readableAngle(deg) {
223873
+ let a2 = deg;
223874
+ if (a2 > 90)
223875
+ a2 -= 180;
223876
+ if (a2 < -90)
223877
+ a2 += 180;
223878
+ return a2;
223879
+ }
223880
+ function getShapeCentroid(shape2) {
223881
+ if (shape2.type === "rectangle") {
223882
+ return [(shape2.x ?? 0) + (shape2.width ?? 0) / 2, (shape2.y ?? 0) + (shape2.height ?? 0) / 2];
223883
+ }
223884
+ if (shape2.type === "line") {
223885
+ return [((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2, ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2];
223886
+ }
223887
+ if (shape2.type === "ellipse") {
223888
+ return [shape2.x1 ?? 0, shape2.y1 ?? 0];
223889
+ }
223890
+ if ((shape2.type === "polygon" || shape2.type === "polyline") && shape2.points?.length >= 1) {
223891
+ const mx = shape2.points.reduce((s2, p) => s2 + p[0], 0) / shape2.points.length;
223892
+ const my = shape2.points.reduce((s2, p) => s2 + p[1], 0) / shape2.points.length;
223893
+ return [mx, my];
223894
+ }
223895
+ return [0, 0];
223896
+ }
223897
+ function computeClusters(shapeList, zoom2, cellPx = 50) {
223898
+ const cellSize = cellPx / 2 ** Math.floor(zoom2);
223899
+ const cells = /* @__PURE__ */ new Map();
223900
+ shapeList.forEach(({ shape: shape2 }) => {
223901
+ const [cx, cy] = getShapeCentroid(shape2);
223902
+ const key2 = `${Math.floor(cx / cellSize)},${Math.floor(cy / cellSize)}`;
223903
+ if (!cells.has(key2)) {
223904
+ cells.set(key2, { sumX: 0, sumY: 0, count: 0, color: shape2.strokeColor ?? [255, 255, 255] });
223905
+ }
223906
+ const c2 = cells.get(key2);
223907
+ c2.sumX += cx;
223908
+ c2.sumY += cy;
223909
+ c2.count++;
223910
+ });
223911
+ return Array.from(cells.values()).map((c2) => ({
223912
+ position: [c2.sumX / c2.count, c2.sumY / c2.count, 0],
223913
+ count: c2.count,
223914
+ color: c2.color
223915
+ }));
223916
+ }
223917
+ function createAnnotationLayers(shapes = [], zoom2 = 0, selectedShapeUid = null, physicalPixelSize = null, authoredZoom = null, semanticZoom = true, viewType = ViewType$1.SPATIAL) {
223918
+ const selectionLayers = [];
223919
+ if (selectedShapeUid) {
223920
+ const sel = shapes.find((s2) => s2.uid === selectedShapeUid);
223921
+ if (sel) {
223922
+ const { uid: sUid, type: sType, strokeWidth: sStrokeWidth = 3 } = sel;
223923
+ const haloColor = [255, 220, 50, 70];
223924
+ const haloWidth = Math.max(sStrokeWidth + 8, 10);
223925
+ const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
223926
+ if (sType === "rectangle") {
223927
+ const { x: x2, y: y2, width: width2, height: height2 } = sel;
223928
+ selectionLayers.push(new PathLayer({
223929
+ ...base2,
223930
+ id: `annotation-select-${sUid}`,
223931
+ data: [{
223932
+ path: [
223933
+ [x2, y2],
223934
+ [x2 + width2, y2],
223935
+ [x2 + width2, y2 + height2],
223936
+ [x2, y2 + height2],
223937
+ [x2, y2]
223938
+ ]
223939
+ }],
223940
+ getPath: (d) => d.path,
223941
+ getColor: haloColor,
223942
+ getWidth: haloWidth,
223943
+ widthUnits: "pixels",
223944
+ jointRounded: true,
223945
+ capRounded: true
223946
+ }));
223947
+ }
223948
+ if (sType === "line") {
223949
+ const { x1: x12, y1: y12, x2, y2 } = sel;
223950
+ selectionLayers.push(new PathLayer({
223951
+ ...base2,
223952
+ id: `annotation-select-${sUid}`,
223953
+ data: [{ path: [[x12, y12], [x2, y2]] }],
223954
+ getPath: (d) => d.path,
223955
+ getColor: haloColor,
223956
+ getWidth: haloWidth,
223957
+ widthUnits: "pixels",
223958
+ capRounded: true
223959
+ }));
223960
+ }
223961
+ if (sType === "ellipse") {
223962
+ const polygon2 = computeEllipsePolygon(sel.x1, sel.y1, sel.radiusX, sel.radiusY);
223963
+ selectionLayers.push(new PathLayer({
223964
+ ...base2,
223965
+ id: `annotation-select-${sUid}`,
223966
+ data: [{ path: [...polygon2, polygon2[0]] }],
223967
+ getPath: (d) => d.path,
223968
+ getColor: haloColor,
223969
+ getWidth: haloWidth,
223970
+ widthUnits: "pixels",
223971
+ jointRounded: true
223972
+ }));
223973
+ }
223974
+ if (sType === "polygon" && sel.points?.length >= 3) {
223975
+ selectionLayers.push(new PathLayer({
223976
+ ...base2,
223977
+ id: `annotation-select-${sUid}`,
223978
+ data: [{ path: [...sel.points, sel.points[0]] }],
223979
+ getPath: (d) => d.path,
223980
+ getColor: haloColor,
223981
+ getWidth: haloWidth,
223982
+ widthUnits: "pixels",
223983
+ jointRounded: true
223984
+ }));
223985
+ }
223986
+ if (sType === "polyline" && sel.points?.length >= 2) {
223987
+ selectionLayers.push(new PathLayer({
223988
+ ...base2,
223989
+ id: `annotation-select-${sUid}`,
223990
+ data: [{ path: sel.points }],
223991
+ getPath: (d) => d.path,
223992
+ getColor: haloColor,
223993
+ getWidth: haloWidth,
223994
+ widthUnits: "pixels",
223995
+ jointRounded: true,
223996
+ capRounded: true
223997
+ }));
223998
+ }
223999
+ }
224000
+ }
224001
+ const layers = [];
224002
+ const dotShapes = [];
224003
+ const clusterDotShapes = [];
224004
+ shapes.forEach((shape2, i2) => {
224005
+ const { uid: uid2, type: type2, strokeColor = [255, 255, 255], strokeWidth = 3, strokeDashArray } = shape2;
224006
+ const isSelected = uid2 === selectedShapeUid;
224007
+ let shapeOpacity = 1;
224008
+ let tipsOpacity = 1;
224009
+ let labelOpacity = 0;
224010
+ if (isSelected || !semanticZoom || authoredZoom === null) {
224011
+ tipsOpacity = 1;
224012
+ labelOpacity = 1;
224013
+ } else {
224014
+ const zoomRatio = 2 ** (zoom2 - authoredZoom);
224015
+ if (zoomRatio < RATIO_CLUSTER) {
224016
+ clusterDotShapes.push({ shape: shape2 });
224017
+ return;
224018
+ }
224019
+ if (zoomRatio < RATIO_DOT) {
224020
+ dotShapes.push({ shape: shape2, alpha: 200 });
224021
+ return;
224022
+ }
224023
+ if (zoomRatio < RATIO_GEO_FADE) {
224024
+ const t4 = (zoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
224025
+ shapeOpacity = t4;
224026
+ dotShapes.push({ shape: shape2, alpha: Math.round((1 - t4) * 200) });
224027
+ }
224028
+ tipsOpacity = zoomRatio >= RATIO_TIPS ? shapeOpacity : Math.max(0, (zoomRatio - RATIO_GEO_FADE) / (RATIO_TIPS - RATIO_GEO_FADE) * shapeOpacity);
224029
+ if (zoomRatio >= RATIO_LABEL_FULL) {
224030
+ labelOpacity = shapeOpacity;
224031
+ } else if (zoomRatio >= RATIO_LABEL) {
224032
+ labelOpacity = (zoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL) * shapeOpacity;
224033
+ }
224034
+ }
224035
+ const arrowDataSize = Math.max(ARROW_SCREEN_PX, strokeWidth * 4) / 2 ** zoom2;
224036
+ const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: shapeOpacity };
224037
+ const tipsBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: tipsOpacity };
224038
+ const labelBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: labelOpacity };
224039
+ const labelBgProps = shape2.labelBackground ? {
224040
+ background: true,
224041
+ getBackgroundColor: textBgColor(strokeColor),
224042
+ backgroundPadding: [3, 1, 3, 2]
224043
+ } : {};
224044
+ const labelProps = { ...labelBgProps };
224045
+ const dashArray = parseDashArray(strokeDashArray);
224046
+ const dashExt = [new PathStyleExtension({ dash: true })];
224047
+ const getDash = dashArray ?? [0, 0];
224048
+ if (type2 === "rectangle") {
224049
+ const { x: x2, y: y2, width: width2, height: height2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
224050
+ const filled = fillOpacity > 0;
224051
+ const rectPolygon = [[x2, y2], [x2 + width2, y2], [x2 + width2, y2 + height2], [x2, y2 + height2]];
224052
+ layers.push(new PolygonLayer({
224053
+ ...base2,
224054
+ id: `annotation-rect-${uid2}-${i2}`,
224055
+ data: [{ polygon: rectPolygon }],
224056
+ getPolygon: (d) => d.polygon,
224057
+ filled,
224058
+ stroked: true,
224059
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
224060
+ getLineColor: strokeColor,
224061
+ getLineWidth: strokeWidth,
224062
+ lineWidthUnits: "pixels",
224063
+ ...dashArray ? {
224064
+ extensions: [new PathStyleExtension({ dash: true })],
224065
+ getDashArray: dashArray
224066
+ } : {}
224067
+ }));
224068
+ if (shape2.text && labelOpacity > 0) {
224069
+ layers.push(new TextLayer({
224070
+ ...labelBase,
224071
+ ...labelProps,
224072
+ id: `annotation-rect-text-${uid2}-${i2}`,
224073
+ data: [{ position: [x2, y2], text: shape2.text }],
224074
+ getPosition: (d) => d.position,
224075
+ getText: (d) => d.text,
224076
+ getColor: strokeColor,
224077
+ getSize: LABEL_FONT_SIZE,
224078
+ sizeUnits: "pixels",
224079
+ fontFamily: LABEL_FONT_FAMILY$1,
224080
+ fontWeight: LABEL_FONT_WEIGHT,
224081
+ getPixelOffset: [3, -7],
224082
+ getTextAnchor: "start",
224083
+ getAlignmentBaseline: "bottom"
224084
+ }));
224085
+ }
224086
+ }
224087
+ if (type2 === "line") {
224088
+ const { x1: x12, y1: y12, x2, y2, markerStart, markerEnd } = shape2;
224089
+ const dx = x2 - x12;
224090
+ const dy = y2 - y12;
224091
+ const len2 = Math.sqrt(dx * dx + dy * dy);
224092
+ const ux = len2 > 0 ? dx / len2 : 0;
224093
+ const uy = len2 > 0 ? dy / len2 : 0;
224094
+ const srcX = markerStart === "Arrow" ? x12 + ux * arrowDataSize : x12;
224095
+ const srcY = markerStart === "Arrow" ? y12 + uy * arrowDataSize : y12;
224096
+ const tgtX = markerEnd === "Arrow" ? x2 - ux * arrowDataSize : x2;
224097
+ const tgtY = markerEnd === "Arrow" ? y2 - uy * arrowDataSize : y2;
224098
+ layers.push(new PathLayer({
224099
+ ...base2,
224100
+ id: `annotation-line-${uid2}-${i2}`,
224101
+ extensions: [new PathStyleExtension({ dash: true })],
224102
+ getDashArray: dashArray ?? [0, 0],
224103
+ data: [{ path: [[srcX, srcY], [tgtX, tgtY]] }],
224104
+ getPath: (d) => d.path,
224105
+ getColor: strokeColor,
224106
+ getWidth: strokeWidth,
224107
+ widthUnits: "pixels",
224108
+ capRounded: true
224109
+ }));
224110
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
224111
+ const head = computeArrowhead(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
224112
+ if (head) {
224113
+ layers.push(new PolygonLayer({
224114
+ ...tipsBase,
224115
+ id: `annotation-end-arrow-${uid2}-${i2}`,
224116
+ data: [{ polygon: head }],
224117
+ getPolygon: (d) => d.polygon,
224118
+ filled: true,
224119
+ stroked: false,
224120
+ getFillColor: strokeColor
224121
+ }));
224122
+ }
224123
+ }
224124
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
224125
+ const head = computeArrowhead(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
224126
+ if (head) {
224127
+ layers.push(new PolygonLayer({
224128
+ ...tipsBase,
224129
+ id: `annotation-start-arrow-${uid2}-${i2}`,
224130
+ data: [{ polygon: head }],
224131
+ getPolygon: (d) => d.polygon,
224132
+ filled: true,
224133
+ stroked: false,
224134
+ getFillColor: strokeColor
224135
+ }));
224136
+ }
224137
+ }
224138
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
224139
+ const tick2 = computeTickCap(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
224140
+ if (tick2) {
224141
+ layers.push(new PathLayer({
224142
+ ...tipsBase,
224143
+ id: `annotation-end-tick-${uid2}-${i2}`,
224144
+ data: [{ path: tick2 }],
224145
+ getPath: (d) => d.path,
224146
+ getColor: strokeColor,
224147
+ getWidth: strokeWidth,
224148
+ widthUnits: "pixels",
224149
+ capRounded: true
224150
+ }));
224151
+ }
224152
+ }
224153
+ if (markerStart === "Tick" && tipsOpacity > 0) {
224154
+ const tick2 = computeTickCap(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
224155
+ if (tick2) {
224156
+ layers.push(new PathLayer({
224157
+ ...tipsBase,
224158
+ id: `annotation-start-tick-${uid2}-${i2}`,
224159
+ data: [{ path: tick2 }],
224160
+ getPath: (d) => d.path,
224161
+ getColor: strokeColor,
224162
+ getWidth: strokeWidth,
224163
+ widthUnits: "pixels",
224164
+ capRounded: true
224165
+ }));
224166
+ }
224167
+ }
224168
+ if (shape2.text) {
224169
+ const pos = shape2.textPosition ?? "start";
224170
+ let textX;
224171
+ let textY;
224172
+ if (pos === "start") {
224173
+ textX = x12;
224174
+ textY = y12;
224175
+ } else if (pos === "end") {
224176
+ textX = x2;
224177
+ textY = y2;
224178
+ } else {
224179
+ textX = (x12 + x2) / 2;
224180
+ textY = (y12 + y2) / 2;
224181
+ }
224182
+ let pixelOffset = [0, 0];
224183
+ let textAnchor = "middle";
224184
+ let alignmentBaseline = "center";
224185
+ if (pos !== "middle") {
224186
+ const dxT = x2 - x12;
224187
+ const dyT = y2 - y12;
224188
+ const lenT = Math.sqrt(dxT * dxT + dyT * dyT);
224189
+ if (lenT > 0) {
224190
+ const uxT = dxT / lenT;
224191
+ const uyT = dyT / lenT;
224192
+ const sign2 = pos === "start" ? -1 : 1;
224193
+ const bufferPx = shape2.textBufferPx ?? 8;
224194
+ const offsetX = sign2 * uxT * bufferPx;
224195
+ const offsetY = sign2 * uyT * bufferPx;
224196
+ pixelOffset = [offsetX, offsetY];
224197
+ const absX = Math.abs(offsetX);
224198
+ const absY = Math.abs(offsetY);
224199
+ if (absX >= absY) {
224200
+ textAnchor = offsetX > 0 ? "start" : "end";
224201
+ }
224202
+ if (absY >= absX) {
224203
+ alignmentBaseline = offsetY > 0 ? "top" : "bottom";
224204
+ }
224205
+ }
224206
+ } else if (len2 > 0) {
224207
+ const belowPerp = pickBelowPerp(ux, uy);
224208
+ const bufferPx = shape2.textBufferPx ?? 14;
224209
+ pixelOffset = [-belowPerp[0] * bufferPx, -belowPerp[1] * bufferPx];
224210
+ textAnchor = "middle";
224211
+ alignmentBaseline = "center";
224212
+ }
224213
+ const middleAngle = pos === "middle" && len2 > 0 ? -readableAngle(Math.atan2(dy, dx) * 180 / Math.PI) : null;
224214
+ if (labelOpacity <= 0)
224215
+ return;
224216
+ layers.push(new TextLayer({
224217
+ ...labelBase,
224218
+ ...labelProps,
224219
+ id: `annotation-line-text-${uid2}-${i2}`,
224220
+ data: [{ position: [textX, textY], text: shape2.text }],
224221
+ getPosition: (d) => d.position,
224222
+ getText: (d) => d.text,
224223
+ getColor: strokeColor,
224224
+ getSize: LABEL_FONT_SIZE,
224225
+ sizeUnits: "pixels",
224226
+ fontFamily: LABEL_FONT_FAMILY$1,
224227
+ fontWeight: LABEL_FONT_WEIGHT,
224228
+ getPixelOffset: pixelOffset,
224229
+ getTextAnchor: textAnchor,
224230
+ getAlignmentBaseline: alignmentBaseline,
224231
+ ...middleAngle !== null && { getAngle: middleAngle }
224232
+ }));
224233
+ }
224234
+ }
224235
+ if (type2 === "ellipse") {
224236
+ const { x1: x12, y1: y12, radiusX, radiusY, fillColor = strokeColor, fillOpacity = 0 } = shape2;
224237
+ const polygon2 = computeEllipsePolygon(x12, y12, radiusX, radiusY);
224238
+ const filled = fillOpacity > 0;
224239
+ layers.push(new PolygonLayer({
224240
+ ...base2,
224241
+ id: `annotation-ellipse-${uid2}-${i2}`,
224242
+ data: [{ polygon: polygon2 }],
224243
+ getPolygon: (d) => d.polygon,
224244
+ filled,
224245
+ stroked: true,
224246
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
224247
+ getLineColor: strokeColor,
224248
+ getLineWidth: strokeWidth,
224249
+ lineWidthUnits: "pixels",
224250
+ ...dashArray ? {
224251
+ extensions: [new PathStyleExtension({ dash: true })],
224252
+ getDashArray: dashArray
224253
+ } : {}
224254
+ }));
224255
+ if (shape2.text && labelOpacity > 0) {
224256
+ layers.push(new TextLayer({
224257
+ ...labelBase,
224258
+ ...labelProps,
224259
+ id: `annotation-ellipse-text-${uid2}-${i2}`,
224260
+ data: [{ position: [x12, y12 - radiusY], text: shape2.text }],
224261
+ getPosition: (d) => d.position,
224262
+ getText: (d) => d.text,
224263
+ getColor: strokeColor,
224264
+ getSize: LABEL_FONT_SIZE,
224265
+ sizeUnits: "pixels",
224266
+ fontFamily: LABEL_FONT_FAMILY$1,
224267
+ fontWeight: LABEL_FONT_WEIGHT,
224268
+ getPixelOffset: [0, -4],
224269
+ getTextAnchor: "middle",
224270
+ getAlignmentBaseline: "bottom"
224271
+ }));
224272
+ }
224273
+ }
224274
+ if (type2 === "polygon") {
224275
+ const { points: points2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
224276
+ if (!points2 || points2.length < 3)
224277
+ return;
224278
+ const closedPath = [...points2, points2[0]];
224279
+ if (fillOpacity > 0) {
224280
+ layers.push(new PolygonLayer({
224281
+ ...base2,
224282
+ id: `annotation-polygon-fill-${uid2}-${i2}`,
224283
+ data: [{ polygon: points2 }],
224284
+ getPolygon: (d) => d.polygon,
224285
+ stroked: false,
224286
+ filled: true,
224287
+ getFillColor: [...fillColor, Math.round(fillOpacity * 255)]
224288
+ }));
224289
+ }
224290
+ layers.push(new PathLayer({
224291
+ ...base2,
224292
+ id: `annotation-polygon-${uid2}-${i2}`,
224293
+ extensions: dashExt,
224294
+ getDashArray: getDash,
224295
+ data: [{ path: closedPath }],
224296
+ getPath: (d) => d.path,
224297
+ getColor: strokeColor,
224298
+ getWidth: strokeWidth,
224299
+ widthUnits: "pixels",
224300
+ jointRounded: true
224301
+ }));
224302
+ if (shape2.text && labelOpacity > 0) {
224303
+ const minX = Math.min(...points2.map((p) => p[0]));
224304
+ const maxX = Math.max(...points2.map((p) => p[0]));
224305
+ const minY = Math.min(...points2.map((p) => p[1]));
224306
+ const topCenterX = (minX + maxX) / 2;
224307
+ layers.push(new TextLayer({
224308
+ ...labelBase,
224309
+ ...labelProps,
224310
+ id: `annotation-polygon-text-${uid2}-${i2}`,
224311
+ data: [{ position: [topCenterX, minY], text: shape2.text }],
224312
+ getPosition: (d) => d.position,
224313
+ getText: (d) => d.text,
224314
+ getColor: strokeColor,
224315
+ getSize: LABEL_FONT_SIZE,
224316
+ sizeUnits: "pixels",
224317
+ fontFamily: LABEL_FONT_FAMILY$1,
224318
+ fontWeight: LABEL_FONT_WEIGHT,
224319
+ getPixelOffset: [0, -4],
224320
+ getTextAnchor: "middle",
224321
+ getAlignmentBaseline: "bottom"
224322
+ }));
224323
+ }
224324
+ }
224325
+ if (type2 === "polyline") {
224326
+ const { points: points2, markerStart, markerEnd } = shape2;
224327
+ if (!points2 || points2.length < 2)
224328
+ return;
224329
+ let pathPoints = points2;
224330
+ if (markerStart === "Arrow") {
224331
+ const [x02, y02] = points2[0];
224332
+ const [x12, y12] = points2[1];
224333
+ const dx = x02 - x12;
224334
+ const dy = y02 - y12;
224335
+ const len2 = Math.sqrt(dx * dx + dy * dy);
224336
+ if (len2 > 0) {
224337
+ const ux = dx / len2;
224338
+ const uy = dy / len2;
224339
+ pathPoints = [[x02 - ux * arrowDataSize, y02 - uy * arrowDataSize], ...pathPoints.slice(1)];
224340
+ }
224341
+ }
224342
+ if (markerEnd === "Arrow") {
224343
+ const last = pathPoints[pathPoints.length - 1];
224344
+ const prev2 = pathPoints[pathPoints.length - 2];
224345
+ const dx = last[0] - prev2[0];
224346
+ const dy = last[1] - prev2[1];
224347
+ const len2 = Math.sqrt(dx * dx + dy * dy);
224348
+ if (len2 > 0) {
224349
+ const ux = dx / len2;
224350
+ const uy = dy / len2;
224351
+ const shortened = [last[0] - ux * arrowDataSize, last[1] - uy * arrowDataSize];
224352
+ pathPoints = [...pathPoints.slice(0, -1), shortened];
224353
+ }
224354
+ }
224355
+ layers.push(new PathLayer({
224356
+ ...base2,
224357
+ id: `annotation-polyline-${uid2}-${i2}`,
224358
+ extensions: dashExt,
224359
+ getDashArray: getDash,
224360
+ data: [{ path: pathPoints }],
224361
+ getPath: (d) => d.path,
224362
+ getColor: strokeColor,
224363
+ getWidth: strokeWidth,
224364
+ widthUnits: "pixels",
224365
+ jointRounded: true,
224366
+ capRounded: true
224367
+ }));
224368
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
224369
+ const [x02, y02] = points2[0];
224370
+ const [x12, y12] = points2[1];
224371
+ const head = computeArrowhead(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
224372
+ if (head) {
224373
+ layers.push(new PolygonLayer({
224374
+ ...tipsBase,
224375
+ id: `annotation-polyline-start-arrow-${uid2}-${i2}`,
224376
+ data: [{ polygon: head }],
224377
+ getPolygon: (d) => d.polygon,
224378
+ filled: true,
224379
+ stroked: false,
224380
+ getFillColor: strokeColor
224381
+ }));
224382
+ }
224383
+ }
224384
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
224385
+ const last = points2[points2.length - 1];
224386
+ const prev2 = points2[points2.length - 2];
224387
+ const dxArrow = last[0] - prev2[0];
224388
+ const dyArrow = last[1] - prev2[1];
224389
+ const head = computeArrowhead(last[0], last[1], dxArrow, dyArrow, arrowDataSize);
224390
+ if (head) {
224391
+ layers.push(new PolygonLayer({
224392
+ ...tipsBase,
224393
+ id: `annotation-polyline-end-arrow-${uid2}-${i2}`,
224394
+ data: [{ polygon: head }],
224395
+ getPolygon: (d) => d.polygon,
224396
+ filled: true,
224397
+ stroked: false,
224398
+ getFillColor: strokeColor
224399
+ }));
224400
+ }
224401
+ }
224402
+ if (markerStart === "Tick" && tipsOpacity > 0) {
224403
+ const [x02, y02] = points2[0];
224404
+ const [x12, y12] = points2[1];
224405
+ const tick2 = computeTickCap(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
224406
+ if (tick2) {
224407
+ layers.push(new PathLayer({
224408
+ ...tipsBase,
224409
+ id: `annotation-polyline-start-tick-${uid2}-${i2}`,
224410
+ data: [{ path: tick2 }],
224411
+ getPath: (d) => d.path,
224412
+ getColor: strokeColor,
224413
+ getWidth: strokeWidth,
224414
+ widthUnits: "pixels",
224415
+ capRounded: true
224416
+ }));
224417
+ }
224418
+ }
224419
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
224420
+ const last = points2[points2.length - 1];
224421
+ const prev2 = points2[points2.length - 2];
224422
+ const dxTick = last[0] - prev2[0];
224423
+ const dyTick = last[1] - prev2[1];
224424
+ const tick2 = computeTickCap(last[0], last[1], dxTick, dyTick, arrowDataSize);
224425
+ if (tick2) {
224426
+ layers.push(new PathLayer({
224427
+ ...tipsBase,
224428
+ id: `annotation-polyline-end-tick-${uid2}-${i2}`,
224429
+ data: [{ path: tick2 }],
224430
+ getPath: (d) => d.path,
224431
+ getColor: strokeColor,
224432
+ getWidth: strokeWidth,
224433
+ widthUnits: "pixels",
224434
+ capRounded: true
224435
+ }));
224436
+ }
224437
+ }
224438
+ if (shape2.text) {
224439
+ const pos = shape2.textPosition ?? "start";
224440
+ const bufferPx = shape2.textBufferPx ?? 8;
224441
+ let textPt;
224442
+ let dirX;
224443
+ let dirY;
224444
+ if (pos === "end") {
224445
+ const last = points2[points2.length - 1];
224446
+ const prev2 = points2[points2.length - 2];
224447
+ textPt = last;
224448
+ dirX = last[0] - prev2[0];
224449
+ dirY = last[1] - prev2[1];
224450
+ } else if (pos === "middle") {
224451
+ const mx = points2.reduce((s2, p) => s2 + p[0], 0) / points2.length;
224452
+ const my = points2.reduce((s2, p) => s2 + p[1], 0) / points2.length;
224453
+ textPt = [mx, my];
224454
+ dirX = 0;
224455
+ dirY = 0;
224456
+ } else {
224457
+ [textPt] = points2;
224458
+ dirX = points2[0][0] - points2[1][0];
224459
+ dirY = points2[0][1] - points2[1][1];
224460
+ }
224461
+ const [textX, textY] = textPt;
224462
+ const lenT = Math.sqrt(dirX * dirX + dirY * dirY);
224463
+ let polylinePixelOffset = [0, 0];
224464
+ let polylineTextAnchor = "middle";
224465
+ let polylineAlignmentBaseline = pos === "middle" ? "center" : "bottom";
224466
+ if (lenT > 0) {
224467
+ const uxT = dirX / lenT;
224468
+ const uyT = dirY / lenT;
224469
+ const offX = uxT * bufferPx;
224470
+ const offY = uyT * bufferPx;
224471
+ polylinePixelOffset = [offX, offY];
224472
+ if (Math.abs(offX) >= Math.abs(offY)) {
224473
+ polylineTextAnchor = offX > 0 ? "start" : "end";
224474
+ }
224475
+ if (Math.abs(offY) >= Math.abs(offX)) {
224476
+ polylineAlignmentBaseline = offY > 0 ? "top" : "bottom";
224477
+ }
224478
+ }
224479
+ if (labelOpacity <= 0)
224480
+ return;
224481
+ layers.push(new TextLayer({
224482
+ ...labelBase,
224483
+ ...labelProps,
224484
+ id: `annotation-polyline-text-${uid2}-${i2}`,
224485
+ data: [{ position: [textX, textY], text: shape2.text }],
224486
+ getPosition: (d) => d.position,
224487
+ getText: (d) => d.text,
224488
+ getColor: strokeColor,
224489
+ getSize: LABEL_FONT_SIZE,
224490
+ sizeUnits: "pixels",
224491
+ fontFamily: LABEL_FONT_FAMILY$1,
224492
+ fontWeight: LABEL_FONT_WEIGHT,
224493
+ getPixelOffset: polylinePixelOffset,
224494
+ getTextAnchor: polylineTextAnchor,
224495
+ getAlignmentBaseline: polylineAlignmentBaseline
224496
+ }));
224497
+ }
224498
+ }
224499
+ });
224500
+ if (dotShapes.length > 0) {
224501
+ layers.push(new ScatterplotLayer({
224502
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
224503
+ id: "annotation-dots",
224504
+ data: dotShapes.map(({ shape: s2, alpha: alpha2 }) => ({
224505
+ position: getShapeCentroid(s2),
224506
+ color: [...s2.strokeColor ?? [255, 255, 255], alpha2]
224507
+ })),
224508
+ getPosition: (d) => d.position,
224509
+ getFillColor: (d) => d.color,
224510
+ getRadius: 4,
224511
+ radiusUnits: "pixels",
224512
+ filled: true,
224513
+ stroked: false
224514
+ }));
224515
+ }
224516
+ if (clusterDotShapes.length > 0) {
224517
+ const clusters = computeClusters(clusterDotShapes, zoom2);
224518
+ layers.push(new ScatterplotLayer({
224519
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
224520
+ id: "annotation-clusters",
224521
+ data: clusters,
224522
+ getPosition: (d) => d.position,
224523
+ getFillColor: (d) => [...d.color, 180],
224524
+ getRadius: (d) => Math.max(6, 4 + Math.sqrt(d.count) * 2),
224525
+ radiusUnits: "pixels",
224526
+ filled: true,
224527
+ stroked: true,
224528
+ getLineColor: (d) => [...d.color, 220],
224529
+ lineWidthMinPixels: 1.5
224530
+ }));
224531
+ const multiClusters = clusters.filter((c2) => c2.count > 1);
224532
+ if (multiClusters.length > 0) {
224533
+ layers.push(new TextLayer({
224534
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
224535
+ id: "annotation-cluster-counts",
224536
+ data: multiClusters,
224537
+ getPosition: (d) => d.position,
224538
+ getText: (d) => String(d.count),
224539
+ getColor: [255, 255, 255],
224540
+ getSize: 10,
224541
+ sizeUnits: "pixels",
224542
+ fontWeight: "bold",
224543
+ getTextAnchor: "middle",
224544
+ getAlignmentBaseline: "center"
224545
+ }));
224546
+ }
224547
+ }
224548
+ const measureLayers = [];
224549
+ shapes.forEach((shape2) => {
224550
+ if (!shape2.showMeasure)
224551
+ return;
224552
+ const mIsSelected = shape2.uid === selectedShapeUid;
224553
+ const label2 = getMeasurementLabel(shape2, physicalPixelSize, viewType);
224554
+ if (!label2)
224555
+ return;
224556
+ const color2 = shape2.strokeColor ?? [255, 255, 255];
224557
+ let mShapeOpacity = 1;
224558
+ let mLabelFactor = 0;
224559
+ if (mIsSelected || !semanticZoom || authoredZoom === null) {
224560
+ mLabelFactor = 1;
224561
+ } else {
224562
+ const mZoomRatio = 2 ** (zoom2 - authoredZoom);
224563
+ if (mZoomRatio < RATIO_DOT)
224564
+ return;
224565
+ if (mZoomRatio < RATIO_GEO_FADE) {
224566
+ mShapeOpacity = (mZoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
224567
+ }
224568
+ if (mZoomRatio >= RATIO_LABEL_FULL) {
224569
+ mLabelFactor = 1;
224570
+ } else if (mZoomRatio >= RATIO_LABEL) {
224571
+ mLabelFactor = (mZoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL);
224572
+ }
224573
+ }
224574
+ const measureOpacity = mShapeOpacity * mLabelFactor;
224575
+ if (measureOpacity <= 0)
224576
+ return;
224577
+ const base2 = {
224578
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
224579
+ opacity: measureOpacity,
224580
+ getText: (d) => d.text,
224581
+ getPosition: (d) => d.position,
224582
+ getColor: color2,
224583
+ getSize: 13,
224584
+ sizeUnits: "pixels",
224585
+ fontFamily: LABEL_FONT_FAMILY$1,
224586
+ fontWeight: "bold",
224587
+ // 'auto' builds the font atlas from the actual rendered characters (e.g. µ, ²)
224588
+ // instead of deck.gl's default ASCII-only atlas.
224589
+ characterSet: "auto",
224590
+ ...shape2.measureBackground ? {
224591
+ background: true,
224592
+ getBackgroundColor: textBgColor(color2),
224593
+ backgroundPadding: [3, 1, 3, 2]
224594
+ } : {}
224595
+ };
224596
+ if (shape2.type === "line") {
224597
+ const mx = ((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2;
224598
+ const my = ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2;
224599
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
224600
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
224601
+ const len2 = Math.sqrt(dx * dx + dy * dy);
224602
+ if (len2 === 0)
224603
+ return;
224604
+ const perp = pickBelowPerp(dx / len2, dy / len2);
224605
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
224606
+ measureLayers.push(new TextLayer({
224607
+ ...base2,
224608
+ id: `annotation-measure-${shape2.uid}`,
224609
+ data: [{ position: [mx, my], text: label2 }],
224610
+ getAngle: -angle2,
224611
+ getTextAnchor: "middle",
224612
+ getAlignmentBaseline: "center",
224613
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
224614
+ }));
224615
+ } else if (shape2.type === "polyline" && shape2.points?.length >= 2) {
224616
+ const pts = shape2.points;
224617
+ const mi = Math.floor((pts.length - 1) / 2);
224618
+ const [ax, ay] = pts[mi];
224619
+ const [bx, by] = pts[mi + 1];
224620
+ const dx = bx - ax;
224621
+ const dy = by - ay;
224622
+ const len2 = Math.sqrt(dx * dx + dy * dy);
224623
+ if (len2 === 0)
224624
+ return;
224625
+ const perp = pickBelowPerp(dx / len2, dy / len2);
224626
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
224627
+ measureLayers.push(new TextLayer({
224628
+ ...base2,
224629
+ id: `annotation-measure-${shape2.uid}`,
224630
+ data: [{ position: [(ax + bx) / 2, (ay + by) / 2], text: label2 }],
224631
+ getAngle: -angle2,
224632
+ getTextAnchor: "middle",
224633
+ getAlignmentBaseline: "center",
224634
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
224635
+ }));
224636
+ } else if (shape2.type === "rectangle") {
224637
+ const x02 = shape2.x ?? 0;
224638
+ const y02 = shape2.y ?? 0;
224639
+ const w2 = shape2.width ?? 0;
224640
+ const h2 = shape2.height ?? 0;
224641
+ const rx = x02 + (w2 >= 0 ? w2 : 0);
224642
+ const ry = y02 + (h2 >= 0 ? h2 : 0);
224643
+ measureLayers.push(new TextLayer({
224644
+ ...base2,
224645
+ id: `annotation-measure-${shape2.uid}`,
224646
+ data: [{ position: [rx, ry], text: label2 }],
224647
+ getTextAnchor: "end",
224648
+ getAlignmentBaseline: "bottom",
224649
+ getPixelOffset: [-6, -6]
224650
+ }));
224651
+ } else if (shape2.type === "ellipse") {
224652
+ const cx = shape2.x1 ?? 0;
224653
+ const cy = shape2.y1 ?? 0;
224654
+ const ry = Math.abs(shape2.radiusY ?? 0);
224655
+ measureLayers.push(new TextLayer({
224656
+ ...base2,
224657
+ id: `annotation-measure-${shape2.uid}`,
224658
+ data: [{ position: [cx, cy + ry], text: label2 }],
224659
+ getTextAnchor: "middle",
224660
+ getAlignmentBaseline: "top",
224661
+ getPixelOffset: [0, 8]
224662
+ }));
224663
+ } else if (shape2.type === "polygon" && shape2.points?.length >= 3) {
224664
+ const xs = shape2.points.map((p) => p[0]);
224665
+ const ys = shape2.points.map((p) => p[1]);
224666
+ const cx = (Math.min(...xs) + Math.max(...xs)) / 2;
224667
+ const maxY2 = Math.max(...ys);
224668
+ measureLayers.push(new TextLayer({
224669
+ ...base2,
224670
+ id: `annotation-measure-${shape2.uid}`,
224671
+ data: [{ position: [cx, maxY2], text: label2 }],
224672
+ getTextAnchor: "middle",
224673
+ getAlignmentBaseline: "top",
224674
+ getPixelOffset: [0, 8]
224675
+ }));
224676
+ }
224677
+ });
224678
+ return [...selectionLayers, ...layers, ...measureLayers];
224679
+ }
224680
+ const defaultProps = {
224681
+ // Array of annotation shape objects (see annotationShapeObj in @vitessce/schemas).
224682
+ data: { type: "object", value: [], compare: true },
224683
+ // UID of the shape to highlight with a selection halo.
224684
+ selectedShapeUid: { type: "string", value: null },
224685
+ // { x, y, unit } used to format measurement labels in physical units.
224686
+ physicalPixelSize: { type: "object", value: null, compare: true },
224687
+ // The zoom level at which the shapes were authored (reference for semantic zoom).
224688
+ authoredZoom: { type: "number", value: null },
224689
+ // Whether to apply semantic zoom (level-of-detail) based on authoredZoom.
224690
+ semanticZoom: { type: "boolean", value: true },
224691
+ // The view type in which the layer is rendered (affects measurement label formatting).
224692
+ viewType: { type: "string", value: ViewType$1.SPATIAL },
224693
+ // In-progress shape being drawn, as { type, vertices }.
224694
+ inProgressShape: { type: "object", value: null, compare: true },
224695
+ // Current mouse position (in data coordinates) while drawing.
224696
+ hoverCoord: { type: "array", value: null, compare: true },
224697
+ // Stroke color [r, g, b] of the in-progress shape preview.
224698
+ previewStrokeColor: { type: "color", value: [255, 255, 0] }
224699
+ };
224700
+ class AnnotationLayer extends CompositeLayer {
224701
+ // The semantic zoom and arrowhead sizes depend on the current zoom level,
224702
+ // so the sublayers must also be re-rendered when the viewport changes.
224703
+ // eslint-disable-next-line class-methods-use-this
224704
+ shouldUpdateState({ changeFlags }) {
224705
+ return changeFlags.propsOrDataChanged || changeFlags.viewportChanged;
224706
+ }
224707
+ /**
224708
+ * Prefix the sublayer ID with this layer's ID (so that multiple
224709
+ * AnnotationLayers can co-exist), and combine this layer's
224710
+ * opacity with the per-shape opacity of the sublayer.
224711
+ * Note: we avoid getSubLayerProps here, since it would
224712
+ * overwrite the sublayer extensions (e.g., PathStyleExtension)
224713
+ * and opacity values.
224714
+ * @param {object} layer A DeckGL layer instance.
224715
+ * @returns {object} The cloned layer instance.
224716
+ */
224717
+ wrapSubLayer(layer) {
224718
+ const { id: id2, opacity: opacity2, pickable, visible } = this.props;
224719
+ return layer.clone({
224720
+ id: `${id2}-${layer.id}`,
224721
+ opacity: layer.props.opacity * opacity2,
224722
+ pickable,
224723
+ visible
224724
+ });
224725
+ }
224726
+ renderLayers() {
224727
+ const { data: data2, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType, inProgressShape, hoverCoord, previewStrokeColor } = this.props;
224728
+ const zoom2 = this.context.viewport?.zoom ?? 0;
224729
+ const visibleShapes = (data2 ?? []).filter((shape2) => shape2.visible !== false);
224730
+ const annotationLayers = createAnnotationLayers(visibleShapes, zoom2, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType);
224731
+ const previewLayer = createPreviewLayer(inProgressShape, hoverCoord, previewStrokeColor.slice(0, 3));
224732
+ return [
224733
+ ...annotationLayers,
224734
+ ...previewLayer ? [previewLayer] : []
224735
+ ].map((layer) => this.wrapSubLayer(layer));
224736
+ }
224737
+ }
224738
+ AnnotationLayer.layerName = "AnnotationLayer";
224739
+ AnnotationLayer.defaultProps = defaultProps;
224740
+ const useStyles$x = makeStyles()(() => ({
223371
224741
  toolButton: {
223372
224742
  display: "inline-flex",
223373
224743
  "&:active": {
@@ -223429,12 +224799,12 @@ const useStyles$w = makeStyles()(() => ({
223429
224799
  }));
223430
224800
  function IconTool(props) {
223431
224801
  const { alt, onClick, isActive: isActive2, children: children3 } = props;
223432
- const { classes: classes2 } = useStyles$w();
224802
+ const { classes: classes2 } = useStyles$x();
223433
224803
  return jsx$1("button", { className: clsx(classes2.toolIcon, { [classes2.toolActive]: isActive2 }), onClick, type: "button", title: alt, children: children3 });
223434
224804
  }
223435
224805
  function IconButton(props) {
223436
224806
  const { alt, onClick, children: children3 } = props;
223437
- const { classes: classes2 } = useStyles$w();
224807
+ const { classes: classes2 } = useStyles$x();
223438
224808
  return jsx$1("button", { className: clsx(classes2.toolIcon, classes2.toolButton), onClick, type: "button", title: alt, children: children3 });
223439
224809
  }
223440
224810
  function ToolMenu(props) {
@@ -223442,7 +224812,7 @@ function ToolMenu(props) {
223442
224812
  const lassoIconAltText = "Select lasso";
223443
224813
  const { setActiveTool, activeTool, visibleTools = { pan: true, selectLasso: true, recenter: true }, recenterOnClick = () => {
223444
224814
  } } = props;
223445
- const { classes: classes2 } = useStyles$w();
224815
+ const { classes: classes2 } = useStyles$x();
223446
224816
  const onRecenterButtonCLick = () => {
223447
224817
  recenterOnClick();
223448
224818
  };
@@ -223924,11 +225294,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
223924
225294
  this.cellSetsLabelPrevZoom = null;
223925
225295
  this.cellSetsLayers = [];
223926
225296
  this.contourLayers = [];
225297
+ this.annotationLayer = null;
223927
225298
  this.onUpdateCellsData();
223928
225299
  this.onUpdateCellsLayer();
223929
225300
  this.onUpdateCellSetsLayers();
223930
225301
  this.onUpdateStratifiedData();
223931
225302
  this.onUpdateContourLayers();
225303
+ this.onUpdateAnnotationLayer();
223932
225304
  }
223933
225305
  // Want to support multiple types of contour layers
223934
225306
  // - One layer for all data points (no filtering)
@@ -223992,6 +225364,21 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
223992
225364
  }));
223993
225365
  return layers;
223994
225366
  }
225367
+ createAnnotationLayer() {
225368
+ const { annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection } = this.props;
225369
+ return new AnnotationLayer({
225370
+ data: annotationShapes,
225371
+ visible: annotationOverlayVisible,
225372
+ semanticZoom: annotationSemanticZoom,
225373
+ selectedShapeUid: annotationShapeSelection,
225374
+ viewType: ViewType$1.SCATTERPLOT
225375
+ // TODO: is this needed?
225376
+ // TODO: these are view-level properties, rather than layer-level.
225377
+ // annotationTransitionDuration,
225378
+ // annotationEditable,
225379
+ // Other coordination types related to editing...
225380
+ });
225381
+ }
223995
225382
  createCellsLayer() {
223996
225383
  const {
223997
225384
  obsEmbeddingIndex: obsIndex,
@@ -224125,12 +225512,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
224125
225512
  ], flipYTooltip, this.props.onSelectionBusy);
224126
225513
  }
224127
225514
  getLayers() {
224128
- const { cellsLayer, cellSetsLayers, contourLayers } = this;
225515
+ const { cellsLayer, cellSetsLayers, contourLayers, annotationLayer } = this;
224129
225516
  return [
224130
225517
  cellsLayer,
224131
225518
  ...contourLayers,
224132
225519
  ...cellSetsLayers,
224133
- this.createSelectionLayer()
225520
+ this.createSelectionLayer(),
225521
+ annotationLayer
224134
225522
  ];
224135
225523
  }
224136
225524
  /**
@@ -224167,6 +225555,14 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
224167
225555
  this.cellsLayer = null;
224168
225556
  }
224169
225557
  }
225558
+ onUpdateAnnotationLayer() {
225559
+ const { annotationShapes } = this.props;
225560
+ if (annotationShapes) {
225561
+ this.annotationLayer = this.createAnnotationLayer();
225562
+ } else {
225563
+ this.annotationLayer = null;
225564
+ }
225565
+ }
224170
225566
  onUpdateStratifiedData() {
224171
225567
  const { stratifiedData } = this.props;
224172
225568
  if (stratifiedData) {
@@ -224282,6 +225678,16 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
224282
225678
  this.onUpdateCellSetsLayers(true);
224283
225679
  forceUpdate = true;
224284
225680
  }
225681
+ if ([
225682
+ "annotationShapes",
225683
+ "annotationOverlayVisible",
225684
+ "annotationSemanticZoom",
225685
+ "annotationTransitionDuration",
225686
+ "annotationEditable"
225687
+ ].some(shallowDiff2)) {
225688
+ this.onUpdateAnnotationLayer();
225689
+ forceUpdate = true;
225690
+ }
224285
225691
  if (forceUpdate) {
224286
225692
  this.forceUpdate();
224287
225693
  }
@@ -224637,7 +226043,7 @@ function ScatterplotOptions(props) {
224637
226043
  id: `feature-aggregation-strategy-${scatterplotOptionsId}`
224638
226044
  }, children: FEATURE_AGGREGATION_STRATEGIES$2.map((opt) => jsx$1("option", { value: opt, children: capitalize$3(opt) }, opt)) }) })] }) : null] });
224639
226045
  }
224640
- const useStyles$v = makeStyles()((theme) => ({
226046
+ const useStyles$w = makeStyles()((theme) => ({
224641
226047
  tooltipAnchor: {
224642
226048
  position: "relative",
224643
226049
  width: "0px",
@@ -224668,7 +226074,7 @@ const useStyles$v = makeStyles()((theme) => ({
224668
226074
  function Tooltip3(props) {
224669
226075
  const { x: x2, y: y2, parentWidth, parentHeight, children: children3 } = props;
224670
226076
  const ref2 = useRef();
224671
- const { classes: classes2 } = useStyles$v();
226077
+ const { classes: classes2 } = useStyles$w();
224672
226078
  const [placementX, setPlacementX] = useState("start");
224673
226079
  const [placementY, setPlacementY] = useState("bottom");
224674
226080
  const getTooltipContainer = useVitessceContainer(ref2);
@@ -224684,7 +226090,7 @@ function Tooltip3(props) {
224684
226090
  }, [x2, y2, parentWidth, parentHeight]);
224685
226091
  return jsx$1("div", { ref: ref2, className: classes2.tooltipAnchor, children: ref2 && ref2.current ? jsx$1(Popper, { open: true, anchorEl: ref2.current, container: getTooltipContainer, transition: true, placement: `${placementY}-${placementX}`, children: jsx$1(Paper, { elevation: 8, className: classes2.tooltipContent, children: children3 }) }) : null });
224686
226092
  }
224687
- const useStyles$u = makeStyles()((theme) => ({
226093
+ const useStyles$v = makeStyles()((theme) => ({
224688
226094
  cellEmphasisCrosshair: {
224689
226095
  zIndex: 50,
224690
226096
  position: "absolute",
@@ -224695,7 +226101,7 @@ const useStyles$u = makeStyles()((theme) => ({
224695
226101
  }));
224696
226102
  function Tooltip2D(props) {
224697
226103
  const { parentUuid, sourceUuid, x: x2, y: y2, parentWidth, parentHeight, children: children3 } = props;
224698
- const { classes: classes2 } = useStyles$u();
226104
+ const { classes: classes2 } = useStyles$v();
224699
226105
  if (x2 < 0 || x2 > parentWidth || y2 < 0 || y2 > parentHeight) {
224700
226106
  return null;
224701
226107
  }
@@ -228607,7 +230013,7 @@ function getXlinkHref(cmap) {
228607
230013
  const xlinkHref = ramp(color2.copy().domain(quantize$3(interpolate$1$1(0, 1), n3))).toDataURL();
228608
230014
  return xlinkHref;
228609
230015
  }
228610
- const useStyles$t = makeStyles()(() => ({
230016
+ const useStyles$u = makeStyles()(() => ({
228611
230017
  legend: {
228612
230018
  position: "relative",
228613
230019
  // Needed for absolute positioning of slider overlay
@@ -228804,7 +230210,7 @@ function Legend(props) {
228804
230210
  contourThresholds
228805
230211
  } = props;
228806
230212
  const svgRef = useRef(null);
228807
- const { classes: classes2 } = useStyles$t();
230213
+ const { classes: classes2 } = useStyles$u();
228808
230214
  const [localRange, setLocalRange] = useState(featureValueColormapRange);
228809
230215
  useEffect(() => {
228810
230216
  setLocalRange(featureValueColormapRange);
@@ -229138,7 +230544,7 @@ function Legend(props) {
229138
230544
  }
229139
230545
  } })] })] });
229140
230546
  }
229141
- const useStyles$s = makeStyles()(() => ({
230547
+ const useStyles$t = makeStyles()(() => ({
229142
230548
  multiLegend: {
229143
230549
  position: "absolute",
229144
230550
  top: "0px",
@@ -229165,7 +230571,7 @@ function MultiLegend(props) {
229165
230571
  pointLayerCoordination,
229166
230572
  pointMultiIndicesData
229167
230573
  } = props;
229168
- const { classes: classes2 } = useStyles$s();
230574
+ const { classes: classes2 } = useStyles$t();
229169
230575
  const reversedSegmentationLayerScopes = useMemo$1(() => [...segmentationLayerScopes || []].reverse(), [segmentationLayerScopes]);
229170
230576
  const reversedSpotLayerScopes = useMemo$1(() => [...spotLayerScopes || []].reverse(), [spotLayerScopes]);
229171
230577
  const reversedPointLayerScopes = useMemo$1(() => [...pointLayerScopes || []].reverse(), [pointLayerScopes]);
@@ -229258,7 +230664,7 @@ function MultiLegend(props) {
229258
230664
  }) : null;
229259
230665
  }) : null] });
229260
230666
  }
229261
- const useStyles$r = makeStyles()(() => ({
230667
+ const useStyles$s = makeStyles()(() => ({
229262
230668
  channelNamesLegendContainer: {
229263
230669
  position: "absolute",
229264
230670
  bottom: "0px",
@@ -229281,7 +230687,7 @@ const useStyles$r = makeStyles()(() => ({
229281
230687
  }));
229282
230688
  function ChannelNamesLegend(props) {
229283
230689
  const { images, imageLayerScopes, imageLayerCoordination, imageChannelScopesByLayer, imageChannelCoordination } = props;
229284
- const { classes: classes2 } = useStyles$r();
230690
+ const { classes: classes2 } = useStyles$s();
229285
230691
  const reversedImageLayerScopes = useMemo$1(() => [...imageLayerScopes || []].reverse(), [imageLayerScopes]);
229286
230692
  return jsx$1("div", { className: classes2.channelNamesLegendContainer, children: imageLayerScopes ? reversedImageLayerScopes.map((layerScope) => {
229287
230693
  const layerCoordination = imageLayerCoordination[0][layerScope];
@@ -229311,7 +230717,6 @@ const DEFAULT_FEATURE_AGGREGATION_STRATEGY$3 = "first";
229311
230717
  function EmbeddingScatterplotSubscriber(props) {
229312
230718
  const {
229313
230719
  uuid: uuid2,
229314
- coordinationScopes: coordinationScopesRaw,
229315
230720
  closeButtonVisible,
229316
230721
  downloadButtonVisible,
229317
230722
  removeGridComponent,
@@ -229327,16 +230732,23 @@ function EmbeddingScatterplotSubscriber(props) {
229327
230732
  circleScaleFactor = 0.8
229328
230733
  } = props;
229329
230734
  const loaders = useLoaders();
229330
- const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
230735
+ const [
230736
+ // eslint-disable-next-line no-unused-vars
230737
+ coordinationScopes,
230738
+ _coordinationScopesBy,
230739
+ coordinationValues
230740
+ ] = useViewMapping(uuid2);
229331
230741
  const setComponentHover = useSetComponentHover();
229332
230742
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
229333
- 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 }, { 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 }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes);
229334
- const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes);
230743
+ useAnnotationFrameCoordination(uuid2, coordinationScopes, coordinationValues);
230744
+ 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 }, { 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);
230745
+ const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes, coordinationValues);
229335
230746
  const observationsLabel = observationsLabelOverride || obsType;
229336
230747
  const sampleSetSelection = sampleSetSelectionFromProps || sampleSetSelectionFromCoordination;
229337
230748
  const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY$3;
229338
230749
  const [width2, height2, deckRef] = useDeckCanvasSize();
229339
230750
  const title2 = titleOverride || `Scatterplot (${mapping})`;
230751
+ const [, annotationStoryStatus, annotationStoryUrls, annotationStoryError] = useAnnotationStoryData(loaders, dataset, false, { setAnnotationStory }, { annotationStory }, {});
229340
230752
  const [
229341
230753
  // eslint-disable-next-line no-unused-vars
229342
230754
  obsLabelsTypes,
@@ -229368,11 +230780,13 @@ function EmbeddingScatterplotSubscriber(props) {
229368
230780
  matrixIndicesError,
229369
230781
  featureLabelsError,
229370
230782
  sampleSetsError,
229371
- sampleEdgesError
230783
+ sampleEdgesError,
230784
+ annotationStoryError
229372
230785
  ];
229373
230786
  const isReady = useReady([
229374
230787
  obsEmbeddingStatus,
229375
230788
  obsSetsStatus,
230789
+ annotationStoryStatus,
229376
230790
  featureSelectionStatus,
229377
230791
  featureLabelsStatus,
229378
230792
  expandedFeatureLabelsStatus,
@@ -229386,7 +230800,8 @@ function EmbeddingScatterplotSubscriber(props) {
229386
230800
  matrixIndicesUrls,
229387
230801
  featureLabelsUrls,
229388
230802
  sampleSetsUrl,
229389
- sampleEdgesUrl
230803
+ sampleEdgesUrl,
230804
+ annotationStoryUrls
229390
230805
  ]);
229391
230806
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
229392
230807
  const [isSelectionPending, setIsSelectionPending] = useState(false);
@@ -229663,7 +231078,13 @@ function EmbeddingScatterplotSubscriber(props) {
229663
231078
  embeddingPointsVisible,
229664
231079
  embeddingContoursVisible,
229665
231080
  circleInfo,
229666
- featureSelection: geneSelection
231081
+ featureSelection: geneSelection,
231082
+ // Annotation stuff
231083
+ annotationShapes,
231084
+ annotationOverlayVisible,
231085
+ annotationSemanticZoom,
231086
+ annotationTransitionDuration,
231087
+ annotationEditable
229667
231088
  }), tooltipsVisible && width2 && height2 ? jsx$1(ScatterplotTooltipSubscriber, { parentUuid: uuid2, obsHighlight: cellHighlight, width: width2, height: height2, getObsInfo: getObsInfo2, featureType, featureLabelsMap }) : null, jsx$1(Legend, {
229668
231089
  visible: true,
229669
231090
  theme,
@@ -244824,8 +246245,8 @@ async function getSingleSelectionStats2D({ loader: loader2, selection }) {
244824
246245
  const filteredSelection = filterSelection(loader2, selection);
244825
246246
  const raster = await data2.getRaster({ selection: filteredSelection });
244826
246247
  const selectionStats = getChannelStats(raster.data);
244827
- const { domain: domain2, contrastLimits: slider } = selectionStats;
244828
- return { domain: domain2, slider };
246248
+ const { domain: domain2, contrastLimits: slider, q1, q3 } = selectionStats;
246249
+ return { domain: domain2, slider, q1, q3 };
244829
246250
  }
244830
246251
  async function getSingleSelectionStats3D({ loader: loader2, selection }) {
244831
246252
  const lowResSource = loader2[loader2.length - 1];
@@ -244852,7 +246273,9 @@ async function getSingleSelectionStats3D({ loader: loader2, selection }) {
244852
246273
  slider: [
244853
246274
  Math.min(stats0.contrastLimits[0], statsMid.contrastLimits[0], statsTop.contrastLimits[0]),
244854
246275
  Math.max(stats0.contrastLimits[1], statsMid.contrastLimits[1], statsTop.contrastLimits[1])
244855
- ]
246276
+ ],
246277
+ q1: Math.min(stats0.q1[0], statsMid.q1[0], statsTop.q1[0]),
246278
+ q3: Math.max(stats0.q3[1], statsMid.q3[1], statsTop.q3[1])
244856
246279
  };
244857
246280
  }
244858
246281
  const getSingleSelectionStats = async ({ loader: loader2, selection, use3d }) => {
@@ -244863,7 +246286,9 @@ const getMultiSelectionStats = async ({ loader: loader2, selections, use3d }) =>
244863
246286
  const stats = await Promise.all(selections.map((selection) => getSingleSelectionStats({ loader: loader2, selection, use3d })));
244864
246287
  const domains = stats.map((stat) => stat.domain);
244865
246288
  const sliders = stats.map((stat) => stat.slider);
244866
- return { domains, sliders };
246289
+ const q1s = stats.map((stat) => stat.q1);
246290
+ const q3s = stats.map((stat) => stat.q3);
246291
+ return { domains, sliders, q1s, q3s };
244867
246292
  };
244868
246293
  function getPhysicalSizeScalingMatrix(loader2) {
244869
246294
  const { x: x2, y: y2, z: z2 } = loader2?.meta?.physicalSizes ?? {};
@@ -249223,6 +250648,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249223
250648
  this.obsSegmentationsPolygonLayer = null;
249224
250649
  this.obsLocationsLayer = null;
249225
250650
  this.neighborhoodsLayer = null;
250651
+ this.annotationLayer = null;
249226
250652
  this.layerLoaderSelections = {};
249227
250653
  this.randomColorData = {
249228
250654
  data: new Uint8Array(2048 * 2048 * 3).map((_, j) => j < 4 ? 0 : Math.round(255 * Math.random())),
@@ -249244,6 +250670,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249244
250670
  this.onUpdateNeighborhoodsData();
249245
250671
  this.onUpdateNeighborhoodsLayer();
249246
250672
  this.onUpdateImages();
250673
+ this.onUpdateAnnotationLayer();
249247
250674
  }
249248
250675
  createPolygonSegmentationsLayer(layerDef, hasExplicitPolygons) {
249249
250676
  const { stroked, visible, opacity: opacity2, radius: radius2 } = layerDef;
@@ -249575,7 +251002,7 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249575
251002
  return [];
249576
251003
  }
249577
251004
  getLayers() {
249578
- const { imageLayers, obsSegmentationsPolygonLayer, neighborhoodsLayer, obsLocationsLayer, obsSegmentationsBitmaskLayers } = this;
251005
+ const { imageLayers, obsSegmentationsPolygonLayer, neighborhoodsLayer, obsLocationsLayer, obsSegmentationsBitmaskLayers, annotationLayer } = this;
249579
251006
  return [
249580
251007
  ...imageLayers,
249581
251008
  ...obsSegmentationsBitmaskLayers,
@@ -249583,7 +251010,8 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249583
251010
  neighborhoodsLayer,
249584
251011
  obsLocationsLayer,
249585
251012
  this.createScaleBarLayer(),
249586
- this.createSelectionLayer()
251013
+ this.createSelectionLayer(),
251014
+ annotationLayer
249587
251015
  ];
249588
251016
  }
249589
251017
  /**
@@ -249690,6 +251118,25 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249690
251118
  onUpdateImages() {
249691
251119
  this.imageLayers = this.createImageLayers();
249692
251120
  }
251121
+ createAnnotationLayer() {
251122
+ const { annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection } = this.props;
251123
+ return new AnnotationLayer({
251124
+ id: "annotation-layer",
251125
+ data: annotationShapes,
251126
+ visible: annotationOverlayVisible,
251127
+ semanticZoom: annotationSemanticZoom,
251128
+ selectedShapeUid: annotationShapeSelection,
251129
+ viewType: ViewType$1.SPATIAL
251130
+ });
251131
+ }
251132
+ onUpdateAnnotationLayer() {
251133
+ const { annotationShapes } = this.props;
251134
+ if (annotationShapes) {
251135
+ this.annotationLayer = this.createAnnotationLayer();
251136
+ } else {
251137
+ this.annotationLayer = null;
251138
+ }
251139
+ }
249693
251140
  viewInfoDidUpdate() {
249694
251141
  const { obsCentroidsIndex, obsCentroids } = this.props;
249695
251142
  super.viewInfoDidUpdate(obsCentroidsIndex, obsCentroids, makeDefaultGetObsCoords$1);
@@ -249789,6 +251236,15 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
249789
251236
  this.onUpdateImages();
249790
251237
  forceUpdate = true;
249791
251238
  }
251239
+ if ([
251240
+ "annotationShapes",
251241
+ "annotationOverlayVisible",
251242
+ "annotationSemanticZoom",
251243
+ "annotationShapeSelection"
251244
+ ].some(shallowDiff2)) {
251245
+ this.onUpdateAnnotationLayer();
251246
+ forceUpdate = true;
251247
+ }
249792
251248
  if (forceUpdate) {
249793
251249
  this.forceUpdate();
249794
251250
  }
@@ -249888,7 +251344,8 @@ function SpatialSubscriber$1(props) {
249888
251344
  const loaders = useLoaders();
249889
251345
  const setComponentHover = useSetComponentHover();
249890
251346
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
249891
- 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 }, { 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 }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
251347
+ useAnnotationFrameCoordination(uuid2, coordinationScopes);
251348
+ 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, annotationShapeSelection }, { 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);
249892
251349
  const { spatialZoom: initialZoom, spatialTargetX: initialTargetX, spatialTargetY: initialTargetY, spatialTargetZ: initialTargetZ } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
249893
251350
  const observationsLabel = observationsLabelOverride || obsType;
249894
251351
  const [{ imageLayerCallbacks, segmentationLayerCallbacks }] = useAuxiliaryCoordination(COMPONENT_COORDINATION_TYPES.layerController, coordinationScopes);
@@ -249925,6 +251382,7 @@ function SpatialSubscriber$1(props) {
249925
251382
  const [neighborhoods, neighborhoodsStatus, neighborhoodsUrls, neighborhoodsError] = useNeighborhoodsData(loaders, dataset, false, { setSpatialNeighborhoodLayer: setNeighborhoodsLayer }, { spatialNeighborhoodLayer: neighborhoodsLayer });
249926
251383
  const [{ featureLabelsMap: featureLabelsMapOrig }, featureLabelsStatus, featureLabelsUrls, featureLabelsError] = useFeatureLabelsData(loaders, dataset, false, {}, {}, { featureType });
249927
251384
  const [featureLabelsMap, expandedFeatureLabelsStatus] = useExpandedFeatureLabelsMap(featureType, featureLabelsMapOrig, { stripCuriePrefixes: true });
251385
+ const [, annotationStoryStatus, annotationStoryUrls, annotationStoryError] = useAnnotationStoryData(loaders, dataset, false, { setAnnotationStory }, { annotationStory }, {});
249928
251386
  const errors = [
249929
251387
  ...obsLabelsErrorsMulti,
249930
251388
  obsLocationsError,
@@ -249936,7 +251394,8 @@ function SpatialSubscriber$1(props) {
249936
251394
  matrixIndicesError,
249937
251395
  imageError,
249938
251396
  neighborhoodsError,
249939
- featureLabelsError
251397
+ featureLabelsError,
251398
+ annotationStoryError
249940
251399
  ];
249941
251400
  const photometricInterpretation = photometricInterpretationFromCoordination ?? instance2?.getPhotometricInterpretation();
249942
251401
  const isReady = useReady([
@@ -249950,7 +251409,8 @@ function SpatialSubscriber$1(props) {
249950
251409
  imageStatus,
249951
251410
  neighborhoodsStatus,
249952
251411
  featureLabelsStatus,
249953
- expandedFeatureLabelsStatus
251412
+ expandedFeatureLabelsStatus,
251413
+ annotationStoryStatus
249954
251414
  ]);
249955
251415
  const urls2 = useUrls([
249956
251416
  obsLocationsUrls,
@@ -249961,7 +251421,8 @@ function SpatialSubscriber$1(props) {
249961
251421
  matrixIndicesUrls,
249962
251422
  imageUrls,
249963
251423
  neighborhoodsUrls,
249964
- featureLabelsUrls
251424
+ featureLabelsUrls,
251425
+ annotationStoryUrls
249965
251426
  ]);
249966
251427
  const obsLocationsFeatureIndex = useMemo$1(() => {
249967
251428
  if (obsLocationsLabels) {
@@ -250200,7 +251661,7 @@ function SpatialSubscriber$1(props) {
250200
251661
  orbitAxis
250201
251662
  }, setViewState, originalViewState, imageLayerDefs: imageLayers, obsSegmentationsLayerDefs: cellsLayer, obsLocationsLayerDefs: moleculesLayer, neighborhoodLayerDefs: neighborhoodsLayer, obsLocationsIndex, obsSegmentationsIndex, obsLocations, obsLocationsLabels, obsLocationsFeatureIndex, hasSegmentations: hasSegmentationsData, obsSegmentations, obsSegmentationsType, obsCentroids, obsCentroidsIndex, cellFilter, cellSelection, cellHighlight, cellColors, neighborhoods, imageLayerLoaders: resolutionFilteredImageLayerLoaders, setCellFilter, setCellSelection: setCellSelectionProp, setCellHighlight, setHoverInfo, setMoleculeHighlight, setComponentHover: () => {
250202
251663
  setComponentHover(uuid2);
250203
- }, updateViewInfo: setComponentViewInfo, imageLayerCallbacks, segmentationLayerCallbacks, spatialAxisFixed, geneExpressionColormap, geneExpressionColormapRange, expressionData: shiftedExpressionDataForBitmask, cellColorEncoding, getExpressionValue, theme, useFullResolutionImage, photometricInterpretation }), tooltipsVisible && jsx$1(SpatialTooltipSubscriber$1, { parentUuid: uuid2, obsHighlight: cellHighlight || moleculeHighlight, width: width2, height: height2, getObsInfo: getTooltipObsInfo, useHoverInfoForTooltip, hoverData, hoverCoord, hoverMode, getObsIdFromHoverData, featureType, featureLabelsMap }), jsx$1(Legend, {
251664
+ }, updateViewInfo: setComponentViewInfo, imageLayerCallbacks, segmentationLayerCallbacks, spatialAxisFixed, geneExpressionColormap, geneExpressionColormapRange, expressionData: shiftedExpressionDataForBitmask, cellColorEncoding, getExpressionValue, theme, useFullResolutionImage, photometricInterpretation, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection }), tooltipsVisible && jsx$1(SpatialTooltipSubscriber$1, { parentUuid: uuid2, obsHighlight: cellHighlight || moleculeHighlight, width: width2, height: height2, getObsInfo: getTooltipObsInfo, useHoverInfoForTooltip, hoverData, hoverCoord, hoverMode, getObsIdFromHoverData, featureType, featureLabelsMap }), jsx$1(Legend, {
250204
251665
  visible: true,
250205
251666
  // Fix to dark theme due to black background of spatial plot.
250206
251667
  theme: "dark",
@@ -250448,6 +251909,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
250448
251909
  this.obsSegmentationsLayers = [];
250449
251910
  this.obsSpotsLayers = [];
250450
251911
  this.obsPointsLayers = [];
251912
+ this.annotationLayer = null;
250451
251913
  this.obsPointsLabelsData = {};
250452
251914
  this.spotToMatrixIndexMap = {};
250453
251915
  this.spotColors = {};
@@ -250489,6 +251951,7 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
250489
251951
  this.onUpdateAllSpotsExpressionData();
250490
251952
  this.onUpdateSpotsLayer();
250491
251953
  this.onUpdateImages();
251954
+ this.onUpdateAnnotationLayer();
250492
251955
  }
250493
251956
  createPolygonSegmentationLayer(layerScope, layerCoordination, channelScopes, channelCoordinations, layerObsSegmentations, layerFeatureValues) {
250494
251957
  const { theme, delegateHover } = this.props;
@@ -251227,7 +252690,8 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
251227
252690
  imageLayers,
251228
252691
  obsSpotsLayers,
251229
252692
  obsPointsLayers,
251230
- obsSegmentationsLayers
252693
+ obsSegmentationsLayers,
252694
+ annotationLayer
251231
252695
  // neighborhoodsLayer,
251232
252696
  // obsLocationsLayer,
251233
252697
  } = this;
@@ -251239,7 +252703,8 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
251239
252703
  // neighborhoodsLayer,
251240
252704
  // obsLocationsLayer,
251241
252705
  this.createScaleBarLayer(),
251242
- this.createSelectionLayer()
252706
+ this.createSelectionLayer(),
252707
+ annotationLayer
251243
252708
  ];
251244
252709
  }
251245
252710
  // onUpdate functions:
@@ -251595,6 +253060,25 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
251595
253060
  onUpdateImages() {
251596
253061
  this.imageLayers = this.createImageLayers();
251597
253062
  }
253063
+ createAnnotationLayer() {
253064
+ const { annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection } = this.props;
253065
+ return new AnnotationLayer({
253066
+ id: "annotation-layer",
253067
+ data: annotationShapes,
253068
+ visible: annotationOverlayVisible,
253069
+ semanticZoom: annotationSemanticZoom,
253070
+ selectedShapeUid: annotationShapeSelection,
253071
+ viewType: ViewType$1.SPATIAL_BETA
253072
+ });
253073
+ }
253074
+ onUpdateAnnotationLayer() {
253075
+ const { annotationShapes } = this.props;
253076
+ if (annotationShapes) {
253077
+ this.annotationLayer = this.createAnnotationLayer();
253078
+ } else {
253079
+ this.annotationLayer = null;
253080
+ }
253081
+ }
251598
253082
  viewInfoDidUpdate() {
251599
253083
  super.viewInfoDidUpdate(null, null, makeDefaultGetObsCoords);
251600
253084
  }
@@ -251792,6 +253276,15 @@ class Spatial2 extends AbstractSpatialOrScatterplot {
251792
253276
  this.onUpdateImages();
251793
253277
  forceUpdate = true;
251794
253278
  }
253279
+ if ([
253280
+ "annotationShapes",
253281
+ "annotationOverlayVisible",
253282
+ "annotationSemanticZoom",
253283
+ "annotationShapeSelection"
253284
+ ].some(shallowDiff2)) {
253285
+ this.onUpdateAnnotationLayer();
253286
+ forceUpdate = true;
253287
+ }
251795
253288
  if (forceUpdate) {
251796
253289
  this.forceUpdate();
251797
253290
  }
@@ -251931,16 +253424,16 @@ class ErrorBoundary extends React__default.Component {
251931
253424
  }
251932
253425
  }
251933
253426
  const LazySpatialThree = React__default.lazy(async () => {
251934
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-Byfj8aLT.js").then((n3) => n3.a);
253427
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-D_-Gt3v4.js").then((n3) => n3.a);
251935
253428
  return { default: SpatialWrapper2 };
251936
253429
  });
251937
253430
  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 }) }) }) }));
251938
253431
  const LazySpatialAccelerated = React__default.lazy(async () => {
251939
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-DEqwtY_4.js");
253432
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-DPtUTwgq.js");
251940
253433
  return { default: SpatialWrapper2 };
251941
253434
  });
251942
253435
  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 }) }) }) }));
251943
- const useStyles$q = makeStyles()(() => ({
253436
+ const useStyles$r = makeStyles()(() => ({
251944
253437
  spatialBetaCameraLabel: {
251945
253438
  padding: "0px 0px 0px 16px"
251946
253439
  },
@@ -251951,7 +253444,7 @@ const useStyles$q = makeStyles()(() => ({
251951
253444
  function SpatialOptions(props) {
251952
253445
  const { spatialAxisFixed, setSpatialAxisFixed, use3d } = props;
251953
253446
  const toggleAxisId = $bdb11010cef70236$export$f680877a34711e37();
251954
- const { classes: classes2 } = useStyles$q();
253447
+ const { classes: classes2 } = useStyles$r();
251955
253448
  return jsx$1(OptionsContainer, { children: jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.spatialBetaCameraLabel, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `spatial-camera-axis-${toggleAxisId}`, children: "Fix Camera Axis" }) }), jsx$1(TableCell, { className: classes2.spatialBetaToggleBox, variant: "body", children: jsx$1(Checkbox$1, { onClick: () => setSpatialAxisFixed(!spatialAxisFixed), disabled: !use3d, checked: Boolean(spatialAxisFixed), slotProps: { input: {
251956
253449
  "aria-label": "Fix or not fix spatial camera axis",
251957
253450
  id: `spatial-camera-axis-${toggleAxisId}`
@@ -252139,6 +253632,7 @@ function SpatialSubscriber(props) {
252139
253632
  const mergeCoordination = useMergeCoordination();
252140
253633
  const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
252141
253634
  const coordinationScopesBy = useCoordinationScopesBy(coordinationScopes, coordinationScopesByRaw);
253635
+ useAnnotationFrameCoordination(uuid2, coordinationScopes);
252142
253636
  const [{
252143
253637
  dataset,
252144
253638
  obsType,
@@ -252160,7 +253654,12 @@ function SpatialSubscriber(props) {
252160
253654
  additionalObsSets,
252161
253655
  obsSetColor,
252162
253656
  obsColorEncoding,
252163
- obsSetSelection
253657
+ obsSetSelection,
253658
+ annotationStory,
253659
+ annotationShapes,
253660
+ annotationOverlayVisible,
253661
+ annotationSemanticZoom,
253662
+ annotationShapeSelection
252164
253663
  }, {
252165
253664
  setSpatialZoom: setZoom,
252166
253665
  setSpatialTargetX: setTargetX,
@@ -252176,7 +253675,8 @@ function SpatialSubscriber(props) {
252176
253675
  setAdditionalObsSets,
252177
253676
  setObsSetColor,
252178
253677
  setObsColorEncoding,
252179
- setObsSetSelection
253678
+ setObsSetSelection,
253679
+ setAnnotationStory
252180
253680
  }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL_BETA], coordinationScopes);
252181
253681
  const { spatialZoom: initialZoom, spatialTargetX: initialTargetX, spatialTargetY: initialTargetY, spatialTargetZ: initialTargetZ } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL_BETA], coordinationScopes);
252182
253682
  const [segmentationLayerScopes, segmentationChannelScopesByLayer] = useMultiCoordinationScopesSecondaryNonNull(CoordinationType$1.SEGMENTATION_CHANNEL, CoordinationType$1.SEGMENTATION_LAYER, coordinationScopes, coordinationScopesBy);
@@ -252319,6 +253819,7 @@ function SpatialSubscriber(props) {
252319
253819
  channelCoordination: segmentationChannelCoordination
252320
253820
  });
252321
253821
  const [imageData, imageDataStatus, imageUrls, imageDataErrors] = useMultiImages(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, uuid2);
253822
+ const [, annotationStoryStatus, annotationStoryUrls, annotationStoryError] = useAnnotationStoryData(loaders, dataset, false, { setAnnotationStory }, { annotationStory }, {});
252322
253823
  const errors = [
252323
253824
  ...obsPointsErrors,
252324
253825
  ...obsSpotsErrors,
@@ -252333,7 +253834,8 @@ function SpatialSubscriber(props) {
252333
253834
  ...pointMultiIndicesDataErrors,
252334
253835
  ...segmentationMultiFeatureSelectionErrors,
252335
253836
  ...segmentationMultiIndicesDataErrors,
252336
- ...obsSegmentationsLocationsDataErrors
253837
+ ...obsSegmentationsLocationsDataErrors,
253838
+ annotationStoryError
252337
253839
  ];
252338
253840
  const isReadyToComputeInitialViewState = useReady([
252339
253841
  obsPointsDataStatus,
@@ -252358,13 +253860,16 @@ function SpatialSubscriber(props) {
252358
253860
  segmentationMultiIndicesDataStatus,
252359
253861
  obsSegmentationsLocationsDataStatus,
252360
253862
  // Images
252361
- imageDataStatus
253863
+ imageDataStatus,
253864
+ // Annotations
253865
+ annotationStoryStatus
252362
253866
  ]);
252363
253867
  const urls2 = useUrls([
252364
253868
  Object.values(obsSpotsUrls || {}).flat(),
252365
253869
  Object.values(obsPointsUrls || {}).flat(),
252366
253870
  Object.values(obsSegmentationsUrls || {}).flat(),
252367
- Object.values(imageUrls || {}).flat()
253871
+ Object.values(imageUrls || {}).flat(),
253872
+ annotationStoryUrls
252368
253873
  // TODO: more urls
252369
253874
  // TODO: a bit of memoization
252370
253875
  ]);
@@ -252612,7 +254117,7 @@ function SpatialSubscriber(props) {
252612
254117
  target: [targetX2, targetY2, targetZ],
252613
254118
  rotationX,
252614
254119
  rotationOrbit
252615
- } : 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 }), !disableTooltip && jsx$1(SpatialTooltipSubscriber, {
254120
+ } : 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, annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection }), !disableTooltip && jsx$1(SpatialTooltipSubscriber, {
252616
254121
  parentUuid: uuid2,
252617
254122
  width: width2,
252618
254123
  height: height2,
@@ -260029,7 +261534,7 @@ _defineProperty$3(WindowScroller, "defaultProps", {
260029
261534
  serverHeight: 0,
260030
261535
  serverWidth: 0
260031
261536
  });
260032
- const useStyles$p = makeStyles()((theme) => ({
261537
+ const useStyles$q = makeStyles()((theme) => ({
260033
261538
  selectableTable: {
260034
261539
  flex: "1 1 auto",
260035
261540
  outline: "none"
@@ -260178,7 +261683,7 @@ function SelectableTable(props) {
260178
261683
  onChange(null);
260179
261684
  }
260180
261685
  }, [selectedRows, allowMultiple]);
260181
- const { classes: classes2 } = useStyles$p();
261686
+ const { classes: classes2 } = useStyles$q();
260182
261687
  const inputUuid = v4$1();
260183
261688
  const rowRenderer = ({ index: index2, style: style2 }) => (
260184
261689
  // eslint-disable-next-line jsx-a11y/interactive-supports-focus
@@ -260203,7 +261708,7 @@ const FEATURELIST_SORT_OPTIONS = [
260203
261708
  "original"
260204
261709
  ];
260205
261710
  const ALT_COLNAME = "Alternate ID";
260206
- const useStyles$o = makeStyles()(() => ({
261711
+ const useStyles$p = makeStyles()(() => ({
260207
261712
  searchBar: {
260208
261713
  marginTop: "10px",
260209
261714
  marginLeft: "10px",
@@ -260216,7 +261721,7 @@ const useStyles$o = makeStyles()(() => ({
260216
261721
  }));
260217
261722
  function FeatureList(props) {
260218
261723
  const { width: width2, height: height2, hasColorEncoding, geneList = [], featureLabelsMap, geneSelection = [], geneFilter = null, setGeneSelection, enableMultiSelect, showFeatureTable, featureListSort, featureListSortKey, hasFeatureLabels, primaryColumnName } = props;
260219
- const { classes: classes2 } = useStyles$o();
261724
+ const { classes: classes2 } = useStyles$p();
260220
261725
  const [searchTerm, setSearchTerm] = useState("");
260221
261726
  const selectableTableSortKey = featureListSortKey === "featureIndex" ? "key" : "name";
260222
261727
  const searchResults = useMemo$1(() => geneList.filter((gene) => gene.toLowerCase().includes(searchTerm.toLowerCase()) || featureLabelsMap?.get(gene)?.toLowerCase().includes(searchTerm.toLowerCase()) || featureLabelsMap?.get(cleanFeatureId(gene))?.toLowerCase().includes(searchTerm.toLowerCase())), [geneList, searchTerm, featureLabelsMap]);
@@ -260289,7 +261794,7 @@ function FeatureListOptions(props) {
260289
261794
  id: `feature-list-show-alternative-ids-${featureListId}`
260290
261795
  } } }) })] })] }) : null] });
260291
261796
  }
260292
- const useStyles$n = makeStyles()((theme) => ({
261797
+ const useStyles$o = makeStyles()((theme) => ({
260293
261798
  featureListContainer: {
260294
261799
  width: "100%",
260295
261800
  height: "100%",
@@ -260304,7 +261809,7 @@ function FeatureListSubscriber(props) {
260304
261809
  const loaders = useLoaders();
260305
261810
  const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
260306
261811
  const [width2, height2, containerRef] = useGridItemSize();
260307
- const { classes: classes2 } = useStyles$n();
261812
+ const { classes: classes2 } = useStyles$o();
260308
261813
  const [{ dataset, obsType, featureType, featureSelection: geneSelection, featureFilter: geneFilter, obsColorEncoding: cellColorEncoding }, { setFeatureSelection: setGeneSelection, setFeatureFilter: setGeneFilter, setFeatureHighlight: setGeneHighlight, setObsColorEncoding: setCellColorEncoding }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.FEATURE_LIST], coordinationScopes);
260309
261814
  const variablesLabel = variablesLabelOverride || featureType;
260310
261815
  const title2 = titleOverride || `${capitalize$3(variablesLabel)} List`;
@@ -260439,7 +261944,7 @@ const useSelectionSliderStyles = makeStyles()(() => ({
260439
261944
  backgroundColor: "rgba(128, 128, 128, 0.7)"
260440
261945
  }
260441
261946
  }));
260442
- const useStyles$m = makeStyles()((theme) => ({
261947
+ const useStyles$n = makeStyles()((theme) => ({
260443
261948
  paletteContainer: {
260444
261949
  width: "70px",
260445
261950
  height: "40px",
@@ -260460,10 +261965,10 @@ const useStyles$m = makeStyles()((theme) => ({
260460
261965
  }
260461
261966
  }));
260462
261967
  const ColorPalette = ({ handleChange }) => {
260463
- const { classes: classes2 } = useStyles$m();
261968
+ const { classes: classes2 } = useStyles$n();
260464
261969
  return jsx$1("div", { className: classes2.paletteContainer, "aria-label": "Color swatch", children: VIEWER_PALETTE.map((color2) => jsx$1(IconButton$1, { className: classes2.button, onClick: () => handleChange(color2), "aria-label": `Change color to ${color2}`, children: jsx$1(LensIcon, { fontSize: "small", style: { color: `rgb(${color2})` }, className: classes2.icon }) }, color2)) });
260465
261970
  };
260466
- const useStyles$l = makeStyles()(() => ({
261971
+ const useStyles$m = makeStyles()(() => ({
260467
261972
  menuButton: {
260468
261973
  backgroundColor: "transparent"
260469
261974
  },
@@ -260482,7 +261987,7 @@ function MuiSpan(props) {
260482
261987
  }
260483
261988
  function ChannelOptions$1({ handlePropertyChange, handleChannelRemove, handleIQRUpdate }) {
260484
261989
  const [open2, setOpen] = useState(false);
260485
- const { classes: classes2 } = useStyles$l();
261990
+ const { classes: classes2 } = useStyles$m();
260486
261991
  const handleColorSelect = (color2) => {
260487
261992
  handlePropertyChange("color", color2);
260488
261993
  };
@@ -261099,7 +262604,7 @@ function LayerController$1(props) {
261099
262604
  minWidth: "50%"
261100
262605
  } })] }), jsx$1(TabPanel, { value: tab2, index: 0, children: FullController }), jsx$1(TabPanel, { value: tab2, index: 1, style: { marginTop: 4 }, children: jsx$1(VolumeOptions, { loader: loader2, handleSlicerSetting, handleRenderingModeChange: setRenderingMode, renderingMode, xSlice, ySlice, zSlice, use3d, setViewState, spatialHeight, spatialWidth, modelMatrix: modelMatrix2 }) })] }) : FullController, shouldShowRemoveLayerButton ? jsx$1(Button, { onClick: handleLayerRemove, fullWidth: true, variant: "outlined", style: buttonStyles, size: "small", children: "Remove Image Layer" }) : null] })] });
261101
262606
  }
261102
- const useStyles$k = makeStyles()(() => ({
262607
+ const useStyles$l = makeStyles()(() => ({
261103
262608
  addButton: {
261104
262609
  marginTop: "10px",
261105
262610
  marginBottom: "10px",
@@ -261111,7 +262616,7 @@ function ImageAddIcon() {
261111
262616
  }
261112
262617
  function ImageAddButton({ imageOptions, handleImageAdd }) {
261113
262618
  const [open2, setOpen] = useState(false);
261114
- const { classes: classes2 } = useStyles$k();
262619
+ const { classes: classes2 } = useStyles$l();
261115
262620
  const handleAdd = (imgData) => {
261116
262621
  setOpen((prev2) => !prev2);
261117
262622
  handleImageAdd(imgData);
@@ -261473,7 +262978,7 @@ const channelControlCellSx = {
261473
262978
  }
261474
262979
  };
261475
262980
  const channelSpacerCellSx = { flexShrink: 0, minWidth: "44px" };
261476
- const useStyles$j = makeStyles()(() => ({
262981
+ const useStyles$k = makeStyles()(() => ({
261477
262982
  colorPickerPaper: {
261478
262983
  overflow: "hidden",
261479
262984
  "& > ul": {
@@ -261531,7 +263036,7 @@ function ChannelColorPickerMenu(props) {
261531
263036
  setColor2([rgb2.r, rgb2.g, rgb2.b]);
261532
263037
  }
261533
263038
  }
261534
- const { classes: classes2 } = useStyles$j();
263039
+ const { classes: classes2 } = useStyles$k();
261535
263040
  const currentColor = color2 ? colorArrayToString(color2) : colorArrayToString(getDefaultColor(theme));
261536
263041
  const isWritable = typeof setColor2 === "function";
261537
263042
  const derivedOpen = isWritable ? isStaticColor && visible ? open2 : false : false;
@@ -261539,7 +263044,7 @@ function ChannelColorPickerMenu(props) {
261539
263044
  [classes2.colorIconOutline]: theme !== "dark" && isEqual$3(color2, [255, 255, 255])
261540
263045
  }), style: { backgroundColor: currentColor } }) : isColormap && visible && featureValueColormap ? jsx$1("div", { className: classes2.colorIcon, children: jsx$1("svg", { width: "18", height: "18", children: jsx$1("image", { x: 0, y: 0, width: 18, height: 18, preserveAspectRatio: "none", href: getXlinkHref(featureValueColormap), clipPath: "inset(0% round 4px)" }) }) }) : jsx$1("div", { className: classes2.colorIcon }), buttonClassName: classes2.colorIconButton, withPaper: true, paperClassName: classes2.colorPickerPaper, "aria-label": "Open color picker menu", children: jsx$1(Twitter$1, { className: classes2.colorPicker, disableAlpha: true, width: 108, triangle: "hide", colors: defaultPalette, color: currentColor, onChangeComplete: handleColorChange }) });
261541
263046
  }
261542
- const useStyles$i = makeStyles()(() => ({
263047
+ const useStyles$j = makeStyles()(() => ({
261543
263048
  layerTypeSpotIcon: {
261544
263049
  height: "100%",
261545
263050
  marginLeft: "1px",
@@ -261552,7 +263057,7 @@ const useStyles$i = makeStyles()(() => ({
261552
263057
  function SpotLayerEllipsisMenu(props) {
261553
263058
  const { strokeWidth, setStrokeWidth, filled, setFilled, featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormap, setFeatureValueColormap, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible } = props;
261554
263059
  const [open2, setOpen] = useState(false);
261555
- const { classes: classes2 } = useStyles$i();
263060
+ const { classes: classes2 } = useStyles$j();
261556
263061
  const { classes: selectClasses2 } = useSelectStyles();
261557
263062
  const { classes: menuClasses } = useEllipsisMenuStyles();
261558
263063
  const filledId = $bdb11010cef70236$export$f680877a34711e37();
@@ -261574,7 +263079,7 @@ function SpotLayerController(props) {
261574
263079
  const Visibility = useMemo$1(() => visibleSetting ? VisibilityIcon : VisibilityOffIcon, [visibleSetting]);
261575
263080
  const isStaticColor = obsColorEncoding === "spatialLayerColor";
261576
263081
  const isColormap = obsColorEncoding === "geneSelection";
261577
- const { classes: classes2 } = useStyles$i();
263082
+ const { classes: classes2 } = useStyles$j();
261578
263083
  const { classes: lcClasses } = useControllerSectionStyles();
261579
263084
  const { classes: menuClasses } = useEllipsisMenuStyles();
261580
263085
  const handleVisibleChange = useCallback(() => {
@@ -261584,7 +263089,7 @@ function SpotLayerController(props) {
261584
263089
  const handleOpacityChange = useCallback((e3, v) => setOpacity2(v), [setOpacity2]);
261585
263090
  return jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsx$1(Paper, { elevation: 4, className: lcClasses.layerControllerRoot, children: jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: handleVisibleChange, className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle spot layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: color2, setColor: setColor2, palette, isStaticColor, isColormap, featureValueColormap, visible }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: label2 }) }), jsx$1(Grid$1, { size: 2, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(SpotLayerEllipsisMenu, { filled, setFilled, strokeWidth, setStrokeWidth, featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormap, setFeatureValueColormap, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(SvgSpots, { className: classes2.layerTypeSpotIcon }) })] }) }) });
261586
263091
  }
261587
- const useStyles$h = makeStyles()(() => ({
263092
+ const useStyles$i = makeStyles()(() => ({
261588
263093
  layerFeatureControllerGrid: {
261589
263094
  padding: "0",
261590
263095
  flexWrap: "nowrap"
@@ -261629,7 +263134,7 @@ function LayerPerFeatureController(props) {
261629
263134
  ]);
261630
263135
  }
261631
263136
  }, [featureName, featureColor, setFeatureColor, featureColorIndex]);
261632
- const { classes: classes2 } = useStyles$h();
263137
+ const { classes: classes2 } = useStyles$i();
261633
263138
  const { classes: lcClasses } = useControllerSectionStyles();
261634
263139
  const { classes: menuClasses } = useEllipsisMenuStyles();
261635
263140
  const [open2, setOpen] = useState(false);
@@ -261683,7 +263188,7 @@ function LayerPerFeatureController(props) {
261683
263188
  ]);
261684
263189
  return jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsxs(Paper, { elevation: 2, className: lcClasses.layerControllerSubRow, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: handleRemoveFeature, className: menuClasses.imageLayerVisibleButton, "aria-label": "Remove feature", children: jsx$1(ClearIcon, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(Tooltip$3, { title: colorPickerTooltip ?? "", disableHoverListener: !colorPickerTooltip, placement: "top", children: jsx$1("span", { children: jsx$1(ChannelColorPickerMenu, { theme, color: colorPickerColor, setColor: colorPickerWritable ? handleColorChange : null, palette, isStaticColor: colorPickerReadable, isColormap: false, featureValueColormap, visible: true }) }) }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: featureName }) }), jsx$1(Grid$1, { size: 2, sx: { paddingRight: "12px", overflow: "visible" }, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${featureName}` }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", children: [jsx$1(SvgPoints, { className: classes2.layerTypeFeatureIcon }), null] })] }), loadingDoneFraction < 1 ? jsx$1(Grid$1, { size: 12, container: true, direction: "column", justifyContent: "space-between", className: classes2.layerFeatureControllerGrid, children: jsx$1(LinearProgress, { variant: loadingDoneFraction === 0 ? "indeterminate" : "determinate", value: loadingDoneFraction * 100 }) }) : null] }) }, featureName);
261685
263190
  }
261686
- const useStyles$g = makeStyles()(() => ({
263191
+ const useStyles$h = makeStyles()(() => ({
261687
263192
  pointLayerButton: {
261688
263193
  borderStyle: "dashed",
261689
263194
  marginTop: "10px",
@@ -261800,7 +263305,7 @@ function PointLayerController(props) {
261800
263305
  featureSelection,
261801
263306
  showStaticColor
261802
263307
  ]);
261803
- const { classes: classes2 } = useStyles$g();
263308
+ const { classes: classes2 } = useStyles$h();
261804
263309
  const { classes: lcClasses } = useControllerSectionStyles();
261805
263310
  const { classes: menuClasses } = useEllipsisMenuStyles();
261806
263311
  const handleVisibleChange = useCallback(() => {
@@ -261829,7 +263334,7 @@ function PointLayerController(props) {
261829
263334
  }, [featureSelection, obsColorEncoding, featureIndex, featureColor]);
261830
263335
  return jsxs(Grid$1, { className: lcClasses.layerControllerGrid, children: [jsxs(Paper, { elevation: 4, className: lcClasses.layerControllerRoot, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", sx: channelRowContainerSx, children: [jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(Button, { onClick: handleVisibleChange, className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(ChannelColorPickerMenu, { theme, color: color2, setColor: setColor2, palette, isStaticColor, isColormap, featureValueColormap, visible }) }), jsx$1(Grid$1, { size: 6, sx: channelSelectorCellSx, children: jsx$1(Typography, { className: menuClasses.imageLayerName, title: label2, children: label2 }) }), jsx$1(Grid$1, { size: 2, sx: channelSliderCellSx, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(PointLayerEllipsisMenu, { featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible, featureFilterMode, setFeatureFilterMode, featureValueColormap, setFeatureValueColormap }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", sx: channelControlCellSx, children: [jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }), null] })] }), loadingDoneFraction < 1 ? jsx$1(Grid$1, { size: 12, container: true, direction: "column", justifyContent: "space-between", className: classes2.pointFeatureControllerGrid, children: jsx$1(LinearProgress, { variant: loadingDoneFraction === 0 ? "indeterminate" : "determinate", value: loadingDoneFraction * 100 }) }) : null, null] }), layerPerFeatureForPoints && hasSelectedFeatures ? jsxs(Fragment, { children: [featureSelection.map((featureName) => jsx$1(LayerPerFeatureController, { theme, featureName, featureColor, setFeatureColor, spatialLayerColor, featureIndex, featureValueColormap, featureSelection, setFeatureSelection, obsColorEncoding, loadingDoneFraction, opacity: opacity2, handleOpacityChange }, featureName)), jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsx$1(Paper, { elevation: 2, className: lcClasses.layerControllerSubRow, children: jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: () => setFeatureFilterMode(featureFilterMode === "featureSelection" ? null : "featureSelection"), className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle visibility of unselected points", children: featureFilterMode === "featureSelection" ? jsx$1(VisibilityOffIcon, {}) : jsx$1(VisibilityIcon, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: getDefaultColor("dark"), setColor: null, isStaticColor: true, isColormap: false, visible: true }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: "Unselected" }) }), jsx$1(Grid$1, { size: 2, sx: { paddingRight: "12px", overflow: "visible" }, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": "Adjust opacity for unselected layer" }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }) })] }) }) })] }) : null] });
261831
263336
  }
261832
- const useStyles$f = makeStyles()(() => ({
263337
+ const useStyles$g = makeStyles()(() => ({
261833
263338
  // Cap the channel name's width; imageLayerName ellipsizes the overflow.
261834
263339
  channelName: {
261835
263340
  overflow: "hidden",
@@ -261848,7 +263353,7 @@ const useStyles$f = makeStyles()(() => ({
261848
263353
  function SegmentationChannelEllipsisMenu(props) {
261849
263354
  const { obsType, featureType, featureValueType, strokeWidth, setStrokeWidth, filled, setFilled, featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormap, setFeatureValueColormap, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible } = props;
261850
263355
  const [open2, setOpen] = useState(false);
261851
- const { classes: classes2 } = useStyles$f();
263356
+ const { classes: classes2 } = useStyles$g();
261852
263357
  const { classes: selectClasses2 } = useSelectStyles();
261853
263358
  const { classes: menuClasses } = useEllipsisMenuStyles();
261854
263359
  const filledId = $bdb11010cef70236$export$f680877a34711e37();
@@ -261867,7 +263372,7 @@ function SegmentationChannelController(props) {
261867
263372
  const Visibility = useMemo$1(() => visibleSetting ? VisibilityIcon : VisibilityOffIcon, [visibleSetting]);
261868
263373
  const isStaticColor = obsColorEncoding === "spatialChannelColor";
261869
263374
  const isColormap = obsColorEncoding === "geneSelection";
261870
- const { classes: classes2 } = useStyles$f();
263375
+ const { classes: classes2 } = useStyles$g();
261871
263376
  const { classes: lcClasses } = useControllerSectionStyles();
261872
263377
  const { classes: menuClasses } = useEllipsisMenuStyles();
261873
263378
  const handleVisibleChange = useCallback(() => {
@@ -264585,7 +266090,7 @@ function useBaseQuery(options, Observer, queryClient) {
264585
266090
  function useQuery(options, queryClient) {
264586
266091
  return useBaseQuery(options, QueryObserver);
264587
266092
  }
264588
- const useStyles$e = makeStyles()(() => ({
266093
+ const useStyles$f = makeStyles()(() => ({
264589
266094
  channelMenuButton: {
264590
266095
  backgroundColor: "transparent",
264591
266096
  padding: "3px 0",
@@ -264599,7 +266104,7 @@ const useStyles$e = makeStyles()(() => ({
264599
266104
  function ChannelOptions(props) {
264600
266105
  const { onRemove: onRemove2, onResetWindowUsingIQR, showValueExtent, setShowValueExtent, numResolutions, spatialMaxResolution, setSpatialMaxResolution } = props;
264601
266106
  const [open2, setOpen] = useState(false);
264602
- const { classes: classes2 } = useStyles$e();
266107
+ const { classes: classes2 } = useStyles$f();
264603
266108
  const { classes: selectClasses2 } = useSelectStyles();
264604
266109
  const { classes: menuClasses } = useEllipsisMenuStyles();
264605
266110
  function handleRemove() {
@@ -264612,7 +266117,7 @@ function ChannelOptions(props) {
264612
266117
  const domainTypeId = $bdb11010cef70236$export$f680877a34711e37();
264613
266118
  return jsxs(PopperMenu, { open: open2, setOpen, buttonIcon: jsx$1(MoreVertIcon, { fontSize: "small" }), buttonClassName: classes2.channelMenuButton, containerClassName: menuClasses.imageLayerPopperContainer, placement: "bottom-end", withPaper: true, "aria-label": "Open channel options menu", children: [jsxs(MenuItem, { dense: true, disableGutters: true, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: domainTypeId, children: "Best Resolution: " }), jsx$1(Slider, { value: spatialMaxResolution || 1, valueLabelDisplay: "auto", onChange: (e3, v) => setSpatialMaxResolution(v), min: 1, max: numResolutions - 1, step: 1, orientation: "horizontal" })] }), jsxs(MenuItem, { dense: true, disableGutters: true, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: domainTypeId, children: "Slider Extent: " }), jsxs(NativeSelect, { onChange: handleDomainTypeChange, value: showValueExtent ? "Value Min/Max" : "Dtype Min/Max", inputProps: { id: domainTypeId, "aria-label": "Slider extent selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { value: "Value Min/Max", children: "Value Min/Max" }), jsx$1("option", { value: "Dtype Min/Max", children: "Dtype Min/Max" })] })] }), jsx$1(MenuItem, { dense: true, disableGutters: true, component: "button", onClick: onResetWindowUsingIQR, className: classes2.menuItemButton, "aria-label": "Click to use IQR for channel", children: "Reset window using IQR" }), jsx$1(MenuItem, { dense: true, disableGutters: true, component: "button", onClick: handleRemove, className: classes2.menuItemButton, "aria-label": "Click to remove channel", children: "Remove channel" })] });
264614
266119
  }
264615
- const useStyles$d = makeStyles()(() => ({
266120
+ const useStyles$e = makeStyles()(() => ({
264616
266121
  channelSlider: {
264617
266122
  marginTop: "7px"
264618
266123
  }
@@ -264622,13 +266127,13 @@ function ChannelSlider(props) {
264622
266127
  const rgbColor = toRgbUIString(colormapOn, color2, theme);
264623
266128
  const dtype = image2?.getDtype();
264624
266129
  const fullDomain = dtype ? DOMAINS[dtype] : [0, 0];
264625
- const { classes: classes2 } = useStyles$d();
266130
+ const { classes: classes2 } = useStyles$e();
264626
266131
  useEffect(() => {
264627
- if (!window2 && !disabled && Array.isArray(minMaxDomain)) {
264628
- setWindow2(minMaxDomain);
266132
+ if (!window2 && !disabled && Array.isArray(minMaxDomain?.upperThreeQuarters)) {
266133
+ setWindow2(minMaxDomain?.upperThreeQuarters);
264629
266134
  }
264630
266135
  }, [minMaxDomain, window2, disabled]);
264631
- const [min2, max2] = (showValueExtent ? minMaxDomain : fullDomain) || [0, 0];
266136
+ const [min2, max2] = (showValueExtent ? minMaxDomain?.minMax : fullDomain) || [0, 0];
264632
266137
  const step = max2 - min2 < 500 && dtype?.startsWith("Float") ? (max2 - min2) / 500 : 1;
264633
266138
  const handleChangeDebounced = useCallback(debounce$5(setWindow2 || (() => {
264634
266139
  }), 3, { trailing: true }), [setWindow2]);
@@ -264637,7 +266142,7 @@ function ChannelSlider(props) {
264637
266142
  return `${labelPrefix} for ${rgbColor} colormap channel`;
264638
266143
  }, getAriaValueText: () => `Current colormap values: ${rgbColor}-${window2}`, min: min2, max: max2, step, orientation: "horizontal", className: classes2.channelSlider, style: { color: rgbColor }, disabled });
264639
266144
  }
264640
- const useStyles$c = makeStyles()(() => ({
266145
+ const useStyles$d = makeStyles()(() => ({
264641
266146
  visibilityCheckbox: {
264642
266147
  padding: "10px 0"
264643
266148
  }
@@ -264651,10 +266156,10 @@ function getCheckboxColor(colormapOn, color2, theme) {
264651
266156
  function ChannelVisibilityCheckbox(props) {
264652
266157
  const { color: color2, visible, setVisible, disabled, theme, colormapOn } = props;
264653
266158
  const rgbColor = getCheckboxColor(colormapOn, color2, theme);
264654
- const { classes: classes2 } = useStyles$c();
266159
+ const { classes: classes2 } = useStyles$d();
264655
266160
  return jsx$1(Checkbox$1, { onChange: (e3, v) => setVisible(v), checked: visible, disabled, className: classes2.visibilityCheckbox, style: { color: rgbColor, "&$checked": { color: rgbColor } }, slotProps: { input: { "aria-label": "Toggle channel visibility" } } });
264656
266161
  }
264657
- const useStyles$b = makeStyles()(() => ({
266162
+ const useStyles$c = makeStyles()(() => ({
264658
266163
  oneLineChannelSelect: {
264659
266164
  width: "90%",
264660
266165
  marginLeft: "5%",
@@ -264663,7 +266168,7 @@ const useStyles$b = makeStyles()(() => ({
264663
266168
  }));
264664
266169
  function ChannelSelectionDropdown(props) {
264665
266170
  const { featureIndex, channelsSortOrder, targetC, setTargetC, setWindow: setWindow2, disabled } = props;
264666
- const { classes: classes2 } = useStyles$b();
266171
+ const { classes: classes2 } = useStyles$c();
264667
266172
  const { classes: selectClasses2 } = useSelectStyles();
264668
266173
  function handleChange(event2) {
264669
266174
  setTargetC(event2.target.value === "" ? null : Number(event2.target.value));
@@ -264733,7 +266238,13 @@ function ImageChannelController(props) {
264733
266238
  use3d: ctx.queryKey[5]
264734
266239
  });
264735
266240
  const [newDomain] = stats.domains;
264736
- return newDomain;
266241
+ return {
266242
+ minMax: newDomain,
266243
+ // iqr: [stats.q1s[0], stats.q3s[0]],
266244
+ // This seems to work better than the IQR for the slider
266245
+ // upper bound.
266246
+ upperThreeQuarters: [stats.q1s[0], newDomain[1]]
266247
+ };
264737
266248
  },
264738
266249
  meta: { image: image2 }
264739
266250
  });
@@ -264741,7 +266252,7 @@ function ImageChannelController(props) {
264741
266252
  const disabled = minMaxQuery.isLoading;
264742
266253
  function handleResetWindowUsingIQR() {
264743
266254
  if (!disabled) {
264744
- setWindow2(minMaxDomain);
266255
+ setWindow2(minMaxDomain?.upperThreeQuarters);
264745
266256
  }
264746
266257
  }
264747
266258
  return jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", sx: channelRowContainerSx, children: [jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(ChannelVisibilityCheckbox, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, colormapOn }) }), jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(ChannelColorPickerMenu, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, isStaticColor: !colormapOn, palette: VIEWER_PALETTE }) }), jsx$1(Grid$1, { size: 6, sx: channelSelectorCellSx, children: jsx$1(ChannelSelectionDropdown, { featureIndex, targetC, setTargetC, setWindow: setWindow2, disabled: isLoading, channelsSortOrder }) }), jsx$1(Grid$1, { size: 3, sx: channelSliderCellSx, children: jsx$1(ChannelSlider, { image: image2, targetT, targetZ, targetC, window: window2, setWindow: setWindow2, disabled, color: color2, theme, colormapOn, showValueExtent, minMaxDomain }) }), jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(ChannelOptions, { onRemove: onRemove2, showValueExtent, setShowValueExtent, onResetWindowUsingIQR: handleResetWindowUsingIQR, numResolutions, spatialMaxResolution, setSpatialMaxResolution }) })] });
@@ -264798,7 +266309,7 @@ function LoadingStatusIndicator(props) {
264798
266309
  }
264799
266310
  return jsxs(Grid$1, { container: true, px: 0.5, children: [jsx$1(Grid$1, { size: 6, alignItems: "start", children: jsx$1(Grid$1, { container: true, alignItems: "center", gap: 1, children: statusColor !== "success" ? jsx$1(StatusChip, { label: statusLabel, color: statusColor, size: "small" }) : null }) }), jsx$1(Grid$1, { size: 6, px: 1, my: 0.25, children: jsx$1(LoadingText, { bricksLoaded, currentRequestCount, totalBricksRequested, isLoading }) }), jsx$1(Grid$1, { size: 12, children: jsxs(Grid$1, { container: true, direction: "row", spacing: 2, alignItems: "center", wrap: "nowrap", children: [jsx$1(LoadingControlButton, { startIcon: jsx$1(Stop, {}), onClick: onStopLoading, disabled: noNewRequests, ariaLabel: "Stop loading data and render at highest resolution", children: "Stop Loading" }), jsx$1(LoadingControlButton, { startIcon: jsx$1(Replay, {}), onClick: onRestartLoading, disabled: !noNewRequests && !isLoading, ariaLabel: "Restart data loading", children: "Restart Loading" })] }) }), jsx$1(Grid$1, { size: 12, visibility: isLoading ? "visible" : "hidden", mt: 1, mb: 0.5, children: jsx$1(LinearProgress, { variant: "determinate", value: percentage }) })] });
264800
266311
  }
264801
- const useStyles$a = makeStyles()(() => ({
266312
+ const useStyles$b = makeStyles()(() => ({
264802
266313
  imageLayerButton: {
264803
266314
  borderStyle: "dashed",
264804
266315
  marginTop: "10px",
@@ -264941,7 +266452,7 @@ function ImageLayerController(props) {
264941
266452
  }, [visible, setVisible]);
264942
266453
  const handleOpacityChange = useCallback((e3, v) => setOpacity2(v), [setOpacity2]);
264943
266454
  const handleOpenChange = useCallback(() => setOpen((prev2) => !prev2), []);
264944
- const { classes: classes2 } = useStyles$a();
266455
+ const { classes: classes2 } = useStyles$b();
264945
266456
  const { classes: menuClasses } = useEllipsisMenuStyles();
264946
266457
  const { classes: controllerSectionClasses } = useControllerSectionStyles();
264947
266458
  const isMultiChannel = photometricInterpretation !== "RGB";
@@ -264953,7 +266464,7 @@ function ImageLayerController(props) {
264953
266464
  return jsx$1(ImageChannelController, { theme, coordinationScopesRaw, layerScope, channelScope: cScope, targetT, targetZ, targetC: channelIndex, setTargetC: setSpatialTargetC, visible: spatialChannelVisible, setVisible: setSpatialChannelVisible, opacity: spatialChannelOpacity, setOpacity: setSpatialChannelOpacity, color: spatialChannelColor, setColor: setSpatialChannelColor, window: spatialChannelWindow, setWindow: setSpatialChannelWindow, colormapOn: colormap !== null, featureIndex, image: image2, channelsSortOrder, spatialRenderingMode, numResolutions, spatialMaxResolution, setSpatialMaxResolution }, cScope);
264954
266465
  }), jsx$1(Button, { disabled: channelScopes.length === MAX_CHANNELS$1 || channelScopes.length === imageNumChannels, onClick: handleChannelAdd, fullWidth: true, variant: "outlined", className: classes2.imageLayerButton, startIcon: jsx$1(AddIcon, {}), size: "small", "aria-label": "Add a channel to this layer", children: "Add Channel" })] }) : null, is3dMode && image2 ? jsxs(Grid$1, { container: true, direction: "column", justifyContent: "space-between", className: classes2.imageChannelControllerGrid, children: [jsx$1(Typography, { className: classes2.clippingPanesLabel, children: "Clipping planes:" }), jsx$1(Grid$1, { size: 12, className: classes2.clippingSliders, children: jsx$1(ClippingSliders, { image: image2, spatialSliceX, spatialSliceY, spatialSliceZ, setSpatialSliceX, setSpatialSliceY, setSpatialSliceZ }) }), jsx$1(LoadingStatusIndicator, { loadingProgress: volumeLoadingProgress, onStopLoading: onStopVolumeLoading, onRestartLoading: onRestartVolumeLoading, stillRef: volumeStillRef, spatialRenderingMode })] }) : null] }) });
264955
266466
  }
264956
- const useStyles$9 = makeStyles()((theme) => ({
266467
+ const useStyles$a = makeStyles()((theme) => ({
264957
266468
  dimensionsIcon: {
264958
266469
  height: "40px",
264959
266470
  width: "40px",
@@ -264977,7 +266488,7 @@ const useStyles$9 = makeStyles()((theme) => ({
264977
266488
  function GlobalDimensionSlider(props) {
264978
266489
  const { label: label2, targetValue, setTargetValue, min: min2 = 0, max: max2 = 0, spatialRenderingMode = null, setSpatialRenderingMode = null, enable3d = true } = props;
264979
266490
  const { classes: lcClasses } = useControllerSectionStyles();
264980
- const { classes: classes2 } = useStyles$9();
266491
+ const { classes: classes2 } = useStyles$a();
264981
266492
  const isForZ = spatialRenderingMode !== null;
264982
266493
  const is3dMode = spatialRenderingMode === "3D";
264983
266494
  function handleRenderingModeChange(event2) {
@@ -264988,7 +266499,7 @@ function GlobalDimensionSlider(props) {
264988
266499
  }
264989
266500
  return jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsx$1(Paper, { elevation: 4, className: lcClasses.layerControllerRoot, children: jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", sx: channelRowContainerSx, children: [jsx$1(Grid$1, { size: 1, sx: channelControlCellSx, children: jsx$1(SvgDimensions, { className: classes2.dimensionsIcon }) }), jsx$1(Grid$1, { size: 1, sx: channelSelectorCellSx, children: jsx$1(Typography, { className: classes2.dimensionLabel, children: label2 }) }), jsx$1(Grid$1, { size: 8, sx: channelSliderCellSx, children: !is3dMode ? jsx$1(Slider, { value: targetValue, min: min2, max: max2, step: 1, onChange: (e3, v) => setTargetValue(v), className: classes2.dimensionSlider, valueLabelDisplay: "auto", orientation: "horizontal", disabled: spatialRenderingMode === "3D", "aria-label": `${label2}-slice slider` }) : null }), jsx$1(Grid$1, { size: 2, sx: channelControlCellSx, children: isForZ && enable3d ? jsx$1(FormGroup, { row: true, className: classes2.switchFormGroup, children: jsx$1(FormControlLabel$1, { control: jsx$1(Switch, { color: "primary", checked: spatialRenderingMode === "3D", onChange: handleRenderingModeChange, name: "is3dMode" }), label: "3D" }) }) : null })] }) }) });
264990
266501
  }
264991
- const useStyles$8 = makeStyles()(() => ({
266502
+ const useStyles$9 = makeStyles()(() => ({
264992
266503
  layerTypeCentroidSegmentationIcon: {
264993
266504
  height: "100%",
264994
266505
  marginLeft: "1px",
@@ -265038,7 +266549,7 @@ function CombinedEllipsisMenu(props) {
265038
266549
  }
265039
266550
  function SegmentationCentroidsController(props) {
265040
266551
  const { theme, segScope, segLayerCoordination, segChannelScopesByLayer, segChannelCoordination, pointScope, pointLayerCoordination } = props;
265041
- const { classes: classes2 } = useStyles$8();
266552
+ const { classes: classes2 } = useStyles$9();
265042
266553
  const { classes: lcClasses } = useControllerSectionStyles();
265043
266554
  const { classes: menuClasses } = useEllipsisMenuStyles();
265044
266555
  const channelScopes = segChannelScopesByLayer?.[segScope] ?? [];
@@ -265480,6 +266991,92 @@ function LinkControllerSubscriber(props) {
265480
266991
  } = props;
265481
266992
  return jsx$1(TitleInfo, { title: title2, closeButtonVisible, removeGridComponent, isScroll: true, theme, isReady: true, children: jsx$1(LinkController, { linkIDInit: linkID, authToken, linkEndpoint, websocketEndpoint, fileTypes, stores, coordinationTypes }) });
265482
266993
  }
266994
+ const useStyles$8 = makeStyles()((theme) => ({
266995
+ textSection: {
266996
+ padding: "6px 10px"
266997
+ },
266998
+ annotationMarkdown: {
266999
+ "& p, details, table": {
267000
+ fontSize: "80%",
267001
+ opacity: "0.8"
267002
+ },
267003
+ "& details": {
267004
+ marginBottom: "6px"
267005
+ },
267006
+ "& summary": {
267007
+ // TODO(monorepo): lighten color by 10%
267008
+ borderBottom: `1px solid ${theme.palette.primaryBackground}`,
267009
+ cursor: "pointer"
267010
+ }
267011
+ },
267012
+ navigation: {
267013
+ display: "flex",
267014
+ alignItems: "center",
267015
+ justifyContent: "space-between",
267016
+ padding: "0 4px",
267017
+ borderTop: `1px solid ${theme.palette.primaryBackground}`,
267018
+ borderBottom: `1px solid ${theme.palette.primaryBackground}`
267019
+ }
267020
+ }));
267021
+ function AnnotationText(props) {
267022
+ const { text: text2, textType } = props;
267023
+ const { classes: classes2 } = useStyles$8();
267024
+ if (!text2) {
267025
+ return null;
267026
+ }
267027
+ return jsx$1("div", { className: classes2.annotationMarkdown, children: textType === DescriptionType.MARKDOWN ? jsx$1(Markdown, { children: text2 }) : jsx$1("p", { children: text2 }) });
267028
+ }
267029
+ function AnnotationController(props) {
267030
+ const { story, frameIndex, setFrameIndex } = props;
267031
+ const { classes: classes2 } = useStyles$8();
267032
+ if (!story) {
267033
+ return jsx$1("div", { className: classes2.textSection, children: jsx$1(Typography, { variant: "body2", children: "No annotation story has been loaded." }) });
267034
+ }
267035
+ const frames = story.frames || [];
267036
+ const numFrames = frames.length;
267037
+ const hasFrameIndex = typeof frameIndex === "number";
267038
+ const currentFrame = hasFrameIndex ? frames[frameIndex] : null;
267039
+ const canGoBack = hasFrameIndex;
267040
+ const canGoForward = hasFrameIndex ? frameIndex < numFrames - 1 : numFrames > 0;
267041
+ function goBack() {
267042
+ setFrameIndex(frameIndex > 0 ? frameIndex - 1 : null);
267043
+ }
267044
+ function goForward() {
267045
+ setFrameIndex(hasFrameIndex ? frameIndex + 1 : 0);
267046
+ }
267047
+ const frameLabel = hasFrameIndex ? `Frame ${frameIndex + 1} of ${numFrames}` : `Overview (${numFrames} frames)`;
267048
+ return jsxs("div", { children: [jsxs("div", { className: classes2.textSection, children: [story.title ? jsx$1(Typography, { variant: "h6", children: story.title }) : null, jsx$1(AnnotationText, { text: story.description, textType: story.descriptionType })] }), jsxs("div", { className: classes2.navigation, children: [jsx$1(Button, { size: "small", onClick: goBack, disabled: !canGoBack, startIcon: jsx$1(ArrowLeft, {}), children: "Previous" }), jsx$1(Typography, { variant: "body2", children: frameLabel }), jsx$1(Button, { size: "small", onClick: goForward, disabled: !canGoForward, endIcon: jsx$1(ArrowRight, {}), children: "Next" })] }), currentFrame ? jsxs("div", { className: classes2.textSection, children: [currentFrame.title ? jsx$1(Typography, { variant: "subtitle1", children: currentFrame.title }) : null, jsx$1(AnnotationText, { text: currentFrame.description, textType: currentFrame.descriptionType })] }) : null, jsx$1(MenuList, { dense: true, "aria-label": "Annotation frames", children: frames.map((frame2, i2) => jsx$1(MenuItem, { selected: i2 === frameIndex, onClick: () => setFrameIndex(i2), children: jsx$1(ListItemText, { primary: `${i2 + 1}. ${frame2.title || frame2.uid}` }) }, frame2.uid)) })] });
267049
+ }
267050
+ function AnnotationControllerSubscriber(props) {
267051
+ const {
267052
+ uuid: uuid2,
267053
+ removeGridComponent,
267054
+ theme,
267055
+ title: title2 = "Annotation",
267056
+ closeButtonVisible,
267057
+ downloadButtonVisible,
267058
+ helpText = ViewHelpMapping.ANNOTATION_CONTROLLER,
267059
+ // TODO: importable/exportable
267060
+ // Note: areAnnotationsEditable is a prop passed down from
267061
+ // the ancestor <Vitessce/> or <VitS/> component.
267062
+ // TODO: use areAnnotationsEditable.
267063
+ // eslint-disable-next-line no-unused-vars
267064
+ areAnnotationsEditable
267065
+ } = props;
267066
+ const loaders = useLoaders();
267067
+ const [
267068
+ // eslint-disable-next-line no-unused-vars
267069
+ coordinationScopes,
267070
+ _coordinationScopesBy,
267071
+ coordinationValues
267072
+ ] = useViewMapping(uuid2);
267073
+ const [{ dataset, annotationStory, annotationFrameIndex }, { setAnnotationStory, setAnnotationFrameIndex }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.ANNOTATION_CONTROLLER], coordinationScopes, coordinationValues, uuid2);
267074
+ const [, annotationStoryStatus, annotationStoryUrls, annotationStoryError] = useAnnotationStoryData(loaders, dataset, false, { setAnnotationStory }, { annotationStory }, {});
267075
+ const errors = [annotationStoryError];
267076
+ const isReady = useReady([annotationStoryStatus]);
267077
+ const urls2 = useUrls([annotationStoryUrls]);
267078
+ return jsx$1(TitleInfo, { title: title2, theme, closeButtonVisible, downloadButtonVisible, removeGridComponent, isScroll: true, isReady, urls: urls2, errors, helpText, withPadding: false, children: jsx$1(AnnotationController, { story: annotationStory, frameIndex: annotationFrameIndex, setFrameIndex: setAnnotationFrameIndex }) });
267079
+ }
265483
267080
  const useStyles$7 = makeStyles()(() => ({
265484
267081
  info: {
265485
267082
  // details
@@ -267291,7 +268888,7 @@ function HiglassGlobalStyles(props) {
267291
268888
  }
267292
268889
  register({ dataFetcher: ZarrMultivecDataFetcher_default, config: ZarrMultivecDataFetcher_default.config }, { pluginType: "dataFetcher" });
267293
268890
  const LazyHiGlassComponent = React__default.lazy(async () => {
267294
- const { HiGlassComponent } = await import("./higlass-byhG4mr1.js");
268891
+ const { HiGlassComponent } = await import("./higlass-PkSl2JRo.js");
267295
268892
  return { default: HiGlassComponent };
267296
268893
  });
267297
268894
  const HG_SIZE = 800;
@@ -270248,7 +271845,7 @@ function NeuroglancerGlobalStyles(props) {
270248
271845
  const { classes: classes2 } = props;
270249
271846
  return jsxs(Fragment, { children: [jsx$1(GlobalStyles$3, { styles: globalNeuroglancerCss }), jsx$1(ScopedGlobalStyles, { styles: globalNeuroglancerStyles, parentClassName: classes2.neuroglancerWrapper })] });
270250
271847
  }
270251
- const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-DlP3D-Nj.js"));
271848
+ const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-Dc6wub70.js"));
270252
271849
  function createWorker() {
270253
271850
  const worker = new WorkerFactory$1();
270254
271851
  worker.AsyncComputationWorker = WorkerFactory;
@@ -324565,7 +326162,7 @@ const VEGA_THEMES = {
324565
326162
  };
324566
326163
  const DATASET_NAME = "table";
324567
326164
  function VegaGlobalStyles() {
324568
- const { theme } = useStyles$A();
326165
+ const { theme } = useStyles$B();
324569
326166
  return jsx$1(GlobalStyles$3, { styles: {
324570
326167
  "#vg-tooltip-element.vg-tooltip.custom-theme": {
324571
326168
  boxShadow: "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)",
@@ -324599,7 +326196,7 @@ function renderTooltipContents(tooltipText) {
324599
326196
  }
324600
326197
  function VegaPlot(props) {
324601
326198
  const { spec: partialSpec, data: data2, getTooltipText, signalListeners, renderer = "svg", onNewView } = props;
324602
- const { classes: tooltipClasses2 } = useStyles$v();
326199
+ const { classes: tooltipClasses2 } = useStyles$w();
324603
326200
  const tooltipHandler = useMemo$1(() => {
324604
326201
  if (typeof getTooltipText === "function") {
324605
326202
  const tooltipConfig = {
@@ -326787,8 +328384,10 @@ class VitessceConfigView {
326787
328384
  * @param {number} y The y-coordinate of the view in the layout.
326788
328385
  * @param {number} w The width of the view in the layout.
326789
328386
  * @param {number} h The height of the view in the layout.
328387
+ * @param {object} coordinationValues A mapping from coordination type names
328388
+ * to coordination values which this view defines directly.
326790
328389
  */
326791
- constructor(component, coordinationScopes, x2, y2, w2, h2, uid2) {
328390
+ constructor(component, coordinationScopes, x2, y2, w2, h2, uid2, coordinationValues) {
326792
328391
  this.view = {
326793
328392
  component,
326794
328393
  coordinationScopes,
@@ -326798,7 +328397,8 @@ class VitessceConfigView {
326798
328397
  y: y2,
326799
328398
  w: w2,
326800
328399
  h: h2,
326801
- uid: uid2
328400
+ uid: uid2,
328401
+ coordinationValues
326802
328402
  };
326803
328403
  }
326804
328404
  /**
@@ -326832,6 +328432,21 @@ class VitessceConfigView {
326832
328432
  this.view.coordinationScopesBy = nextCoordinationScopesBy;
326833
328433
  return this;
326834
328434
  }
328435
+ /**
328436
+ * Set coordination values on this view directly, without a coordination
328437
+ * scope in the coordination space as an intermediary.
328438
+ * These values take precedence over any coordination scope
328439
+ * (from coordinationScopes or metaCoordinationScopes) for the same type.
328440
+ * @param {object} cValues A mapping from coordination type names to values.
328441
+ * @returns {VitessceConfigView} This, to allow chaining.
328442
+ */
328443
+ setCoordinationValues(cValues) {
328444
+ this.view.coordinationValues = {
328445
+ ...this.view.coordinationValues || {},
328446
+ ...cValues
328447
+ };
328448
+ return this;
328449
+ }
326835
328450
  /**
326836
328451
  * Attach meta coordination scopes to this view.
326837
328452
  * @param {VitessceConfigMetaCoordinationScope} metaScope A meta coordination scope instance.
@@ -327342,7 +328957,8 @@ class VitessceConfig {
327342
328957
  url: f2.url,
327343
328958
  fileType: f2.fileType,
327344
328959
  coordinationValues: f2.coordinationValues,
327345
- options: f2.options
328960
+ options: f2.options,
328961
+ requestInit: f2.requestInit
327346
328962
  });
327347
328963
  });
327348
328964
  });
@@ -327358,7 +328974,7 @@ class VitessceConfig {
327358
328974
  }
327359
328975
  });
327360
328976
  config3.layout.forEach((c2) => {
327361
- const newView = new VitessceConfigView(c2.component, c2.coordinationScopes, c2.x, c2.y, c2.w, c2.h, c2.uid);
328977
+ const newView = new VitessceConfigView(c2.component, c2.coordinationScopes, c2.x, c2.y, c2.w, c2.h, c2.uid, c2.coordinationValues);
327362
328978
  vc.config.layout.push(newView);
327363
328979
  });
327364
328980
  return vc;
@@ -327595,7 +329211,7 @@ function getStore(parsedUrl) {
327595
329211
  }
327596
329212
  return fileType.endsWith(".zip") ? ZipFileStore.fromUrl(url, {
327597
329213
  transformEntries: transformEntriesForZipFileStore
327598
- }) : new FetchStore$1(url);
329214
+ }) : new FetchStore$1(url, { fetch: relaxedFetch });
327599
329215
  }
327600
329216
  function ensureStores(parsedUrls) {
327601
329217
  return parsedUrls.map((parsedUrl) => {
@@ -328152,6 +329768,24 @@ class ObsSetsJsonLoader extends JsonLoader {
328152
329768
  }, url, coordinationValues));
328153
329769
  }
328154
329770
  }
329771
+ class AnnotationStoryJsonLoader extends JsonLoader {
329772
+ constructor(dataSource, params2) {
329773
+ super(dataSource, params2);
329774
+ this.schema = annotationStoryObj;
329775
+ }
329776
+ async load() {
329777
+ if (this.cachedResult) {
329778
+ return this.cachedResult;
329779
+ }
329780
+ const payload = await super.load();
329781
+ const { data: annotationStory, url } = payload;
329782
+ const coordinationValues = {
329783
+ annotationStory
329784
+ };
329785
+ this.cachedResult = new LoaderResult({ annotationStory }, url, coordinationValues);
329786
+ return this.cachedResult;
329787
+ }
329788
+ }
328155
329789
  class CellsJsonAsObsEmbeddingLoader extends JsonLoader {
328156
329790
  constructor(dataSource, params2) {
328157
329791
  super(dataSource, params2);
@@ -350941,7 +352575,8 @@ const baseViewTypes = [
350941
352575
  makeViewType(ViewType$1.COMPARATIVE_HEADING, ComparativeHeadingSubscriber),
350942
352576
  makeViewType(ViewType$1.SAMPLE_SET_PAIR_MANAGER, SampleSetPairManagerSubscriber),
350943
352577
  makeViewType(ViewType$1.OBS_SET_COMPOSITION_BAR_PLOT, CellSetCompositionBarPlotSubscriber),
350944
- makeViewType(ViewType$1.FEATURE_SET_ENRICHMENT_BAR_PLOT, FeatureSetEnrichmentBarPlotSubscriber)
352578
+ makeViewType(ViewType$1.FEATURE_SET_ENRICHMENT_BAR_PLOT, FeatureSetEnrichmentBarPlotSubscriber),
352579
+ makeViewType(ViewType$1.ANNOTATION_CONTROLLER, AnnotationControllerSubscriber)
350945
352580
  ];
350946
352581
  const baseFileTypes = [
350947
352582
  // All CSV file types
@@ -350958,6 +352593,7 @@ const baseFileTypes = [
350958
352593
  // All JSON file types
350959
352594
  makeFileType(FileType$1.OBS_SEGMENTATIONS_JSON, DataType$3.OBS_SEGMENTATIONS, ObsSegmentationsJsonLoader, JsonSource, z.null()),
350960
352595
  makeFileType(FileType$1.OBS_SETS_JSON, DataType$3.OBS_SETS, ObsSetsJsonLoader, JsonSource, z.null()),
352596
+ makeFileType(FileType$1.ANNOTATION_STORY_JSON, DataType$3.ANNOTATION_STORY, AnnotationStoryJsonLoader, JsonSource, z.null()),
350961
352597
  // All AnnData file types
350962
352598
  ...makeZarrFileTypes(FileType$1.OBS_SETS_ANNDATA_ZARR, DataType$3.OBS_SETS, ObsSetsAnndataLoader, AnnDataSource, obsSetsAnndataSchema),
350963
352599
  ...makeZarrFileTypes(FileType$1.OBS_EMBEDDING_ANNDATA_ZARR, DataType$3.OBS_EMBEDDING, ObsEmbeddingAnndataLoader, AnnDataSource, obsEmbeddingAnndataSchema),
@@ -351213,7 +352849,16 @@ const baseCoordinationTypes = [
351213
352849
  new PluginCoordinationType(CoordinationType$1.FEATURE_POINT_SIGNIFICANCE_THRESHOLD, 0.01, z.number().nullable()),
351214
352850
  new PluginCoordinationType(CoordinationType$1.FEATURE_LABEL_SIGNIFICANCE_THRESHOLD, 0.01, z.number().nullable()),
351215
352851
  new PluginCoordinationType(CoordinationType$1.FEATURE_POINT_FOLD_CHANGE_THRESHOLD, 1, z.number().nullable()),
351216
- new PluginCoordinationType(CoordinationType$1.FEATURE_LABEL_FOLD_CHANGE_THRESHOLD, 5, z.number().nullable())
352852
+ new PluginCoordinationType(CoordinationType$1.FEATURE_LABEL_FOLD_CHANGE_THRESHOLD, 5, z.number().nullable()),
352853
+ // Annotation frames
352854
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_STORY, null, annotationStoryObj.nullable()),
352855
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_SHAPES, null, annotationShapesArray.nullable()),
352856
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_FRAME_INDEX, null, z.number().nullable()),
352857
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE, true, z.boolean()),
352858
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_TRANSITION_DURATION, 0, z.number()),
352859
+ // TODO: make this non-zero by default?
352860
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM, true, z.boolean()),
352861
+ new PluginCoordinationType(CoordinationType$1.ANNOTATION_EDITABLE, false, z.boolean())
351217
352862
  ];
351218
352863
  const baseAsyncFunctions = [
351219
352864
  new PluginAsyncFunction(AsyncFunctionType.AUTOCOMPLETE_FEATURE, autocompleteFeature),