@vitessce/scatterplot-embedding 4.0.8 → 4.0.9

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.
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import React__default, { useLayoutEffect, useEffect, cloneElement, createElement, forwardRef, useState, useRef, useMemo, useImperativeHandle, useContext, createContext, isValidElement, Children, PureComponent, useCallback, useDeferredValue } from "react";
3
- import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useCoordinationScopes, useSetComponentHover, useSetComponentViewInfo, useCoordination, useInitialCoordination, useDeckCanvasSize, useMultiObsLabels, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useExpandedFeatureLabelsMap, useSampleSetsData, useSampleEdgesData, useReady, useUrls, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo } from "@vitessce/vit-s";
3
+ import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useViewMapping, useSetComponentHover, useSetComponentViewInfo, useAnnotationFrameCoordination, useCoordination, useInitialCoordination, useDeckCanvasSize, useAnnotationStoryData, useMultiObsLabels, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useExpandedFeatureLabelsMap, useSampleSetsData, useSampleEdgesData, useReady, useUrls, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo, useCoordinationScopes } from "@vitessce/vit-s";
4
4
  import { jsxs, jsx as jsx$1, Fragment } from "react/jsx-runtime";
5
5
  import * as ReactDOM from "react-dom";
6
6
  function _mergeNamespaces(n2, m2) {
@@ -2214,11 +2214,11 @@ function requireConcaveman() {
2214
2214
  while (node2) {
2215
2215
  for (var i2 = 0; i2 < node2.children.length; i2++) {
2216
2216
  var child = node2.children[i2];
2217
- var dist = node2.leaf ? sqSegDist(child, b, c2) : sqSegBoxDist(b, c2, child);
2218
- if (dist > maxDist) continue;
2217
+ var dist2 = node2.leaf ? sqSegDist(child, b, c2) : sqSegBoxDist(b, c2, child);
2218
+ if (dist2 > maxDist) continue;
2219
2219
  queue.push({
2220
2220
  node: child,
2221
- dist
2221
+ dist: dist2
2222
2222
  });
2223
2223
  }
2224
2224
  while (queue.length && !queue.peek().node.children) {
@@ -7096,7 +7096,7 @@ const latestFileDefSchema = z.object({
7096
7096
  options: fileOptionsSchema.optional(),
7097
7097
  requestInit: requestInit.optional(),
7098
7098
  // New: file def can have coordinationValues.
7099
- coordinationValues: z.record(z.string()).optional()
7099
+ coordinationValues: z.record(z.any()).optional()
7100
7100
  });
7101
7101
  const datasetsSchema1_0_13 = z.array(z.object({
7102
7102
  uid: z.string(),
@@ -7127,7 +7127,8 @@ const configSchema1_0_16 = configSchema1_0_13.extend({
7127
7127
  h: z.number().int().optional(),
7128
7128
  // Updates coordinationScopes and coordinationScopesBy
7129
7129
  coordinationScopes: componentCoordinationScopes.optional(),
7130
- coordinationScopesBy: componentCoordinationScopesBy.optional()
7130
+ coordinationScopesBy: componentCoordinationScopesBy.optional(),
7131
+ coordinationValues: z.record(z.any()).optional()
7131
7132
  }))
7132
7133
  });
7133
7134
  const configSchema1_0_17 = configSchema1_0_16.extend({
@@ -9634,7 +9635,8 @@ const ViewType$1 = {
9634
9635
  TREEMAP: "treemap",
9635
9636
  SAMPLE_SET_PAIR_MANAGER: "sampleSetPairManager",
9636
9637
  FEATURE_STATS_TABLE: "featureStatsTable",
9637
- SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector"
9638
+ SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector",
9639
+ ANNOTATION_CONTROLLER: "annotationController"
9638
9640
  };
9639
9641
  const DataType$2 = {
9640
9642
  OBS_LABELS: "obsLabels",
@@ -9655,7 +9657,8 @@ const DataType$2 = {
9655
9657
  COMPARISON_METADATA: "comparisonMetadata",
9656
9658
  FEATURE_STATS: "featureStats",
9657
9659
  FEATURE_SET_STATS: "featureSetStats",
9658
- OBS_SET_STATS: "obsSetStats"
9660
+ OBS_SET_STATS: "obsSetStats",
9661
+ ANNOTATION_STORY: "annotationStory"
9659
9662
  };
9660
9663
  const FileType$1 = {
9661
9664
  // Joint file types
@@ -9677,6 +9680,7 @@ const FileType$1 = {
9677
9680
  OBS_SETS_CSV: "obsSets.csv",
9678
9681
  OBS_SETS_JSON: "obsSets.json",
9679
9682
  SAMPLE_SETS_CSV: "sampleSets.csv",
9683
+ ANNOTATION_STORY_JSON: "annotationStory.json",
9680
9684
  // OME-Zarr
9681
9685
  IMAGE_OME_ZARR: "image.ome-zarr",
9682
9686
  OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
@@ -9961,7 +9965,15 @@ const CoordinationType$1 = {
9961
9965
  FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
9962
9966
  FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
9963
9967
  // Treemap
9964
- HIERARCHY_LEVELS: "hierarchyLevels"
9968
+ HIERARCHY_LEVELS: "hierarchyLevels",
9969
+ // Annotation frames
9970
+ ANNOTATION_STORY: "annotationStory",
9971
+ ANNOTATION_FRAME_INDEX: "annotationFrameIndex",
9972
+ ANNOTATION_SHAPES: "annotationShapes",
9973
+ ANNOTATION_OVERLAY_VISIBLE: "annotationOverlayVisible",
9974
+ ANNOTATION_TRANSITION_DURATION: "annotationTransitionDuration",
9975
+ ANNOTATION_SEMANTIC_ZOOM: "annotationSemanticZoom",
9976
+ ANNOTATION_EDITABLE: "annotationEditable"
9965
9977
  };
9966
9978
  const ViewHelpMapping = {
9967
9979
  SCATTERPLOT: "The scatterplot displays two-dimensional (pre-computed) dimensionality reduction results (such as from t-SNE or UMAP). Each point on the scatterplot represents an observation (e.g., cell)."
@@ -9980,6 +9992,7 @@ const ViewHelpMapping = {
9980
9992
  [FileType$1.OBS_SEGMENTATIONS_JSON]: DataType$2.OBS_SEGMENTATIONS,
9981
9993
  [FileType$1.OBS_SETS_CSV]: DataType$2.OBS_SETS,
9982
9994
  [FileType$1.OBS_SETS_JSON]: DataType$2.OBS_SETS,
9995
+ [FileType$1.ANNOTATION_STORY_JSON]: DataType$2.ANNOTATION_STORY,
9983
9996
  [FileType$1.IMAGE_OME_ZARR]: DataType$2.IMAGE,
9984
9997
  [FileType$1.OBS_SEGMENTATIONS_OME_ZARR]: DataType$2.OBS_SEGMENTATIONS,
9985
9998
  [FileType$1.OBS_FEATURE_MATRIX_ANNDATA_ZARR]: DataType$2.OBS_FEATURE_MATRIX,
@@ -10102,7 +10115,8 @@ const ViewHelpMapping = {
10102
10115
  [DataType$2.OBS_SET_STATS]: [
10103
10116
  CoordinationType$1.OBS_TYPE
10104
10117
  // TODO: should sampleType, obsSetSelection, and/or sampleSetSelection be used here?
10105
- ]
10118
+ ],
10119
+ [DataType$2.ANNOTATION_STORY]: []
10106
10120
  });
10107
10121
  ({
10108
10122
  // For AnnData:
@@ -10235,7 +10249,9 @@ const ViewHelpMapping = {
10235
10249
  CoordinationType$1.SPATIAL_TARGET_Z,
10236
10250
  CoordinationType$1.SPATIAL_AXIS_FIXED,
10237
10251
  CoordinationType$1.SPATIAL_ORBIT_AXIS,
10238
- CoordinationType$1.FEATURE_AGGREGATION_STRATEGY
10252
+ CoordinationType$1.FEATURE_AGGREGATION_STRATEGY,
10253
+ // Annotation shapes are specific to a view's coordinate system.
10254
+ CoordinationType$1.ANNOTATION_SHAPES
10239
10255
  ];
10240
10256
  const COMPONENT_COORDINATION_TYPES = {
10241
10257
  [ViewType$1.NEUROGLANCER]: [
@@ -10327,7 +10343,14 @@ const COMPONENT_COORDINATION_TYPES = {
10327
10343
  CoordinationType$1.EMBEDDING_CONTOURS_FILLED,
10328
10344
  CoordinationType$1.EMBEDDING_CONTOUR_PERCENTILES,
10329
10345
  CoordinationType$1.CONTOUR_COLOR_ENCODING,
10330
- CoordinationType$1.CONTOUR_COLOR
10346
+ CoordinationType$1.CONTOUR_COLOR,
10347
+ CoordinationType$1.ANNOTATION_STORY,
10348
+ CoordinationType$1.ANNOTATION_SHAPES,
10349
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10350
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10351
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10352
+ CoordinationType$1.ANNOTATION_EDITABLE,
10353
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10331
10354
  ],
10332
10355
  [ViewType$1.DUAL_SCATTERPLOT]: [
10333
10356
  CoordinationType$1.DATASET,
@@ -10443,7 +10466,14 @@ const COMPONENT_COORDINATION_TYPES = {
10443
10466
  CoordinationType$1.ADDITIONAL_OBS_SETS,
10444
10467
  CoordinationType$1.MOLECULE_HIGHLIGHT,
10445
10468
  CoordinationType$1.TOOLTIPS_VISIBLE,
10446
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10469
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
10470
+ CoordinationType$1.ANNOTATION_STORY,
10471
+ CoordinationType$1.ANNOTATION_SHAPES,
10472
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10473
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10474
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10475
+ CoordinationType$1.ANNOTATION_EDITABLE,
10476
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10447
10477
  ],
10448
10478
  [ViewType$1.SPATIAL_BETA]: [
10449
10479
  CoordinationType$1.META_COORDINATION_SCOPES,
@@ -10521,7 +10551,27 @@ const COMPONENT_COORDINATION_TYPES = {
10521
10551
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
10522
10552
  CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
10523
10553
  CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
10524
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10554
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
10555
+ CoordinationType$1.ANNOTATION_STORY,
10556
+ CoordinationType$1.ANNOTATION_SHAPES,
10557
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10558
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10559
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10560
+ CoordinationType$1.ANNOTATION_EDITABLE,
10561
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10562
+ ],
10563
+ [ViewType$1.ANNOTATION_CONTROLLER]: [
10564
+ CoordinationType$1.DATASET,
10565
+ CoordinationType$1.ANNOTATION_STORY,
10566
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10567
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10568
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10569
+ CoordinationType$1.ANNOTATION_EDITABLE,
10570
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10571
+ // Note: the annotation controller also needs to read the coordination state
10572
+ // of all other views/coordination types via the full config.
10573
+ // Note: we get/set the CoordinationType.ANNOTATION_SHAPES from the full config,
10574
+ // as this info is view-specific rather than global to the story.
10525
10575
  ],
10526
10576
  [ViewType$1.HEATMAP]: [
10527
10577
  CoordinationType$1.DATASET,
@@ -11539,6 +11589,124 @@ z.object({
11539
11589
  radius: z.number(),
11540
11590
  opacity: z.number()
11541
11591
  });
11592
+ const shapeBaseObj = z.object({
11593
+ uid: z.string(),
11594
+ text: z.string().optional(),
11595
+ strokeColor: z.array(z.number()).length(3).optional(),
11596
+ strokeWidth: z.number().optional(),
11597
+ // SVG-style dash pattern, e.g. "10 5" or "10 20 30 10". "none" or omitted = solid.
11598
+ strokeDashArray: z.string().optional(),
11599
+ visible: z.boolean().optional()
11600
+ // TODO: define unit modes for x and y axes
11601
+ // ("pixels" vs "normalized" vs "physical" etc.)
11602
+ // TODO: a coordinate system identifier (e.g., "DeckGL" for now,
11603
+ // but a coordinate system from OME-NGFF/SpatialData eventually?)
11604
+ });
11605
+ const rectangleShapeObj = shapeBaseObj.extend({
11606
+ type: z.literal("rectangle"),
11607
+ // OME-XML field names verbatim (upper-left origin)
11608
+ x: z.number(),
11609
+ y: z.number(),
11610
+ width: z.number(),
11611
+ height: z.number(),
11612
+ fillColor: z.array(z.number()).length(3).optional(),
11613
+ fillOpacity: z.number().optional()
11614
+ });
11615
+ const lineShapeObj = shapeBaseObj.extend({
11616
+ type: z.literal("line"),
11617
+ // OME-XML field names verbatim
11618
+ x1: z.number(),
11619
+ y1: z.number(),
11620
+ x2: z.number(),
11621
+ y2: z.number(),
11622
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
11623
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional(),
11624
+ textPosition: z.enum(["start", "middle", "end"]).optional(),
11625
+ textBufferPx: z.number().optional()
11626
+ });
11627
+ const ellipseShapeObj = shapeBaseObj.extend({
11628
+ type: z.literal("ellipse"),
11629
+ // OME-XML field names verbatim (centre point + radii)
11630
+ x1: z.number(),
11631
+ y1: z.number(),
11632
+ radiusX: z.number(),
11633
+ radiusY: z.number(),
11634
+ fillColor: z.array(z.number()).length(3).optional(),
11635
+ fillOpacity: z.number().optional()
11636
+ });
11637
+ const polygonShapeObj = shapeBaseObj.extend({
11638
+ type: z.literal("polygon"),
11639
+ // OME-XML: array of [x, y] coordinate pairs, closed automatically
11640
+ points: z.array(z.tuple([z.number(), z.number()])),
11641
+ fillColor: z.array(z.number()).length(3).optional(),
11642
+ fillOpacity: z.number().optional()
11643
+ });
11644
+ const polylineShapeObj = shapeBaseObj.extend({
11645
+ type: z.literal("polyline"),
11646
+ // OME-XML: array of [x, y] coordinate pairs, open (not closed)
11647
+ points: z.array(z.tuple([z.number(), z.number()])),
11648
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
11649
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional()
11650
+ });
11651
+ const annotationShapeObj = z.discriminatedUnion("type", [
11652
+ rectangleShapeObj,
11653
+ lineShapeObj,
11654
+ ellipseShapeObj,
11655
+ polygonShapeObj,
11656
+ polylineShapeObj
11657
+ ]);
11658
+ z.array(annotationShapeObj);
11659
+ const annotationFrameObj = z.object({
11660
+ uid: z.string(),
11661
+ title: z.string().optional(),
11662
+ description: z.string().optional(),
11663
+ descriptionType: z.enum(["text", "markdown"]).optional(),
11664
+ // A frame can define per-view: coordinationValues
11665
+ // (if the view's state should not be coordinated with other views)
11666
+ // or per-view coordinationScopes/coordinationScopesBy
11667
+ // (if at this frame, the view should be coordinated with other views).
11668
+ // We can also define a frame-level coordination space,
11669
+ // which will be merged with the global coordination space.
11670
+ // TODO: datasets
11671
+ // TODO: coordinationSpace
11672
+ layout: z.array(
11673
+ // Note: for now, we will infer view objects which have a uid
11674
+ // that is present in the global layout, and do NOT have x/y/w/h defined,
11675
+ // to mean that in this frame, the layout and set of views is unchanged
11676
+ // from the global layout.
11677
+ // This will allow each frame to omit the full list of views from the layout,
11678
+ // and only specify the views whose coordination state is changing in this frame.
11679
+ // If a frame includes a view with a uid that is not present
11680
+ // in the global layout, then that view will be added to the layout at this frame.
11681
+ // This frame should also define x/y/w/h for all views,
11682
+ // since it will otherwise be ambiguous how to layout the updated set of views
11683
+ // for this frame.
11684
+ z.object({
11685
+ // The view UID. If this view uid is not present in the global layout,
11686
+ // it will be added to the layout at this frame,
11687
+ // and will need to have its coordination values initialized to their defaults
11688
+ // for any that were not fully specified.
11689
+ uid: z.string(),
11690
+ coordinationValues: z.record(
11691
+ z.string(),
11692
+ // The coordination type name, e.g. "embeddingType"
11693
+ z.any()
11694
+ ).optional()
11695
+ // TODO: support coordinationScopes/coordinationScopesBy for per-view coordination
11696
+ // at this frame.
11697
+ // TODO: view x/y/w/h once we support view layout changes per-frame.
11698
+ })
11699
+ ).optional()
11700
+ });
11701
+ z.object({
11702
+ // TODO: schema version for the story schema?
11703
+ // Same as current Vitessce schema version?
11704
+ uid: z.string(),
11705
+ title: z.string().optional(),
11706
+ description: z.string().optional(),
11707
+ descriptionType: z.enum(["text", "markdown"]).optional(),
11708
+ frames: z.array(annotationFrameObj)
11709
+ });
11542
11710
  const SETS_DATATYPE_OBS = "obs";
11543
11711
  const HIERARCHICAL_SCHEMAS = {
11544
11712
  latestVersion: "0.1.3"
@@ -24592,8 +24760,8 @@ class Vector extends MathArray {
24592
24760
  distanceSquared(mathArray) {
24593
24761
  let length2 = 0;
24594
24762
  for (let i2 = 0; i2 < this.ELEMENTS; ++i2) {
24595
- const dist = this[i2] - mathArray[i2];
24596
- length2 += dist * dist;
24763
+ const dist2 = this[i2] - mathArray[i2];
24764
+ length2 += dist2 * dist2;
24597
24765
  }
24598
24766
  return checkNumber(length2);
24599
24767
  }
@@ -24914,6 +25082,12 @@ function multiply$3(out, a2, b) {
24914
25082
  out[2] = a2[2] * b[2];
24915
25083
  return out;
24916
25084
  }
25085
+ function distance$3(a2, b) {
25086
+ var x = b[0] - a2[0];
25087
+ var y = b[1] - a2[1];
25088
+ var z2 = b[2] - a2[2];
25089
+ return Math.hypot(x, y, z2);
25090
+ }
24917
25091
  function squaredLength$2(a2) {
24918
25092
  var x = a2[0];
24919
25093
  var y = a2[1];
@@ -25037,6 +25211,7 @@ function angle$2(a2, b) {
25037
25211
  }
25038
25212
  var sub = subtract;
25039
25213
  var mul = multiply$3;
25214
+ var dist = distance$3;
25040
25215
  var len = length$5;
25041
25216
  var sqrLen = squaredLength$2;
25042
25217
  (function() {
@@ -39507,7 +39682,7 @@ function noop$2() {
39507
39682
  const getCursor$1 = ({
39508
39683
  isDragging
39509
39684
  }) => isDragging ? "grabbing" : "grab";
39510
- const defaultProps$O = {
39685
+ const defaultProps$P = {
39511
39686
  id: "",
39512
39687
  width: "100%",
39513
39688
  height: "100%",
@@ -39638,7 +39813,7 @@ class Deck {
39638
39813
  this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
39639
39814
  });
39640
39815
  this.props = {
39641
- ...defaultProps$O,
39816
+ ...defaultProps$P,
39642
39817
  ...props
39643
39818
  };
39644
39819
  props = this.props;
@@ -40140,7 +40315,7 @@ class Deck {
40140
40315
  metrics.gpuMemory = memoryStats.get("GPU Memory").count;
40141
40316
  }
40142
40317
  }
40143
- _defineProperty(Deck, "defaultProps", defaultProps$O);
40318
+ _defineProperty(Deck, "defaultProps", defaultProps$P);
40144
40319
  _defineProperty(Deck, "VERSION", deckGlobal.VERSION);
40145
40320
  class ShaderAttribute {
40146
40321
  constructor(dataColumn, opts) {
@@ -42895,7 +43070,7 @@ const areViewportsEqual = memoize$3(({
42895
43070
  return oldViewport.equals(viewport);
42896
43071
  });
42897
43072
  let pickingColorCache = new Uint8ClampedArray(0);
42898
- const defaultProps$N = {
43073
+ const defaultProps$O = {
42899
43074
  data: {
42900
43075
  type: "data",
42901
43076
  value: EMPTY_ARRAY$1,
@@ -43770,7 +43945,7 @@ class Layer extends Component {
43770
43945
  this.setNeedsUpdate();
43771
43946
  }
43772
43947
  }
43773
- _defineProperty(Layer, "defaultProps", defaultProps$N);
43948
+ _defineProperty(Layer, "defaultProps", defaultProps$O);
43774
43949
  _defineProperty(Layer, "layerName", "Layer");
43775
43950
  const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
43776
43951
  class CompositeLayer extends Layer {
@@ -44806,6 +44981,124 @@ const esm$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
44806
44981
  project32,
44807
44982
  shadow
44808
44983
  }, Symbol.toStringTag, { value: "Module" }));
44984
+ const dashShaders = {
44985
+ inject: {
44986
+ "vs:#decl": "\nattribute vec2 instanceDashArrays;\nattribute float instanceDashOffsets;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n",
44987
+ "vs:#main-end": "\nvDashArray = instanceDashArrays;\nvDashOffset = instanceDashOffsets / width.x;\n",
44988
+ "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",
44989
+ "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"
44990
+ }
44991
+ };
44992
+ const offsetShaders = {
44993
+ inject: {
44994
+ "vs:#decl": "\nattribute float instanceOffsets;\n",
44995
+ "vs:DECKGL_FILTER_SIZE": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n size *= offsetWidth;\n",
44996
+ "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",
44997
+ "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"
44998
+ }
44999
+ };
45000
+ const defaultProps$N = {
45001
+ getDashArray: {
45002
+ type: "accessor",
45003
+ value: [0, 0]
45004
+ },
45005
+ getOffset: {
45006
+ type: "accessor",
45007
+ value: 0
45008
+ },
45009
+ dashJustified: false,
45010
+ dashGapPickable: false
45011
+ };
45012
+ class PathStyleExtension extends LayerExtension {
45013
+ constructor({
45014
+ dash = false,
45015
+ offset: offset2 = false,
45016
+ highPrecisionDash = false
45017
+ } = {}) {
45018
+ super({
45019
+ dash: dash || highPrecisionDash,
45020
+ offset: offset2,
45021
+ highPrecisionDash
45022
+ });
45023
+ }
45024
+ isEnabled(layer) {
45025
+ return "pathTesselator" in layer.state;
45026
+ }
45027
+ getShaders(extension) {
45028
+ if (!extension.isEnabled(this)) {
45029
+ return null;
45030
+ }
45031
+ let result = {};
45032
+ if (extension.opts.dash) {
45033
+ result = mergeShaders(result, dashShaders);
45034
+ }
45035
+ if (extension.opts.offset) {
45036
+ result = mergeShaders(result, offsetShaders);
45037
+ }
45038
+ return result;
45039
+ }
45040
+ initializeState(context, extension) {
45041
+ const attributeManager = this.getAttributeManager();
45042
+ if (!attributeManager || !extension.isEnabled(this)) {
45043
+ return;
45044
+ }
45045
+ if (extension.opts.dash) {
45046
+ attributeManager.addInstanced({
45047
+ instanceDashArrays: {
45048
+ size: 2,
45049
+ accessor: "getDashArray"
45050
+ }
45051
+ });
45052
+ }
45053
+ if (extension.opts.highPrecisionDash) {
45054
+ attributeManager.addInstanced({
45055
+ instanceDashOffsets: {
45056
+ size: 1,
45057
+ accessor: "getPath",
45058
+ transform: extension.getDashOffsets.bind(this)
45059
+ }
45060
+ });
45061
+ }
45062
+ if (extension.opts.offset) {
45063
+ attributeManager.addInstanced({
45064
+ instanceOffsets: {
45065
+ size: 1,
45066
+ accessor: "getOffset"
45067
+ }
45068
+ });
45069
+ }
45070
+ }
45071
+ updateState(params, extension) {
45072
+ if (!extension.isEnabled(this)) {
45073
+ return;
45074
+ }
45075
+ const uniforms = {};
45076
+ if (extension.opts.dash) {
45077
+ uniforms.dashAlignMode = this.props.dashJustified ? 1 : 0;
45078
+ uniforms.dashGapPickable = Boolean(this.props.dashGapPickable);
45079
+ }
45080
+ this.state.model.setUniforms(uniforms);
45081
+ }
45082
+ getDashOffsets(path) {
45083
+ const result = [0];
45084
+ const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
45085
+ const isNested2 = Array.isArray(path[0]);
45086
+ const geometrySize = isNested2 ? path.length : path.length / positionSize;
45087
+ let p;
45088
+ let prevP;
45089
+ for (let i2 = 0; i2 < geometrySize - 1; i2++) {
45090
+ p = isNested2 ? path[i2] : path.slice(i2 * positionSize, i2 * positionSize + positionSize);
45091
+ p = this.projectPosition(p);
45092
+ if (i2 > 0) {
45093
+ result[i2] = result[i2 - 1] + dist(prevP, p);
45094
+ }
45095
+ prevP = p;
45096
+ }
45097
+ return result;
45098
+ }
45099
+ }
45100
+ _defineProperty(PathStyleExtension, "defaultProps", defaultProps$N);
45101
+ _defineProperty(PathStyleExtension, "extensionName", "PathStyleExtension");
44809
45102
  const defaultProps$M = {
44810
45103
  clipBounds: [0, 0, 1, 1]
44811
45104
  };
@@ -100853,8 +101146,8 @@ function requireJs$b() {
100853
101146
  var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi12 / 2 + Math.PI / 4));
100854
101147
  var q = Math.abs(DeltaPsi) > 1e-11 ? DeltaPhi / DeltaPsi : Math.cos(phi12);
100855
101148
  var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda);
100856
- var dist = delta * R;
100857
- return dist;
101149
+ var dist2 = delta * R;
101150
+ return dist2;
100858
101151
  }
100859
101152
  js$a.default = rhumbDistance;
100860
101153
  return js$a;
@@ -101167,7 +101460,7 @@ function requireUtils$2() {
101167
101460
  var x;
101168
101461
  var y;
101169
101462
  var segmentIdx;
101170
- var dist;
101463
+ var dist2;
101171
101464
  if (coords.length > 1 && pointCoords.length) {
101172
101465
  var lineCoordinates;
101173
101466
  var pointCoordinate;
@@ -101184,17 +101477,17 @@ function requireUtils$2() {
101184
101477
  if (lineCoordinates[n2][0] !== lineCoordinates[n2 - 1][0]) {
101185
101478
  var slope = (lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1]) / (lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0]);
101186
101479
  var inverseSlope = lineCoordinates[n2][1] - slope * lineCoordinates[n2][0];
101187
- dist = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
101188
- } else dist = Math.abs(pointCoordinate[0] - lineCoordinates[n2][0]);
101480
+ dist2 = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
101481
+ } else dist2 = Math.abs(pointCoordinate[0] - lineCoordinates[n2][0]);
101189
101482
  var rl2 = Math.pow(lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1], 2) + Math.pow(lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0], 2);
101190
101483
  var ln2 = Math.pow(lineCoordinates[n2][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2][0] - pointCoordinate[0], 2);
101191
101484
  var lnm12 = Math.pow(lineCoordinates[n2 - 1][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2 - 1][0] - pointCoordinate[0], 2);
101192
- var dist2 = Math.pow(dist, 2);
101193
- var calcrl2 = ln2 - dist2 + lnm12 - dist2;
101485
+ var dist22 = Math.pow(dist2, 2);
101486
+ var calcrl2 = ln2 - dist22 + lnm12 - dist22;
101194
101487
  if (calcrl2 > rl2) {
101195
- dist = Math.sqrt(Math.min(ln2, lnm12));
101488
+ dist2 = Math.sqrt(Math.min(ln2, lnm12));
101196
101489
  }
101197
- if (minDist === null || minDist === void 0 || minDist > dist) {
101490
+ if (minDist === null || minDist === void 0 || minDist > dist2) {
101198
101491
  if (calcrl2 > rl2) {
101199
101492
  if (lnm12 < ln2) {
101200
101493
  to = 0;
@@ -101204,10 +101497,10 @@ function requireUtils$2() {
101204
101497
  to = 1;
101205
101498
  }
101206
101499
  } else {
101207
- to = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
101208
- from2 = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
101500
+ to = Math.sqrt(lnm12 - dist22) / Math.sqrt(rl2);
101501
+ from2 = Math.sqrt(ln2 - dist22) / Math.sqrt(rl2);
101209
101502
  }
101210
- minDist = dist;
101503
+ minDist = dist2;
101211
101504
  segmentIdx = n2;
101212
101505
  }
101213
101506
  }
@@ -117538,22 +117831,22 @@ function addDecoder(cases, importFn) {
117538
117831
  }
117539
117832
  cases.forEach((c2) => registry$1.set(c2, importFn));
117540
117833
  }
117541
- addDecoder([void 0, 1], () => import("./raw-BO651BQa.js").then((m2) => m2.default));
117542
- addDecoder(5, () => import("./lzw-B1Ve5CoF.js").then((m2) => m2.default));
117834
+ addDecoder([void 0, 1], () => import("./raw-DWdrKuNt.js").then((m2) => m2.default));
117835
+ addDecoder(5, () => import("./lzw-qjsUiTV8.js").then((m2) => m2.default));
117543
117836
  addDecoder(6, () => {
117544
117837
  throw new Error("old style JPEG compression is not supported.");
117545
117838
  });
117546
- addDecoder(7, () => import("./jpeg-DkDHRRxb.js").then((m2) => m2.default));
117547
- addDecoder([8, 32946], () => import("./deflate-D1w4oupf.js").then((m2) => m2.default));
117548
- addDecoder(32773, () => import("./packbits-DkxsQnHM.js").then((m2) => m2.default));
117839
+ addDecoder(7, () => import("./jpeg-DfpY4ESw.js").then((m2) => m2.default));
117840
+ addDecoder([8, 32946], () => import("./deflate-CHWmGKzs.js").then((m2) => m2.default));
117841
+ addDecoder(32773, () => import("./packbits-DpcvKlj_.js").then((m2) => m2.default));
117549
117842
  addDecoder(
117550
117843
  34887,
117551
- () => import("./lerc-WlrBcKr7.js").then(async (m2) => {
117844
+ () => import("./lerc-zU6xDjk2.js").then(async (m2) => {
117552
117845
  await m2.zstd.init();
117553
117846
  return m2;
117554
117847
  }).then((m2) => m2.default)
117555
117848
  );
117556
- addDecoder(50001, () => import("./webimage-j5GKznX1.js").then((m2) => m2.default));
117849
+ addDecoder(50001, () => import("./webimage-DP9dgaA0.js").then((m2) => m2.default));
117557
117850
  function decodeRowAcc(row, stride) {
117558
117851
  let length2 = row.length - stride;
117559
117852
  let offset2 = 0;
@@ -117968,8 +118261,8 @@ function TreeDesc(dyn_tree, stat_desc) {
117968
118261
  this.max_code = 0;
117969
118262
  this.stat_desc = stat_desc;
117970
118263
  }
117971
- const d_code = (dist) => {
117972
- return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
118264
+ const d_code = (dist2) => {
118265
+ return dist2 < 256 ? _dist_code[dist2] : _dist_code[256 + (dist2 >>> 7)];
117973
118266
  };
117974
118267
  const put_short = (s2, w2) => {
117975
118268
  s2.pending_buf[s2.pending++] = w2 & 255;
@@ -118103,7 +118396,7 @@ const tr_static_init = () => {
118103
118396
  let bits;
118104
118397
  let length2;
118105
118398
  let code;
118106
- let dist;
118399
+ let dist2;
118107
118400
  const bl_count = new Array(MAX_BITS + 1);
118108
118401
  length2 = 0;
118109
118402
  for (code = 0; code < LENGTH_CODES - 1; code++) {
@@ -118113,18 +118406,18 @@ const tr_static_init = () => {
118113
118406
  }
118114
118407
  }
118115
118408
  _length_code[length2 - 1] = code;
118116
- dist = 0;
118409
+ dist2 = 0;
118117
118410
  for (code = 0; code < 16; code++) {
118118
- base_dist[code] = dist;
118411
+ base_dist[code] = dist2;
118119
118412
  for (n2 = 0; n2 < 1 << extra_dbits[code]; n2++) {
118120
- _dist_code[dist++] = code;
118413
+ _dist_code[dist2++] = code;
118121
118414
  }
118122
118415
  }
118123
- dist >>= 7;
118416
+ dist2 >>= 7;
118124
118417
  for (; code < D_CODES; code++) {
118125
- base_dist[code] = dist << 7;
118418
+ base_dist[code] = dist2 << 7;
118126
118419
  for (n2 = 0; n2 < 1 << extra_dbits[code] - 7; n2++) {
118127
- _dist_code[256 + dist++] = code;
118420
+ _dist_code[256 + dist2++] = code;
118128
118421
  }
118129
118422
  }
118130
118423
  for (bits = 0; bits <= MAX_BITS; bits++) {
@@ -118215,17 +118508,17 @@ const pqdownheap = (s2, tree, k) => {
118215
118508
  s2.heap[k] = v;
118216
118509
  };
118217
118510
  const compress_block = (s2, ltree, dtree) => {
118218
- let dist;
118511
+ let dist2;
118219
118512
  let lc;
118220
118513
  let lx = 0;
118221
118514
  let code;
118222
118515
  let extra;
118223
118516
  if (s2.last_lit !== 0) {
118224
118517
  do {
118225
- dist = s2.pending_buf[s2.d_buf + lx * 2] << 8 | s2.pending_buf[s2.d_buf + lx * 2 + 1];
118518
+ dist2 = s2.pending_buf[s2.d_buf + lx * 2] << 8 | s2.pending_buf[s2.d_buf + lx * 2 + 1];
118226
118519
  lc = s2.pending_buf[s2.l_buf + lx];
118227
118520
  lx++;
118228
- if (dist === 0) {
118521
+ if (dist2 === 0) {
118229
118522
  send_code(s2, lc, ltree);
118230
118523
  } else {
118231
118524
  code = _length_code[lc];
@@ -118235,13 +118528,13 @@ const compress_block = (s2, ltree, dtree) => {
118235
118528
  lc -= base_length[code];
118236
118529
  send_bits(s2, lc, extra);
118237
118530
  }
118238
- dist--;
118239
- code = d_code(dist);
118531
+ dist2--;
118532
+ code = d_code(dist2);
118240
118533
  send_code(s2, code, dtree);
118241
118534
  extra = extra_dbits[code];
118242
118535
  if (extra !== 0) {
118243
- dist -= base_dist[code];
118244
- send_bits(s2, dist, extra);
118536
+ dist2 -= base_dist[code];
118537
+ send_bits(s2, dist2, extra);
118245
118538
  }
118246
118539
  }
118247
118540
  } while (lx < s2.last_lit);
@@ -118512,18 +118805,18 @@ const _tr_flush_block = (s2, buf, stored_len, last) => {
118512
118805
  bi_windup(s2);
118513
118806
  }
118514
118807
  };
118515
- const _tr_tally = (s2, dist, lc) => {
118516
- s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist >>> 8 & 255;
118517
- s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] = dist & 255;
118808
+ const _tr_tally = (s2, dist2, lc) => {
118809
+ s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist2 >>> 8 & 255;
118810
+ s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] = dist2 & 255;
118518
118811
  s2.pending_buf[s2.l_buf + s2.last_lit] = lc & 255;
118519
118812
  s2.last_lit++;
118520
- if (dist === 0) {
118813
+ if (dist2 === 0) {
118521
118814
  s2.dyn_ltree[lc * 2]++;
118522
118815
  } else {
118523
118816
  s2.matches++;
118524
- dist--;
118817
+ dist2--;
118525
118818
  s2.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;
118526
- s2.dyn_dtree[d_code(dist) * 2]++;
118819
+ s2.dyn_dtree[d_code(dist2) * 2]++;
118527
118820
  }
118528
118821
  return s2.last_lit === s2.lit_bufsize - 1;
118529
118822
  };
@@ -120028,7 +120321,7 @@ var inffast = function inflate_fast(strm, start) {
120028
120321
  let here;
120029
120322
  let op;
120030
120323
  let len2;
120031
- let dist;
120324
+ let dist2;
120032
120325
  let from2;
120033
120326
  let from_source;
120034
120327
  let input, output;
@@ -120094,7 +120387,7 @@ var inffast = function inflate_fast(strm, start) {
120094
120387
  bits -= op;
120095
120388
  op = here >>> 16 & 255;
120096
120389
  if (op & 16) {
120097
- dist = here & 65535;
120390
+ dist2 = here & 65535;
120098
120391
  op &= 15;
120099
120392
  if (bits < op) {
120100
120393
  hold += input[_in++] << bits;
@@ -120104,8 +120397,8 @@ var inffast = function inflate_fast(strm, start) {
120104
120397
  bits += 8;
120105
120398
  }
120106
120399
  }
120107
- dist += hold & (1 << op) - 1;
120108
- if (dist > dmax) {
120400
+ dist2 += hold & (1 << op) - 1;
120401
+ if (dist2 > dmax) {
120109
120402
  strm.msg = "invalid distance too far back";
120110
120403
  state.mode = BAD;
120111
120404
  break top;
@@ -120113,8 +120406,8 @@ var inffast = function inflate_fast(strm, start) {
120113
120406
  hold >>>= op;
120114
120407
  bits -= op;
120115
120408
  op = _out - beg;
120116
- if (dist > op) {
120117
- op = dist - op;
120409
+ if (dist2 > op) {
120410
+ op = dist2 - op;
120118
120411
  if (op > whave) {
120119
120412
  if (state.sane) {
120120
120413
  strm.msg = "invalid distance too far back";
@@ -120131,7 +120424,7 @@ var inffast = function inflate_fast(strm, start) {
120131
120424
  do {
120132
120425
  output[_out++] = s_window[from2++];
120133
120426
  } while (--op);
120134
- from2 = _out - dist;
120427
+ from2 = _out - dist2;
120135
120428
  from_source = output;
120136
120429
  }
120137
120430
  } else if (wnext < op) {
@@ -120149,7 +120442,7 @@ var inffast = function inflate_fast(strm, start) {
120149
120442
  do {
120150
120443
  output[_out++] = s_window[from2++];
120151
120444
  } while (--op);
120152
- from2 = _out - dist;
120445
+ from2 = _out - dist2;
120153
120446
  from_source = output;
120154
120447
  }
120155
120448
  }
@@ -120160,7 +120453,7 @@ var inffast = function inflate_fast(strm, start) {
120160
120453
  do {
120161
120454
  output[_out++] = s_window[from2++];
120162
120455
  } while (--op);
120163
- from2 = _out - dist;
120456
+ from2 = _out - dist2;
120164
120457
  from_source = output;
120165
120458
  }
120166
120459
  }
@@ -120177,7 +120470,7 @@ var inffast = function inflate_fast(strm, start) {
120177
120470
  }
120178
120471
  }
120179
120472
  } else {
120180
- from2 = _out - dist;
120473
+ from2 = _out - dist2;
120181
120474
  do {
120182
120475
  output[_out++] = output[from2++];
120183
120476
  output[_out++] = output[from2++];
@@ -120735,7 +121028,7 @@ const fixedtables = (state) => {
120735
121028
  state.distbits = 5;
120736
121029
  };
120737
121030
  const updatewindow = (strm, src, end, copy2) => {
120738
- let dist;
121031
+ let dist2;
120739
121032
  const state = strm.state;
120740
121033
  if (state.window === null) {
120741
121034
  state.wsize = 1 << state.wbits;
@@ -120748,23 +121041,23 @@ const updatewindow = (strm, src, end, copy2) => {
120748
121041
  state.wnext = 0;
120749
121042
  state.whave = state.wsize;
120750
121043
  } else {
120751
- dist = state.wsize - state.wnext;
120752
- if (dist > copy2) {
120753
- dist = copy2;
121044
+ dist2 = state.wsize - state.wnext;
121045
+ if (dist2 > copy2) {
121046
+ dist2 = copy2;
120754
121047
  }
120755
- state.window.set(src.subarray(end - copy2, end - copy2 + dist), state.wnext);
120756
- copy2 -= dist;
121048
+ state.window.set(src.subarray(end - copy2, end - copy2 + dist2), state.wnext);
121049
+ copy2 -= dist2;
120757
121050
  if (copy2) {
120758
121051
  state.window.set(src.subarray(end - copy2, end), 0);
120759
121052
  state.wnext = copy2;
120760
121053
  state.whave = state.wsize;
120761
121054
  } else {
120762
- state.wnext += dist;
121055
+ state.wnext += dist2;
120763
121056
  if (state.wnext === state.wsize) {
120764
121057
  state.wnext = 0;
120765
121058
  }
120766
121059
  if (state.whave < state.wsize) {
120767
- state.whave += dist;
121060
+ state.whave += dist2;
120768
121061
  }
120769
121062
  }
120770
121063
  }
@@ -124643,14 +124936,14 @@ vec4 colormap(float intensity) {
124643
124936
  }
124644
124937
  };
124645
124938
  }
124646
- const defaultProps$4$1 = {
124939
+ const defaultProps$4$2 = {
124647
124940
  colormap: { type: "string", value: "viridis", compare: true },
124648
124941
  opacity: { type: "number", value: 1, compare: true },
124649
124942
  useTransparentColor: { type: "boolean", value: false, compare: true }
124650
124943
  };
124651
124944
  const AdditiveColormapExtension = class extends LayerExtension {
124652
124945
  getShaders() {
124653
- const name2 = this?.props?.colormap || defaultProps$4$1.colormap.value;
124946
+ const name2 = this?.props?.colormap || defaultProps$4$2.colormap.value;
124654
124947
  const apply_cmap = cmaps[name2];
124655
124948
  if (!apply_cmap) {
124656
124949
  throw Error(`No colormap named ${name2} found in registry`);
@@ -124669,8 +124962,8 @@ const AdditiveColormapExtension = class extends LayerExtension {
124669
124962
  }
124670
124963
  draw() {
124671
124964
  const {
124672
- useTransparentColor = defaultProps$4$1.useTransparentColor.value,
124673
- opacity = defaultProps$4$1.opacity.value
124965
+ useTransparentColor = defaultProps$4$2.useTransparentColor.value,
124966
+ opacity = defaultProps$4$2.opacity.value
124674
124967
  } = this.props;
124675
124968
  const uniforms = {
124676
124969
  opacity,
@@ -124680,7 +124973,7 @@ const AdditiveColormapExtension = class extends LayerExtension {
124680
124973
  }
124681
124974
  };
124682
124975
  AdditiveColormapExtension.extensionName = "AdditiveColormapExtension";
124683
- AdditiveColormapExtension.defaultProps = defaultProps$4$1;
124976
+ AdditiveColormapExtension.defaultProps = defaultProps$4$2;
124684
124977
  const fs$1$2 = `uniform vec3 transparentColor;
124685
124978
  uniform bool useTransparentColor;
124686
124979
  uniform float opacity;
@@ -125973,7 +126266,7 @@ const ImageLayer = class extends CompositeLayer {
125973
126266
  };
125974
126267
  ImageLayer.layerName = "ImageLayer";
125975
126268
  ImageLayer.defaultProps = defaultProps$5;
125976
- const defaultProps$4 = {
126269
+ const defaultProps$4$1 = {
125977
126270
  pickable: { type: "boolean", value: true, compare: true },
125978
126271
  onHover: { type: "function", value: null, compare: false },
125979
126272
  contrastLimits: { type: "array", value: [], compare: true },
@@ -126085,7 +126378,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
126085
126378
  }
126086
126379
  };
126087
126380
  MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
126088
- MultiscaleImageLayer.defaultProps = defaultProps$4;
126381
+ MultiscaleImageLayer.defaultProps = defaultProps$4$1;
126089
126382
  const defaultProps$3$1 = {
126090
126383
  pickable: { type: "boolean", value: true, compare: true },
126091
126384
  loader: {
@@ -127161,7 +127454,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
127161
127454
  }
127162
127455
  return newArr;
127163
127456
  }
127164
- const defaultProps$3 = {
127457
+ const defaultProps$4 = {
127165
127458
  hoveredCell: { type: "number", value: null, compare: true },
127166
127459
  // We do not want to deep-compare cellColorData,
127167
127460
  // as it is potentially a TypedArray with millions of elements.
@@ -127278,7 +127571,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
127278
127571
  }
127279
127572
  };
127280
127573
  BitmaskLayer$1.layerName = "BitmaskLayer";
127281
- BitmaskLayer$1.defaultProps = defaultProps$3;
127574
+ BitmaskLayer$1.defaultProps = defaultProps$4;
127282
127575
  const vs = `
127283
127576
  #define SHADER_NAME bitmask-layer-vertex-shader
127284
127577
 
@@ -127620,7 +127913,7 @@ function isEqualShallow(prevArr, nextArr) {
127620
127913
  }
127621
127914
  return prevArr === nextArr;
127622
127915
  }
127623
- const defaultProps$2 = {
127916
+ const defaultProps$3 = {
127624
127917
  channelStrokeWidths: { type: "array", value: null, compare: true },
127625
127918
  channelsFilled: { type: "array", value: null, compare: true },
127626
127919
  channelOpacities: { type: "array", value: null, compare: true },
@@ -127884,7 +128177,7 @@ class BitmaskLayer2 extends XRLayer {
127884
128177
  }
127885
128178
  }
127886
128179
  BitmaskLayer2.layerName = "BitmaskLayer";
127887
- BitmaskLayer2.defaultProps = defaultProps$2;
128180
+ BitmaskLayer2.defaultProps = defaultProps$3;
127888
128181
  var isNumeric$1 = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, mathceil = Math.ceil, mathfloor = Math.floor, bignumberError = "[BigNumber Error] ", tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ", BASE = 1e14, LOG_BASE = 14, MAX_SAFE_INTEGER = 9007199254740991, POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, MAX = 1e9;
127889
128182
  function clone(configObject) {
127890
128183
  var div, convertBase, parseNumeric, P = 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 = {
@@ -130827,7 +131120,7 @@ function ringArea(coords) {
130827
131120
  return total * FACTOR;
130828
131121
  }
130829
131122
  const DEFAULT_THRESHOLD = 1;
130830
- const defaultProps$1 = {
131123
+ const defaultProps$2 = {
130831
131124
  // for text
130832
131125
  obsSetPath: { type: "object" },
130833
131126
  sampleSetPath: { type: "object" },
@@ -130922,9 +131215,9 @@ class ContourLayerWithText extends ContourLayer {
130922
131215
  const circlePoint = point(circleCoord);
130923
131216
  polygonVertices.forEach((polyCoord) => {
130924
131217
  const polyPoint = point(polyCoord);
130925
- const dist = distance$1(circlePoint, polyPoint);
130926
- if (dist < minDist) {
130927
- minDist = dist;
131218
+ const dist2 = distance$1(circlePoint, polyPoint);
131219
+ if (dist2 < minDist) {
131220
+ minDist = dist2;
130928
131221
  minCirclePoint = circleCoord;
130929
131222
  minCirclePointI = circlePointI;
130930
131223
  minPolygonPoint = polyCoord;
@@ -131001,7 +131294,1077 @@ class ContourLayerWithText extends ContourLayer {
131001
131294
  }
131002
131295
  }
131003
131296
  ContourLayerWithText.layerName = "ContourLayerWithText";
131004
- ContourLayerWithText.defaultProps = defaultProps$1;
131297
+ ContourLayerWithText.defaultProps = defaultProps$2;
131298
+ const ARROW_SCREEN_PX = 14;
131299
+ const LABEL_FONT_FAMILY$1 = '"Roboto", "Helvetica", "Arial", sans-serif';
131300
+ const LABEL_FONT_WEIGHT = "bold";
131301
+ const LABEL_FONT_SIZE = 14;
131302
+ const RATIO_CLUSTER = 0.1;
131303
+ const RATIO_DOT = 0.3;
131304
+ const RATIO_GEO_FADE = 0.55;
131305
+ const RATIO_TIPS = 0.7;
131306
+ const RATIO_LABEL = 0.55;
131307
+ const RATIO_LABEL_FULL = 0.75;
131308
+ function textBgColor(strokeColor) {
131309
+ const [r2, g2, b] = strokeColor;
131310
+ const lum = (0.299 * r2 + 0.587 * g2 + 0.114 * b) / 255;
131311
+ return lum > 0.45 ? [20, 20, 20, 210] : [245, 245, 245, 210];
131312
+ }
131313
+ function parseDashArray(strokeDashArray) {
131314
+ if (!strokeDashArray || strokeDashArray === "none")
131315
+ return null;
131316
+ const nums = strokeDashArray.trim().split(/\s+/).map(Number).filter((n2) => !Number.isNaN(n2) && n2 >= 0);
131317
+ return nums.length >= 2 ? [nums[0], nums[1]] : null;
131318
+ }
131319
+ function computeEllipsePolygon(cx, cy, rx, ry, numSegments = 64) {
131320
+ const pts = [];
131321
+ for (let i2 = 0; i2 < numSegments; i2++) {
131322
+ const angle2 = 2 * Math.PI * i2 / numSegments;
131323
+ pts.push([cx + rx * Math.cos(angle2), cy + ry * Math.sin(angle2)]);
131324
+ }
131325
+ return pts;
131326
+ }
131327
+ function createPreviewLayer(inProgress, hoverCoord, strokeColor = [255, 255, 0]) {
131328
+ if (!inProgress || inProgress.vertices.length === 0)
131329
+ return null;
131330
+ const { type, vertices } = inProgress;
131331
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
131332
+ const previewColor = [...strokeColor, 160];
131333
+ const cursor2 = hoverCoord ?? vertices[vertices.length - 1];
131334
+ if (type === "rectangle" && vertices.length === 1) {
131335
+ const [ax, ay] = vertices[0];
131336
+ const [bx, by] = cursor2;
131337
+ const path = [[ax, ay], [bx, ay], [bx, by], [ax, by], [ax, ay]];
131338
+ return new PathLayer({
131339
+ ...base,
131340
+ id: "annotation-preview-rectangle",
131341
+ data: [{ path }],
131342
+ getPath: (d) => d.path,
131343
+ getColor: previewColor,
131344
+ getWidth: 1,
131345
+ widthUnits: "pixels",
131346
+ extensions: [new PathStyleExtension({ dash: true })],
131347
+ getDashArray: [8, 4]
131348
+ });
131349
+ }
131350
+ if (type === "line" && vertices.length === 1) {
131351
+ const path = [vertices[0], cursor2];
131352
+ return new PathLayer({
131353
+ ...base,
131354
+ id: "annotation-preview-line",
131355
+ data: [{ path }],
131356
+ getPath: (d) => d.path,
131357
+ getColor: previewColor,
131358
+ getWidth: 1,
131359
+ widthUnits: "pixels",
131360
+ extensions: [new PathStyleExtension({ dash: true })],
131361
+ getDashArray: [8, 4]
131362
+ });
131363
+ }
131364
+ if (type === "ellipse" && vertices.length === 1) {
131365
+ const [cx, cy] = vertices[0];
131366
+ const [ex, ey] = cursor2;
131367
+ const rx = Math.abs(ex - cx);
131368
+ const ry = Math.abs(ey - cy);
131369
+ if (rx < 1 && ry < 1)
131370
+ return null;
131371
+ const pts = computeEllipsePolygon(cx, cy, Math.max(rx, 1), Math.max(ry, 1));
131372
+ const path = [...pts, pts[0]];
131373
+ return new PathLayer({
131374
+ ...base,
131375
+ id: "annotation-preview-ellipse",
131376
+ data: [{ path }],
131377
+ getPath: (d) => d.path,
131378
+ getColor: previewColor,
131379
+ getWidth: 1,
131380
+ widthUnits: "pixels",
131381
+ extensions: [new PathStyleExtension({ dash: true })],
131382
+ getDashArray: [8, 4]
131383
+ });
131384
+ }
131385
+ if ((type === "polygon" || type === "polyline") && vertices.length >= 1) {
131386
+ const path = [...vertices, cursor2];
131387
+ if (type === "polygon" && vertices.length >= 2)
131388
+ path.push(vertices[0]);
131389
+ return new PathLayer({
131390
+ ...base,
131391
+ id: `annotation-preview-${type}`,
131392
+ data: [{ path }],
131393
+ getPath: (d) => d.path,
131394
+ getColor: previewColor,
131395
+ getWidth: 1,
131396
+ widthUnits: "pixels",
131397
+ jointRounded: true,
131398
+ capRounded: true,
131399
+ extensions: [new PathStyleExtension({ dash: true })],
131400
+ getDashArray: [8, 4]
131401
+ });
131402
+ }
131403
+ return null;
131404
+ }
131405
+ function computeTickCap(tipX, tipY, dirX, dirY, dataSize) {
131406
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
131407
+ if (len2 === 0)
131408
+ return null;
131409
+ const ux = dirX / len2;
131410
+ const uy = dirY / len2;
131411
+ const px = -uy;
131412
+ const py = ux;
131413
+ const half = dataSize * 0.55;
131414
+ return [
131415
+ [tipX + px * half, tipY + py * half],
131416
+ [tipX - px * half, tipY - py * half]
131417
+ ];
131418
+ }
131419
+ function computeArrowhead(tipX, tipY, dirX, dirY, dataSize) {
131420
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
131421
+ if (len2 === 0)
131422
+ return null;
131423
+ const ux = dirX / len2;
131424
+ const uy = dirY / len2;
131425
+ const px = -uy;
131426
+ const py = ux;
131427
+ const halfBase = dataSize * 0.4;
131428
+ const bx = tipX - ux * dataSize;
131429
+ const by = tipY - uy * dataSize;
131430
+ return [
131431
+ [tipX, tipY],
131432
+ [bx + px * halfBase, by + py * halfBase],
131433
+ [bx - px * halfBase, by - py * halfBase]
131434
+ ];
131435
+ }
131436
+ function fmtCommas(n2) {
131437
+ return Math.round(n2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
131438
+ }
131439
+ function getMeasurementLabel(shape2, physicalPixelSize, viewType = ViewType$1.SPATIAL) {
131440
+ const pps = physicalPixelSize;
131441
+ const px = pps?.x ?? 1;
131442
+ const py = pps?.y ?? 1;
131443
+ const unit2 = pps ? pps.unit ?? "" : null;
131444
+ const hasPhys = !!pps;
131445
+ const isEmbedding = viewType === ViewType$1.SCATTERPLOT;
131446
+ const fmtDist = (d) => {
131447
+ if (hasPhys)
131448
+ return `${d.toFixed(2)} ${unit2}`;
131449
+ if (isEmbedding)
131450
+ return d.toFixed(2);
131451
+ return `${fmtCommas(d)} px`;
131452
+ };
131453
+ const fmtArea = (a2) => {
131454
+ if (hasPhys)
131455
+ return `${a2.toFixed(2)} ${unit2}²`;
131456
+ if (isEmbedding)
131457
+ return a2.toFixed(2);
131458
+ return `${fmtCommas(a2)} px²`;
131459
+ };
131460
+ if (shape2.type === "line") {
131461
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
131462
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
131463
+ const dist2 = hasPhys ? Math.sqrt((dx * px) ** 2 + (dy * py) ** 2) : Math.sqrt(dx * dx + dy * dy);
131464
+ return fmtDist(dist2);
131465
+ }
131466
+ if (shape2.type === "rectangle") {
131467
+ return fmtArea(hasPhys ? Math.abs(shape2.width ?? 0) * px * Math.abs(shape2.height ?? 0) * py : Math.abs((shape2.width ?? 0) * (shape2.height ?? 0)));
131468
+ }
131469
+ if (shape2.type === "ellipse") {
131470
+ const rx = Math.abs(shape2.radiusX ?? 0);
131471
+ const ry = Math.abs(shape2.radiusY ?? 0);
131472
+ return fmtArea(hasPhys ? Math.PI * rx * px * ry * py : Math.PI * rx * ry);
131473
+ }
131474
+ if (shape2.type === "polygon" && shape2.points?.length >= 3) {
131475
+ const pts = shape2.points;
131476
+ let shoelace = 0;
131477
+ for (let i2 = 0; i2 < pts.length; i2++) {
131478
+ const [ax, ay] = pts[i2];
131479
+ const [bx, by] = pts[(i2 + 1) % pts.length];
131480
+ shoelace += (hasPhys ? ax * px : ax) * (hasPhys ? by * py : by) - (hasPhys ? bx * px : bx) * (hasPhys ? ay * py : ay);
131481
+ }
131482
+ return fmtArea(Math.abs(shoelace / 2));
131483
+ }
131484
+ if (shape2.type === "polyline" && shape2.points?.length >= 2) {
131485
+ let total = 0;
131486
+ for (let i2 = 0; i2 < shape2.points.length - 1; i2++) {
131487
+ const [ax, ay] = shape2.points[i2];
131488
+ const [bx, by] = shape2.points[i2 + 1];
131489
+ total += hasPhys ? Math.sqrt(((bx - ax) * px) ** 2 + ((by - ay) * py) ** 2) : Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2);
131490
+ }
131491
+ return fmtDist(total);
131492
+ }
131493
+ return null;
131494
+ }
131495
+ function pickBelowPerp(ux, uy) {
131496
+ const rp = [uy, -ux];
131497
+ const lp = [-uy, ux];
131498
+ return rp[1] > lp[1] || rp[1] === lp[1] && rp[0] > lp[0] ? rp : lp;
131499
+ }
131500
+ function readableAngle(deg) {
131501
+ let a2 = deg;
131502
+ if (a2 > 90)
131503
+ a2 -= 180;
131504
+ if (a2 < -90)
131505
+ a2 += 180;
131506
+ return a2;
131507
+ }
131508
+ function getShapeCentroid(shape2) {
131509
+ if (shape2.type === "rectangle") {
131510
+ return [(shape2.x ?? 0) + (shape2.width ?? 0) / 2, (shape2.y ?? 0) + (shape2.height ?? 0) / 2];
131511
+ }
131512
+ if (shape2.type === "line") {
131513
+ return [((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2, ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2];
131514
+ }
131515
+ if (shape2.type === "ellipse") {
131516
+ return [shape2.x1 ?? 0, shape2.y1 ?? 0];
131517
+ }
131518
+ if ((shape2.type === "polygon" || shape2.type === "polyline") && shape2.points?.length >= 1) {
131519
+ const mx = shape2.points.reduce((s2, p) => s2 + p[0], 0) / shape2.points.length;
131520
+ const my = shape2.points.reduce((s2, p) => s2 + p[1], 0) / shape2.points.length;
131521
+ return [mx, my];
131522
+ }
131523
+ return [0, 0];
131524
+ }
131525
+ function computeClusters(shapeList, zoom, cellPx = 50) {
131526
+ const cellSize = cellPx / 2 ** Math.floor(zoom);
131527
+ const cells = /* @__PURE__ */ new Map();
131528
+ shapeList.forEach(({ shape: shape2 }) => {
131529
+ const [cx, cy] = getShapeCentroid(shape2);
131530
+ const key = `${Math.floor(cx / cellSize)},${Math.floor(cy / cellSize)}`;
131531
+ if (!cells.has(key)) {
131532
+ cells.set(key, { sumX: 0, sumY: 0, count: 0, color: shape2.strokeColor ?? [255, 255, 255] });
131533
+ }
131534
+ const c2 = cells.get(key);
131535
+ c2.sumX += cx;
131536
+ c2.sumY += cy;
131537
+ c2.count++;
131538
+ });
131539
+ return Array.from(cells.values()).map((c2) => ({
131540
+ position: [c2.sumX / c2.count, c2.sumY / c2.count, 0],
131541
+ count: c2.count,
131542
+ color: c2.color
131543
+ }));
131544
+ }
131545
+ function createAnnotationLayers(shapes = [], zoom = 0, selectedShapeUid = null, physicalPixelSize = null, authoredZoom = null, semanticZoom = true, viewType = ViewType$1.SPATIAL) {
131546
+ const selectionLayers = [];
131547
+ if (selectedShapeUid) {
131548
+ const sel = shapes.find((s2) => s2.uid === selectedShapeUid);
131549
+ if (sel) {
131550
+ const { uid: sUid, type: sType, strokeWidth: sStrokeWidth = 3 } = sel;
131551
+ const haloColor = [255, 220, 50, 70];
131552
+ const haloWidth = Math.max(sStrokeWidth + 8, 10);
131553
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
131554
+ if (sType === "rectangle") {
131555
+ const { x, y, width: width2, height: height2 } = sel;
131556
+ selectionLayers.push(new PathLayer({
131557
+ ...base,
131558
+ id: `annotation-select-${sUid}`,
131559
+ data: [{
131560
+ path: [
131561
+ [x, y],
131562
+ [x + width2, y],
131563
+ [x + width2, y + height2],
131564
+ [x, y + height2],
131565
+ [x, y]
131566
+ ]
131567
+ }],
131568
+ getPath: (d) => d.path,
131569
+ getColor: haloColor,
131570
+ getWidth: haloWidth,
131571
+ widthUnits: "pixels",
131572
+ jointRounded: true,
131573
+ capRounded: true
131574
+ }));
131575
+ }
131576
+ if (sType === "line") {
131577
+ const { x1: x12, y1: y12, x2, y2 } = sel;
131578
+ selectionLayers.push(new PathLayer({
131579
+ ...base,
131580
+ id: `annotation-select-${sUid}`,
131581
+ data: [{ path: [[x12, y12], [x2, y2]] }],
131582
+ getPath: (d) => d.path,
131583
+ getColor: haloColor,
131584
+ getWidth: haloWidth,
131585
+ widthUnits: "pixels",
131586
+ capRounded: true
131587
+ }));
131588
+ }
131589
+ if (sType === "ellipse") {
131590
+ const polygon2 = computeEllipsePolygon(sel.x1, sel.y1, sel.radiusX, sel.radiusY);
131591
+ selectionLayers.push(new PathLayer({
131592
+ ...base,
131593
+ id: `annotation-select-${sUid}`,
131594
+ data: [{ path: [...polygon2, polygon2[0]] }],
131595
+ getPath: (d) => d.path,
131596
+ getColor: haloColor,
131597
+ getWidth: haloWidth,
131598
+ widthUnits: "pixels",
131599
+ jointRounded: true
131600
+ }));
131601
+ }
131602
+ if (sType === "polygon" && sel.points?.length >= 3) {
131603
+ selectionLayers.push(new PathLayer({
131604
+ ...base,
131605
+ id: `annotation-select-${sUid}`,
131606
+ data: [{ path: [...sel.points, sel.points[0]] }],
131607
+ getPath: (d) => d.path,
131608
+ getColor: haloColor,
131609
+ getWidth: haloWidth,
131610
+ widthUnits: "pixels",
131611
+ jointRounded: true
131612
+ }));
131613
+ }
131614
+ if (sType === "polyline" && sel.points?.length >= 2) {
131615
+ selectionLayers.push(new PathLayer({
131616
+ ...base,
131617
+ id: `annotation-select-${sUid}`,
131618
+ data: [{ path: sel.points }],
131619
+ getPath: (d) => d.path,
131620
+ getColor: haloColor,
131621
+ getWidth: haloWidth,
131622
+ widthUnits: "pixels",
131623
+ jointRounded: true,
131624
+ capRounded: true
131625
+ }));
131626
+ }
131627
+ }
131628
+ }
131629
+ const layers = [];
131630
+ const dotShapes = [];
131631
+ const clusterDotShapes = [];
131632
+ shapes.forEach((shape2, i2) => {
131633
+ const { uid: uid2, type, strokeColor = [255, 255, 255], strokeWidth = 3, strokeDashArray } = shape2;
131634
+ const isSelected = uid2 === selectedShapeUid;
131635
+ let shapeOpacity = 1;
131636
+ let tipsOpacity = 1;
131637
+ let labelOpacity = 0;
131638
+ if (isSelected || !semanticZoom || authoredZoom === null) {
131639
+ tipsOpacity = 1;
131640
+ labelOpacity = 1;
131641
+ } else {
131642
+ const zoomRatio = 2 ** (zoom - authoredZoom);
131643
+ if (zoomRatio < RATIO_CLUSTER) {
131644
+ clusterDotShapes.push({ shape: shape2 });
131645
+ return;
131646
+ }
131647
+ if (zoomRatio < RATIO_DOT) {
131648
+ dotShapes.push({ shape: shape2, alpha: 200 });
131649
+ return;
131650
+ }
131651
+ if (zoomRatio < RATIO_GEO_FADE) {
131652
+ const t = (zoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
131653
+ shapeOpacity = t;
131654
+ dotShapes.push({ shape: shape2, alpha: Math.round((1 - t) * 200) });
131655
+ }
131656
+ tipsOpacity = zoomRatio >= RATIO_TIPS ? shapeOpacity : Math.max(0, (zoomRatio - RATIO_GEO_FADE) / (RATIO_TIPS - RATIO_GEO_FADE) * shapeOpacity);
131657
+ if (zoomRatio >= RATIO_LABEL_FULL) {
131658
+ labelOpacity = shapeOpacity;
131659
+ } else if (zoomRatio >= RATIO_LABEL) {
131660
+ labelOpacity = (zoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL) * shapeOpacity;
131661
+ }
131662
+ }
131663
+ const arrowDataSize = Math.max(ARROW_SCREEN_PX, strokeWidth * 4) / 2 ** zoom;
131664
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: shapeOpacity };
131665
+ const tipsBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: tipsOpacity };
131666
+ const labelBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: labelOpacity };
131667
+ const labelBgProps = shape2.labelBackground ? {
131668
+ background: true,
131669
+ getBackgroundColor: textBgColor(strokeColor),
131670
+ backgroundPadding: [3, 1, 3, 2]
131671
+ } : {};
131672
+ const labelProps = { ...labelBgProps };
131673
+ const dashArray = parseDashArray(strokeDashArray);
131674
+ const dashExt = [new PathStyleExtension({ dash: true })];
131675
+ const getDash = dashArray ?? [0, 0];
131676
+ if (type === "rectangle") {
131677
+ const { x, y, width: width2, height: height2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131678
+ const filled = fillOpacity > 0;
131679
+ const rectPolygon = [[x, y], [x + width2, y], [x + width2, y + height2], [x, y + height2]];
131680
+ layers.push(new PolygonLayer({
131681
+ ...base,
131682
+ id: `annotation-rect-${uid2}-${i2}`,
131683
+ data: [{ polygon: rectPolygon }],
131684
+ getPolygon: (d) => d.polygon,
131685
+ filled,
131686
+ stroked: true,
131687
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
131688
+ getLineColor: strokeColor,
131689
+ getLineWidth: strokeWidth,
131690
+ lineWidthUnits: "pixels",
131691
+ ...dashArray ? {
131692
+ extensions: [new PathStyleExtension({ dash: true })],
131693
+ getDashArray: dashArray
131694
+ } : {}
131695
+ }));
131696
+ if (shape2.text && labelOpacity > 0) {
131697
+ layers.push(new TextLayer({
131698
+ ...labelBase,
131699
+ ...labelProps,
131700
+ id: `annotation-rect-text-${uid2}-${i2}`,
131701
+ data: [{ position: [x, y], text: shape2.text }],
131702
+ getPosition: (d) => d.position,
131703
+ getText: (d) => d.text,
131704
+ getColor: strokeColor,
131705
+ getSize: LABEL_FONT_SIZE,
131706
+ sizeUnits: "pixels",
131707
+ fontFamily: LABEL_FONT_FAMILY$1,
131708
+ fontWeight: LABEL_FONT_WEIGHT,
131709
+ getPixelOffset: [3, -7],
131710
+ getTextAnchor: "start",
131711
+ getAlignmentBaseline: "bottom"
131712
+ }));
131713
+ }
131714
+ }
131715
+ if (type === "line") {
131716
+ const { x1: x12, y1: y12, x2, y2, markerStart, markerEnd } = shape2;
131717
+ const dx = x2 - x12;
131718
+ const dy = y2 - y12;
131719
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131720
+ const ux = len2 > 0 ? dx / len2 : 0;
131721
+ const uy = len2 > 0 ? dy / len2 : 0;
131722
+ const srcX = markerStart === "Arrow" ? x12 + ux * arrowDataSize : x12;
131723
+ const srcY = markerStart === "Arrow" ? y12 + uy * arrowDataSize : y12;
131724
+ const tgtX = markerEnd === "Arrow" ? x2 - ux * arrowDataSize : x2;
131725
+ const tgtY = markerEnd === "Arrow" ? y2 - uy * arrowDataSize : y2;
131726
+ layers.push(new PathLayer({
131727
+ ...base,
131728
+ id: `annotation-line-${uid2}-${i2}`,
131729
+ extensions: [new PathStyleExtension({ dash: true })],
131730
+ getDashArray: dashArray ?? [0, 0],
131731
+ data: [{ path: [[srcX, srcY], [tgtX, tgtY]] }],
131732
+ getPath: (d) => d.path,
131733
+ getColor: strokeColor,
131734
+ getWidth: strokeWidth,
131735
+ widthUnits: "pixels",
131736
+ capRounded: true
131737
+ }));
131738
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
131739
+ const head = computeArrowhead(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
131740
+ if (head) {
131741
+ layers.push(new PolygonLayer({
131742
+ ...tipsBase,
131743
+ id: `annotation-end-arrow-${uid2}-${i2}`,
131744
+ data: [{ polygon: head }],
131745
+ getPolygon: (d) => d.polygon,
131746
+ filled: true,
131747
+ stroked: false,
131748
+ getFillColor: strokeColor
131749
+ }));
131750
+ }
131751
+ }
131752
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
131753
+ const head = computeArrowhead(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
131754
+ if (head) {
131755
+ layers.push(new PolygonLayer({
131756
+ ...tipsBase,
131757
+ id: `annotation-start-arrow-${uid2}-${i2}`,
131758
+ data: [{ polygon: head }],
131759
+ getPolygon: (d) => d.polygon,
131760
+ filled: true,
131761
+ stroked: false,
131762
+ getFillColor: strokeColor
131763
+ }));
131764
+ }
131765
+ }
131766
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
131767
+ const tick = computeTickCap(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
131768
+ if (tick) {
131769
+ layers.push(new PathLayer({
131770
+ ...tipsBase,
131771
+ id: `annotation-end-tick-${uid2}-${i2}`,
131772
+ data: [{ path: tick }],
131773
+ getPath: (d) => d.path,
131774
+ getColor: strokeColor,
131775
+ getWidth: strokeWidth,
131776
+ widthUnits: "pixels",
131777
+ capRounded: true
131778
+ }));
131779
+ }
131780
+ }
131781
+ if (markerStart === "Tick" && tipsOpacity > 0) {
131782
+ const tick = computeTickCap(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
131783
+ if (tick) {
131784
+ layers.push(new PathLayer({
131785
+ ...tipsBase,
131786
+ id: `annotation-start-tick-${uid2}-${i2}`,
131787
+ data: [{ path: tick }],
131788
+ getPath: (d) => d.path,
131789
+ getColor: strokeColor,
131790
+ getWidth: strokeWidth,
131791
+ widthUnits: "pixels",
131792
+ capRounded: true
131793
+ }));
131794
+ }
131795
+ }
131796
+ if (shape2.text) {
131797
+ const pos = shape2.textPosition ?? "start";
131798
+ let textX;
131799
+ let textY;
131800
+ if (pos === "start") {
131801
+ textX = x12;
131802
+ textY = y12;
131803
+ } else if (pos === "end") {
131804
+ textX = x2;
131805
+ textY = y2;
131806
+ } else {
131807
+ textX = (x12 + x2) / 2;
131808
+ textY = (y12 + y2) / 2;
131809
+ }
131810
+ let pixelOffset = [0, 0];
131811
+ let textAnchor = "middle";
131812
+ let alignmentBaseline = "center";
131813
+ if (pos !== "middle") {
131814
+ const dxT = x2 - x12;
131815
+ const dyT = y2 - y12;
131816
+ const lenT = Math.sqrt(dxT * dxT + dyT * dyT);
131817
+ if (lenT > 0) {
131818
+ const uxT = dxT / lenT;
131819
+ const uyT = dyT / lenT;
131820
+ const sign2 = pos === "start" ? -1 : 1;
131821
+ const bufferPx = shape2.textBufferPx ?? 8;
131822
+ const offsetX = sign2 * uxT * bufferPx;
131823
+ const offsetY = sign2 * uyT * bufferPx;
131824
+ pixelOffset = [offsetX, offsetY];
131825
+ const absX = Math.abs(offsetX);
131826
+ const absY = Math.abs(offsetY);
131827
+ if (absX >= absY) {
131828
+ textAnchor = offsetX > 0 ? "start" : "end";
131829
+ }
131830
+ if (absY >= absX) {
131831
+ alignmentBaseline = offsetY > 0 ? "top" : "bottom";
131832
+ }
131833
+ }
131834
+ } else if (len2 > 0) {
131835
+ const belowPerp = pickBelowPerp(ux, uy);
131836
+ const bufferPx = shape2.textBufferPx ?? 14;
131837
+ pixelOffset = [-belowPerp[0] * bufferPx, -belowPerp[1] * bufferPx];
131838
+ textAnchor = "middle";
131839
+ alignmentBaseline = "center";
131840
+ }
131841
+ const middleAngle = pos === "middle" && len2 > 0 ? -readableAngle(Math.atan2(dy, dx) * 180 / Math.PI) : null;
131842
+ if (labelOpacity <= 0)
131843
+ return;
131844
+ layers.push(new TextLayer({
131845
+ ...labelBase,
131846
+ ...labelProps,
131847
+ id: `annotation-line-text-${uid2}-${i2}`,
131848
+ data: [{ position: [textX, textY], text: shape2.text }],
131849
+ getPosition: (d) => d.position,
131850
+ getText: (d) => d.text,
131851
+ getColor: strokeColor,
131852
+ getSize: LABEL_FONT_SIZE,
131853
+ sizeUnits: "pixels",
131854
+ fontFamily: LABEL_FONT_FAMILY$1,
131855
+ fontWeight: LABEL_FONT_WEIGHT,
131856
+ getPixelOffset: pixelOffset,
131857
+ getTextAnchor: textAnchor,
131858
+ getAlignmentBaseline: alignmentBaseline,
131859
+ ...middleAngle !== null && { getAngle: middleAngle }
131860
+ }));
131861
+ }
131862
+ }
131863
+ if (type === "ellipse") {
131864
+ const { x1: x12, y1: y12, radiusX, radiusY, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131865
+ const polygon2 = computeEllipsePolygon(x12, y12, radiusX, radiusY);
131866
+ const filled = fillOpacity > 0;
131867
+ layers.push(new PolygonLayer({
131868
+ ...base,
131869
+ id: `annotation-ellipse-${uid2}-${i2}`,
131870
+ data: [{ polygon: polygon2 }],
131871
+ getPolygon: (d) => d.polygon,
131872
+ filled,
131873
+ stroked: true,
131874
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
131875
+ getLineColor: strokeColor,
131876
+ getLineWidth: strokeWidth,
131877
+ lineWidthUnits: "pixels",
131878
+ ...dashArray ? {
131879
+ extensions: [new PathStyleExtension({ dash: true })],
131880
+ getDashArray: dashArray
131881
+ } : {}
131882
+ }));
131883
+ if (shape2.text && labelOpacity > 0) {
131884
+ layers.push(new TextLayer({
131885
+ ...labelBase,
131886
+ ...labelProps,
131887
+ id: `annotation-ellipse-text-${uid2}-${i2}`,
131888
+ data: [{ position: [x12, y12 - radiusY], text: shape2.text }],
131889
+ getPosition: (d) => d.position,
131890
+ getText: (d) => d.text,
131891
+ getColor: strokeColor,
131892
+ getSize: LABEL_FONT_SIZE,
131893
+ sizeUnits: "pixels",
131894
+ fontFamily: LABEL_FONT_FAMILY$1,
131895
+ fontWeight: LABEL_FONT_WEIGHT,
131896
+ getPixelOffset: [0, -4],
131897
+ getTextAnchor: "middle",
131898
+ getAlignmentBaseline: "bottom"
131899
+ }));
131900
+ }
131901
+ }
131902
+ if (type === "polygon") {
131903
+ const { points, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131904
+ if (!points || points.length < 3)
131905
+ return;
131906
+ const closedPath = [...points, points[0]];
131907
+ if (fillOpacity > 0) {
131908
+ layers.push(new PolygonLayer({
131909
+ ...base,
131910
+ id: `annotation-polygon-fill-${uid2}-${i2}`,
131911
+ data: [{ polygon: points }],
131912
+ getPolygon: (d) => d.polygon,
131913
+ stroked: false,
131914
+ filled: true,
131915
+ getFillColor: [...fillColor, Math.round(fillOpacity * 255)]
131916
+ }));
131917
+ }
131918
+ layers.push(new PathLayer({
131919
+ ...base,
131920
+ id: `annotation-polygon-${uid2}-${i2}`,
131921
+ extensions: dashExt,
131922
+ getDashArray: getDash,
131923
+ data: [{ path: closedPath }],
131924
+ getPath: (d) => d.path,
131925
+ getColor: strokeColor,
131926
+ getWidth: strokeWidth,
131927
+ widthUnits: "pixels",
131928
+ jointRounded: true
131929
+ }));
131930
+ if (shape2.text && labelOpacity > 0) {
131931
+ const minX = Math.min(...points.map((p) => p[0]));
131932
+ const maxX = Math.max(...points.map((p) => p[0]));
131933
+ const minY = Math.min(...points.map((p) => p[1]));
131934
+ const topCenterX = (minX + maxX) / 2;
131935
+ layers.push(new TextLayer({
131936
+ ...labelBase,
131937
+ ...labelProps,
131938
+ id: `annotation-polygon-text-${uid2}-${i2}`,
131939
+ data: [{ position: [topCenterX, minY], text: shape2.text }],
131940
+ getPosition: (d) => d.position,
131941
+ getText: (d) => d.text,
131942
+ getColor: strokeColor,
131943
+ getSize: LABEL_FONT_SIZE,
131944
+ sizeUnits: "pixels",
131945
+ fontFamily: LABEL_FONT_FAMILY$1,
131946
+ fontWeight: LABEL_FONT_WEIGHT,
131947
+ getPixelOffset: [0, -4],
131948
+ getTextAnchor: "middle",
131949
+ getAlignmentBaseline: "bottom"
131950
+ }));
131951
+ }
131952
+ }
131953
+ if (type === "polyline") {
131954
+ const { points, markerStart, markerEnd } = shape2;
131955
+ if (!points || points.length < 2)
131956
+ return;
131957
+ let pathPoints = points;
131958
+ if (markerStart === "Arrow") {
131959
+ const [x02, y02] = points[0];
131960
+ const [x12, y12] = points[1];
131961
+ const dx = x02 - x12;
131962
+ const dy = y02 - y12;
131963
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131964
+ if (len2 > 0) {
131965
+ const ux = dx / len2;
131966
+ const uy = dy / len2;
131967
+ pathPoints = [[x02 - ux * arrowDataSize, y02 - uy * arrowDataSize], ...pathPoints.slice(1)];
131968
+ }
131969
+ }
131970
+ if (markerEnd === "Arrow") {
131971
+ const last = pathPoints[pathPoints.length - 1];
131972
+ const prev2 = pathPoints[pathPoints.length - 2];
131973
+ const dx = last[0] - prev2[0];
131974
+ const dy = last[1] - prev2[1];
131975
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131976
+ if (len2 > 0) {
131977
+ const ux = dx / len2;
131978
+ const uy = dy / len2;
131979
+ const shortened = [last[0] - ux * arrowDataSize, last[1] - uy * arrowDataSize];
131980
+ pathPoints = [...pathPoints.slice(0, -1), shortened];
131981
+ }
131982
+ }
131983
+ layers.push(new PathLayer({
131984
+ ...base,
131985
+ id: `annotation-polyline-${uid2}-${i2}`,
131986
+ extensions: dashExt,
131987
+ getDashArray: getDash,
131988
+ data: [{ path: pathPoints }],
131989
+ getPath: (d) => d.path,
131990
+ getColor: strokeColor,
131991
+ getWidth: strokeWidth,
131992
+ widthUnits: "pixels",
131993
+ jointRounded: true,
131994
+ capRounded: true
131995
+ }));
131996
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
131997
+ const [x02, y02] = points[0];
131998
+ const [x12, y12] = points[1];
131999
+ const head = computeArrowhead(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
132000
+ if (head) {
132001
+ layers.push(new PolygonLayer({
132002
+ ...tipsBase,
132003
+ id: `annotation-polyline-start-arrow-${uid2}-${i2}`,
132004
+ data: [{ polygon: head }],
132005
+ getPolygon: (d) => d.polygon,
132006
+ filled: true,
132007
+ stroked: false,
132008
+ getFillColor: strokeColor
132009
+ }));
132010
+ }
132011
+ }
132012
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
132013
+ const last = points[points.length - 1];
132014
+ const prev2 = points[points.length - 2];
132015
+ const dxArrow = last[0] - prev2[0];
132016
+ const dyArrow = last[1] - prev2[1];
132017
+ const head = computeArrowhead(last[0], last[1], dxArrow, dyArrow, arrowDataSize);
132018
+ if (head) {
132019
+ layers.push(new PolygonLayer({
132020
+ ...tipsBase,
132021
+ id: `annotation-polyline-end-arrow-${uid2}-${i2}`,
132022
+ data: [{ polygon: head }],
132023
+ getPolygon: (d) => d.polygon,
132024
+ filled: true,
132025
+ stroked: false,
132026
+ getFillColor: strokeColor
132027
+ }));
132028
+ }
132029
+ }
132030
+ if (markerStart === "Tick" && tipsOpacity > 0) {
132031
+ const [x02, y02] = points[0];
132032
+ const [x12, y12] = points[1];
132033
+ const tick = computeTickCap(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
132034
+ if (tick) {
132035
+ layers.push(new PathLayer({
132036
+ ...tipsBase,
132037
+ id: `annotation-polyline-start-tick-${uid2}-${i2}`,
132038
+ data: [{ path: tick }],
132039
+ getPath: (d) => d.path,
132040
+ getColor: strokeColor,
132041
+ getWidth: strokeWidth,
132042
+ widthUnits: "pixels",
132043
+ capRounded: true
132044
+ }));
132045
+ }
132046
+ }
132047
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
132048
+ const last = points[points.length - 1];
132049
+ const prev2 = points[points.length - 2];
132050
+ const dxTick = last[0] - prev2[0];
132051
+ const dyTick = last[1] - prev2[1];
132052
+ const tick = computeTickCap(last[0], last[1], dxTick, dyTick, arrowDataSize);
132053
+ if (tick) {
132054
+ layers.push(new PathLayer({
132055
+ ...tipsBase,
132056
+ id: `annotation-polyline-end-tick-${uid2}-${i2}`,
132057
+ data: [{ path: tick }],
132058
+ getPath: (d) => d.path,
132059
+ getColor: strokeColor,
132060
+ getWidth: strokeWidth,
132061
+ widthUnits: "pixels",
132062
+ capRounded: true
132063
+ }));
132064
+ }
132065
+ }
132066
+ if (shape2.text) {
132067
+ const pos = shape2.textPosition ?? "start";
132068
+ const bufferPx = shape2.textBufferPx ?? 8;
132069
+ let textPt;
132070
+ let dirX;
132071
+ let dirY;
132072
+ if (pos === "end") {
132073
+ const last = points[points.length - 1];
132074
+ const prev2 = points[points.length - 2];
132075
+ textPt = last;
132076
+ dirX = last[0] - prev2[0];
132077
+ dirY = last[1] - prev2[1];
132078
+ } else if (pos === "middle") {
132079
+ const mx = points.reduce((s2, p) => s2 + p[0], 0) / points.length;
132080
+ const my = points.reduce((s2, p) => s2 + p[1], 0) / points.length;
132081
+ textPt = [mx, my];
132082
+ dirX = 0;
132083
+ dirY = 0;
132084
+ } else {
132085
+ [textPt] = points;
132086
+ dirX = points[0][0] - points[1][0];
132087
+ dirY = points[0][1] - points[1][1];
132088
+ }
132089
+ const [textX, textY] = textPt;
132090
+ const lenT = Math.sqrt(dirX * dirX + dirY * dirY);
132091
+ let polylinePixelOffset = [0, 0];
132092
+ let polylineTextAnchor = "middle";
132093
+ let polylineAlignmentBaseline = pos === "middle" ? "center" : "bottom";
132094
+ if (lenT > 0) {
132095
+ const uxT = dirX / lenT;
132096
+ const uyT = dirY / lenT;
132097
+ const offX = uxT * bufferPx;
132098
+ const offY = uyT * bufferPx;
132099
+ polylinePixelOffset = [offX, offY];
132100
+ if (Math.abs(offX) >= Math.abs(offY)) {
132101
+ polylineTextAnchor = offX > 0 ? "start" : "end";
132102
+ }
132103
+ if (Math.abs(offY) >= Math.abs(offX)) {
132104
+ polylineAlignmentBaseline = offY > 0 ? "top" : "bottom";
132105
+ }
132106
+ }
132107
+ if (labelOpacity <= 0)
132108
+ return;
132109
+ layers.push(new TextLayer({
132110
+ ...labelBase,
132111
+ ...labelProps,
132112
+ id: `annotation-polyline-text-${uid2}-${i2}`,
132113
+ data: [{ position: [textX, textY], text: shape2.text }],
132114
+ getPosition: (d) => d.position,
132115
+ getText: (d) => d.text,
132116
+ getColor: strokeColor,
132117
+ getSize: LABEL_FONT_SIZE,
132118
+ sizeUnits: "pixels",
132119
+ fontFamily: LABEL_FONT_FAMILY$1,
132120
+ fontWeight: LABEL_FONT_WEIGHT,
132121
+ getPixelOffset: polylinePixelOffset,
132122
+ getTextAnchor: polylineTextAnchor,
132123
+ getAlignmentBaseline: polylineAlignmentBaseline
132124
+ }));
132125
+ }
132126
+ }
132127
+ });
132128
+ if (dotShapes.length > 0) {
132129
+ layers.push(new ScatterplotLayer({
132130
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
132131
+ id: "annotation-dots",
132132
+ data: dotShapes.map(({ shape: s2, alpha: alpha2 }) => ({
132133
+ position: getShapeCentroid(s2),
132134
+ color: [...s2.strokeColor ?? [255, 255, 255], alpha2]
132135
+ })),
132136
+ getPosition: (d) => d.position,
132137
+ getFillColor: (d) => d.color,
132138
+ getRadius: 4,
132139
+ radiusUnits: "pixels",
132140
+ filled: true,
132141
+ stroked: false
132142
+ }));
132143
+ }
132144
+ if (clusterDotShapes.length > 0) {
132145
+ const clusters = computeClusters(clusterDotShapes, zoom);
132146
+ layers.push(new ScatterplotLayer({
132147
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
132148
+ id: "annotation-clusters",
132149
+ data: clusters,
132150
+ getPosition: (d) => d.position,
132151
+ getFillColor: (d) => [...d.color, 180],
132152
+ getRadius: (d) => Math.max(6, 4 + Math.sqrt(d.count) * 2),
132153
+ radiusUnits: "pixels",
132154
+ filled: true,
132155
+ stroked: true,
132156
+ getLineColor: (d) => [...d.color, 220],
132157
+ lineWidthMinPixels: 1.5
132158
+ }));
132159
+ const multiClusters = clusters.filter((c2) => c2.count > 1);
132160
+ if (multiClusters.length > 0) {
132161
+ layers.push(new TextLayer({
132162
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
132163
+ id: "annotation-cluster-counts",
132164
+ data: multiClusters,
132165
+ getPosition: (d) => d.position,
132166
+ getText: (d) => String(d.count),
132167
+ getColor: [255, 255, 255],
132168
+ getSize: 10,
132169
+ sizeUnits: "pixels",
132170
+ fontWeight: "bold",
132171
+ getTextAnchor: "middle",
132172
+ getAlignmentBaseline: "center"
132173
+ }));
132174
+ }
132175
+ }
132176
+ const measureLayers = [];
132177
+ shapes.forEach((shape2) => {
132178
+ if (!shape2.showMeasure)
132179
+ return;
132180
+ const mIsSelected = shape2.uid === selectedShapeUid;
132181
+ const label = getMeasurementLabel(shape2, physicalPixelSize, viewType);
132182
+ if (!label)
132183
+ return;
132184
+ const color2 = shape2.strokeColor ?? [255, 255, 255];
132185
+ let mShapeOpacity = 1;
132186
+ let mLabelFactor = 0;
132187
+ if (mIsSelected || !semanticZoom || authoredZoom === null) {
132188
+ mLabelFactor = 1;
132189
+ } else {
132190
+ const mZoomRatio = 2 ** (zoom - authoredZoom);
132191
+ if (mZoomRatio < RATIO_DOT)
132192
+ return;
132193
+ if (mZoomRatio < RATIO_GEO_FADE) {
132194
+ mShapeOpacity = (mZoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
132195
+ }
132196
+ if (mZoomRatio >= RATIO_LABEL_FULL) {
132197
+ mLabelFactor = 1;
132198
+ } else if (mZoomRatio >= RATIO_LABEL) {
132199
+ mLabelFactor = (mZoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL);
132200
+ }
132201
+ }
132202
+ const measureOpacity = mShapeOpacity * mLabelFactor;
132203
+ if (measureOpacity <= 0)
132204
+ return;
132205
+ const base = {
132206
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
132207
+ opacity: measureOpacity,
132208
+ getText: (d) => d.text,
132209
+ getPosition: (d) => d.position,
132210
+ getColor: color2,
132211
+ getSize: 13,
132212
+ sizeUnits: "pixels",
132213
+ fontFamily: LABEL_FONT_FAMILY$1,
132214
+ fontWeight: "bold",
132215
+ // 'auto' builds the font atlas from the actual rendered characters (e.g. µ, ²)
132216
+ // instead of deck.gl's default ASCII-only atlas.
132217
+ characterSet: "auto",
132218
+ ...shape2.measureBackground ? {
132219
+ background: true,
132220
+ getBackgroundColor: textBgColor(color2),
132221
+ backgroundPadding: [3, 1, 3, 2]
132222
+ } : {}
132223
+ };
132224
+ if (shape2.type === "line") {
132225
+ const mx = ((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2;
132226
+ const my = ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2;
132227
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
132228
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
132229
+ const len2 = Math.sqrt(dx * dx + dy * dy);
132230
+ if (len2 === 0)
132231
+ return;
132232
+ const perp = pickBelowPerp(dx / len2, dy / len2);
132233
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
132234
+ measureLayers.push(new TextLayer({
132235
+ ...base,
132236
+ id: `annotation-measure-${shape2.uid}`,
132237
+ data: [{ position: [mx, my], text: label }],
132238
+ getAngle: -angle2,
132239
+ getTextAnchor: "middle",
132240
+ getAlignmentBaseline: "center",
132241
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
132242
+ }));
132243
+ } else if (shape2.type === "polyline" && shape2.points?.length >= 2) {
132244
+ const pts = shape2.points;
132245
+ const mi = Math.floor((pts.length - 1) / 2);
132246
+ const [ax, ay] = pts[mi];
132247
+ const [bx, by] = pts[mi + 1];
132248
+ const dx = bx - ax;
132249
+ const dy = by - ay;
132250
+ const len2 = Math.sqrt(dx * dx + dy * dy);
132251
+ if (len2 === 0)
132252
+ return;
132253
+ const perp = pickBelowPerp(dx / len2, dy / len2);
132254
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
132255
+ measureLayers.push(new TextLayer({
132256
+ ...base,
132257
+ id: `annotation-measure-${shape2.uid}`,
132258
+ data: [{ position: [(ax + bx) / 2, (ay + by) / 2], text: label }],
132259
+ getAngle: -angle2,
132260
+ getTextAnchor: "middle",
132261
+ getAlignmentBaseline: "center",
132262
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
132263
+ }));
132264
+ } else if (shape2.type === "rectangle") {
132265
+ const x02 = shape2.x ?? 0;
132266
+ const y02 = shape2.y ?? 0;
132267
+ const w2 = shape2.width ?? 0;
132268
+ const h = shape2.height ?? 0;
132269
+ const rx = x02 + (w2 >= 0 ? w2 : 0);
132270
+ const ry = y02 + (h >= 0 ? h : 0);
132271
+ measureLayers.push(new TextLayer({
132272
+ ...base,
132273
+ id: `annotation-measure-${shape2.uid}`,
132274
+ data: [{ position: [rx, ry], text: label }],
132275
+ getTextAnchor: "end",
132276
+ getAlignmentBaseline: "bottom",
132277
+ getPixelOffset: [-6, -6]
132278
+ }));
132279
+ } else if (shape2.type === "ellipse") {
132280
+ const cx = shape2.x1 ?? 0;
132281
+ const cy = shape2.y1 ?? 0;
132282
+ const ry = Math.abs(shape2.radiusY ?? 0);
132283
+ measureLayers.push(new TextLayer({
132284
+ ...base,
132285
+ id: `annotation-measure-${shape2.uid}`,
132286
+ data: [{ position: [cx, cy + ry], text: label }],
132287
+ getTextAnchor: "middle",
132288
+ getAlignmentBaseline: "top",
132289
+ getPixelOffset: [0, 8]
132290
+ }));
132291
+ } else if (shape2.type === "polygon" && shape2.points?.length >= 3) {
132292
+ const xs = shape2.points.map((p) => p[0]);
132293
+ const ys = shape2.points.map((p) => p[1]);
132294
+ const cx = (Math.min(...xs) + Math.max(...xs)) / 2;
132295
+ const maxY = Math.max(...ys);
132296
+ measureLayers.push(new TextLayer({
132297
+ ...base,
132298
+ id: `annotation-measure-${shape2.uid}`,
132299
+ data: [{ position: [cx, maxY], text: label }],
132300
+ getTextAnchor: "middle",
132301
+ getAlignmentBaseline: "top",
132302
+ getPixelOffset: [0, 8]
132303
+ }));
132304
+ }
132305
+ });
132306
+ return [...selectionLayers, ...layers, ...measureLayers];
132307
+ }
132308
+ const defaultProps$1 = {
132309
+ // Array of annotation shape objects (see annotationShapeObj in @vitessce/schemas).
132310
+ data: { type: "object", value: [], compare: true },
132311
+ // UID of the shape to highlight with a selection halo.
132312
+ selectedShapeUid: { type: "string", value: null },
132313
+ // { x, y, unit } used to format measurement labels in physical units.
132314
+ physicalPixelSize: { type: "object", value: null, compare: true },
132315
+ // The zoom level at which the shapes were authored (reference for semantic zoom).
132316
+ authoredZoom: { type: "number", value: null },
132317
+ // Whether to apply semantic zoom (level-of-detail) based on authoredZoom.
132318
+ semanticZoom: { type: "boolean", value: true },
132319
+ // The view type in which the layer is rendered (affects measurement label formatting).
132320
+ viewType: { type: "string", value: ViewType$1.SPATIAL },
132321
+ // In-progress shape being drawn, as { type, vertices }.
132322
+ inProgressShape: { type: "object", value: null, compare: true },
132323
+ // Current mouse position (in data coordinates) while drawing.
132324
+ hoverCoord: { type: "array", value: null, compare: true },
132325
+ // Stroke color [r, g, b] of the in-progress shape preview.
132326
+ previewStrokeColor: { type: "color", value: [255, 255, 0] }
132327
+ };
132328
+ class AnnotationLayer extends CompositeLayer {
132329
+ // The semantic zoom and arrowhead sizes depend on the current zoom level,
132330
+ // so the sublayers must also be re-rendered when the viewport changes.
132331
+ // eslint-disable-next-line class-methods-use-this
132332
+ shouldUpdateState({ changeFlags }) {
132333
+ return changeFlags.propsOrDataChanged || changeFlags.viewportChanged;
132334
+ }
132335
+ /**
132336
+ * Prefix the sublayer ID with this layer's ID (so that multiple
132337
+ * AnnotationLayers can co-exist), and combine this layer's
132338
+ * opacity with the per-shape opacity of the sublayer.
132339
+ * Note: we avoid getSubLayerProps here, since it would
132340
+ * overwrite the sublayer extensions (e.g., PathStyleExtension)
132341
+ * and opacity values.
132342
+ * @param {object} layer A DeckGL layer instance.
132343
+ * @returns {object} The cloned layer instance.
132344
+ */
132345
+ wrapSubLayer(layer) {
132346
+ const { id, opacity, pickable, visible } = this.props;
132347
+ return layer.clone({
132348
+ id: `${id}-${layer.id}`,
132349
+ opacity: layer.props.opacity * opacity,
132350
+ pickable,
132351
+ visible
132352
+ });
132353
+ }
132354
+ renderLayers() {
132355
+ const { data, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType, inProgressShape, hoverCoord, previewStrokeColor } = this.props;
132356
+ const zoom = this.context.viewport?.zoom ?? 0;
132357
+ const visibleShapes = (data ?? []).filter((shape2) => shape2.visible !== false);
132358
+ const annotationLayers = createAnnotationLayers(visibleShapes, zoom, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType);
132359
+ const previewLayer = createPreviewLayer(inProgressShape, hoverCoord, previewStrokeColor.slice(0, 3));
132360
+ return [
132361
+ ...annotationLayers,
132362
+ ...previewLayer ? [previewLayer] : []
132363
+ ].map((layer) => this.wrapSubLayer(layer));
132364
+ }
132365
+ }
132366
+ AnnotationLayer.layerName = "AnnotationLayer";
132367
+ AnnotationLayer.defaultProps = defaultProps$1;
131005
132368
  function r$1(e3) {
131006
132369
  var t, f2, n2 = "";
131007
132370
  if ("string" == typeof e3 || "number" == typeof e3) n2 += e3;
@@ -145642,11 +147005,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145642
147005
  this.cellSetsLabelPrevZoom = null;
145643
147006
  this.cellSetsLayers = [];
145644
147007
  this.contourLayers = [];
147008
+ this.annotationLayer = null;
145645
147009
  this.onUpdateCellsData();
145646
147010
  this.onUpdateCellsLayer();
145647
147011
  this.onUpdateCellSetsLayers();
145648
147012
  this.onUpdateStratifiedData();
145649
147013
  this.onUpdateContourLayers();
147014
+ this.onUpdateAnnotationLayer();
145650
147015
  }
145651
147016
  // Want to support multiple types of contour layers
145652
147017
  // - One layer for all data points (no filtering)
@@ -145710,6 +147075,21 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145710
147075
  }));
145711
147076
  return layers;
145712
147077
  }
147078
+ createAnnotationLayer() {
147079
+ const { annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection } = this.props;
147080
+ return new AnnotationLayer({
147081
+ data: annotationShapes,
147082
+ visible: annotationOverlayVisible,
147083
+ semanticZoom: annotationSemanticZoom,
147084
+ selectedShapeUid: annotationShapeSelection,
147085
+ viewType: ViewType$1.SCATTERPLOT
147086
+ // TODO: is this needed?
147087
+ // TODO: these are view-level properties, rather than layer-level.
147088
+ // annotationTransitionDuration,
147089
+ // annotationEditable,
147090
+ // Other coordination types related to editing...
147091
+ });
147092
+ }
145713
147093
  createCellsLayer() {
145714
147094
  const {
145715
147095
  obsEmbeddingIndex: obsIndex,
@@ -145843,12 +147223,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145843
147223
  ], flipYTooltip, this.props.onSelectionBusy);
145844
147224
  }
145845
147225
  getLayers() {
145846
- const { cellsLayer, cellSetsLayers, contourLayers } = this;
147226
+ const { cellsLayer, cellSetsLayers, contourLayers, annotationLayer } = this;
145847
147227
  return [
145848
147228
  cellsLayer,
145849
147229
  ...contourLayers,
145850
147230
  ...cellSetsLayers,
145851
- this.createSelectionLayer()
147231
+ this.createSelectionLayer(),
147232
+ annotationLayer
145852
147233
  ];
145853
147234
  }
145854
147235
  /**
@@ -145885,6 +147266,14 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145885
147266
  this.cellsLayer = null;
145886
147267
  }
145887
147268
  }
147269
+ onUpdateAnnotationLayer() {
147270
+ const { annotationShapes } = this.props;
147271
+ if (annotationShapes) {
147272
+ this.annotationLayer = this.createAnnotationLayer();
147273
+ } else {
147274
+ this.annotationLayer = null;
147275
+ }
147276
+ }
145888
147277
  onUpdateStratifiedData() {
145889
147278
  const { stratifiedData } = this.props;
145890
147279
  if (stratifiedData) {
@@ -146000,6 +147389,16 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
146000
147389
  this.onUpdateCellSetsLayers(true);
146001
147390
  forceUpdate = true;
146002
147391
  }
147392
+ if ([
147393
+ "annotationShapes",
147394
+ "annotationOverlayVisible",
147395
+ "annotationSemanticZoom",
147396
+ "annotationTransitionDuration",
147397
+ "annotationEditable"
147398
+ ].some(shallowDiff)) {
147399
+ this.onUpdateAnnotationLayer();
147400
+ forceUpdate = true;
147401
+ }
146003
147402
  if (forceUpdate) {
146004
147403
  this.forceUpdate();
146005
147404
  }
@@ -148801,7 +150200,6 @@ const DEFAULT_FEATURE_AGGREGATION_STRATEGY = "first";
148801
150200
  function EmbeddingScatterplotSubscriber(props) {
148802
150201
  const {
148803
150202
  uuid,
148804
- coordinationScopes: coordinationScopesRaw,
148805
150203
  closeButtonVisible,
148806
150204
  downloadButtonVisible,
148807
150205
  removeGridComponent,
@@ -148817,9 +150215,15 @@ function EmbeddingScatterplotSubscriber(props) {
148817
150215
  circleScaleFactor = 0.8
148818
150216
  } = props;
148819
150217
  const loaders = useLoaders();
148820
- const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
150218
+ const [
150219
+ // eslint-disable-next-line no-unused-vars
150220
+ coordinationScopes,
150221
+ _coordinationScopesBy,
150222
+ coordinationValues
150223
+ ] = useViewMapping(uuid);
148821
150224
  const setComponentHover = useSetComponentHover();
148822
150225
  const setComponentViewInfo = useSetComponentViewInfo(uuid);
150226
+ useAnnotationFrameCoordination(uuid, coordinationScopes, coordinationValues);
148823
150227
  const [{
148824
150228
  dataset,
148825
150229
  obsType,
@@ -148856,7 +150260,13 @@ function EmbeddingScatterplotSubscriber(props) {
148856
150260
  embeddingContourPercentiles: contourPercentiles,
148857
150261
  contourColorEncoding,
148858
150262
  contourColor,
148859
- featureAggregationStrategy
150263
+ featureAggregationStrategy,
150264
+ annotationStory,
150265
+ annotationShapes,
150266
+ annotationOverlayVisible,
150267
+ annotationSemanticZoom,
150268
+ annotationTransitionDuration,
150269
+ annotationEditable
148860
150270
  }, {
148861
150271
  setEmbeddingZoom: setZoom,
148862
150272
  setEmbeddingTargetX: setTargetX,
@@ -148883,21 +150293,41 @@ function EmbeddingScatterplotSubscriber(props) {
148883
150293
  setEmbeddingContoursFilled,
148884
150294
  setEmbeddingContourPercentiles: setContourPercentiles,
148885
150295
  setContourColorEncoding,
148886
- setFeatureAggregationStrategy
148887
- }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes);
150296
+ setFeatureAggregationStrategy,
150297
+ setAnnotationStory
150298
+ }] = useCoordination(
150299
+ COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT],
150300
+ coordinationScopes,
150301
+ coordinationValues,
150302
+ uuid
150303
+ );
148888
150304
  const {
148889
150305
  embeddingZoom: initialZoom,
148890
150306
  embeddingTargetX: initialTargetX,
148891
150307
  embeddingTargetY: initialTargetY
148892
150308
  } = useInitialCoordination(
148893
150309
  COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT],
148894
- coordinationScopes
150310
+ coordinationScopes,
150311
+ coordinationValues
148895
150312
  );
148896
150313
  const observationsLabel = observationsLabelOverride || obsType;
148897
150314
  const sampleSetSelection = sampleSetSelectionFromProps || sampleSetSelectionFromCoordination;
148898
150315
  const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY;
148899
150316
  const [width2, height2, deckRef] = useDeckCanvasSize();
148900
150317
  const title = titleOverride || `Scatterplot (${mapping})`;
150318
+ const [
150319
+ ,
150320
+ annotationStoryStatus,
150321
+ annotationStoryUrls,
150322
+ annotationStoryError
150323
+ ] = useAnnotationStoryData(
150324
+ loaders,
150325
+ dataset,
150326
+ false,
150327
+ { setAnnotationStory },
150328
+ { annotationStory },
150329
+ {}
150330
+ );
148901
150331
  const [
148902
150332
  // eslint-disable-next-line no-unused-vars
148903
150333
  obsLabelsTypes,
@@ -149004,11 +150434,13 @@ function EmbeddingScatterplotSubscriber(props) {
149004
150434
  matrixIndicesError,
149005
150435
  featureLabelsError,
149006
150436
  sampleSetsError,
149007
- sampleEdgesError
150437
+ sampleEdgesError,
150438
+ annotationStoryError
149008
150439
  ];
149009
150440
  const isReady = useReady([
149010
150441
  obsEmbeddingStatus,
149011
150442
  obsSetsStatus,
150443
+ annotationStoryStatus,
149012
150444
  featureSelectionStatus,
149013
150445
  featureLabelsStatus,
149014
150446
  expandedFeatureLabelsStatus,
@@ -149022,7 +150454,8 @@ function EmbeddingScatterplotSubscriber(props) {
149022
150454
  matrixIndicesUrls,
149023
150455
  featureLabelsUrls,
149024
150456
  sampleSetsUrl,
149025
- sampleEdgesUrl
150457
+ sampleEdgesUrl,
150458
+ annotationStoryUrls
149026
150459
  ]);
149027
150460
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
149028
150461
  const [isSelectionPending, setIsSelectionPending] = useState(false);
@@ -149398,7 +150831,12 @@ function EmbeddingScatterplotSubscriber(props) {
149398
150831
  embeddingPointsVisible,
149399
150832
  embeddingContoursVisible,
149400
150833
  circleInfo,
149401
- featureSelection: geneSelection
150834
+ featureSelection: geneSelection,
150835
+ annotationShapes,
150836
+ annotationOverlayVisible,
150837
+ annotationSemanticZoom,
150838
+ annotationTransitionDuration,
150839
+ annotationEditable
149402
150840
  }
149403
150841
  ),
149404
150842
  tooltipsVisible && width2 && height2 ? /* @__PURE__ */ React__default.createElement(