@vitessce/scatterplot-embedding 4.0.7 → 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({
@@ -9633,7 +9634,9 @@ const ViewType$1 = {
9633
9634
  DUAL_SCATTERPLOT: "dualScatterplot",
9634
9635
  TREEMAP: "treemap",
9635
9636
  SAMPLE_SET_PAIR_MANAGER: "sampleSetPairManager",
9636
- FEATURE_STATS_TABLE: "featureStatsTable"
9637
+ FEATURE_STATS_TABLE: "featureStatsTable",
9638
+ SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector",
9639
+ ANNOTATION_CONTROLLER: "annotationController"
9637
9640
  };
9638
9641
  const DataType$2 = {
9639
9642
  OBS_LABELS: "obsLabels",
@@ -9654,7 +9657,8 @@ const DataType$2 = {
9654
9657
  COMPARISON_METADATA: "comparisonMetadata",
9655
9658
  FEATURE_STATS: "featureStats",
9656
9659
  FEATURE_SET_STATS: "featureSetStats",
9657
- OBS_SET_STATS: "obsSetStats"
9660
+ OBS_SET_STATS: "obsSetStats",
9661
+ ANNOTATION_STORY: "annotationStory"
9658
9662
  };
9659
9663
  const FileType$1 = {
9660
9664
  // Joint file types
@@ -9676,6 +9680,7 @@ const FileType$1 = {
9676
9680
  OBS_SETS_CSV: "obsSets.csv",
9677
9681
  OBS_SETS_JSON: "obsSets.json",
9678
9682
  SAMPLE_SETS_CSV: "sampleSets.csv",
9683
+ ANNOTATION_STORY_JSON: "annotationStory.json",
9679
9684
  // OME-Zarr
9680
9685
  IMAGE_OME_ZARR: "image.ome-zarr",
9681
9686
  OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
@@ -9960,7 +9965,15 @@ const CoordinationType$1 = {
9960
9965
  FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
9961
9966
  FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
9962
9967
  // Treemap
9963
- 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"
9964
9977
  };
9965
9978
  const ViewHelpMapping = {
9966
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)."
@@ -9979,6 +9992,7 @@ const ViewHelpMapping = {
9979
9992
  [FileType$1.OBS_SEGMENTATIONS_JSON]: DataType$2.OBS_SEGMENTATIONS,
9980
9993
  [FileType$1.OBS_SETS_CSV]: DataType$2.OBS_SETS,
9981
9994
  [FileType$1.OBS_SETS_JSON]: DataType$2.OBS_SETS,
9995
+ [FileType$1.ANNOTATION_STORY_JSON]: DataType$2.ANNOTATION_STORY,
9982
9996
  [FileType$1.IMAGE_OME_ZARR]: DataType$2.IMAGE,
9983
9997
  [FileType$1.OBS_SEGMENTATIONS_OME_ZARR]: DataType$2.OBS_SEGMENTATIONS,
9984
9998
  [FileType$1.OBS_FEATURE_MATRIX_ANNDATA_ZARR]: DataType$2.OBS_FEATURE_MATRIX,
@@ -10101,7 +10115,8 @@ const ViewHelpMapping = {
10101
10115
  [DataType$2.OBS_SET_STATS]: [
10102
10116
  CoordinationType$1.OBS_TYPE
10103
10117
  // TODO: should sampleType, obsSetSelection, and/or sampleSetSelection be used here?
10104
- ]
10118
+ ],
10119
+ [DataType$2.ANNOTATION_STORY]: []
10105
10120
  });
10106
10121
  ({
10107
10122
  // For AnnData:
@@ -10234,7 +10249,9 @@ const ViewHelpMapping = {
10234
10249
  CoordinationType$1.SPATIAL_TARGET_Z,
10235
10250
  CoordinationType$1.SPATIAL_AXIS_FIXED,
10236
10251
  CoordinationType$1.SPATIAL_ORBIT_AXIS,
10237
- 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
10238
10255
  ];
10239
10256
  const COMPONENT_COORDINATION_TYPES = {
10240
10257
  [ViewType$1.NEUROGLANCER]: [
@@ -10326,7 +10343,14 @@ const COMPONENT_COORDINATION_TYPES = {
10326
10343
  CoordinationType$1.EMBEDDING_CONTOURS_FILLED,
10327
10344
  CoordinationType$1.EMBEDDING_CONTOUR_PERCENTILES,
10328
10345
  CoordinationType$1.CONTOUR_COLOR_ENCODING,
10329
- 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
10330
10354
  ],
10331
10355
  [ViewType$1.DUAL_SCATTERPLOT]: [
10332
10356
  CoordinationType$1.DATASET,
@@ -10442,7 +10466,14 @@ const COMPONENT_COORDINATION_TYPES = {
10442
10466
  CoordinationType$1.ADDITIONAL_OBS_SETS,
10443
10467
  CoordinationType$1.MOLECULE_HIGHLIGHT,
10444
10468
  CoordinationType$1.TOOLTIPS_VISIBLE,
10445
- 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
10446
10477
  ],
10447
10478
  [ViewType$1.SPATIAL_BETA]: [
10448
10479
  CoordinationType$1.META_COORDINATION_SCOPES,
@@ -10520,7 +10551,27 @@ const COMPONENT_COORDINATION_TYPES = {
10520
10551
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
10521
10552
  CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
10522
10553
  CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
10523
- 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.
10524
10575
  ],
10525
10576
  [ViewType$1.HEATMAP]: [
10526
10577
  CoordinationType$1.DATASET,
@@ -10830,6 +10881,11 @@ const COMPONENT_COORDINATION_TYPES = {
10830
10881
  CoordinationType$1.FEATURE_POINT_FOLD_CHANGE_THRESHOLD,
10831
10882
  CoordinationType$1.FEATURE_LABEL_FOLD_CHANGE_THRESHOLD
10832
10883
  ],
10884
+ [ViewType$1.SINGLE_OBS_SET_SELECTOR]: [
10885
+ CoordinationType$1.OBS_TYPE,
10886
+ CoordinationType$1.OBS_SET_COLOR,
10887
+ CoordinationType$1.OBS_SET_SELECTION
10888
+ ],
10833
10889
  [ViewType$1.OBS_SET_COMPOSITION_BAR_PLOT]: [
10834
10890
  CoordinationType$1.DATASET,
10835
10891
  CoordinationType$1.OBS_TYPE,
@@ -11533,6 +11589,124 @@ z.object({
11533
11589
  radius: z.number(),
11534
11590
  opacity: z.number()
11535
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
+ });
11536
11710
  const SETS_DATATYPE_OBS = "obs";
11537
11711
  const HIERARCHICAL_SCHEMAS = {
11538
11712
  latestVersion: "0.1.3"
@@ -24586,8 +24760,8 @@ class Vector extends MathArray {
24586
24760
  distanceSquared(mathArray) {
24587
24761
  let length2 = 0;
24588
24762
  for (let i2 = 0; i2 < this.ELEMENTS; ++i2) {
24589
- const dist = this[i2] - mathArray[i2];
24590
- length2 += dist * dist;
24763
+ const dist2 = this[i2] - mathArray[i2];
24764
+ length2 += dist2 * dist2;
24591
24765
  }
24592
24766
  return checkNumber(length2);
24593
24767
  }
@@ -24908,6 +25082,12 @@ function multiply$3(out, a2, b) {
24908
25082
  out[2] = a2[2] * b[2];
24909
25083
  return out;
24910
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
+ }
24911
25091
  function squaredLength$2(a2) {
24912
25092
  var x = a2[0];
24913
25093
  var y = a2[1];
@@ -25031,6 +25211,7 @@ function angle$2(a2, b) {
25031
25211
  }
25032
25212
  var sub = subtract;
25033
25213
  var mul = multiply$3;
25214
+ var dist = distance$3;
25034
25215
  var len = length$5;
25035
25216
  var sqrLen = squaredLength$2;
25036
25217
  (function() {
@@ -39501,7 +39682,7 @@ function noop$2() {
39501
39682
  const getCursor$1 = ({
39502
39683
  isDragging
39503
39684
  }) => isDragging ? "grabbing" : "grab";
39504
- const defaultProps$O = {
39685
+ const defaultProps$P = {
39505
39686
  id: "",
39506
39687
  width: "100%",
39507
39688
  height: "100%",
@@ -39632,7 +39813,7 @@ class Deck {
39632
39813
  this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
39633
39814
  });
39634
39815
  this.props = {
39635
- ...defaultProps$O,
39816
+ ...defaultProps$P,
39636
39817
  ...props
39637
39818
  };
39638
39819
  props = this.props;
@@ -40134,7 +40315,7 @@ class Deck {
40134
40315
  metrics.gpuMemory = memoryStats.get("GPU Memory").count;
40135
40316
  }
40136
40317
  }
40137
- _defineProperty(Deck, "defaultProps", defaultProps$O);
40318
+ _defineProperty(Deck, "defaultProps", defaultProps$P);
40138
40319
  _defineProperty(Deck, "VERSION", deckGlobal.VERSION);
40139
40320
  class ShaderAttribute {
40140
40321
  constructor(dataColumn, opts) {
@@ -42889,7 +43070,7 @@ const areViewportsEqual = memoize$3(({
42889
43070
  return oldViewport.equals(viewport);
42890
43071
  });
42891
43072
  let pickingColorCache = new Uint8ClampedArray(0);
42892
- const defaultProps$N = {
43073
+ const defaultProps$O = {
42893
43074
  data: {
42894
43075
  type: "data",
42895
43076
  value: EMPTY_ARRAY$1,
@@ -43764,7 +43945,7 @@ class Layer extends Component {
43764
43945
  this.setNeedsUpdate();
43765
43946
  }
43766
43947
  }
43767
- _defineProperty(Layer, "defaultProps", defaultProps$N);
43948
+ _defineProperty(Layer, "defaultProps", defaultProps$O);
43768
43949
  _defineProperty(Layer, "layerName", "Layer");
43769
43950
  const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
43770
43951
  class CompositeLayer extends Layer {
@@ -44800,6 +44981,124 @@ const esm$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
44800
44981
  project32,
44801
44982
  shadow
44802
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");
44803
45102
  const defaultProps$M = {
44804
45103
  clipBounds: [0, 0, 1, 1]
44805
45104
  };
@@ -100847,8 +101146,8 @@ function requireJs$b() {
100847
101146
  var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi12 / 2 + Math.PI / 4));
100848
101147
  var q = Math.abs(DeltaPsi) > 1e-11 ? DeltaPhi / DeltaPsi : Math.cos(phi12);
100849
101148
  var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda);
100850
- var dist = delta * R;
100851
- return dist;
101149
+ var dist2 = delta * R;
101150
+ return dist2;
100852
101151
  }
100853
101152
  js$a.default = rhumbDistance;
100854
101153
  return js$a;
@@ -101161,7 +101460,7 @@ function requireUtils$2() {
101161
101460
  var x;
101162
101461
  var y;
101163
101462
  var segmentIdx;
101164
- var dist;
101463
+ var dist2;
101165
101464
  if (coords.length > 1 && pointCoords.length) {
101166
101465
  var lineCoordinates;
101167
101466
  var pointCoordinate;
@@ -101178,17 +101477,17 @@ function requireUtils$2() {
101178
101477
  if (lineCoordinates[n2][0] !== lineCoordinates[n2 - 1][0]) {
101179
101478
  var slope = (lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1]) / (lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0]);
101180
101479
  var inverseSlope = lineCoordinates[n2][1] - slope * lineCoordinates[n2][0];
101181
- dist = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
101182
- } 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]);
101183
101482
  var rl2 = Math.pow(lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1], 2) + Math.pow(lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0], 2);
101184
101483
  var ln2 = Math.pow(lineCoordinates[n2][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2][0] - pointCoordinate[0], 2);
101185
101484
  var lnm12 = Math.pow(lineCoordinates[n2 - 1][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2 - 1][0] - pointCoordinate[0], 2);
101186
- var dist2 = Math.pow(dist, 2);
101187
- var calcrl2 = ln2 - dist2 + lnm12 - dist2;
101485
+ var dist22 = Math.pow(dist2, 2);
101486
+ var calcrl2 = ln2 - dist22 + lnm12 - dist22;
101188
101487
  if (calcrl2 > rl2) {
101189
- dist = Math.sqrt(Math.min(ln2, lnm12));
101488
+ dist2 = Math.sqrt(Math.min(ln2, lnm12));
101190
101489
  }
101191
- if (minDist === null || minDist === void 0 || minDist > dist) {
101490
+ if (minDist === null || minDist === void 0 || minDist > dist2) {
101192
101491
  if (calcrl2 > rl2) {
101193
101492
  if (lnm12 < ln2) {
101194
101493
  to = 0;
@@ -101198,10 +101497,10 @@ function requireUtils$2() {
101198
101497
  to = 1;
101199
101498
  }
101200
101499
  } else {
101201
- to = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
101202
- 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);
101203
101502
  }
101204
- minDist = dist;
101503
+ minDist = dist2;
101205
101504
  segmentIdx = n2;
101206
101505
  }
101207
101506
  }
@@ -117532,22 +117831,22 @@ function addDecoder(cases, importFn) {
117532
117831
  }
117533
117832
  cases.forEach((c2) => registry$1.set(c2, importFn));
117534
117833
  }
117535
- addDecoder([void 0, 1], () => import("./raw-gRNpvpQg.js").then((m2) => m2.default));
117536
- addDecoder(5, () => import("./lzw-BdtUMX-Z.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));
117537
117836
  addDecoder(6, () => {
117538
117837
  throw new Error("old style JPEG compression is not supported.");
117539
117838
  });
117540
- addDecoder(7, () => import("./jpeg-0GPV7wHB.js").then((m2) => m2.default));
117541
- addDecoder([8, 32946], () => import("./deflate-aaOFaah9.js").then((m2) => m2.default));
117542
- addDecoder(32773, () => import("./packbits-XKIpoMsP.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));
117543
117842
  addDecoder(
117544
117843
  34887,
117545
- () => import("./lerc-b0eKtxKR.js").then(async (m2) => {
117844
+ () => import("./lerc-zU6xDjk2.js").then(async (m2) => {
117546
117845
  await m2.zstd.init();
117547
117846
  return m2;
117548
117847
  }).then((m2) => m2.default)
117549
117848
  );
117550
- addDecoder(50001, () => import("./webimage-CbAzpg9y.js").then((m2) => m2.default));
117849
+ addDecoder(50001, () => import("./webimage-DP9dgaA0.js").then((m2) => m2.default));
117551
117850
  function decodeRowAcc(row, stride) {
117552
117851
  let length2 = row.length - stride;
117553
117852
  let offset2 = 0;
@@ -117962,8 +118261,8 @@ function TreeDesc(dyn_tree, stat_desc) {
117962
118261
  this.max_code = 0;
117963
118262
  this.stat_desc = stat_desc;
117964
118263
  }
117965
- const d_code = (dist) => {
117966
- 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)];
117967
118266
  };
117968
118267
  const put_short = (s2, w2) => {
117969
118268
  s2.pending_buf[s2.pending++] = w2 & 255;
@@ -118097,7 +118396,7 @@ const tr_static_init = () => {
118097
118396
  let bits;
118098
118397
  let length2;
118099
118398
  let code;
118100
- let dist;
118399
+ let dist2;
118101
118400
  const bl_count = new Array(MAX_BITS + 1);
118102
118401
  length2 = 0;
118103
118402
  for (code = 0; code < LENGTH_CODES - 1; code++) {
@@ -118107,18 +118406,18 @@ const tr_static_init = () => {
118107
118406
  }
118108
118407
  }
118109
118408
  _length_code[length2 - 1] = code;
118110
- dist = 0;
118409
+ dist2 = 0;
118111
118410
  for (code = 0; code < 16; code++) {
118112
- base_dist[code] = dist;
118411
+ base_dist[code] = dist2;
118113
118412
  for (n2 = 0; n2 < 1 << extra_dbits[code]; n2++) {
118114
- _dist_code[dist++] = code;
118413
+ _dist_code[dist2++] = code;
118115
118414
  }
118116
118415
  }
118117
- dist >>= 7;
118416
+ dist2 >>= 7;
118118
118417
  for (; code < D_CODES; code++) {
118119
- base_dist[code] = dist << 7;
118418
+ base_dist[code] = dist2 << 7;
118120
118419
  for (n2 = 0; n2 < 1 << extra_dbits[code] - 7; n2++) {
118121
- _dist_code[256 + dist++] = code;
118420
+ _dist_code[256 + dist2++] = code;
118122
118421
  }
118123
118422
  }
118124
118423
  for (bits = 0; bits <= MAX_BITS; bits++) {
@@ -118209,17 +118508,17 @@ const pqdownheap = (s2, tree, k) => {
118209
118508
  s2.heap[k] = v;
118210
118509
  };
118211
118510
  const compress_block = (s2, ltree, dtree) => {
118212
- let dist;
118511
+ let dist2;
118213
118512
  let lc;
118214
118513
  let lx = 0;
118215
118514
  let code;
118216
118515
  let extra;
118217
118516
  if (s2.last_lit !== 0) {
118218
118517
  do {
118219
- 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];
118220
118519
  lc = s2.pending_buf[s2.l_buf + lx];
118221
118520
  lx++;
118222
- if (dist === 0) {
118521
+ if (dist2 === 0) {
118223
118522
  send_code(s2, lc, ltree);
118224
118523
  } else {
118225
118524
  code = _length_code[lc];
@@ -118229,13 +118528,13 @@ const compress_block = (s2, ltree, dtree) => {
118229
118528
  lc -= base_length[code];
118230
118529
  send_bits(s2, lc, extra);
118231
118530
  }
118232
- dist--;
118233
- code = d_code(dist);
118531
+ dist2--;
118532
+ code = d_code(dist2);
118234
118533
  send_code(s2, code, dtree);
118235
118534
  extra = extra_dbits[code];
118236
118535
  if (extra !== 0) {
118237
- dist -= base_dist[code];
118238
- send_bits(s2, dist, extra);
118536
+ dist2 -= base_dist[code];
118537
+ send_bits(s2, dist2, extra);
118239
118538
  }
118240
118539
  }
118241
118540
  } while (lx < s2.last_lit);
@@ -118506,18 +118805,18 @@ const _tr_flush_block = (s2, buf, stored_len, last) => {
118506
118805
  bi_windup(s2);
118507
118806
  }
118508
118807
  };
118509
- const _tr_tally = (s2, dist, lc) => {
118510
- s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist >>> 8 & 255;
118511
- 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;
118512
118811
  s2.pending_buf[s2.l_buf + s2.last_lit] = lc & 255;
118513
118812
  s2.last_lit++;
118514
- if (dist === 0) {
118813
+ if (dist2 === 0) {
118515
118814
  s2.dyn_ltree[lc * 2]++;
118516
118815
  } else {
118517
118816
  s2.matches++;
118518
- dist--;
118817
+ dist2--;
118519
118818
  s2.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;
118520
- s2.dyn_dtree[d_code(dist) * 2]++;
118819
+ s2.dyn_dtree[d_code(dist2) * 2]++;
118521
118820
  }
118522
118821
  return s2.last_lit === s2.lit_bufsize - 1;
118523
118822
  };
@@ -120022,7 +120321,7 @@ var inffast = function inflate_fast(strm, start) {
120022
120321
  let here;
120023
120322
  let op;
120024
120323
  let len2;
120025
- let dist;
120324
+ let dist2;
120026
120325
  let from2;
120027
120326
  let from_source;
120028
120327
  let input, output;
@@ -120088,7 +120387,7 @@ var inffast = function inflate_fast(strm, start) {
120088
120387
  bits -= op;
120089
120388
  op = here >>> 16 & 255;
120090
120389
  if (op & 16) {
120091
- dist = here & 65535;
120390
+ dist2 = here & 65535;
120092
120391
  op &= 15;
120093
120392
  if (bits < op) {
120094
120393
  hold += input[_in++] << bits;
@@ -120098,8 +120397,8 @@ var inffast = function inflate_fast(strm, start) {
120098
120397
  bits += 8;
120099
120398
  }
120100
120399
  }
120101
- dist += hold & (1 << op) - 1;
120102
- if (dist > dmax) {
120400
+ dist2 += hold & (1 << op) - 1;
120401
+ if (dist2 > dmax) {
120103
120402
  strm.msg = "invalid distance too far back";
120104
120403
  state.mode = BAD;
120105
120404
  break top;
@@ -120107,8 +120406,8 @@ var inffast = function inflate_fast(strm, start) {
120107
120406
  hold >>>= op;
120108
120407
  bits -= op;
120109
120408
  op = _out - beg;
120110
- if (dist > op) {
120111
- op = dist - op;
120409
+ if (dist2 > op) {
120410
+ op = dist2 - op;
120112
120411
  if (op > whave) {
120113
120412
  if (state.sane) {
120114
120413
  strm.msg = "invalid distance too far back";
@@ -120125,7 +120424,7 @@ var inffast = function inflate_fast(strm, start) {
120125
120424
  do {
120126
120425
  output[_out++] = s_window[from2++];
120127
120426
  } while (--op);
120128
- from2 = _out - dist;
120427
+ from2 = _out - dist2;
120129
120428
  from_source = output;
120130
120429
  }
120131
120430
  } else if (wnext < op) {
@@ -120143,7 +120442,7 @@ var inffast = function inflate_fast(strm, start) {
120143
120442
  do {
120144
120443
  output[_out++] = s_window[from2++];
120145
120444
  } while (--op);
120146
- from2 = _out - dist;
120445
+ from2 = _out - dist2;
120147
120446
  from_source = output;
120148
120447
  }
120149
120448
  }
@@ -120154,7 +120453,7 @@ var inffast = function inflate_fast(strm, start) {
120154
120453
  do {
120155
120454
  output[_out++] = s_window[from2++];
120156
120455
  } while (--op);
120157
- from2 = _out - dist;
120456
+ from2 = _out - dist2;
120158
120457
  from_source = output;
120159
120458
  }
120160
120459
  }
@@ -120171,7 +120470,7 @@ var inffast = function inflate_fast(strm, start) {
120171
120470
  }
120172
120471
  }
120173
120472
  } else {
120174
- from2 = _out - dist;
120473
+ from2 = _out - dist2;
120175
120474
  do {
120176
120475
  output[_out++] = output[from2++];
120177
120476
  output[_out++] = output[from2++];
@@ -120729,7 +121028,7 @@ const fixedtables = (state) => {
120729
121028
  state.distbits = 5;
120730
121029
  };
120731
121030
  const updatewindow = (strm, src, end, copy2) => {
120732
- let dist;
121031
+ let dist2;
120733
121032
  const state = strm.state;
120734
121033
  if (state.window === null) {
120735
121034
  state.wsize = 1 << state.wbits;
@@ -120742,23 +121041,23 @@ const updatewindow = (strm, src, end, copy2) => {
120742
121041
  state.wnext = 0;
120743
121042
  state.whave = state.wsize;
120744
121043
  } else {
120745
- dist = state.wsize - state.wnext;
120746
- if (dist > copy2) {
120747
- dist = copy2;
121044
+ dist2 = state.wsize - state.wnext;
121045
+ if (dist2 > copy2) {
121046
+ dist2 = copy2;
120748
121047
  }
120749
- state.window.set(src.subarray(end - copy2, end - copy2 + dist), state.wnext);
120750
- copy2 -= dist;
121048
+ state.window.set(src.subarray(end - copy2, end - copy2 + dist2), state.wnext);
121049
+ copy2 -= dist2;
120751
121050
  if (copy2) {
120752
121051
  state.window.set(src.subarray(end - copy2, end), 0);
120753
121052
  state.wnext = copy2;
120754
121053
  state.whave = state.wsize;
120755
121054
  } else {
120756
- state.wnext += dist;
121055
+ state.wnext += dist2;
120757
121056
  if (state.wnext === state.wsize) {
120758
121057
  state.wnext = 0;
120759
121058
  }
120760
121059
  if (state.whave < state.wsize) {
120761
- state.whave += dist;
121060
+ state.whave += dist2;
120762
121061
  }
120763
121062
  }
120764
121063
  }
@@ -124637,14 +124936,14 @@ vec4 colormap(float intensity) {
124637
124936
  }
124638
124937
  };
124639
124938
  }
124640
- const defaultProps$4$1 = {
124939
+ const defaultProps$4$2 = {
124641
124940
  colormap: { type: "string", value: "viridis", compare: true },
124642
124941
  opacity: { type: "number", value: 1, compare: true },
124643
124942
  useTransparentColor: { type: "boolean", value: false, compare: true }
124644
124943
  };
124645
124944
  const AdditiveColormapExtension = class extends LayerExtension {
124646
124945
  getShaders() {
124647
- const name2 = this?.props?.colormap || defaultProps$4$1.colormap.value;
124946
+ const name2 = this?.props?.colormap || defaultProps$4$2.colormap.value;
124648
124947
  const apply_cmap = cmaps[name2];
124649
124948
  if (!apply_cmap) {
124650
124949
  throw Error(`No colormap named ${name2} found in registry`);
@@ -124663,8 +124962,8 @@ const AdditiveColormapExtension = class extends LayerExtension {
124663
124962
  }
124664
124963
  draw() {
124665
124964
  const {
124666
- useTransparentColor = defaultProps$4$1.useTransparentColor.value,
124667
- opacity = defaultProps$4$1.opacity.value
124965
+ useTransparentColor = defaultProps$4$2.useTransparentColor.value,
124966
+ opacity = defaultProps$4$2.opacity.value
124668
124967
  } = this.props;
124669
124968
  const uniforms = {
124670
124969
  opacity,
@@ -124674,7 +124973,7 @@ const AdditiveColormapExtension = class extends LayerExtension {
124674
124973
  }
124675
124974
  };
124676
124975
  AdditiveColormapExtension.extensionName = "AdditiveColormapExtension";
124677
- AdditiveColormapExtension.defaultProps = defaultProps$4$1;
124976
+ AdditiveColormapExtension.defaultProps = defaultProps$4$2;
124678
124977
  const fs$1$2 = `uniform vec3 transparentColor;
124679
124978
  uniform bool useTransparentColor;
124680
124979
  uniform float opacity;
@@ -125967,7 +126266,7 @@ const ImageLayer = class extends CompositeLayer {
125967
126266
  };
125968
126267
  ImageLayer.layerName = "ImageLayer";
125969
126268
  ImageLayer.defaultProps = defaultProps$5;
125970
- const defaultProps$4 = {
126269
+ const defaultProps$4$1 = {
125971
126270
  pickable: { type: "boolean", value: true, compare: true },
125972
126271
  onHover: { type: "function", value: null, compare: false },
125973
126272
  contrastLimits: { type: "array", value: [], compare: true },
@@ -126079,7 +126378,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
126079
126378
  }
126080
126379
  };
126081
126380
  MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
126082
- MultiscaleImageLayer.defaultProps = defaultProps$4;
126381
+ MultiscaleImageLayer.defaultProps = defaultProps$4$1;
126083
126382
  const defaultProps$3$1 = {
126084
126383
  pickable: { type: "boolean", value: true, compare: true },
126085
126384
  loader: {
@@ -127155,7 +127454,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
127155
127454
  }
127156
127455
  return newArr;
127157
127456
  }
127158
- const defaultProps$3 = {
127457
+ const defaultProps$4 = {
127159
127458
  hoveredCell: { type: "number", value: null, compare: true },
127160
127459
  // We do not want to deep-compare cellColorData,
127161
127460
  // as it is potentially a TypedArray with millions of elements.
@@ -127272,7 +127571,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
127272
127571
  }
127273
127572
  };
127274
127573
  BitmaskLayer$1.layerName = "BitmaskLayer";
127275
- BitmaskLayer$1.defaultProps = defaultProps$3;
127574
+ BitmaskLayer$1.defaultProps = defaultProps$4;
127276
127575
  const vs = `
127277
127576
  #define SHADER_NAME bitmask-layer-vertex-shader
127278
127577
 
@@ -127614,7 +127913,7 @@ function isEqualShallow(prevArr, nextArr) {
127614
127913
  }
127615
127914
  return prevArr === nextArr;
127616
127915
  }
127617
- const defaultProps$2 = {
127916
+ const defaultProps$3 = {
127618
127917
  channelStrokeWidths: { type: "array", value: null, compare: true },
127619
127918
  channelsFilled: { type: "array", value: null, compare: true },
127620
127919
  channelOpacities: { type: "array", value: null, compare: true },
@@ -127878,7 +128177,7 @@ class BitmaskLayer2 extends XRLayer {
127878
128177
  }
127879
128178
  }
127880
128179
  BitmaskLayer2.layerName = "BitmaskLayer";
127881
- BitmaskLayer2.defaultProps = defaultProps$2;
128180
+ BitmaskLayer2.defaultProps = defaultProps$3;
127882
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;
127883
128182
  function clone(configObject) {
127884
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 = {
@@ -130821,7 +131120,7 @@ function ringArea(coords) {
130821
131120
  return total * FACTOR;
130822
131121
  }
130823
131122
  const DEFAULT_THRESHOLD = 1;
130824
- const defaultProps$1 = {
131123
+ const defaultProps$2 = {
130825
131124
  // for text
130826
131125
  obsSetPath: { type: "object" },
130827
131126
  sampleSetPath: { type: "object" },
@@ -130916,9 +131215,9 @@ class ContourLayerWithText extends ContourLayer {
130916
131215
  const circlePoint = point(circleCoord);
130917
131216
  polygonVertices.forEach((polyCoord) => {
130918
131217
  const polyPoint = point(polyCoord);
130919
- const dist = distance$1(circlePoint, polyPoint);
130920
- if (dist < minDist) {
130921
- minDist = dist;
131218
+ const dist2 = distance$1(circlePoint, polyPoint);
131219
+ if (dist2 < minDist) {
131220
+ minDist = dist2;
130922
131221
  minCirclePoint = circleCoord;
130923
131222
  minCirclePointI = circlePointI;
130924
131223
  minPolygonPoint = polyCoord;
@@ -130995,7 +131294,1077 @@ class ContourLayerWithText extends ContourLayer {
130995
131294
  }
130996
131295
  }
130997
131296
  ContourLayerWithText.layerName = "ContourLayerWithText";
130998
- 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;
130999
132368
  function r$1(e3) {
131000
132369
  var t, f2, n2 = "";
131001
132370
  if ("string" == typeof e3 || "number" == typeof e3) n2 += e3;
@@ -145636,11 +147005,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145636
147005
  this.cellSetsLabelPrevZoom = null;
145637
147006
  this.cellSetsLayers = [];
145638
147007
  this.contourLayers = [];
147008
+ this.annotationLayer = null;
145639
147009
  this.onUpdateCellsData();
145640
147010
  this.onUpdateCellsLayer();
145641
147011
  this.onUpdateCellSetsLayers();
145642
147012
  this.onUpdateStratifiedData();
145643
147013
  this.onUpdateContourLayers();
147014
+ this.onUpdateAnnotationLayer();
145644
147015
  }
145645
147016
  // Want to support multiple types of contour layers
145646
147017
  // - One layer for all data points (no filtering)
@@ -145704,6 +147075,21 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145704
147075
  }));
145705
147076
  return layers;
145706
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
+ }
145707
147093
  createCellsLayer() {
145708
147094
  const {
145709
147095
  obsEmbeddingIndex: obsIndex,
@@ -145837,12 +147223,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145837
147223
  ], flipYTooltip, this.props.onSelectionBusy);
145838
147224
  }
145839
147225
  getLayers() {
145840
- const { cellsLayer, cellSetsLayers, contourLayers } = this;
147226
+ const { cellsLayer, cellSetsLayers, contourLayers, annotationLayer } = this;
145841
147227
  return [
145842
147228
  cellsLayer,
145843
147229
  ...contourLayers,
145844
147230
  ...cellSetsLayers,
145845
- this.createSelectionLayer()
147231
+ this.createSelectionLayer(),
147232
+ annotationLayer
145846
147233
  ];
145847
147234
  }
145848
147235
  /**
@@ -145879,6 +147266,14 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145879
147266
  this.cellsLayer = null;
145880
147267
  }
145881
147268
  }
147269
+ onUpdateAnnotationLayer() {
147270
+ const { annotationShapes } = this.props;
147271
+ if (annotationShapes) {
147272
+ this.annotationLayer = this.createAnnotationLayer();
147273
+ } else {
147274
+ this.annotationLayer = null;
147275
+ }
147276
+ }
145882
147277
  onUpdateStratifiedData() {
145883
147278
  const { stratifiedData } = this.props;
145884
147279
  if (stratifiedData) {
@@ -145994,6 +147389,16 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
145994
147389
  this.onUpdateCellSetsLayers(true);
145995
147390
  forceUpdate = true;
145996
147391
  }
147392
+ if ([
147393
+ "annotationShapes",
147394
+ "annotationOverlayVisible",
147395
+ "annotationSemanticZoom",
147396
+ "annotationTransitionDuration",
147397
+ "annotationEditable"
147398
+ ].some(shallowDiff)) {
147399
+ this.onUpdateAnnotationLayer();
147400
+ forceUpdate = true;
147401
+ }
145997
147402
  if (forceUpdate) {
145998
147403
  this.forceUpdate();
145999
147404
  }
@@ -148795,7 +150200,6 @@ const DEFAULT_FEATURE_AGGREGATION_STRATEGY = "first";
148795
150200
  function EmbeddingScatterplotSubscriber(props) {
148796
150201
  const {
148797
150202
  uuid,
148798
- coordinationScopes: coordinationScopesRaw,
148799
150203
  closeButtonVisible,
148800
150204
  downloadButtonVisible,
148801
150205
  removeGridComponent,
@@ -148811,9 +150215,15 @@ function EmbeddingScatterplotSubscriber(props) {
148811
150215
  circleScaleFactor = 0.8
148812
150216
  } = props;
148813
150217
  const loaders = useLoaders();
148814
- const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
150218
+ const [
150219
+ // eslint-disable-next-line no-unused-vars
150220
+ coordinationScopes,
150221
+ _coordinationScopesBy,
150222
+ coordinationValues
150223
+ ] = useViewMapping(uuid);
148815
150224
  const setComponentHover = useSetComponentHover();
148816
150225
  const setComponentViewInfo = useSetComponentViewInfo(uuid);
150226
+ useAnnotationFrameCoordination(uuid, coordinationScopes, coordinationValues);
148817
150227
  const [{
148818
150228
  dataset,
148819
150229
  obsType,
@@ -148850,7 +150260,13 @@ function EmbeddingScatterplotSubscriber(props) {
148850
150260
  embeddingContourPercentiles: contourPercentiles,
148851
150261
  contourColorEncoding,
148852
150262
  contourColor,
148853
- featureAggregationStrategy
150263
+ featureAggregationStrategy,
150264
+ annotationStory,
150265
+ annotationShapes,
150266
+ annotationOverlayVisible,
150267
+ annotationSemanticZoom,
150268
+ annotationTransitionDuration,
150269
+ annotationEditable
148854
150270
  }, {
148855
150271
  setEmbeddingZoom: setZoom,
148856
150272
  setEmbeddingTargetX: setTargetX,
@@ -148877,21 +150293,41 @@ function EmbeddingScatterplotSubscriber(props) {
148877
150293
  setEmbeddingContoursFilled,
148878
150294
  setEmbeddingContourPercentiles: setContourPercentiles,
148879
150295
  setContourColorEncoding,
148880
- setFeatureAggregationStrategy
148881
- }] = 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
+ );
148882
150304
  const {
148883
150305
  embeddingZoom: initialZoom,
148884
150306
  embeddingTargetX: initialTargetX,
148885
150307
  embeddingTargetY: initialTargetY
148886
150308
  } = useInitialCoordination(
148887
150309
  COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT],
148888
- coordinationScopes
150310
+ coordinationScopes,
150311
+ coordinationValues
148889
150312
  );
148890
150313
  const observationsLabel = observationsLabelOverride || obsType;
148891
150314
  const sampleSetSelection = sampleSetSelectionFromProps || sampleSetSelectionFromCoordination;
148892
150315
  const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY;
148893
150316
  const [width2, height2, deckRef] = useDeckCanvasSize();
148894
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
+ );
148895
150331
  const [
148896
150332
  // eslint-disable-next-line no-unused-vars
148897
150333
  obsLabelsTypes,
@@ -148998,11 +150434,13 @@ function EmbeddingScatterplotSubscriber(props) {
148998
150434
  matrixIndicesError,
148999
150435
  featureLabelsError,
149000
150436
  sampleSetsError,
149001
- sampleEdgesError
150437
+ sampleEdgesError,
150438
+ annotationStoryError
149002
150439
  ];
149003
150440
  const isReady = useReady([
149004
150441
  obsEmbeddingStatus,
149005
150442
  obsSetsStatus,
150443
+ annotationStoryStatus,
149006
150444
  featureSelectionStatus,
149007
150445
  featureLabelsStatus,
149008
150446
  expandedFeatureLabelsStatus,
@@ -149016,7 +150454,8 @@ function EmbeddingScatterplotSubscriber(props) {
149016
150454
  matrixIndicesUrls,
149017
150455
  featureLabelsUrls,
149018
150456
  sampleSetsUrl,
149019
- sampleEdgesUrl
150457
+ sampleEdgesUrl,
150458
+ annotationStoryUrls
149020
150459
  ]);
149021
150460
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
149022
150461
  const [isSelectionPending, setIsSelectionPending] = useState(false);
@@ -149392,7 +150831,12 @@ function EmbeddingScatterplotSubscriber(props) {
149392
150831
  embeddingPointsVisible,
149393
150832
  embeddingContoursVisible,
149394
150833
  circleInfo,
149395
- featureSelection: geneSelection
150834
+ featureSelection: geneSelection,
150835
+ annotationShapes,
150836
+ annotationOverlayVisible,
150837
+ annotationSemanticZoom,
150838
+ annotationTransitionDuration,
150839
+ annotationEditable
149396
150840
  }
149397
150841
  ),
149398
150842
  tooltipsVisible && width2 && height2 ? /* @__PURE__ */ React__default.createElement(