@vitessce/scatterplot-gating 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.
@@ -2824,11 +2824,11 @@ function requireConcaveman() {
2824
2824
  while (node2) {
2825
2825
  for (var i2 = 0; i2 < node2.children.length; i2++) {
2826
2826
  var child = node2.children[i2];
2827
- var dist = node2.leaf ? sqSegDist(child, b, c2) : sqSegBoxDist(b, c2, child);
2828
- if (dist > maxDist) continue;
2827
+ var dist2 = node2.leaf ? sqSegDist(child, b, c2) : sqSegBoxDist(b, c2, child);
2828
+ if (dist2 > maxDist) continue;
2829
2829
  queue.push({
2830
2830
  node: child,
2831
- dist
2831
+ dist: dist2
2832
2832
  });
2833
2833
  }
2834
2834
  while (queue.length && !queue.peek().node.children) {
@@ -6977,7 +6977,7 @@ const latestFileDefSchema = z.object({
6977
6977
  options: fileOptionsSchema.optional(),
6978
6978
  requestInit: requestInit.optional(),
6979
6979
  // New: file def can have coordinationValues.
6980
- coordinationValues: z.record(z.string()).optional()
6980
+ coordinationValues: z.record(z.any()).optional()
6981
6981
  });
6982
6982
  const datasetsSchema1_0_13 = z.array(z.object({
6983
6983
  uid: z.string(),
@@ -7008,7 +7008,8 @@ const configSchema1_0_16 = configSchema1_0_13.extend({
7008
7008
  h: z.number().int().optional(),
7009
7009
  // Updates coordinationScopes and coordinationScopesBy
7010
7010
  coordinationScopes: componentCoordinationScopes.optional(),
7011
- coordinationScopesBy: componentCoordinationScopesBy.optional()
7011
+ coordinationScopesBy: componentCoordinationScopesBy.optional(),
7012
+ coordinationValues: z.record(z.any()).optional()
7012
7013
  }))
7013
7014
  });
7014
7015
  const configSchema1_0_17 = configSchema1_0_16.extend({
@@ -9514,7 +9515,9 @@ const ViewType$1 = {
9514
9515
  DUAL_SCATTERPLOT: "dualScatterplot",
9515
9516
  TREEMAP: "treemap",
9516
9517
  SAMPLE_SET_PAIR_MANAGER: "sampleSetPairManager",
9517
- FEATURE_STATS_TABLE: "featureStatsTable"
9518
+ FEATURE_STATS_TABLE: "featureStatsTable",
9519
+ SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector",
9520
+ ANNOTATION_CONTROLLER: "annotationController"
9518
9521
  };
9519
9522
  const DataType$2 = {
9520
9523
  OBS_LABELS: "obsLabels",
@@ -9535,7 +9538,8 @@ const DataType$2 = {
9535
9538
  COMPARISON_METADATA: "comparisonMetadata",
9536
9539
  FEATURE_STATS: "featureStats",
9537
9540
  FEATURE_SET_STATS: "featureSetStats",
9538
- OBS_SET_STATS: "obsSetStats"
9541
+ OBS_SET_STATS: "obsSetStats",
9542
+ ANNOTATION_STORY: "annotationStory"
9539
9543
  };
9540
9544
  const FileType$1 = {
9541
9545
  // Joint file types
@@ -9557,6 +9561,7 @@ const FileType$1 = {
9557
9561
  OBS_SETS_CSV: "obsSets.csv",
9558
9562
  OBS_SETS_JSON: "obsSets.json",
9559
9563
  SAMPLE_SETS_CSV: "sampleSets.csv",
9564
+ ANNOTATION_STORY_JSON: "annotationStory.json",
9560
9565
  // OME-Zarr
9561
9566
  IMAGE_OME_ZARR: "image.ome-zarr",
9562
9567
  OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
@@ -9841,7 +9846,15 @@ const CoordinationType$1 = {
9841
9846
  FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
9842
9847
  FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
9843
9848
  // Treemap
9844
- HIERARCHY_LEVELS: "hierarchyLevels"
9849
+ HIERARCHY_LEVELS: "hierarchyLevels",
9850
+ // Annotation frames
9851
+ ANNOTATION_STORY: "annotationStory",
9852
+ ANNOTATION_FRAME_INDEX: "annotationFrameIndex",
9853
+ ANNOTATION_SHAPES: "annotationShapes",
9854
+ ANNOTATION_OVERLAY_VISIBLE: "annotationOverlayVisible",
9855
+ ANNOTATION_TRANSITION_DURATION: "annotationTransitionDuration",
9856
+ ANNOTATION_SEMANTIC_ZOOM: "annotationSemanticZoom",
9857
+ ANNOTATION_EDITABLE: "annotationEditable"
9845
9858
  };
9846
9859
  const ViewHelpMapping = {
9847
9860
  GATING: "The gating scatterplot displays expression data for two genes (along the X and Y axes). Users can select two genes, and the scatterplot is dynamically generated using observation-by-feature matrix data. Gating can then be performed by using the lasso or box select tools."
@@ -9860,6 +9873,7 @@ const ViewHelpMapping = {
9860
9873
  [FileType$1.OBS_SEGMENTATIONS_JSON]: DataType$2.OBS_SEGMENTATIONS,
9861
9874
  [FileType$1.OBS_SETS_CSV]: DataType$2.OBS_SETS,
9862
9875
  [FileType$1.OBS_SETS_JSON]: DataType$2.OBS_SETS,
9876
+ [FileType$1.ANNOTATION_STORY_JSON]: DataType$2.ANNOTATION_STORY,
9863
9877
  [FileType$1.IMAGE_OME_ZARR]: DataType$2.IMAGE,
9864
9878
  [FileType$1.OBS_SEGMENTATIONS_OME_ZARR]: DataType$2.OBS_SEGMENTATIONS,
9865
9879
  [FileType$1.OBS_FEATURE_MATRIX_ANNDATA_ZARR]: DataType$2.OBS_FEATURE_MATRIX,
@@ -9982,7 +9996,8 @@ const ViewHelpMapping = {
9982
9996
  [DataType$2.OBS_SET_STATS]: [
9983
9997
  CoordinationType$1.OBS_TYPE
9984
9998
  // TODO: should sampleType, obsSetSelection, and/or sampleSetSelection be used here?
9985
- ]
9999
+ ],
10000
+ [DataType$2.ANNOTATION_STORY]: []
9986
10001
  });
9987
10002
  ({
9988
10003
  // For AnnData:
@@ -10115,7 +10130,9 @@ const ViewHelpMapping = {
10115
10130
  CoordinationType$1.SPATIAL_TARGET_Z,
10116
10131
  CoordinationType$1.SPATIAL_AXIS_FIXED,
10117
10132
  CoordinationType$1.SPATIAL_ORBIT_AXIS,
10118
- CoordinationType$1.FEATURE_AGGREGATION_STRATEGY
10133
+ CoordinationType$1.FEATURE_AGGREGATION_STRATEGY,
10134
+ // Annotation shapes are specific to a view's coordinate system.
10135
+ CoordinationType$1.ANNOTATION_SHAPES
10119
10136
  ];
10120
10137
  const COMPONENT_COORDINATION_TYPES = {
10121
10138
  [ViewType$1.NEUROGLANCER]: [
@@ -10207,7 +10224,14 @@ const COMPONENT_COORDINATION_TYPES = {
10207
10224
  CoordinationType$1.EMBEDDING_CONTOURS_FILLED,
10208
10225
  CoordinationType$1.EMBEDDING_CONTOUR_PERCENTILES,
10209
10226
  CoordinationType$1.CONTOUR_COLOR_ENCODING,
10210
- CoordinationType$1.CONTOUR_COLOR
10227
+ CoordinationType$1.CONTOUR_COLOR,
10228
+ CoordinationType$1.ANNOTATION_STORY,
10229
+ CoordinationType$1.ANNOTATION_SHAPES,
10230
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10231
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10232
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10233
+ CoordinationType$1.ANNOTATION_EDITABLE,
10234
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10211
10235
  ],
10212
10236
  [ViewType$1.DUAL_SCATTERPLOT]: [
10213
10237
  CoordinationType$1.DATASET,
@@ -10323,7 +10347,14 @@ const COMPONENT_COORDINATION_TYPES = {
10323
10347
  CoordinationType$1.ADDITIONAL_OBS_SETS,
10324
10348
  CoordinationType$1.MOLECULE_HIGHLIGHT,
10325
10349
  CoordinationType$1.TOOLTIPS_VISIBLE,
10326
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10350
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
10351
+ CoordinationType$1.ANNOTATION_STORY,
10352
+ CoordinationType$1.ANNOTATION_SHAPES,
10353
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10354
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10355
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10356
+ CoordinationType$1.ANNOTATION_EDITABLE,
10357
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10327
10358
  ],
10328
10359
  [ViewType$1.SPATIAL_BETA]: [
10329
10360
  CoordinationType$1.META_COORDINATION_SCOPES,
@@ -10401,7 +10432,27 @@ const COMPONENT_COORDINATION_TYPES = {
10401
10432
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
10402
10433
  CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
10403
10434
  CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
10404
- CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10435
+ CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
10436
+ CoordinationType$1.ANNOTATION_STORY,
10437
+ CoordinationType$1.ANNOTATION_SHAPES,
10438
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10439
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10440
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10441
+ CoordinationType$1.ANNOTATION_EDITABLE,
10442
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10443
+ ],
10444
+ [ViewType$1.ANNOTATION_CONTROLLER]: [
10445
+ CoordinationType$1.DATASET,
10446
+ CoordinationType$1.ANNOTATION_STORY,
10447
+ CoordinationType$1.ANNOTATION_FRAME_INDEX,
10448
+ CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
10449
+ CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
10450
+ CoordinationType$1.ANNOTATION_EDITABLE,
10451
+ CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
10452
+ // Note: the annotation controller also needs to read the coordination state
10453
+ // of all other views/coordination types via the full config.
10454
+ // Note: we get/set the CoordinationType.ANNOTATION_SHAPES from the full config,
10455
+ // as this info is view-specific rather than global to the story.
10405
10456
  ],
10406
10457
  [ViewType$1.HEATMAP]: [
10407
10458
  CoordinationType$1.DATASET,
@@ -10711,6 +10762,11 @@ const COMPONENT_COORDINATION_TYPES = {
10711
10762
  CoordinationType$1.FEATURE_POINT_FOLD_CHANGE_THRESHOLD,
10712
10763
  CoordinationType$1.FEATURE_LABEL_FOLD_CHANGE_THRESHOLD
10713
10764
  ],
10765
+ [ViewType$1.SINGLE_OBS_SET_SELECTOR]: [
10766
+ CoordinationType$1.OBS_TYPE,
10767
+ CoordinationType$1.OBS_SET_COLOR,
10768
+ CoordinationType$1.OBS_SET_SELECTION
10769
+ ],
10714
10770
  [ViewType$1.OBS_SET_COMPOSITION_BAR_PLOT]: [
10715
10771
  CoordinationType$1.DATASET,
10716
10772
  CoordinationType$1.OBS_TYPE,
@@ -11414,6 +11470,124 @@ z.object({
11414
11470
  radius: z.number(),
11415
11471
  opacity: z.number()
11416
11472
  });
11473
+ const shapeBaseObj = z.object({
11474
+ uid: z.string(),
11475
+ text: z.string().optional(),
11476
+ strokeColor: z.array(z.number()).length(3).optional(),
11477
+ strokeWidth: z.number().optional(),
11478
+ // SVG-style dash pattern, e.g. "10 5" or "10 20 30 10". "none" or omitted = solid.
11479
+ strokeDashArray: z.string().optional(),
11480
+ visible: z.boolean().optional()
11481
+ // TODO: define unit modes for x and y axes
11482
+ // ("pixels" vs "normalized" vs "physical" etc.)
11483
+ // TODO: a coordinate system identifier (e.g., "DeckGL" for now,
11484
+ // but a coordinate system from OME-NGFF/SpatialData eventually?)
11485
+ });
11486
+ const rectangleShapeObj = shapeBaseObj.extend({
11487
+ type: z.literal("rectangle"),
11488
+ // OME-XML field names verbatim (upper-left origin)
11489
+ x: z.number(),
11490
+ y: z.number(),
11491
+ width: z.number(),
11492
+ height: z.number(),
11493
+ fillColor: z.array(z.number()).length(3).optional(),
11494
+ fillOpacity: z.number().optional()
11495
+ });
11496
+ const lineShapeObj = shapeBaseObj.extend({
11497
+ type: z.literal("line"),
11498
+ // OME-XML field names verbatim
11499
+ x1: z.number(),
11500
+ y1: z.number(),
11501
+ x2: z.number(),
11502
+ y2: z.number(),
11503
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
11504
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional(),
11505
+ textPosition: z.enum(["start", "middle", "end"]).optional(),
11506
+ textBufferPx: z.number().optional()
11507
+ });
11508
+ const ellipseShapeObj = shapeBaseObj.extend({
11509
+ type: z.literal("ellipse"),
11510
+ // OME-XML field names verbatim (centre point + radii)
11511
+ x1: z.number(),
11512
+ y1: z.number(),
11513
+ radiusX: z.number(),
11514
+ radiusY: z.number(),
11515
+ fillColor: z.array(z.number()).length(3).optional(),
11516
+ fillOpacity: z.number().optional()
11517
+ });
11518
+ const polygonShapeObj = shapeBaseObj.extend({
11519
+ type: z.literal("polygon"),
11520
+ // OME-XML: array of [x, y] coordinate pairs, closed automatically
11521
+ points: z.array(z.tuple([z.number(), z.number()])),
11522
+ fillColor: z.array(z.number()).length(3).optional(),
11523
+ fillOpacity: z.number().optional()
11524
+ });
11525
+ const polylineShapeObj = shapeBaseObj.extend({
11526
+ type: z.literal("polyline"),
11527
+ // OME-XML: array of [x, y] coordinate pairs, open (not closed)
11528
+ points: z.array(z.tuple([z.number(), z.number()])),
11529
+ markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
11530
+ markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional()
11531
+ });
11532
+ const annotationShapeObj = z.discriminatedUnion("type", [
11533
+ rectangleShapeObj,
11534
+ lineShapeObj,
11535
+ ellipseShapeObj,
11536
+ polygonShapeObj,
11537
+ polylineShapeObj
11538
+ ]);
11539
+ z.array(annotationShapeObj);
11540
+ const annotationFrameObj = z.object({
11541
+ uid: z.string(),
11542
+ title: z.string().optional(),
11543
+ description: z.string().optional(),
11544
+ descriptionType: z.enum(["text", "markdown"]).optional(),
11545
+ // A frame can define per-view: coordinationValues
11546
+ // (if the view's state should not be coordinated with other views)
11547
+ // or per-view coordinationScopes/coordinationScopesBy
11548
+ // (if at this frame, the view should be coordinated with other views).
11549
+ // We can also define a frame-level coordination space,
11550
+ // which will be merged with the global coordination space.
11551
+ // TODO: datasets
11552
+ // TODO: coordinationSpace
11553
+ layout: z.array(
11554
+ // Note: for now, we will infer view objects which have a uid
11555
+ // that is present in the global layout, and do NOT have x/y/w/h defined,
11556
+ // to mean that in this frame, the layout and set of views is unchanged
11557
+ // from the global layout.
11558
+ // This will allow each frame to omit the full list of views from the layout,
11559
+ // and only specify the views whose coordination state is changing in this frame.
11560
+ // If a frame includes a view with a uid that is not present
11561
+ // in the global layout, then that view will be added to the layout at this frame.
11562
+ // This frame should also define x/y/w/h for all views,
11563
+ // since it will otherwise be ambiguous how to layout the updated set of views
11564
+ // for this frame.
11565
+ z.object({
11566
+ // The view UID. If this view uid is not present in the global layout,
11567
+ // it will be added to the layout at this frame,
11568
+ // and will need to have its coordination values initialized to their defaults
11569
+ // for any that were not fully specified.
11570
+ uid: z.string(),
11571
+ coordinationValues: z.record(
11572
+ z.string(),
11573
+ // The coordination type name, e.g. "embeddingType"
11574
+ z.any()
11575
+ ).optional()
11576
+ // TODO: support coordinationScopes/coordinationScopesBy for per-view coordination
11577
+ // at this frame.
11578
+ // TODO: view x/y/w/h once we support view layout changes per-frame.
11579
+ })
11580
+ ).optional()
11581
+ });
11582
+ z.object({
11583
+ // TODO: schema version for the story schema?
11584
+ // Same as current Vitessce schema version?
11585
+ uid: z.string(),
11586
+ title: z.string().optional(),
11587
+ description: z.string().optional(),
11588
+ descriptionType: z.enum(["text", "markdown"]).optional(),
11589
+ frames: z.array(annotationFrameObj)
11590
+ });
11417
11591
  const SETS_DATATYPE_OBS = "obs";
11418
11592
  const HIERARCHICAL_SCHEMAS = {
11419
11593
  latestVersion: "0.1.3"
@@ -24234,8 +24408,8 @@ class Vector extends MathArray {
24234
24408
  distanceSquared(mathArray) {
24235
24409
  let length2 = 0;
24236
24410
  for (let i2 = 0; i2 < this.ELEMENTS; ++i2) {
24237
- const dist = this[i2] - mathArray[i2];
24238
- length2 += dist * dist;
24411
+ const dist2 = this[i2] - mathArray[i2];
24412
+ length2 += dist2 * dist2;
24239
24413
  }
24240
24414
  return checkNumber(length2);
24241
24415
  }
@@ -24556,6 +24730,12 @@ function multiply$3(out, a2, b) {
24556
24730
  out[2] = a2[2] * b[2];
24557
24731
  return out;
24558
24732
  }
24733
+ function distance$3(a2, b) {
24734
+ var x = b[0] - a2[0];
24735
+ var y = b[1] - a2[1];
24736
+ var z2 = b[2] - a2[2];
24737
+ return Math.hypot(x, y, z2);
24738
+ }
24559
24739
  function squaredLength$2(a2) {
24560
24740
  var x = a2[0];
24561
24741
  var y = a2[1];
@@ -24679,6 +24859,7 @@ function angle$2(a2, b) {
24679
24859
  }
24680
24860
  var sub = subtract;
24681
24861
  var mul = multiply$3;
24862
+ var dist = distance$3;
24682
24863
  var len = length$5;
24683
24864
  var sqrLen = squaredLength$2;
24684
24865
  (function() {
@@ -39149,7 +39330,7 @@ function noop$4() {
39149
39330
  const getCursor$1 = ({
39150
39331
  isDragging
39151
39332
  }) => isDragging ? "grabbing" : "grab";
39152
- const defaultProps$O = {
39333
+ const defaultProps$P = {
39153
39334
  id: "",
39154
39335
  width: "100%",
39155
39336
  height: "100%",
@@ -39280,7 +39461,7 @@ class Deck {
39280
39461
  this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
39281
39462
  });
39282
39463
  this.props = {
39283
- ...defaultProps$O,
39464
+ ...defaultProps$P,
39284
39465
  ...props
39285
39466
  };
39286
39467
  props = this.props;
@@ -39782,7 +39963,7 @@ class Deck {
39782
39963
  metrics.gpuMemory = memoryStats.get("GPU Memory").count;
39783
39964
  }
39784
39965
  }
39785
- _defineProperty(Deck, "defaultProps", defaultProps$O);
39966
+ _defineProperty(Deck, "defaultProps", defaultProps$P);
39786
39967
  _defineProperty(Deck, "VERSION", deckGlobal.VERSION);
39787
39968
  class ShaderAttribute {
39788
39969
  constructor(dataColumn, opts) {
@@ -42537,7 +42718,7 @@ const areViewportsEqual = memoize$3(({
42537
42718
  return oldViewport.equals(viewport);
42538
42719
  });
42539
42720
  let pickingColorCache = new Uint8ClampedArray(0);
42540
- const defaultProps$N = {
42721
+ const defaultProps$O = {
42541
42722
  data: {
42542
42723
  type: "data",
42543
42724
  value: EMPTY_ARRAY$1,
@@ -43412,7 +43593,7 @@ class Layer extends Component {
43412
43593
  this.setNeedsUpdate();
43413
43594
  }
43414
43595
  }
43415
- _defineProperty(Layer, "defaultProps", defaultProps$N);
43596
+ _defineProperty(Layer, "defaultProps", defaultProps$O);
43416
43597
  _defineProperty(Layer, "layerName", "Layer");
43417
43598
  const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
43418
43599
  class CompositeLayer extends Layer {
@@ -44448,6 +44629,124 @@ const esm$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
44448
44629
  project32,
44449
44630
  shadow
44450
44631
  }, Symbol.toStringTag, { value: "Module" }));
44632
+ const dashShaders = {
44633
+ inject: {
44634
+ "vs:#decl": "\nattribute vec2 instanceDashArrays;\nattribute float instanceDashOffsets;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n",
44635
+ "vs:#main-end": "\nvDashArray = instanceDashArrays;\nvDashOffset = instanceDashOffsets / width.x;\n",
44636
+ "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",
44637
+ "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"
44638
+ }
44639
+ };
44640
+ const offsetShaders = {
44641
+ inject: {
44642
+ "vs:#decl": "\nattribute float instanceOffsets;\n",
44643
+ "vs:DECKGL_FILTER_SIZE": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n size *= offsetWidth;\n",
44644
+ "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",
44645
+ "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"
44646
+ }
44647
+ };
44648
+ const defaultProps$N = {
44649
+ getDashArray: {
44650
+ type: "accessor",
44651
+ value: [0, 0]
44652
+ },
44653
+ getOffset: {
44654
+ type: "accessor",
44655
+ value: 0
44656
+ },
44657
+ dashJustified: false,
44658
+ dashGapPickable: false
44659
+ };
44660
+ class PathStyleExtension extends LayerExtension {
44661
+ constructor({
44662
+ dash = false,
44663
+ offset: offset2 = false,
44664
+ highPrecisionDash = false
44665
+ } = {}) {
44666
+ super({
44667
+ dash: dash || highPrecisionDash,
44668
+ offset: offset2,
44669
+ highPrecisionDash
44670
+ });
44671
+ }
44672
+ isEnabled(layer) {
44673
+ return "pathTesselator" in layer.state;
44674
+ }
44675
+ getShaders(extension) {
44676
+ if (!extension.isEnabled(this)) {
44677
+ return null;
44678
+ }
44679
+ let result = {};
44680
+ if (extension.opts.dash) {
44681
+ result = mergeShaders(result, dashShaders);
44682
+ }
44683
+ if (extension.opts.offset) {
44684
+ result = mergeShaders(result, offsetShaders);
44685
+ }
44686
+ return result;
44687
+ }
44688
+ initializeState(context, extension) {
44689
+ const attributeManager = this.getAttributeManager();
44690
+ if (!attributeManager || !extension.isEnabled(this)) {
44691
+ return;
44692
+ }
44693
+ if (extension.opts.dash) {
44694
+ attributeManager.addInstanced({
44695
+ instanceDashArrays: {
44696
+ size: 2,
44697
+ accessor: "getDashArray"
44698
+ }
44699
+ });
44700
+ }
44701
+ if (extension.opts.highPrecisionDash) {
44702
+ attributeManager.addInstanced({
44703
+ instanceDashOffsets: {
44704
+ size: 1,
44705
+ accessor: "getPath",
44706
+ transform: extension.getDashOffsets.bind(this)
44707
+ }
44708
+ });
44709
+ }
44710
+ if (extension.opts.offset) {
44711
+ attributeManager.addInstanced({
44712
+ instanceOffsets: {
44713
+ size: 1,
44714
+ accessor: "getOffset"
44715
+ }
44716
+ });
44717
+ }
44718
+ }
44719
+ updateState(params, extension) {
44720
+ if (!extension.isEnabled(this)) {
44721
+ return;
44722
+ }
44723
+ const uniforms = {};
44724
+ if (extension.opts.dash) {
44725
+ uniforms.dashAlignMode = this.props.dashJustified ? 1 : 0;
44726
+ uniforms.dashGapPickable = Boolean(this.props.dashGapPickable);
44727
+ }
44728
+ this.state.model.setUniforms(uniforms);
44729
+ }
44730
+ getDashOffsets(path) {
44731
+ const result = [0];
44732
+ const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
44733
+ const isNested2 = Array.isArray(path[0]);
44734
+ const geometrySize = isNested2 ? path.length : path.length / positionSize;
44735
+ let p;
44736
+ let prevP;
44737
+ for (let i2 = 0; i2 < geometrySize - 1; i2++) {
44738
+ p = isNested2 ? path[i2] : path.slice(i2 * positionSize, i2 * positionSize + positionSize);
44739
+ p = this.projectPosition(p);
44740
+ if (i2 > 0) {
44741
+ result[i2] = result[i2 - 1] + dist(prevP, p);
44742
+ }
44743
+ prevP = p;
44744
+ }
44745
+ return result;
44746
+ }
44747
+ }
44748
+ _defineProperty(PathStyleExtension, "defaultProps", defaultProps$N);
44749
+ _defineProperty(PathStyleExtension, "extensionName", "PathStyleExtension");
44451
44750
  const defaultProps$M = {
44452
44751
  clipBounds: [0, 0, 1, 1]
44453
44752
  };
@@ -100535,8 +100834,8 @@ function requireJs$b() {
100535
100834
  var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi12 / 2 + Math.PI / 4));
100536
100835
  var q = Math.abs(DeltaPsi) > 1e-11 ? DeltaPhi / DeltaPsi : Math.cos(phi12);
100537
100836
  var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda);
100538
- var dist = delta * R;
100539
- return dist;
100837
+ var dist2 = delta * R;
100838
+ return dist2;
100540
100839
  }
100541
100840
  js$a.default = rhumbDistance;
100542
100841
  return js$a;
@@ -100849,7 +101148,7 @@ function requireUtils$2() {
100849
101148
  var x;
100850
101149
  var y;
100851
101150
  var segmentIdx;
100852
- var dist;
101151
+ var dist2;
100853
101152
  if (coords.length > 1 && pointCoords.length) {
100854
101153
  var lineCoordinates;
100855
101154
  var pointCoordinate;
@@ -100866,17 +101165,17 @@ function requireUtils$2() {
100866
101165
  if (lineCoordinates[n2][0] !== lineCoordinates[n2 - 1][0]) {
100867
101166
  var slope = (lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1]) / (lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0]);
100868
101167
  var inverseSlope = lineCoordinates[n2][1] - slope * lineCoordinates[n2][0];
100869
- dist = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
100870
- } else dist = Math.abs(pointCoordinate[0] - lineCoordinates[n2][0]);
101168
+ dist2 = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
101169
+ } else dist2 = Math.abs(pointCoordinate[0] - lineCoordinates[n2][0]);
100871
101170
  var rl2 = Math.pow(lineCoordinates[n2][1] - lineCoordinates[n2 - 1][1], 2) + Math.pow(lineCoordinates[n2][0] - lineCoordinates[n2 - 1][0], 2);
100872
101171
  var ln2 = Math.pow(lineCoordinates[n2][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2][0] - pointCoordinate[0], 2);
100873
101172
  var lnm12 = Math.pow(lineCoordinates[n2 - 1][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n2 - 1][0] - pointCoordinate[0], 2);
100874
- var dist2 = Math.pow(dist, 2);
100875
- var calcrl2 = ln2 - dist2 + lnm12 - dist2;
101173
+ var dist22 = Math.pow(dist2, 2);
101174
+ var calcrl2 = ln2 - dist22 + lnm12 - dist22;
100876
101175
  if (calcrl2 > rl2) {
100877
- dist = Math.sqrt(Math.min(ln2, lnm12));
101176
+ dist2 = Math.sqrt(Math.min(ln2, lnm12));
100878
101177
  }
100879
- if (minDist === null || minDist === void 0 || minDist > dist) {
101178
+ if (minDist === null || minDist === void 0 || minDist > dist2) {
100880
101179
  if (calcrl2 > rl2) {
100881
101180
  if (lnm12 < ln2) {
100882
101181
  to = 0;
@@ -100886,10 +101185,10 @@ function requireUtils$2() {
100886
101185
  to = 1;
100887
101186
  }
100888
101187
  } else {
100889
- to = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
100890
- from2 = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
101188
+ to = Math.sqrt(lnm12 - dist22) / Math.sqrt(rl2);
101189
+ from2 = Math.sqrt(ln2 - dist22) / Math.sqrt(rl2);
100891
101190
  }
100892
- minDist = dist;
101191
+ minDist = dist2;
100893
101192
  segmentIdx = n2;
100894
101193
  }
100895
101194
  }
@@ -117220,22 +117519,22 @@ function addDecoder(cases, importFn) {
117220
117519
  }
117221
117520
  cases.forEach((c2) => registry$1.set(c2, importFn));
117222
117521
  }
117223
- addDecoder([void 0, 1], () => import("./raw-BfH2zeya.js").then((m2) => m2.default));
117224
- addDecoder(5, () => import("./lzw-DEJye0-W.js").then((m2) => m2.default));
117522
+ addDecoder([void 0, 1], () => import("./raw-AvZwnBim.js").then((m2) => m2.default));
117523
+ addDecoder(5, () => import("./lzw-BpQ8dLUH.js").then((m2) => m2.default));
117225
117524
  addDecoder(6, () => {
117226
117525
  throw new Error("old style JPEG compression is not supported.");
117227
117526
  });
117228
- addDecoder(7, () => import("./jpeg-B9_avAIf.js").then((m2) => m2.default));
117229
- addDecoder([8, 32946], () => import("./deflate-9OJa3Ewi.js").then((m2) => m2.default));
117230
- addDecoder(32773, () => import("./packbits-CvrWa3x_.js").then((m2) => m2.default));
117527
+ addDecoder(7, () => import("./jpeg-DdAMSG2w.js").then((m2) => m2.default));
117528
+ addDecoder([8, 32946], () => import("./deflate-DUmHvVPz.js").then((m2) => m2.default));
117529
+ addDecoder(32773, () => import("./packbits-Cb8CXJgl.js").then((m2) => m2.default));
117231
117530
  addDecoder(
117232
117531
  34887,
117233
- () => import("./lerc-BjrLoND6.js").then(async (m2) => {
117532
+ () => import("./lerc-D4PnY1mB.js").then(async (m2) => {
117234
117533
  await m2.zstd.init();
117235
117534
  return m2;
117236
117535
  }).then((m2) => m2.default)
117237
117536
  );
117238
- addDecoder(50001, () => import("./webimage-CaSVfEZI.js").then((m2) => m2.default));
117537
+ addDecoder(50001, () => import("./webimage-Di-764UM.js").then((m2) => m2.default));
117239
117538
  function decodeRowAcc(row, stride) {
117240
117539
  let length2 = row.length - stride;
117241
117540
  let offset2 = 0;
@@ -117650,8 +117949,8 @@ function TreeDesc(dyn_tree, stat_desc) {
117650
117949
  this.max_code = 0;
117651
117950
  this.stat_desc = stat_desc;
117652
117951
  }
117653
- const d_code = (dist) => {
117654
- return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
117952
+ const d_code = (dist2) => {
117953
+ return dist2 < 256 ? _dist_code[dist2] : _dist_code[256 + (dist2 >>> 7)];
117655
117954
  };
117656
117955
  const put_short = (s2, w2) => {
117657
117956
  s2.pending_buf[s2.pending++] = w2 & 255;
@@ -117785,7 +118084,7 @@ const tr_static_init = () => {
117785
118084
  let bits;
117786
118085
  let length2;
117787
118086
  let code;
117788
- let dist;
118087
+ let dist2;
117789
118088
  const bl_count = new Array(MAX_BITS + 1);
117790
118089
  length2 = 0;
117791
118090
  for (code = 0; code < LENGTH_CODES - 1; code++) {
@@ -117795,18 +118094,18 @@ const tr_static_init = () => {
117795
118094
  }
117796
118095
  }
117797
118096
  _length_code[length2 - 1] = code;
117798
- dist = 0;
118097
+ dist2 = 0;
117799
118098
  for (code = 0; code < 16; code++) {
117800
- base_dist[code] = dist;
118099
+ base_dist[code] = dist2;
117801
118100
  for (n2 = 0; n2 < 1 << extra_dbits[code]; n2++) {
117802
- _dist_code[dist++] = code;
118101
+ _dist_code[dist2++] = code;
117803
118102
  }
117804
118103
  }
117805
- dist >>= 7;
118104
+ dist2 >>= 7;
117806
118105
  for (; code < D_CODES; code++) {
117807
- base_dist[code] = dist << 7;
118106
+ base_dist[code] = dist2 << 7;
117808
118107
  for (n2 = 0; n2 < 1 << extra_dbits[code] - 7; n2++) {
117809
- _dist_code[256 + dist++] = code;
118108
+ _dist_code[256 + dist2++] = code;
117810
118109
  }
117811
118110
  }
117812
118111
  for (bits = 0; bits <= MAX_BITS; bits++) {
@@ -117897,17 +118196,17 @@ const pqdownheap = (s2, tree, k) => {
117897
118196
  s2.heap[k] = v;
117898
118197
  };
117899
118198
  const compress_block = (s2, ltree, dtree) => {
117900
- let dist;
118199
+ let dist2;
117901
118200
  let lc;
117902
118201
  let lx = 0;
117903
118202
  let code;
117904
118203
  let extra;
117905
118204
  if (s2.last_lit !== 0) {
117906
118205
  do {
117907
- dist = s2.pending_buf[s2.d_buf + lx * 2] << 8 | s2.pending_buf[s2.d_buf + lx * 2 + 1];
118206
+ dist2 = s2.pending_buf[s2.d_buf + lx * 2] << 8 | s2.pending_buf[s2.d_buf + lx * 2 + 1];
117908
118207
  lc = s2.pending_buf[s2.l_buf + lx];
117909
118208
  lx++;
117910
- if (dist === 0) {
118209
+ if (dist2 === 0) {
117911
118210
  send_code(s2, lc, ltree);
117912
118211
  } else {
117913
118212
  code = _length_code[lc];
@@ -117917,13 +118216,13 @@ const compress_block = (s2, ltree, dtree) => {
117917
118216
  lc -= base_length[code];
117918
118217
  send_bits(s2, lc, extra);
117919
118218
  }
117920
- dist--;
117921
- code = d_code(dist);
118219
+ dist2--;
118220
+ code = d_code(dist2);
117922
118221
  send_code(s2, code, dtree);
117923
118222
  extra = extra_dbits[code];
117924
118223
  if (extra !== 0) {
117925
- dist -= base_dist[code];
117926
- send_bits(s2, dist, extra);
118224
+ dist2 -= base_dist[code];
118225
+ send_bits(s2, dist2, extra);
117927
118226
  }
117928
118227
  }
117929
118228
  } while (lx < s2.last_lit);
@@ -118194,18 +118493,18 @@ const _tr_flush_block = (s2, buf, stored_len, last) => {
118194
118493
  bi_windup(s2);
118195
118494
  }
118196
118495
  };
118197
- const _tr_tally = (s2, dist, lc) => {
118198
- s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist >>> 8 & 255;
118199
- s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] = dist & 255;
118496
+ const _tr_tally = (s2, dist2, lc) => {
118497
+ s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist2 >>> 8 & 255;
118498
+ s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] = dist2 & 255;
118200
118499
  s2.pending_buf[s2.l_buf + s2.last_lit] = lc & 255;
118201
118500
  s2.last_lit++;
118202
- if (dist === 0) {
118501
+ if (dist2 === 0) {
118203
118502
  s2.dyn_ltree[lc * 2]++;
118204
118503
  } else {
118205
118504
  s2.matches++;
118206
- dist--;
118505
+ dist2--;
118207
118506
  s2.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;
118208
- s2.dyn_dtree[d_code(dist) * 2]++;
118507
+ s2.dyn_dtree[d_code(dist2) * 2]++;
118209
118508
  }
118210
118509
  return s2.last_lit === s2.lit_bufsize - 1;
118211
118510
  };
@@ -119710,7 +120009,7 @@ var inffast = function inflate_fast(strm, start) {
119710
120009
  let here;
119711
120010
  let op;
119712
120011
  let len2;
119713
- let dist;
120012
+ let dist2;
119714
120013
  let from2;
119715
120014
  let from_source;
119716
120015
  let input, output;
@@ -119776,7 +120075,7 @@ var inffast = function inflate_fast(strm, start) {
119776
120075
  bits -= op;
119777
120076
  op = here >>> 16 & 255;
119778
120077
  if (op & 16) {
119779
- dist = here & 65535;
120078
+ dist2 = here & 65535;
119780
120079
  op &= 15;
119781
120080
  if (bits < op) {
119782
120081
  hold += input[_in++] << bits;
@@ -119786,8 +120085,8 @@ var inffast = function inflate_fast(strm, start) {
119786
120085
  bits += 8;
119787
120086
  }
119788
120087
  }
119789
- dist += hold & (1 << op) - 1;
119790
- if (dist > dmax) {
120088
+ dist2 += hold & (1 << op) - 1;
120089
+ if (dist2 > dmax) {
119791
120090
  strm.msg = "invalid distance too far back";
119792
120091
  state.mode = BAD;
119793
120092
  break top;
@@ -119795,8 +120094,8 @@ var inffast = function inflate_fast(strm, start) {
119795
120094
  hold >>>= op;
119796
120095
  bits -= op;
119797
120096
  op = _out - beg;
119798
- if (dist > op) {
119799
- op = dist - op;
120097
+ if (dist2 > op) {
120098
+ op = dist2 - op;
119800
120099
  if (op > whave) {
119801
120100
  if (state.sane) {
119802
120101
  strm.msg = "invalid distance too far back";
@@ -119813,7 +120112,7 @@ var inffast = function inflate_fast(strm, start) {
119813
120112
  do {
119814
120113
  output[_out++] = s_window[from2++];
119815
120114
  } while (--op);
119816
- from2 = _out - dist;
120115
+ from2 = _out - dist2;
119817
120116
  from_source = output;
119818
120117
  }
119819
120118
  } else if (wnext < op) {
@@ -119831,7 +120130,7 @@ var inffast = function inflate_fast(strm, start) {
119831
120130
  do {
119832
120131
  output[_out++] = s_window[from2++];
119833
120132
  } while (--op);
119834
- from2 = _out - dist;
120133
+ from2 = _out - dist2;
119835
120134
  from_source = output;
119836
120135
  }
119837
120136
  }
@@ -119842,7 +120141,7 @@ var inffast = function inflate_fast(strm, start) {
119842
120141
  do {
119843
120142
  output[_out++] = s_window[from2++];
119844
120143
  } while (--op);
119845
- from2 = _out - dist;
120144
+ from2 = _out - dist2;
119846
120145
  from_source = output;
119847
120146
  }
119848
120147
  }
@@ -119859,7 +120158,7 @@ var inffast = function inflate_fast(strm, start) {
119859
120158
  }
119860
120159
  }
119861
120160
  } else {
119862
- from2 = _out - dist;
120161
+ from2 = _out - dist2;
119863
120162
  do {
119864
120163
  output[_out++] = output[from2++];
119865
120164
  output[_out++] = output[from2++];
@@ -120417,7 +120716,7 @@ const fixedtables = (state) => {
120417
120716
  state.distbits = 5;
120418
120717
  };
120419
120718
  const updatewindow = (strm, src, end, copy2) => {
120420
- let dist;
120719
+ let dist2;
120421
120720
  const state = strm.state;
120422
120721
  if (state.window === null) {
120423
120722
  state.wsize = 1 << state.wbits;
@@ -120430,23 +120729,23 @@ const updatewindow = (strm, src, end, copy2) => {
120430
120729
  state.wnext = 0;
120431
120730
  state.whave = state.wsize;
120432
120731
  } else {
120433
- dist = state.wsize - state.wnext;
120434
- if (dist > copy2) {
120435
- dist = copy2;
120732
+ dist2 = state.wsize - state.wnext;
120733
+ if (dist2 > copy2) {
120734
+ dist2 = copy2;
120436
120735
  }
120437
- state.window.set(src.subarray(end - copy2, end - copy2 + dist), state.wnext);
120438
- copy2 -= dist;
120736
+ state.window.set(src.subarray(end - copy2, end - copy2 + dist2), state.wnext);
120737
+ copy2 -= dist2;
120439
120738
  if (copy2) {
120440
120739
  state.window.set(src.subarray(end - copy2, end), 0);
120441
120740
  state.wnext = copy2;
120442
120741
  state.whave = state.wsize;
120443
120742
  } else {
120444
- state.wnext += dist;
120743
+ state.wnext += dist2;
120445
120744
  if (state.wnext === state.wsize) {
120446
120745
  state.wnext = 0;
120447
120746
  }
120448
120747
  if (state.whave < state.wsize) {
120449
- state.whave += dist;
120748
+ state.whave += dist2;
120450
120749
  }
120451
120750
  }
120452
120751
  }
@@ -124325,14 +124624,14 @@ vec4 colormap(float intensity) {
124325
124624
  }
124326
124625
  };
124327
124626
  }
124328
- const defaultProps$4$1 = {
124627
+ const defaultProps$4$2 = {
124329
124628
  colormap: { type: "string", value: "viridis", compare: true },
124330
124629
  opacity: { type: "number", value: 1, compare: true },
124331
124630
  useTransparentColor: { type: "boolean", value: false, compare: true }
124332
124631
  };
124333
124632
  const AdditiveColormapExtension = class extends LayerExtension {
124334
124633
  getShaders() {
124335
- const name2 = this?.props?.colormap || defaultProps$4$1.colormap.value;
124634
+ const name2 = this?.props?.colormap || defaultProps$4$2.colormap.value;
124336
124635
  const apply_cmap = cmaps[name2];
124337
124636
  if (!apply_cmap) {
124338
124637
  throw Error(`No colormap named ${name2} found in registry`);
@@ -124351,8 +124650,8 @@ const AdditiveColormapExtension = class extends LayerExtension {
124351
124650
  }
124352
124651
  draw() {
124353
124652
  const {
124354
- useTransparentColor = defaultProps$4$1.useTransparentColor.value,
124355
- opacity = defaultProps$4$1.opacity.value
124653
+ useTransparentColor = defaultProps$4$2.useTransparentColor.value,
124654
+ opacity = defaultProps$4$2.opacity.value
124356
124655
  } = this.props;
124357
124656
  const uniforms = {
124358
124657
  opacity,
@@ -124362,7 +124661,7 @@ const AdditiveColormapExtension = class extends LayerExtension {
124362
124661
  }
124363
124662
  };
124364
124663
  AdditiveColormapExtension.extensionName = "AdditiveColormapExtension";
124365
- AdditiveColormapExtension.defaultProps = defaultProps$4$1;
124664
+ AdditiveColormapExtension.defaultProps = defaultProps$4$2;
124366
124665
  const fs$1$2 = `uniform vec3 transparentColor;
124367
124666
  uniform bool useTransparentColor;
124368
124667
  uniform float opacity;
@@ -125655,7 +125954,7 @@ const ImageLayer = class extends CompositeLayer {
125655
125954
  };
125656
125955
  ImageLayer.layerName = "ImageLayer";
125657
125956
  ImageLayer.defaultProps = defaultProps$5;
125658
- const defaultProps$4 = {
125957
+ const defaultProps$4$1 = {
125659
125958
  pickable: { type: "boolean", value: true, compare: true },
125660
125959
  onHover: { type: "function", value: null, compare: false },
125661
125960
  contrastLimits: { type: "array", value: [], compare: true },
@@ -125767,7 +126066,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
125767
126066
  }
125768
126067
  };
125769
126068
  MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
125770
- MultiscaleImageLayer.defaultProps = defaultProps$4;
126069
+ MultiscaleImageLayer.defaultProps = defaultProps$4$1;
125771
126070
  const defaultProps$3$1 = {
125772
126071
  pickable: { type: "boolean", value: true, compare: true },
125773
126072
  loader: {
@@ -126843,7 +127142,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
126843
127142
  }
126844
127143
  return newArr;
126845
127144
  }
126846
- const defaultProps$3 = {
127145
+ const defaultProps$4 = {
126847
127146
  hoveredCell: { type: "number", value: null, compare: true },
126848
127147
  // We do not want to deep-compare cellColorData,
126849
127148
  // as it is potentially a TypedArray with millions of elements.
@@ -126960,7 +127259,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
126960
127259
  }
126961
127260
  };
126962
127261
  BitmaskLayer$1.layerName = "BitmaskLayer";
126963
- BitmaskLayer$1.defaultProps = defaultProps$3;
127262
+ BitmaskLayer$1.defaultProps = defaultProps$4;
126964
127263
  const vs = `
126965
127264
  #define SHADER_NAME bitmask-layer-vertex-shader
126966
127265
 
@@ -127302,7 +127601,7 @@ function isEqualShallow(prevArr, nextArr) {
127302
127601
  }
127303
127602
  return prevArr === nextArr;
127304
127603
  }
127305
- const defaultProps$2 = {
127604
+ const defaultProps$3 = {
127306
127605
  channelStrokeWidths: { type: "array", value: null, compare: true },
127307
127606
  channelsFilled: { type: "array", value: null, compare: true },
127308
127607
  channelOpacities: { type: "array", value: null, compare: true },
@@ -127566,7 +127865,7 @@ class BitmaskLayer2 extends XRLayer {
127566
127865
  }
127567
127866
  }
127568
127867
  BitmaskLayer2.layerName = "BitmaskLayer";
127569
- BitmaskLayer2.defaultProps = defaultProps$2;
127868
+ BitmaskLayer2.defaultProps = defaultProps$3;
127570
127869
  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;
127571
127870
  function clone(configObject) {
127572
127871
  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 = {
@@ -130509,7 +130808,7 @@ function ringArea(coords) {
130509
130808
  return total * FACTOR;
130510
130809
  }
130511
130810
  const DEFAULT_THRESHOLD = 1;
130512
- const defaultProps$1 = {
130811
+ const defaultProps$2 = {
130513
130812
  // for text
130514
130813
  obsSetPath: { type: "object" },
130515
130814
  sampleSetPath: { type: "object" },
@@ -130604,9 +130903,9 @@ class ContourLayerWithText extends ContourLayer {
130604
130903
  const circlePoint = point(circleCoord);
130605
130904
  polygonVertices.forEach((polyCoord) => {
130606
130905
  const polyPoint = point(polyCoord);
130607
- const dist = distance$1(circlePoint, polyPoint);
130608
- if (dist < minDist) {
130609
- minDist = dist;
130906
+ const dist2 = distance$1(circlePoint, polyPoint);
130907
+ if (dist2 < minDist) {
130908
+ minDist = dist2;
130610
130909
  minCirclePoint = circleCoord;
130611
130910
  minCirclePointI = circlePointI;
130612
130911
  minPolygonPoint = polyCoord;
@@ -130683,7 +130982,1077 @@ class ContourLayerWithText extends ContourLayer {
130683
130982
  }
130684
130983
  }
130685
130984
  ContourLayerWithText.layerName = "ContourLayerWithText";
130686
- ContourLayerWithText.defaultProps = defaultProps$1;
130985
+ ContourLayerWithText.defaultProps = defaultProps$2;
130986
+ const ARROW_SCREEN_PX = 14;
130987
+ const LABEL_FONT_FAMILY$1 = '"Roboto", "Helvetica", "Arial", sans-serif';
130988
+ const LABEL_FONT_WEIGHT = "bold";
130989
+ const LABEL_FONT_SIZE = 14;
130990
+ const RATIO_CLUSTER = 0.1;
130991
+ const RATIO_DOT = 0.3;
130992
+ const RATIO_GEO_FADE = 0.55;
130993
+ const RATIO_TIPS = 0.7;
130994
+ const RATIO_LABEL = 0.55;
130995
+ const RATIO_LABEL_FULL = 0.75;
130996
+ function textBgColor(strokeColor) {
130997
+ const [r2, g2, b] = strokeColor;
130998
+ const lum = (0.299 * r2 + 0.587 * g2 + 0.114 * b) / 255;
130999
+ return lum > 0.45 ? [20, 20, 20, 210] : [245, 245, 245, 210];
131000
+ }
131001
+ function parseDashArray(strokeDashArray) {
131002
+ if (!strokeDashArray || strokeDashArray === "none")
131003
+ return null;
131004
+ const nums = strokeDashArray.trim().split(/\s+/).map(Number).filter((n2) => !Number.isNaN(n2) && n2 >= 0);
131005
+ return nums.length >= 2 ? [nums[0], nums[1]] : null;
131006
+ }
131007
+ function computeEllipsePolygon(cx, cy, rx, ry, numSegments = 64) {
131008
+ const pts = [];
131009
+ for (let i2 = 0; i2 < numSegments; i2++) {
131010
+ const angle2 = 2 * Math.PI * i2 / numSegments;
131011
+ pts.push([cx + rx * Math.cos(angle2), cy + ry * Math.sin(angle2)]);
131012
+ }
131013
+ return pts;
131014
+ }
131015
+ function createPreviewLayer(inProgress, hoverCoord, strokeColor = [255, 255, 0]) {
131016
+ if (!inProgress || inProgress.vertices.length === 0)
131017
+ return null;
131018
+ const { type, vertices } = inProgress;
131019
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
131020
+ const previewColor = [...strokeColor, 160];
131021
+ const cursor2 = hoverCoord ?? vertices[vertices.length - 1];
131022
+ if (type === "rectangle" && vertices.length === 1) {
131023
+ const [ax, ay] = vertices[0];
131024
+ const [bx, by] = cursor2;
131025
+ const path = [[ax, ay], [bx, ay], [bx, by], [ax, by], [ax, ay]];
131026
+ return new PathLayer({
131027
+ ...base,
131028
+ id: "annotation-preview-rectangle",
131029
+ data: [{ path }],
131030
+ getPath: (d) => d.path,
131031
+ getColor: previewColor,
131032
+ getWidth: 1,
131033
+ widthUnits: "pixels",
131034
+ extensions: [new PathStyleExtension({ dash: true })],
131035
+ getDashArray: [8, 4]
131036
+ });
131037
+ }
131038
+ if (type === "line" && vertices.length === 1) {
131039
+ const path = [vertices[0], cursor2];
131040
+ return new PathLayer({
131041
+ ...base,
131042
+ id: "annotation-preview-line",
131043
+ data: [{ path }],
131044
+ getPath: (d) => d.path,
131045
+ getColor: previewColor,
131046
+ getWidth: 1,
131047
+ widthUnits: "pixels",
131048
+ extensions: [new PathStyleExtension({ dash: true })],
131049
+ getDashArray: [8, 4]
131050
+ });
131051
+ }
131052
+ if (type === "ellipse" && vertices.length === 1) {
131053
+ const [cx, cy] = vertices[0];
131054
+ const [ex, ey] = cursor2;
131055
+ const rx = Math.abs(ex - cx);
131056
+ const ry = Math.abs(ey - cy);
131057
+ if (rx < 1 && ry < 1)
131058
+ return null;
131059
+ const pts = computeEllipsePolygon(cx, cy, Math.max(rx, 1), Math.max(ry, 1));
131060
+ const path = [...pts, pts[0]];
131061
+ return new PathLayer({
131062
+ ...base,
131063
+ id: "annotation-preview-ellipse",
131064
+ data: [{ path }],
131065
+ getPath: (d) => d.path,
131066
+ getColor: previewColor,
131067
+ getWidth: 1,
131068
+ widthUnits: "pixels",
131069
+ extensions: [new PathStyleExtension({ dash: true })],
131070
+ getDashArray: [8, 4]
131071
+ });
131072
+ }
131073
+ if ((type === "polygon" || type === "polyline") && vertices.length >= 1) {
131074
+ const path = [...vertices, cursor2];
131075
+ if (type === "polygon" && vertices.length >= 2)
131076
+ path.push(vertices[0]);
131077
+ return new PathLayer({
131078
+ ...base,
131079
+ id: `annotation-preview-${type}`,
131080
+ data: [{ path }],
131081
+ getPath: (d) => d.path,
131082
+ getColor: previewColor,
131083
+ getWidth: 1,
131084
+ widthUnits: "pixels",
131085
+ jointRounded: true,
131086
+ capRounded: true,
131087
+ extensions: [new PathStyleExtension({ dash: true })],
131088
+ getDashArray: [8, 4]
131089
+ });
131090
+ }
131091
+ return null;
131092
+ }
131093
+ function computeTickCap(tipX, tipY, dirX, dirY, dataSize) {
131094
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
131095
+ if (len2 === 0)
131096
+ return null;
131097
+ const ux = dirX / len2;
131098
+ const uy = dirY / len2;
131099
+ const px = -uy;
131100
+ const py = ux;
131101
+ const half = dataSize * 0.55;
131102
+ return [
131103
+ [tipX + px * half, tipY + py * half],
131104
+ [tipX - px * half, tipY - py * half]
131105
+ ];
131106
+ }
131107
+ function computeArrowhead(tipX, tipY, dirX, dirY, dataSize) {
131108
+ const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
131109
+ if (len2 === 0)
131110
+ return null;
131111
+ const ux = dirX / len2;
131112
+ const uy = dirY / len2;
131113
+ const px = -uy;
131114
+ const py = ux;
131115
+ const halfBase = dataSize * 0.4;
131116
+ const bx = tipX - ux * dataSize;
131117
+ const by = tipY - uy * dataSize;
131118
+ return [
131119
+ [tipX, tipY],
131120
+ [bx + px * halfBase, by + py * halfBase],
131121
+ [bx - px * halfBase, by - py * halfBase]
131122
+ ];
131123
+ }
131124
+ function fmtCommas(n2) {
131125
+ return Math.round(n2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
131126
+ }
131127
+ function getMeasurementLabel(shape2, physicalPixelSize, viewType = ViewType$1.SPATIAL) {
131128
+ const pps = physicalPixelSize;
131129
+ const px = pps?.x ?? 1;
131130
+ const py = pps?.y ?? 1;
131131
+ const unit = pps ? pps.unit ?? "" : null;
131132
+ const hasPhys = !!pps;
131133
+ const isEmbedding = viewType === ViewType$1.SCATTERPLOT;
131134
+ const fmtDist = (d) => {
131135
+ if (hasPhys)
131136
+ return `${d.toFixed(2)} ${unit}`;
131137
+ if (isEmbedding)
131138
+ return d.toFixed(2);
131139
+ return `${fmtCommas(d)} px`;
131140
+ };
131141
+ const fmtArea = (a2) => {
131142
+ if (hasPhys)
131143
+ return `${a2.toFixed(2)} ${unit}²`;
131144
+ if (isEmbedding)
131145
+ return a2.toFixed(2);
131146
+ return `${fmtCommas(a2)} px²`;
131147
+ };
131148
+ if (shape2.type === "line") {
131149
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
131150
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
131151
+ const dist2 = hasPhys ? Math.sqrt((dx * px) ** 2 + (dy * py) ** 2) : Math.sqrt(dx * dx + dy * dy);
131152
+ return fmtDist(dist2);
131153
+ }
131154
+ if (shape2.type === "rectangle") {
131155
+ return fmtArea(hasPhys ? Math.abs(shape2.width ?? 0) * px * Math.abs(shape2.height ?? 0) * py : Math.abs((shape2.width ?? 0) * (shape2.height ?? 0)));
131156
+ }
131157
+ if (shape2.type === "ellipse") {
131158
+ const rx = Math.abs(shape2.radiusX ?? 0);
131159
+ const ry = Math.abs(shape2.radiusY ?? 0);
131160
+ return fmtArea(hasPhys ? Math.PI * rx * px * ry * py : Math.PI * rx * ry);
131161
+ }
131162
+ if (shape2.type === "polygon" && shape2.points?.length >= 3) {
131163
+ const pts = shape2.points;
131164
+ let shoelace = 0;
131165
+ for (let i2 = 0; i2 < pts.length; i2++) {
131166
+ const [ax, ay] = pts[i2];
131167
+ const [bx, by] = pts[(i2 + 1) % pts.length];
131168
+ shoelace += (hasPhys ? ax * px : ax) * (hasPhys ? by * py : by) - (hasPhys ? bx * px : bx) * (hasPhys ? ay * py : ay);
131169
+ }
131170
+ return fmtArea(Math.abs(shoelace / 2));
131171
+ }
131172
+ if (shape2.type === "polyline" && shape2.points?.length >= 2) {
131173
+ let total = 0;
131174
+ for (let i2 = 0; i2 < shape2.points.length - 1; i2++) {
131175
+ const [ax, ay] = shape2.points[i2];
131176
+ const [bx, by] = shape2.points[i2 + 1];
131177
+ total += hasPhys ? Math.sqrt(((bx - ax) * px) ** 2 + ((by - ay) * py) ** 2) : Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2);
131178
+ }
131179
+ return fmtDist(total);
131180
+ }
131181
+ return null;
131182
+ }
131183
+ function pickBelowPerp(ux, uy) {
131184
+ const rp = [uy, -ux];
131185
+ const lp = [-uy, ux];
131186
+ return rp[1] > lp[1] || rp[1] === lp[1] && rp[0] > lp[0] ? rp : lp;
131187
+ }
131188
+ function readableAngle(deg) {
131189
+ let a2 = deg;
131190
+ if (a2 > 90)
131191
+ a2 -= 180;
131192
+ if (a2 < -90)
131193
+ a2 += 180;
131194
+ return a2;
131195
+ }
131196
+ function getShapeCentroid(shape2) {
131197
+ if (shape2.type === "rectangle") {
131198
+ return [(shape2.x ?? 0) + (shape2.width ?? 0) / 2, (shape2.y ?? 0) + (shape2.height ?? 0) / 2];
131199
+ }
131200
+ if (shape2.type === "line") {
131201
+ return [((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2, ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2];
131202
+ }
131203
+ if (shape2.type === "ellipse") {
131204
+ return [shape2.x1 ?? 0, shape2.y1 ?? 0];
131205
+ }
131206
+ if ((shape2.type === "polygon" || shape2.type === "polyline") && shape2.points?.length >= 1) {
131207
+ const mx = shape2.points.reduce((s2, p) => s2 + p[0], 0) / shape2.points.length;
131208
+ const my = shape2.points.reduce((s2, p) => s2 + p[1], 0) / shape2.points.length;
131209
+ return [mx, my];
131210
+ }
131211
+ return [0, 0];
131212
+ }
131213
+ function computeClusters(shapeList, zoom, cellPx = 50) {
131214
+ const cellSize = cellPx / 2 ** Math.floor(zoom);
131215
+ const cells = /* @__PURE__ */ new Map();
131216
+ shapeList.forEach(({ shape: shape2 }) => {
131217
+ const [cx, cy] = getShapeCentroid(shape2);
131218
+ const key = `${Math.floor(cx / cellSize)},${Math.floor(cy / cellSize)}`;
131219
+ if (!cells.has(key)) {
131220
+ cells.set(key, { sumX: 0, sumY: 0, count: 0, color: shape2.strokeColor ?? [255, 255, 255] });
131221
+ }
131222
+ const c2 = cells.get(key);
131223
+ c2.sumX += cx;
131224
+ c2.sumY += cy;
131225
+ c2.count++;
131226
+ });
131227
+ return Array.from(cells.values()).map((c2) => ({
131228
+ position: [c2.sumX / c2.count, c2.sumY / c2.count, 0],
131229
+ count: c2.count,
131230
+ color: c2.color
131231
+ }));
131232
+ }
131233
+ function createAnnotationLayers(shapes = [], zoom = 0, selectedShapeUid = null, physicalPixelSize = null, authoredZoom = null, semanticZoom = true, viewType = ViewType$1.SPATIAL) {
131234
+ const selectionLayers = [];
131235
+ if (selectedShapeUid) {
131236
+ const sel = shapes.find((s2) => s2.uid === selectedShapeUid);
131237
+ if (sel) {
131238
+ const { uid: sUid, type: sType, strokeWidth: sStrokeWidth = 3 } = sel;
131239
+ const haloColor = [255, 220, 50, 70];
131240
+ const haloWidth = Math.max(sStrokeWidth + 8, 10);
131241
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
131242
+ if (sType === "rectangle") {
131243
+ const { x, y, width: width2, height: height2 } = sel;
131244
+ selectionLayers.push(new PathLayer({
131245
+ ...base,
131246
+ id: `annotation-select-${sUid}`,
131247
+ data: [{
131248
+ path: [
131249
+ [x, y],
131250
+ [x + width2, y],
131251
+ [x + width2, y + height2],
131252
+ [x, y + height2],
131253
+ [x, y]
131254
+ ]
131255
+ }],
131256
+ getPath: (d) => d.path,
131257
+ getColor: haloColor,
131258
+ getWidth: haloWidth,
131259
+ widthUnits: "pixels",
131260
+ jointRounded: true,
131261
+ capRounded: true
131262
+ }));
131263
+ }
131264
+ if (sType === "line") {
131265
+ const { x1: x12, y1: y12, x2, y2 } = sel;
131266
+ selectionLayers.push(new PathLayer({
131267
+ ...base,
131268
+ id: `annotation-select-${sUid}`,
131269
+ data: [{ path: [[x12, y12], [x2, y2]] }],
131270
+ getPath: (d) => d.path,
131271
+ getColor: haloColor,
131272
+ getWidth: haloWidth,
131273
+ widthUnits: "pixels",
131274
+ capRounded: true
131275
+ }));
131276
+ }
131277
+ if (sType === "ellipse") {
131278
+ const polygon2 = computeEllipsePolygon(sel.x1, sel.y1, sel.radiusX, sel.radiusY);
131279
+ selectionLayers.push(new PathLayer({
131280
+ ...base,
131281
+ id: `annotation-select-${sUid}`,
131282
+ data: [{ path: [...polygon2, polygon2[0]] }],
131283
+ getPath: (d) => d.path,
131284
+ getColor: haloColor,
131285
+ getWidth: haloWidth,
131286
+ widthUnits: "pixels",
131287
+ jointRounded: true
131288
+ }));
131289
+ }
131290
+ if (sType === "polygon" && sel.points?.length >= 3) {
131291
+ selectionLayers.push(new PathLayer({
131292
+ ...base,
131293
+ id: `annotation-select-${sUid}`,
131294
+ data: [{ path: [...sel.points, sel.points[0]] }],
131295
+ getPath: (d) => d.path,
131296
+ getColor: haloColor,
131297
+ getWidth: haloWidth,
131298
+ widthUnits: "pixels",
131299
+ jointRounded: true
131300
+ }));
131301
+ }
131302
+ if (sType === "polyline" && sel.points?.length >= 2) {
131303
+ selectionLayers.push(new PathLayer({
131304
+ ...base,
131305
+ id: `annotation-select-${sUid}`,
131306
+ data: [{ path: sel.points }],
131307
+ getPath: (d) => d.path,
131308
+ getColor: haloColor,
131309
+ getWidth: haloWidth,
131310
+ widthUnits: "pixels",
131311
+ jointRounded: true,
131312
+ capRounded: true
131313
+ }));
131314
+ }
131315
+ }
131316
+ }
131317
+ const layers = [];
131318
+ const dotShapes = [];
131319
+ const clusterDotShapes = [];
131320
+ shapes.forEach((shape2, i2) => {
131321
+ const { uid: uid2, type, strokeColor = [255, 255, 255], strokeWidth = 3, strokeDashArray } = shape2;
131322
+ const isSelected = uid2 === selectedShapeUid;
131323
+ let shapeOpacity = 1;
131324
+ let tipsOpacity = 1;
131325
+ let labelOpacity = 0;
131326
+ if (isSelected || !semanticZoom || authoredZoom === null) {
131327
+ tipsOpacity = 1;
131328
+ labelOpacity = 1;
131329
+ } else {
131330
+ const zoomRatio = 2 ** (zoom - authoredZoom);
131331
+ if (zoomRatio < RATIO_CLUSTER) {
131332
+ clusterDotShapes.push({ shape: shape2 });
131333
+ return;
131334
+ }
131335
+ if (zoomRatio < RATIO_DOT) {
131336
+ dotShapes.push({ shape: shape2, alpha: 200 });
131337
+ return;
131338
+ }
131339
+ if (zoomRatio < RATIO_GEO_FADE) {
131340
+ const t = (zoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
131341
+ shapeOpacity = t;
131342
+ dotShapes.push({ shape: shape2, alpha: Math.round((1 - t) * 200) });
131343
+ }
131344
+ tipsOpacity = zoomRatio >= RATIO_TIPS ? shapeOpacity : Math.max(0, (zoomRatio - RATIO_GEO_FADE) / (RATIO_TIPS - RATIO_GEO_FADE) * shapeOpacity);
131345
+ if (zoomRatio >= RATIO_LABEL_FULL) {
131346
+ labelOpacity = shapeOpacity;
131347
+ } else if (zoomRatio >= RATIO_LABEL) {
131348
+ labelOpacity = (zoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL) * shapeOpacity;
131349
+ }
131350
+ }
131351
+ const arrowDataSize = Math.max(ARROW_SCREEN_PX, strokeWidth * 4) / 2 ** zoom;
131352
+ const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: shapeOpacity };
131353
+ const tipsBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: tipsOpacity };
131354
+ const labelBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: labelOpacity };
131355
+ const labelBgProps = shape2.labelBackground ? {
131356
+ background: true,
131357
+ getBackgroundColor: textBgColor(strokeColor),
131358
+ backgroundPadding: [3, 1, 3, 2]
131359
+ } : {};
131360
+ const labelProps = { ...labelBgProps };
131361
+ const dashArray = parseDashArray(strokeDashArray);
131362
+ const dashExt = [new PathStyleExtension({ dash: true })];
131363
+ const getDash = dashArray ?? [0, 0];
131364
+ if (type === "rectangle") {
131365
+ const { x, y, width: width2, height: height2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131366
+ const filled = fillOpacity > 0;
131367
+ const rectPolygon = [[x, y], [x + width2, y], [x + width2, y + height2], [x, y + height2]];
131368
+ layers.push(new PolygonLayer({
131369
+ ...base,
131370
+ id: `annotation-rect-${uid2}-${i2}`,
131371
+ data: [{ polygon: rectPolygon }],
131372
+ getPolygon: (d) => d.polygon,
131373
+ filled,
131374
+ stroked: true,
131375
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
131376
+ getLineColor: strokeColor,
131377
+ getLineWidth: strokeWidth,
131378
+ lineWidthUnits: "pixels",
131379
+ ...dashArray ? {
131380
+ extensions: [new PathStyleExtension({ dash: true })],
131381
+ getDashArray: dashArray
131382
+ } : {}
131383
+ }));
131384
+ if (shape2.text && labelOpacity > 0) {
131385
+ layers.push(new TextLayer({
131386
+ ...labelBase,
131387
+ ...labelProps,
131388
+ id: `annotation-rect-text-${uid2}-${i2}`,
131389
+ data: [{ position: [x, y], text: shape2.text }],
131390
+ getPosition: (d) => d.position,
131391
+ getText: (d) => d.text,
131392
+ getColor: strokeColor,
131393
+ getSize: LABEL_FONT_SIZE,
131394
+ sizeUnits: "pixels",
131395
+ fontFamily: LABEL_FONT_FAMILY$1,
131396
+ fontWeight: LABEL_FONT_WEIGHT,
131397
+ getPixelOffset: [3, -7],
131398
+ getTextAnchor: "start",
131399
+ getAlignmentBaseline: "bottom"
131400
+ }));
131401
+ }
131402
+ }
131403
+ if (type === "line") {
131404
+ const { x1: x12, y1: y12, x2, y2, markerStart, markerEnd } = shape2;
131405
+ const dx = x2 - x12;
131406
+ const dy = y2 - y12;
131407
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131408
+ const ux = len2 > 0 ? dx / len2 : 0;
131409
+ const uy = len2 > 0 ? dy / len2 : 0;
131410
+ const srcX = markerStart === "Arrow" ? x12 + ux * arrowDataSize : x12;
131411
+ const srcY = markerStart === "Arrow" ? y12 + uy * arrowDataSize : y12;
131412
+ const tgtX = markerEnd === "Arrow" ? x2 - ux * arrowDataSize : x2;
131413
+ const tgtY = markerEnd === "Arrow" ? y2 - uy * arrowDataSize : y2;
131414
+ layers.push(new PathLayer({
131415
+ ...base,
131416
+ id: `annotation-line-${uid2}-${i2}`,
131417
+ extensions: [new PathStyleExtension({ dash: true })],
131418
+ getDashArray: dashArray ?? [0, 0],
131419
+ data: [{ path: [[srcX, srcY], [tgtX, tgtY]] }],
131420
+ getPath: (d) => d.path,
131421
+ getColor: strokeColor,
131422
+ getWidth: strokeWidth,
131423
+ widthUnits: "pixels",
131424
+ capRounded: true
131425
+ }));
131426
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
131427
+ const head = computeArrowhead(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
131428
+ if (head) {
131429
+ layers.push(new PolygonLayer({
131430
+ ...tipsBase,
131431
+ id: `annotation-end-arrow-${uid2}-${i2}`,
131432
+ data: [{ polygon: head }],
131433
+ getPolygon: (d) => d.polygon,
131434
+ filled: true,
131435
+ stroked: false,
131436
+ getFillColor: strokeColor
131437
+ }));
131438
+ }
131439
+ }
131440
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
131441
+ const head = computeArrowhead(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
131442
+ if (head) {
131443
+ layers.push(new PolygonLayer({
131444
+ ...tipsBase,
131445
+ id: `annotation-start-arrow-${uid2}-${i2}`,
131446
+ data: [{ polygon: head }],
131447
+ getPolygon: (d) => d.polygon,
131448
+ filled: true,
131449
+ stroked: false,
131450
+ getFillColor: strokeColor
131451
+ }));
131452
+ }
131453
+ }
131454
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
131455
+ const tick = computeTickCap(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
131456
+ if (tick) {
131457
+ layers.push(new PathLayer({
131458
+ ...tipsBase,
131459
+ id: `annotation-end-tick-${uid2}-${i2}`,
131460
+ data: [{ path: tick }],
131461
+ getPath: (d) => d.path,
131462
+ getColor: strokeColor,
131463
+ getWidth: strokeWidth,
131464
+ widthUnits: "pixels",
131465
+ capRounded: true
131466
+ }));
131467
+ }
131468
+ }
131469
+ if (markerStart === "Tick" && tipsOpacity > 0) {
131470
+ const tick = computeTickCap(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
131471
+ if (tick) {
131472
+ layers.push(new PathLayer({
131473
+ ...tipsBase,
131474
+ id: `annotation-start-tick-${uid2}-${i2}`,
131475
+ data: [{ path: tick }],
131476
+ getPath: (d) => d.path,
131477
+ getColor: strokeColor,
131478
+ getWidth: strokeWidth,
131479
+ widthUnits: "pixels",
131480
+ capRounded: true
131481
+ }));
131482
+ }
131483
+ }
131484
+ if (shape2.text) {
131485
+ const pos = shape2.textPosition ?? "start";
131486
+ let textX;
131487
+ let textY;
131488
+ if (pos === "start") {
131489
+ textX = x12;
131490
+ textY = y12;
131491
+ } else if (pos === "end") {
131492
+ textX = x2;
131493
+ textY = y2;
131494
+ } else {
131495
+ textX = (x12 + x2) / 2;
131496
+ textY = (y12 + y2) / 2;
131497
+ }
131498
+ let pixelOffset = [0, 0];
131499
+ let textAnchor = "middle";
131500
+ let alignmentBaseline = "center";
131501
+ if (pos !== "middle") {
131502
+ const dxT = x2 - x12;
131503
+ const dyT = y2 - y12;
131504
+ const lenT = Math.sqrt(dxT * dxT + dyT * dyT);
131505
+ if (lenT > 0) {
131506
+ const uxT = dxT / lenT;
131507
+ const uyT = dyT / lenT;
131508
+ const sign2 = pos === "start" ? -1 : 1;
131509
+ const bufferPx = shape2.textBufferPx ?? 8;
131510
+ const offsetX = sign2 * uxT * bufferPx;
131511
+ const offsetY = sign2 * uyT * bufferPx;
131512
+ pixelOffset = [offsetX, offsetY];
131513
+ const absX = Math.abs(offsetX);
131514
+ const absY = Math.abs(offsetY);
131515
+ if (absX >= absY) {
131516
+ textAnchor = offsetX > 0 ? "start" : "end";
131517
+ }
131518
+ if (absY >= absX) {
131519
+ alignmentBaseline = offsetY > 0 ? "top" : "bottom";
131520
+ }
131521
+ }
131522
+ } else if (len2 > 0) {
131523
+ const belowPerp = pickBelowPerp(ux, uy);
131524
+ const bufferPx = shape2.textBufferPx ?? 14;
131525
+ pixelOffset = [-belowPerp[0] * bufferPx, -belowPerp[1] * bufferPx];
131526
+ textAnchor = "middle";
131527
+ alignmentBaseline = "center";
131528
+ }
131529
+ const middleAngle = pos === "middle" && len2 > 0 ? -readableAngle(Math.atan2(dy, dx) * 180 / Math.PI) : null;
131530
+ if (labelOpacity <= 0)
131531
+ return;
131532
+ layers.push(new TextLayer({
131533
+ ...labelBase,
131534
+ ...labelProps,
131535
+ id: `annotation-line-text-${uid2}-${i2}`,
131536
+ data: [{ position: [textX, textY], text: shape2.text }],
131537
+ getPosition: (d) => d.position,
131538
+ getText: (d) => d.text,
131539
+ getColor: strokeColor,
131540
+ getSize: LABEL_FONT_SIZE,
131541
+ sizeUnits: "pixels",
131542
+ fontFamily: LABEL_FONT_FAMILY$1,
131543
+ fontWeight: LABEL_FONT_WEIGHT,
131544
+ getPixelOffset: pixelOffset,
131545
+ getTextAnchor: textAnchor,
131546
+ getAlignmentBaseline: alignmentBaseline,
131547
+ ...middleAngle !== null && { getAngle: middleAngle }
131548
+ }));
131549
+ }
131550
+ }
131551
+ if (type === "ellipse") {
131552
+ const { x1: x12, y1: y12, radiusX, radiusY, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131553
+ const polygon2 = computeEllipsePolygon(x12, y12, radiusX, radiusY);
131554
+ const filled = fillOpacity > 0;
131555
+ layers.push(new PolygonLayer({
131556
+ ...base,
131557
+ id: `annotation-ellipse-${uid2}-${i2}`,
131558
+ data: [{ polygon: polygon2 }],
131559
+ getPolygon: (d) => d.polygon,
131560
+ filled,
131561
+ stroked: true,
131562
+ getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
131563
+ getLineColor: strokeColor,
131564
+ getLineWidth: strokeWidth,
131565
+ lineWidthUnits: "pixels",
131566
+ ...dashArray ? {
131567
+ extensions: [new PathStyleExtension({ dash: true })],
131568
+ getDashArray: dashArray
131569
+ } : {}
131570
+ }));
131571
+ if (shape2.text && labelOpacity > 0) {
131572
+ layers.push(new TextLayer({
131573
+ ...labelBase,
131574
+ ...labelProps,
131575
+ id: `annotation-ellipse-text-${uid2}-${i2}`,
131576
+ data: [{ position: [x12, y12 - radiusY], text: shape2.text }],
131577
+ getPosition: (d) => d.position,
131578
+ getText: (d) => d.text,
131579
+ getColor: strokeColor,
131580
+ getSize: LABEL_FONT_SIZE,
131581
+ sizeUnits: "pixels",
131582
+ fontFamily: LABEL_FONT_FAMILY$1,
131583
+ fontWeight: LABEL_FONT_WEIGHT,
131584
+ getPixelOffset: [0, -4],
131585
+ getTextAnchor: "middle",
131586
+ getAlignmentBaseline: "bottom"
131587
+ }));
131588
+ }
131589
+ }
131590
+ if (type === "polygon") {
131591
+ const { points, fillColor = strokeColor, fillOpacity = 0 } = shape2;
131592
+ if (!points || points.length < 3)
131593
+ return;
131594
+ const closedPath = [...points, points[0]];
131595
+ if (fillOpacity > 0) {
131596
+ layers.push(new PolygonLayer({
131597
+ ...base,
131598
+ id: `annotation-polygon-fill-${uid2}-${i2}`,
131599
+ data: [{ polygon: points }],
131600
+ getPolygon: (d) => d.polygon,
131601
+ stroked: false,
131602
+ filled: true,
131603
+ getFillColor: [...fillColor, Math.round(fillOpacity * 255)]
131604
+ }));
131605
+ }
131606
+ layers.push(new PathLayer({
131607
+ ...base,
131608
+ id: `annotation-polygon-${uid2}-${i2}`,
131609
+ extensions: dashExt,
131610
+ getDashArray: getDash,
131611
+ data: [{ path: closedPath }],
131612
+ getPath: (d) => d.path,
131613
+ getColor: strokeColor,
131614
+ getWidth: strokeWidth,
131615
+ widthUnits: "pixels",
131616
+ jointRounded: true
131617
+ }));
131618
+ if (shape2.text && labelOpacity > 0) {
131619
+ const minX = Math.min(...points.map((p) => p[0]));
131620
+ const maxX = Math.max(...points.map((p) => p[0]));
131621
+ const minY = Math.min(...points.map((p) => p[1]));
131622
+ const topCenterX = (minX + maxX) / 2;
131623
+ layers.push(new TextLayer({
131624
+ ...labelBase,
131625
+ ...labelProps,
131626
+ id: `annotation-polygon-text-${uid2}-${i2}`,
131627
+ data: [{ position: [topCenterX, minY], text: shape2.text }],
131628
+ getPosition: (d) => d.position,
131629
+ getText: (d) => d.text,
131630
+ getColor: strokeColor,
131631
+ getSize: LABEL_FONT_SIZE,
131632
+ sizeUnits: "pixels",
131633
+ fontFamily: LABEL_FONT_FAMILY$1,
131634
+ fontWeight: LABEL_FONT_WEIGHT,
131635
+ getPixelOffset: [0, -4],
131636
+ getTextAnchor: "middle",
131637
+ getAlignmentBaseline: "bottom"
131638
+ }));
131639
+ }
131640
+ }
131641
+ if (type === "polyline") {
131642
+ const { points, markerStart, markerEnd } = shape2;
131643
+ if (!points || points.length < 2)
131644
+ return;
131645
+ let pathPoints = points;
131646
+ if (markerStart === "Arrow") {
131647
+ const [x02, y02] = points[0];
131648
+ const [x12, y12] = points[1];
131649
+ const dx = x02 - x12;
131650
+ const dy = y02 - y12;
131651
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131652
+ if (len2 > 0) {
131653
+ const ux = dx / len2;
131654
+ const uy = dy / len2;
131655
+ pathPoints = [[x02 - ux * arrowDataSize, y02 - uy * arrowDataSize], ...pathPoints.slice(1)];
131656
+ }
131657
+ }
131658
+ if (markerEnd === "Arrow") {
131659
+ const last = pathPoints[pathPoints.length - 1];
131660
+ const prev2 = pathPoints[pathPoints.length - 2];
131661
+ const dx = last[0] - prev2[0];
131662
+ const dy = last[1] - prev2[1];
131663
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131664
+ if (len2 > 0) {
131665
+ const ux = dx / len2;
131666
+ const uy = dy / len2;
131667
+ const shortened = [last[0] - ux * arrowDataSize, last[1] - uy * arrowDataSize];
131668
+ pathPoints = [...pathPoints.slice(0, -1), shortened];
131669
+ }
131670
+ }
131671
+ layers.push(new PathLayer({
131672
+ ...base,
131673
+ id: `annotation-polyline-${uid2}-${i2}`,
131674
+ extensions: dashExt,
131675
+ getDashArray: getDash,
131676
+ data: [{ path: pathPoints }],
131677
+ getPath: (d) => d.path,
131678
+ getColor: strokeColor,
131679
+ getWidth: strokeWidth,
131680
+ widthUnits: "pixels",
131681
+ jointRounded: true,
131682
+ capRounded: true
131683
+ }));
131684
+ if (markerStart === "Arrow" && tipsOpacity > 0) {
131685
+ const [x02, y02] = points[0];
131686
+ const [x12, y12] = points[1];
131687
+ const head = computeArrowhead(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
131688
+ if (head) {
131689
+ layers.push(new PolygonLayer({
131690
+ ...tipsBase,
131691
+ id: `annotation-polyline-start-arrow-${uid2}-${i2}`,
131692
+ data: [{ polygon: head }],
131693
+ getPolygon: (d) => d.polygon,
131694
+ filled: true,
131695
+ stroked: false,
131696
+ getFillColor: strokeColor
131697
+ }));
131698
+ }
131699
+ }
131700
+ if (markerEnd === "Arrow" && tipsOpacity > 0) {
131701
+ const last = points[points.length - 1];
131702
+ const prev2 = points[points.length - 2];
131703
+ const dxArrow = last[0] - prev2[0];
131704
+ const dyArrow = last[1] - prev2[1];
131705
+ const head = computeArrowhead(last[0], last[1], dxArrow, dyArrow, arrowDataSize);
131706
+ if (head) {
131707
+ layers.push(new PolygonLayer({
131708
+ ...tipsBase,
131709
+ id: `annotation-polyline-end-arrow-${uid2}-${i2}`,
131710
+ data: [{ polygon: head }],
131711
+ getPolygon: (d) => d.polygon,
131712
+ filled: true,
131713
+ stroked: false,
131714
+ getFillColor: strokeColor
131715
+ }));
131716
+ }
131717
+ }
131718
+ if (markerStart === "Tick" && tipsOpacity > 0) {
131719
+ const [x02, y02] = points[0];
131720
+ const [x12, y12] = points[1];
131721
+ const tick = computeTickCap(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
131722
+ if (tick) {
131723
+ layers.push(new PathLayer({
131724
+ ...tipsBase,
131725
+ id: `annotation-polyline-start-tick-${uid2}-${i2}`,
131726
+ data: [{ path: tick }],
131727
+ getPath: (d) => d.path,
131728
+ getColor: strokeColor,
131729
+ getWidth: strokeWidth,
131730
+ widthUnits: "pixels",
131731
+ capRounded: true
131732
+ }));
131733
+ }
131734
+ }
131735
+ if (markerEnd === "Tick" && tipsOpacity > 0) {
131736
+ const last = points[points.length - 1];
131737
+ const prev2 = points[points.length - 2];
131738
+ const dxTick = last[0] - prev2[0];
131739
+ const dyTick = last[1] - prev2[1];
131740
+ const tick = computeTickCap(last[0], last[1], dxTick, dyTick, arrowDataSize);
131741
+ if (tick) {
131742
+ layers.push(new PathLayer({
131743
+ ...tipsBase,
131744
+ id: `annotation-polyline-end-tick-${uid2}-${i2}`,
131745
+ data: [{ path: tick }],
131746
+ getPath: (d) => d.path,
131747
+ getColor: strokeColor,
131748
+ getWidth: strokeWidth,
131749
+ widthUnits: "pixels",
131750
+ capRounded: true
131751
+ }));
131752
+ }
131753
+ }
131754
+ if (shape2.text) {
131755
+ const pos = shape2.textPosition ?? "start";
131756
+ const bufferPx = shape2.textBufferPx ?? 8;
131757
+ let textPt;
131758
+ let dirX;
131759
+ let dirY;
131760
+ if (pos === "end") {
131761
+ const last = points[points.length - 1];
131762
+ const prev2 = points[points.length - 2];
131763
+ textPt = last;
131764
+ dirX = last[0] - prev2[0];
131765
+ dirY = last[1] - prev2[1];
131766
+ } else if (pos === "middle") {
131767
+ const mx = points.reduce((s2, p) => s2 + p[0], 0) / points.length;
131768
+ const my = points.reduce((s2, p) => s2 + p[1], 0) / points.length;
131769
+ textPt = [mx, my];
131770
+ dirX = 0;
131771
+ dirY = 0;
131772
+ } else {
131773
+ [textPt] = points;
131774
+ dirX = points[0][0] - points[1][0];
131775
+ dirY = points[0][1] - points[1][1];
131776
+ }
131777
+ const [textX, textY] = textPt;
131778
+ const lenT = Math.sqrt(dirX * dirX + dirY * dirY);
131779
+ let polylinePixelOffset = [0, 0];
131780
+ let polylineTextAnchor = "middle";
131781
+ let polylineAlignmentBaseline = pos === "middle" ? "center" : "bottom";
131782
+ if (lenT > 0) {
131783
+ const uxT = dirX / lenT;
131784
+ const uyT = dirY / lenT;
131785
+ const offX = uxT * bufferPx;
131786
+ const offY = uyT * bufferPx;
131787
+ polylinePixelOffset = [offX, offY];
131788
+ if (Math.abs(offX) >= Math.abs(offY)) {
131789
+ polylineTextAnchor = offX > 0 ? "start" : "end";
131790
+ }
131791
+ if (Math.abs(offY) >= Math.abs(offX)) {
131792
+ polylineAlignmentBaseline = offY > 0 ? "top" : "bottom";
131793
+ }
131794
+ }
131795
+ if (labelOpacity <= 0)
131796
+ return;
131797
+ layers.push(new TextLayer({
131798
+ ...labelBase,
131799
+ ...labelProps,
131800
+ id: `annotation-polyline-text-${uid2}-${i2}`,
131801
+ data: [{ position: [textX, textY], text: shape2.text }],
131802
+ getPosition: (d) => d.position,
131803
+ getText: (d) => d.text,
131804
+ getColor: strokeColor,
131805
+ getSize: LABEL_FONT_SIZE,
131806
+ sizeUnits: "pixels",
131807
+ fontFamily: LABEL_FONT_FAMILY$1,
131808
+ fontWeight: LABEL_FONT_WEIGHT,
131809
+ getPixelOffset: polylinePixelOffset,
131810
+ getTextAnchor: polylineTextAnchor,
131811
+ getAlignmentBaseline: polylineAlignmentBaseline
131812
+ }));
131813
+ }
131814
+ }
131815
+ });
131816
+ if (dotShapes.length > 0) {
131817
+ layers.push(new ScatterplotLayer({
131818
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
131819
+ id: "annotation-dots",
131820
+ data: dotShapes.map(({ shape: s2, alpha: alpha2 }) => ({
131821
+ position: getShapeCentroid(s2),
131822
+ color: [...s2.strokeColor ?? [255, 255, 255], alpha2]
131823
+ })),
131824
+ getPosition: (d) => d.position,
131825
+ getFillColor: (d) => d.color,
131826
+ getRadius: 4,
131827
+ radiusUnits: "pixels",
131828
+ filled: true,
131829
+ stroked: false
131830
+ }));
131831
+ }
131832
+ if (clusterDotShapes.length > 0) {
131833
+ const clusters = computeClusters(clusterDotShapes, zoom);
131834
+ layers.push(new ScatterplotLayer({
131835
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
131836
+ id: "annotation-clusters",
131837
+ data: clusters,
131838
+ getPosition: (d) => d.position,
131839
+ getFillColor: (d) => [...d.color, 180],
131840
+ getRadius: (d) => Math.max(6, 4 + Math.sqrt(d.count) * 2),
131841
+ radiusUnits: "pixels",
131842
+ filled: true,
131843
+ stroked: true,
131844
+ getLineColor: (d) => [...d.color, 220],
131845
+ lineWidthMinPixels: 1.5
131846
+ }));
131847
+ const multiClusters = clusters.filter((c2) => c2.count > 1);
131848
+ if (multiClusters.length > 0) {
131849
+ layers.push(new TextLayer({
131850
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
131851
+ id: "annotation-cluster-counts",
131852
+ data: multiClusters,
131853
+ getPosition: (d) => d.position,
131854
+ getText: (d) => String(d.count),
131855
+ getColor: [255, 255, 255],
131856
+ getSize: 10,
131857
+ sizeUnits: "pixels",
131858
+ fontWeight: "bold",
131859
+ getTextAnchor: "middle",
131860
+ getAlignmentBaseline: "center"
131861
+ }));
131862
+ }
131863
+ }
131864
+ const measureLayers = [];
131865
+ shapes.forEach((shape2) => {
131866
+ if (!shape2.showMeasure)
131867
+ return;
131868
+ const mIsSelected = shape2.uid === selectedShapeUid;
131869
+ const label = getMeasurementLabel(shape2, physicalPixelSize, viewType);
131870
+ if (!label)
131871
+ return;
131872
+ const color2 = shape2.strokeColor ?? [255, 255, 255];
131873
+ let mShapeOpacity = 1;
131874
+ let mLabelFactor = 0;
131875
+ if (mIsSelected || !semanticZoom || authoredZoom === null) {
131876
+ mLabelFactor = 1;
131877
+ } else {
131878
+ const mZoomRatio = 2 ** (zoom - authoredZoom);
131879
+ if (mZoomRatio < RATIO_DOT)
131880
+ return;
131881
+ if (mZoomRatio < RATIO_GEO_FADE) {
131882
+ mShapeOpacity = (mZoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
131883
+ }
131884
+ if (mZoomRatio >= RATIO_LABEL_FULL) {
131885
+ mLabelFactor = 1;
131886
+ } else if (mZoomRatio >= RATIO_LABEL) {
131887
+ mLabelFactor = (mZoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL);
131888
+ }
131889
+ }
131890
+ const measureOpacity = mShapeOpacity * mLabelFactor;
131891
+ if (measureOpacity <= 0)
131892
+ return;
131893
+ const base = {
131894
+ coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
131895
+ opacity: measureOpacity,
131896
+ getText: (d) => d.text,
131897
+ getPosition: (d) => d.position,
131898
+ getColor: color2,
131899
+ getSize: 13,
131900
+ sizeUnits: "pixels",
131901
+ fontFamily: LABEL_FONT_FAMILY$1,
131902
+ fontWeight: "bold",
131903
+ // 'auto' builds the font atlas from the actual rendered characters (e.g. µ, ²)
131904
+ // instead of deck.gl's default ASCII-only atlas.
131905
+ characterSet: "auto",
131906
+ ...shape2.measureBackground ? {
131907
+ background: true,
131908
+ getBackgroundColor: textBgColor(color2),
131909
+ backgroundPadding: [3, 1, 3, 2]
131910
+ } : {}
131911
+ };
131912
+ if (shape2.type === "line") {
131913
+ const mx = ((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2;
131914
+ const my = ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2;
131915
+ const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
131916
+ const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
131917
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131918
+ if (len2 === 0)
131919
+ return;
131920
+ const perp = pickBelowPerp(dx / len2, dy / len2);
131921
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
131922
+ measureLayers.push(new TextLayer({
131923
+ ...base,
131924
+ id: `annotation-measure-${shape2.uid}`,
131925
+ data: [{ position: [mx, my], text: label }],
131926
+ getAngle: -angle2,
131927
+ getTextAnchor: "middle",
131928
+ getAlignmentBaseline: "center",
131929
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
131930
+ }));
131931
+ } else if (shape2.type === "polyline" && shape2.points?.length >= 2) {
131932
+ const pts = shape2.points;
131933
+ const mi = Math.floor((pts.length - 1) / 2);
131934
+ const [ax, ay] = pts[mi];
131935
+ const [bx, by] = pts[mi + 1];
131936
+ const dx = bx - ax;
131937
+ const dy = by - ay;
131938
+ const len2 = Math.sqrt(dx * dx + dy * dy);
131939
+ if (len2 === 0)
131940
+ return;
131941
+ const perp = pickBelowPerp(dx / len2, dy / len2);
131942
+ const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
131943
+ measureLayers.push(new TextLayer({
131944
+ ...base,
131945
+ id: `annotation-measure-${shape2.uid}`,
131946
+ data: [{ position: [(ax + bx) / 2, (ay + by) / 2], text: label }],
131947
+ getAngle: -angle2,
131948
+ getTextAnchor: "middle",
131949
+ getAlignmentBaseline: "center",
131950
+ getPixelOffset: [perp[0] * 16, perp[1] * 16]
131951
+ }));
131952
+ } else if (shape2.type === "rectangle") {
131953
+ const x02 = shape2.x ?? 0;
131954
+ const y02 = shape2.y ?? 0;
131955
+ const w2 = shape2.width ?? 0;
131956
+ const h = shape2.height ?? 0;
131957
+ const rx = x02 + (w2 >= 0 ? w2 : 0);
131958
+ const ry = y02 + (h >= 0 ? h : 0);
131959
+ measureLayers.push(new TextLayer({
131960
+ ...base,
131961
+ id: `annotation-measure-${shape2.uid}`,
131962
+ data: [{ position: [rx, ry], text: label }],
131963
+ getTextAnchor: "end",
131964
+ getAlignmentBaseline: "bottom",
131965
+ getPixelOffset: [-6, -6]
131966
+ }));
131967
+ } else if (shape2.type === "ellipse") {
131968
+ const cx = shape2.x1 ?? 0;
131969
+ const cy = shape2.y1 ?? 0;
131970
+ const ry = Math.abs(shape2.radiusY ?? 0);
131971
+ measureLayers.push(new TextLayer({
131972
+ ...base,
131973
+ id: `annotation-measure-${shape2.uid}`,
131974
+ data: [{ position: [cx, cy + ry], text: label }],
131975
+ getTextAnchor: "middle",
131976
+ getAlignmentBaseline: "top",
131977
+ getPixelOffset: [0, 8]
131978
+ }));
131979
+ } else if (shape2.type === "polygon" && shape2.points?.length >= 3) {
131980
+ const xs = shape2.points.map((p) => p[0]);
131981
+ const ys = shape2.points.map((p) => p[1]);
131982
+ const cx = (Math.min(...xs) + Math.max(...xs)) / 2;
131983
+ const maxY = Math.max(...ys);
131984
+ measureLayers.push(new TextLayer({
131985
+ ...base,
131986
+ id: `annotation-measure-${shape2.uid}`,
131987
+ data: [{ position: [cx, maxY], text: label }],
131988
+ getTextAnchor: "middle",
131989
+ getAlignmentBaseline: "top",
131990
+ getPixelOffset: [0, 8]
131991
+ }));
131992
+ }
131993
+ });
131994
+ return [...selectionLayers, ...layers, ...measureLayers];
131995
+ }
131996
+ const defaultProps$1 = {
131997
+ // Array of annotation shape objects (see annotationShapeObj in @vitessce/schemas).
131998
+ data: { type: "object", value: [], compare: true },
131999
+ // UID of the shape to highlight with a selection halo.
132000
+ selectedShapeUid: { type: "string", value: null },
132001
+ // { x, y, unit } used to format measurement labels in physical units.
132002
+ physicalPixelSize: { type: "object", value: null, compare: true },
132003
+ // The zoom level at which the shapes were authored (reference for semantic zoom).
132004
+ authoredZoom: { type: "number", value: null },
132005
+ // Whether to apply semantic zoom (level-of-detail) based on authoredZoom.
132006
+ semanticZoom: { type: "boolean", value: true },
132007
+ // The view type in which the layer is rendered (affects measurement label formatting).
132008
+ viewType: { type: "string", value: ViewType$1.SPATIAL },
132009
+ // In-progress shape being drawn, as { type, vertices }.
132010
+ inProgressShape: { type: "object", value: null, compare: true },
132011
+ // Current mouse position (in data coordinates) while drawing.
132012
+ hoverCoord: { type: "array", value: null, compare: true },
132013
+ // Stroke color [r, g, b] of the in-progress shape preview.
132014
+ previewStrokeColor: { type: "color", value: [255, 255, 0] }
132015
+ };
132016
+ class AnnotationLayer extends CompositeLayer {
132017
+ // The semantic zoom and arrowhead sizes depend on the current zoom level,
132018
+ // so the sublayers must also be re-rendered when the viewport changes.
132019
+ // eslint-disable-next-line class-methods-use-this
132020
+ shouldUpdateState({ changeFlags }) {
132021
+ return changeFlags.propsOrDataChanged || changeFlags.viewportChanged;
132022
+ }
132023
+ /**
132024
+ * Prefix the sublayer ID with this layer's ID (so that multiple
132025
+ * AnnotationLayers can co-exist), and combine this layer's
132026
+ * opacity with the per-shape opacity of the sublayer.
132027
+ * Note: we avoid getSubLayerProps here, since it would
132028
+ * overwrite the sublayer extensions (e.g., PathStyleExtension)
132029
+ * and opacity values.
132030
+ * @param {object} layer A DeckGL layer instance.
132031
+ * @returns {object} The cloned layer instance.
132032
+ */
132033
+ wrapSubLayer(layer) {
132034
+ const { id, opacity, pickable, visible } = this.props;
132035
+ return layer.clone({
132036
+ id: `${id}-${layer.id}`,
132037
+ opacity: layer.props.opacity * opacity,
132038
+ pickable,
132039
+ visible
132040
+ });
132041
+ }
132042
+ renderLayers() {
132043
+ const { data, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType, inProgressShape, hoverCoord, previewStrokeColor } = this.props;
132044
+ const zoom = this.context.viewport?.zoom ?? 0;
132045
+ const visibleShapes = (data ?? []).filter((shape2) => shape2.visible !== false);
132046
+ const annotationLayers = createAnnotationLayers(visibleShapes, zoom, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType);
132047
+ const previewLayer = createPreviewLayer(inProgressShape, hoverCoord, previewStrokeColor.slice(0, 3));
132048
+ return [
132049
+ ...annotationLayers,
132050
+ ...previewLayer ? [previewLayer] : []
132051
+ ].map((layer) => this.wrapSubLayer(layer));
132052
+ }
132053
+ }
132054
+ AnnotationLayer.layerName = "AnnotationLayer";
132055
+ AnnotationLayer.defaultProps = defaultProps$1;
130687
132056
  function r$1(e2) {
130688
132057
  var t, f2, n2 = "";
130689
132058
  if ("string" == typeof e2 || "number" == typeof e2) n2 += e2;
@@ -153601,11 +154970,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
153601
154970
  this.cellSetsLabelPrevZoom = null;
153602
154971
  this.cellSetsLayers = [];
153603
154972
  this.contourLayers = [];
154973
+ this.annotationLayer = null;
153604
154974
  this.onUpdateCellsData();
153605
154975
  this.onUpdateCellsLayer();
153606
154976
  this.onUpdateCellSetsLayers();
153607
154977
  this.onUpdateStratifiedData();
153608
154978
  this.onUpdateContourLayers();
154979
+ this.onUpdateAnnotationLayer();
153609
154980
  }
153610
154981
  // Want to support multiple types of contour layers
153611
154982
  // - One layer for all data points (no filtering)
@@ -153669,6 +155040,21 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
153669
155040
  }));
153670
155041
  return layers;
153671
155042
  }
155043
+ createAnnotationLayer() {
155044
+ const { annotationShapes, annotationOverlayVisible, annotationSemanticZoom, annotationShapeSelection } = this.props;
155045
+ return new AnnotationLayer({
155046
+ data: annotationShapes,
155047
+ visible: annotationOverlayVisible,
155048
+ semanticZoom: annotationSemanticZoom,
155049
+ selectedShapeUid: annotationShapeSelection,
155050
+ viewType: ViewType$1.SCATTERPLOT
155051
+ // TODO: is this needed?
155052
+ // TODO: these are view-level properties, rather than layer-level.
155053
+ // annotationTransitionDuration,
155054
+ // annotationEditable,
155055
+ // Other coordination types related to editing...
155056
+ });
155057
+ }
153672
155058
  createCellsLayer() {
153673
155059
  const {
153674
155060
  obsEmbeddingIndex: obsIndex,
@@ -153802,12 +155188,13 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
153802
155188
  ], flipYTooltip, this.props.onSelectionBusy);
153803
155189
  }
153804
155190
  getLayers() {
153805
- const { cellsLayer, cellSetsLayers, contourLayers } = this;
155191
+ const { cellsLayer, cellSetsLayers, contourLayers, annotationLayer } = this;
153806
155192
  return [
153807
155193
  cellsLayer,
153808
155194
  ...contourLayers,
153809
155195
  ...cellSetsLayers,
153810
- this.createSelectionLayer()
155196
+ this.createSelectionLayer(),
155197
+ annotationLayer
153811
155198
  ];
153812
155199
  }
153813
155200
  /**
@@ -153844,6 +155231,14 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
153844
155231
  this.cellsLayer = null;
153845
155232
  }
153846
155233
  }
155234
+ onUpdateAnnotationLayer() {
155235
+ const { annotationShapes } = this.props;
155236
+ if (annotationShapes) {
155237
+ this.annotationLayer = this.createAnnotationLayer();
155238
+ } else {
155239
+ this.annotationLayer = null;
155240
+ }
155241
+ }
153847
155242
  onUpdateStratifiedData() {
153848
155243
  const { stratifiedData } = this.props;
153849
155244
  if (stratifiedData) {
@@ -153959,6 +155354,16 @@ class Scatterplot extends AbstractSpatialOrScatterplot {
153959
155354
  this.onUpdateCellSetsLayers(true);
153960
155355
  forceUpdate = true;
153961
155356
  }
155357
+ if ([
155358
+ "annotationShapes",
155359
+ "annotationOverlayVisible",
155360
+ "annotationSemanticZoom",
155361
+ "annotationTransitionDuration",
155362
+ "annotationEditable"
155363
+ ].some(shallowDiff)) {
155364
+ this.onUpdateAnnotationLayer();
155365
+ forceUpdate = true;
155366
+ }
153962
155367
  if (forceUpdate) {
153963
155368
  this.forceUpdate();
153964
155369
  }