@vitessce/statistical-plots 4.0.8 → 4.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{deflate--aCxt3Uk.js → deflate-BG2HUqgg.js} +1 -1
- package/dist/{index-BSDNU38l.js → index-DySLEwfl.js} +1400 -37
- package/dist/index.js +1 -1
- package/dist/{jpeg-KhuOxw4Z.js → jpeg-DhNGUcND.js} +1 -1
- package/dist/{lerc-CElkXFuI.js → lerc-CeaVG0Hd.js} +1 -1
- package/dist/{lzw-CKBozwxj.js → lzw-DkbMJx1b.js} +1 -1
- package/dist/{packbits-DBXx1JcY.js → packbits-8pX5TxcK.js} +1 -1
- package/dist/{raw-Vb44MxD9.js → raw-Dg8kCOnj.js} +1 -1
- package/dist/{webimage-Df6sOKlo.js → webimage-DqIQm4cj.js} +1 -1
- package/package.json +8 -8
|
@@ -54,7 +54,8 @@ const ViewType$1 = {
|
|
|
54
54
|
TREEMAP: "treemap",
|
|
55
55
|
SAMPLE_SET_PAIR_MANAGER: "sampleSetPairManager",
|
|
56
56
|
FEATURE_STATS_TABLE: "featureStatsTable",
|
|
57
|
-
SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector"
|
|
57
|
+
SINGLE_OBS_SET_SELECTOR: "singleObsSetSelector",
|
|
58
|
+
ANNOTATION_CONTROLLER: "annotationController"
|
|
58
59
|
};
|
|
59
60
|
const DataType$2 = {
|
|
60
61
|
OBS_LABELS: "obsLabels",
|
|
@@ -75,7 +76,8 @@ const DataType$2 = {
|
|
|
75
76
|
COMPARISON_METADATA: "comparisonMetadata",
|
|
76
77
|
FEATURE_STATS: "featureStats",
|
|
77
78
|
FEATURE_SET_STATS: "featureSetStats",
|
|
78
|
-
OBS_SET_STATS: "obsSetStats"
|
|
79
|
+
OBS_SET_STATS: "obsSetStats",
|
|
80
|
+
ANNOTATION_STORY: "annotationStory"
|
|
79
81
|
};
|
|
80
82
|
const AsyncFunctionType = {
|
|
81
83
|
TRANSFORM_FEATURE: "transformFeature"
|
|
@@ -100,6 +102,7 @@ const FileType$1 = {
|
|
|
100
102
|
OBS_SETS_CSV: "obsSets.csv",
|
|
101
103
|
OBS_SETS_JSON: "obsSets.json",
|
|
102
104
|
SAMPLE_SETS_CSV: "sampleSets.csv",
|
|
105
|
+
ANNOTATION_STORY_JSON: "annotationStory.json",
|
|
103
106
|
// OME-Zarr
|
|
104
107
|
IMAGE_OME_ZARR: "image.ome-zarr",
|
|
105
108
|
OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
|
|
@@ -384,7 +387,15 @@ const CoordinationType$1 = {
|
|
|
384
387
|
FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
|
|
385
388
|
FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
|
|
386
389
|
// Treemap
|
|
387
|
-
HIERARCHY_LEVELS: "hierarchyLevels"
|
|
390
|
+
HIERARCHY_LEVELS: "hierarchyLevels",
|
|
391
|
+
// Annotation frames
|
|
392
|
+
ANNOTATION_STORY: "annotationStory",
|
|
393
|
+
ANNOTATION_FRAME_INDEX: "annotationFrameIndex",
|
|
394
|
+
ANNOTATION_SHAPES: "annotationShapes",
|
|
395
|
+
ANNOTATION_OVERLAY_VISIBLE: "annotationOverlayVisible",
|
|
396
|
+
ANNOTATION_TRANSITION_DURATION: "annotationTransitionDuration",
|
|
397
|
+
ANNOTATION_SEMANTIC_ZOOM: "annotationSemanticZoom",
|
|
398
|
+
ANNOTATION_EDITABLE: "annotationEditable"
|
|
388
399
|
};
|
|
389
400
|
const ViewHelpMapping = {
|
|
390
401
|
OBS_SET_SIZES: "The observation set sizes view displays a bar plot with the currently-selected observation sets (e.g., cell types) on the x-axis and bars representing their size (e.g., number of cells) on the y-axis.",
|
|
@@ -412,6 +423,7 @@ const ViewHelpMapping = {
|
|
|
412
423
|
[FileType$1.OBS_SEGMENTATIONS_JSON]: DataType$2.OBS_SEGMENTATIONS,
|
|
413
424
|
[FileType$1.OBS_SETS_CSV]: DataType$2.OBS_SETS,
|
|
414
425
|
[FileType$1.OBS_SETS_JSON]: DataType$2.OBS_SETS,
|
|
426
|
+
[FileType$1.ANNOTATION_STORY_JSON]: DataType$2.ANNOTATION_STORY,
|
|
415
427
|
[FileType$1.IMAGE_OME_ZARR]: DataType$2.IMAGE,
|
|
416
428
|
[FileType$1.OBS_SEGMENTATIONS_OME_ZARR]: DataType$2.OBS_SEGMENTATIONS,
|
|
417
429
|
[FileType$1.OBS_FEATURE_MATRIX_ANNDATA_ZARR]: DataType$2.OBS_FEATURE_MATRIX,
|
|
@@ -534,7 +546,8 @@ const ViewHelpMapping = {
|
|
|
534
546
|
[DataType$2.OBS_SET_STATS]: [
|
|
535
547
|
CoordinationType$1.OBS_TYPE
|
|
536
548
|
// TODO: should sampleType, obsSetSelection, and/or sampleSetSelection be used here?
|
|
537
|
-
]
|
|
549
|
+
],
|
|
550
|
+
[DataType$2.ANNOTATION_STORY]: []
|
|
538
551
|
});
|
|
539
552
|
({
|
|
540
553
|
// For AnnData:
|
|
@@ -667,7 +680,9 @@ const ViewHelpMapping = {
|
|
|
667
680
|
CoordinationType$1.SPATIAL_TARGET_Z,
|
|
668
681
|
CoordinationType$1.SPATIAL_AXIS_FIXED,
|
|
669
682
|
CoordinationType$1.SPATIAL_ORBIT_AXIS,
|
|
670
|
-
CoordinationType$1.FEATURE_AGGREGATION_STRATEGY
|
|
683
|
+
CoordinationType$1.FEATURE_AGGREGATION_STRATEGY,
|
|
684
|
+
// Annotation shapes are specific to a view's coordinate system.
|
|
685
|
+
CoordinationType$1.ANNOTATION_SHAPES
|
|
671
686
|
];
|
|
672
687
|
const COMPONENT_COORDINATION_TYPES = {
|
|
673
688
|
[ViewType$1.NEUROGLANCER]: [
|
|
@@ -759,7 +774,14 @@ const COMPONENT_COORDINATION_TYPES = {
|
|
|
759
774
|
CoordinationType$1.EMBEDDING_CONTOURS_FILLED,
|
|
760
775
|
CoordinationType$1.EMBEDDING_CONTOUR_PERCENTILES,
|
|
761
776
|
CoordinationType$1.CONTOUR_COLOR_ENCODING,
|
|
762
|
-
CoordinationType$1.CONTOUR_COLOR
|
|
777
|
+
CoordinationType$1.CONTOUR_COLOR,
|
|
778
|
+
CoordinationType$1.ANNOTATION_STORY,
|
|
779
|
+
CoordinationType$1.ANNOTATION_SHAPES,
|
|
780
|
+
CoordinationType$1.ANNOTATION_FRAME_INDEX,
|
|
781
|
+
CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
|
|
782
|
+
CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
|
|
783
|
+
CoordinationType$1.ANNOTATION_EDITABLE,
|
|
784
|
+
CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
|
|
763
785
|
],
|
|
764
786
|
[ViewType$1.DUAL_SCATTERPLOT]: [
|
|
765
787
|
CoordinationType$1.DATASET,
|
|
@@ -875,7 +897,14 @@ const COMPONENT_COORDINATION_TYPES = {
|
|
|
875
897
|
CoordinationType$1.ADDITIONAL_OBS_SETS,
|
|
876
898
|
CoordinationType$1.MOLECULE_HIGHLIGHT,
|
|
877
899
|
CoordinationType$1.TOOLTIPS_VISIBLE,
|
|
878
|
-
CoordinationType$1.PHOTOMETRIC_INTERPRETATION
|
|
900
|
+
CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
|
|
901
|
+
CoordinationType$1.ANNOTATION_STORY,
|
|
902
|
+
CoordinationType$1.ANNOTATION_SHAPES,
|
|
903
|
+
CoordinationType$1.ANNOTATION_FRAME_INDEX,
|
|
904
|
+
CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
|
|
905
|
+
CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
|
|
906
|
+
CoordinationType$1.ANNOTATION_EDITABLE,
|
|
907
|
+
CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
|
|
879
908
|
],
|
|
880
909
|
[ViewType$1.SPATIAL_BETA]: [
|
|
881
910
|
CoordinationType$1.META_COORDINATION_SCOPES,
|
|
@@ -953,7 +982,27 @@ const COMPONENT_COORDINATION_TYPES = {
|
|
|
953
982
|
CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
|
|
954
983
|
CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
|
|
955
984
|
CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
|
|
956
|
-
CoordinationType$1.PHOTOMETRIC_INTERPRETATION
|
|
985
|
+
CoordinationType$1.PHOTOMETRIC_INTERPRETATION,
|
|
986
|
+
CoordinationType$1.ANNOTATION_STORY,
|
|
987
|
+
CoordinationType$1.ANNOTATION_SHAPES,
|
|
988
|
+
CoordinationType$1.ANNOTATION_FRAME_INDEX,
|
|
989
|
+
CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
|
|
990
|
+
CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
|
|
991
|
+
CoordinationType$1.ANNOTATION_EDITABLE,
|
|
992
|
+
CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
|
|
993
|
+
],
|
|
994
|
+
[ViewType$1.ANNOTATION_CONTROLLER]: [
|
|
995
|
+
CoordinationType$1.DATASET,
|
|
996
|
+
CoordinationType$1.ANNOTATION_STORY,
|
|
997
|
+
CoordinationType$1.ANNOTATION_FRAME_INDEX,
|
|
998
|
+
CoordinationType$1.ANNOTATION_OVERLAY_VISIBLE,
|
|
999
|
+
CoordinationType$1.ANNOTATION_TRANSITION_DURATION,
|
|
1000
|
+
CoordinationType$1.ANNOTATION_EDITABLE,
|
|
1001
|
+
CoordinationType$1.ANNOTATION_SEMANTIC_ZOOM
|
|
1002
|
+
// Note: the annotation controller also needs to read the coordination state
|
|
1003
|
+
// of all other views/coordination types via the full config.
|
|
1004
|
+
// Note: we get/set the CoordinationType.ANNOTATION_SHAPES from the full config,
|
|
1005
|
+
// as this info is view-specific rather than global to the story.
|
|
957
1006
|
],
|
|
958
1007
|
[ViewType$1.HEATMAP]: [
|
|
959
1008
|
CoordinationType$1.DATASET,
|
|
@@ -8679,7 +8728,7 @@ const latestFileDefSchema = z.object({
|
|
|
8679
8728
|
options: fileOptionsSchema.optional(),
|
|
8680
8729
|
requestInit: requestInit.optional(),
|
|
8681
8730
|
// New: file def can have coordinationValues.
|
|
8682
|
-
coordinationValues: z.record(z.
|
|
8731
|
+
coordinationValues: z.record(z.any()).optional()
|
|
8683
8732
|
});
|
|
8684
8733
|
const datasetsSchema1_0_13 = z.array(z.object({
|
|
8685
8734
|
uid: z.string(),
|
|
@@ -8710,7 +8759,8 @@ const configSchema1_0_16 = configSchema1_0_13.extend({
|
|
|
8710
8759
|
h: z.number().int().optional(),
|
|
8711
8760
|
// Updates coordinationScopes and coordinationScopesBy
|
|
8712
8761
|
coordinationScopes: componentCoordinationScopes.optional(),
|
|
8713
|
-
coordinationScopesBy: componentCoordinationScopesBy.optional()
|
|
8762
|
+
coordinationScopesBy: componentCoordinationScopesBy.optional(),
|
|
8763
|
+
coordinationValues: z.record(z.any()).optional()
|
|
8714
8764
|
}))
|
|
8715
8765
|
});
|
|
8716
8766
|
const configSchema1_0_17 = configSchema1_0_16.extend({
|
|
@@ -11795,6 +11845,124 @@ z.object({
|
|
|
11795
11845
|
radius: z.number(),
|
|
11796
11846
|
opacity: z.number()
|
|
11797
11847
|
});
|
|
11848
|
+
const shapeBaseObj = z.object({
|
|
11849
|
+
uid: z.string(),
|
|
11850
|
+
text: z.string().optional(),
|
|
11851
|
+
strokeColor: z.array(z.number()).length(3).optional(),
|
|
11852
|
+
strokeWidth: z.number().optional(),
|
|
11853
|
+
// SVG-style dash pattern, e.g. "10 5" or "10 20 30 10". "none" or omitted = solid.
|
|
11854
|
+
strokeDashArray: z.string().optional(),
|
|
11855
|
+
visible: z.boolean().optional()
|
|
11856
|
+
// TODO: define unit modes for x and y axes
|
|
11857
|
+
// ("pixels" vs "normalized" vs "physical" etc.)
|
|
11858
|
+
// TODO: a coordinate system identifier (e.g., "DeckGL" for now,
|
|
11859
|
+
// but a coordinate system from OME-NGFF/SpatialData eventually?)
|
|
11860
|
+
});
|
|
11861
|
+
const rectangleShapeObj = shapeBaseObj.extend({
|
|
11862
|
+
type: z.literal("rectangle"),
|
|
11863
|
+
// OME-XML field names verbatim (upper-left origin)
|
|
11864
|
+
x: z.number(),
|
|
11865
|
+
y: z.number(),
|
|
11866
|
+
width: z.number(),
|
|
11867
|
+
height: z.number(),
|
|
11868
|
+
fillColor: z.array(z.number()).length(3).optional(),
|
|
11869
|
+
fillOpacity: z.number().optional()
|
|
11870
|
+
});
|
|
11871
|
+
const lineShapeObj = shapeBaseObj.extend({
|
|
11872
|
+
type: z.literal("line"),
|
|
11873
|
+
// OME-XML field names verbatim
|
|
11874
|
+
x1: z.number(),
|
|
11875
|
+
y1: z.number(),
|
|
11876
|
+
x2: z.number(),
|
|
11877
|
+
y2: z.number(),
|
|
11878
|
+
markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
|
|
11879
|
+
markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional(),
|
|
11880
|
+
textPosition: z.enum(["start", "middle", "end"]).optional(),
|
|
11881
|
+
textBufferPx: z.number().optional()
|
|
11882
|
+
});
|
|
11883
|
+
const ellipseShapeObj = shapeBaseObj.extend({
|
|
11884
|
+
type: z.literal("ellipse"),
|
|
11885
|
+
// OME-XML field names verbatim (centre point + radii)
|
|
11886
|
+
x1: z.number(),
|
|
11887
|
+
y1: z.number(),
|
|
11888
|
+
radiusX: z.number(),
|
|
11889
|
+
radiusY: z.number(),
|
|
11890
|
+
fillColor: z.array(z.number()).length(3).optional(),
|
|
11891
|
+
fillOpacity: z.number().optional()
|
|
11892
|
+
});
|
|
11893
|
+
const polygonShapeObj = shapeBaseObj.extend({
|
|
11894
|
+
type: z.literal("polygon"),
|
|
11895
|
+
// OME-XML: array of [x, y] coordinate pairs, closed automatically
|
|
11896
|
+
points: z.array(z.tuple([z.number(), z.number()])),
|
|
11897
|
+
fillColor: z.array(z.number()).length(3).optional(),
|
|
11898
|
+
fillOpacity: z.number().optional()
|
|
11899
|
+
});
|
|
11900
|
+
const polylineShapeObj = shapeBaseObj.extend({
|
|
11901
|
+
type: z.literal("polyline"),
|
|
11902
|
+
// OME-XML: array of [x, y] coordinate pairs, open (not closed)
|
|
11903
|
+
points: z.array(z.tuple([z.number(), z.number()])),
|
|
11904
|
+
markerStart: z.enum(["Arrow", "Tick"]).nullable().optional(),
|
|
11905
|
+
markerEnd: z.enum(["Arrow", "Tick"]).nullable().optional()
|
|
11906
|
+
});
|
|
11907
|
+
const annotationShapeObj = z.discriminatedUnion("type", [
|
|
11908
|
+
rectangleShapeObj,
|
|
11909
|
+
lineShapeObj,
|
|
11910
|
+
ellipseShapeObj,
|
|
11911
|
+
polygonShapeObj,
|
|
11912
|
+
polylineShapeObj
|
|
11913
|
+
]);
|
|
11914
|
+
z.array(annotationShapeObj);
|
|
11915
|
+
const annotationFrameObj = z.object({
|
|
11916
|
+
uid: z.string(),
|
|
11917
|
+
title: z.string().optional(),
|
|
11918
|
+
description: z.string().optional(),
|
|
11919
|
+
descriptionType: z.enum(["text", "markdown"]).optional(),
|
|
11920
|
+
// A frame can define per-view: coordinationValues
|
|
11921
|
+
// (if the view's state should not be coordinated with other views)
|
|
11922
|
+
// or per-view coordinationScopes/coordinationScopesBy
|
|
11923
|
+
// (if at this frame, the view should be coordinated with other views).
|
|
11924
|
+
// We can also define a frame-level coordination space,
|
|
11925
|
+
// which will be merged with the global coordination space.
|
|
11926
|
+
// TODO: datasets
|
|
11927
|
+
// TODO: coordinationSpace
|
|
11928
|
+
layout: z.array(
|
|
11929
|
+
// Note: for now, we will infer view objects which have a uid
|
|
11930
|
+
// that is present in the global layout, and do NOT have x/y/w/h defined,
|
|
11931
|
+
// to mean that in this frame, the layout and set of views is unchanged
|
|
11932
|
+
// from the global layout.
|
|
11933
|
+
// This will allow each frame to omit the full list of views from the layout,
|
|
11934
|
+
// and only specify the views whose coordination state is changing in this frame.
|
|
11935
|
+
// If a frame includes a view with a uid that is not present
|
|
11936
|
+
// in the global layout, then that view will be added to the layout at this frame.
|
|
11937
|
+
// This frame should also define x/y/w/h for all views,
|
|
11938
|
+
// since it will otherwise be ambiguous how to layout the updated set of views
|
|
11939
|
+
// for this frame.
|
|
11940
|
+
z.object({
|
|
11941
|
+
// The view UID. If this view uid is not present in the global layout,
|
|
11942
|
+
// it will be added to the layout at this frame,
|
|
11943
|
+
// and will need to have its coordination values initialized to their defaults
|
|
11944
|
+
// for any that were not fully specified.
|
|
11945
|
+
uid: z.string(),
|
|
11946
|
+
coordinationValues: z.record(
|
|
11947
|
+
z.string(),
|
|
11948
|
+
// The coordination type name, e.g. "embeddingType"
|
|
11949
|
+
z.any()
|
|
11950
|
+
).optional()
|
|
11951
|
+
// TODO: support coordinationScopes/coordinationScopesBy for per-view coordination
|
|
11952
|
+
// at this frame.
|
|
11953
|
+
// TODO: view x/y/w/h once we support view layout changes per-frame.
|
|
11954
|
+
})
|
|
11955
|
+
).optional()
|
|
11956
|
+
});
|
|
11957
|
+
z.object({
|
|
11958
|
+
// TODO: schema version for the story schema?
|
|
11959
|
+
// Same as current Vitessce schema version?
|
|
11960
|
+
uid: z.string(),
|
|
11961
|
+
title: z.string().optional(),
|
|
11962
|
+
description: z.string().optional(),
|
|
11963
|
+
descriptionType: z.enum(["text", "markdown"]).optional(),
|
|
11964
|
+
frames: z.array(annotationFrameObj)
|
|
11965
|
+
});
|
|
11798
11966
|
const SETS_DATATYPE_OBS = "obs";
|
|
11799
11967
|
const HIERARCHICAL_SCHEMAS = {
|
|
11800
11968
|
latestVersion: "0.1.3"
|
|
@@ -21745,7 +21913,7 @@ var values$5 = Object.values || function(obj) {
|
|
|
21745
21913
|
return obj[k];
|
|
21746
21914
|
});
|
|
21747
21915
|
};
|
|
21748
|
-
var defaultProps$
|
|
21916
|
+
var defaultProps$Q = {
|
|
21749
21917
|
component: "div",
|
|
21750
21918
|
childFactory: function childFactory(child) {
|
|
21751
21919
|
return child;
|
|
@@ -21872,7 +22040,7 @@ TransitionGroup.propTypes = {
|
|
|
21872
22040
|
*/
|
|
21873
22041
|
childFactory: _pt.func
|
|
21874
22042
|
};
|
|
21875
|
-
TransitionGroup.defaultProps = defaultProps$
|
|
22043
|
+
TransitionGroup.defaultProps = defaultProps$Q;
|
|
21876
22044
|
const UNINITIALIZED = {};
|
|
21877
22045
|
function useLazyRef(init2, initArg) {
|
|
21878
22046
|
const ref2 = React.useRef(UNINITIALIZED);
|
|
@@ -82094,6 +82262,12 @@ function multiply$3(out, a2, b2) {
|
|
|
82094
82262
|
out[2] = a2[2] * b2[2];
|
|
82095
82263
|
return out;
|
|
82096
82264
|
}
|
|
82265
|
+
function distance$3(a2, b2) {
|
|
82266
|
+
var x2 = b2[0] - a2[0];
|
|
82267
|
+
var y2 = b2[1] - a2[1];
|
|
82268
|
+
var z2 = b2[2] - a2[2];
|
|
82269
|
+
return Math.hypot(x2, y2, z2);
|
|
82270
|
+
}
|
|
82097
82271
|
function squaredLength$2(a2) {
|
|
82098
82272
|
var x2 = a2[0];
|
|
82099
82273
|
var y2 = a2[1];
|
|
@@ -82217,6 +82391,7 @@ function angle$3(a2, b2) {
|
|
|
82217
82391
|
}
|
|
82218
82392
|
var sub = subtract;
|
|
82219
82393
|
var mul = multiply$3;
|
|
82394
|
+
var dist$1 = distance$3;
|
|
82220
82395
|
var len = length$5;
|
|
82221
82396
|
var sqrLen = squaredLength$2;
|
|
82222
82397
|
(function() {
|
|
@@ -96687,7 +96862,7 @@ function noop$7() {
|
|
|
96687
96862
|
const getCursor = ({
|
|
96688
96863
|
isDragging
|
|
96689
96864
|
}) => isDragging ? "grabbing" : "grab";
|
|
96690
|
-
const defaultProps$
|
|
96865
|
+
const defaultProps$P = {
|
|
96691
96866
|
id: "",
|
|
96692
96867
|
width: "100%",
|
|
96693
96868
|
height: "100%",
|
|
@@ -96818,7 +96993,7 @@ class Deck {
|
|
|
96818
96993
|
this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
|
|
96819
96994
|
});
|
|
96820
96995
|
this.props = {
|
|
96821
|
-
...defaultProps$
|
|
96996
|
+
...defaultProps$P,
|
|
96822
96997
|
...props
|
|
96823
96998
|
};
|
|
96824
96999
|
props = this.props;
|
|
@@ -97320,7 +97495,7 @@ class Deck {
|
|
|
97320
97495
|
metrics.gpuMemory = memoryStats.get("GPU Memory").count;
|
|
97321
97496
|
}
|
|
97322
97497
|
}
|
|
97323
|
-
_defineProperty$3(Deck, "defaultProps", defaultProps$
|
|
97498
|
+
_defineProperty$3(Deck, "defaultProps", defaultProps$P);
|
|
97324
97499
|
_defineProperty$3(Deck, "VERSION", deckGlobal.VERSION);
|
|
97325
97500
|
class ShaderAttribute {
|
|
97326
97501
|
constructor(dataColumn, opts2) {
|
|
@@ -100075,7 +100250,7 @@ const areViewportsEqual = memoize$2(({
|
|
|
100075
100250
|
return oldViewport.equals(viewport2);
|
|
100076
100251
|
});
|
|
100077
100252
|
let pickingColorCache = new Uint8ClampedArray(0);
|
|
100078
|
-
const defaultProps$
|
|
100253
|
+
const defaultProps$O = {
|
|
100079
100254
|
data: {
|
|
100080
100255
|
type: "data",
|
|
100081
100256
|
value: EMPTY_ARRAY$1,
|
|
@@ -100950,7 +101125,7 @@ class Layer extends Component {
|
|
|
100950
101125
|
this.setNeedsUpdate();
|
|
100951
101126
|
}
|
|
100952
101127
|
}
|
|
100953
|
-
_defineProperty$3(Layer, "defaultProps", defaultProps$
|
|
101128
|
+
_defineProperty$3(Layer, "defaultProps", defaultProps$O);
|
|
100954
101129
|
_defineProperty$3(Layer, "layerName", "Layer");
|
|
100955
101130
|
const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
|
|
100956
101131
|
class CompositeLayer extends Layer {
|
|
@@ -101986,6 +102161,124 @@ const esm$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
101986
102161
|
project32,
|
|
101987
102162
|
shadow
|
|
101988
102163
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
102164
|
+
const dashShaders = {
|
|
102165
|
+
inject: {
|
|
102166
|
+
"vs:#decl": "\nattribute vec2 instanceDashArrays;\nattribute float instanceDashOffsets;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n",
|
|
102167
|
+
"vs:#main-end": "\nvDashArray = instanceDashArrays;\nvDashOffset = instanceDashOffsets / width.x;\n",
|
|
102168
|
+
"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",
|
|
102169
|
+
"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"
|
|
102170
|
+
}
|
|
102171
|
+
};
|
|
102172
|
+
const offsetShaders = {
|
|
102173
|
+
inject: {
|
|
102174
|
+
"vs:#decl": "\nattribute float instanceOffsets;\n",
|
|
102175
|
+
"vs:DECKGL_FILTER_SIZE": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n size *= offsetWidth;\n",
|
|
102176
|
+
"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",
|
|
102177
|
+
"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"
|
|
102178
|
+
}
|
|
102179
|
+
};
|
|
102180
|
+
const defaultProps$N = {
|
|
102181
|
+
getDashArray: {
|
|
102182
|
+
type: "accessor",
|
|
102183
|
+
value: [0, 0]
|
|
102184
|
+
},
|
|
102185
|
+
getOffset: {
|
|
102186
|
+
type: "accessor",
|
|
102187
|
+
value: 0
|
|
102188
|
+
},
|
|
102189
|
+
dashJustified: false,
|
|
102190
|
+
dashGapPickable: false
|
|
102191
|
+
};
|
|
102192
|
+
class PathStyleExtension extends LayerExtension {
|
|
102193
|
+
constructor({
|
|
102194
|
+
dash = false,
|
|
102195
|
+
offset: offset2 = false,
|
|
102196
|
+
highPrecisionDash = false
|
|
102197
|
+
} = {}) {
|
|
102198
|
+
super({
|
|
102199
|
+
dash: dash || highPrecisionDash,
|
|
102200
|
+
offset: offset2,
|
|
102201
|
+
highPrecisionDash
|
|
102202
|
+
});
|
|
102203
|
+
}
|
|
102204
|
+
isEnabled(layer) {
|
|
102205
|
+
return "pathTesselator" in layer.state;
|
|
102206
|
+
}
|
|
102207
|
+
getShaders(extension2) {
|
|
102208
|
+
if (!extension2.isEnabled(this)) {
|
|
102209
|
+
return null;
|
|
102210
|
+
}
|
|
102211
|
+
let result = {};
|
|
102212
|
+
if (extension2.opts.dash) {
|
|
102213
|
+
result = mergeShaders(result, dashShaders);
|
|
102214
|
+
}
|
|
102215
|
+
if (extension2.opts.offset) {
|
|
102216
|
+
result = mergeShaders(result, offsetShaders);
|
|
102217
|
+
}
|
|
102218
|
+
return result;
|
|
102219
|
+
}
|
|
102220
|
+
initializeState(context2, extension2) {
|
|
102221
|
+
const attributeManager = this.getAttributeManager();
|
|
102222
|
+
if (!attributeManager || !extension2.isEnabled(this)) {
|
|
102223
|
+
return;
|
|
102224
|
+
}
|
|
102225
|
+
if (extension2.opts.dash) {
|
|
102226
|
+
attributeManager.addInstanced({
|
|
102227
|
+
instanceDashArrays: {
|
|
102228
|
+
size: 2,
|
|
102229
|
+
accessor: "getDashArray"
|
|
102230
|
+
}
|
|
102231
|
+
});
|
|
102232
|
+
}
|
|
102233
|
+
if (extension2.opts.highPrecisionDash) {
|
|
102234
|
+
attributeManager.addInstanced({
|
|
102235
|
+
instanceDashOffsets: {
|
|
102236
|
+
size: 1,
|
|
102237
|
+
accessor: "getPath",
|
|
102238
|
+
transform: extension2.getDashOffsets.bind(this)
|
|
102239
|
+
}
|
|
102240
|
+
});
|
|
102241
|
+
}
|
|
102242
|
+
if (extension2.opts.offset) {
|
|
102243
|
+
attributeManager.addInstanced({
|
|
102244
|
+
instanceOffsets: {
|
|
102245
|
+
size: 1,
|
|
102246
|
+
accessor: "getOffset"
|
|
102247
|
+
}
|
|
102248
|
+
});
|
|
102249
|
+
}
|
|
102250
|
+
}
|
|
102251
|
+
updateState(params2, extension2) {
|
|
102252
|
+
if (!extension2.isEnabled(this)) {
|
|
102253
|
+
return;
|
|
102254
|
+
}
|
|
102255
|
+
const uniforms = {};
|
|
102256
|
+
if (extension2.opts.dash) {
|
|
102257
|
+
uniforms.dashAlignMode = this.props.dashJustified ? 1 : 0;
|
|
102258
|
+
uniforms.dashGapPickable = Boolean(this.props.dashGapPickable);
|
|
102259
|
+
}
|
|
102260
|
+
this.state.model.setUniforms(uniforms);
|
|
102261
|
+
}
|
|
102262
|
+
getDashOffsets(path2) {
|
|
102263
|
+
const result = [0];
|
|
102264
|
+
const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
|
|
102265
|
+
const isNested2 = Array.isArray(path2[0]);
|
|
102266
|
+
const geometrySize = isNested2 ? path2.length : path2.length / positionSize;
|
|
102267
|
+
let p;
|
|
102268
|
+
let prevP;
|
|
102269
|
+
for (let i2 = 0; i2 < geometrySize - 1; i2++) {
|
|
102270
|
+
p = isNested2 ? path2[i2] : path2.slice(i2 * positionSize, i2 * positionSize + positionSize);
|
|
102271
|
+
p = this.projectPosition(p);
|
|
102272
|
+
if (i2 > 0) {
|
|
102273
|
+
result[i2] = result[i2 - 1] + dist$1(prevP, p);
|
|
102274
|
+
}
|
|
102275
|
+
prevP = p;
|
|
102276
|
+
}
|
|
102277
|
+
return result;
|
|
102278
|
+
}
|
|
102279
|
+
}
|
|
102280
|
+
_defineProperty$3(PathStyleExtension, "defaultProps", defaultProps$N);
|
|
102281
|
+
_defineProperty$3(PathStyleExtension, "extensionName", "PathStyleExtension");
|
|
101989
102282
|
const defaultProps$M = {
|
|
101990
102283
|
clipBounds: [0, 0, 1, 1]
|
|
101991
102284
|
};
|
|
@@ -174341,22 +174634,22 @@ function addDecoder(cases2, importFn) {
|
|
|
174341
174634
|
}
|
|
174342
174635
|
cases2.forEach((c2) => registry$1.set(c2, importFn));
|
|
174343
174636
|
}
|
|
174344
|
-
addDecoder([void 0, 1], () => import("./raw-
|
|
174345
|
-
addDecoder(5, () => import("./lzw-
|
|
174637
|
+
addDecoder([void 0, 1], () => import("./raw-Dg8kCOnj.js").then((m2) => m2.default));
|
|
174638
|
+
addDecoder(5, () => import("./lzw-DkbMJx1b.js").then((m2) => m2.default));
|
|
174346
174639
|
addDecoder(6, () => {
|
|
174347
174640
|
throw new Error("old style JPEG compression is not supported.");
|
|
174348
174641
|
});
|
|
174349
|
-
addDecoder(7, () => import("./jpeg-
|
|
174350
|
-
addDecoder([8, 32946], () => import("./deflate
|
|
174351
|
-
addDecoder(32773, () => import("./packbits-
|
|
174642
|
+
addDecoder(7, () => import("./jpeg-DhNGUcND.js").then((m2) => m2.default));
|
|
174643
|
+
addDecoder([8, 32946], () => import("./deflate-BG2HUqgg.js").then((m2) => m2.default));
|
|
174644
|
+
addDecoder(32773, () => import("./packbits-8pX5TxcK.js").then((m2) => m2.default));
|
|
174352
174645
|
addDecoder(
|
|
174353
174646
|
34887,
|
|
174354
|
-
() => import("./lerc-
|
|
174647
|
+
() => import("./lerc-CeaVG0Hd.js").then(async (m2) => {
|
|
174355
174648
|
await m2.zstd.init();
|
|
174356
174649
|
return m2;
|
|
174357
174650
|
}).then((m2) => m2.default)
|
|
174358
174651
|
);
|
|
174359
|
-
addDecoder(50001, () => import("./webimage-
|
|
174652
|
+
addDecoder(50001, () => import("./webimage-DqIQm4cj.js").then((m2) => m2.default));
|
|
174360
174653
|
function decodeRowAcc(row, stride) {
|
|
174361
174654
|
let length2 = row.length - stride;
|
|
174362
174655
|
let offset2 = 0;
|
|
@@ -181559,7 +181852,7 @@ function padColors({ colors: colors2, channelsVisible }) {
|
|
|
181559
181852
|
).reduce((acc, val) => acc.concat(val), []);
|
|
181560
181853
|
return paddedColors;
|
|
181561
181854
|
}
|
|
181562
|
-
const defaultProps$3$
|
|
181855
|
+
const defaultProps$3$2 = {
|
|
181563
181856
|
colors: { type: "array", value: null, compare: true },
|
|
181564
181857
|
opacity: { type: "number", value: 1, compare: true },
|
|
181565
181858
|
transparentColor: { type: "array", value: null, compare: true },
|
|
@@ -181576,9 +181869,9 @@ const ColorPaletteExtension = class extends LayerExtension {
|
|
|
181576
181869
|
const {
|
|
181577
181870
|
colors: colors2,
|
|
181578
181871
|
channelsVisible,
|
|
181579
|
-
opacity: opacity2 = defaultProps$3$
|
|
181580
|
-
transparentColor = defaultProps$3$
|
|
181581
|
-
useTransparentColor = defaultProps$3$
|
|
181872
|
+
opacity: opacity2 = defaultProps$3$2.opacity.value,
|
|
181873
|
+
transparentColor = defaultProps$3$2.transparentColor.value,
|
|
181874
|
+
useTransparentColor = defaultProps$3$2.useTransparentColor.value
|
|
181582
181875
|
} = this.props;
|
|
181583
181876
|
const paddedColors = padColors({
|
|
181584
181877
|
channelsVisible: channelsVisible || this.selections.map(() => true),
|
|
@@ -181594,7 +181887,7 @@ const ColorPaletteExtension = class extends LayerExtension {
|
|
|
181594
181887
|
}
|
|
181595
181888
|
};
|
|
181596
181889
|
ColorPaletteExtension.extensionName = "ColorPaletteExtension";
|
|
181597
|
-
ColorPaletteExtension.defaultProps = defaultProps$3$
|
|
181890
|
+
ColorPaletteExtension.defaultProps = defaultProps$3$2;
|
|
181598
181891
|
const fs$4 = `// lens bounds for ellipse
|
|
181599
181892
|
uniform float majorLensAxis;
|
|
181600
181893
|
uniform float minorLensAxis;
|
|
@@ -182889,7 +183182,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
|
|
|
182889
183182
|
};
|
|
182890
183183
|
MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
|
|
182891
183184
|
MultiscaleImageLayer.defaultProps = defaultProps$4;
|
|
182892
|
-
const defaultProps$3 = {
|
|
183185
|
+
const defaultProps$3$1 = {
|
|
182893
183186
|
pickable: { type: "boolean", value: true, compare: true },
|
|
182894
183187
|
loader: {
|
|
182895
183188
|
type: "object",
|
|
@@ -182976,7 +183269,7 @@ const OverviewLayer = class extends CompositeLayer {
|
|
|
182976
183269
|
}
|
|
182977
183270
|
};
|
|
182978
183271
|
OverviewLayer.layerName = "OverviewLayer";
|
|
182979
|
-
OverviewLayer.defaultProps = defaultProps$3;
|
|
183272
|
+
OverviewLayer.defaultProps = defaultProps$3$1;
|
|
182980
183273
|
function getPosition(boundingBox, position2, length2) {
|
|
182981
183274
|
const viewWidth2 = boundingBox[2][0] - boundingBox[0][0];
|
|
182982
183275
|
const viewHeight2 = boundingBox[2][1] - boundingBox[0][1];
|
|
@@ -183964,7 +184257,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
|
|
|
183964
184257
|
}
|
|
183965
184258
|
return newArr;
|
|
183966
184259
|
}
|
|
183967
|
-
const defaultProps$
|
|
184260
|
+
const defaultProps$3 = {
|
|
183968
184261
|
hoveredCell: { type: "number", value: null, compare: true },
|
|
183969
184262
|
// We do not want to deep-compare cellColorData,
|
|
183970
184263
|
// as it is potentially a TypedArray with millions of elements.
|
|
@@ -184081,7 +184374,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
|
|
|
184081
184374
|
}
|
|
184082
184375
|
};
|
|
184083
184376
|
BitmaskLayer$1.layerName = "BitmaskLayer";
|
|
184084
|
-
BitmaskLayer$1.defaultProps = defaultProps$
|
|
184377
|
+
BitmaskLayer$1.defaultProps = defaultProps$3;
|
|
184085
184378
|
const vs = `
|
|
184086
184379
|
#define SHADER_NAME bitmask-layer-vertex-shader
|
|
184087
184380
|
|
|
@@ -184423,7 +184716,7 @@ function isEqualShallow(prevArr, nextArr) {
|
|
|
184423
184716
|
}
|
|
184424
184717
|
return prevArr === nextArr;
|
|
184425
184718
|
}
|
|
184426
|
-
const defaultProps$
|
|
184719
|
+
const defaultProps$2 = {
|
|
184427
184720
|
channelStrokeWidths: { type: "array", value: null, compare: true },
|
|
184428
184721
|
channelsFilled: { type: "array", value: null, compare: true },
|
|
184429
184722
|
channelOpacities: { type: "array", value: null, compare: true },
|
|
@@ -184687,7 +184980,7 @@ class BitmaskLayer2 extends XRLayer {
|
|
|
184687
184980
|
}
|
|
184688
184981
|
}
|
|
184689
184982
|
BitmaskLayer2.layerName = "BitmaskLayer";
|
|
184690
|
-
BitmaskLayer2.defaultProps = defaultProps$
|
|
184983
|
+
BitmaskLayer2.defaultProps = defaultProps$2;
|
|
184691
184984
|
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$2 = 9007199254740991, POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, MAX$1 = 1e9;
|
|
184692
184985
|
function clone$1(configObject) {
|
|
184693
184986
|
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 = {
|
|
@@ -187630,7 +187923,7 @@ function ringArea(coords) {
|
|
|
187630
187923
|
return total * FACTOR;
|
|
187631
187924
|
}
|
|
187632
187925
|
const DEFAULT_THRESHOLD = 1;
|
|
187633
|
-
const defaultProps = {
|
|
187926
|
+
const defaultProps$1 = {
|
|
187634
187927
|
// for text
|
|
187635
187928
|
obsSetPath: { type: "object" },
|
|
187636
187929
|
sampleSetPath: { type: "object" },
|
|
@@ -187804,7 +188097,1077 @@ class ContourLayerWithText extends ContourLayer {
|
|
|
187804
188097
|
}
|
|
187805
188098
|
}
|
|
187806
188099
|
ContourLayerWithText.layerName = "ContourLayerWithText";
|
|
187807
|
-
ContourLayerWithText.defaultProps = defaultProps;
|
|
188100
|
+
ContourLayerWithText.defaultProps = defaultProps$1;
|
|
188101
|
+
const ARROW_SCREEN_PX = 14;
|
|
188102
|
+
const LABEL_FONT_FAMILY = '"Roboto", "Helvetica", "Arial", sans-serif';
|
|
188103
|
+
const LABEL_FONT_WEIGHT = "bold";
|
|
188104
|
+
const LABEL_FONT_SIZE = 14;
|
|
188105
|
+
const RATIO_CLUSTER = 0.1;
|
|
188106
|
+
const RATIO_DOT = 0.3;
|
|
188107
|
+
const RATIO_GEO_FADE = 0.55;
|
|
188108
|
+
const RATIO_TIPS = 0.7;
|
|
188109
|
+
const RATIO_LABEL = 0.55;
|
|
188110
|
+
const RATIO_LABEL_FULL = 0.75;
|
|
188111
|
+
function textBgColor(strokeColor) {
|
|
188112
|
+
const [r3, g2, b2] = strokeColor;
|
|
188113
|
+
const lum = (0.299 * r3 + 0.587 * g2 + 0.114 * b2) / 255;
|
|
188114
|
+
return lum > 0.45 ? [20, 20, 20, 210] : [245, 245, 245, 210];
|
|
188115
|
+
}
|
|
188116
|
+
function parseDashArray(strokeDashArray) {
|
|
188117
|
+
if (!strokeDashArray || strokeDashArray === "none")
|
|
188118
|
+
return null;
|
|
188119
|
+
const nums = strokeDashArray.trim().split(/\s+/).map(Number).filter((n2) => !Number.isNaN(n2) && n2 >= 0);
|
|
188120
|
+
return nums.length >= 2 ? [nums[0], nums[1]] : null;
|
|
188121
|
+
}
|
|
188122
|
+
function computeEllipsePolygon(cx, cy, rx, ry, numSegments = 64) {
|
|
188123
|
+
const pts = [];
|
|
188124
|
+
for (let i2 = 0; i2 < numSegments; i2++) {
|
|
188125
|
+
const angle2 = 2 * Math.PI * i2 / numSegments;
|
|
188126
|
+
pts.push([cx + rx * Math.cos(angle2), cy + ry * Math.sin(angle2)]);
|
|
188127
|
+
}
|
|
188128
|
+
return pts;
|
|
188129
|
+
}
|
|
188130
|
+
function createPreviewLayer(inProgress, hoverCoord, strokeColor = [255, 255, 0]) {
|
|
188131
|
+
if (!inProgress || inProgress.vertices.length === 0)
|
|
188132
|
+
return null;
|
|
188133
|
+
const { type: type2, vertices } = inProgress;
|
|
188134
|
+
const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
|
|
188135
|
+
const previewColor = [...strokeColor, 160];
|
|
188136
|
+
const cursor2 = hoverCoord ?? vertices[vertices.length - 1];
|
|
188137
|
+
if (type2 === "rectangle" && vertices.length === 1) {
|
|
188138
|
+
const [ax, ay] = vertices[0];
|
|
188139
|
+
const [bx, by] = cursor2;
|
|
188140
|
+
const path2 = [[ax, ay], [bx, ay], [bx, by], [ax, by], [ax, ay]];
|
|
188141
|
+
return new PathLayer({
|
|
188142
|
+
...base2,
|
|
188143
|
+
id: "annotation-preview-rectangle",
|
|
188144
|
+
data: [{ path: path2 }],
|
|
188145
|
+
getPath: (d) => d.path,
|
|
188146
|
+
getColor: previewColor,
|
|
188147
|
+
getWidth: 1,
|
|
188148
|
+
widthUnits: "pixels",
|
|
188149
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188150
|
+
getDashArray: [8, 4]
|
|
188151
|
+
});
|
|
188152
|
+
}
|
|
188153
|
+
if (type2 === "line" && vertices.length === 1) {
|
|
188154
|
+
const path2 = [vertices[0], cursor2];
|
|
188155
|
+
return new PathLayer({
|
|
188156
|
+
...base2,
|
|
188157
|
+
id: "annotation-preview-line",
|
|
188158
|
+
data: [{ path: path2 }],
|
|
188159
|
+
getPath: (d) => d.path,
|
|
188160
|
+
getColor: previewColor,
|
|
188161
|
+
getWidth: 1,
|
|
188162
|
+
widthUnits: "pixels",
|
|
188163
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188164
|
+
getDashArray: [8, 4]
|
|
188165
|
+
});
|
|
188166
|
+
}
|
|
188167
|
+
if (type2 === "ellipse" && vertices.length === 1) {
|
|
188168
|
+
const [cx, cy] = vertices[0];
|
|
188169
|
+
const [ex, ey] = cursor2;
|
|
188170
|
+
const rx = Math.abs(ex - cx);
|
|
188171
|
+
const ry = Math.abs(ey - cy);
|
|
188172
|
+
if (rx < 1 && ry < 1)
|
|
188173
|
+
return null;
|
|
188174
|
+
const pts = computeEllipsePolygon(cx, cy, Math.max(rx, 1), Math.max(ry, 1));
|
|
188175
|
+
const path2 = [...pts, pts[0]];
|
|
188176
|
+
return new PathLayer({
|
|
188177
|
+
...base2,
|
|
188178
|
+
id: "annotation-preview-ellipse",
|
|
188179
|
+
data: [{ path: path2 }],
|
|
188180
|
+
getPath: (d) => d.path,
|
|
188181
|
+
getColor: previewColor,
|
|
188182
|
+
getWidth: 1,
|
|
188183
|
+
widthUnits: "pixels",
|
|
188184
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188185
|
+
getDashArray: [8, 4]
|
|
188186
|
+
});
|
|
188187
|
+
}
|
|
188188
|
+
if ((type2 === "polygon" || type2 === "polyline") && vertices.length >= 1) {
|
|
188189
|
+
const path2 = [...vertices, cursor2];
|
|
188190
|
+
if (type2 === "polygon" && vertices.length >= 2)
|
|
188191
|
+
path2.push(vertices[0]);
|
|
188192
|
+
return new PathLayer({
|
|
188193
|
+
...base2,
|
|
188194
|
+
id: `annotation-preview-${type2}`,
|
|
188195
|
+
data: [{ path: path2 }],
|
|
188196
|
+
getPath: (d) => d.path,
|
|
188197
|
+
getColor: previewColor,
|
|
188198
|
+
getWidth: 1,
|
|
188199
|
+
widthUnits: "pixels",
|
|
188200
|
+
jointRounded: true,
|
|
188201
|
+
capRounded: true,
|
|
188202
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188203
|
+
getDashArray: [8, 4]
|
|
188204
|
+
});
|
|
188205
|
+
}
|
|
188206
|
+
return null;
|
|
188207
|
+
}
|
|
188208
|
+
function computeTickCap(tipX, tipY, dirX, dirY, dataSize) {
|
|
188209
|
+
const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
188210
|
+
if (len2 === 0)
|
|
188211
|
+
return null;
|
|
188212
|
+
const ux = dirX / len2;
|
|
188213
|
+
const uy = dirY / len2;
|
|
188214
|
+
const px2 = -uy;
|
|
188215
|
+
const py2 = ux;
|
|
188216
|
+
const half = dataSize * 0.55;
|
|
188217
|
+
return [
|
|
188218
|
+
[tipX + px2 * half, tipY + py2 * half],
|
|
188219
|
+
[tipX - px2 * half, tipY - py2 * half]
|
|
188220
|
+
];
|
|
188221
|
+
}
|
|
188222
|
+
function computeArrowhead(tipX, tipY, dirX, dirY, dataSize) {
|
|
188223
|
+
const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
188224
|
+
if (len2 === 0)
|
|
188225
|
+
return null;
|
|
188226
|
+
const ux = dirX / len2;
|
|
188227
|
+
const uy = dirY / len2;
|
|
188228
|
+
const px2 = -uy;
|
|
188229
|
+
const py2 = ux;
|
|
188230
|
+
const halfBase = dataSize * 0.4;
|
|
188231
|
+
const bx = tipX - ux * dataSize;
|
|
188232
|
+
const by = tipY - uy * dataSize;
|
|
188233
|
+
return [
|
|
188234
|
+
[tipX, tipY],
|
|
188235
|
+
[bx + px2 * halfBase, by + py2 * halfBase],
|
|
188236
|
+
[bx - px2 * halfBase, by - py2 * halfBase]
|
|
188237
|
+
];
|
|
188238
|
+
}
|
|
188239
|
+
function fmtCommas(n2) {
|
|
188240
|
+
return Math.round(n2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
188241
|
+
}
|
|
188242
|
+
function getMeasurementLabel(shape2, physicalPixelSize, viewType = ViewType$1.SPATIAL) {
|
|
188243
|
+
const pps = physicalPixelSize;
|
|
188244
|
+
const px2 = pps?.x ?? 1;
|
|
188245
|
+
const py2 = pps?.y ?? 1;
|
|
188246
|
+
const unit2 = pps ? pps.unit ?? "" : null;
|
|
188247
|
+
const hasPhys = !!pps;
|
|
188248
|
+
const isEmbedding = viewType === ViewType$1.SCATTERPLOT;
|
|
188249
|
+
const fmtDist = (d) => {
|
|
188250
|
+
if (hasPhys)
|
|
188251
|
+
return `${d.toFixed(2)} ${unit2}`;
|
|
188252
|
+
if (isEmbedding)
|
|
188253
|
+
return d.toFixed(2);
|
|
188254
|
+
return `${fmtCommas(d)} px`;
|
|
188255
|
+
};
|
|
188256
|
+
const fmtArea = (a2) => {
|
|
188257
|
+
if (hasPhys)
|
|
188258
|
+
return `${a2.toFixed(2)} ${unit2}²`;
|
|
188259
|
+
if (isEmbedding)
|
|
188260
|
+
return a2.toFixed(2);
|
|
188261
|
+
return `${fmtCommas(a2)} px²`;
|
|
188262
|
+
};
|
|
188263
|
+
if (shape2.type === "line") {
|
|
188264
|
+
const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
|
|
188265
|
+
const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
|
|
188266
|
+
const dist2 = hasPhys ? Math.sqrt((dx * px2) ** 2 + (dy * py2) ** 2) : Math.sqrt(dx * dx + dy * dy);
|
|
188267
|
+
return fmtDist(dist2);
|
|
188268
|
+
}
|
|
188269
|
+
if (shape2.type === "rectangle") {
|
|
188270
|
+
return fmtArea(hasPhys ? Math.abs(shape2.width ?? 0) * px2 * Math.abs(shape2.height ?? 0) * py2 : Math.abs((shape2.width ?? 0) * (shape2.height ?? 0)));
|
|
188271
|
+
}
|
|
188272
|
+
if (shape2.type === "ellipse") {
|
|
188273
|
+
const rx = Math.abs(shape2.radiusX ?? 0);
|
|
188274
|
+
const ry = Math.abs(shape2.radiusY ?? 0);
|
|
188275
|
+
return fmtArea(hasPhys ? Math.PI * rx * px2 * ry * py2 : Math.PI * rx * ry);
|
|
188276
|
+
}
|
|
188277
|
+
if (shape2.type === "polygon" && shape2.points?.length >= 3) {
|
|
188278
|
+
const pts = shape2.points;
|
|
188279
|
+
let shoelace = 0;
|
|
188280
|
+
for (let i2 = 0; i2 < pts.length; i2++) {
|
|
188281
|
+
const [ax, ay] = pts[i2];
|
|
188282
|
+
const [bx, by] = pts[(i2 + 1) % pts.length];
|
|
188283
|
+
shoelace += (hasPhys ? ax * px2 : ax) * (hasPhys ? by * py2 : by) - (hasPhys ? bx * px2 : bx) * (hasPhys ? ay * py2 : ay);
|
|
188284
|
+
}
|
|
188285
|
+
return fmtArea(Math.abs(shoelace / 2));
|
|
188286
|
+
}
|
|
188287
|
+
if (shape2.type === "polyline" && shape2.points?.length >= 2) {
|
|
188288
|
+
let total = 0;
|
|
188289
|
+
for (let i2 = 0; i2 < shape2.points.length - 1; i2++) {
|
|
188290
|
+
const [ax, ay] = shape2.points[i2];
|
|
188291
|
+
const [bx, by] = shape2.points[i2 + 1];
|
|
188292
|
+
total += hasPhys ? Math.sqrt(((bx - ax) * px2) ** 2 + ((by - ay) * py2) ** 2) : Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2);
|
|
188293
|
+
}
|
|
188294
|
+
return fmtDist(total);
|
|
188295
|
+
}
|
|
188296
|
+
return null;
|
|
188297
|
+
}
|
|
188298
|
+
function pickBelowPerp(ux, uy) {
|
|
188299
|
+
const rp = [uy, -ux];
|
|
188300
|
+
const lp = [-uy, ux];
|
|
188301
|
+
return rp[1] > lp[1] || rp[1] === lp[1] && rp[0] > lp[0] ? rp : lp;
|
|
188302
|
+
}
|
|
188303
|
+
function readableAngle(deg) {
|
|
188304
|
+
let a2 = deg;
|
|
188305
|
+
if (a2 > 90)
|
|
188306
|
+
a2 -= 180;
|
|
188307
|
+
if (a2 < -90)
|
|
188308
|
+
a2 += 180;
|
|
188309
|
+
return a2;
|
|
188310
|
+
}
|
|
188311
|
+
function getShapeCentroid(shape2) {
|
|
188312
|
+
if (shape2.type === "rectangle") {
|
|
188313
|
+
return [(shape2.x ?? 0) + (shape2.width ?? 0) / 2, (shape2.y ?? 0) + (shape2.height ?? 0) / 2];
|
|
188314
|
+
}
|
|
188315
|
+
if (shape2.type === "line") {
|
|
188316
|
+
return [((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2, ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2];
|
|
188317
|
+
}
|
|
188318
|
+
if (shape2.type === "ellipse") {
|
|
188319
|
+
return [shape2.x1 ?? 0, shape2.y1 ?? 0];
|
|
188320
|
+
}
|
|
188321
|
+
if ((shape2.type === "polygon" || shape2.type === "polyline") && shape2.points?.length >= 1) {
|
|
188322
|
+
const mx = shape2.points.reduce((s2, p) => s2 + p[0], 0) / shape2.points.length;
|
|
188323
|
+
const my = shape2.points.reduce((s2, p) => s2 + p[1], 0) / shape2.points.length;
|
|
188324
|
+
return [mx, my];
|
|
188325
|
+
}
|
|
188326
|
+
return [0, 0];
|
|
188327
|
+
}
|
|
188328
|
+
function computeClusters(shapeList, zoom2, cellPx = 50) {
|
|
188329
|
+
const cellSize = cellPx / 2 ** Math.floor(zoom2);
|
|
188330
|
+
const cells = /* @__PURE__ */ new Map();
|
|
188331
|
+
shapeList.forEach(({ shape: shape2 }) => {
|
|
188332
|
+
const [cx, cy] = getShapeCentroid(shape2);
|
|
188333
|
+
const key2 = `${Math.floor(cx / cellSize)},${Math.floor(cy / cellSize)}`;
|
|
188334
|
+
if (!cells.has(key2)) {
|
|
188335
|
+
cells.set(key2, { sumX: 0, sumY: 0, count: 0, color: shape2.strokeColor ?? [255, 255, 255] });
|
|
188336
|
+
}
|
|
188337
|
+
const c2 = cells.get(key2);
|
|
188338
|
+
c2.sumX += cx;
|
|
188339
|
+
c2.sumY += cy;
|
|
188340
|
+
c2.count++;
|
|
188341
|
+
});
|
|
188342
|
+
return Array.from(cells.values()).map((c2) => ({
|
|
188343
|
+
position: [c2.sumX / c2.count, c2.sumY / c2.count, 0],
|
|
188344
|
+
count: c2.count,
|
|
188345
|
+
color: c2.color
|
|
188346
|
+
}));
|
|
188347
|
+
}
|
|
188348
|
+
function createAnnotationLayers(shapes = [], zoom2 = 0, selectedShapeUid = null, physicalPixelSize = null, authoredZoom = null, semanticZoom = true, viewType = ViewType$1.SPATIAL) {
|
|
188349
|
+
const selectionLayers = [];
|
|
188350
|
+
if (selectedShapeUid) {
|
|
188351
|
+
const sel = shapes.find((s2) => s2.uid === selectedShapeUid);
|
|
188352
|
+
if (sel) {
|
|
188353
|
+
const { uid: sUid, type: sType, strokeWidth: sStrokeWidth = 3 } = sel;
|
|
188354
|
+
const haloColor = [255, 220, 50, 70];
|
|
188355
|
+
const haloWidth = Math.max(sStrokeWidth + 8, 10);
|
|
188356
|
+
const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
|
|
188357
|
+
if (sType === "rectangle") {
|
|
188358
|
+
const { x: x2, y: y2, width: width2, height: height2 } = sel;
|
|
188359
|
+
selectionLayers.push(new PathLayer({
|
|
188360
|
+
...base2,
|
|
188361
|
+
id: `annotation-select-${sUid}`,
|
|
188362
|
+
data: [{
|
|
188363
|
+
path: [
|
|
188364
|
+
[x2, y2],
|
|
188365
|
+
[x2 + width2, y2],
|
|
188366
|
+
[x2 + width2, y2 + height2],
|
|
188367
|
+
[x2, y2 + height2],
|
|
188368
|
+
[x2, y2]
|
|
188369
|
+
]
|
|
188370
|
+
}],
|
|
188371
|
+
getPath: (d) => d.path,
|
|
188372
|
+
getColor: haloColor,
|
|
188373
|
+
getWidth: haloWidth,
|
|
188374
|
+
widthUnits: "pixels",
|
|
188375
|
+
jointRounded: true,
|
|
188376
|
+
capRounded: true
|
|
188377
|
+
}));
|
|
188378
|
+
}
|
|
188379
|
+
if (sType === "line") {
|
|
188380
|
+
const { x1: x12, y1: y12, x2, y2 } = sel;
|
|
188381
|
+
selectionLayers.push(new PathLayer({
|
|
188382
|
+
...base2,
|
|
188383
|
+
id: `annotation-select-${sUid}`,
|
|
188384
|
+
data: [{ path: [[x12, y12], [x2, y2]] }],
|
|
188385
|
+
getPath: (d) => d.path,
|
|
188386
|
+
getColor: haloColor,
|
|
188387
|
+
getWidth: haloWidth,
|
|
188388
|
+
widthUnits: "pixels",
|
|
188389
|
+
capRounded: true
|
|
188390
|
+
}));
|
|
188391
|
+
}
|
|
188392
|
+
if (sType === "ellipse") {
|
|
188393
|
+
const polygon2 = computeEllipsePolygon(sel.x1, sel.y1, sel.radiusX, sel.radiusY);
|
|
188394
|
+
selectionLayers.push(new PathLayer({
|
|
188395
|
+
...base2,
|
|
188396
|
+
id: `annotation-select-${sUid}`,
|
|
188397
|
+
data: [{ path: [...polygon2, polygon2[0]] }],
|
|
188398
|
+
getPath: (d) => d.path,
|
|
188399
|
+
getColor: haloColor,
|
|
188400
|
+
getWidth: haloWidth,
|
|
188401
|
+
widthUnits: "pixels",
|
|
188402
|
+
jointRounded: true
|
|
188403
|
+
}));
|
|
188404
|
+
}
|
|
188405
|
+
if (sType === "polygon" && sel.points?.length >= 3) {
|
|
188406
|
+
selectionLayers.push(new PathLayer({
|
|
188407
|
+
...base2,
|
|
188408
|
+
id: `annotation-select-${sUid}`,
|
|
188409
|
+
data: [{ path: [...sel.points, sel.points[0]] }],
|
|
188410
|
+
getPath: (d) => d.path,
|
|
188411
|
+
getColor: haloColor,
|
|
188412
|
+
getWidth: haloWidth,
|
|
188413
|
+
widthUnits: "pixels",
|
|
188414
|
+
jointRounded: true
|
|
188415
|
+
}));
|
|
188416
|
+
}
|
|
188417
|
+
if (sType === "polyline" && sel.points?.length >= 2) {
|
|
188418
|
+
selectionLayers.push(new PathLayer({
|
|
188419
|
+
...base2,
|
|
188420
|
+
id: `annotation-select-${sUid}`,
|
|
188421
|
+
data: [{ path: sel.points }],
|
|
188422
|
+
getPath: (d) => d.path,
|
|
188423
|
+
getColor: haloColor,
|
|
188424
|
+
getWidth: haloWidth,
|
|
188425
|
+
widthUnits: "pixels",
|
|
188426
|
+
jointRounded: true,
|
|
188427
|
+
capRounded: true
|
|
188428
|
+
}));
|
|
188429
|
+
}
|
|
188430
|
+
}
|
|
188431
|
+
}
|
|
188432
|
+
const layers = [];
|
|
188433
|
+
const dotShapes = [];
|
|
188434
|
+
const clusterDotShapes = [];
|
|
188435
|
+
shapes.forEach((shape2, i2) => {
|
|
188436
|
+
const { uid: uid2, type: type2, strokeColor = [255, 255, 255], strokeWidth = 3, strokeDashArray } = shape2;
|
|
188437
|
+
const isSelected = uid2 === selectedShapeUid;
|
|
188438
|
+
let shapeOpacity = 1;
|
|
188439
|
+
let tipsOpacity = 1;
|
|
188440
|
+
let labelOpacity = 0;
|
|
188441
|
+
if (isSelected || !semanticZoom || authoredZoom === null) {
|
|
188442
|
+
tipsOpacity = 1;
|
|
188443
|
+
labelOpacity = 1;
|
|
188444
|
+
} else {
|
|
188445
|
+
const zoomRatio = 2 ** (zoom2 - authoredZoom);
|
|
188446
|
+
if (zoomRatio < RATIO_CLUSTER) {
|
|
188447
|
+
clusterDotShapes.push({ shape: shape2 });
|
|
188448
|
+
return;
|
|
188449
|
+
}
|
|
188450
|
+
if (zoomRatio < RATIO_DOT) {
|
|
188451
|
+
dotShapes.push({ shape: shape2, alpha: 200 });
|
|
188452
|
+
return;
|
|
188453
|
+
}
|
|
188454
|
+
if (zoomRatio < RATIO_GEO_FADE) {
|
|
188455
|
+
const t4 = (zoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
|
|
188456
|
+
shapeOpacity = t4;
|
|
188457
|
+
dotShapes.push({ shape: shape2, alpha: Math.round((1 - t4) * 200) });
|
|
188458
|
+
}
|
|
188459
|
+
tipsOpacity = zoomRatio >= RATIO_TIPS ? shapeOpacity : Math.max(0, (zoomRatio - RATIO_GEO_FADE) / (RATIO_TIPS - RATIO_GEO_FADE) * shapeOpacity);
|
|
188460
|
+
if (zoomRatio >= RATIO_LABEL_FULL) {
|
|
188461
|
+
labelOpacity = shapeOpacity;
|
|
188462
|
+
} else if (zoomRatio >= RATIO_LABEL) {
|
|
188463
|
+
labelOpacity = (zoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL) * shapeOpacity;
|
|
188464
|
+
}
|
|
188465
|
+
}
|
|
188466
|
+
const arrowDataSize = Math.max(ARROW_SCREEN_PX, strokeWidth * 4) / 2 ** zoom2;
|
|
188467
|
+
const base2 = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: shapeOpacity };
|
|
188468
|
+
const tipsBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: tipsOpacity };
|
|
188469
|
+
const labelBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: labelOpacity };
|
|
188470
|
+
const labelBgProps = shape2.labelBackground ? {
|
|
188471
|
+
background: true,
|
|
188472
|
+
getBackgroundColor: textBgColor(strokeColor),
|
|
188473
|
+
backgroundPadding: [3, 1, 3, 2]
|
|
188474
|
+
} : {};
|
|
188475
|
+
const labelProps = { ...labelBgProps };
|
|
188476
|
+
const dashArray = parseDashArray(strokeDashArray);
|
|
188477
|
+
const dashExt = [new PathStyleExtension({ dash: true })];
|
|
188478
|
+
const getDash = dashArray ?? [0, 0];
|
|
188479
|
+
if (type2 === "rectangle") {
|
|
188480
|
+
const { x: x2, y: y2, width: width2, height: height2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
|
|
188481
|
+
const filled = fillOpacity > 0;
|
|
188482
|
+
const rectPolygon = [[x2, y2], [x2 + width2, y2], [x2 + width2, y2 + height2], [x2, y2 + height2]];
|
|
188483
|
+
layers.push(new PolygonLayer({
|
|
188484
|
+
...base2,
|
|
188485
|
+
id: `annotation-rect-${uid2}-${i2}`,
|
|
188486
|
+
data: [{ polygon: rectPolygon }],
|
|
188487
|
+
getPolygon: (d) => d.polygon,
|
|
188488
|
+
filled,
|
|
188489
|
+
stroked: true,
|
|
188490
|
+
getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
|
|
188491
|
+
getLineColor: strokeColor,
|
|
188492
|
+
getLineWidth: strokeWidth,
|
|
188493
|
+
lineWidthUnits: "pixels",
|
|
188494
|
+
...dashArray ? {
|
|
188495
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188496
|
+
getDashArray: dashArray
|
|
188497
|
+
} : {}
|
|
188498
|
+
}));
|
|
188499
|
+
if (shape2.text && labelOpacity > 0) {
|
|
188500
|
+
layers.push(new TextLayer({
|
|
188501
|
+
...labelBase,
|
|
188502
|
+
...labelProps,
|
|
188503
|
+
id: `annotation-rect-text-${uid2}-${i2}`,
|
|
188504
|
+
data: [{ position: [x2, y2], text: shape2.text }],
|
|
188505
|
+
getPosition: (d) => d.position,
|
|
188506
|
+
getText: (d) => d.text,
|
|
188507
|
+
getColor: strokeColor,
|
|
188508
|
+
getSize: LABEL_FONT_SIZE,
|
|
188509
|
+
sizeUnits: "pixels",
|
|
188510
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
188511
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
188512
|
+
getPixelOffset: [3, -7],
|
|
188513
|
+
getTextAnchor: "start",
|
|
188514
|
+
getAlignmentBaseline: "bottom"
|
|
188515
|
+
}));
|
|
188516
|
+
}
|
|
188517
|
+
}
|
|
188518
|
+
if (type2 === "line") {
|
|
188519
|
+
const { x1: x12, y1: y12, x2, y2, markerStart, markerEnd } = shape2;
|
|
188520
|
+
const dx = x2 - x12;
|
|
188521
|
+
const dy = y2 - y12;
|
|
188522
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
188523
|
+
const ux = len2 > 0 ? dx / len2 : 0;
|
|
188524
|
+
const uy = len2 > 0 ? dy / len2 : 0;
|
|
188525
|
+
const srcX = markerStart === "Arrow" ? x12 + ux * arrowDataSize : x12;
|
|
188526
|
+
const srcY = markerStart === "Arrow" ? y12 + uy * arrowDataSize : y12;
|
|
188527
|
+
const tgtX = markerEnd === "Arrow" ? x2 - ux * arrowDataSize : x2;
|
|
188528
|
+
const tgtY = markerEnd === "Arrow" ? y2 - uy * arrowDataSize : y2;
|
|
188529
|
+
layers.push(new PathLayer({
|
|
188530
|
+
...base2,
|
|
188531
|
+
id: `annotation-line-${uid2}-${i2}`,
|
|
188532
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188533
|
+
getDashArray: dashArray ?? [0, 0],
|
|
188534
|
+
data: [{ path: [[srcX, srcY], [tgtX, tgtY]] }],
|
|
188535
|
+
getPath: (d) => d.path,
|
|
188536
|
+
getColor: strokeColor,
|
|
188537
|
+
getWidth: strokeWidth,
|
|
188538
|
+
widthUnits: "pixels",
|
|
188539
|
+
capRounded: true
|
|
188540
|
+
}));
|
|
188541
|
+
if (markerEnd === "Arrow" && tipsOpacity > 0) {
|
|
188542
|
+
const head = computeArrowhead(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
|
|
188543
|
+
if (head) {
|
|
188544
|
+
layers.push(new PolygonLayer({
|
|
188545
|
+
...tipsBase,
|
|
188546
|
+
id: `annotation-end-arrow-${uid2}-${i2}`,
|
|
188547
|
+
data: [{ polygon: head }],
|
|
188548
|
+
getPolygon: (d) => d.polygon,
|
|
188549
|
+
filled: true,
|
|
188550
|
+
stroked: false,
|
|
188551
|
+
getFillColor: strokeColor
|
|
188552
|
+
}));
|
|
188553
|
+
}
|
|
188554
|
+
}
|
|
188555
|
+
if (markerStart === "Arrow" && tipsOpacity > 0) {
|
|
188556
|
+
const head = computeArrowhead(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
|
|
188557
|
+
if (head) {
|
|
188558
|
+
layers.push(new PolygonLayer({
|
|
188559
|
+
...tipsBase,
|
|
188560
|
+
id: `annotation-start-arrow-${uid2}-${i2}`,
|
|
188561
|
+
data: [{ polygon: head }],
|
|
188562
|
+
getPolygon: (d) => d.polygon,
|
|
188563
|
+
filled: true,
|
|
188564
|
+
stroked: false,
|
|
188565
|
+
getFillColor: strokeColor
|
|
188566
|
+
}));
|
|
188567
|
+
}
|
|
188568
|
+
}
|
|
188569
|
+
if (markerEnd === "Tick" && tipsOpacity > 0) {
|
|
188570
|
+
const tick2 = computeTickCap(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
|
|
188571
|
+
if (tick2) {
|
|
188572
|
+
layers.push(new PathLayer({
|
|
188573
|
+
...tipsBase,
|
|
188574
|
+
id: `annotation-end-tick-${uid2}-${i2}`,
|
|
188575
|
+
data: [{ path: tick2 }],
|
|
188576
|
+
getPath: (d) => d.path,
|
|
188577
|
+
getColor: strokeColor,
|
|
188578
|
+
getWidth: strokeWidth,
|
|
188579
|
+
widthUnits: "pixels",
|
|
188580
|
+
capRounded: true
|
|
188581
|
+
}));
|
|
188582
|
+
}
|
|
188583
|
+
}
|
|
188584
|
+
if (markerStart === "Tick" && tipsOpacity > 0) {
|
|
188585
|
+
const tick2 = computeTickCap(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
|
|
188586
|
+
if (tick2) {
|
|
188587
|
+
layers.push(new PathLayer({
|
|
188588
|
+
...tipsBase,
|
|
188589
|
+
id: `annotation-start-tick-${uid2}-${i2}`,
|
|
188590
|
+
data: [{ path: tick2 }],
|
|
188591
|
+
getPath: (d) => d.path,
|
|
188592
|
+
getColor: strokeColor,
|
|
188593
|
+
getWidth: strokeWidth,
|
|
188594
|
+
widthUnits: "pixels",
|
|
188595
|
+
capRounded: true
|
|
188596
|
+
}));
|
|
188597
|
+
}
|
|
188598
|
+
}
|
|
188599
|
+
if (shape2.text) {
|
|
188600
|
+
const pos = shape2.textPosition ?? "start";
|
|
188601
|
+
let textX;
|
|
188602
|
+
let textY;
|
|
188603
|
+
if (pos === "start") {
|
|
188604
|
+
textX = x12;
|
|
188605
|
+
textY = y12;
|
|
188606
|
+
} else if (pos === "end") {
|
|
188607
|
+
textX = x2;
|
|
188608
|
+
textY = y2;
|
|
188609
|
+
} else {
|
|
188610
|
+
textX = (x12 + x2) / 2;
|
|
188611
|
+
textY = (y12 + y2) / 2;
|
|
188612
|
+
}
|
|
188613
|
+
let pixelOffset = [0, 0];
|
|
188614
|
+
let textAnchor = "middle";
|
|
188615
|
+
let alignmentBaseline = "center";
|
|
188616
|
+
if (pos !== "middle") {
|
|
188617
|
+
const dxT = x2 - x12;
|
|
188618
|
+
const dyT = y2 - y12;
|
|
188619
|
+
const lenT = Math.sqrt(dxT * dxT + dyT * dyT);
|
|
188620
|
+
if (lenT > 0) {
|
|
188621
|
+
const uxT = dxT / lenT;
|
|
188622
|
+
const uyT = dyT / lenT;
|
|
188623
|
+
const sign2 = pos === "start" ? -1 : 1;
|
|
188624
|
+
const bufferPx = shape2.textBufferPx ?? 8;
|
|
188625
|
+
const offsetX = sign2 * uxT * bufferPx;
|
|
188626
|
+
const offsetY = sign2 * uyT * bufferPx;
|
|
188627
|
+
pixelOffset = [offsetX, offsetY];
|
|
188628
|
+
const absX = Math.abs(offsetX);
|
|
188629
|
+
const absY = Math.abs(offsetY);
|
|
188630
|
+
if (absX >= absY) {
|
|
188631
|
+
textAnchor = offsetX > 0 ? "start" : "end";
|
|
188632
|
+
}
|
|
188633
|
+
if (absY >= absX) {
|
|
188634
|
+
alignmentBaseline = offsetY > 0 ? "top" : "bottom";
|
|
188635
|
+
}
|
|
188636
|
+
}
|
|
188637
|
+
} else if (len2 > 0) {
|
|
188638
|
+
const belowPerp = pickBelowPerp(ux, uy);
|
|
188639
|
+
const bufferPx = shape2.textBufferPx ?? 14;
|
|
188640
|
+
pixelOffset = [-belowPerp[0] * bufferPx, -belowPerp[1] * bufferPx];
|
|
188641
|
+
textAnchor = "middle";
|
|
188642
|
+
alignmentBaseline = "center";
|
|
188643
|
+
}
|
|
188644
|
+
const middleAngle = pos === "middle" && len2 > 0 ? -readableAngle(Math.atan2(dy, dx) * 180 / Math.PI) : null;
|
|
188645
|
+
if (labelOpacity <= 0)
|
|
188646
|
+
return;
|
|
188647
|
+
layers.push(new TextLayer({
|
|
188648
|
+
...labelBase,
|
|
188649
|
+
...labelProps,
|
|
188650
|
+
id: `annotation-line-text-${uid2}-${i2}`,
|
|
188651
|
+
data: [{ position: [textX, textY], text: shape2.text }],
|
|
188652
|
+
getPosition: (d) => d.position,
|
|
188653
|
+
getText: (d) => d.text,
|
|
188654
|
+
getColor: strokeColor,
|
|
188655
|
+
getSize: LABEL_FONT_SIZE,
|
|
188656
|
+
sizeUnits: "pixels",
|
|
188657
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
188658
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
188659
|
+
getPixelOffset: pixelOffset,
|
|
188660
|
+
getTextAnchor: textAnchor,
|
|
188661
|
+
getAlignmentBaseline: alignmentBaseline,
|
|
188662
|
+
...middleAngle !== null && { getAngle: middleAngle }
|
|
188663
|
+
}));
|
|
188664
|
+
}
|
|
188665
|
+
}
|
|
188666
|
+
if (type2 === "ellipse") {
|
|
188667
|
+
const { x1: x12, y1: y12, radiusX, radiusY, fillColor = strokeColor, fillOpacity = 0 } = shape2;
|
|
188668
|
+
const polygon2 = computeEllipsePolygon(x12, y12, radiusX, radiusY);
|
|
188669
|
+
const filled = fillOpacity > 0;
|
|
188670
|
+
layers.push(new PolygonLayer({
|
|
188671
|
+
...base2,
|
|
188672
|
+
id: `annotation-ellipse-${uid2}-${i2}`,
|
|
188673
|
+
data: [{ polygon: polygon2 }],
|
|
188674
|
+
getPolygon: (d) => d.polygon,
|
|
188675
|
+
filled,
|
|
188676
|
+
stroked: true,
|
|
188677
|
+
getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
|
|
188678
|
+
getLineColor: strokeColor,
|
|
188679
|
+
getLineWidth: strokeWidth,
|
|
188680
|
+
lineWidthUnits: "pixels",
|
|
188681
|
+
...dashArray ? {
|
|
188682
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
188683
|
+
getDashArray: dashArray
|
|
188684
|
+
} : {}
|
|
188685
|
+
}));
|
|
188686
|
+
if (shape2.text && labelOpacity > 0) {
|
|
188687
|
+
layers.push(new TextLayer({
|
|
188688
|
+
...labelBase,
|
|
188689
|
+
...labelProps,
|
|
188690
|
+
id: `annotation-ellipse-text-${uid2}-${i2}`,
|
|
188691
|
+
data: [{ position: [x12, y12 - radiusY], text: shape2.text }],
|
|
188692
|
+
getPosition: (d) => d.position,
|
|
188693
|
+
getText: (d) => d.text,
|
|
188694
|
+
getColor: strokeColor,
|
|
188695
|
+
getSize: LABEL_FONT_SIZE,
|
|
188696
|
+
sizeUnits: "pixels",
|
|
188697
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
188698
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
188699
|
+
getPixelOffset: [0, -4],
|
|
188700
|
+
getTextAnchor: "middle",
|
|
188701
|
+
getAlignmentBaseline: "bottom"
|
|
188702
|
+
}));
|
|
188703
|
+
}
|
|
188704
|
+
}
|
|
188705
|
+
if (type2 === "polygon") {
|
|
188706
|
+
const { points: points2, fillColor = strokeColor, fillOpacity = 0 } = shape2;
|
|
188707
|
+
if (!points2 || points2.length < 3)
|
|
188708
|
+
return;
|
|
188709
|
+
const closedPath = [...points2, points2[0]];
|
|
188710
|
+
if (fillOpacity > 0) {
|
|
188711
|
+
layers.push(new PolygonLayer({
|
|
188712
|
+
...base2,
|
|
188713
|
+
id: `annotation-polygon-fill-${uid2}-${i2}`,
|
|
188714
|
+
data: [{ polygon: points2 }],
|
|
188715
|
+
getPolygon: (d) => d.polygon,
|
|
188716
|
+
stroked: false,
|
|
188717
|
+
filled: true,
|
|
188718
|
+
getFillColor: [...fillColor, Math.round(fillOpacity * 255)]
|
|
188719
|
+
}));
|
|
188720
|
+
}
|
|
188721
|
+
layers.push(new PathLayer({
|
|
188722
|
+
...base2,
|
|
188723
|
+
id: `annotation-polygon-${uid2}-${i2}`,
|
|
188724
|
+
extensions: dashExt,
|
|
188725
|
+
getDashArray: getDash,
|
|
188726
|
+
data: [{ path: closedPath }],
|
|
188727
|
+
getPath: (d) => d.path,
|
|
188728
|
+
getColor: strokeColor,
|
|
188729
|
+
getWidth: strokeWidth,
|
|
188730
|
+
widthUnits: "pixels",
|
|
188731
|
+
jointRounded: true
|
|
188732
|
+
}));
|
|
188733
|
+
if (shape2.text && labelOpacity > 0) {
|
|
188734
|
+
const minX = Math.min(...points2.map((p) => p[0]));
|
|
188735
|
+
const maxX = Math.max(...points2.map((p) => p[0]));
|
|
188736
|
+
const minY = Math.min(...points2.map((p) => p[1]));
|
|
188737
|
+
const topCenterX = (minX + maxX) / 2;
|
|
188738
|
+
layers.push(new TextLayer({
|
|
188739
|
+
...labelBase,
|
|
188740
|
+
...labelProps,
|
|
188741
|
+
id: `annotation-polygon-text-${uid2}-${i2}`,
|
|
188742
|
+
data: [{ position: [topCenterX, minY], text: shape2.text }],
|
|
188743
|
+
getPosition: (d) => d.position,
|
|
188744
|
+
getText: (d) => d.text,
|
|
188745
|
+
getColor: strokeColor,
|
|
188746
|
+
getSize: LABEL_FONT_SIZE,
|
|
188747
|
+
sizeUnits: "pixels",
|
|
188748
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
188749
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
188750
|
+
getPixelOffset: [0, -4],
|
|
188751
|
+
getTextAnchor: "middle",
|
|
188752
|
+
getAlignmentBaseline: "bottom"
|
|
188753
|
+
}));
|
|
188754
|
+
}
|
|
188755
|
+
}
|
|
188756
|
+
if (type2 === "polyline") {
|
|
188757
|
+
const { points: points2, markerStart, markerEnd } = shape2;
|
|
188758
|
+
if (!points2 || points2.length < 2)
|
|
188759
|
+
return;
|
|
188760
|
+
let pathPoints = points2;
|
|
188761
|
+
if (markerStart === "Arrow") {
|
|
188762
|
+
const [x02, y02] = points2[0];
|
|
188763
|
+
const [x12, y12] = points2[1];
|
|
188764
|
+
const dx = x02 - x12;
|
|
188765
|
+
const dy = y02 - y12;
|
|
188766
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
188767
|
+
if (len2 > 0) {
|
|
188768
|
+
const ux = dx / len2;
|
|
188769
|
+
const uy = dy / len2;
|
|
188770
|
+
pathPoints = [[x02 - ux * arrowDataSize, y02 - uy * arrowDataSize], ...pathPoints.slice(1)];
|
|
188771
|
+
}
|
|
188772
|
+
}
|
|
188773
|
+
if (markerEnd === "Arrow") {
|
|
188774
|
+
const last = pathPoints[pathPoints.length - 1];
|
|
188775
|
+
const prev2 = pathPoints[pathPoints.length - 2];
|
|
188776
|
+
const dx = last[0] - prev2[0];
|
|
188777
|
+
const dy = last[1] - prev2[1];
|
|
188778
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
188779
|
+
if (len2 > 0) {
|
|
188780
|
+
const ux = dx / len2;
|
|
188781
|
+
const uy = dy / len2;
|
|
188782
|
+
const shortened = [last[0] - ux * arrowDataSize, last[1] - uy * arrowDataSize];
|
|
188783
|
+
pathPoints = [...pathPoints.slice(0, -1), shortened];
|
|
188784
|
+
}
|
|
188785
|
+
}
|
|
188786
|
+
layers.push(new PathLayer({
|
|
188787
|
+
...base2,
|
|
188788
|
+
id: `annotation-polyline-${uid2}-${i2}`,
|
|
188789
|
+
extensions: dashExt,
|
|
188790
|
+
getDashArray: getDash,
|
|
188791
|
+
data: [{ path: pathPoints }],
|
|
188792
|
+
getPath: (d) => d.path,
|
|
188793
|
+
getColor: strokeColor,
|
|
188794
|
+
getWidth: strokeWidth,
|
|
188795
|
+
widthUnits: "pixels",
|
|
188796
|
+
jointRounded: true,
|
|
188797
|
+
capRounded: true
|
|
188798
|
+
}));
|
|
188799
|
+
if (markerStart === "Arrow" && tipsOpacity > 0) {
|
|
188800
|
+
const [x02, y02] = points2[0];
|
|
188801
|
+
const [x12, y12] = points2[1];
|
|
188802
|
+
const head = computeArrowhead(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
|
|
188803
|
+
if (head) {
|
|
188804
|
+
layers.push(new PolygonLayer({
|
|
188805
|
+
...tipsBase,
|
|
188806
|
+
id: `annotation-polyline-start-arrow-${uid2}-${i2}`,
|
|
188807
|
+
data: [{ polygon: head }],
|
|
188808
|
+
getPolygon: (d) => d.polygon,
|
|
188809
|
+
filled: true,
|
|
188810
|
+
stroked: false,
|
|
188811
|
+
getFillColor: strokeColor
|
|
188812
|
+
}));
|
|
188813
|
+
}
|
|
188814
|
+
}
|
|
188815
|
+
if (markerEnd === "Arrow" && tipsOpacity > 0) {
|
|
188816
|
+
const last = points2[points2.length - 1];
|
|
188817
|
+
const prev2 = points2[points2.length - 2];
|
|
188818
|
+
const dxArrow = last[0] - prev2[0];
|
|
188819
|
+
const dyArrow = last[1] - prev2[1];
|
|
188820
|
+
const head = computeArrowhead(last[0], last[1], dxArrow, dyArrow, arrowDataSize);
|
|
188821
|
+
if (head) {
|
|
188822
|
+
layers.push(new PolygonLayer({
|
|
188823
|
+
...tipsBase,
|
|
188824
|
+
id: `annotation-polyline-end-arrow-${uid2}-${i2}`,
|
|
188825
|
+
data: [{ polygon: head }],
|
|
188826
|
+
getPolygon: (d) => d.polygon,
|
|
188827
|
+
filled: true,
|
|
188828
|
+
stroked: false,
|
|
188829
|
+
getFillColor: strokeColor
|
|
188830
|
+
}));
|
|
188831
|
+
}
|
|
188832
|
+
}
|
|
188833
|
+
if (markerStart === "Tick" && tipsOpacity > 0) {
|
|
188834
|
+
const [x02, y02] = points2[0];
|
|
188835
|
+
const [x12, y12] = points2[1];
|
|
188836
|
+
const tick2 = computeTickCap(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
|
|
188837
|
+
if (tick2) {
|
|
188838
|
+
layers.push(new PathLayer({
|
|
188839
|
+
...tipsBase,
|
|
188840
|
+
id: `annotation-polyline-start-tick-${uid2}-${i2}`,
|
|
188841
|
+
data: [{ path: tick2 }],
|
|
188842
|
+
getPath: (d) => d.path,
|
|
188843
|
+
getColor: strokeColor,
|
|
188844
|
+
getWidth: strokeWidth,
|
|
188845
|
+
widthUnits: "pixels",
|
|
188846
|
+
capRounded: true
|
|
188847
|
+
}));
|
|
188848
|
+
}
|
|
188849
|
+
}
|
|
188850
|
+
if (markerEnd === "Tick" && tipsOpacity > 0) {
|
|
188851
|
+
const last = points2[points2.length - 1];
|
|
188852
|
+
const prev2 = points2[points2.length - 2];
|
|
188853
|
+
const dxTick = last[0] - prev2[0];
|
|
188854
|
+
const dyTick = last[1] - prev2[1];
|
|
188855
|
+
const tick2 = computeTickCap(last[0], last[1], dxTick, dyTick, arrowDataSize);
|
|
188856
|
+
if (tick2) {
|
|
188857
|
+
layers.push(new PathLayer({
|
|
188858
|
+
...tipsBase,
|
|
188859
|
+
id: `annotation-polyline-end-tick-${uid2}-${i2}`,
|
|
188860
|
+
data: [{ path: tick2 }],
|
|
188861
|
+
getPath: (d) => d.path,
|
|
188862
|
+
getColor: strokeColor,
|
|
188863
|
+
getWidth: strokeWidth,
|
|
188864
|
+
widthUnits: "pixels",
|
|
188865
|
+
capRounded: true
|
|
188866
|
+
}));
|
|
188867
|
+
}
|
|
188868
|
+
}
|
|
188869
|
+
if (shape2.text) {
|
|
188870
|
+
const pos = shape2.textPosition ?? "start";
|
|
188871
|
+
const bufferPx = shape2.textBufferPx ?? 8;
|
|
188872
|
+
let textPt;
|
|
188873
|
+
let dirX;
|
|
188874
|
+
let dirY;
|
|
188875
|
+
if (pos === "end") {
|
|
188876
|
+
const last = points2[points2.length - 1];
|
|
188877
|
+
const prev2 = points2[points2.length - 2];
|
|
188878
|
+
textPt = last;
|
|
188879
|
+
dirX = last[0] - prev2[0];
|
|
188880
|
+
dirY = last[1] - prev2[1];
|
|
188881
|
+
} else if (pos === "middle") {
|
|
188882
|
+
const mx = points2.reduce((s2, p) => s2 + p[0], 0) / points2.length;
|
|
188883
|
+
const my = points2.reduce((s2, p) => s2 + p[1], 0) / points2.length;
|
|
188884
|
+
textPt = [mx, my];
|
|
188885
|
+
dirX = 0;
|
|
188886
|
+
dirY = 0;
|
|
188887
|
+
} else {
|
|
188888
|
+
[textPt] = points2;
|
|
188889
|
+
dirX = points2[0][0] - points2[1][0];
|
|
188890
|
+
dirY = points2[0][1] - points2[1][1];
|
|
188891
|
+
}
|
|
188892
|
+
const [textX, textY] = textPt;
|
|
188893
|
+
const lenT = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
188894
|
+
let polylinePixelOffset = [0, 0];
|
|
188895
|
+
let polylineTextAnchor = "middle";
|
|
188896
|
+
let polylineAlignmentBaseline = pos === "middle" ? "center" : "bottom";
|
|
188897
|
+
if (lenT > 0) {
|
|
188898
|
+
const uxT = dirX / lenT;
|
|
188899
|
+
const uyT = dirY / lenT;
|
|
188900
|
+
const offX = uxT * bufferPx;
|
|
188901
|
+
const offY = uyT * bufferPx;
|
|
188902
|
+
polylinePixelOffset = [offX, offY];
|
|
188903
|
+
if (Math.abs(offX) >= Math.abs(offY)) {
|
|
188904
|
+
polylineTextAnchor = offX > 0 ? "start" : "end";
|
|
188905
|
+
}
|
|
188906
|
+
if (Math.abs(offY) >= Math.abs(offX)) {
|
|
188907
|
+
polylineAlignmentBaseline = offY > 0 ? "top" : "bottom";
|
|
188908
|
+
}
|
|
188909
|
+
}
|
|
188910
|
+
if (labelOpacity <= 0)
|
|
188911
|
+
return;
|
|
188912
|
+
layers.push(new TextLayer({
|
|
188913
|
+
...labelBase,
|
|
188914
|
+
...labelProps,
|
|
188915
|
+
id: `annotation-polyline-text-${uid2}-${i2}`,
|
|
188916
|
+
data: [{ position: [textX, textY], text: shape2.text }],
|
|
188917
|
+
getPosition: (d) => d.position,
|
|
188918
|
+
getText: (d) => d.text,
|
|
188919
|
+
getColor: strokeColor,
|
|
188920
|
+
getSize: LABEL_FONT_SIZE,
|
|
188921
|
+
sizeUnits: "pixels",
|
|
188922
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
188923
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
188924
|
+
getPixelOffset: polylinePixelOffset,
|
|
188925
|
+
getTextAnchor: polylineTextAnchor,
|
|
188926
|
+
getAlignmentBaseline: polylineAlignmentBaseline
|
|
188927
|
+
}));
|
|
188928
|
+
}
|
|
188929
|
+
}
|
|
188930
|
+
});
|
|
188931
|
+
if (dotShapes.length > 0) {
|
|
188932
|
+
layers.push(new ScatterplotLayer({
|
|
188933
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
188934
|
+
id: "annotation-dots",
|
|
188935
|
+
data: dotShapes.map(({ shape: s2, alpha: alpha2 }) => ({
|
|
188936
|
+
position: getShapeCentroid(s2),
|
|
188937
|
+
color: [...s2.strokeColor ?? [255, 255, 255], alpha2]
|
|
188938
|
+
})),
|
|
188939
|
+
getPosition: (d) => d.position,
|
|
188940
|
+
getFillColor: (d) => d.color,
|
|
188941
|
+
getRadius: 4,
|
|
188942
|
+
radiusUnits: "pixels",
|
|
188943
|
+
filled: true,
|
|
188944
|
+
stroked: false
|
|
188945
|
+
}));
|
|
188946
|
+
}
|
|
188947
|
+
if (clusterDotShapes.length > 0) {
|
|
188948
|
+
const clusters = computeClusters(clusterDotShapes, zoom2);
|
|
188949
|
+
layers.push(new ScatterplotLayer({
|
|
188950
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
188951
|
+
id: "annotation-clusters",
|
|
188952
|
+
data: clusters,
|
|
188953
|
+
getPosition: (d) => d.position,
|
|
188954
|
+
getFillColor: (d) => [...d.color, 180],
|
|
188955
|
+
getRadius: (d) => Math.max(6, 4 + Math.sqrt(d.count) * 2),
|
|
188956
|
+
radiusUnits: "pixels",
|
|
188957
|
+
filled: true,
|
|
188958
|
+
stroked: true,
|
|
188959
|
+
getLineColor: (d) => [...d.color, 220],
|
|
188960
|
+
lineWidthMinPixels: 1.5
|
|
188961
|
+
}));
|
|
188962
|
+
const multiClusters = clusters.filter((c2) => c2.count > 1);
|
|
188963
|
+
if (multiClusters.length > 0) {
|
|
188964
|
+
layers.push(new TextLayer({
|
|
188965
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
188966
|
+
id: "annotation-cluster-counts",
|
|
188967
|
+
data: multiClusters,
|
|
188968
|
+
getPosition: (d) => d.position,
|
|
188969
|
+
getText: (d) => String(d.count),
|
|
188970
|
+
getColor: [255, 255, 255],
|
|
188971
|
+
getSize: 10,
|
|
188972
|
+
sizeUnits: "pixels",
|
|
188973
|
+
fontWeight: "bold",
|
|
188974
|
+
getTextAnchor: "middle",
|
|
188975
|
+
getAlignmentBaseline: "center"
|
|
188976
|
+
}));
|
|
188977
|
+
}
|
|
188978
|
+
}
|
|
188979
|
+
const measureLayers = [];
|
|
188980
|
+
shapes.forEach((shape2) => {
|
|
188981
|
+
if (!shape2.showMeasure)
|
|
188982
|
+
return;
|
|
188983
|
+
const mIsSelected = shape2.uid === selectedShapeUid;
|
|
188984
|
+
const label2 = getMeasurementLabel(shape2, physicalPixelSize, viewType);
|
|
188985
|
+
if (!label2)
|
|
188986
|
+
return;
|
|
188987
|
+
const color2 = shape2.strokeColor ?? [255, 255, 255];
|
|
188988
|
+
let mShapeOpacity = 1;
|
|
188989
|
+
let mLabelFactor = 0;
|
|
188990
|
+
if (mIsSelected || !semanticZoom || authoredZoom === null) {
|
|
188991
|
+
mLabelFactor = 1;
|
|
188992
|
+
} else {
|
|
188993
|
+
const mZoomRatio = 2 ** (zoom2 - authoredZoom);
|
|
188994
|
+
if (mZoomRatio < RATIO_DOT)
|
|
188995
|
+
return;
|
|
188996
|
+
if (mZoomRatio < RATIO_GEO_FADE) {
|
|
188997
|
+
mShapeOpacity = (mZoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
|
|
188998
|
+
}
|
|
188999
|
+
if (mZoomRatio >= RATIO_LABEL_FULL) {
|
|
189000
|
+
mLabelFactor = 1;
|
|
189001
|
+
} else if (mZoomRatio >= RATIO_LABEL) {
|
|
189002
|
+
mLabelFactor = (mZoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL);
|
|
189003
|
+
}
|
|
189004
|
+
}
|
|
189005
|
+
const measureOpacity = mShapeOpacity * mLabelFactor;
|
|
189006
|
+
if (measureOpacity <= 0)
|
|
189007
|
+
return;
|
|
189008
|
+
const base2 = {
|
|
189009
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
189010
|
+
opacity: measureOpacity,
|
|
189011
|
+
getText: (d) => d.text,
|
|
189012
|
+
getPosition: (d) => d.position,
|
|
189013
|
+
getColor: color2,
|
|
189014
|
+
getSize: 13,
|
|
189015
|
+
sizeUnits: "pixels",
|
|
189016
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
189017
|
+
fontWeight: "bold",
|
|
189018
|
+
// 'auto' builds the font atlas from the actual rendered characters (e.g. µ, ²)
|
|
189019
|
+
// instead of deck.gl's default ASCII-only atlas.
|
|
189020
|
+
characterSet: "auto",
|
|
189021
|
+
...shape2.measureBackground ? {
|
|
189022
|
+
background: true,
|
|
189023
|
+
getBackgroundColor: textBgColor(color2),
|
|
189024
|
+
backgroundPadding: [3, 1, 3, 2]
|
|
189025
|
+
} : {}
|
|
189026
|
+
};
|
|
189027
|
+
if (shape2.type === "line") {
|
|
189028
|
+
const mx = ((shape2.x1 ?? 0) + (shape2.x2 ?? 0)) / 2;
|
|
189029
|
+
const my = ((shape2.y1 ?? 0) + (shape2.y2 ?? 0)) / 2;
|
|
189030
|
+
const dx = (shape2.x2 ?? 0) - (shape2.x1 ?? 0);
|
|
189031
|
+
const dy = (shape2.y2 ?? 0) - (shape2.y1 ?? 0);
|
|
189032
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
189033
|
+
if (len2 === 0)
|
|
189034
|
+
return;
|
|
189035
|
+
const perp = pickBelowPerp(dx / len2, dy / len2);
|
|
189036
|
+
const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
|
|
189037
|
+
measureLayers.push(new TextLayer({
|
|
189038
|
+
...base2,
|
|
189039
|
+
id: `annotation-measure-${shape2.uid}`,
|
|
189040
|
+
data: [{ position: [mx, my], text: label2 }],
|
|
189041
|
+
getAngle: -angle2,
|
|
189042
|
+
getTextAnchor: "middle",
|
|
189043
|
+
getAlignmentBaseline: "center",
|
|
189044
|
+
getPixelOffset: [perp[0] * 16, perp[1] * 16]
|
|
189045
|
+
}));
|
|
189046
|
+
} else if (shape2.type === "polyline" && shape2.points?.length >= 2) {
|
|
189047
|
+
const pts = shape2.points;
|
|
189048
|
+
const mi = Math.floor((pts.length - 1) / 2);
|
|
189049
|
+
const [ax, ay] = pts[mi];
|
|
189050
|
+
const [bx, by] = pts[mi + 1];
|
|
189051
|
+
const dx = bx - ax;
|
|
189052
|
+
const dy = by - ay;
|
|
189053
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
189054
|
+
if (len2 === 0)
|
|
189055
|
+
return;
|
|
189056
|
+
const perp = pickBelowPerp(dx / len2, dy / len2);
|
|
189057
|
+
const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
|
|
189058
|
+
measureLayers.push(new TextLayer({
|
|
189059
|
+
...base2,
|
|
189060
|
+
id: `annotation-measure-${shape2.uid}`,
|
|
189061
|
+
data: [{ position: [(ax + bx) / 2, (ay + by) / 2], text: label2 }],
|
|
189062
|
+
getAngle: -angle2,
|
|
189063
|
+
getTextAnchor: "middle",
|
|
189064
|
+
getAlignmentBaseline: "center",
|
|
189065
|
+
getPixelOffset: [perp[0] * 16, perp[1] * 16]
|
|
189066
|
+
}));
|
|
189067
|
+
} else if (shape2.type === "rectangle") {
|
|
189068
|
+
const x02 = shape2.x ?? 0;
|
|
189069
|
+
const y02 = shape2.y ?? 0;
|
|
189070
|
+
const w2 = shape2.width ?? 0;
|
|
189071
|
+
const h2 = shape2.height ?? 0;
|
|
189072
|
+
const rx = x02 + (w2 >= 0 ? w2 : 0);
|
|
189073
|
+
const ry = y02 + (h2 >= 0 ? h2 : 0);
|
|
189074
|
+
measureLayers.push(new TextLayer({
|
|
189075
|
+
...base2,
|
|
189076
|
+
id: `annotation-measure-${shape2.uid}`,
|
|
189077
|
+
data: [{ position: [rx, ry], text: label2 }],
|
|
189078
|
+
getTextAnchor: "end",
|
|
189079
|
+
getAlignmentBaseline: "bottom",
|
|
189080
|
+
getPixelOffset: [-6, -6]
|
|
189081
|
+
}));
|
|
189082
|
+
} else if (shape2.type === "ellipse") {
|
|
189083
|
+
const cx = shape2.x1 ?? 0;
|
|
189084
|
+
const cy = shape2.y1 ?? 0;
|
|
189085
|
+
const ry = Math.abs(shape2.radiusY ?? 0);
|
|
189086
|
+
measureLayers.push(new TextLayer({
|
|
189087
|
+
...base2,
|
|
189088
|
+
id: `annotation-measure-${shape2.uid}`,
|
|
189089
|
+
data: [{ position: [cx, cy + ry], text: label2 }],
|
|
189090
|
+
getTextAnchor: "middle",
|
|
189091
|
+
getAlignmentBaseline: "top",
|
|
189092
|
+
getPixelOffset: [0, 8]
|
|
189093
|
+
}));
|
|
189094
|
+
} else if (shape2.type === "polygon" && shape2.points?.length >= 3) {
|
|
189095
|
+
const xs = shape2.points.map((p) => p[0]);
|
|
189096
|
+
const ys = shape2.points.map((p) => p[1]);
|
|
189097
|
+
const cx = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
189098
|
+
const maxY2 = Math.max(...ys);
|
|
189099
|
+
measureLayers.push(new TextLayer({
|
|
189100
|
+
...base2,
|
|
189101
|
+
id: `annotation-measure-${shape2.uid}`,
|
|
189102
|
+
data: [{ position: [cx, maxY2], text: label2 }],
|
|
189103
|
+
getTextAnchor: "middle",
|
|
189104
|
+
getAlignmentBaseline: "top",
|
|
189105
|
+
getPixelOffset: [0, 8]
|
|
189106
|
+
}));
|
|
189107
|
+
}
|
|
189108
|
+
});
|
|
189109
|
+
return [...selectionLayers, ...layers, ...measureLayers];
|
|
189110
|
+
}
|
|
189111
|
+
const defaultProps = {
|
|
189112
|
+
// Array of annotation shape objects (see annotationShapeObj in @vitessce/schemas).
|
|
189113
|
+
data: { type: "object", value: [], compare: true },
|
|
189114
|
+
// UID of the shape to highlight with a selection halo.
|
|
189115
|
+
selectedShapeUid: { type: "string", value: null },
|
|
189116
|
+
// { x, y, unit } used to format measurement labels in physical units.
|
|
189117
|
+
physicalPixelSize: { type: "object", value: null, compare: true },
|
|
189118
|
+
// The zoom level at which the shapes were authored (reference for semantic zoom).
|
|
189119
|
+
authoredZoom: { type: "number", value: null },
|
|
189120
|
+
// Whether to apply semantic zoom (level-of-detail) based on authoredZoom.
|
|
189121
|
+
semanticZoom: { type: "boolean", value: true },
|
|
189122
|
+
// The view type in which the layer is rendered (affects measurement label formatting).
|
|
189123
|
+
viewType: { type: "string", value: ViewType$1.SPATIAL },
|
|
189124
|
+
// In-progress shape being drawn, as { type, vertices }.
|
|
189125
|
+
inProgressShape: { type: "object", value: null, compare: true },
|
|
189126
|
+
// Current mouse position (in data coordinates) while drawing.
|
|
189127
|
+
hoverCoord: { type: "array", value: null, compare: true },
|
|
189128
|
+
// Stroke color [r, g, b] of the in-progress shape preview.
|
|
189129
|
+
previewStrokeColor: { type: "color", value: [255, 255, 0] }
|
|
189130
|
+
};
|
|
189131
|
+
class AnnotationLayer extends CompositeLayer {
|
|
189132
|
+
// The semantic zoom and arrowhead sizes depend on the current zoom level,
|
|
189133
|
+
// so the sublayers must also be re-rendered when the viewport changes.
|
|
189134
|
+
// eslint-disable-next-line class-methods-use-this
|
|
189135
|
+
shouldUpdateState({ changeFlags }) {
|
|
189136
|
+
return changeFlags.propsOrDataChanged || changeFlags.viewportChanged;
|
|
189137
|
+
}
|
|
189138
|
+
/**
|
|
189139
|
+
* Prefix the sublayer ID with this layer's ID (so that multiple
|
|
189140
|
+
* AnnotationLayers can co-exist), and combine this layer's
|
|
189141
|
+
* opacity with the per-shape opacity of the sublayer.
|
|
189142
|
+
* Note: we avoid getSubLayerProps here, since it would
|
|
189143
|
+
* overwrite the sublayer extensions (e.g., PathStyleExtension)
|
|
189144
|
+
* and opacity values.
|
|
189145
|
+
* @param {object} layer A DeckGL layer instance.
|
|
189146
|
+
* @returns {object} The cloned layer instance.
|
|
189147
|
+
*/
|
|
189148
|
+
wrapSubLayer(layer) {
|
|
189149
|
+
const { id: id2, opacity: opacity2, pickable, visible } = this.props;
|
|
189150
|
+
return layer.clone({
|
|
189151
|
+
id: `${id2}-${layer.id}`,
|
|
189152
|
+
opacity: layer.props.opacity * opacity2,
|
|
189153
|
+
pickable,
|
|
189154
|
+
visible
|
|
189155
|
+
});
|
|
189156
|
+
}
|
|
189157
|
+
renderLayers() {
|
|
189158
|
+
const { data: data2, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType, inProgressShape, hoverCoord, previewStrokeColor } = this.props;
|
|
189159
|
+
const zoom2 = this.context.viewport?.zoom ?? 0;
|
|
189160
|
+
const visibleShapes = (data2 ?? []).filter((shape2) => shape2.visible !== false);
|
|
189161
|
+
const annotationLayers = createAnnotationLayers(visibleShapes, zoom2, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType);
|
|
189162
|
+
const previewLayer = createPreviewLayer(inProgressShape, hoverCoord, previewStrokeColor.slice(0, 3));
|
|
189163
|
+
return [
|
|
189164
|
+
...annotationLayers,
|
|
189165
|
+
...previewLayer ? [previewLayer] : []
|
|
189166
|
+
].map((layer) => this.wrapSubLayer(layer));
|
|
189167
|
+
}
|
|
189168
|
+
}
|
|
189169
|
+
AnnotationLayer.layerName = "AnnotationLayer";
|
|
189170
|
+
AnnotationLayer.defaultProps = defaultProps;
|
|
187808
189171
|
const FEATURE_AGGREGATION_STRATEGIES = ["first", "last", "sum", "mean"];
|
|
187809
189172
|
function CellSetExpressionPlotOptions(props) {
|
|
187810
189173
|
const {
|