@vitessce/spatial-utils 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.
- package/dist/{deflate-BpOWypHr.js → deflate-CNjgm89Q.js} +1 -1
- package/dist/{index-BScMs9Qo.js → index-BpQ3fbd8.js} +1289 -86
- package/dist/index.js +1 -1
- package/dist/{jpeg-CEsy1aGu.js → jpeg-ISmJxKn1.js} +1 -1
- package/dist/{lerc-CoY4QzZT.js → lerc-Bx1iViC_.js} +1 -1
- package/dist/{lzw-C0hm4LU9.js → lzw-D7u1eQSe.js} +1 -1
- package/dist/{packbits-CkQ8qELh.js → packbits-D4yNoB9e.js} +1 -1
- package/dist/{raw-BFsjOa9D.js → raw-taMYakY-.js} +1 -1
- package/dist/{webimage-C8ngyR6p.js → webimage-DjvdutBx.js} +1 -1
- package/dist-tsc/layer-controller.d.ts +2 -0
- package/dist-tsc/layer-controller.d.ts.map +1 -1
- package/dist-tsc/layer-controller.js +7 -3
- package/dist-tsc/layer-controller.js.map +1 -1
- package/package.json +7 -7
- package/src/layer-controller.js +7 -3
|
@@ -18,6 +18,10 @@ function _mergeNamespaces(n3, m) {
|
|
|
18
18
|
}
|
|
19
19
|
return Object.freeze(Object.defineProperty(n3, Symbol.toStringTag, { value: "Module" }));
|
|
20
20
|
}
|
|
21
|
+
const ViewType = {
|
|
22
|
+
SCATTERPLOT: "scatterplot",
|
|
23
|
+
SPATIAL: "spatial"
|
|
24
|
+
};
|
|
21
25
|
const GLOBAL_LABELS = ["z", "t"];
|
|
22
26
|
const DEFAULT_RASTER_DOMAIN_TYPE = "Min/Max";
|
|
23
27
|
const DEFAULT_MOLECULES_LAYER = {
|
|
@@ -1263,8 +1267,8 @@ class Vector extends MathArray {
|
|
|
1263
1267
|
distanceSquared(mathArray) {
|
|
1264
1268
|
let length2 = 0;
|
|
1265
1269
|
for (let i2 = 0; i2 < this.ELEMENTS; ++i2) {
|
|
1266
|
-
const
|
|
1267
|
-
length2 +=
|
|
1270
|
+
const dist2 = this[i2] - mathArray[i2];
|
|
1271
|
+
length2 += dist2 * dist2;
|
|
1268
1272
|
}
|
|
1269
1273
|
return checkNumber(length2);
|
|
1270
1274
|
}
|
|
@@ -1585,6 +1589,12 @@ function multiply$4(out, a2, b) {
|
|
|
1585
1589
|
out[2] = a2[2] * b[2];
|
|
1586
1590
|
return out;
|
|
1587
1591
|
}
|
|
1592
|
+
function distance$3(a2, b) {
|
|
1593
|
+
var x = b[0] - a2[0];
|
|
1594
|
+
var y = b[1] - a2[1];
|
|
1595
|
+
var z = b[2] - a2[2];
|
|
1596
|
+
return Math.hypot(x, y, z);
|
|
1597
|
+
}
|
|
1588
1598
|
function squaredLength$2(a2) {
|
|
1589
1599
|
var x = a2[0];
|
|
1590
1600
|
var y = a2[1];
|
|
@@ -1708,6 +1718,7 @@ function angle$2(a2, b) {
|
|
|
1708
1718
|
}
|
|
1709
1719
|
var sub$1 = subtract$1;
|
|
1710
1720
|
var mul$1 = multiply$4;
|
|
1721
|
+
var dist = distance$3;
|
|
1711
1722
|
var len = length$4;
|
|
1712
1723
|
var sqrLen = squaredLength$2;
|
|
1713
1724
|
(function() {
|
|
@@ -42374,7 +42385,7 @@ function noop$2() {
|
|
|
42374
42385
|
const getCursor = ({
|
|
42375
42386
|
isDragging
|
|
42376
42387
|
}) => isDragging ? "grabbing" : "grab";
|
|
42377
|
-
const defaultProps$
|
|
42388
|
+
const defaultProps$P = {
|
|
42378
42389
|
id: "",
|
|
42379
42390
|
width: "100%",
|
|
42380
42391
|
height: "100%",
|
|
@@ -42505,7 +42516,7 @@ class Deck {
|
|
|
42505
42516
|
this._lastPointerDownInfo = pickedInfo.result[0] || pickedInfo.emptyInfo;
|
|
42506
42517
|
});
|
|
42507
42518
|
this.props = {
|
|
42508
|
-
...defaultProps$
|
|
42519
|
+
...defaultProps$P,
|
|
42509
42520
|
...props
|
|
42510
42521
|
};
|
|
42511
42522
|
props = this.props;
|
|
@@ -43007,7 +43018,7 @@ class Deck {
|
|
|
43007
43018
|
metrics.gpuMemory = memoryStats.get("GPU Memory").count;
|
|
43008
43019
|
}
|
|
43009
43020
|
}
|
|
43010
|
-
_defineProperty(Deck, "defaultProps", defaultProps$
|
|
43021
|
+
_defineProperty(Deck, "defaultProps", defaultProps$P);
|
|
43011
43022
|
_defineProperty(Deck, "VERSION", deckGlobal.VERSION);
|
|
43012
43023
|
class ShaderAttribute {
|
|
43013
43024
|
constructor(dataColumn, opts) {
|
|
@@ -45762,7 +45773,7 @@ const areViewportsEqual = memoize$1(({
|
|
|
45762
45773
|
return oldViewport.equals(viewport);
|
|
45763
45774
|
});
|
|
45764
45775
|
let pickingColorCache = new Uint8ClampedArray(0);
|
|
45765
|
-
const defaultProps$
|
|
45776
|
+
const defaultProps$O = {
|
|
45766
45777
|
data: {
|
|
45767
45778
|
type: "data",
|
|
45768
45779
|
value: EMPTY_ARRAY$1,
|
|
@@ -46637,7 +46648,7 @@ class Layer extends Component {
|
|
|
46637
46648
|
this.setNeedsUpdate();
|
|
46638
46649
|
}
|
|
46639
46650
|
}
|
|
46640
|
-
_defineProperty(Layer, "defaultProps", defaultProps$
|
|
46651
|
+
_defineProperty(Layer, "defaultProps", defaultProps$O);
|
|
46641
46652
|
_defineProperty(Layer, "layerName", "Layer");
|
|
46642
46653
|
const TRACE_RENDER_LAYERS = "compositeLayer.renderLayers";
|
|
46643
46654
|
class CompositeLayer extends Layer {
|
|
@@ -47673,6 +47684,124 @@ const esm$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
47673
47684
|
project32,
|
|
47674
47685
|
shadow
|
|
47675
47686
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
47687
|
+
const dashShaders = {
|
|
47688
|
+
inject: {
|
|
47689
|
+
"vs:#decl": "\nattribute vec2 instanceDashArrays;\nattribute float instanceDashOffsets;\nvarying vec2 vDashArray;\nvarying float vDashOffset;\n",
|
|
47690
|
+
"vs:#main-end": "\nvDashArray = instanceDashArrays;\nvDashOffset = instanceDashOffsets / width.x;\n",
|
|
47691
|
+
"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",
|
|
47692
|
+
"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"
|
|
47693
|
+
}
|
|
47694
|
+
};
|
|
47695
|
+
const offsetShaders = {
|
|
47696
|
+
inject: {
|
|
47697
|
+
"vs:#decl": "\nattribute float instanceOffsets;\n",
|
|
47698
|
+
"vs:DECKGL_FILTER_SIZE": "\n float offsetWidth = abs(instanceOffsets * 2.0) + 1.0;\n size *= offsetWidth;\n",
|
|
47699
|
+
"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",
|
|
47700
|
+
"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"
|
|
47701
|
+
}
|
|
47702
|
+
};
|
|
47703
|
+
const defaultProps$N = {
|
|
47704
|
+
getDashArray: {
|
|
47705
|
+
type: "accessor",
|
|
47706
|
+
value: [0, 0]
|
|
47707
|
+
},
|
|
47708
|
+
getOffset: {
|
|
47709
|
+
type: "accessor",
|
|
47710
|
+
value: 0
|
|
47711
|
+
},
|
|
47712
|
+
dashJustified: false,
|
|
47713
|
+
dashGapPickable: false
|
|
47714
|
+
};
|
|
47715
|
+
class PathStyleExtension extends LayerExtension {
|
|
47716
|
+
constructor({
|
|
47717
|
+
dash = false,
|
|
47718
|
+
offset = false,
|
|
47719
|
+
highPrecisionDash = false
|
|
47720
|
+
} = {}) {
|
|
47721
|
+
super({
|
|
47722
|
+
dash: dash || highPrecisionDash,
|
|
47723
|
+
offset,
|
|
47724
|
+
highPrecisionDash
|
|
47725
|
+
});
|
|
47726
|
+
}
|
|
47727
|
+
isEnabled(layer) {
|
|
47728
|
+
return "pathTesselator" in layer.state;
|
|
47729
|
+
}
|
|
47730
|
+
getShaders(extension) {
|
|
47731
|
+
if (!extension.isEnabled(this)) {
|
|
47732
|
+
return null;
|
|
47733
|
+
}
|
|
47734
|
+
let result = {};
|
|
47735
|
+
if (extension.opts.dash) {
|
|
47736
|
+
result = mergeShaders(result, dashShaders);
|
|
47737
|
+
}
|
|
47738
|
+
if (extension.opts.offset) {
|
|
47739
|
+
result = mergeShaders(result, offsetShaders);
|
|
47740
|
+
}
|
|
47741
|
+
return result;
|
|
47742
|
+
}
|
|
47743
|
+
initializeState(context, extension) {
|
|
47744
|
+
const attributeManager = this.getAttributeManager();
|
|
47745
|
+
if (!attributeManager || !extension.isEnabled(this)) {
|
|
47746
|
+
return;
|
|
47747
|
+
}
|
|
47748
|
+
if (extension.opts.dash) {
|
|
47749
|
+
attributeManager.addInstanced({
|
|
47750
|
+
instanceDashArrays: {
|
|
47751
|
+
size: 2,
|
|
47752
|
+
accessor: "getDashArray"
|
|
47753
|
+
}
|
|
47754
|
+
});
|
|
47755
|
+
}
|
|
47756
|
+
if (extension.opts.highPrecisionDash) {
|
|
47757
|
+
attributeManager.addInstanced({
|
|
47758
|
+
instanceDashOffsets: {
|
|
47759
|
+
size: 1,
|
|
47760
|
+
accessor: "getPath",
|
|
47761
|
+
transform: extension.getDashOffsets.bind(this)
|
|
47762
|
+
}
|
|
47763
|
+
});
|
|
47764
|
+
}
|
|
47765
|
+
if (extension.opts.offset) {
|
|
47766
|
+
attributeManager.addInstanced({
|
|
47767
|
+
instanceOffsets: {
|
|
47768
|
+
size: 1,
|
|
47769
|
+
accessor: "getOffset"
|
|
47770
|
+
}
|
|
47771
|
+
});
|
|
47772
|
+
}
|
|
47773
|
+
}
|
|
47774
|
+
updateState(params, extension) {
|
|
47775
|
+
if (!extension.isEnabled(this)) {
|
|
47776
|
+
return;
|
|
47777
|
+
}
|
|
47778
|
+
const uniforms = {};
|
|
47779
|
+
if (extension.opts.dash) {
|
|
47780
|
+
uniforms.dashAlignMode = this.props.dashJustified ? 1 : 0;
|
|
47781
|
+
uniforms.dashGapPickable = Boolean(this.props.dashGapPickable);
|
|
47782
|
+
}
|
|
47783
|
+
this.state.model.setUniforms(uniforms);
|
|
47784
|
+
}
|
|
47785
|
+
getDashOffsets(path) {
|
|
47786
|
+
const result = [0];
|
|
47787
|
+
const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
|
|
47788
|
+
const isNested2 = Array.isArray(path[0]);
|
|
47789
|
+
const geometrySize = isNested2 ? path.length : path.length / positionSize;
|
|
47790
|
+
let p;
|
|
47791
|
+
let prevP;
|
|
47792
|
+
for (let i2 = 0; i2 < geometrySize - 1; i2++) {
|
|
47793
|
+
p = isNested2 ? path[i2] : path.slice(i2 * positionSize, i2 * positionSize + positionSize);
|
|
47794
|
+
p = this.projectPosition(p);
|
|
47795
|
+
if (i2 > 0) {
|
|
47796
|
+
result[i2] = result[i2 - 1] + dist(prevP, p);
|
|
47797
|
+
}
|
|
47798
|
+
prevP = p;
|
|
47799
|
+
}
|
|
47800
|
+
return result;
|
|
47801
|
+
}
|
|
47802
|
+
}
|
|
47803
|
+
_defineProperty(PathStyleExtension, "defaultProps", defaultProps$N);
|
|
47804
|
+
_defineProperty(PathStyleExtension, "extensionName", "PathStyleExtension");
|
|
47676
47805
|
const defaultProps$M = {
|
|
47677
47806
|
clipBounds: [0, 0, 1, 1]
|
|
47678
47807
|
};
|
|
@@ -103784,8 +103913,8 @@ function requireJs$b() {
|
|
|
103784
103913
|
var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi12 / 2 + Math.PI / 4));
|
|
103785
103914
|
var q = Math.abs(DeltaPsi) > 1e-11 ? DeltaPhi / DeltaPsi : Math.cos(phi12);
|
|
103786
103915
|
var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda);
|
|
103787
|
-
var
|
|
103788
|
-
return
|
|
103916
|
+
var dist2 = delta * R;
|
|
103917
|
+
return dist2;
|
|
103789
103918
|
}
|
|
103790
103919
|
js$a.default = rhumbDistance;
|
|
103791
103920
|
return js$a;
|
|
@@ -104098,7 +104227,7 @@ function requireUtils$2() {
|
|
|
104098
104227
|
var x;
|
|
104099
104228
|
var y;
|
|
104100
104229
|
var segmentIdx;
|
|
104101
|
-
var
|
|
104230
|
+
var dist2;
|
|
104102
104231
|
if (coords.length > 1 && pointCoords.length) {
|
|
104103
104232
|
var lineCoordinates;
|
|
104104
104233
|
var pointCoordinate;
|
|
@@ -104115,17 +104244,17 @@ function requireUtils$2() {
|
|
|
104115
104244
|
if (lineCoordinates[n3][0] !== lineCoordinates[n3 - 1][0]) {
|
|
104116
104245
|
var slope = (lineCoordinates[n3][1] - lineCoordinates[n3 - 1][1]) / (lineCoordinates[n3][0] - lineCoordinates[n3 - 1][0]);
|
|
104117
104246
|
var inverseSlope = lineCoordinates[n3][1] - slope * lineCoordinates[n3][0];
|
|
104118
|
-
|
|
104119
|
-
} else
|
|
104247
|
+
dist2 = Math.abs(slope * pointCoordinate[0] + inverseSlope - pointCoordinate[1]) / Math.sqrt(slope * slope + 1);
|
|
104248
|
+
} else dist2 = Math.abs(pointCoordinate[0] - lineCoordinates[n3][0]);
|
|
104120
104249
|
var rl2 = Math.pow(lineCoordinates[n3][1] - lineCoordinates[n3 - 1][1], 2) + Math.pow(lineCoordinates[n3][0] - lineCoordinates[n3 - 1][0], 2);
|
|
104121
104250
|
var ln2 = Math.pow(lineCoordinates[n3][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n3][0] - pointCoordinate[0], 2);
|
|
104122
104251
|
var lnm12 = Math.pow(lineCoordinates[n3 - 1][1] - pointCoordinate[1], 2) + Math.pow(lineCoordinates[n3 - 1][0] - pointCoordinate[0], 2);
|
|
104123
|
-
var
|
|
104124
|
-
var calcrl2 = ln2 -
|
|
104252
|
+
var dist22 = Math.pow(dist2, 2);
|
|
104253
|
+
var calcrl2 = ln2 - dist22 + lnm12 - dist22;
|
|
104125
104254
|
if (calcrl2 > rl2) {
|
|
104126
|
-
|
|
104255
|
+
dist2 = Math.sqrt(Math.min(ln2, lnm12));
|
|
104127
104256
|
}
|
|
104128
|
-
if (minDist === null || minDist === void 0 || minDist >
|
|
104257
|
+
if (minDist === null || minDist === void 0 || minDist > dist2) {
|
|
104129
104258
|
if (calcrl2 > rl2) {
|
|
104130
104259
|
if (lnm12 < ln2) {
|
|
104131
104260
|
to = 0;
|
|
@@ -104135,10 +104264,10 @@ function requireUtils$2() {
|
|
|
104135
104264
|
to = 1;
|
|
104136
104265
|
}
|
|
104137
104266
|
} else {
|
|
104138
|
-
to = Math.sqrt(lnm12 -
|
|
104139
|
-
from = Math.sqrt(ln2 -
|
|
104267
|
+
to = Math.sqrt(lnm12 - dist22) / Math.sqrt(rl2);
|
|
104268
|
+
from = Math.sqrt(ln2 - dist22) / Math.sqrt(rl2);
|
|
104140
104269
|
}
|
|
104141
|
-
minDist =
|
|
104270
|
+
minDist = dist2;
|
|
104142
104271
|
segmentIdx = n3;
|
|
104143
104272
|
}
|
|
104144
104273
|
}
|
|
@@ -120396,22 +120525,22 @@ function addDecoder(cases, importFn) {
|
|
|
120396
120525
|
}
|
|
120397
120526
|
cases.forEach((c) => registry$2.set(c, importFn));
|
|
120398
120527
|
}
|
|
120399
|
-
addDecoder([void 0, 1], () => import("./raw-
|
|
120400
|
-
addDecoder(5, () => import("./lzw-
|
|
120528
|
+
addDecoder([void 0, 1], () => import("./raw-taMYakY-.js").then((m) => m.default));
|
|
120529
|
+
addDecoder(5, () => import("./lzw-D7u1eQSe.js").then((m) => m.default));
|
|
120401
120530
|
addDecoder(6, () => {
|
|
120402
120531
|
throw new Error("old style JPEG compression is not supported.");
|
|
120403
120532
|
});
|
|
120404
|
-
addDecoder(7, () => import("./jpeg-
|
|
120405
|
-
addDecoder([8, 32946], () => import("./deflate-
|
|
120406
|
-
addDecoder(32773, () => import("./packbits-
|
|
120533
|
+
addDecoder(7, () => import("./jpeg-ISmJxKn1.js").then((m) => m.default));
|
|
120534
|
+
addDecoder([8, 32946], () => import("./deflate-CNjgm89Q.js").then((m) => m.default));
|
|
120535
|
+
addDecoder(32773, () => import("./packbits-D4yNoB9e.js").then((m) => m.default));
|
|
120407
120536
|
addDecoder(
|
|
120408
120537
|
34887,
|
|
120409
|
-
() => import("./lerc-
|
|
120538
|
+
() => import("./lerc-Bx1iViC_.js").then(async (m) => {
|
|
120410
120539
|
await m.zstd.init();
|
|
120411
120540
|
return m;
|
|
120412
120541
|
}).then((m) => m.default)
|
|
120413
120542
|
);
|
|
120414
|
-
addDecoder(50001, () => import("./webimage-
|
|
120543
|
+
addDecoder(50001, () => import("./webimage-DjvdutBx.js").then((m) => m.default));
|
|
120415
120544
|
function decodeRowAcc(row, stride) {
|
|
120416
120545
|
let length2 = row.length - stride;
|
|
120417
120546
|
let offset = 0;
|
|
@@ -124412,8 +124541,8 @@ function TreeDesc(dyn_tree, stat_desc) {
|
|
|
124412
124541
|
this.max_code = 0;
|
|
124413
124542
|
this.stat_desc = stat_desc;
|
|
124414
124543
|
}
|
|
124415
|
-
const d_code = (
|
|
124416
|
-
return
|
|
124544
|
+
const d_code = (dist2) => {
|
|
124545
|
+
return dist2 < 256 ? _dist_code[dist2] : _dist_code[256 + (dist2 >>> 7)];
|
|
124417
124546
|
};
|
|
124418
124547
|
const put_short = (s2, w2) => {
|
|
124419
124548
|
s2.pending_buf[s2.pending++] = w2 & 255;
|
|
@@ -124547,7 +124676,7 @@ const tr_static_init = () => {
|
|
|
124547
124676
|
let bits;
|
|
124548
124677
|
let length2;
|
|
124549
124678
|
let code;
|
|
124550
|
-
let
|
|
124679
|
+
let dist2;
|
|
124551
124680
|
const bl_count = new Array(MAX_BITS + 1);
|
|
124552
124681
|
length2 = 0;
|
|
124553
124682
|
for (code = 0; code < LENGTH_CODES - 1; code++) {
|
|
@@ -124557,18 +124686,18 @@ const tr_static_init = () => {
|
|
|
124557
124686
|
}
|
|
124558
124687
|
}
|
|
124559
124688
|
_length_code[length2 - 1] = code;
|
|
124560
|
-
|
|
124689
|
+
dist2 = 0;
|
|
124561
124690
|
for (code = 0; code < 16; code++) {
|
|
124562
|
-
base_dist[code] =
|
|
124691
|
+
base_dist[code] = dist2;
|
|
124563
124692
|
for (n3 = 0; n3 < 1 << extra_dbits[code]; n3++) {
|
|
124564
|
-
_dist_code[
|
|
124693
|
+
_dist_code[dist2++] = code;
|
|
124565
124694
|
}
|
|
124566
124695
|
}
|
|
124567
|
-
|
|
124696
|
+
dist2 >>= 7;
|
|
124568
124697
|
for (; code < D_CODES; code++) {
|
|
124569
|
-
base_dist[code] =
|
|
124698
|
+
base_dist[code] = dist2 << 7;
|
|
124570
124699
|
for (n3 = 0; n3 < 1 << extra_dbits[code] - 7; n3++) {
|
|
124571
|
-
_dist_code[256 +
|
|
124700
|
+
_dist_code[256 + dist2++] = code;
|
|
124572
124701
|
}
|
|
124573
124702
|
}
|
|
124574
124703
|
for (bits = 0; bits <= MAX_BITS; bits++) {
|
|
@@ -124659,17 +124788,17 @@ const pqdownheap = (s2, tree, k) => {
|
|
|
124659
124788
|
s2.heap[k] = v;
|
|
124660
124789
|
};
|
|
124661
124790
|
const compress_block = (s2, ltree, dtree) => {
|
|
124662
|
-
let
|
|
124791
|
+
let dist2;
|
|
124663
124792
|
let lc;
|
|
124664
124793
|
let lx = 0;
|
|
124665
124794
|
let code;
|
|
124666
124795
|
let extra;
|
|
124667
124796
|
if (s2.last_lit !== 0) {
|
|
124668
124797
|
do {
|
|
124669
|
-
|
|
124798
|
+
dist2 = s2.pending_buf[s2.d_buf + lx * 2] << 8 | s2.pending_buf[s2.d_buf + lx * 2 + 1];
|
|
124670
124799
|
lc = s2.pending_buf[s2.l_buf + lx];
|
|
124671
124800
|
lx++;
|
|
124672
|
-
if (
|
|
124801
|
+
if (dist2 === 0) {
|
|
124673
124802
|
send_code(s2, lc, ltree);
|
|
124674
124803
|
} else {
|
|
124675
124804
|
code = _length_code[lc];
|
|
@@ -124679,13 +124808,13 @@ const compress_block = (s2, ltree, dtree) => {
|
|
|
124679
124808
|
lc -= base_length[code];
|
|
124680
124809
|
send_bits(s2, lc, extra);
|
|
124681
124810
|
}
|
|
124682
|
-
|
|
124683
|
-
code = d_code(
|
|
124811
|
+
dist2--;
|
|
124812
|
+
code = d_code(dist2);
|
|
124684
124813
|
send_code(s2, code, dtree);
|
|
124685
124814
|
extra = extra_dbits[code];
|
|
124686
124815
|
if (extra !== 0) {
|
|
124687
|
-
|
|
124688
|
-
send_bits(s2,
|
|
124816
|
+
dist2 -= base_dist[code];
|
|
124817
|
+
send_bits(s2, dist2, extra);
|
|
124689
124818
|
}
|
|
124690
124819
|
}
|
|
124691
124820
|
} while (lx < s2.last_lit);
|
|
@@ -124956,18 +125085,18 @@ const _tr_flush_block = (s2, buf, stored_len, last) => {
|
|
|
124956
125085
|
bi_windup(s2);
|
|
124957
125086
|
}
|
|
124958
125087
|
};
|
|
124959
|
-
const _tr_tally = (s2,
|
|
124960
|
-
s2.pending_buf[s2.d_buf + s2.last_lit * 2] =
|
|
124961
|
-
s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] =
|
|
125088
|
+
const _tr_tally = (s2, dist2, lc) => {
|
|
125089
|
+
s2.pending_buf[s2.d_buf + s2.last_lit * 2] = dist2 >>> 8 & 255;
|
|
125090
|
+
s2.pending_buf[s2.d_buf + s2.last_lit * 2 + 1] = dist2 & 255;
|
|
124962
125091
|
s2.pending_buf[s2.l_buf + s2.last_lit] = lc & 255;
|
|
124963
125092
|
s2.last_lit++;
|
|
124964
|
-
if (
|
|
125093
|
+
if (dist2 === 0) {
|
|
124965
125094
|
s2.dyn_ltree[lc * 2]++;
|
|
124966
125095
|
} else {
|
|
124967
125096
|
s2.matches++;
|
|
124968
|
-
|
|
125097
|
+
dist2--;
|
|
124969
125098
|
s2.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;
|
|
124970
|
-
s2.dyn_dtree[d_code(
|
|
125099
|
+
s2.dyn_dtree[d_code(dist2) * 2]++;
|
|
124971
125100
|
}
|
|
124972
125101
|
return s2.last_lit === s2.lit_bufsize - 1;
|
|
124973
125102
|
};
|
|
@@ -126472,7 +126601,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126472
126601
|
let here;
|
|
126473
126602
|
let op;
|
|
126474
126603
|
let len2;
|
|
126475
|
-
let
|
|
126604
|
+
let dist2;
|
|
126476
126605
|
let from;
|
|
126477
126606
|
let from_source;
|
|
126478
126607
|
let input, output;
|
|
@@ -126538,7 +126667,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126538
126667
|
bits -= op;
|
|
126539
126668
|
op = here >>> 16 & 255;
|
|
126540
126669
|
if (op & 16) {
|
|
126541
|
-
|
|
126670
|
+
dist2 = here & 65535;
|
|
126542
126671
|
op &= 15;
|
|
126543
126672
|
if (bits < op) {
|
|
126544
126673
|
hold += input[_in++] << bits;
|
|
@@ -126548,8 +126677,8 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126548
126677
|
bits += 8;
|
|
126549
126678
|
}
|
|
126550
126679
|
}
|
|
126551
|
-
|
|
126552
|
-
if (
|
|
126680
|
+
dist2 += hold & (1 << op) - 1;
|
|
126681
|
+
if (dist2 > dmax) {
|
|
126553
126682
|
strm.msg = "invalid distance too far back";
|
|
126554
126683
|
state.mode = BAD;
|
|
126555
126684
|
break top;
|
|
@@ -126557,8 +126686,8 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126557
126686
|
hold >>>= op;
|
|
126558
126687
|
bits -= op;
|
|
126559
126688
|
op = _out - beg;
|
|
126560
|
-
if (
|
|
126561
|
-
op =
|
|
126689
|
+
if (dist2 > op) {
|
|
126690
|
+
op = dist2 - op;
|
|
126562
126691
|
if (op > whave) {
|
|
126563
126692
|
if (state.sane) {
|
|
126564
126693
|
strm.msg = "invalid distance too far back";
|
|
@@ -126575,7 +126704,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126575
126704
|
do {
|
|
126576
126705
|
output[_out++] = s_window[from++];
|
|
126577
126706
|
} while (--op);
|
|
126578
|
-
from = _out -
|
|
126707
|
+
from = _out - dist2;
|
|
126579
126708
|
from_source = output;
|
|
126580
126709
|
}
|
|
126581
126710
|
} else if (wnext < op) {
|
|
@@ -126593,7 +126722,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126593
126722
|
do {
|
|
126594
126723
|
output[_out++] = s_window[from++];
|
|
126595
126724
|
} while (--op);
|
|
126596
|
-
from = _out -
|
|
126725
|
+
from = _out - dist2;
|
|
126597
126726
|
from_source = output;
|
|
126598
126727
|
}
|
|
126599
126728
|
}
|
|
@@ -126604,7 +126733,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126604
126733
|
do {
|
|
126605
126734
|
output[_out++] = s_window[from++];
|
|
126606
126735
|
} while (--op);
|
|
126607
|
-
from = _out -
|
|
126736
|
+
from = _out - dist2;
|
|
126608
126737
|
from_source = output;
|
|
126609
126738
|
}
|
|
126610
126739
|
}
|
|
@@ -126621,7 +126750,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
126621
126750
|
}
|
|
126622
126751
|
}
|
|
126623
126752
|
} else {
|
|
126624
|
-
from = _out -
|
|
126753
|
+
from = _out - dist2;
|
|
126625
126754
|
do {
|
|
126626
126755
|
output[_out++] = output[from++];
|
|
126627
126756
|
output[_out++] = output[from++];
|
|
@@ -127179,7 +127308,7 @@ const fixedtables = (state) => {
|
|
|
127179
127308
|
state.distbits = 5;
|
|
127180
127309
|
};
|
|
127181
127310
|
const updatewindow = (strm, src, end, copy2) => {
|
|
127182
|
-
let
|
|
127311
|
+
let dist2;
|
|
127183
127312
|
const state = strm.state;
|
|
127184
127313
|
if (state.window === null) {
|
|
127185
127314
|
state.wsize = 1 << state.wbits;
|
|
@@ -127192,23 +127321,23 @@ const updatewindow = (strm, src, end, copy2) => {
|
|
|
127192
127321
|
state.wnext = 0;
|
|
127193
127322
|
state.whave = state.wsize;
|
|
127194
127323
|
} else {
|
|
127195
|
-
|
|
127196
|
-
if (
|
|
127197
|
-
|
|
127324
|
+
dist2 = state.wsize - state.wnext;
|
|
127325
|
+
if (dist2 > copy2) {
|
|
127326
|
+
dist2 = copy2;
|
|
127198
127327
|
}
|
|
127199
|
-
state.window.set(src.subarray(end - copy2, end - copy2 +
|
|
127200
|
-
copy2 -=
|
|
127328
|
+
state.window.set(src.subarray(end - copy2, end - copy2 + dist2), state.wnext);
|
|
127329
|
+
copy2 -= dist2;
|
|
127201
127330
|
if (copy2) {
|
|
127202
127331
|
state.window.set(src.subarray(end - copy2, end), 0);
|
|
127203
127332
|
state.wnext = copy2;
|
|
127204
127333
|
state.whave = state.wsize;
|
|
127205
127334
|
} else {
|
|
127206
|
-
state.wnext +=
|
|
127335
|
+
state.wnext += dist2;
|
|
127207
127336
|
if (state.wnext === state.wsize) {
|
|
127208
127337
|
state.wnext = 0;
|
|
127209
127338
|
}
|
|
127210
127339
|
if (state.whave < state.wsize) {
|
|
127211
|
-
state.whave +=
|
|
127340
|
+
state.whave += dist2;
|
|
127212
127341
|
}
|
|
127213
127342
|
}
|
|
127214
127343
|
}
|
|
@@ -131378,7 +131507,7 @@ function padColors({ colors, channelsVisible }) {
|
|
|
131378
131507
|
).reduce((acc, val) => acc.concat(val), []);
|
|
131379
131508
|
return paddedColors;
|
|
131380
131509
|
}
|
|
131381
|
-
const defaultProps$3$
|
|
131510
|
+
const defaultProps$3$2 = {
|
|
131382
131511
|
colors: { type: "array", value: null, compare: true },
|
|
131383
131512
|
opacity: { type: "number", value: 1, compare: true },
|
|
131384
131513
|
transparentColor: { type: "array", value: null, compare: true },
|
|
@@ -131395,9 +131524,9 @@ const ColorPaletteExtension = class extends LayerExtension {
|
|
|
131395
131524
|
const {
|
|
131396
131525
|
colors,
|
|
131397
131526
|
channelsVisible,
|
|
131398
|
-
opacity = defaultProps$3$
|
|
131399
|
-
transparentColor = defaultProps$3$
|
|
131400
|
-
useTransparentColor = defaultProps$3$
|
|
131527
|
+
opacity = defaultProps$3$2.opacity.value,
|
|
131528
|
+
transparentColor = defaultProps$3$2.transparentColor.value,
|
|
131529
|
+
useTransparentColor = defaultProps$3$2.useTransparentColor.value
|
|
131401
131530
|
} = this.props;
|
|
131402
131531
|
const paddedColors = padColors({
|
|
131403
131532
|
channelsVisible: channelsVisible || this.selections.map(() => true),
|
|
@@ -131413,7 +131542,7 @@ const ColorPaletteExtension = class extends LayerExtension {
|
|
|
131413
131542
|
}
|
|
131414
131543
|
};
|
|
131415
131544
|
ColorPaletteExtension.extensionName = "ColorPaletteExtension";
|
|
131416
|
-
ColorPaletteExtension.defaultProps = defaultProps$3$
|
|
131545
|
+
ColorPaletteExtension.defaultProps = defaultProps$3$2;
|
|
131417
131546
|
const fs$4 = `// lens bounds for ellipse
|
|
131418
131547
|
uniform float majorLensAxis;
|
|
131419
131548
|
uniform float minorLensAxis;
|
|
@@ -132708,7 +132837,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
|
|
|
132708
132837
|
};
|
|
132709
132838
|
MultiscaleImageLayer.layerName = "MultiscaleImageLayer";
|
|
132710
132839
|
MultiscaleImageLayer.defaultProps = defaultProps$4;
|
|
132711
|
-
const defaultProps$3 = {
|
|
132840
|
+
const defaultProps$3$1 = {
|
|
132712
132841
|
pickable: { type: "boolean", value: true, compare: true },
|
|
132713
132842
|
loader: {
|
|
132714
132843
|
type: "object",
|
|
@@ -132795,7 +132924,7 @@ const OverviewLayer = class extends CompositeLayer {
|
|
|
132795
132924
|
}
|
|
132796
132925
|
};
|
|
132797
132926
|
OverviewLayer.layerName = "OverviewLayer";
|
|
132798
|
-
OverviewLayer.defaultProps = defaultProps$3;
|
|
132927
|
+
OverviewLayer.defaultProps = defaultProps$3$1;
|
|
132799
132928
|
function getPosition(boundingBox, position, length2) {
|
|
132800
132929
|
const viewWidth = boundingBox[2][0] - boundingBox[0][0];
|
|
132801
132930
|
const viewHeight = boundingBox[2][1] - boundingBox[0][1];
|
|
@@ -133783,7 +133912,7 @@ function padWithDefault$1(arr, defaultValue2, padWidth) {
|
|
|
133783
133912
|
}
|
|
133784
133913
|
return newArr;
|
|
133785
133914
|
}
|
|
133786
|
-
const defaultProps$
|
|
133915
|
+
const defaultProps$3 = {
|
|
133787
133916
|
hoveredCell: { type: "number", value: null, compare: true },
|
|
133788
133917
|
// We do not want to deep-compare cellColorData,
|
|
133789
133918
|
// as it is potentially a TypedArray with millions of elements.
|
|
@@ -133900,7 +134029,7 @@ let BitmaskLayer$1 = class BitmaskLayer extends XRLayer {
|
|
|
133900
134029
|
}
|
|
133901
134030
|
};
|
|
133902
134031
|
BitmaskLayer$1.layerName = "BitmaskLayer";
|
|
133903
|
-
BitmaskLayer$1.defaultProps = defaultProps$
|
|
134032
|
+
BitmaskLayer$1.defaultProps = defaultProps$3;
|
|
133904
134033
|
const vs = `
|
|
133905
134034
|
#define SHADER_NAME bitmask-layer-vertex-shader
|
|
133906
134035
|
|
|
@@ -134242,7 +134371,7 @@ function isEqualShallow(prevArr, nextArr) {
|
|
|
134242
134371
|
}
|
|
134243
134372
|
return prevArr === nextArr;
|
|
134244
134373
|
}
|
|
134245
|
-
const defaultProps$
|
|
134374
|
+
const defaultProps$2 = {
|
|
134246
134375
|
channelStrokeWidths: { type: "array", value: null, compare: true },
|
|
134247
134376
|
channelsFilled: { type: "array", value: null, compare: true },
|
|
134248
134377
|
channelOpacities: { type: "array", value: null, compare: true },
|
|
@@ -134506,7 +134635,7 @@ class BitmaskLayer2 extends XRLayer {
|
|
|
134506
134635
|
}
|
|
134507
134636
|
}
|
|
134508
134637
|
BitmaskLayer2.layerName = "BitmaskLayer";
|
|
134509
|
-
BitmaskLayer2.defaultProps = defaultProps$
|
|
134638
|
+
BitmaskLayer2.defaultProps = defaultProps$2;
|
|
134510
134639
|
var isNumeric = /^-?(?:\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;
|
|
134511
134640
|
function clone(configObject) {
|
|
134512
134641
|
var div2, convertBase2, parseNumeric, P2 = BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }, ONE = new BigNumber2(1), DECIMAL_PLACES = 20, ROUNDING_MODE = 4, TO_EXP_NEG = -7, TO_EXP_POS = 21, MIN_EXP = -1e7, MAX_EXP = 1e7, CRYPTO = false, MODULO_MODE = 1, POW_PRECISION = 0, FORMAT = {
|
|
@@ -137449,7 +137578,7 @@ function ringArea(coords) {
|
|
|
137449
137578
|
return total * FACTOR;
|
|
137450
137579
|
}
|
|
137451
137580
|
const DEFAULT_THRESHOLD = 1;
|
|
137452
|
-
const defaultProps = {
|
|
137581
|
+
const defaultProps$1 = {
|
|
137453
137582
|
// for text
|
|
137454
137583
|
obsSetPath: { type: "object" },
|
|
137455
137584
|
sampleSetPath: { type: "object" },
|
|
@@ -137544,9 +137673,9 @@ class ContourLayerWithText extends ContourLayer {
|
|
|
137544
137673
|
const circlePoint = point(circleCoord);
|
|
137545
137674
|
polygonVertices.forEach((polyCoord) => {
|
|
137546
137675
|
const polyPoint = point(polyCoord);
|
|
137547
|
-
const
|
|
137548
|
-
if (
|
|
137549
|
-
minDist =
|
|
137676
|
+
const dist2 = distance$1(circlePoint, polyPoint);
|
|
137677
|
+
if (dist2 < minDist) {
|
|
137678
|
+
minDist = dist2;
|
|
137550
137679
|
minCirclePoint = circleCoord;
|
|
137551
137680
|
minCirclePointI = circlePointI;
|
|
137552
137681
|
minPolygonPoint = polyCoord;
|
|
@@ -137623,7 +137752,1077 @@ class ContourLayerWithText extends ContourLayer {
|
|
|
137623
137752
|
}
|
|
137624
137753
|
}
|
|
137625
137754
|
ContourLayerWithText.layerName = "ContourLayerWithText";
|
|
137626
|
-
ContourLayerWithText.defaultProps = defaultProps;
|
|
137755
|
+
ContourLayerWithText.defaultProps = defaultProps$1;
|
|
137756
|
+
const ARROW_SCREEN_PX = 14;
|
|
137757
|
+
const LABEL_FONT_FAMILY = '"Roboto", "Helvetica", "Arial", sans-serif';
|
|
137758
|
+
const LABEL_FONT_WEIGHT = "bold";
|
|
137759
|
+
const LABEL_FONT_SIZE = 14;
|
|
137760
|
+
const RATIO_CLUSTER = 0.1;
|
|
137761
|
+
const RATIO_DOT = 0.3;
|
|
137762
|
+
const RATIO_GEO_FADE = 0.55;
|
|
137763
|
+
const RATIO_TIPS = 0.7;
|
|
137764
|
+
const RATIO_LABEL = 0.55;
|
|
137765
|
+
const RATIO_LABEL_FULL = 0.75;
|
|
137766
|
+
function textBgColor(strokeColor) {
|
|
137767
|
+
const [r2, g2, b] = strokeColor;
|
|
137768
|
+
const lum = (0.299 * r2 + 0.587 * g2 + 0.114 * b) / 255;
|
|
137769
|
+
return lum > 0.45 ? [20, 20, 20, 210] : [245, 245, 245, 210];
|
|
137770
|
+
}
|
|
137771
|
+
function parseDashArray(strokeDashArray) {
|
|
137772
|
+
if (!strokeDashArray || strokeDashArray === "none")
|
|
137773
|
+
return null;
|
|
137774
|
+
const nums = strokeDashArray.trim().split(/\s+/).map(Number).filter((n3) => !Number.isNaN(n3) && n3 >= 0);
|
|
137775
|
+
return nums.length >= 2 ? [nums[0], nums[1]] : null;
|
|
137776
|
+
}
|
|
137777
|
+
function computeEllipsePolygon(cx, cy, rx, ry, numSegments = 64) {
|
|
137778
|
+
const pts = [];
|
|
137779
|
+
for (let i2 = 0; i2 < numSegments; i2++) {
|
|
137780
|
+
const angle2 = 2 * Math.PI * i2 / numSegments;
|
|
137781
|
+
pts.push([cx + rx * Math.cos(angle2), cy + ry * Math.sin(angle2)]);
|
|
137782
|
+
}
|
|
137783
|
+
return pts;
|
|
137784
|
+
}
|
|
137785
|
+
function createPreviewLayer(inProgress, hoverCoord, strokeColor = [255, 255, 0]) {
|
|
137786
|
+
if (!inProgress || inProgress.vertices.length === 0)
|
|
137787
|
+
return null;
|
|
137788
|
+
const { type, vertices } = inProgress;
|
|
137789
|
+
const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
|
|
137790
|
+
const previewColor = [...strokeColor, 160];
|
|
137791
|
+
const cursor = hoverCoord ?? vertices[vertices.length - 1];
|
|
137792
|
+
if (type === "rectangle" && vertices.length === 1) {
|
|
137793
|
+
const [ax, ay] = vertices[0];
|
|
137794
|
+
const [bx, by] = cursor;
|
|
137795
|
+
const path = [[ax, ay], [bx, ay], [bx, by], [ax, by], [ax, ay]];
|
|
137796
|
+
return new PathLayer({
|
|
137797
|
+
...base,
|
|
137798
|
+
id: "annotation-preview-rectangle",
|
|
137799
|
+
data: [{ path }],
|
|
137800
|
+
getPath: (d) => d.path,
|
|
137801
|
+
getColor: previewColor,
|
|
137802
|
+
getWidth: 1,
|
|
137803
|
+
widthUnits: "pixels",
|
|
137804
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
137805
|
+
getDashArray: [8, 4]
|
|
137806
|
+
});
|
|
137807
|
+
}
|
|
137808
|
+
if (type === "line" && vertices.length === 1) {
|
|
137809
|
+
const path = [vertices[0], cursor];
|
|
137810
|
+
return new PathLayer({
|
|
137811
|
+
...base,
|
|
137812
|
+
id: "annotation-preview-line",
|
|
137813
|
+
data: [{ path }],
|
|
137814
|
+
getPath: (d) => d.path,
|
|
137815
|
+
getColor: previewColor,
|
|
137816
|
+
getWidth: 1,
|
|
137817
|
+
widthUnits: "pixels",
|
|
137818
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
137819
|
+
getDashArray: [8, 4]
|
|
137820
|
+
});
|
|
137821
|
+
}
|
|
137822
|
+
if (type === "ellipse" && vertices.length === 1) {
|
|
137823
|
+
const [cx, cy] = vertices[0];
|
|
137824
|
+
const [ex, ey] = cursor;
|
|
137825
|
+
const rx = Math.abs(ex - cx);
|
|
137826
|
+
const ry = Math.abs(ey - cy);
|
|
137827
|
+
if (rx < 1 && ry < 1)
|
|
137828
|
+
return null;
|
|
137829
|
+
const pts = computeEllipsePolygon(cx, cy, Math.max(rx, 1), Math.max(ry, 1));
|
|
137830
|
+
const path = [...pts, pts[0]];
|
|
137831
|
+
return new PathLayer({
|
|
137832
|
+
...base,
|
|
137833
|
+
id: "annotation-preview-ellipse",
|
|
137834
|
+
data: [{ path }],
|
|
137835
|
+
getPath: (d) => d.path,
|
|
137836
|
+
getColor: previewColor,
|
|
137837
|
+
getWidth: 1,
|
|
137838
|
+
widthUnits: "pixels",
|
|
137839
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
137840
|
+
getDashArray: [8, 4]
|
|
137841
|
+
});
|
|
137842
|
+
}
|
|
137843
|
+
if ((type === "polygon" || type === "polyline") && vertices.length >= 1) {
|
|
137844
|
+
const path = [...vertices, cursor];
|
|
137845
|
+
if (type === "polygon" && vertices.length >= 2)
|
|
137846
|
+
path.push(vertices[0]);
|
|
137847
|
+
return new PathLayer({
|
|
137848
|
+
...base,
|
|
137849
|
+
id: `annotation-preview-${type}`,
|
|
137850
|
+
data: [{ path }],
|
|
137851
|
+
getPath: (d) => d.path,
|
|
137852
|
+
getColor: previewColor,
|
|
137853
|
+
getWidth: 1,
|
|
137854
|
+
widthUnits: "pixels",
|
|
137855
|
+
jointRounded: true,
|
|
137856
|
+
capRounded: true,
|
|
137857
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
137858
|
+
getDashArray: [8, 4]
|
|
137859
|
+
});
|
|
137860
|
+
}
|
|
137861
|
+
return null;
|
|
137862
|
+
}
|
|
137863
|
+
function computeTickCap(tipX, tipY, dirX, dirY, dataSize) {
|
|
137864
|
+
const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
137865
|
+
if (len2 === 0)
|
|
137866
|
+
return null;
|
|
137867
|
+
const ux = dirX / len2;
|
|
137868
|
+
const uy = dirY / len2;
|
|
137869
|
+
const px = -uy;
|
|
137870
|
+
const py = ux;
|
|
137871
|
+
const half = dataSize * 0.55;
|
|
137872
|
+
return [
|
|
137873
|
+
[tipX + px * half, tipY + py * half],
|
|
137874
|
+
[tipX - px * half, tipY - py * half]
|
|
137875
|
+
];
|
|
137876
|
+
}
|
|
137877
|
+
function computeArrowhead(tipX, tipY, dirX, dirY, dataSize) {
|
|
137878
|
+
const len2 = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
137879
|
+
if (len2 === 0)
|
|
137880
|
+
return null;
|
|
137881
|
+
const ux = dirX / len2;
|
|
137882
|
+
const uy = dirY / len2;
|
|
137883
|
+
const px = -uy;
|
|
137884
|
+
const py = ux;
|
|
137885
|
+
const halfBase = dataSize * 0.4;
|
|
137886
|
+
const bx = tipX - ux * dataSize;
|
|
137887
|
+
const by = tipY - uy * dataSize;
|
|
137888
|
+
return [
|
|
137889
|
+
[tipX, tipY],
|
|
137890
|
+
[bx + px * halfBase, by + py * halfBase],
|
|
137891
|
+
[bx - px * halfBase, by - py * halfBase]
|
|
137892
|
+
];
|
|
137893
|
+
}
|
|
137894
|
+
function fmtCommas(n3) {
|
|
137895
|
+
return Math.round(n3).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
137896
|
+
}
|
|
137897
|
+
function getMeasurementLabel(shape, physicalPixelSize, viewType = ViewType.SPATIAL) {
|
|
137898
|
+
const pps = physicalPixelSize;
|
|
137899
|
+
const px = pps?.x ?? 1;
|
|
137900
|
+
const py = pps?.y ?? 1;
|
|
137901
|
+
const unit2 = pps ? pps.unit ?? "" : null;
|
|
137902
|
+
const hasPhys = !!pps;
|
|
137903
|
+
const isEmbedding = viewType === ViewType.SCATTERPLOT;
|
|
137904
|
+
const fmtDist = (d) => {
|
|
137905
|
+
if (hasPhys)
|
|
137906
|
+
return `${d.toFixed(2)} ${unit2}`;
|
|
137907
|
+
if (isEmbedding)
|
|
137908
|
+
return d.toFixed(2);
|
|
137909
|
+
return `${fmtCommas(d)} px`;
|
|
137910
|
+
};
|
|
137911
|
+
const fmtArea = (a2) => {
|
|
137912
|
+
if (hasPhys)
|
|
137913
|
+
return `${a2.toFixed(2)} ${unit2}²`;
|
|
137914
|
+
if (isEmbedding)
|
|
137915
|
+
return a2.toFixed(2);
|
|
137916
|
+
return `${fmtCommas(a2)} px²`;
|
|
137917
|
+
};
|
|
137918
|
+
if (shape.type === "line") {
|
|
137919
|
+
const dx = (shape.x2 ?? 0) - (shape.x1 ?? 0);
|
|
137920
|
+
const dy = (shape.y2 ?? 0) - (shape.y1 ?? 0);
|
|
137921
|
+
const dist2 = hasPhys ? Math.sqrt((dx * px) ** 2 + (dy * py) ** 2) : Math.sqrt(dx * dx + dy * dy);
|
|
137922
|
+
return fmtDist(dist2);
|
|
137923
|
+
}
|
|
137924
|
+
if (shape.type === "rectangle") {
|
|
137925
|
+
return fmtArea(hasPhys ? Math.abs(shape.width ?? 0) * px * Math.abs(shape.height ?? 0) * py : Math.abs((shape.width ?? 0) * (shape.height ?? 0)));
|
|
137926
|
+
}
|
|
137927
|
+
if (shape.type === "ellipse") {
|
|
137928
|
+
const rx = Math.abs(shape.radiusX ?? 0);
|
|
137929
|
+
const ry = Math.abs(shape.radiusY ?? 0);
|
|
137930
|
+
return fmtArea(hasPhys ? Math.PI * rx * px * ry * py : Math.PI * rx * ry);
|
|
137931
|
+
}
|
|
137932
|
+
if (shape.type === "polygon" && shape.points?.length >= 3) {
|
|
137933
|
+
const pts = shape.points;
|
|
137934
|
+
let shoelace = 0;
|
|
137935
|
+
for (let i2 = 0; i2 < pts.length; i2++) {
|
|
137936
|
+
const [ax, ay] = pts[i2];
|
|
137937
|
+
const [bx, by] = pts[(i2 + 1) % pts.length];
|
|
137938
|
+
shoelace += (hasPhys ? ax * px : ax) * (hasPhys ? by * py : by) - (hasPhys ? bx * px : bx) * (hasPhys ? ay * py : ay);
|
|
137939
|
+
}
|
|
137940
|
+
return fmtArea(Math.abs(shoelace / 2));
|
|
137941
|
+
}
|
|
137942
|
+
if (shape.type === "polyline" && shape.points?.length >= 2) {
|
|
137943
|
+
let total = 0;
|
|
137944
|
+
for (let i2 = 0; i2 < shape.points.length - 1; i2++) {
|
|
137945
|
+
const [ax, ay] = shape.points[i2];
|
|
137946
|
+
const [bx, by] = shape.points[i2 + 1];
|
|
137947
|
+
total += hasPhys ? Math.sqrt(((bx - ax) * px) ** 2 + ((by - ay) * py) ** 2) : Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2);
|
|
137948
|
+
}
|
|
137949
|
+
return fmtDist(total);
|
|
137950
|
+
}
|
|
137951
|
+
return null;
|
|
137952
|
+
}
|
|
137953
|
+
function pickBelowPerp(ux, uy) {
|
|
137954
|
+
const rp = [uy, -ux];
|
|
137955
|
+
const lp = [-uy, ux];
|
|
137956
|
+
return rp[1] > lp[1] || rp[1] === lp[1] && rp[0] > lp[0] ? rp : lp;
|
|
137957
|
+
}
|
|
137958
|
+
function readableAngle(deg) {
|
|
137959
|
+
let a2 = deg;
|
|
137960
|
+
if (a2 > 90)
|
|
137961
|
+
a2 -= 180;
|
|
137962
|
+
if (a2 < -90)
|
|
137963
|
+
a2 += 180;
|
|
137964
|
+
return a2;
|
|
137965
|
+
}
|
|
137966
|
+
function getShapeCentroid(shape) {
|
|
137967
|
+
if (shape.type === "rectangle") {
|
|
137968
|
+
return [(shape.x ?? 0) + (shape.width ?? 0) / 2, (shape.y ?? 0) + (shape.height ?? 0) / 2];
|
|
137969
|
+
}
|
|
137970
|
+
if (shape.type === "line") {
|
|
137971
|
+
return [((shape.x1 ?? 0) + (shape.x2 ?? 0)) / 2, ((shape.y1 ?? 0) + (shape.y2 ?? 0)) / 2];
|
|
137972
|
+
}
|
|
137973
|
+
if (shape.type === "ellipse") {
|
|
137974
|
+
return [shape.x1 ?? 0, shape.y1 ?? 0];
|
|
137975
|
+
}
|
|
137976
|
+
if ((shape.type === "polygon" || shape.type === "polyline") && shape.points?.length >= 1) {
|
|
137977
|
+
const mx = shape.points.reduce((s2, p) => s2 + p[0], 0) / shape.points.length;
|
|
137978
|
+
const my = shape.points.reduce((s2, p) => s2 + p[1], 0) / shape.points.length;
|
|
137979
|
+
return [mx, my];
|
|
137980
|
+
}
|
|
137981
|
+
return [0, 0];
|
|
137982
|
+
}
|
|
137983
|
+
function computeClusters(shapeList, zoom, cellPx = 50) {
|
|
137984
|
+
const cellSize = cellPx / 2 ** Math.floor(zoom);
|
|
137985
|
+
const cells = /* @__PURE__ */ new Map();
|
|
137986
|
+
shapeList.forEach(({ shape }) => {
|
|
137987
|
+
const [cx, cy] = getShapeCentroid(shape);
|
|
137988
|
+
const key = `${Math.floor(cx / cellSize)},${Math.floor(cy / cellSize)}`;
|
|
137989
|
+
if (!cells.has(key)) {
|
|
137990
|
+
cells.set(key, { sumX: 0, sumY: 0, count: 0, color: shape.strokeColor ?? [255, 255, 255] });
|
|
137991
|
+
}
|
|
137992
|
+
const c = cells.get(key);
|
|
137993
|
+
c.sumX += cx;
|
|
137994
|
+
c.sumY += cy;
|
|
137995
|
+
c.count++;
|
|
137996
|
+
});
|
|
137997
|
+
return Array.from(cells.values()).map((c) => ({
|
|
137998
|
+
position: [c.sumX / c.count, c.sumY / c.count, 0],
|
|
137999
|
+
count: c.count,
|
|
138000
|
+
color: c.color
|
|
138001
|
+
}));
|
|
138002
|
+
}
|
|
138003
|
+
function createAnnotationLayers(shapes = [], zoom = 0, selectedShapeUid = null, physicalPixelSize = null, authoredZoom = null, semanticZoom = true, viewType = ViewType.SPATIAL) {
|
|
138004
|
+
const selectionLayers = [];
|
|
138005
|
+
if (selectedShapeUid) {
|
|
138006
|
+
const sel = shapes.find((s2) => s2.uid === selectedShapeUid);
|
|
138007
|
+
if (sel) {
|
|
138008
|
+
const { uid: sUid, type: sType, strokeWidth: sStrokeWidth = 3 } = sel;
|
|
138009
|
+
const haloColor = [255, 220, 50, 70];
|
|
138010
|
+
const haloWidth = Math.max(sStrokeWidth + 8, 10);
|
|
138011
|
+
const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN };
|
|
138012
|
+
if (sType === "rectangle") {
|
|
138013
|
+
const { x, y, width, height } = sel;
|
|
138014
|
+
selectionLayers.push(new PathLayer({
|
|
138015
|
+
...base,
|
|
138016
|
+
id: `annotation-select-${sUid}`,
|
|
138017
|
+
data: [{
|
|
138018
|
+
path: [
|
|
138019
|
+
[x, y],
|
|
138020
|
+
[x + width, y],
|
|
138021
|
+
[x + width, y + height],
|
|
138022
|
+
[x, y + height],
|
|
138023
|
+
[x, y]
|
|
138024
|
+
]
|
|
138025
|
+
}],
|
|
138026
|
+
getPath: (d) => d.path,
|
|
138027
|
+
getColor: haloColor,
|
|
138028
|
+
getWidth: haloWidth,
|
|
138029
|
+
widthUnits: "pixels",
|
|
138030
|
+
jointRounded: true,
|
|
138031
|
+
capRounded: true
|
|
138032
|
+
}));
|
|
138033
|
+
}
|
|
138034
|
+
if (sType === "line") {
|
|
138035
|
+
const { x1: x12, y1: y12, x2, y2 } = sel;
|
|
138036
|
+
selectionLayers.push(new PathLayer({
|
|
138037
|
+
...base,
|
|
138038
|
+
id: `annotation-select-${sUid}`,
|
|
138039
|
+
data: [{ path: [[x12, y12], [x2, y2]] }],
|
|
138040
|
+
getPath: (d) => d.path,
|
|
138041
|
+
getColor: haloColor,
|
|
138042
|
+
getWidth: haloWidth,
|
|
138043
|
+
widthUnits: "pixels",
|
|
138044
|
+
capRounded: true
|
|
138045
|
+
}));
|
|
138046
|
+
}
|
|
138047
|
+
if (sType === "ellipse") {
|
|
138048
|
+
const polygon2 = computeEllipsePolygon(sel.x1, sel.y1, sel.radiusX, sel.radiusY);
|
|
138049
|
+
selectionLayers.push(new PathLayer({
|
|
138050
|
+
...base,
|
|
138051
|
+
id: `annotation-select-${sUid}`,
|
|
138052
|
+
data: [{ path: [...polygon2, polygon2[0]] }],
|
|
138053
|
+
getPath: (d) => d.path,
|
|
138054
|
+
getColor: haloColor,
|
|
138055
|
+
getWidth: haloWidth,
|
|
138056
|
+
widthUnits: "pixels",
|
|
138057
|
+
jointRounded: true
|
|
138058
|
+
}));
|
|
138059
|
+
}
|
|
138060
|
+
if (sType === "polygon" && sel.points?.length >= 3) {
|
|
138061
|
+
selectionLayers.push(new PathLayer({
|
|
138062
|
+
...base,
|
|
138063
|
+
id: `annotation-select-${sUid}`,
|
|
138064
|
+
data: [{ path: [...sel.points, sel.points[0]] }],
|
|
138065
|
+
getPath: (d) => d.path,
|
|
138066
|
+
getColor: haloColor,
|
|
138067
|
+
getWidth: haloWidth,
|
|
138068
|
+
widthUnits: "pixels",
|
|
138069
|
+
jointRounded: true
|
|
138070
|
+
}));
|
|
138071
|
+
}
|
|
138072
|
+
if (sType === "polyline" && sel.points?.length >= 2) {
|
|
138073
|
+
selectionLayers.push(new PathLayer({
|
|
138074
|
+
...base,
|
|
138075
|
+
id: `annotation-select-${sUid}`,
|
|
138076
|
+
data: [{ path: sel.points }],
|
|
138077
|
+
getPath: (d) => d.path,
|
|
138078
|
+
getColor: haloColor,
|
|
138079
|
+
getWidth: haloWidth,
|
|
138080
|
+
widthUnits: "pixels",
|
|
138081
|
+
jointRounded: true,
|
|
138082
|
+
capRounded: true
|
|
138083
|
+
}));
|
|
138084
|
+
}
|
|
138085
|
+
}
|
|
138086
|
+
}
|
|
138087
|
+
const layers = [];
|
|
138088
|
+
const dotShapes = [];
|
|
138089
|
+
const clusterDotShapes = [];
|
|
138090
|
+
shapes.forEach((shape, i2) => {
|
|
138091
|
+
const { uid: uid2, type, strokeColor = [255, 255, 255], strokeWidth = 3, strokeDashArray } = shape;
|
|
138092
|
+
const isSelected = uid2 === selectedShapeUid;
|
|
138093
|
+
let shapeOpacity = 1;
|
|
138094
|
+
let tipsOpacity = 1;
|
|
138095
|
+
let labelOpacity = 0;
|
|
138096
|
+
if (isSelected || !semanticZoom || authoredZoom === null) {
|
|
138097
|
+
tipsOpacity = 1;
|
|
138098
|
+
labelOpacity = 1;
|
|
138099
|
+
} else {
|
|
138100
|
+
const zoomRatio = 2 ** (zoom - authoredZoom);
|
|
138101
|
+
if (zoomRatio < RATIO_CLUSTER) {
|
|
138102
|
+
clusterDotShapes.push({ shape });
|
|
138103
|
+
return;
|
|
138104
|
+
}
|
|
138105
|
+
if (zoomRatio < RATIO_DOT) {
|
|
138106
|
+
dotShapes.push({ shape, alpha: 200 });
|
|
138107
|
+
return;
|
|
138108
|
+
}
|
|
138109
|
+
if (zoomRatio < RATIO_GEO_FADE) {
|
|
138110
|
+
const t = (zoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
|
|
138111
|
+
shapeOpacity = t;
|
|
138112
|
+
dotShapes.push({ shape, alpha: Math.round((1 - t) * 200) });
|
|
138113
|
+
}
|
|
138114
|
+
tipsOpacity = zoomRatio >= RATIO_TIPS ? shapeOpacity : Math.max(0, (zoomRatio - RATIO_GEO_FADE) / (RATIO_TIPS - RATIO_GEO_FADE) * shapeOpacity);
|
|
138115
|
+
if (zoomRatio >= RATIO_LABEL_FULL) {
|
|
138116
|
+
labelOpacity = shapeOpacity;
|
|
138117
|
+
} else if (zoomRatio >= RATIO_LABEL) {
|
|
138118
|
+
labelOpacity = (zoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL) * shapeOpacity;
|
|
138119
|
+
}
|
|
138120
|
+
}
|
|
138121
|
+
const arrowDataSize = Math.max(ARROW_SCREEN_PX, strokeWidth * 4) / 2 ** zoom;
|
|
138122
|
+
const base = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: shapeOpacity };
|
|
138123
|
+
const tipsBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: tipsOpacity };
|
|
138124
|
+
const labelBase = { coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, opacity: labelOpacity };
|
|
138125
|
+
const labelBgProps = shape.labelBackground ? {
|
|
138126
|
+
background: true,
|
|
138127
|
+
getBackgroundColor: textBgColor(strokeColor),
|
|
138128
|
+
backgroundPadding: [3, 1, 3, 2]
|
|
138129
|
+
} : {};
|
|
138130
|
+
const labelProps = { ...labelBgProps };
|
|
138131
|
+
const dashArray = parseDashArray(strokeDashArray);
|
|
138132
|
+
const dashExt = [new PathStyleExtension({ dash: true })];
|
|
138133
|
+
const getDash = dashArray ?? [0, 0];
|
|
138134
|
+
if (type === "rectangle") {
|
|
138135
|
+
const { x, y, width, height, fillColor = strokeColor, fillOpacity = 0 } = shape;
|
|
138136
|
+
const filled = fillOpacity > 0;
|
|
138137
|
+
const rectPolygon = [[x, y], [x + width, y], [x + width, y + height], [x, y + height]];
|
|
138138
|
+
layers.push(new PolygonLayer({
|
|
138139
|
+
...base,
|
|
138140
|
+
id: `annotation-rect-${uid2}-${i2}`,
|
|
138141
|
+
data: [{ polygon: rectPolygon }],
|
|
138142
|
+
getPolygon: (d) => d.polygon,
|
|
138143
|
+
filled,
|
|
138144
|
+
stroked: true,
|
|
138145
|
+
getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
|
|
138146
|
+
getLineColor: strokeColor,
|
|
138147
|
+
getLineWidth: strokeWidth,
|
|
138148
|
+
lineWidthUnits: "pixels",
|
|
138149
|
+
...dashArray ? {
|
|
138150
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
138151
|
+
getDashArray: dashArray
|
|
138152
|
+
} : {}
|
|
138153
|
+
}));
|
|
138154
|
+
if (shape.text && labelOpacity > 0) {
|
|
138155
|
+
layers.push(new TextLayer({
|
|
138156
|
+
...labelBase,
|
|
138157
|
+
...labelProps,
|
|
138158
|
+
id: `annotation-rect-text-${uid2}-${i2}`,
|
|
138159
|
+
data: [{ position: [x, y], text: shape.text }],
|
|
138160
|
+
getPosition: (d) => d.position,
|
|
138161
|
+
getText: (d) => d.text,
|
|
138162
|
+
getColor: strokeColor,
|
|
138163
|
+
getSize: LABEL_FONT_SIZE,
|
|
138164
|
+
sizeUnits: "pixels",
|
|
138165
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138166
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
138167
|
+
getPixelOffset: [3, -7],
|
|
138168
|
+
getTextAnchor: "start",
|
|
138169
|
+
getAlignmentBaseline: "bottom"
|
|
138170
|
+
}));
|
|
138171
|
+
}
|
|
138172
|
+
}
|
|
138173
|
+
if (type === "line") {
|
|
138174
|
+
const { x1: x12, y1: y12, x2, y2, markerStart, markerEnd } = shape;
|
|
138175
|
+
const dx = x2 - x12;
|
|
138176
|
+
const dy = y2 - y12;
|
|
138177
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
138178
|
+
const ux = len2 > 0 ? dx / len2 : 0;
|
|
138179
|
+
const uy = len2 > 0 ? dy / len2 : 0;
|
|
138180
|
+
const srcX = markerStart === "Arrow" ? x12 + ux * arrowDataSize : x12;
|
|
138181
|
+
const srcY = markerStart === "Arrow" ? y12 + uy * arrowDataSize : y12;
|
|
138182
|
+
const tgtX = markerEnd === "Arrow" ? x2 - ux * arrowDataSize : x2;
|
|
138183
|
+
const tgtY = markerEnd === "Arrow" ? y2 - uy * arrowDataSize : y2;
|
|
138184
|
+
layers.push(new PathLayer({
|
|
138185
|
+
...base,
|
|
138186
|
+
id: `annotation-line-${uid2}-${i2}`,
|
|
138187
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
138188
|
+
getDashArray: dashArray ?? [0, 0],
|
|
138189
|
+
data: [{ path: [[srcX, srcY], [tgtX, tgtY]] }],
|
|
138190
|
+
getPath: (d) => d.path,
|
|
138191
|
+
getColor: strokeColor,
|
|
138192
|
+
getWidth: strokeWidth,
|
|
138193
|
+
widthUnits: "pixels",
|
|
138194
|
+
capRounded: true
|
|
138195
|
+
}));
|
|
138196
|
+
if (markerEnd === "Arrow" && tipsOpacity > 0) {
|
|
138197
|
+
const head = computeArrowhead(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
|
|
138198
|
+
if (head) {
|
|
138199
|
+
layers.push(new PolygonLayer({
|
|
138200
|
+
...tipsBase,
|
|
138201
|
+
id: `annotation-end-arrow-${uid2}-${i2}`,
|
|
138202
|
+
data: [{ polygon: head }],
|
|
138203
|
+
getPolygon: (d) => d.polygon,
|
|
138204
|
+
filled: true,
|
|
138205
|
+
stroked: false,
|
|
138206
|
+
getFillColor: strokeColor
|
|
138207
|
+
}));
|
|
138208
|
+
}
|
|
138209
|
+
}
|
|
138210
|
+
if (markerStart === "Arrow" && tipsOpacity > 0) {
|
|
138211
|
+
const head = computeArrowhead(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
|
|
138212
|
+
if (head) {
|
|
138213
|
+
layers.push(new PolygonLayer({
|
|
138214
|
+
...tipsBase,
|
|
138215
|
+
id: `annotation-start-arrow-${uid2}-${i2}`,
|
|
138216
|
+
data: [{ polygon: head }],
|
|
138217
|
+
getPolygon: (d) => d.polygon,
|
|
138218
|
+
filled: true,
|
|
138219
|
+
stroked: false,
|
|
138220
|
+
getFillColor: strokeColor
|
|
138221
|
+
}));
|
|
138222
|
+
}
|
|
138223
|
+
}
|
|
138224
|
+
if (markerEnd === "Tick" && tipsOpacity > 0) {
|
|
138225
|
+
const tick = computeTickCap(x2, y2, x2 - x12, y2 - y12, arrowDataSize);
|
|
138226
|
+
if (tick) {
|
|
138227
|
+
layers.push(new PathLayer({
|
|
138228
|
+
...tipsBase,
|
|
138229
|
+
id: `annotation-end-tick-${uid2}-${i2}`,
|
|
138230
|
+
data: [{ path: tick }],
|
|
138231
|
+
getPath: (d) => d.path,
|
|
138232
|
+
getColor: strokeColor,
|
|
138233
|
+
getWidth: strokeWidth,
|
|
138234
|
+
widthUnits: "pixels",
|
|
138235
|
+
capRounded: true
|
|
138236
|
+
}));
|
|
138237
|
+
}
|
|
138238
|
+
}
|
|
138239
|
+
if (markerStart === "Tick" && tipsOpacity > 0) {
|
|
138240
|
+
const tick = computeTickCap(x12, y12, x12 - x2, y12 - y2, arrowDataSize);
|
|
138241
|
+
if (tick) {
|
|
138242
|
+
layers.push(new PathLayer({
|
|
138243
|
+
...tipsBase,
|
|
138244
|
+
id: `annotation-start-tick-${uid2}-${i2}`,
|
|
138245
|
+
data: [{ path: tick }],
|
|
138246
|
+
getPath: (d) => d.path,
|
|
138247
|
+
getColor: strokeColor,
|
|
138248
|
+
getWidth: strokeWidth,
|
|
138249
|
+
widthUnits: "pixels",
|
|
138250
|
+
capRounded: true
|
|
138251
|
+
}));
|
|
138252
|
+
}
|
|
138253
|
+
}
|
|
138254
|
+
if (shape.text) {
|
|
138255
|
+
const pos = shape.textPosition ?? "start";
|
|
138256
|
+
let textX;
|
|
138257
|
+
let textY;
|
|
138258
|
+
if (pos === "start") {
|
|
138259
|
+
textX = x12;
|
|
138260
|
+
textY = y12;
|
|
138261
|
+
} else if (pos === "end") {
|
|
138262
|
+
textX = x2;
|
|
138263
|
+
textY = y2;
|
|
138264
|
+
} else {
|
|
138265
|
+
textX = (x12 + x2) / 2;
|
|
138266
|
+
textY = (y12 + y2) / 2;
|
|
138267
|
+
}
|
|
138268
|
+
let pixelOffset = [0, 0];
|
|
138269
|
+
let textAnchor = "middle";
|
|
138270
|
+
let alignmentBaseline = "center";
|
|
138271
|
+
if (pos !== "middle") {
|
|
138272
|
+
const dxT = x2 - x12;
|
|
138273
|
+
const dyT = y2 - y12;
|
|
138274
|
+
const lenT = Math.sqrt(dxT * dxT + dyT * dyT);
|
|
138275
|
+
if (lenT > 0) {
|
|
138276
|
+
const uxT = dxT / lenT;
|
|
138277
|
+
const uyT = dyT / lenT;
|
|
138278
|
+
const sign2 = pos === "start" ? -1 : 1;
|
|
138279
|
+
const bufferPx = shape.textBufferPx ?? 8;
|
|
138280
|
+
const offsetX = sign2 * uxT * bufferPx;
|
|
138281
|
+
const offsetY = sign2 * uyT * bufferPx;
|
|
138282
|
+
pixelOffset = [offsetX, offsetY];
|
|
138283
|
+
const absX = Math.abs(offsetX);
|
|
138284
|
+
const absY = Math.abs(offsetY);
|
|
138285
|
+
if (absX >= absY) {
|
|
138286
|
+
textAnchor = offsetX > 0 ? "start" : "end";
|
|
138287
|
+
}
|
|
138288
|
+
if (absY >= absX) {
|
|
138289
|
+
alignmentBaseline = offsetY > 0 ? "top" : "bottom";
|
|
138290
|
+
}
|
|
138291
|
+
}
|
|
138292
|
+
} else if (len2 > 0) {
|
|
138293
|
+
const belowPerp = pickBelowPerp(ux, uy);
|
|
138294
|
+
const bufferPx = shape.textBufferPx ?? 14;
|
|
138295
|
+
pixelOffset = [-belowPerp[0] * bufferPx, -belowPerp[1] * bufferPx];
|
|
138296
|
+
textAnchor = "middle";
|
|
138297
|
+
alignmentBaseline = "center";
|
|
138298
|
+
}
|
|
138299
|
+
const middleAngle = pos === "middle" && len2 > 0 ? -readableAngle(Math.atan2(dy, dx) * 180 / Math.PI) : null;
|
|
138300
|
+
if (labelOpacity <= 0)
|
|
138301
|
+
return;
|
|
138302
|
+
layers.push(new TextLayer({
|
|
138303
|
+
...labelBase,
|
|
138304
|
+
...labelProps,
|
|
138305
|
+
id: `annotation-line-text-${uid2}-${i2}`,
|
|
138306
|
+
data: [{ position: [textX, textY], text: shape.text }],
|
|
138307
|
+
getPosition: (d) => d.position,
|
|
138308
|
+
getText: (d) => d.text,
|
|
138309
|
+
getColor: strokeColor,
|
|
138310
|
+
getSize: LABEL_FONT_SIZE,
|
|
138311
|
+
sizeUnits: "pixels",
|
|
138312
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138313
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
138314
|
+
getPixelOffset: pixelOffset,
|
|
138315
|
+
getTextAnchor: textAnchor,
|
|
138316
|
+
getAlignmentBaseline: alignmentBaseline,
|
|
138317
|
+
...middleAngle !== null && { getAngle: middleAngle }
|
|
138318
|
+
}));
|
|
138319
|
+
}
|
|
138320
|
+
}
|
|
138321
|
+
if (type === "ellipse") {
|
|
138322
|
+
const { x1: x12, y1: y12, radiusX, radiusY, fillColor = strokeColor, fillOpacity = 0 } = shape;
|
|
138323
|
+
const polygon2 = computeEllipsePolygon(x12, y12, radiusX, radiusY);
|
|
138324
|
+
const filled = fillOpacity > 0;
|
|
138325
|
+
layers.push(new PolygonLayer({
|
|
138326
|
+
...base,
|
|
138327
|
+
id: `annotation-ellipse-${uid2}-${i2}`,
|
|
138328
|
+
data: [{ polygon: polygon2 }],
|
|
138329
|
+
getPolygon: (d) => d.polygon,
|
|
138330
|
+
filled,
|
|
138331
|
+
stroked: true,
|
|
138332
|
+
getFillColor: filled ? [...fillColor, Math.round(fillOpacity * 255)] : [0, 0, 0, 0],
|
|
138333
|
+
getLineColor: strokeColor,
|
|
138334
|
+
getLineWidth: strokeWidth,
|
|
138335
|
+
lineWidthUnits: "pixels",
|
|
138336
|
+
...dashArray ? {
|
|
138337
|
+
extensions: [new PathStyleExtension({ dash: true })],
|
|
138338
|
+
getDashArray: dashArray
|
|
138339
|
+
} : {}
|
|
138340
|
+
}));
|
|
138341
|
+
if (shape.text && labelOpacity > 0) {
|
|
138342
|
+
layers.push(new TextLayer({
|
|
138343
|
+
...labelBase,
|
|
138344
|
+
...labelProps,
|
|
138345
|
+
id: `annotation-ellipse-text-${uid2}-${i2}`,
|
|
138346
|
+
data: [{ position: [x12, y12 - radiusY], text: shape.text }],
|
|
138347
|
+
getPosition: (d) => d.position,
|
|
138348
|
+
getText: (d) => d.text,
|
|
138349
|
+
getColor: strokeColor,
|
|
138350
|
+
getSize: LABEL_FONT_SIZE,
|
|
138351
|
+
sizeUnits: "pixels",
|
|
138352
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138353
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
138354
|
+
getPixelOffset: [0, -4],
|
|
138355
|
+
getTextAnchor: "middle",
|
|
138356
|
+
getAlignmentBaseline: "bottom"
|
|
138357
|
+
}));
|
|
138358
|
+
}
|
|
138359
|
+
}
|
|
138360
|
+
if (type === "polygon") {
|
|
138361
|
+
const { points, fillColor = strokeColor, fillOpacity = 0 } = shape;
|
|
138362
|
+
if (!points || points.length < 3)
|
|
138363
|
+
return;
|
|
138364
|
+
const closedPath = [...points, points[0]];
|
|
138365
|
+
if (fillOpacity > 0) {
|
|
138366
|
+
layers.push(new PolygonLayer({
|
|
138367
|
+
...base,
|
|
138368
|
+
id: `annotation-polygon-fill-${uid2}-${i2}`,
|
|
138369
|
+
data: [{ polygon: points }],
|
|
138370
|
+
getPolygon: (d) => d.polygon,
|
|
138371
|
+
stroked: false,
|
|
138372
|
+
filled: true,
|
|
138373
|
+
getFillColor: [...fillColor, Math.round(fillOpacity * 255)]
|
|
138374
|
+
}));
|
|
138375
|
+
}
|
|
138376
|
+
layers.push(new PathLayer({
|
|
138377
|
+
...base,
|
|
138378
|
+
id: `annotation-polygon-${uid2}-${i2}`,
|
|
138379
|
+
extensions: dashExt,
|
|
138380
|
+
getDashArray: getDash,
|
|
138381
|
+
data: [{ path: closedPath }],
|
|
138382
|
+
getPath: (d) => d.path,
|
|
138383
|
+
getColor: strokeColor,
|
|
138384
|
+
getWidth: strokeWidth,
|
|
138385
|
+
widthUnits: "pixels",
|
|
138386
|
+
jointRounded: true
|
|
138387
|
+
}));
|
|
138388
|
+
if (shape.text && labelOpacity > 0) {
|
|
138389
|
+
const minX = Math.min(...points.map((p) => p[0]));
|
|
138390
|
+
const maxX = Math.max(...points.map((p) => p[0]));
|
|
138391
|
+
const minY = Math.min(...points.map((p) => p[1]));
|
|
138392
|
+
const topCenterX = (minX + maxX) / 2;
|
|
138393
|
+
layers.push(new TextLayer({
|
|
138394
|
+
...labelBase,
|
|
138395
|
+
...labelProps,
|
|
138396
|
+
id: `annotation-polygon-text-${uid2}-${i2}`,
|
|
138397
|
+
data: [{ position: [topCenterX, minY], text: shape.text }],
|
|
138398
|
+
getPosition: (d) => d.position,
|
|
138399
|
+
getText: (d) => d.text,
|
|
138400
|
+
getColor: strokeColor,
|
|
138401
|
+
getSize: LABEL_FONT_SIZE,
|
|
138402
|
+
sizeUnits: "pixels",
|
|
138403
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138404
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
138405
|
+
getPixelOffset: [0, -4],
|
|
138406
|
+
getTextAnchor: "middle",
|
|
138407
|
+
getAlignmentBaseline: "bottom"
|
|
138408
|
+
}));
|
|
138409
|
+
}
|
|
138410
|
+
}
|
|
138411
|
+
if (type === "polyline") {
|
|
138412
|
+
const { points, markerStart, markerEnd } = shape;
|
|
138413
|
+
if (!points || points.length < 2)
|
|
138414
|
+
return;
|
|
138415
|
+
let pathPoints = points;
|
|
138416
|
+
if (markerStart === "Arrow") {
|
|
138417
|
+
const [x02, y02] = points[0];
|
|
138418
|
+
const [x12, y12] = points[1];
|
|
138419
|
+
const dx = x02 - x12;
|
|
138420
|
+
const dy = y02 - y12;
|
|
138421
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
138422
|
+
if (len2 > 0) {
|
|
138423
|
+
const ux = dx / len2;
|
|
138424
|
+
const uy = dy / len2;
|
|
138425
|
+
pathPoints = [[x02 - ux * arrowDataSize, y02 - uy * arrowDataSize], ...pathPoints.slice(1)];
|
|
138426
|
+
}
|
|
138427
|
+
}
|
|
138428
|
+
if (markerEnd === "Arrow") {
|
|
138429
|
+
const last = pathPoints[pathPoints.length - 1];
|
|
138430
|
+
const prev = pathPoints[pathPoints.length - 2];
|
|
138431
|
+
const dx = last[0] - prev[0];
|
|
138432
|
+
const dy = last[1] - prev[1];
|
|
138433
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
138434
|
+
if (len2 > 0) {
|
|
138435
|
+
const ux = dx / len2;
|
|
138436
|
+
const uy = dy / len2;
|
|
138437
|
+
const shortened = [last[0] - ux * arrowDataSize, last[1] - uy * arrowDataSize];
|
|
138438
|
+
pathPoints = [...pathPoints.slice(0, -1), shortened];
|
|
138439
|
+
}
|
|
138440
|
+
}
|
|
138441
|
+
layers.push(new PathLayer({
|
|
138442
|
+
...base,
|
|
138443
|
+
id: `annotation-polyline-${uid2}-${i2}`,
|
|
138444
|
+
extensions: dashExt,
|
|
138445
|
+
getDashArray: getDash,
|
|
138446
|
+
data: [{ path: pathPoints }],
|
|
138447
|
+
getPath: (d) => d.path,
|
|
138448
|
+
getColor: strokeColor,
|
|
138449
|
+
getWidth: strokeWidth,
|
|
138450
|
+
widthUnits: "pixels",
|
|
138451
|
+
jointRounded: true,
|
|
138452
|
+
capRounded: true
|
|
138453
|
+
}));
|
|
138454
|
+
if (markerStart === "Arrow" && tipsOpacity > 0) {
|
|
138455
|
+
const [x02, y02] = points[0];
|
|
138456
|
+
const [x12, y12] = points[1];
|
|
138457
|
+
const head = computeArrowhead(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
|
|
138458
|
+
if (head) {
|
|
138459
|
+
layers.push(new PolygonLayer({
|
|
138460
|
+
...tipsBase,
|
|
138461
|
+
id: `annotation-polyline-start-arrow-${uid2}-${i2}`,
|
|
138462
|
+
data: [{ polygon: head }],
|
|
138463
|
+
getPolygon: (d) => d.polygon,
|
|
138464
|
+
filled: true,
|
|
138465
|
+
stroked: false,
|
|
138466
|
+
getFillColor: strokeColor
|
|
138467
|
+
}));
|
|
138468
|
+
}
|
|
138469
|
+
}
|
|
138470
|
+
if (markerEnd === "Arrow" && tipsOpacity > 0) {
|
|
138471
|
+
const last = points[points.length - 1];
|
|
138472
|
+
const prev = points[points.length - 2];
|
|
138473
|
+
const dxArrow = last[0] - prev[0];
|
|
138474
|
+
const dyArrow = last[1] - prev[1];
|
|
138475
|
+
const head = computeArrowhead(last[0], last[1], dxArrow, dyArrow, arrowDataSize);
|
|
138476
|
+
if (head) {
|
|
138477
|
+
layers.push(new PolygonLayer({
|
|
138478
|
+
...tipsBase,
|
|
138479
|
+
id: `annotation-polyline-end-arrow-${uid2}-${i2}`,
|
|
138480
|
+
data: [{ polygon: head }],
|
|
138481
|
+
getPolygon: (d) => d.polygon,
|
|
138482
|
+
filled: true,
|
|
138483
|
+
stroked: false,
|
|
138484
|
+
getFillColor: strokeColor
|
|
138485
|
+
}));
|
|
138486
|
+
}
|
|
138487
|
+
}
|
|
138488
|
+
if (markerStart === "Tick" && tipsOpacity > 0) {
|
|
138489
|
+
const [x02, y02] = points[0];
|
|
138490
|
+
const [x12, y12] = points[1];
|
|
138491
|
+
const tick = computeTickCap(x02, y02, x02 - x12, y02 - y12, arrowDataSize);
|
|
138492
|
+
if (tick) {
|
|
138493
|
+
layers.push(new PathLayer({
|
|
138494
|
+
...tipsBase,
|
|
138495
|
+
id: `annotation-polyline-start-tick-${uid2}-${i2}`,
|
|
138496
|
+
data: [{ path: tick }],
|
|
138497
|
+
getPath: (d) => d.path,
|
|
138498
|
+
getColor: strokeColor,
|
|
138499
|
+
getWidth: strokeWidth,
|
|
138500
|
+
widthUnits: "pixels",
|
|
138501
|
+
capRounded: true
|
|
138502
|
+
}));
|
|
138503
|
+
}
|
|
138504
|
+
}
|
|
138505
|
+
if (markerEnd === "Tick" && tipsOpacity > 0) {
|
|
138506
|
+
const last = points[points.length - 1];
|
|
138507
|
+
const prev = points[points.length - 2];
|
|
138508
|
+
const dxTick = last[0] - prev[0];
|
|
138509
|
+
const dyTick = last[1] - prev[1];
|
|
138510
|
+
const tick = computeTickCap(last[0], last[1], dxTick, dyTick, arrowDataSize);
|
|
138511
|
+
if (tick) {
|
|
138512
|
+
layers.push(new PathLayer({
|
|
138513
|
+
...tipsBase,
|
|
138514
|
+
id: `annotation-polyline-end-tick-${uid2}-${i2}`,
|
|
138515
|
+
data: [{ path: tick }],
|
|
138516
|
+
getPath: (d) => d.path,
|
|
138517
|
+
getColor: strokeColor,
|
|
138518
|
+
getWidth: strokeWidth,
|
|
138519
|
+
widthUnits: "pixels",
|
|
138520
|
+
capRounded: true
|
|
138521
|
+
}));
|
|
138522
|
+
}
|
|
138523
|
+
}
|
|
138524
|
+
if (shape.text) {
|
|
138525
|
+
const pos = shape.textPosition ?? "start";
|
|
138526
|
+
const bufferPx = shape.textBufferPx ?? 8;
|
|
138527
|
+
let textPt;
|
|
138528
|
+
let dirX;
|
|
138529
|
+
let dirY;
|
|
138530
|
+
if (pos === "end") {
|
|
138531
|
+
const last = points[points.length - 1];
|
|
138532
|
+
const prev = points[points.length - 2];
|
|
138533
|
+
textPt = last;
|
|
138534
|
+
dirX = last[0] - prev[0];
|
|
138535
|
+
dirY = last[1] - prev[1];
|
|
138536
|
+
} else if (pos === "middle") {
|
|
138537
|
+
const mx = points.reduce((s2, p) => s2 + p[0], 0) / points.length;
|
|
138538
|
+
const my = points.reduce((s2, p) => s2 + p[1], 0) / points.length;
|
|
138539
|
+
textPt = [mx, my];
|
|
138540
|
+
dirX = 0;
|
|
138541
|
+
dirY = 0;
|
|
138542
|
+
} else {
|
|
138543
|
+
[textPt] = points;
|
|
138544
|
+
dirX = points[0][0] - points[1][0];
|
|
138545
|
+
dirY = points[0][1] - points[1][1];
|
|
138546
|
+
}
|
|
138547
|
+
const [textX, textY] = textPt;
|
|
138548
|
+
const lenT = Math.sqrt(dirX * dirX + dirY * dirY);
|
|
138549
|
+
let polylinePixelOffset = [0, 0];
|
|
138550
|
+
let polylineTextAnchor = "middle";
|
|
138551
|
+
let polylineAlignmentBaseline = pos === "middle" ? "center" : "bottom";
|
|
138552
|
+
if (lenT > 0) {
|
|
138553
|
+
const uxT = dirX / lenT;
|
|
138554
|
+
const uyT = dirY / lenT;
|
|
138555
|
+
const offX = uxT * bufferPx;
|
|
138556
|
+
const offY = uyT * bufferPx;
|
|
138557
|
+
polylinePixelOffset = [offX, offY];
|
|
138558
|
+
if (Math.abs(offX) >= Math.abs(offY)) {
|
|
138559
|
+
polylineTextAnchor = offX > 0 ? "start" : "end";
|
|
138560
|
+
}
|
|
138561
|
+
if (Math.abs(offY) >= Math.abs(offX)) {
|
|
138562
|
+
polylineAlignmentBaseline = offY > 0 ? "top" : "bottom";
|
|
138563
|
+
}
|
|
138564
|
+
}
|
|
138565
|
+
if (labelOpacity <= 0)
|
|
138566
|
+
return;
|
|
138567
|
+
layers.push(new TextLayer({
|
|
138568
|
+
...labelBase,
|
|
138569
|
+
...labelProps,
|
|
138570
|
+
id: `annotation-polyline-text-${uid2}-${i2}`,
|
|
138571
|
+
data: [{ position: [textX, textY], text: shape.text }],
|
|
138572
|
+
getPosition: (d) => d.position,
|
|
138573
|
+
getText: (d) => d.text,
|
|
138574
|
+
getColor: strokeColor,
|
|
138575
|
+
getSize: LABEL_FONT_SIZE,
|
|
138576
|
+
sizeUnits: "pixels",
|
|
138577
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138578
|
+
fontWeight: LABEL_FONT_WEIGHT,
|
|
138579
|
+
getPixelOffset: polylinePixelOffset,
|
|
138580
|
+
getTextAnchor: polylineTextAnchor,
|
|
138581
|
+
getAlignmentBaseline: polylineAlignmentBaseline
|
|
138582
|
+
}));
|
|
138583
|
+
}
|
|
138584
|
+
}
|
|
138585
|
+
});
|
|
138586
|
+
if (dotShapes.length > 0) {
|
|
138587
|
+
layers.push(new ScatterplotLayer({
|
|
138588
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
138589
|
+
id: "annotation-dots",
|
|
138590
|
+
data: dotShapes.map(({ shape: s2, alpha: alpha2 }) => ({
|
|
138591
|
+
position: getShapeCentroid(s2),
|
|
138592
|
+
color: [...s2.strokeColor ?? [255, 255, 255], alpha2]
|
|
138593
|
+
})),
|
|
138594
|
+
getPosition: (d) => d.position,
|
|
138595
|
+
getFillColor: (d) => d.color,
|
|
138596
|
+
getRadius: 4,
|
|
138597
|
+
radiusUnits: "pixels",
|
|
138598
|
+
filled: true,
|
|
138599
|
+
stroked: false
|
|
138600
|
+
}));
|
|
138601
|
+
}
|
|
138602
|
+
if (clusterDotShapes.length > 0) {
|
|
138603
|
+
const clusters = computeClusters(clusterDotShapes, zoom);
|
|
138604
|
+
layers.push(new ScatterplotLayer({
|
|
138605
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
138606
|
+
id: "annotation-clusters",
|
|
138607
|
+
data: clusters,
|
|
138608
|
+
getPosition: (d) => d.position,
|
|
138609
|
+
getFillColor: (d) => [...d.color, 180],
|
|
138610
|
+
getRadius: (d) => Math.max(6, 4 + Math.sqrt(d.count) * 2),
|
|
138611
|
+
radiusUnits: "pixels",
|
|
138612
|
+
filled: true,
|
|
138613
|
+
stroked: true,
|
|
138614
|
+
getLineColor: (d) => [...d.color, 220],
|
|
138615
|
+
lineWidthMinPixels: 1.5
|
|
138616
|
+
}));
|
|
138617
|
+
const multiClusters = clusters.filter((c) => c.count > 1);
|
|
138618
|
+
if (multiClusters.length > 0) {
|
|
138619
|
+
layers.push(new TextLayer({
|
|
138620
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
138621
|
+
id: "annotation-cluster-counts",
|
|
138622
|
+
data: multiClusters,
|
|
138623
|
+
getPosition: (d) => d.position,
|
|
138624
|
+
getText: (d) => String(d.count),
|
|
138625
|
+
getColor: [255, 255, 255],
|
|
138626
|
+
getSize: 10,
|
|
138627
|
+
sizeUnits: "pixels",
|
|
138628
|
+
fontWeight: "bold",
|
|
138629
|
+
getTextAnchor: "middle",
|
|
138630
|
+
getAlignmentBaseline: "center"
|
|
138631
|
+
}));
|
|
138632
|
+
}
|
|
138633
|
+
}
|
|
138634
|
+
const measureLayers = [];
|
|
138635
|
+
shapes.forEach((shape) => {
|
|
138636
|
+
if (!shape.showMeasure)
|
|
138637
|
+
return;
|
|
138638
|
+
const mIsSelected = shape.uid === selectedShapeUid;
|
|
138639
|
+
const label = getMeasurementLabel(shape, physicalPixelSize, viewType);
|
|
138640
|
+
if (!label)
|
|
138641
|
+
return;
|
|
138642
|
+
const color = shape.strokeColor ?? [255, 255, 255];
|
|
138643
|
+
let mShapeOpacity = 1;
|
|
138644
|
+
let mLabelFactor = 0;
|
|
138645
|
+
if (mIsSelected || !semanticZoom || authoredZoom === null) {
|
|
138646
|
+
mLabelFactor = 1;
|
|
138647
|
+
} else {
|
|
138648
|
+
const mZoomRatio = 2 ** (zoom - authoredZoom);
|
|
138649
|
+
if (mZoomRatio < RATIO_DOT)
|
|
138650
|
+
return;
|
|
138651
|
+
if (mZoomRatio < RATIO_GEO_FADE) {
|
|
138652
|
+
mShapeOpacity = (mZoomRatio - RATIO_DOT) / (RATIO_GEO_FADE - RATIO_DOT);
|
|
138653
|
+
}
|
|
138654
|
+
if (mZoomRatio >= RATIO_LABEL_FULL) {
|
|
138655
|
+
mLabelFactor = 1;
|
|
138656
|
+
} else if (mZoomRatio >= RATIO_LABEL) {
|
|
138657
|
+
mLabelFactor = (mZoomRatio - RATIO_LABEL) / (RATIO_LABEL_FULL - RATIO_LABEL);
|
|
138658
|
+
}
|
|
138659
|
+
}
|
|
138660
|
+
const measureOpacity = mShapeOpacity * mLabelFactor;
|
|
138661
|
+
if (measureOpacity <= 0)
|
|
138662
|
+
return;
|
|
138663
|
+
const base = {
|
|
138664
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
138665
|
+
opacity: measureOpacity,
|
|
138666
|
+
getText: (d) => d.text,
|
|
138667
|
+
getPosition: (d) => d.position,
|
|
138668
|
+
getColor: color,
|
|
138669
|
+
getSize: 13,
|
|
138670
|
+
sizeUnits: "pixels",
|
|
138671
|
+
fontFamily: LABEL_FONT_FAMILY,
|
|
138672
|
+
fontWeight: "bold",
|
|
138673
|
+
// 'auto' builds the font atlas from the actual rendered characters (e.g. µ, ²)
|
|
138674
|
+
// instead of deck.gl's default ASCII-only atlas.
|
|
138675
|
+
characterSet: "auto",
|
|
138676
|
+
...shape.measureBackground ? {
|
|
138677
|
+
background: true,
|
|
138678
|
+
getBackgroundColor: textBgColor(color),
|
|
138679
|
+
backgroundPadding: [3, 1, 3, 2]
|
|
138680
|
+
} : {}
|
|
138681
|
+
};
|
|
138682
|
+
if (shape.type === "line") {
|
|
138683
|
+
const mx = ((shape.x1 ?? 0) + (shape.x2 ?? 0)) / 2;
|
|
138684
|
+
const my = ((shape.y1 ?? 0) + (shape.y2 ?? 0)) / 2;
|
|
138685
|
+
const dx = (shape.x2 ?? 0) - (shape.x1 ?? 0);
|
|
138686
|
+
const dy = (shape.y2 ?? 0) - (shape.y1 ?? 0);
|
|
138687
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
138688
|
+
if (len2 === 0)
|
|
138689
|
+
return;
|
|
138690
|
+
const perp = pickBelowPerp(dx / len2, dy / len2);
|
|
138691
|
+
const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
|
|
138692
|
+
measureLayers.push(new TextLayer({
|
|
138693
|
+
...base,
|
|
138694
|
+
id: `annotation-measure-${shape.uid}`,
|
|
138695
|
+
data: [{ position: [mx, my], text: label }],
|
|
138696
|
+
getAngle: -angle2,
|
|
138697
|
+
getTextAnchor: "middle",
|
|
138698
|
+
getAlignmentBaseline: "center",
|
|
138699
|
+
getPixelOffset: [perp[0] * 16, perp[1] * 16]
|
|
138700
|
+
}));
|
|
138701
|
+
} else if (shape.type === "polyline" && shape.points?.length >= 2) {
|
|
138702
|
+
const pts = shape.points;
|
|
138703
|
+
const mi = Math.floor((pts.length - 1) / 2);
|
|
138704
|
+
const [ax, ay] = pts[mi];
|
|
138705
|
+
const [bx, by] = pts[mi + 1];
|
|
138706
|
+
const dx = bx - ax;
|
|
138707
|
+
const dy = by - ay;
|
|
138708
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
138709
|
+
if (len2 === 0)
|
|
138710
|
+
return;
|
|
138711
|
+
const perp = pickBelowPerp(dx / len2, dy / len2);
|
|
138712
|
+
const angle2 = readableAngle(Math.atan2(dy, dx) * 180 / Math.PI);
|
|
138713
|
+
measureLayers.push(new TextLayer({
|
|
138714
|
+
...base,
|
|
138715
|
+
id: `annotation-measure-${shape.uid}`,
|
|
138716
|
+
data: [{ position: [(ax + bx) / 2, (ay + by) / 2], text: label }],
|
|
138717
|
+
getAngle: -angle2,
|
|
138718
|
+
getTextAnchor: "middle",
|
|
138719
|
+
getAlignmentBaseline: "center",
|
|
138720
|
+
getPixelOffset: [perp[0] * 16, perp[1] * 16]
|
|
138721
|
+
}));
|
|
138722
|
+
} else if (shape.type === "rectangle") {
|
|
138723
|
+
const x02 = shape.x ?? 0;
|
|
138724
|
+
const y02 = shape.y ?? 0;
|
|
138725
|
+
const w2 = shape.width ?? 0;
|
|
138726
|
+
const h = shape.height ?? 0;
|
|
138727
|
+
const rx = x02 + (w2 >= 0 ? w2 : 0);
|
|
138728
|
+
const ry = y02 + (h >= 0 ? h : 0);
|
|
138729
|
+
measureLayers.push(new TextLayer({
|
|
138730
|
+
...base,
|
|
138731
|
+
id: `annotation-measure-${shape.uid}`,
|
|
138732
|
+
data: [{ position: [rx, ry], text: label }],
|
|
138733
|
+
getTextAnchor: "end",
|
|
138734
|
+
getAlignmentBaseline: "bottom",
|
|
138735
|
+
getPixelOffset: [-6, -6]
|
|
138736
|
+
}));
|
|
138737
|
+
} else if (shape.type === "ellipse") {
|
|
138738
|
+
const cx = shape.x1 ?? 0;
|
|
138739
|
+
const cy = shape.y1 ?? 0;
|
|
138740
|
+
const ry = Math.abs(shape.radiusY ?? 0);
|
|
138741
|
+
measureLayers.push(new TextLayer({
|
|
138742
|
+
...base,
|
|
138743
|
+
id: `annotation-measure-${shape.uid}`,
|
|
138744
|
+
data: [{ position: [cx, cy + ry], text: label }],
|
|
138745
|
+
getTextAnchor: "middle",
|
|
138746
|
+
getAlignmentBaseline: "top",
|
|
138747
|
+
getPixelOffset: [0, 8]
|
|
138748
|
+
}));
|
|
138749
|
+
} else if (shape.type === "polygon" && shape.points?.length >= 3) {
|
|
138750
|
+
const xs = shape.points.map((p) => p[0]);
|
|
138751
|
+
const ys = shape.points.map((p) => p[1]);
|
|
138752
|
+
const cx = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
138753
|
+
const maxY = Math.max(...ys);
|
|
138754
|
+
measureLayers.push(new TextLayer({
|
|
138755
|
+
...base,
|
|
138756
|
+
id: `annotation-measure-${shape.uid}`,
|
|
138757
|
+
data: [{ position: [cx, maxY], text: label }],
|
|
138758
|
+
getTextAnchor: "middle",
|
|
138759
|
+
getAlignmentBaseline: "top",
|
|
138760
|
+
getPixelOffset: [0, 8]
|
|
138761
|
+
}));
|
|
138762
|
+
}
|
|
138763
|
+
});
|
|
138764
|
+
return [...selectionLayers, ...layers, ...measureLayers];
|
|
138765
|
+
}
|
|
138766
|
+
const defaultProps = {
|
|
138767
|
+
// Array of annotation shape objects (see annotationShapeObj in @vitessce/schemas).
|
|
138768
|
+
data: { type: "object", value: [], compare: true },
|
|
138769
|
+
// UID of the shape to highlight with a selection halo.
|
|
138770
|
+
selectedShapeUid: { type: "string", value: null },
|
|
138771
|
+
// { x, y, unit } used to format measurement labels in physical units.
|
|
138772
|
+
physicalPixelSize: { type: "object", value: null, compare: true },
|
|
138773
|
+
// The zoom level at which the shapes were authored (reference for semantic zoom).
|
|
138774
|
+
authoredZoom: { type: "number", value: null },
|
|
138775
|
+
// Whether to apply semantic zoom (level-of-detail) based on authoredZoom.
|
|
138776
|
+
semanticZoom: { type: "boolean", value: true },
|
|
138777
|
+
// The view type in which the layer is rendered (affects measurement label formatting).
|
|
138778
|
+
viewType: { type: "string", value: ViewType.SPATIAL },
|
|
138779
|
+
// In-progress shape being drawn, as { type, vertices }.
|
|
138780
|
+
inProgressShape: { type: "object", value: null, compare: true },
|
|
138781
|
+
// Current mouse position (in data coordinates) while drawing.
|
|
138782
|
+
hoverCoord: { type: "array", value: null, compare: true },
|
|
138783
|
+
// Stroke color [r, g, b] of the in-progress shape preview.
|
|
138784
|
+
previewStrokeColor: { type: "color", value: [255, 255, 0] }
|
|
138785
|
+
};
|
|
138786
|
+
class AnnotationLayer extends CompositeLayer {
|
|
138787
|
+
// The semantic zoom and arrowhead sizes depend on the current zoom level,
|
|
138788
|
+
// so the sublayers must also be re-rendered when the viewport changes.
|
|
138789
|
+
// eslint-disable-next-line class-methods-use-this
|
|
138790
|
+
shouldUpdateState({ changeFlags }) {
|
|
138791
|
+
return changeFlags.propsOrDataChanged || changeFlags.viewportChanged;
|
|
138792
|
+
}
|
|
138793
|
+
/**
|
|
138794
|
+
* Prefix the sublayer ID with this layer's ID (so that multiple
|
|
138795
|
+
* AnnotationLayers can co-exist), and combine this layer's
|
|
138796
|
+
* opacity with the per-shape opacity of the sublayer.
|
|
138797
|
+
* Note: we avoid getSubLayerProps here, since it would
|
|
138798
|
+
* overwrite the sublayer extensions (e.g., PathStyleExtension)
|
|
138799
|
+
* and opacity values.
|
|
138800
|
+
* @param {object} layer A DeckGL layer instance.
|
|
138801
|
+
* @returns {object} The cloned layer instance.
|
|
138802
|
+
*/
|
|
138803
|
+
wrapSubLayer(layer) {
|
|
138804
|
+
const { id, opacity, pickable, visible } = this.props;
|
|
138805
|
+
return layer.clone({
|
|
138806
|
+
id: `${id}-${layer.id}`,
|
|
138807
|
+
opacity: layer.props.opacity * opacity,
|
|
138808
|
+
pickable,
|
|
138809
|
+
visible
|
|
138810
|
+
});
|
|
138811
|
+
}
|
|
138812
|
+
renderLayers() {
|
|
138813
|
+
const { data, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType, inProgressShape, hoverCoord, previewStrokeColor } = this.props;
|
|
138814
|
+
const zoom = this.context.viewport?.zoom ?? 0;
|
|
138815
|
+
const visibleShapes = (data ?? []).filter((shape) => shape.visible !== false);
|
|
138816
|
+
const annotationLayers = createAnnotationLayers(visibleShapes, zoom, selectedShapeUid, physicalPixelSize, authoredZoom, semanticZoom, viewType);
|
|
138817
|
+
const previewLayer = createPreviewLayer(inProgressShape, hoverCoord, previewStrokeColor.slice(0, 3));
|
|
138818
|
+
return [
|
|
138819
|
+
...annotationLayers,
|
|
138820
|
+
...previewLayer ? [previewLayer] : []
|
|
138821
|
+
].map((layer) => this.wrapSubLayer(layer));
|
|
138822
|
+
}
|
|
138823
|
+
}
|
|
138824
|
+
AnnotationLayer.layerName = "AnnotationLayer";
|
|
138825
|
+
AnnotationLayer.defaultProps = defaultProps;
|
|
137627
138826
|
const toRgbUIString = (on, arr, theme) => {
|
|
137628
138827
|
const color = on || theme !== "dark" && arr?.every((i2) => i2 === 255) ? [220, 220, 220] : arr;
|
|
137629
138828
|
return `rgb(${color})`;
|
|
@@ -137641,8 +138840,8 @@ async function getSingleSelectionStats2D({ loader, selection }) {
|
|
|
137641
138840
|
const filteredSelection = filterSelection(loader, selection);
|
|
137642
138841
|
const raster = await data.getRaster({ selection: filteredSelection });
|
|
137643
138842
|
const selectionStats = getChannelStats(raster.data);
|
|
137644
|
-
const { domain, contrastLimits: slider } = selectionStats;
|
|
137645
|
-
return { domain, slider };
|
|
138843
|
+
const { domain, contrastLimits: slider, q1, q3 } = selectionStats;
|
|
138844
|
+
return { domain, slider, q1, q3 };
|
|
137646
138845
|
}
|
|
137647
138846
|
async function getSingleSelectionStats3D({ loader, selection }) {
|
|
137648
138847
|
const lowResSource = loader[loader.length - 1];
|
|
@@ -137677,7 +138876,9 @@ async function getSingleSelectionStats3D({ loader, selection }) {
|
|
|
137677
138876
|
statsMid.contrastLimits[1],
|
|
137678
138877
|
statsTop.contrastLimits[1]
|
|
137679
138878
|
)
|
|
137680
|
-
]
|
|
138879
|
+
],
|
|
138880
|
+
q1: Math.min(stats0.q1[0], statsMid.q1[0], statsTop.q1[0]),
|
|
138881
|
+
q3: Math.max(stats0.q3[1], statsMid.q3[1], statsTop.q3[1])
|
|
137681
138882
|
};
|
|
137682
138883
|
}
|
|
137683
138884
|
const getSingleSelectionStats = async ({ loader, selection, use3d }) => {
|
|
@@ -137690,7 +138891,9 @@ const getMultiSelectionStats = async ({ loader, selections, use3d }) => {
|
|
|
137690
138891
|
);
|
|
137691
138892
|
const domains = stats.map((stat) => stat.domain);
|
|
137692
138893
|
const sliders = stats.map((stat) => stat.slider);
|
|
137693
|
-
|
|
138894
|
+
const q1s = stats.map((stat) => stat.q1);
|
|
138895
|
+
const q3s = stats.map((stat) => stat.q3);
|
|
138896
|
+
return { domains, sliders, q1s, q3s };
|
|
137694
138897
|
};
|
|
137695
138898
|
function getPhysicalSizeScalingMatrix(loader) {
|
|
137696
138899
|
const { x, y, z } = loader?.meta?.physicalSizes ?? {};
|